The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
table.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** Functions to convert strings to integers and vice versa
18  *
19  * @file lib/util/table.c
20  *
21  * @copyright 2019 The FreeRADIUS server project
22  * @copyright 2019 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23  */
24 RCSID("$Id: c9bbf86f4f402f0bffa10f354d44a21012246079 $")
25 
26 #include <freeradius-devel/util/table.h>
27 #include <freeradius-devel/util/misc.h>
28 
29 #include <string.h>
30 
31 #define TABLE_IDX(_table, _idx, _element_size) (((uint8_t const *)(_table)) + ((_idx) * (_element_size)))
32 #define ELEM_STR(_offset) (*((fr_table_elem_t const *)(_offset))).str
33 #define ELEM_LEN(_offset) (*((fr_table_elem_t const *)(_offset))).len
34 
35 /** Brute force search a sorted or ordered ptr table, assuming the pointers are strings
36  *
37  * @param[in] table to search in.
38  * @param[in] table_len Number of elements in the table.
39  * @param[in] str_val to compare against the ptr field.
40  * @param[in] def default value.
41  */
42 char const *_fr_table_ptr_by_str_value(fr_table_ptr_sorted_t const *table, size_t table_len, char const *str_val, char const *def)
43 {
44  size_t i;
45 
46  if (!str_val) return NULL;
47 
48  for (i = 0; i < table_len; i++) if (strcasecmp(str_val, table[i].value) == 0) return table[i].name.str;
49 
50  return def;
51 }
52 
53 /** Create type specific string to value functions
54  *
55  * @param[in] _func used for searching.
56  * @param[in] _our_table_type that we'll be searching in.
57  * @param[in] _our_name The function that we'll be creating.
58  * @param[in] _our_def_type The type of the default value.
59  * @param[in] _our_return_type What we return.
60  */
61 #define TABLE_TYPE_STR_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type) \
62 _our_return_type _our_name(_our_table_type table, size_t table_len, char const *name, _our_def_type def) \
63 { \
64  _our_return_type ret; \
65  _our_table_type found; \
66  found = (_our_table_type)_func(table, table_len, sizeof(((_our_table_type)0)[0]), name); \
67  if (!found) { \
68  memcpy(&ret, &def, sizeof(ret)); \
69  return ret; \
70  } \
71  memcpy(&ret, &found->value, sizeof(ret)); \
72  return ret; \
73 }
74 
75 /** Create type specific string to value functions with an input string length argument
76  *
77  * @param[in] _func used for searching.
78  * @param[in] _our_table_type that we'll be searching in.
79  * @param[in] _our_name The function that we'll be creating.
80  * @param[in] _our_def_type The type of the default value.
81  * @param[in] _our_return_type What we return.
82  */
83 #define TABLE_TYPE_STR_LEN_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type) \
84 _our_return_type _our_name(_our_table_type table, size_t table_len, char const *name, ssize_t name_len, _our_def_type def) \
85 { \
86  _our_return_type ret; \
87  _our_table_type found; \
88  found = (_our_table_type)_func(table, table_len, sizeof(((_our_table_type)0)[0]), name, name_len); \
89  if (!found) { \
90  memcpy(&ret, &def, sizeof(ret)); \
91  return ret; \
92  } \
93  memcpy(&ret, &found->value, sizeof(ret)); \
94  return ret; \
95 }
96 
97 #define TABLE_TYPE_STR_MATCH_LEN_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type) \
98 _our_return_type _our_name(size_t *match_len, _our_table_type table, size_t table_len, char const *name, ssize_t name_len, _our_def_type def) \
99 { \
100  _our_return_type ret; \
101  _our_table_type found; \
102  found = (_our_table_type)_func(match_len, table, table_len, sizeof(((_our_table_type)0)[0]), name, name_len); \
103  if (!found) { \
104  memcpy(&ret, &def, sizeof(ret)); \
105  return ret; \
106  } \
107  memcpy(&ret, &found->value, sizeof(ret)); \
108  return ret; \
109 }
110 
111 
112 #define TABLE_TYPE_VALUE_FUNC(_our_table_type, _our_name, _our_value_type) \
113 char const *_our_name(_our_table_type table, size_t table_len, _our_value_type value, char const *def) \
114 { \
115  size_t i; \
116  for (i = 0; i < table_len; i++) if (table[i].value == value) return table[i].name.str; \
117  return def; \
118 }
119 
120 #define TABLE_TYPE_VALUE_INDEX_BIT_FIELD_FUNC(_our_table_type, _our_name, _our_value_type) \
121 char const *_our_name(_our_table_type table, size_t table_len, _our_value_type value, char const *def) \
122 { \
123  uint8_t idx = fr_high_bit_pos(value); \
124  if (idx >= table_len) return def; \
125  return table[idx].name.str; \
126 }
127 
128 #define TABLE_TYPE_VALUE_INDEX_FUNC(_our_table_type, _our_name, _our_value_type) \
129 char const *_our_name(_our_table_type table, size_t table_len, _our_value_type value, char const *def) \
130 { \
131  if (value >= table_len) return def; \
132  return table[value].name.str; \
133 }
134 
135 /** Convert a string to a value using a lexicographically sorted table
136  *
137  * @param[in] table to search in.
138  * @param[in] table_len The number of elements in the table.
139  * @param[in] element_size Size of elements in the table.
140  * @param[in] name to resolve to a value.
141  * @return
142  * - value of matching entry.
143  * - NULL if no matching entries.
144  */
145 static void const *table_sorted_value_by_str(void const *table, size_t table_len, size_t element_size,
146  char const *name)
147 {
148  ssize_t start = 0;
149  ssize_t end = table_len - 1;
150  ssize_t mid;
151 
152  int ret;
153 
154  if (!name) return NULL;
155 
156  while (start <= end) {
157  void const *offset;
158 
159  mid = start + ((end - start) / 2); /* Avoid overflow */
160 
161  offset = TABLE_IDX(table, mid, element_size);
162  ret = strcasecmp(name, ELEM_STR(offset));
163  if (ret == 0) return offset;
164  if (ret < 0) {
165  end = mid - 1;
166  } else {
167  start = mid + 1;
168  }
169  }
170 
171  return NULL;
172 }
173 
175  fr_table_sorted_num_by_str, int, int)
177  fr_table_sorted_ptr_by_str, void const *, void *)
178 
179 /** Convert a string to a value using an arbitrarily ordered table
180  *
181  * @param[in] table to search in.
182  * @param[in] table_len The number of elements in the table.
183  * @param[in] element_size Size of elements in the table.
184  * @param[in] name to resolve to a number.
185  * @return
186  * - value of matching entry.
187  * - NULL if no matching entries.
188  */
189 static void const *table_ordered_value_by_str(void const *table, size_t table_len, size_t element_size,
190  char const *name)
191 {
192  size_t i;
193 
194  if (!name) return NULL;
195 
196  for (i = 0; i < table_len; i++) {
197  void const *offset = TABLE_IDX(table, i, element_size);
198  if (strcasecmp(name, ELEM_STR(offset)) == 0) return offset;
199  }
200 
201  return NULL;
202 }
203 
204 TABLE_TYPE_STR_FUNC(table_ordered_value_by_str, fr_table_num_ordered_t const *,
205  fr_table_ordered_num_by_str, int, int)
206 TABLE_TYPE_STR_FUNC(table_ordered_value_by_str, fr_table_ptr_ordered_t const *,
207  fr_table_ordered_ptr_by_str, void const *, void *)
208 
209 /** Convert a string matching part of name to an integer using a lexicographically sorted table
210  *
211  * @param[in] table to search in.
212  * @param[in] table_len The number of elements in the table.
213  * @param[in] element_size Size of elements in the table.
214  * @param[in] name to locate.
215  * @param[in] name_len the maximum amount of name that should be matched.
216  * If < 0, the length of the name in the table offsetent
217  * will be used as the maximum match length.
218  * @return
219  * - value of matching entry.
220  * - NULL if no matching entries.
221  */
222 static void const *table_sorted_value_by_substr(void const *table, size_t table_len, size_t element_size,
223  char const *name, ssize_t name_len)
224 {
225  ssize_t start = 0;
226  ssize_t end = table_len - 1;
227  ssize_t mid;
228 
229  int ret;
230 
231  if (!name) return NULL;
232 
233  while (start <= end) {
234  void const *offset;
235 
236  mid = start + ((end - start) / 2); /* Avoid overflow */
237 
238  offset = TABLE_IDX(table, mid, element_size);
239 
240  /*
241  * Match up to the length of the table entry if len is < 0.
242  */
243  ret = strncasecmp(name, ELEM_STR(offset),
244  (name_len < 0) ? ELEM_LEN(offset) : (size_t)name_len);
245  if (ret == 0) return offset;
246 
247  if (ret < 0) {
248  end = mid - 1;
249  } else {
250  start = mid + 1;
251  }
252  }
253 
254  return NULL;
255 }
256 
257 TABLE_TYPE_STR_LEN_FUNC(table_sorted_value_by_substr, fr_table_num_sorted_t const *,
259 TABLE_TYPE_STR_LEN_FUNC(table_sorted_value_by_substr, fr_table_ptr_sorted_t const *,
260  fr_table_sorted_ptr_by_substr, void const *, void *)
261 
262 /** Convert a string matching part of name to an integer using an arbitrarily ordered table
263  *
264  * @param[in] table to search in.
265  * @param[in] table_len The number of elements in the table.
266  * @param[in] element_size Size of elements in the table.
267  * @param[in] name to locate.
268  * @param[in] name_len the maximum amount of name that should be matched.
269  * If < 0, the length of the name in the table offsetent
270  * will be used as the maximum match length.
271  * @return
272  * - value of matching entry.
273  * - NULL if no matching entries.
274  */
275 static void const *table_ordered_value_by_substr(void const *table, size_t table_len, size_t element_size,
276  char const *name, ssize_t name_len)
277 {
278  size_t i;
279 
280  if (!name) return NULL;
281 
282  for (i = 0; i < table_len; i++) {
283  void const *offset;
284  size_t tlen;
285 
286  offset = TABLE_IDX(table, i, element_size);
287 
288  tlen = ELEM_LEN(offset);
289 
290  /*
291  * Don't match "request" to user input "req".
292  */
293  if ((name_len > 0) && (name_len < (int) tlen)) continue;
294 
295  /*
296  * Match up to the length of the table entry if len is < 0.
297  */
298  if (strncasecmp(name, ELEM_STR(offset),
299  (name_len < 0) ? tlen : (size_t)name_len) == 0) return offset;
300  }
301 
302  return NULL;
303 }
304 
305 TABLE_TYPE_STR_LEN_FUNC(table_ordered_value_by_substr, fr_table_num_ordered_t const *,
307 TABLE_TYPE_STR_LEN_FUNC(table_ordered_value_by_substr, fr_table_ptr_ordered_t const *,
308  fr_table_ordered_ptr_by_substr, void const *, void *)
309 
310 /** Find the longest string match using a lexicographically sorted table
311  *
312  * Performs a binary search in the specified table, returning the longest
313  * offsetent which is a prefix of name.
314  *
315  * i.e. given name of "food", and table of f, foo, of - foo would be returned.
316  *
317  * @note The table *MUST* be sorted lexicographically, else the result may be incorrect.
318  *
319  * @param[out] match_len How much of the input string matched.
320  * @param[in] table to search in.
321  * @param[in] table_len The number of elements in the table.
322  * @param[in] element_size Size of elements in the table.
323  * @param[in] name to locate.
324  * @param[in] name_len the maximum amount of name that should be matched.
325  * @return
326  * - num value of matching entry.
327  * - NULL if no matching entries.
328  */
329 static void const *table_sorted_value_by_longest_prefix(size_t *match_len,
330  void const *table, size_t table_len, size_t element_size,
331  char const *name, ssize_t name_len)
332 {
333  ssize_t start = 0;
334  ssize_t end = table_len - 1;
335  ssize_t mid;
336 
337  int ret;
338  void const *found = NULL;
339 
340  if (!name) return NULL;
341  if (name_len < 0) name_len = strlen(name);
342 
343  while (start <= end) {
344  void const *offset;
345  char const *elem;
346  size_t tlen;
347 
348  mid = start + ((end - start) / 2); /* Avoid overflow */
349 
350  offset = TABLE_IDX(table, mid, element_size);
351  elem = ELEM_STR(offset);
352  tlen = ELEM_LEN(offset);
353 
354  ret = strncasecmp(name, elem, tlen < (size_t)name_len ? tlen : (size_t)name_len);
355  if (ret == 0) {
356  /*
357  * Exact match
358  */
359  if (tlen == (size_t)name_len) {
360  if (match_len) *match_len = tlen;
361  return offset;
362  }
363 
364  /*
365  * Partial match.
366  * Name we're searching for is longer.
367  * This might be the longest prefix,
368  * so record it.
369  */
370  if (tlen < (size_t)name_len) {
371  found = offset;
372  if (match_len) *match_len = tlen;
373  ret = 1;
374  } else {
375  ret = -1;
376  }
377  }
378 
379  if (ret < 0) {
380  end = mid - 1;
381  } else {
382  start = mid + 1;
383  }
384  }
385 
386  if (!found && match_len) *match_len = 0;
387 
388  return found;
389 }
390 
391 TABLE_TYPE_STR_MATCH_LEN_FUNC(table_sorted_value_by_longest_prefix, fr_table_num_sorted_t const *,
393 TABLE_TYPE_STR_MATCH_LEN_FUNC(table_sorted_value_by_longest_prefix, fr_table_ptr_sorted_t const *,
394  fr_table_sorted_ptr_by_longest_prefix, void const *, void *)
395 
396 /** Find the longest string match using an arbitrarily ordered table
397  *
398  * i.e. given name of "food", and table of f, foo, of - foo would be returned.
399  *
400  * @param[out] match_len How much of the input string matched.
401  * @param[in] table to search in.
402  * @param[in] table_len The number of elements in the table.
403  * @param[in] element_size Size of elements in the table.
404  * @param[in] name to locate.
405  * @param[in] name_len the maximum amount of name that should be matched.
406  * @return
407  * - num value of matching entry.
408  * - def if no matching entries.
409  */
410 static void const *table_ordered_value_by_longest_prefix(size_t *match_len,
411  void const *table, size_t table_len, size_t element_size,
412  char const *name, ssize_t name_len)
413 {
414  size_t i;
415  size_t found_len = 0;
416  void const *found = NULL;
417 
418  if (!name) return NULL;
419  if (name_len < 0) name_len = strlen(name);
420 
421  for (i = 0; i < table_len; i++) {
422  void const *offset;
423  size_t j;
424 
425  offset = TABLE_IDX(table, i, element_size);
426 
427  for (j = 0; (j < (size_t)name_len) && (j < ELEM_LEN(offset)) &&
428  (tolower(name[j]) == tolower((ELEM_STR(offset))[j])); j++);
429 
430  /*
431  * If we didn't get to the end of the
432  * table string, then continue.
433  */
434  if ((ELEM_STR(offset))[j] != '\0') continue;
435 
436  /*
437  * Exact match
438  */
439  if (j == (size_t)name_len) {
440  if (match_len) *match_len = name_len;
441  return offset;
442  }
443 
444  /*
445  * Partial match.
446  * Name we're searching for is longer.
447  * This might be the longest prefix,
448  * so record it.
449  */
450  if (j > found_len) {
451  found_len = j;
452  found = offset;
453  }
454  }
455 
456  if (match_len) *match_len = found_len;
457 
458  return found;
459 }
460 
461 TABLE_TYPE_STR_MATCH_LEN_FUNC(table_ordered_value_by_longest_prefix, fr_table_num_ordered_t const *,
463 TABLE_TYPE_STR_MATCH_LEN_FUNC(table_ordered_value_by_longest_prefix, fr_table_ptr_ordered_t const *,
464  fr_table_ordered_ptr_by_longest_prefix, void const *, void *)
465 
466 /*
467  * Value to string conversion functions
468  */
473 
474 /*
475  * Indexed value to string conversion functions
476  * These are O(1) for bitfields, and are
477  * particularly useful for looking up string
478  * definitions for flag values.
479  */
481 
482 /*
483  * Array lookup based on numeric value
484  */
#define RCSID(id)
Definition: build.h:444
Test enumeration values.
Definition: dict_test.h:92
long int ssize_t
Definition: merged_model.c:24
unsigned long int size_t
Definition: merged_model.c:25
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:36
int strcasecmp(char *s1, char *s2)
Definition: missing.c:66
static char const * name
#define TABLE_TYPE_VALUE_FUNC(_our_table_type, _our_name, _our_value_type)
Definition: table.c:112
#define TABLE_TYPE_VALUE_INDEX_BIT_FIELD_FUNC(_our_table_type, _our_name, _our_value_type)
Definition: table.c:120
#define ELEM_STR(_offset)
Definition: table.c:32
#define TABLE_TYPE_STR_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type)
Create type specific string to value functions.
Definition: table.c:61
#define TABLE_TYPE_VALUE_INDEX_FUNC(_our_table_type, _our_name, _our_value_type)
Definition: table.c:128
#define TABLE_TYPE_STR_LEN_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type)
Create type specific string to value functions with an input string length argument.
Definition: table.c:83
#define TABLE_IDX(_table, _idx, _element_size)
Definition: table.c:31
char const * _fr_table_ptr_by_str_value(fr_table_ptr_sorted_t const *table, size_t table_len, char const *str_val, char const *def)
Brute force search a sorted or ordered ptr table, assuming the pointers are strings.
Definition: table.c:42
static void const * table_sorted_value_by_str(void const *table, size_t table_len, size_t element_size, char const *name)
Convert a string to a value using a lexicographically sorted table.
Definition: table.c:145
#define ELEM_LEN(_offset)
Definition: table.c:33
#define TABLE_TYPE_STR_MATCH_LEN_FUNC(_func, _our_table_type, _our_name, _our_def_type, _our_return_type)
Definition: table.c:97
int fr_table_ordered_num_by_substr(fr_table_num_ordered_t const *table, size_t table_len, char const *name, ssize_t name_len, int def)
char const * fr_table_sorted_str_by_ptr(fr_table_ptr_sorted_t const *table, size_t table_len, void const *ptr, char const *def)
int fr_table_ordered_num_by_longest_prefix(size_t *match_len, fr_table_num_ordered_t const *table, size_t table_len, char const *name, ssize_t name_len, int def)
void * fr_table_ordered_ptr_by_str(fr_table_ptr_ordered_t const *table, size_t table_len, char const *name, void const *def)
void * fr_table_ordered_ptr_by_longest_prefix(size_t *match_len, fr_table_ptr_ordered_t const *table, size_t table_len, char const *name, ssize_t name_len, void const *def)
char const * str
Literal string.
Definition: table.h:38
int fr_table_sorted_num_by_substr(fr_table_num_sorted_t const *table, size_t table_len, char const *name, ssize_t name_len, int def)
char const * fr_table_ordered_str_by_num(fr_table_num_ordered_t const *table, size_t table_len, int number, char const *def)
fr_table_elem_t name
Definition: table.h:62
void * fr_table_sorted_ptr_by_str(fr_table_ptr_sorted_t const *table, size_t table_len, char const *name, void const *def)
char const * fr_table_ordered_str_by_ptr(fr_table_ptr_ordered_t const *table, size_t table_len, void const *ptr, char const *def)
void * fr_table_sorted_ptr_by_substr(fr_table_ptr_sorted_t const *table, size_t table_len, char const *name, ssize_t name_len, void const *def)
char const * fr_table_sorted_str_by_num(fr_table_num_sorted_t const *table, size_t table_len, int number, char const *def)
int fr_table_sorted_num_by_str(fr_table_num_sorted_t const *table, size_t table_len, char const *name, int def)
char const * fr_table_indexed_str_by_num(fr_table_num_indexed_t const *table, size_t table_len, unsigned int number, char const *def)
void * fr_table_ordered_ptr_by_substr(fr_table_ptr_ordered_t const *table, size_t table_len, char const *name, ssize_t name_len, void const *def)
int fr_table_ordered_num_by_str(fr_table_num_ordered_t const *table, size_t table_len, char const *name, int def)
void * fr_table_sorted_ptr_by_longest_prefix(size_t *match_len, fr_table_ptr_sorted_t const *table, size_t table_len, char const *name, ssize_t name_len, void const *def)
char const * fr_table_indexed_str_by_bit_field(fr_table_num_indexed_bit_pos_t const *table, size_t table_len, uint64_t number, char const *def)
int fr_table_sorted_num_by_longest_prefix(size_t *match_len, fr_table_num_sorted_t const *table, size_t table_len, char const *name, ssize_t name_len, int def)
An element in a table indexed by bit position.
Definition: table.h:79
An element in a table indexed by numeric value.
Definition: table.h:88
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
An element in an arbitrarily ordered array of name to ptr mappings.
Definition: table.h:69
An element in a lexicographically sorted array of name to ptr mappings.
Definition: table.h:61