Fix bugs I introduced. Now
[metze/wireshark/wip.git] / epan / value_string.c
1 /* value_string.c
2  * Routines for value_strings
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #include "config.h"
26
27 #include <stdio.h>
28
29 #include "to_str.h"
30 #include "emem.h"
31 #include "value_string.h"
32 #include <string.h>
33
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. */
38 const gchar*
39 val_to_str(const guint32 val, const value_string *vs, const char *fmt) {
40   const gchar *ret;
41
42   g_assert(fmt != NULL);
43
44   ret = match_strval(val, vs);
45   if (ret != NULL)
46     return ret;
47
48   return ep_strdup_printf(fmt, val);
49 }
50
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. */
55 const gchar*
56 val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_str) {
57   const gchar *ret;
58
59   g_assert(unknown_str != NULL);
60
61   ret = match_strval(val, vs);
62   if (ret != NULL)
63     return ret;
64
65   return unknown_str;
66 }
67
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,
72    on failure. */
73 const gchar*
74 match_strval_idx(const guint32 val, const value_string *vs, gint *idx) {
75   gint i = 0;
76
77   if(vs) {
78     while (vs[i].strptr) {
79       if (vs[i].value == val) {
80         *idx = i;
81         return(vs[i].strptr);
82       }
83       i++;
84     }
85   }
86
87   *idx = -1;
88   return NULL;
89 }
90
91 /* Like match_strval_idx(), but doesn't return the index. */
92 const gchar*
93 match_strval(const guint32 val, const value_string *vs) {
94     gint ignore_me;
95     return match_strval_idx(val, vs, &ignore_me);
96 }
97
98 /* --------------------------------------------------------------------*/
99 /* value_string_ext functions
100  *
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.
103  *
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.
106  *
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.
109  *
110  *    If direct access or binary search cannot be used, then a linear search
111  *    is used.
112  *
113  *    Note that the value_string array used with VALUE_STRING_EXT_INIT
114  *     *must* be terminated with {0, NULL}).
115  *
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);
119  *
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
125  *
126  */
127
128 /* --------------------------------------------------------------------*/
129
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.                                */
133 value_string_ext *
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));
140     vse->_vs_p           = vs;
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;
145     return vse;
146 }
147
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.
151  */
152 const gchar*
153 match_strval_ext(const guint32 val, const value_string_ext *vse) {
154     if (vse) {
155       const value_string *vs = vse->_vs_match2(val, vse);
156       if (vs)
157         return vs->strptr;
158     }
159     return NULL;
160 }
161
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,
165  *  on failure.
166  */
167
168 const gchar*
169 match_strval_idx_ext(const guint32 val, value_string_ext *vse, gint *idx) {
170     if (vse) {
171       const value_string *vs = vse->_vs_match2(val, vse);
172       if (vs) {
173         *idx = (gint) (vs - vse->_vs_p);
174         return vs->strptr;
175       }
176     }
177     *idx = -1;
178     return NULL;
179 }
180
181 /* Similar to match_strval_ext except that on failure
182  * Formats val with fmt, and returns the resulting string
183  */
184 const gchar*
185 val_to_str_ext(const guint32 val, const value_string_ext *vse, const char *fmt) {
186   const gchar *ret;
187
188   g_assert(fmt != NULL);
189
190   ret = match_strval_ext(val, vse);
191   if (ret != NULL)
192     return ret;
193
194   return ep_strdup_printf(fmt, val);
195 }
196
197 /* Similar to match_strval_ext except that on failure
198  *  Returns 'unknown_str'
199  */
200 const gchar*
201 val_to_str_ext_const(const guint32 val, const value_string_ext *vse, const char *unknown_str) {
202   const gchar *ret;
203
204   g_assert(unknown_str != NULL);
205
206   ret = match_strval_ext(val, vse);
207   if (ret != NULL)
208     return ret;
209
210   return unknown_str;
211 }
212
213 static const value_string *
214 _match_strval_linear(const guint32 val, const value_string_ext *vse)
215 {
216   const value_string *vs_p = vse->_vs_p;
217   guint i;
218   for (i=0; i<vse->_vs_num_entries; i++) {
219     if (vs_p[i].value == val)
220       return &(vs_p[i]);
221   }
222   return NULL;
223 }
224
225 static const value_string *
226 _match_strval_index(const guint32 val, const value_string_ext *vse)
227 {
228   guint i;
229
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]);
234   }
235   return NULL;
236 }
237
238 static const value_string *
239 _match_strval_bsearch(const guint32 val, const value_string_ext *vse)
240 {
241   guint low, i, max;
242   guint32 item;
243
244   for (low = 0, max = vse->_vs_num_entries; low < max; ) {
245     i = (low + max) / 2;
246     item = vse->_vs_p[i].value;
247
248     if (val < item)
249       max = i;
250     else if (val > item)
251       low = i + 1;
252     else
253       return &(vse->_vs_p[i]);
254   }
255   return NULL;
256 }
257
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
264       by {0, NULL};
265 */
266 const value_string *
267 _match_strval_ext_init(const guint32 val, const value_string_ext *a_vse)
268 {
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
274    *  modify the vse.
275    */
276   value_string_ext    *vse            = (value_string_ext *)a_vse;
277
278   const value_string *vs_p           = vse->_vs_p;
279   const guint         vs_num_entries = vse->_vs_num_entries;
280
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)
285  */
286
287 /* Note: The value_string 'value' is *unsigned*.
288  *
289  *   Special case:
290  *    { -3, -2, -1, 0, 1, 2 }                      will be treated as "ascending ordered" (altho not really such)
291  *                                                  thus allowing as a 'direct' search.
292  *
293  *   Note:
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.
298  */
299
300   enum { VS_SEARCH = 0, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
301
302   guint32 prev_value;
303   guint   first_value;
304   guint   i;
305
306   g_assert((vs_p[vs_num_entries].value==0) && (vs_p[vs_num_entries].strptr==NULL));
307
308   vse->_vs_first_value = vs_p[0].value;
309   first_value          = vs_p[0].value;
310   prev_value           = first_value;
311
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))) {
315       type = VS_BIN_TREE;
316     }
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))) {
320       type = VS_SEARCH;
321       break;
322     }
323
324     prev_value = vs_p[i].value;
325   }
326
327   switch (type) {
328   case VS_SEARCH:
329     vse->_vs_match2 = _match_strval_linear;
330     break;
331   case VS_BIN_TREE:
332     vse->_vs_match2 = _match_strval_bsearch;
333     break;
334   case VS_INDEX:
335     vse->_vs_match2 = _match_strval_index;
336     break;
337   default:
338     g_assert_not_reached();
339     break;
340   }
341
342   return vse->_vs_match2(val, vse);
343 }
344
345 /* (Fcns for use by proto_registrar_dump_values() [See proto.c]) */
346 gboolean
347 value_string_ext_validate(const value_string_ext *vse) {
348     if (vse == NULL)
349         return FALSE;
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))
354         return TRUE;
355     return FALSE;
356 }
357
358 const gchar *
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]";
367 }
368
369 /* ----------- */
370
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. */
374 const gchar*
375 str_to_str(const gchar *val, const string_string *vs, const char *fmt) {
376   const gchar *ret;
377
378   g_assert(fmt != NULL);
379
380   ret = match_strstr(val, vs);
381   if (ret != NULL)
382     return ret;
383
384   return ep_strdup_printf(fmt, val);
385 }
386
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,
390    on failure. */
391 const gchar*
392 match_strstr_idx(const gchar *val, const string_string *vs, gint *idx) {
393   gint i = 0;
394
395   if(vs) {
396     while (vs[i].strptr) {
397       if (!strcmp(vs[i].value,val)) {
398         *idx = i;
399         return(vs[i].strptr);
400       }
401       i++;
402     }
403   }
404
405   *idx = -1;
406   return NULL;
407 }
408
409 /* Like match_strval_idx(), but doesn't return the index. */
410 const gchar*
411 match_strstr(const gchar *val, const string_string *vs) {
412     gint ignore_me;
413     return match_strstr_idx(val, vs, &ignore_me);
414 }
415
416 /* Generate a string describing an enumerated bitfield (an N-bit field
417    with various specific values having particular names). */
418 const char *
419 decode_enumerated_bitfield(const guint32 val, const guint32 mask, const int width,
420     const value_string *tab, const char *fmt)
421 {
422   static char buf[1025];
423   char *p;
424
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"));
427   return buf;
428 }
429
430
431 /* Generate a string describing an enumerated bitfield (an N-bit field
432    with various specific values having particular names). */
433 const char *
434 decode_enumerated_bitfield_shifted(const guint32 val, const guint32 mask, const int width,
435     const value_string *tab, const char *fmt)
436 {
437   static char buf[1025];
438   char *p;
439   int shift = 0;
440
441   /* Compute the number of bits we have to shift the bitfield right
442      to extract its value. */
443   while ((mask & (1<<shift)) == 0)
444     shift++;
445
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"));
448   return buf;
449 }
450
451
452 /* FF: ranges aware versions */
453
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. */
457 const gchar *
458 rval_to_str(const guint32 val, const range_string *rs, const char *fmt)
459 {
460   const gchar *ret = NULL;
461
462   g_assert(fmt != NULL);
463
464   ret = match_strrval(val, rs);
465   if(ret != NULL)
466     return ret;
467
468   return ep_strdup_printf(fmt, val);
469 }
470
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,
474    on failure. */
475 const gchar *
476 match_strrval_idx(const guint32 val, const range_string *rs, gint *idx)
477 {
478   gint i = 0;
479
480   if(rs) {
481     while(rs[i].strptr) {
482       if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
483         *idx = i;
484         return (rs[i].strptr);
485       }
486       i++;
487     }
488   }
489
490   *idx = -1;
491   return NULL;
492 }
493
494 /* Like match_strrval_idx(), but doesn't return the index. */
495 const gchar *
496 match_strrval(const guint32 val, const range_string *rs)
497 {
498     gint ignore_me = 0;
499     return match_strrval_idx(val, rs, &ignore_me);
500 }
501