/src/wireshark/wsutil/value_string.c
Line | Count | Source |
1 | | /* value_string.c |
2 | | * Routines for value_strings |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | 0 | #define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL |
13 | | |
14 | | #include <stdio.h> |
15 | | #include <string.h> |
16 | | |
17 | | #include "to_str.h" |
18 | | #include "value_string.h" |
19 | | #include <wsutil/ws_assert.h> |
20 | | |
21 | | #include <wsutil/wslog.h> |
22 | | |
23 | | /* |
24 | | * List of registered value strings for use outside of dissectors |
25 | | */ |
26 | | static GHashTable* registered_vs; |
27 | | static GHashTable* registered_vs_ext; |
28 | | |
29 | | |
30 | | /* Sort function that can be used with dynamically created value_strings */ |
31 | | int |
32 | | value_str_value_compare(const void* a, const void* b) |
33 | 0 | { |
34 | 0 | const value_string* vsa = (const value_string*)a; |
35 | 0 | const value_string* vsb = (const value_string*)b; |
36 | |
|
37 | 0 | if (vsa->value > vsb->value) |
38 | 0 | return 1; |
39 | 0 | if (vsa->value < vsb->value) |
40 | 0 | return -1; |
41 | | |
42 | 0 | return 0; |
43 | 0 | } |
44 | | |
45 | | /* REGULAR VALUE STRING */ |
46 | | |
47 | | /* Tries to match val against each element in the value_string array vs. |
48 | | Returns the associated string ptr on a match. |
49 | | Formats val with fmt, and returns the resulting string, on failure. */ |
50 | | char * |
51 | | val_to_str(wmem_allocator_t *scope, const uint32_t val, const value_string *vs, const char *fmt) |
52 | 12.0M | { |
53 | 12.0M | const char *ret; |
54 | | |
55 | 12.0M | ret = try_val_to_str(val, vs); |
56 | 12.0M | if (ret != NULL) |
57 | 11.8M | return wmem_strdup(scope, ret); |
58 | | |
59 | | //Programming error check |
60 | 224k | if (fmt == NULL) |
61 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
62 | | |
63 | 224k | return wmem_strdup_printf(scope, fmt, val); |
64 | 224k | } |
65 | | |
66 | | /* Tries to match val against each element in the value_string array vs. |
67 | | Returns the associated string ptr on a match. |
68 | | Returns 'unknown_str', on failure. */ |
69 | | const char * |
70 | | val_to_str_const(const uint32_t val, const value_string *vs, const char *unknown_str) |
71 | 12.2M | { |
72 | 12.2M | const char *ret; |
73 | | |
74 | 12.2M | ret = try_val_to_str(val, vs); |
75 | 12.2M | if (ret != NULL) |
76 | 11.7M | return ret; |
77 | | |
78 | | //Programming error check |
79 | 498k | if (unknown_str == NULL) |
80 | 0 | return "(invalid argument: unknown_str cannot be NULL)"; |
81 | | |
82 | 498k | return unknown_str; |
83 | 498k | } |
84 | | |
85 | | /* Tries to match val against each element in the value_string array vs. |
86 | | Returns the associated string ptr, and sets "*idx" to the index in |
87 | | that table, on a match, and returns NULL, and sets "*idx" to -1, |
88 | | on failure. */ |
89 | | const char * |
90 | | try_val_to_str_idx(const uint32_t val, const value_string *vs, int *idx) |
91 | 24.9M | { |
92 | 24.9M | int i = 0; |
93 | | |
94 | 24.9M | if(vs) { |
95 | 144M | while (vs[i].strptr) { |
96 | 143M | if (vs[i].value == val) { |
97 | 24.1M | if (idx != NULL) |
98 | 17.8k | *idx = i; |
99 | 24.1M | return(vs[i].strptr); |
100 | 24.1M | } |
101 | 119M | i++; |
102 | 119M | } |
103 | 24.9M | } |
104 | | |
105 | 791k | if (idx != NULL) |
106 | 17.4k | *idx = -1; |
107 | 791k | return NULL; |
108 | 24.9M | } |
109 | | |
110 | | /* Like try_val_to_str_idx(), but doesn't return the index. */ |
111 | | const char * |
112 | | try_val_to_str(const uint32_t val, const value_string *vs) |
113 | 24.9M | { |
114 | 24.9M | return try_val_to_str_idx(val, vs, NULL); |
115 | 24.9M | } |
116 | | |
117 | | /* 64-BIT VALUE STRING */ |
118 | | |
119 | | const char * |
120 | | val64_to_str_wmem(wmem_allocator_t* scope, const uint64_t val, const val64_string *vs, const char *fmt) |
121 | 2.16k | { |
122 | 2.16k | const char *ret; |
123 | | |
124 | 2.16k | ret = try_val64_to_str(val, vs); |
125 | 2.16k | if (ret != NULL) |
126 | 1.26k | return ret; |
127 | | |
128 | | //Programming error check |
129 | 900 | if (fmt == NULL) |
130 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
131 | | |
132 | 900 | return wmem_strdup_printf(scope, fmt, val); |
133 | 900 | } |
134 | | |
135 | | const char * |
136 | | val64_to_str_const(const uint64_t val, const val64_string *vs, const char *unknown_str) |
137 | 2.23k | { |
138 | 2.23k | const char *ret; |
139 | | |
140 | 2.23k | ret = try_val64_to_str(val, vs); |
141 | 2.23k | if (ret != NULL) |
142 | 1.00k | return ret; |
143 | | |
144 | | //Programming error check |
145 | 1.23k | if (unknown_str == NULL) |
146 | 0 | return "(invalid argument: unknown_str cannot be NULL)"; |
147 | | |
148 | 1.23k | return unknown_str; |
149 | 1.23k | } |
150 | | |
151 | | const char * |
152 | | try_val64_to_str_idx(const uint64_t val, const val64_string *vs, int *idx) |
153 | 4.88k | { |
154 | 4.88k | int i = 0; |
155 | | |
156 | 4.88k | if(vs) { |
157 | 95.5k | while (vs[i].strptr) { |
158 | 92.8k | if (vs[i].value == val) { |
159 | 2.26k | if (idx != NULL) |
160 | 0 | *idx = i; |
161 | 2.26k | return(vs[i].strptr); |
162 | 2.26k | } |
163 | 90.6k | i++; |
164 | 90.6k | } |
165 | 4.88k | } |
166 | | |
167 | 2.61k | if (idx != NULL) |
168 | 0 | *idx = -1; |
169 | 2.61k | return NULL; |
170 | 4.88k | } |
171 | | |
172 | | const char * |
173 | | try_val64_to_str(const uint64_t val, const val64_string *vs) |
174 | 4.88k | { |
175 | 4.88k | return try_val64_to_str_idx(val, vs, NULL); |
176 | 4.88k | } |
177 | | |
178 | | /* REVERSE VALUE STRING */ |
179 | | |
180 | | /* We use the same struct as for regular value strings, but we look up strings |
181 | | * and return values instead */ |
182 | | |
183 | | /* Like val_to_str except backwards */ |
184 | | uint32_t |
185 | | str_to_val(const char *val, const value_string *vs, const uint32_t err_val) |
186 | 4.60k | { |
187 | 4.60k | int i; |
188 | | |
189 | 4.60k | i = str_to_val_idx(val, vs); |
190 | | |
191 | 4.60k | if (i >= 0) { |
192 | 645 | return vs[i].value; |
193 | 645 | } |
194 | | |
195 | 3.96k | return err_val; |
196 | 4.60k | } |
197 | | |
198 | | /* Find the index of a string in a value_string, or -1 when not present */ |
199 | | int |
200 | | str_to_val_idx(const char *val, const value_string *vs) |
201 | 4.60k | { |
202 | 4.60k | int i = 0; |
203 | | |
204 | 4.60k | if(vs) { |
205 | | |
206 | 144k | while (vs[i].strptr) { |
207 | | |
208 | 140k | if (strcmp(vs[i].strptr, val) == 0) { |
209 | 645 | return i; |
210 | 645 | } |
211 | | |
212 | 139k | i++; |
213 | 139k | } |
214 | | |
215 | 4.60k | } |
216 | | |
217 | 3.96k | return -1; |
218 | 4.60k | } |
219 | | |
220 | | /* EXTENDED VALUE STRING */ |
221 | | |
222 | | /* Extended value strings allow fast(er) value_string array lookups by |
223 | | * using (if possible) direct access or a binary search of the array. |
224 | | * |
225 | | * If the values in the value_string array are a contiguous range of values |
226 | | * from min to max, the value will be used as a direct index into the array. |
227 | | * |
228 | | * If the values in the array are not contiguous (ie: there are "gaps"), |
229 | | * but are in assending order a binary search will be used. |
230 | | * |
231 | | * If direct access or binary search cannot be used, then a linear search |
232 | | * is used and a warning is emitted. |
233 | | * |
234 | | * Note that the value_string array used with VALUE_STRING_EXT_INIT |
235 | | * *must* be terminated with {0, NULL}). |
236 | | * |
237 | | * Extended value strings are defined at compile time as follows: |
238 | | * static const value_string vs[] = { {value1, "string1"}, |
239 | | * {value2, "string2"}, |
240 | | * ..., |
241 | | * {0, NULL}}; |
242 | | * static value_string_ext vse = VALUE_STRING_EXT_INIT(vs); |
243 | | * |
244 | | * Extended value strings can be created at runtime by calling |
245 | | * value_string_ext_new(<ptr to value_string array>, |
246 | | * <total number of entries in the value_string_array>, |
247 | | * <value_string_name>); |
248 | | * Note: The <total number of entries in the value_string_array> should include |
249 | | * the {0, NULL} entry. |
250 | | */ |
251 | | |
252 | | /* Create a value_string_ext given a ptr to a value_string array and the total |
253 | | * number of entries. Note that the total number of entries should include the |
254 | | * required {0, NULL} terminating entry of the array. |
255 | | * Returns a pointer to an epan-scoped'd and initialized value_string_ext |
256 | | * struct. */ |
257 | | value_string_ext * |
258 | | value_string_ext_new(wmem_allocator_t* scope, const value_string *vs, unsigned vs_tot_num_entries, const char *vs_name) |
259 | 5 | { |
260 | 5 | value_string_ext *vse; |
261 | | |
262 | 5 | ws_return_val_if((vs_name == NULL), NULL); |
263 | 5 | ws_return_val_if((vs_tot_num_entries == 0), NULL); |
264 | 5 | ws_return_val_if((vs[vs_tot_num_entries - 1].strptr != NULL), NULL); |
265 | | |
266 | 5 | vse = wmem_new(scope, value_string_ext); |
267 | 5 | vse->_vs_p = vs; |
268 | 5 | vse->_vs_num_entries = vs_tot_num_entries - 1; |
269 | | /* We set our 'match' function to the init function, which finishes by |
270 | | * setting the match function properly and then calling it. This is a |
271 | | * simple way to do lazy initialization of extended value strings. |
272 | | * The init function also sets up _vs_first_value for us. */ |
273 | 5 | vse->_vs_first_value = 0; |
274 | 5 | vse->_vs_match2 = _try_val_to_str_ext_init; |
275 | 5 | vse->_vs_name = vs_name; |
276 | 5 | vse->_scope = scope; |
277 | | |
278 | 5 | return vse; |
279 | 5 | } |
280 | | |
281 | | void |
282 | | value_string_ext_free(value_string_ext *vse) |
283 | 0 | { |
284 | 0 | wmem_free(vse->_scope, vse); |
285 | 0 | } |
286 | | |
287 | | /* Like try_val_to_str for extended value strings */ |
288 | | const char * |
289 | | try_val_to_str_ext(const uint32_t val, value_string_ext *vse) |
290 | 864k | { |
291 | 864k | if (vse) { |
292 | 864k | const value_string *vs = vse->_vs_match2(val, vse); |
293 | | |
294 | 864k | if (vs) { |
295 | 506k | return vs->strptr; |
296 | 506k | } |
297 | 864k | } |
298 | | |
299 | 358k | return NULL; |
300 | 864k | } |
301 | | |
302 | | /* Like try_val_to_str_idx for extended value strings */ |
303 | | const char * |
304 | | try_val_to_str_idx_ext(const uint32_t val, value_string_ext *vse, int *idx) |
305 | 1.92k | { |
306 | 1.92k | if (vse) { |
307 | 1.92k | const value_string *vs = vse->_vs_match2(val, vse); |
308 | 1.92k | if (vs) { |
309 | 1.84k | *idx = (int) (vs - vse->_vs_p); |
310 | 1.84k | return vs->strptr; |
311 | 1.84k | } |
312 | 1.92k | } |
313 | 79 | *idx = -1; |
314 | 79 | return NULL; |
315 | 1.92k | } |
316 | | |
317 | | /* Like val_to_str for extended value strings */ |
318 | | char * |
319 | | val_to_str_ext(wmem_allocator_t *scope, const uint32_t val, value_string_ext *vse, const char *fmt) |
320 | 460k | { |
321 | 460k | const char *ret; |
322 | | |
323 | 460k | ret = try_val_to_str_ext(val, vse); |
324 | 460k | if (ret != NULL) |
325 | 309k | return wmem_strdup(scope, ret); |
326 | | |
327 | 151k | if (fmt == NULL) |
328 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
329 | | |
330 | 151k | return wmem_strdup_printf(scope, fmt, val); |
331 | 151k | } |
332 | | |
333 | | /* Like val_to_str_const for extended value strings */ |
334 | | const char * |
335 | | val_to_str_ext_const(const uint32_t val, value_string_ext *vse, |
336 | | const char *unknown_str) |
337 | 350k | { |
338 | 350k | const char *ret; |
339 | | |
340 | 350k | ret = try_val_to_str_ext(val, vse); |
341 | 350k | if (ret != NULL) |
342 | 168k | return ret; |
343 | | |
344 | 182k | if (unknown_str == NULL) |
345 | 0 | return "unknown_str cannot be NULL"; |
346 | | |
347 | 182k | return unknown_str; |
348 | 182k | } |
349 | | |
350 | | /* Fallback linear matching algorithm for extended value strings */ |
351 | | static const value_string * |
352 | | _try_val_to_str_linear(const uint32_t val, value_string_ext *vse) |
353 | 0 | { |
354 | 0 | const value_string *vs_p = vse->_vs_p; |
355 | 0 | unsigned i; |
356 | 0 | for (i=0; i<vse->_vs_num_entries; i++) { |
357 | 0 | if (vs_p[i].value == val) |
358 | 0 | return &(vs_p[i]); |
359 | 0 | } |
360 | 0 | return NULL; |
361 | 0 | } |
362 | | |
363 | | /* Constant-time matching algorithm for contiguous extended value strings */ |
364 | | static const value_string * |
365 | | _try_val_to_str_index(const uint32_t val, value_string_ext *vse) |
366 | 224k | { |
367 | 224k | uint32_t i; |
368 | | |
369 | 224k | i = val - vse->_vs_first_value; |
370 | 224k | if (i < vse->_vs_num_entries) { |
371 | 173k | ws_assert (val == vse->_vs_p[i].value); |
372 | 173k | return &(vse->_vs_p[i]); |
373 | 173k | } |
374 | 50.2k | return NULL; |
375 | 224k | } |
376 | | |
377 | | /* Value comparator for sorted extended value strings */ |
378 | | static int |
379 | | val_to_str_compar(const void *v_needle, const void *v_item) |
380 | 4.14M | { |
381 | 4.14M | uint32_t needle = *(const uint32_t *)v_needle; |
382 | 4.14M | uint32_t value = ((const value_string *)v_item)->value; |
383 | 4.14M | return needle > value ? 1 : (needle < value ? -1 : 0); |
384 | 4.14M | } |
385 | | |
386 | | /* log(n)-time matching for sorted extended value strings */ |
387 | | static const value_string * |
388 | | _try_val_to_str_bsearch(const uint32_t val, value_string_ext *vse) |
389 | 642k | { |
390 | 642k | return bsearch(&val, vse->_vs_p, vse->_vs_num_entries, |
391 | 642k | sizeof vse->_vs_p[0], val_to_str_compar); |
392 | 642k | } |
393 | | |
394 | | /* Initializes an extended value string. Behaves like a match function to |
395 | | * permit lazy initialization of extended value strings. |
396 | | * - Goes through the value_string array to determine the fastest possible |
397 | | * access method. |
398 | | * - Verifies that the value_string contains no NULL string pointers. |
399 | | * - Verifies that the value_string is terminated by {0, NULL} |
400 | | */ |
401 | | const value_string * |
402 | | _try_val_to_str_ext_init(const uint32_t val, value_string_ext *vse) |
403 | 664 | { |
404 | 664 | const value_string *vs_p = vse->_vs_p; |
405 | 664 | const unsigned vs_num_entries = vse->_vs_num_entries; |
406 | | |
407 | | /* The matching algorithm used: |
408 | | * VS_LIN_SEARCH - slow linear search (as in a normal value string) |
409 | | * VS_BIN_SEARCH - log(n)-time binary search, the values must be sorted |
410 | | * VS_INDEX - constant-time index lookup, the values must be contiguous |
411 | | */ |
412 | 664 | enum { VS_LIN_SEARCH, VS_BIN_SEARCH, VS_INDEX } type = VS_INDEX; |
413 | | |
414 | | /* Note: The value_string 'value' is *unsigned*, but we do a little magic |
415 | | * to help with value strings that have negative values. |
416 | | * |
417 | | * { -3, -2, -1, 0, 1, 2 } |
418 | | * will be treated as "ascending ordered" (although it isn't technically), |
419 | | * thus allowing constant-time index search |
420 | | * |
421 | | * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } |
422 | | * will both be considered as "out-of-order with gaps", thus falling |
423 | | * back to the slow linear search |
424 | | * |
425 | | * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } |
426 | | * will be considered "ascending ordered with gaps" thus allowing |
427 | | * a log(n)-time 'binary' search |
428 | | * |
429 | | * If you're confused, think of how negative values are represented, or |
430 | | * google two's complement. |
431 | | */ |
432 | | |
433 | 664 | uint32_t prev_value; |
434 | 664 | uint32_t first_value; |
435 | 664 | unsigned i; |
436 | | |
437 | 664 | if ((vs_p[vs_num_entries].value != 0) || |
438 | 664 | (vs_p[vs_num_entries].strptr != NULL)) { |
439 | 0 | ws_warning("vse must end with {0, NULL}"); |
440 | 0 | return NULL; |
441 | 0 | } |
442 | | |
443 | 664 | vse->_vs_first_value = vs_p[0].value; |
444 | 664 | first_value = vs_p[0].value; |
445 | 664 | prev_value = first_value; |
446 | | |
447 | 1.01M | for (i = 0; i < vs_num_entries; i++) { |
448 | 1.01M | if (vs_p[i].strptr == NULL) |
449 | 1.01M | ws_warning("vse[%u].strptr cannot be NULL!", i); |
450 | 1.01M | if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { |
451 | 302 | type = VS_BIN_SEARCH; |
452 | 302 | } |
453 | | /* XXX: Should check for dups ?? */ |
454 | 1.01M | if (type == VS_BIN_SEARCH) { |
455 | 968k | if (prev_value > vs_p[i].value) { |
456 | 0 | ws_warning("Extended value string '%s' forced to fall back to linear search:\n" |
457 | 0 | " entry %u, value %u [%#x] < previous entry, value %u [%#x]", |
458 | 0 | vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value); |
459 | 0 | type = VS_LIN_SEARCH; |
460 | 0 | break; |
461 | 0 | } |
462 | 968k | if (first_value > vs_p[i].value) { |
463 | 0 | ws_warning("Extended value string '%s' forced to fall back to linear search:\n" |
464 | 0 | " entry %u, value %u [%#x] < first entry, value %u [%#x]", |
465 | 0 | vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value); |
466 | 0 | type = VS_LIN_SEARCH; |
467 | 0 | break; |
468 | 0 | } |
469 | 968k | } |
470 | | |
471 | 1.01M | prev_value = vs_p[i].value; |
472 | 1.01M | } |
473 | | |
474 | 664 | switch (type) { |
475 | 0 | case VS_LIN_SEARCH: |
476 | 0 | vse->_vs_match2 = _try_val_to_str_linear; |
477 | 0 | break; |
478 | 302 | case VS_BIN_SEARCH: |
479 | 302 | vse->_vs_match2 = _try_val_to_str_bsearch; |
480 | 302 | break; |
481 | 362 | case VS_INDEX: |
482 | 362 | vse->_vs_match2 = _try_val_to_str_index; |
483 | 362 | break; |
484 | 0 | default: |
485 | 0 | ws_assert_not_reached(); |
486 | 0 | break; |
487 | 664 | } |
488 | | |
489 | 664 | return vse->_vs_match2(val, vse); |
490 | 664 | } |
491 | | |
492 | | /* EXTENDED 64-BIT VALUE STRING */ |
493 | | |
494 | | /* Extended value strings allow fast(er) val64_string array lookups by |
495 | | * using (if possible) direct access or a binary search of the array. |
496 | | * |
497 | | * If the values in the val64_string array are a contiguous range of values |
498 | | * from min to max, the value will be used as a direct index into the array. |
499 | | * |
500 | | * If the values in the array are not contiguous (ie: there are "gaps"), |
501 | | * but are in assending order a binary search will be used. |
502 | | * |
503 | | * If direct access or binary search cannot be used, then a linear search |
504 | | * is used and a warning is emitted. |
505 | | * |
506 | | * Note that the val64_string array used with VAL64_STRING_EXT_INIT |
507 | | * *must* be terminated with {0, NULL}). |
508 | | * |
509 | | * Extended value strings are defined at compile time as follows: |
510 | | * static const val64_string vs[] = { {value1, "string1"}, |
511 | | * {value2, "string2"}, |
512 | | * ..., |
513 | | * {0, NULL}}; |
514 | | * static val64_string_ext vse = VAL64_STRING_EXT_INIT(vs); |
515 | | * |
516 | | * Extended value strings can be created at runtime by calling |
517 | | * val64_string_ext_new(<ptr to val64_string array>, |
518 | | * <total number of entries in the val64_string_array>, |
519 | | * <val64_string_name>); |
520 | | * Note: The <total number of entries in the val64_string_array> should include |
521 | | * the {0, NULL} entry. |
522 | | */ |
523 | | |
524 | | /* Create a val64_string_ext given a ptr to a val64_string array and the total |
525 | | * number of entries. Note that the total number of entries should include the |
526 | | * required {0, NULL} terminating entry of the array. |
527 | | * Returns a pointer to an epan-scoped'd and initialized val64_string_ext |
528 | | * struct. */ |
529 | | val64_string_ext * |
530 | | val64_string_ext_new(wmem_allocator_t* scope, const val64_string *vs, unsigned vs_tot_num_entries, const char *vs_name) |
531 | 0 | { |
532 | 0 | val64_string_ext *vse; |
533 | |
|
534 | 0 | ws_return_val_if((vs_name == NULL), NULL); |
535 | 0 | ws_return_val_if((vs_tot_num_entries == 0), NULL); |
536 | 0 | ws_return_val_if((vs[vs_tot_num_entries - 1].strptr != NULL), NULL); |
537 | | |
538 | 0 | vse = wmem_new(NULL, val64_string_ext); |
539 | 0 | vse->_vs_p = vs; |
540 | 0 | vse->_vs_num_entries = vs_tot_num_entries - 1; |
541 | | /* We set our 'match' function to the init function, which finishes by |
542 | | * setting the match function properly and then calling it. This is a |
543 | | * simple way to do lazy initialization of extended value strings. |
544 | | * The init function also sets up _vs_first_value for us. */ |
545 | 0 | vse->_vs_first_value = 0; |
546 | 0 | vse->_vs_match2 = _try_val64_to_str_ext_init; |
547 | 0 | vse->_vs_name = vs_name; |
548 | 0 | vse->_scope = scope; |
549 | |
|
550 | 0 | return vse; |
551 | 0 | } |
552 | | |
553 | | void |
554 | | val64_string_ext_free(val64_string_ext *vse) |
555 | 0 | { |
556 | 0 | wmem_free(vse->_scope, vse); |
557 | 0 | } |
558 | | |
559 | | /* Like try_val_to_str for extended value strings */ |
560 | | const char * |
561 | | try_val64_to_str_ext(const uint64_t val, val64_string_ext *vse) |
562 | 4 | { |
563 | 4 | if (vse) { |
564 | 4 | const val64_string *vs = vse->_vs_match2(val, vse); |
565 | | |
566 | 4 | if (vs) { |
567 | 3 | return vs->strptr; |
568 | 3 | } |
569 | 4 | } |
570 | | |
571 | 1 | return NULL; |
572 | 4 | } |
573 | | |
574 | | /* Like try_val_to_str_idx for extended value strings */ |
575 | | const char * |
576 | | try_val64_to_str_idx_ext(const uint64_t val, val64_string_ext *vse, int *idx) |
577 | 0 | { |
578 | 0 | if (vse) { |
579 | 0 | const val64_string *vs = vse->_vs_match2(val, vse); |
580 | 0 | if (vs) { |
581 | 0 | *idx = (int) (vs - vse->_vs_p); |
582 | 0 | return vs->strptr; |
583 | 0 | } |
584 | 0 | } |
585 | 0 | *idx = -1; |
586 | 0 | return NULL; |
587 | 0 | } |
588 | | |
589 | | char * |
590 | | val64_to_str_ext_wmem(wmem_allocator_t *scope, const uint64_t val, val64_string_ext *vse, const char *fmt) |
591 | 4 | { |
592 | 4 | const char *ret; |
593 | | |
594 | 4 | ret = try_val64_to_str_ext(val, vse); |
595 | 4 | if (ret != NULL) |
596 | 3 | return wmem_strdup(scope, ret); |
597 | | |
598 | 1 | if (fmt == NULL) |
599 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
600 | | |
601 | 1 | return wmem_strdup_printf(scope, fmt, val); |
602 | 1 | } |
603 | | |
604 | | /* Like val_to_str_const for extended value strings */ |
605 | | const char * |
606 | | val64_to_str_ext_const(const uint64_t val, val64_string_ext *vse, |
607 | | const char *unknown_str) |
608 | 0 | { |
609 | 0 | const char *ret; |
610 | |
|
611 | 0 | ret = try_val64_to_str_ext(val, vse); |
612 | 0 | if (ret != NULL) |
613 | 0 | return ret; |
614 | | |
615 | 0 | if (unknown_str == NULL) |
616 | 0 | return "unknown_str cannot be NULL"; |
617 | | |
618 | 0 | return unknown_str; |
619 | 0 | } |
620 | | |
621 | | /* Fallback linear matching algorithm for extended value strings */ |
622 | | static const val64_string * |
623 | | _try_val64_to_str_linear(const uint64_t val, val64_string_ext *vse) |
624 | 0 | { |
625 | 0 | const val64_string *vs_p = vse->_vs_p; |
626 | 0 | unsigned i; |
627 | 0 | for (i=0; i<vse->_vs_num_entries; i++) { |
628 | 0 | if (vs_p[i].value == val) |
629 | 0 | return &(vs_p[i]); |
630 | 0 | } |
631 | 0 | return NULL; |
632 | 0 | } |
633 | | |
634 | | /* Constant-time matching algorithm for contiguous extended value strings */ |
635 | | static const val64_string * |
636 | | _try_val64_to_str_index(const uint64_t val, val64_string_ext *vse) |
637 | 0 | { |
638 | 0 | uint64_t i; |
639 | |
|
640 | 0 | i = val - vse->_vs_first_value; |
641 | 0 | if (i < vse->_vs_num_entries) { |
642 | 0 | ws_assert (val == vse->_vs_p[i].value); |
643 | 0 | return &(vse->_vs_p[i]); |
644 | 0 | } |
645 | 0 | return NULL; |
646 | 0 | } |
647 | | |
648 | | /* Value comparator for sorted extended value strings */ |
649 | | static int |
650 | | val64_to_str_compar(const void *v_needle, const void *v_item) |
651 | 20 | { |
652 | 20 | uint64_t needle = *(const uint64_t *)v_needle; |
653 | 20 | uint64_t value = ((const val64_string *)v_item)->value; |
654 | 20 | return needle > value ? 1 : (needle < value ? -1 : 0); |
655 | 20 | } |
656 | | |
657 | | /* log(n)-time matching for sorted extended value strings */ |
658 | | static const val64_string * |
659 | | _try_val64_to_str_bsearch(const uint64_t val, val64_string_ext *vse) |
660 | 4 | { |
661 | 4 | return bsearch(&val, vse->_vs_p, vse->_vs_num_entries, |
662 | 4 | sizeof vse->_vs_p[0], val64_to_str_compar); |
663 | 4 | } |
664 | | |
665 | | /* Initializes an extended value string. Behaves like a match function to |
666 | | * permit lazy initialization of extended value strings. |
667 | | * - Goes through the val64_string array to determine the fastest possible |
668 | | * access method. |
669 | | * - Verifies that the val64_string contains no NULL string pointers. |
670 | | * - Verifies that the val64_string is terminated by {0, NULL} |
671 | | */ |
672 | | const val64_string * |
673 | | _try_val64_to_str_ext_init(const uint64_t val, val64_string_ext *vse) |
674 | 1 | { |
675 | 1 | const val64_string *vs_p = vse->_vs_p; |
676 | 1 | const unsigned vs_num_entries = vse->_vs_num_entries; |
677 | | |
678 | | /* The matching algorithm used: |
679 | | * VS_LIN_SEARCH - slow linear search (as in a normal value string) |
680 | | * VS_BIN_SEARCH - log(n)-time binary search, the values must be sorted |
681 | | * VS_INDEX - constant-time index lookup, the values must be contiguous |
682 | | */ |
683 | 1 | enum { VS_LIN_SEARCH, VS_BIN_SEARCH, VS_INDEX } type = VS_INDEX; |
684 | | |
685 | | /* Note: The val64_string 'value' is *unsigned*, but we do a little magic |
686 | | * to help with value strings that have negative values. |
687 | | * |
688 | | * { -3, -2, -1, 0, 1, 2 } |
689 | | * will be treated as "ascending ordered" (although it isn't technically), |
690 | | * thus allowing constant-time index search |
691 | | * |
692 | | * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } |
693 | | * will both be considered as "out-of-order with gaps", thus falling |
694 | | * back to the slow linear search |
695 | | * |
696 | | * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } |
697 | | * will be considered "ascending ordered with gaps" thus allowing |
698 | | * a log(n)-time 'binary' search |
699 | | * |
700 | | * If you're confused, think of how negative values are represented, or |
701 | | * google two's complement. |
702 | | */ |
703 | | |
704 | 1 | uint64_t prev_value; |
705 | 1 | uint64_t first_value; |
706 | 1 | unsigned i; |
707 | | |
708 | 1 | if ((vs_p[vs_num_entries].value != 0) || |
709 | 1 | (vs_p[vs_num_entries].strptr != NULL)) { |
710 | 0 | ws_warning("vse must end with {0, NULL}"); |
711 | 0 | return NULL; |
712 | 0 | } |
713 | | |
714 | 1 | vse->_vs_first_value = vs_p[0].value; |
715 | 1 | first_value = vs_p[0].value; |
716 | 1 | prev_value = first_value; |
717 | | |
718 | 31 | for (i = 0; i < vs_num_entries; i++) { |
719 | 30 | if (vs_p[i].strptr == NULL) |
720 | 30 | ws_warning("vse[%u].strptr cannot be NULL!", i); |
721 | 30 | if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { |
722 | 1 | type = VS_BIN_SEARCH; |
723 | 1 | } |
724 | | /* XXX: Should check for dups ?? */ |
725 | 30 | if (type == VS_BIN_SEARCH) { |
726 | 28 | if (prev_value > vs_p[i].value) { |
727 | 0 | ws_warning("Extended value string '%s' forced to fall back to linear search:\n" |
728 | 0 | " entry %u, value %" PRIu64 " [%#" PRIx64 "] < previous entry, value %" PRIu64 " [%#" PRIx64 "]", |
729 | 0 | vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value); |
730 | 0 | type = VS_LIN_SEARCH; |
731 | 0 | break; |
732 | 0 | } |
733 | 28 | if (first_value > vs_p[i].value) { |
734 | 0 | ws_warning("Extended value string '%s' forced to fall back to linear search:\n" |
735 | 0 | " entry %u, value %" PRIu64 " [%#" PRIx64 "] < first entry, value %" PRIu64 " [%#" PRIx64 "]", |
736 | 0 | vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value); |
737 | 0 | type = VS_LIN_SEARCH; |
738 | 0 | break; |
739 | 0 | } |
740 | 28 | } |
741 | | |
742 | 30 | prev_value = vs_p[i].value; |
743 | 30 | } |
744 | | |
745 | 1 | switch (type) { |
746 | 0 | case VS_LIN_SEARCH: |
747 | 0 | vse->_vs_match2 = _try_val64_to_str_linear; |
748 | 0 | break; |
749 | 1 | case VS_BIN_SEARCH: |
750 | 1 | vse->_vs_match2 = _try_val64_to_str_bsearch; |
751 | 1 | break; |
752 | 0 | case VS_INDEX: |
753 | 0 | vse->_vs_match2 = _try_val64_to_str_index; |
754 | 0 | break; |
755 | 0 | default: |
756 | 0 | ws_assert_not_reached(); |
757 | 0 | break; |
758 | 1 | } |
759 | | |
760 | 1 | return vse->_vs_match2(val, vse); |
761 | 1 | } |
762 | | |
763 | | /* STRING TO STRING MATCHING */ |
764 | | |
765 | | /* string_string is like value_string except the values being matched are |
766 | | * also strings (instead of unsigned integers) */ |
767 | | |
768 | | /* Like val_to_str except for string_string */ |
769 | | const char * |
770 | | str_to_str_wmem(wmem_allocator_t* scope, const char *val, const string_string *vs, const char *fmt) |
771 | 772 | { |
772 | 772 | const char *ret; |
773 | | |
774 | 772 | ret = try_str_to_str(val, vs); |
775 | 772 | if (ret != NULL) |
776 | 66 | return ret; |
777 | | |
778 | 706 | if (fmt == NULL) |
779 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
780 | | |
781 | 706 | return wmem_strdup_printf(scope, fmt, val); |
782 | 706 | } |
783 | | |
784 | | /* Like try_val_to_str_idx except for string_string */ |
785 | | const char * |
786 | | try_str_to_str_idx(const char *val, const string_string *vs, int *idx) |
787 | 773 | { |
788 | 773 | int i = 0; |
789 | | |
790 | 773 | if(vs) { |
791 | 4.22k | while (vs[i].strptr) { |
792 | 3.51k | if (!strcmp(vs[i].value,val)) { |
793 | 66 | *idx = i; |
794 | 66 | return(vs[i].strptr); |
795 | 66 | } |
796 | 3.45k | i++; |
797 | 3.45k | } |
798 | 773 | } |
799 | | |
800 | 707 | *idx = -1; |
801 | 707 | return NULL; |
802 | 773 | } |
803 | | |
804 | | /* Like try_val_to_str except for string_string */ |
805 | | const char * |
806 | | try_str_to_str(const char *val, const string_string *vs) |
807 | 772 | { |
808 | 772 | int ignore_me; |
809 | 772 | return try_str_to_str_idx(val, vs, &ignore_me); |
810 | 772 | } |
811 | | |
812 | | /* RANGE TO STRING MATCHING */ |
813 | | |
814 | | /* range_string is like value_string except the values being matched are |
815 | | * integer ranges (for example, 0-10, 11-19, etc.) instead of single values. */ |
816 | | |
817 | | /* Like val_to_str except for range_string */ |
818 | | const char * |
819 | | rval_to_str_wmem(wmem_allocator_t* scope, const uint32_t val, const range_string *rs, const char *fmt) |
820 | 149 | { |
821 | 149 | const char *ret = NULL; |
822 | | |
823 | 149 | ret = try_rval_to_str(val, rs); |
824 | 149 | if(ret != NULL) |
825 | 142 | return ret; |
826 | | |
827 | 7 | if (fmt == NULL) |
828 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
829 | | |
830 | 7 | return wmem_strdup_printf(scope, fmt, val); |
831 | 7 | } |
832 | | |
833 | | /* Like val_to_str_const except for range_string */ |
834 | | const char * |
835 | | rval_to_str_const(const uint32_t val, const range_string *rs, |
836 | | const char *unknown_str) |
837 | 23.5k | { |
838 | 23.5k | const char *ret = NULL; |
839 | | |
840 | 23.5k | ret = try_rval_to_str(val, rs); |
841 | 23.5k | if(ret != NULL) |
842 | 14.4k | return ret; |
843 | | |
844 | 9.06k | if (unknown_str == NULL) |
845 | 0 | return "unknown_str cannot be NULL"; |
846 | | |
847 | 9.06k | return unknown_str; |
848 | 9.06k | } |
849 | | |
850 | | /* Like try_val_to_str_idx except for range_string */ |
851 | | const char * |
852 | | try_rval_to_str_idx(const uint32_t val, const range_string *rs, int *idx) |
853 | 37.9k | { |
854 | 37.9k | int i = 0; |
855 | | |
856 | 37.9k | if(rs) { |
857 | 710k | while(rs[i].strptr) { |
858 | 699k | if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) { |
859 | 27.5k | *idx = i; |
860 | 27.5k | return (rs[i].strptr); |
861 | 27.5k | } |
862 | 672k | i++; |
863 | 672k | } |
864 | 37.9k | } |
865 | | |
866 | 10.4k | *idx = -1; |
867 | 10.4k | return NULL; |
868 | 37.9k | } |
869 | | |
870 | | /* Like try_val_to_str except for range_string */ |
871 | | const char * |
872 | | try_rval_to_str(const uint32_t val, const range_string *rs) |
873 | 37.9k | { |
874 | 37.9k | int ignore_me = 0; |
875 | 37.9k | return try_rval_to_str_idx(val, rs, &ignore_me); |
876 | 37.9k | } |
877 | | |
878 | | /* Like try_val_to_str_idx except for range_string */ |
879 | | const char * |
880 | | try_rval64_to_str_idx(const uint64_t val, const range_string *rs, int *idx) |
881 | 0 | { |
882 | 0 | int i = 0; |
883 | |
|
884 | 0 | if(rs) { |
885 | 0 | while(rs[i].strptr) { |
886 | 0 | if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) { |
887 | 0 | *idx = i; |
888 | 0 | return (rs[i].strptr); |
889 | 0 | } |
890 | 0 | i++; |
891 | 0 | } |
892 | 0 | } |
893 | | |
894 | 0 | *idx = -1; |
895 | 0 | return NULL; |
896 | 0 | } |
897 | | |
898 | | /* Like try_val64_to_str except for range_string */ |
899 | | const char * |
900 | | try_rval64_to_str(const uint64_t val, const range_string *rs) |
901 | 0 | { |
902 | 0 | int ignore_me = 0; |
903 | 0 | return try_rval64_to_str_idx(val, rs, &ignore_me); |
904 | 0 | } |
905 | | |
906 | | /* TIME TO STRING MATCHING */ |
907 | | |
908 | | /* Tries to match val against each element in the value_string array vs. |
909 | | Returns the associated string ptr, and sets "*idx" to the index in |
910 | | that table, on a match, and returns NULL, and sets "*idx" to -1, |
911 | | on failure. */ |
912 | | const char * |
913 | | try_time_val_to_str(const nstime_t *val, const time_value_string *vs) |
914 | 0 | { |
915 | 0 | int i = 0; |
916 | |
|
917 | 0 | if(vs) { |
918 | 0 | while (vs[i].strptr) { |
919 | 0 | if (nstime_cmp(&vs[i].value, val) == 0) { |
920 | 0 | return(vs[i].strptr); |
921 | 0 | } |
922 | 0 | i++; |
923 | 0 | } |
924 | 0 | } |
925 | | |
926 | 0 | return NULL; |
927 | 0 | } |
928 | | |
929 | | /* BYTE BUFFER TO STRING MATCHING */ |
930 | | |
931 | | /* Like val_to_str except for bytes_string */ |
932 | | const char * |
933 | | bytesval_to_str_wmem(wmem_allocator_t* scope, const uint8_t *val, const size_t val_len, const bytes_string *bs, const char *fmt) |
934 | 25 | { |
935 | 25 | const char *ret; |
936 | | |
937 | 25 | ret = try_bytesval_to_str(val, val_len, bs); |
938 | 25 | if (ret != NULL) |
939 | 0 | return ret; |
940 | | |
941 | 25 | if (fmt == NULL) |
942 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
943 | | |
944 | | /* |
945 | | * XXX should this use bytes_to_str as format parameter for consistency? |
946 | | * Though for bytes I guess most of the time you want to show "Unknown" |
947 | | * anyway rather than "Unknown (\x13\x37...)" |
948 | | */ |
949 | 25 | return wmem_strdup(scope, fmt); |
950 | 25 | } |
951 | | |
952 | | /* Like try_val_to_str except for bytes_string */ |
953 | | const char * |
954 | | try_bytesval_to_str(const uint8_t *val, const size_t val_len, const bytes_string *bs) |
955 | 25 | { |
956 | 25 | unsigned i = 0; |
957 | | |
958 | 25 | if (bs) { |
959 | 4.70k | while (bs[i].strptr) { |
960 | 4.67k | if (bs[i].value_length == val_len && !memcmp(bs[i].value, val, val_len)) { |
961 | 0 | return bs[i].strptr; |
962 | 0 | } |
963 | 4.67k | i++; |
964 | 4.67k | } |
965 | 25 | } |
966 | | |
967 | 25 | return NULL; |
968 | 25 | } |
969 | | |
970 | | /* Like val_to_str, but tries to find a prefix (instead of an exact) match |
971 | | of any prefix from the bytes_string array bs against the haystack. */ |
972 | | const char * |
973 | | bytesprefix_to_str(wmem_allocator_t* scope, const uint8_t *haystack, const size_t haystack_len, const bytes_string *bs, const char *fmt) |
974 | 0 | { |
975 | 0 | const char *ret; |
976 | |
|
977 | 0 | ret = try_bytesprefix_to_str(haystack, haystack_len, bs); |
978 | 0 | if (ret != NULL) |
979 | 0 | return ret; |
980 | | |
981 | 0 | if (fmt == NULL) |
982 | 0 | return wmem_strdup(scope, "(invalid argument: fmt cannot be NULL)"); |
983 | | |
984 | | /* XXX See note at bytesval_to_str. */ |
985 | 0 | return wmem_strdup(scope, fmt); |
986 | 0 | } |
987 | | |
988 | | /* Like try_val_to_str, but tries to find a prefix (instead of an exact) match |
989 | | of any prefix from the bytes_string array bs against the haystack. */ |
990 | | const char * |
991 | | try_bytesprefix_to_str(const uint8_t *haystack, const size_t haystack_len, const bytes_string *bs) |
992 | 0 | { |
993 | 0 | unsigned i = 0; |
994 | |
|
995 | 0 | if (bs) { |
996 | 0 | while (bs[i].strptr) { |
997 | 0 | if (haystack_len >= bs[i].value_length && |
998 | 0 | !memcmp(bs[i].value, haystack, bs[i].value_length)) { |
999 | 0 | return bs[i].strptr; |
1000 | 0 | } |
1001 | 0 | i++; |
1002 | 0 | } |
1003 | 0 | } |
1004 | | |
1005 | 0 | return NULL; |
1006 | 0 | } |
1007 | | |
1008 | | void |
1009 | | value_string_externals_init(void) |
1010 | 14 | { |
1011 | 14 | registered_vs = g_hash_table_new(g_str_hash, g_str_equal); |
1012 | 14 | registered_vs_ext = g_hash_table_new(g_str_hash, g_str_equal); |
1013 | 14 | } |
1014 | | |
1015 | | void value_string_externals_cleanup(void) |
1016 | 0 | { |
1017 | 0 | g_hash_table_destroy(registered_vs); |
1018 | 0 | g_hash_table_destroy(registered_vs_ext); |
1019 | 0 | } |
1020 | | |
1021 | | void |
1022 | | register_external_value_string(const char* name, const value_string* vs) |
1023 | 574 | { |
1024 | 574 | g_hash_table_insert(registered_vs, (void*)name, (void*)vs); |
1025 | 574 | } |
1026 | | |
1027 | | value_string* |
1028 | | get_external_value_string(const char* name) |
1029 | 0 | { |
1030 | 0 | return (value_string*)g_hash_table_lookup(registered_vs, name); |
1031 | 0 | } |
1032 | | |
1033 | | void |
1034 | | register_external_value_string_ext(const char* name, const value_string_ext* vse) |
1035 | 168 | { |
1036 | 168 | g_hash_table_insert(registered_vs_ext, (void*)name, (void*)vse); |
1037 | 168 | } |
1038 | | |
1039 | | value_string_ext* |
1040 | | get_external_value_string_ext(const char* name) |
1041 | 0 | { |
1042 | 0 | return (value_string_ext*)g_hash_table_lookup(registered_vs_ext, name); |
1043 | 0 | } |
1044 | | |
1045 | | |
1046 | | |
1047 | | /* MISC */ |
1048 | | |
1049 | | /* Functions for use by proto_registrar_dump_values(), see proto.c */ |
1050 | | |
1051 | | bool |
1052 | | value_string_ext_validate(const value_string_ext *vse) |
1053 | 0 | { |
1054 | 0 | if (vse == NULL) |
1055 | 0 | return false; |
1056 | 0 | #ifndef _WIN32 /* doesn't work on Windows for refs from another DLL ?? */ |
1057 | 0 | if ((vse->_vs_match2 != _try_val_to_str_ext_init) && |
1058 | 0 | (vse->_vs_match2 != _try_val_to_str_linear) && |
1059 | 0 | (vse->_vs_match2 != _try_val_to_str_bsearch) && |
1060 | 0 | (vse->_vs_match2 != _try_val_to_str_index)) |
1061 | 0 | return false; |
1062 | 0 | #endif |
1063 | 0 | return true; |
1064 | 0 | } |
1065 | | |
1066 | | const char * |
1067 | | value_string_ext_match_type_str(const value_string_ext *vse) |
1068 | 0 | { |
1069 | 0 | if (vse->_vs_match2 == _try_val_to_str_ext_init) |
1070 | 0 | return "[Not Initialized]"; |
1071 | 0 | if (vse->_vs_match2 == _try_val_to_str_linear) |
1072 | 0 | return "[Linear Search]"; |
1073 | 0 | if (vse->_vs_match2 == _try_val_to_str_bsearch) |
1074 | 0 | return "[Binary Search]"; |
1075 | 0 | if (vse->_vs_match2 == _try_val_to_str_index) |
1076 | 0 | return "[Direct (indexed) Access]"; |
1077 | 0 | return "[Invalid]"; |
1078 | 0 | } |
1079 | | |
1080 | | bool |
1081 | | val64_string_ext_validate(const val64_string_ext *vse) |
1082 | 0 | { |
1083 | 0 | if (vse == NULL) |
1084 | 0 | return false; |
1085 | 0 | #ifndef _WIN32 /* doesn't work on Windows for refs from another DLL ?? */ |
1086 | 0 | if ((vse->_vs_match2 != _try_val64_to_str_ext_init) && |
1087 | 0 | (vse->_vs_match2 != _try_val64_to_str_linear) && |
1088 | 0 | (vse->_vs_match2 != _try_val64_to_str_bsearch) && |
1089 | 0 | (vse->_vs_match2 != _try_val64_to_str_index)) |
1090 | 0 | return false; |
1091 | 0 | #endif |
1092 | 0 | return true; |
1093 | 0 | } |
1094 | | |
1095 | | const char * |
1096 | | val64_string_ext_match_type_str(const val64_string_ext *vse) |
1097 | 0 | { |
1098 | 0 | if (vse->_vs_match2 == _try_val64_to_str_ext_init) |
1099 | 0 | return "[Not Initialized]"; |
1100 | 0 | if (vse->_vs_match2 == _try_val64_to_str_linear) |
1101 | 0 | return "[Linear Search]"; |
1102 | 0 | if (vse->_vs_match2 == _try_val64_to_str_bsearch) |
1103 | 0 | return "[Binary Search]"; |
1104 | 0 | if (vse->_vs_match2 == _try_val64_to_str_index) |
1105 | 0 | return "[Direct (indexed) Access]"; |
1106 | 0 | return "[Invalid]"; |
1107 | 0 | } |
1108 | | |
1109 | | /* |
1110 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1111 | | * |
1112 | | * Local variables: |
1113 | | * c-basic-offset: 4 |
1114 | | * tab-width: 8 |
1115 | | * indent-tabs-mode: nil |
1116 | | * End: |
1117 | | * |
1118 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
1119 | | * :indentSize=4:tabSize=8:noTabs=true: |
1120 | | */ |