2 * Routines for value_strings
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "value_string.h"
34 /* --------------------------------------------------------------------*/
35 /* Tries to match val against each element in the value_string array vs.
36 Returns the associated string ptr on a match.
37 Formats val with fmt, and returns the resulting string, on failure. */
39 val_to_str(const guint32 val, const value_string *vs, const char *fmt) {
42 g_assert(fmt != NULL);
44 ret = match_strval(val, vs);
48 return ep_strdup_printf(fmt, val);
51 /* --------------------------------------------------------------------*/
52 /* Tries to match val against each element in the value_string array vs.
53 Returns the associated string ptr on a match.
54 Returns 'unknown_str', on failure. */
56 val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_str) {
59 g_assert(unknown_str != NULL);
61 ret = match_strval(val, vs);
68 /* --------------------------------------------------------------------*/
69 /* Tries to match val against each element in the value_string array vs.
70 Returns the associated string ptr, and sets "*idx" to the index in
71 that table, on a match, and returns NULL, and sets "*idx" to -1,
74 match_strval_idx(const guint32 val, const value_string *vs, gint *idx) {
78 while (vs[i].strptr) {
79 if (vs[i].value == val) {
91 /* Like match_strval_idx(), but doesn't return the index. */
93 match_strval(const guint32 val, const value_string *vs) {
95 return match_strval_idx(val, vs, &ignore_me);
98 /* --------------------------------------------------------------------*/
99 /* value_string_ext functions
101 * Extended value strings allow fast(er) value_string array lookups by
102 * using (if possible) direct access or a binary search of the array.
104 * If the values in the value_string array are a contiguous range of values
105 * from min to max, the value will be used as as a direct index into the array.
107 * If the values in the array are not contiguous (ie: there are "gaps"),
108 * but are in assending order a binary search will be used.
110 * If direct access or binary search cannot be used, then a linear search
113 * Note that the value_string array used with VALUE_STRING_EXT_INIT
114 * *must* be terminated with {0, NULL}).
116 * Extended value strings are defined at compile time as follows:
117 * static const value_string vs[] = { {value1, "string1"}, {value2, "string2"}, ..., {0, NULL}};
118 * static value_string_ext vse = VALUE_STRING_EXT_INIT(vs);
120 * Extended value strings can be created at runtime by calling
121 * value_string_ext_new(<ptr to value_string array>,
122 * <total number of entries in the value_string_array>,
123 * <value_string_name>);
124 * Note: <total number of entries in the value_string_array> should include the {0, NULL} entry
128 /* --------------------------------------------------------------------*/
130 /* Create a value_string_ext given a ptr to a value_string array and the total number of entries. */
131 /* Note: The total number of entries should include the required {0, NULL} terminating entry of the array. */
132 /* Return: a pointer to a g_malloc'd and initialized value_string_ext struct. */
134 value_string_ext_new(value_string *vs, guint vs_tot_num_entries, gchar *vs_name) {
135 value_string_ext *vse;
136 g_assert (vs_name != NULL);
137 g_assert (vs_tot_num_entries > 0);
138 g_assert (vs[vs_tot_num_entries-1].strptr == NULL); /* Null-terminated value-string ? */
139 vse = g_malloc(sizeof (value_string_ext));
141 vse->_vs_num_entries = vs_tot_num_entries - 1; /* remember the actual number of entries */
142 vse->_vs_first_value = 0; /* initialized in _match_strval_ext_init */
143 vse->_vs_match2 = _match_strval_ext_init;
144 vse->_vs_name = vs_name;
148 /* Looks up val in a value_string array using access method (direct, binary search
149 * or linear) determined at rutime during the initial access); (see _match_strval_ext_init)
150 * Returns the associated string ptr on a match, and returns NULL on failure.
153 match_strval_ext(const guint32 val, const value_string_ext *vse) {
155 const value_string *vs = vse->_vs_match2(val, vse);
162 /* Tries to match val against each element in the value_string array vs.
163 * Returns the associated string ptr, and sets "*idx" to the index in
164 * that table, on a match, and returns NULL, and sets "*idx" to -1,
169 match_strval_idx_ext(const guint32 val, value_string_ext *vse, gint *idx) {
171 const value_string *vs = vse->_vs_match2(val, vse);
173 *idx = (gint) (vs - vse->_vs_p);
181 /* Similar to match_strval_ext except that on failure
182 * Formats val with fmt, and returns the resulting string
185 val_to_str_ext(const guint32 val, const value_string_ext *vse, const char *fmt) {
188 g_assert(fmt != NULL);
190 ret = match_strval_ext(val, vse);
194 return ep_strdup_printf(fmt, val);
197 /* Similar to match_strval_ext except that on failure
198 * Returns 'unknown_str'
201 val_to_str_ext_const(const guint32 val, const value_string_ext *vse, const char *unknown_str) {
204 g_assert(unknown_str != NULL);
206 ret = match_strval_ext(val, vse);
213 static const value_string *
214 _match_strval_linear(const guint32 val, const value_string_ext *vse)
216 const value_string *vs_p = vse->_vs_p;
218 for (i=0; i<vse->_vs_num_entries; i++) {
219 if (vs_p[i].value == val)
225 static const value_string *
226 _match_strval_index(const guint32 val, const value_string_ext *vse)
230 i = val - vse->_vs_first_value;
231 if (i < vse->_vs_num_entries) {
232 g_assert (val == vse->_vs_p[i].value);
233 return &(vse->_vs_p[i]);
238 static const value_string *
239 _match_strval_bsearch(const guint32 val, const value_string_ext *vse)
244 for (low = 0, max = vse->_vs_num_entries; low < max; ) {
246 item = vse->_vs_p[i].value;
253 return &(vse->_vs_p[i]);
258 /* Init value_string_ext struct
259 - Go thru the value_string array to determine whether indexed access
260 or binary search access is possible;
261 - Verify that the value_string array does not contain any
262 NULL string pointers;
263 - Verify that the value_string array is terminated
267 _match_strval_ext_init(const guint32 val, const value_string_ext *a_vse)
269 /* Cast away the constness!
270 * It's better if the prototype for this function matches the other
271 * _match_strval_* functions (so we don't have to cast it when storing it
272 * in _match_strval so the compiler will notice if the prototypes get out
273 * of sync), but the init function is unique in that it does actually
276 value_string_ext *vse = (value_string_ext *)a_vse;
278 const value_string *vs_p = vse->_vs_p;
279 const guint vs_num_entries = vse->_vs_num_entries;
281 /* The way matching of value is done in a value_string:
282 * 0 Sequential search (as in a normal value string)
283 * 1 Binary search, the values MUST be in numerical order.
284 * 2 The value used as an index(the value string MUST have all values between first and last defined in numerical order)
287 /* Note: The value_string 'value' is *unsigned*.
290 * { -3, -2, -1, 0, 1, 2 } will be treated as "ascending ordered" (altho not really such)
291 * thus allowing as a 'direct' search.
294 * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } will both be considered as "out-of-order with gaps"
295 * thus requiring a 'linear' search.
296 * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } will be considered "ascending ordered with gaps"
297 * thus allowing a 'binary' search.
300 enum { VS_SEARCH = 0, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
306 g_assert((vs_p[vs_num_entries].value==0) && (vs_p[vs_num_entries].strptr==NULL));
308 vse->_vs_first_value = vs_p[0].value;
309 first_value = vs_p[0].value;
310 prev_value = first_value;
312 for (i = 0; i < vs_num_entries; i++) {
313 g_assert(vs_p[i].strptr != NULL);
314 if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) {
317 /* XXX: Should check for dups ?? */
318 if ((type == VS_BIN_TREE) &&
319 ((prev_value > vs_p[i].value) || (first_value > vs_p[i].value))) {
324 prev_value = vs_p[i].value;
329 vse->_vs_match2 = _match_strval_linear;
332 vse->_vs_match2 = _match_strval_bsearch;
335 vse->_vs_match2 = _match_strval_index;
338 g_assert_not_reached();
342 return vse->_vs_match2(val, vse);
345 /* (Fcns for use by proto_registrar_dump_values() [See proto.c]) */
347 value_string_ext_validate(const value_string_ext *vse) {
350 if ((vse->_vs_match2 == _match_strval_ext_init) ||
351 (vse->_vs_match2 == _match_strval_linear) ||
352 (vse->_vs_match2 == _match_strval_bsearch) ||
353 (vse->_vs_match2 == _match_strval_index))
359 value_string_ext_match_type_str(const value_string_ext *vse) {
360 if (vse->_vs_match2 == _match_strval_linear)
361 return "[Linear Search]";
362 if (vse->_vs_match2 == _match_strval_bsearch)
363 return "[Binary Search]";
364 if (vse->_vs_match2 == _match_strval_index)
365 return "[Direct (indexed) Access]";
366 return "[Match Type not initialized or invalid]";
371 /* Tries to match val against each element in the value_string array vs.
372 Returns the associated string ptr on a match.
373 Formats val with fmt, and returns the resulting string, on failure. */
375 str_to_str(const gchar *val, const string_string *vs, const char *fmt) {
378 g_assert(fmt != NULL);
380 ret = match_strstr(val, vs);
384 return ep_strdup_printf(fmt, val);
387 /* Tries to match val against each element in the value_string array vs.
388 Returns the associated string ptr, and sets "*idx" to the index in
389 that table, on a match, and returns NULL, and sets "*idx" to -1,
392 match_strstr_idx(const gchar *val, const string_string *vs, gint *idx) {
396 while (vs[i].strptr) {
397 if (!strcmp(vs[i].value,val)) {
399 return(vs[i].strptr);
409 /* Like match_strval_idx(), but doesn't return the index. */
411 match_strstr(const gchar *val, const string_string *vs) {
413 return match_strstr_idx(val, vs, &ignore_me);
416 /* Generate a string describing an enumerated bitfield (an N-bit field
417 with various specific values having particular names). */
419 decode_enumerated_bitfield(const guint32 val, const guint32 mask, const int width,
420 const value_string *tab, const char *fmt)
422 static char buf[1025];
425 p = decode_bitfield_value(buf, val, mask, width);
426 g_snprintf(p, (gulong) (1024-(p-buf)), fmt, val_to_str(val & mask, tab, "Unknown"));
431 /* Generate a string describing an enumerated bitfield (an N-bit field
432 with various specific values having particular names). */
434 decode_enumerated_bitfield_shifted(const guint32 val, const guint32 mask, const int width,
435 const value_string *tab, const char *fmt)
437 static char buf[1025];
441 /* Compute the number of bits we have to shift the bitfield right
442 to extract its value. */
443 while ((mask & (1<<shift)) == 0)
446 p = decode_bitfield_value(buf, val, mask, width);
447 g_snprintf(p, (gulong) (1024-(p-buf)), fmt, val_to_str((val & mask) >> shift, tab, "Unknown"));
452 /* FF: ranges aware versions */
454 /* Tries to match val against each range in the range_string array rs.
455 Returns the associated string ptr on a match.
456 Formats val with fmt, and returns the resulting string, on failure. */
458 rval_to_str(const guint32 val, const range_string *rs, const char *fmt)
460 const gchar *ret = NULL;
462 g_assert(fmt != NULL);
464 ret = match_strrval(val, rs);
468 return ep_strdup_printf(fmt, val);
471 /* Tries to match val against each range in the range_string array rs.
472 Returns the associated string ptr, and sets "*idx" to the index in
473 that table, on a match, and returns NULL, and sets "*idx" to -1,
476 match_strrval_idx(const guint32 val, const range_string *rs, gint *idx)
481 while(rs[i].strptr) {
482 if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
484 return (rs[i].strptr);
494 /* Like match_strrval_idx(), but doesn't return the index. */
496 match_strrval(const guint32 val, const range_string *rs)
499 return match_strrval_idx(val, rs, &ignore_me);