Get the Windows build going again.
[obnox/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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30
31 #include "to_str.h"
32 #include "emem.h"
33 #include "value_string.h"
34 #include <string.h>
35
36 /* --------------------------------------------------------------------*/
37 /* Tries to match val against each element in the value_string array vs.
38    Returns the associated string ptr on a match.
39    Formats val with fmt, and returns the resulting string, on failure. */
40 const gchar*
41 val_to_str(const guint32 val, const value_string *vs, const char *fmt) {
42   const gchar *ret;
43
44   g_assert(fmt != NULL);
45
46   ret = match_strval(val, vs);
47   if (ret != NULL)
48     return ret;
49
50   return ep_strdup_printf(fmt, val);
51 }
52
53 /* --------------------------------------------------------------------*/
54 /* Tries to match val against each element in the value_string array vs.
55    Returns the associated string ptr on a match.
56    Returns 'unknown_str', on failure. */
57 const gchar*
58 val_to_str_const(const guint32 val, const value_string *vs, const char *unknown_str) {
59   const gchar *ret;
60
61   g_assert(unknown_str != NULL);
62
63   ret = match_strval(val, vs);
64   if (ret != NULL)
65     return ret;
66
67   return unknown_str;
68 }
69
70 /* --------------------------------------------------------------------*/
71 /* Tries to match val against each element in the value_string array vs.
72    Returns the associated string ptr, and sets "*idx" to the index in
73    that table, on a match, and returns NULL, and sets "*idx" to -1,
74    on failure. */
75 const gchar*
76 match_strval_idx(const guint32 val, const value_string *vs, gint *idx) {
77   gint i = 0;
78
79   if(vs) {
80     while (vs[i].strptr) {
81       if (vs[i].value == val) {
82         *idx = i;
83         return(vs[i].strptr);
84       }
85       i++;
86     }
87   }
88
89   *idx = -1;
90   return NULL;
91 }
92
93 /* Like match_strval_idx(), but doesn't return the index. */
94 const gchar*
95 match_strval(const guint32 val, const value_string *vs) {
96     gint ignore_me;
97     return match_strval_idx(val, vs, &ignore_me);
98 }
99
100 /* --------------------------------------------------------------------*/
101 /* value_string_ext functions
102  *
103  *   Extended value strings allow fast(er) value_string array lookups by
104  *    using (if possible) direct access or a binary search of the array.
105  *
106  *    If the values in the value_string array are a contiguous range of values
107  *    from min to max, the value will be used as as a direct index into the array.
108  *
109  *    If the values in the array are not contiguous (ie: there are "gaps"),
110  *    but are in assending order a binary search will be used.
111  *
112  *    If direct access or binary search cannot be used, then a linear search
113  *    is used.
114  *
115  *    Note that the value_string array used with VALUE_STRING_EXT_INIT
116  *     *must* be terminated with {0, NULL}).
117  *
118  *    Extended value strings are defined at compile time as follows:
119  *      static const value_string vs[] = { {value1, "string1"}, {value2, "string2"}, ..., {0, NULL}};
120  *      static value_string_ext vse = VALUE_STRING_EXT_INIT(vs);
121  *
122  *    Extended value strings can be created at runtime by calling
123  *      value_string_ext_new(<ptr to value_string array>,
124  *                           <total number of entries in the value_string_array>,
125  *                           <value_string_name>);
126  *      Note: <total number of entries in the value_string_array> should include the {0, NULL} entry
127  *
128  */
129
130 /* --------------------------------------------------------------------*/
131
132 /* Create a value_string_ext given a ptr to a value_string array and the total number of entries.           */
133 /* Note:  The total number of entries should include the required {0, NULL} terminating entry of the array. */
134 /* Return: a pointer to a gmalloc'd and initialized value_string_ext struct.                                */
135 value_string_ext *
136 value_string_ext_new(value_string *vs, guint vs_tot_num_entries, gchar *vs_name) {
137     value_string_ext *vse;
138     g_assert (vs_name != NULL);
139     g_assert (vs_tot_num_entries > 0);
140     g_assert (vs[vs_tot_num_entries-1].strptr == NULL); /* Null-terminated value-string ? */
141     vse                  = g_malloc(sizeof (value_string_ext));
142     vse->_vs_p           = vs;
143     vse->_vs_num_entries = vs_tot_num_entries - 1; /* remember the actual number of entries */
144     vse->_vs_first_value = 0;                      /* initialized in _match_strval_ext_init */
145     vse->_vs_match       = (_value_string_match_t) _match_strval_ext_init;
146     vse->_vs_name        = vs_name;
147     return vse;
148 }
149
150 /* Looks up val in a value_string array using access method (direct, binary search
151  *  or linear) determined at rutime during the initial access); (see _match_strval_ext_init)
152  * Returns the associated string ptr on a match, and returns NULL on failure.
153  */
154 const gchar*
155 match_strval_ext(const guint32 val, const value_string_ext *vse) {
156     if (vse)
157       return vse->_vs_match(val, vse);
158     return NULL;
159 }
160
161 /* Similar to match_strval_ext except that on failure
162  * Formats val with fmt, and returns the resulting string
163  */
164 const gchar*
165 val_to_str_ext(const guint32 val, const value_string_ext *vse, const char *fmt) {
166   const gchar *ret;
167
168   g_assert(fmt != NULL);
169
170   ret = match_strval_ext(val, vse);
171   if (ret != NULL)
172     return ret;
173
174   return ep_strdup_printf(fmt, val);
175 }
176
177 /* Similar to match_strval_ext except that on failure
178  *  Returns 'unknown_str'
179  */
180 const gchar*
181 val_to_str_ext_const(const guint32 val, const value_string_ext *vse, const char *unknown_str) {
182   const gchar *ret;
183
184   g_assert(unknown_str != NULL);
185
186   ret = match_strval_ext(val, vse);
187   if (ret != NULL)
188     return ret;
189
190   return unknown_str;
191 }
192
193 static const gchar *
194 _match_strval_linear(const guint32 val, const value_string_ext *vse)
195 {
196   const value_string *vs_p = vse->_vs_p;
197   guint i;
198   for (i=0; i<vse->_vs_num_entries; i++) {
199     if (vs_p[i].value == val) {
200       return vs_p[i].strptr;
201     }
202   }
203   return NULL;
204 }
205
206 static const gchar *
207 _match_strval_index(const guint32 val, const value_string_ext *vse)
208 {
209   if ((val - vse->_vs_first_value) < vse->_vs_num_entries) {
210     g_assert (val == vse->_vs_p[val - vse->_vs_first_value].value);
211     return vse->_vs_p[val - vse->_vs_first_value].strptr;
212   }
213   return NULL;
214 }
215
216 static const gchar *
217 _match_strval_bsearch(const guint32 val, const value_string_ext *vse)
218 {
219   guint low, idx, max;
220   guint32 item;
221
222   for (low = 0, max = vse->_vs_num_entries; low < max; ) {
223     idx = (low + max) / 2;
224     item = vse->_vs_p[idx].value;
225
226     if (val < item)
227       max = idx;
228     else if (val > item)
229       low = idx + 1;
230     else
231       return vse->_vs_p[idx].strptr;
232   }
233   return NULL;
234 }
235
236 /* Init value_string_ext struct
237    - Go thru the value_string array to determine whether indexed access
238       or binary search access is possible;
239    - Verify that the value_string array does not contain any
240       NULL string pointers;
241    - Verify that the value_string array is terminated
242       by {0, NULL};
243 */
244 const gchar *
245 _match_strval_ext_init(const guint32 val, value_string_ext *vse)
246 {
247   const value_string *vs_p           = vse->_vs_p;
248   const guint         vs_num_entries = vse->_vs_num_entries;
249
250 /* The way matching of value is done in a value_string:
251  * 0 Sequential search (as in a normal value string)
252  * 1 Binary search, the values MUST be in numerical order.
253  * 2 The value used as an index(the value string MUST have all values between first and last defined in numerical order)
254  */
255   enum { VS_SEARCH = 0, VS_BIN_TREE, VS_INDEX } type = VS_INDEX;
256
257   guint32 prev_value;
258   guint   first_value;
259   guint   i;
260
261   g_assert((vs_p[vs_num_entries].value==0) && (vs_p[vs_num_entries].strptr==NULL));
262
263   vse->_vs_first_value = vs_p[0].value;
264   first_value          = vs_p[0].value;
265   prev_value           = first_value;
266
267   for (i = 0; i < vs_num_entries; i++) {
268     g_assert(vs_p[i].strptr != NULL);
269     if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) {
270       type = VS_BIN_TREE;
271     }
272     /* XXX: Should check for dups ?? */
273     if ((type == VS_BIN_TREE) && (prev_value > vs_p[i].value)) {
274       type = VS_SEARCH;
275       break;
276     }
277
278     prev_value = vs_p[i].value;
279   }
280
281   switch (type) {
282   case VS_SEARCH:
283     vse->_vs_match = _match_strval_linear;
284     g_warning("Extended value string: %s not sorted; accessing linearly (%0x/%0x)",
285               vse->_vs_name, prev_value, vs_p[i].value);
286     break;
287   case VS_BIN_TREE:
288     vse->_vs_match = _match_strval_bsearch;
289     break;
290   case VS_INDEX:
291     vse->_vs_match = _match_strval_index;
292     break;
293   default:
294     g_assert_not_reached();
295     break;
296   }
297
298   return vse->_vs_match(val, vse);
299 }
300 /* ----------- */
301
302 /* Tries to match val against each element in the value_string array vs.
303    Returns the associated string ptr on a match.
304    Formats val with fmt, and returns the resulting string, on failure. */
305 const gchar*
306 str_to_str(const gchar *val, const string_string *vs, const char *fmt) {
307   const gchar *ret;
308
309   g_assert(fmt != NULL);
310
311   ret = match_strstr(val, vs);
312   if (ret != NULL)
313     return ret;
314
315   return ep_strdup_printf(fmt, val);
316 }
317
318 /* Tries to match val against each element in the value_string array vs.
319    Returns the associated string ptr, and sets "*idx" to the index in
320    that table, on a match, and returns NULL, and sets "*idx" to -1,
321    on failure. */
322 const gchar*
323 match_strstr_idx(const gchar *val, const string_string *vs, gint *idx) {
324   gint i = 0;
325
326   if(vs) {
327     while (vs[i].strptr) {
328       if (!strcmp(vs[i].value,val)) {
329         *idx = i;
330         return(vs[i].strptr);
331       }
332       i++;
333     }
334   }
335
336   *idx = -1;
337   return NULL;
338 }
339
340 /* Like match_strval_idx(), but doesn't return the index. */
341 const gchar*
342 match_strstr(const gchar *val, const string_string *vs) {
343     gint ignore_me;
344     return match_strstr_idx(val, vs, &ignore_me);
345 }
346
347 /* Generate a string describing an enumerated bitfield (an N-bit field
348    with various specific values having particular names). */
349 const char *
350 decode_enumerated_bitfield(const guint32 val, const guint32 mask, const int width,
351     const value_string *tab, const char *fmt)
352 {
353   static char buf[1025];
354   char *p;
355
356   p = decode_bitfield_value(buf, val, mask, width);
357   g_snprintf(p, (gulong) (1024-(p-buf)), fmt, val_to_str(val & mask, tab, "Unknown"));
358   return buf;
359 }
360
361
362 /* Generate a string describing an enumerated bitfield (an N-bit field
363    with various specific values having particular names). */
364 const char *
365 decode_enumerated_bitfield_shifted(const guint32 val, const guint32 mask, const int width,
366     const value_string *tab, const char *fmt)
367 {
368   static char buf[1025];
369   char *p;
370   int shift = 0;
371
372   /* Compute the number of bits we have to shift the bitfield right
373      to extract its value. */
374   while ((mask & (1<<shift)) == 0)
375     shift++;
376
377   p = decode_bitfield_value(buf, val, mask, width);
378   g_snprintf(p, (gulong) (1024-(p-buf)), fmt, val_to_str((val & mask) >> shift, tab, "Unknown"));
379   return buf;
380 }
381
382
383 /* FF: ranges aware versions */
384
385 /* Tries to match val against each range in the range_string array rs.
386    Returns the associated string ptr on a match.
387    Formats val with fmt, and returns the resulting string, on failure. */
388 const gchar *rval_to_str(const guint32 val, const range_string *rs, const char *fmt) 
389 {
390   const gchar *ret = NULL;
391
392   g_assert(fmt != NULL);
393
394   ret = match_strrval(val, rs);
395   if(ret != NULL)
396     return ret;
397
398   return ep_strdup_printf(fmt, val);
399 }
400
401 /* Tries to match val against each range in the range_string array rs.
402    Returns the associated string ptr, and sets "*idx" to the index in
403    that table, on a match, and returns NULL, and sets "*idx" to -1,
404    on failure. */
405 const gchar *match_strrval_idx(const guint32 val, const range_string *rs, gint *idx)
406 {
407   gint i = 0;
408
409   if(rs) {
410     while(rs[i].strptr) {
411       if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) {
412         *idx = i;
413         return (rs[i].strptr);
414       }
415       i++;
416     }
417   }
418
419   *idx = -1;
420   return NULL;
421 }
422
423 /* Like match_strrval_idx(), but doesn't return the index. */
424 const gchar *match_strrval(const guint32 val, const range_string *rs)
425 {
426     gint ignore_me = 0;
427     return match_strrval_idx(val, rs, &ignore_me);
428 }
429