File: | plugins/epan/mate/mate_util.c |
Warning: | line 143, column 9 Null pointer passed to 1st parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* mate_util.c | |||
2 | * MATE -- Meta Analysis Tracing Engine | |||
3 | * Utility Library: Single Copy Strings and Attribute Value Pairs | |||
4 | * | |||
5 | * Copyright 2004, Luis E. Garcia Ontanon <[email protected]> | |||
6 | * | |||
7 | * Wireshark - Network traffic analyzer | |||
8 | * By Gerald Combs <[email protected]> | |||
9 | * Copyright 1998 Gerald Combs | |||
10 | * | |||
11 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
12 | */ | |||
13 | ||||
14 | #include "config.h" | |||
15 | ||||
16 | #include "mate.h" | |||
17 | #include "mate_util.h" | |||
18 | ||||
19 | #include <errno(*__errno_location ()).h> | |||
20 | #include <wsutil/file_util.h> | |||
21 | ||||
22 | ||||
23 | /*************************************************************************** | |||
24 | * dbg_print | |||
25 | *************************************************************************** | |||
26 | * This is the debug facility of the thing. | |||
27 | ***************************************************************************/ | |||
28 | ||||
29 | /* dbg_print: | |||
30 | * which: a pointer to the current level of debugging for a feature | |||
31 | * how: the level over which this message should be printed out | |||
32 | * where: the file on which to print (ws_message if null) | |||
33 | * fmt, ...: what to print | |||
34 | */ | |||
35 | ||||
36 | void dbg_print(const int* which, int how, FILE* where, const char* fmt, ... ) { | |||
37 | static char debug_buffer[DEBUG_BUFFER_SIZE4096]; | |||
38 | va_list list; | |||
39 | ||||
40 | if ( ! which || *which < how ) return; | |||
41 | ||||
42 | va_start( list, fmt )__builtin_va_start(list, fmt); | |||
43 | vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE4096,fmt,list); | |||
44 | va_end( list )__builtin_va_end(list); | |||
45 | ||||
46 | if (! where) { | |||
47 | ws_message("%s", debug_buffer)do { if (1) { ws_log_full("MATE", LOG_LEVEL_MESSAGE, ((void*) 0), -1, ((void*)0), "%s", debug_buffer); } } while (0); | |||
48 | } else { | |||
49 | fputs(debug_buffer,where); | |||
50 | fputs("\n",where); | |||
51 | } | |||
52 | ||||
53 | } | |||
54 | ||||
55 | /*************************************************************************** | |||
56 | * single copy strings | |||
57 | *************************************************************************** | |||
58 | * Strings repeat more often than don't. In order to save memory | |||
59 | * we'll keep only one copy of each as key to a hash with a count of | |||
60 | * subscribers as value. Each string is truncated to be no more than | |||
61 | * SCS_HUGE_SIZE. | |||
62 | * XXX - GLib 2.58 adds reference counted strings, use that? | |||
63 | ***************************************************************************/ | |||
64 | ||||
65 | /** | |||
66 | * scs_init: | |||
67 | * | |||
68 | * Initializes the scs hash. | |||
69 | **/ | |||
70 | ||||
71 | struct _scs_collection { | |||
72 | GHashTable* hash; /* key: a string value: unsigned number of subscribers */ | |||
73 | }; | |||
74 | ||||
75 | /* | |||
76 | * XXX: AFAIKT destroy_scs_collection() might be called only when reading a | |||
77 | * mate config file. Since reading a new config file can apparently currently | |||
78 | * only be done once after starting Wireshark, in theory this fcn | |||
79 | * currently should never be called since there will never be an existing | |||
80 | * scs_collection to be destroyed. | |||
81 | */ | |||
82 | static void destroy_scs_collection(SCS_collection* c) { | |||
83 | if (c->hash) g_hash_table_destroy(c->hash); | |||
84 | } | |||
85 | ||||
86 | /* The same djb2 hash used in g_str_hash, except that it stops after | |||
87 | * SCS_HUGE_SIZE bytes. */ | |||
88 | static unsigned scs_hash(const void *v) | |||
89 | { | |||
90 | const signed char *p; | |||
91 | uint32_t h = 5381; | |||
92 | size_t i = 0; | |||
93 | ||||
94 | for (p = v; *p != '\0' && i++ < SCS_HUGE_SIZE65535; p++) { | |||
95 | h = (h << 5) + h + *p; | |||
96 | } | |||
97 | ||||
98 | return h; | |||
99 | } | |||
100 | ||||
101 | /* Compare the first SCS_HUGE_SIZE bytes for equality. */ | |||
102 | static gboolean scs_equal(const void *a, const void *b) | |||
103 | { | |||
104 | const char *str1 = a; | |||
105 | const char *str2 = b; | |||
106 | ||||
107 | return strncmp(str1, str2, SCS_HUGE_SIZE65535) == 0; | |||
108 | } | |||
109 | ||||
110 | static SCS_collection* scs_init(void) { | |||
111 | SCS_collection* c = g_new(SCS_collection, 1)((SCS_collection *) g_malloc_n ((1), sizeof (SCS_collection)) ); | |||
112 | ||||
113 | c->hash = g_hash_table_new_full(scs_hash, scs_equal, g_free, g_free); | |||
114 | ||||
115 | return c; | |||
116 | } | |||
117 | ||||
118 | ||||
119 | /** | |||
120 | * subscribe: | |||
121 | * @param c the scs hash | |||
122 | * @param s a string | |||
123 | * | |||
124 | * Checks if the given string exists already and if so it increases the count of | |||
125 | * subsscribers and returns a pointer to the stored string. If not it will copy | |||
126 | * the given string, store it in the hash, and return the pointer to the copy. | |||
127 | * Remember, containment is handled internally, take care of your own strings. | |||
128 | * | |||
129 | * Return value: a pointer to the subscribed string. | |||
130 | **/ | |||
131 | char* scs_subscribe(SCS_collection* c, const char* s) { | |||
132 | char* orig = NULL((void*)0); | |||
133 | unsigned* ip = NULL((void*)0); | |||
134 | size_t len = 0; | |||
135 | ||||
136 | g_hash_table_lookup_extended(c->hash,(const void *)s,(void * *)&orig,(void * *)&ip); | |||
137 | ||||
138 | if (ip) { | |||
139 | (*ip)++; | |||
140 | } else { | |||
141 | ip = g_new0(unsigned, 1)((unsigned *) g_malloc0_n ((1), sizeof (unsigned))); | |||
142 | ||||
143 | len = strlen(s); | |||
| ||||
144 | ||||
145 | if(G_LIKELY(len <= SCS_HUGE_SIZE)(len <= 65535)) { | |||
146 | orig = g_strdup(s)g_strdup_inline (s); | |||
147 | } else { | |||
148 | ws_warning("mate SCS: string truncated due to huge size")do { if (1) { ws_log_full("MATE", LOG_LEVEL_WARNING, "plugins/epan/mate/mate_util.c" , 148, __func__, "mate SCS: string truncated due to huge size" ); } } while (0); | |||
149 | orig = g_strndup(s, SCS_HUGE_SIZE65535); | |||
150 | } | |||
151 | ||||
152 | g_hash_table_insert(c->hash, orig, ip); | |||
153 | } | |||
154 | ||||
155 | return orig; | |||
156 | } | |||
157 | ||||
158 | /** | |||
159 | * unsubscribe: | |||
160 | * @param c the scs hash | |||
161 | * @param s a string. | |||
162 | * | |||
163 | * decreases the count of subscribers, if zero frees the internal copy of | |||
164 | * the string. | |||
165 | **/ | |||
166 | void scs_unsubscribe(SCS_collection* c, char* s) { | |||
167 | char* orig = NULL((void*)0); | |||
168 | unsigned* ip = NULL((void*)0); | |||
169 | ||||
170 | if (g_hash_table_lookup_extended(c->hash,(const void *)s,(void **)&orig,(void **)&ip)) { | |||
171 | if (*ip == 0) { | |||
172 | g_hash_table_remove(c->hash,orig); | |||
173 | } | |||
174 | else { | |||
175 | (*ip)--; | |||
176 | } | |||
177 | } else { | |||
178 | ws_warning("mate SCS: not subscribed")do { if (1) { ws_log_full("MATE", LOG_LEVEL_WARNING, "plugins/epan/mate/mate_util.c" , 178, __func__, "mate SCS: not subscribed"); } } while (0); | |||
179 | } | |||
180 | } | |||
181 | ||||
182 | /** | |||
183 | * scs_subscribe_printf: | |||
184 | * @param fmt a format string ... | |||
185 | * | |||
186 | * Formats the input and subscribes it. | |||
187 | * | |||
188 | * Return value: the stored copy of the formatted string. | |||
189 | * | |||
190 | **/ | |||
191 | char* scs_subscribe_printf(SCS_collection* c, char* fmt, ...) { | |||
192 | va_list list; | |||
193 | char *buf, *ret; | |||
194 | ||||
195 | va_start( list, fmt )__builtin_va_start(list, fmt); | |||
196 | buf = g_strdup_vprintf(fmt, list); | |||
197 | va_end( list )__builtin_va_end(list); | |||
198 | ||||
199 | ret = scs_subscribe(c, buf); | |||
200 | g_free(buf); | |||
201 | ||||
202 | return ret; | |||
203 | } | |||
204 | ||||
205 | /*************************************************************************** | |||
206 | * AVPs & Co. | |||
207 | *************************************************************************** | |||
208 | * The Thing operates mainly on avps, avpls and loals | |||
209 | * - attribute value pairs (two strings: the name and the value and an operator) | |||
210 | * - avp lists a somehow sorted list of avps | |||
211 | * - loal (list of avp lists) an arbitrarily sorted list of avpls | |||
212 | * | |||
213 | * | |||
214 | ***************************************************************************/ | |||
215 | ||||
216 | ||||
217 | typedef union _any_avp_type { | |||
218 | AVP avp; | |||
219 | AVPN avpn; | |||
220 | AVPL avpl; | |||
221 | LoAL loal; | |||
222 | LoALnode loaln; | |||
223 | } any_avp_type; | |||
224 | ||||
225 | ||||
226 | static SCS_collection* avp_strings; | |||
227 | ||||
228 | #ifdef _AVP_DEBUGGING | |||
229 | static FILE* dbg_fp; | |||
230 | ||||
231 | static int dbg_level; | |||
232 | static int* dbg = &dbg_level; | |||
233 | ||||
234 | static int dbg_avp_level; | |||
235 | static int* dbg_avp = &dbg_avp_level; | |||
236 | ||||
237 | static int dbg_avp_op_level; | |||
238 | static int* dbg_avp_op = &dbg_avp_op_level; | |||
239 | ||||
240 | static int dbg_avpl_level; | |||
241 | static int* dbg_avpl = &dbg_avpl_level; | |||
242 | ||||
243 | static int dbg_avpl_op_level; | |||
244 | static int* dbg_avpl_op = &dbg_avpl_op_level; | |||
245 | ||||
246 | /** | |||
247 | * setup_avp_debug: | |||
248 | * @param fp the file in which to send debugging output. | |||
249 | * @param general a pointer to the level of debugging of facility "general" | |||
250 | * @param avp a pointer to the level of debugging of facility "avp" | |||
251 | * @param avp_op a pointer to the level of debugging of facility "avp_op" | |||
252 | * @param avpl a pointer to the level of debugging of facility "avpl" | |||
253 | * @param avpl_op a pointer to the level of debugging of facility "avpl_op" | |||
254 | * | |||
255 | * If enabled sets up the debug facilities for the avp library. | |||
256 | * | |||
257 | **/ | |||
258 | extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) { | |||
259 | dbg_fp = fp; | |||
260 | dbg = general; | |||
261 | dbg_avp = avp; | |||
262 | dbg_avp_op = avp_op; | |||
263 | dbg_avpl = avpl; | |||
264 | dbg_avpl_op = avpl_op; | |||
265 | } | |||
266 | ||||
267 | #endif /* _AVP_DEBUGGING */ | |||
268 | ||||
269 | /** | |||
270 | * avp_init: | |||
271 | * | |||
272 | * (Re)Initializes the avp library. | |||
273 | * | |||
274 | **/ | |||
275 | extern void avp_init(void) { | |||
276 | ||||
277 | if (avp_strings) destroy_scs_collection(avp_strings); | |||
278 | avp_strings = scs_init(); | |||
279 | ||||
280 | } | |||
281 | ||||
282 | /** | |||
283 | * new_avp_from_finfo: | |||
284 | * @param name the name the avp will have. | |||
285 | * @param finfo the field_info from which to fetch the data. | |||
286 | * | |||
287 | * Creates an avp from a field_info record. | |||
288 | * | |||
289 | * Return value: a pointer to the newly created avp. | |||
290 | * | |||
291 | **/ | |||
292 | extern AVP* new_avp_from_finfo(const char* name, field_info* finfo) { | |||
293 | AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
294 | char* value; | |||
295 | char* repr; | |||
296 | ||||
297 | new_avp_val->n = scs_subscribe(avp_strings, name); | |||
298 | ||||
299 | repr = fvalue_to_string_repr(NULL((void*)0), finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display); | |||
300 | ||||
301 | if (repr) { | |||
302 | value = scs_subscribe(avp_strings, repr); | |||
303 | wmem_free(NULL((void*)0), repr); | |||
304 | #ifdef _AVP_DEBUGGING | |||
305 | dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value); | |||
306 | #endif | |||
307 | } else { | |||
308 | #ifdef _AVP_DEBUGGING | |||
309 | dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev); | |||
310 | #endif | |||
311 | value = scs_subscribe(avp_strings, ""); | |||
312 | } | |||
313 | ||||
314 | new_avp_val->v = value; | |||
315 | ||||
316 | new_avp_val->o = '='; | |||
317 | ||||
318 | #ifdef _AVP_DEBUGGING | |||
319 | dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); | |||
320 | #endif | |||
321 | ||||
322 | return new_avp_val; | |||
323 | } | |||
324 | ||||
325 | ||||
326 | /** | |||
327 | * new_avp: | |||
328 | * @param name the name the avp will have. | |||
329 | * @param value the value the avp will have. | |||
330 | * @param o the operator of this avp. | |||
331 | * | |||
332 | * Creates an avp given every parameter. | |||
333 | * | |||
334 | * Return value: a pointer to the newly created avp. | |||
335 | * | |||
336 | **/ | |||
337 | extern AVP* new_avp(const char* name, const char* value, char o) { | |||
338 | AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
339 | ||||
340 | new_avp_val->n = scs_subscribe(avp_strings, name); | |||
341 | new_avp_val->v = scs_subscribe(avp_strings, value); | |||
342 | new_avp_val->o = o; | |||
343 | ||||
344 | #ifdef _AVP_DEBUGGING | |||
345 | dbg_print(dbg_avp,1,dbg_fp,"new_avp_val: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); | |||
346 | #endif | |||
347 | return new_avp_val; | |||
348 | } | |||
349 | ||||
350 | ||||
351 | /** | |||
352 | * delete_avp: | |||
353 | * @param avp the avp to delete. | |||
354 | * | |||
355 | * Destroys an avp and releases the resources it uses. | |||
356 | * | |||
357 | **/ | |||
358 | extern void delete_avp(AVP* avp) { | |||
359 | #ifdef _AVP_DEBUGGING | |||
360 | dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %p %s%c%s;",avp,avp->n,avp->o,avp->v); | |||
361 | #endif | |||
362 | ||||
363 | scs_unsubscribe(avp_strings, avp->n); | |||
364 | scs_unsubscribe(avp_strings, avp->v); | |||
365 | g_slice_free(any_avp_type,(any_avp_type*)avp)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)avp)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)avp )); } while (0); | |||
366 | } | |||
367 | ||||
368 | ||||
369 | /** | |||
370 | * avp_copy: | |||
371 | * @param from the avp to be copied. | |||
372 | * | |||
373 | * Creates an avp whose name op and value are copies of the given one. | |||
374 | * | |||
375 | * Return value: a pointer to the newly created avp. | |||
376 | * | |||
377 | **/ | |||
378 | extern AVP* avp_copy(AVP* from) { | |||
379 | AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
380 | ||||
381 | new_avp_val->n = scs_subscribe(avp_strings, from->n); | |||
382 | new_avp_val->v = scs_subscribe(avp_strings, from->v); | |||
383 | new_avp_val->o = from->o; | |||
384 | ||||
385 | #ifdef _AVP_DEBUGGING | |||
386 | dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %p %s%c%s;",new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v); | |||
387 | #endif | |||
388 | ||||
389 | return new_avp_val; | |||
390 | } | |||
391 | ||||
392 | /** | |||
393 | * new_avpl: | |||
394 | * @param name the name the avpl will have. | |||
395 | * | |||
396 | * Creates an empty avpl. | |||
397 | * | |||
398 | * Return value: a pointer to the newly created avpl. | |||
399 | * | |||
400 | **/ | |||
401 | extern AVPL* new_avpl(const char* name) { | |||
402 | AVPL* new_avpl_p = (AVPL*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
403 | ||||
404 | #ifdef _AVP_DEBUGGING | |||
405 | dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl_p: %p name=%s",new_avpl_p,name); | |||
406 | #endif | |||
407 | ||||
408 | new_avpl_p->name = name ? scs_subscribe(avp_strings, name) : scs_subscribe(avp_strings, ""); | |||
409 | new_avpl_p->len = 0; | |||
410 | new_avpl_p->null.avp = NULL((void*)0); | |||
411 | new_avpl_p->null.next = &new_avpl_p->null; | |||
412 | new_avpl_p->null.prev = &new_avpl_p->null; | |||
413 | ||||
414 | ||||
415 | return new_avpl_p; | |||
416 | } | |||
417 | ||||
418 | extern void rename_avpl(AVPL* avpl, char* name) { | |||
419 | scs_unsubscribe(avp_strings,avpl->name); | |||
420 | avpl->name = scs_subscribe(avp_strings,name); | |||
421 | } | |||
422 | ||||
423 | /** | |||
424 | * insert_avp_before_node: | |||
425 | * @param avpl the avpl in which to insert. | |||
426 | * @param next_node the next node before which the new avpn has to be inserted. | |||
427 | * @param avp the avp to be inserted. | |||
428 | * @param copy_avp whether the original AVP or a copy thereof must be inserted. | |||
429 | * | |||
430 | * Pre-condition: the avp is sorted before before_avp and does not already exist | |||
431 | * in the avpl. | |||
432 | */ | |||
433 | static void insert_avp_before_node(AVPL* avpl, AVPN* next_node, AVP *avp, bool_Bool copy_avp) { | |||
434 | AVPN* new_avp_val = (AVPN*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
435 | ||||
436 | new_avp_val->avp = copy_avp
| |||
437 | ||||
438 | #ifdef _AVP_DEBUGGING | |||
439 | dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %p",new_avp_val); | |||
440 | dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %p in %p before %p;",avp,avpl,next_node); | |||
441 | #endif | |||
442 | ||||
443 | new_avp_val->next = next_node; | |||
444 | new_avp_val->prev = next_node->prev; | |||
445 | next_node->prev->next = new_avp_val; | |||
446 | next_node->prev = new_avp_val; | |||
447 | ||||
448 | avpl->len++; | |||
449 | ||||
450 | #ifdef _AVP_DEBUGGING | |||
451 | dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); | |||
452 | #endif | |||
453 | } | |||
454 | ||||
455 | /** | |||
456 | * insert_avp: | |||
457 | * @param avpl the avpl in which to insert. | |||
458 | * @param avp the avp to be inserted. | |||
459 | * | |||
460 | * Inserts the given AVP into the given AVPL if an identical one isn't yet there. | |||
461 | * | |||
462 | * Return value: whether it was inserted or not. | |||
463 | * | |||
464 | * BEWARE: Check the return value, you might need to delete the avp if | |||
465 | * it is not inserted. | |||
466 | **/ | |||
467 | extern bool_Bool insert_avp(AVPL* avpl, AVP* avp) { | |||
468 | AVPN* c; | |||
469 | ||||
470 | #ifdef _AVP_DEBUGGING | |||
471 | dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %p %p %s%c%s;",avpl,avp,avp->n,avp->o,avp->v); | |||
472 | #endif | |||
473 | ||||
474 | /* get to the insertion point */ | |||
475 | for (c=avpl->null.next; c->avp; c = c->next) { | |||
476 | int name_diff = strcmp(avp->n, c->avp->n); | |||
477 | ||||
478 | if (name_diff == 0) { | |||
479 | int value_diff = strcmp(avp->v, c->avp->v); | |||
480 | ||||
481 | if (value_diff < 0) { | |||
482 | break; | |||
483 | } | |||
484 | ||||
485 | if (value_diff == 0) { | |||
486 | // ignore duplicate values, prevents (a=1, a=1) | |||
487 | // note that this is also used to insert | |||
488 | // conditions AVPs, so really check if the name, | |||
489 | // value and operator are all equal. | |||
490 | if (c->avp->o == avp->o && avp->o == AVP_OP_EQUAL'=') { | |||
491 | return false0; | |||
492 | } | |||
493 | } | |||
494 | } | |||
495 | ||||
496 | if (name_diff < 0) { | |||
497 | break; | |||
498 | } | |||
499 | } | |||
500 | ||||
501 | insert_avp_before_node(avpl, c, avp, false0); | |||
502 | ||||
503 | return true1; | |||
504 | } | |||
505 | ||||
506 | /** | |||
507 | * get_avp_by_name: | |||
508 | * @param avpl the avpl from which to try to get the avp. | |||
509 | * @param name the name of the avp we are looking for. | |||
510 | * @param cookie variable in which to store the state between calls. | |||
511 | * | |||
512 | * Gets pointer to the next avp whose name is given; uses cookie to store its | |||
513 | * state between calls. | |||
514 | * | |||
515 | * Return value: a pointer to the next matching avp if there's one, else NULL. | |||
516 | * | |||
517 | **/ | |||
518 | extern AVP* get_avp_by_name(AVPL* avpl, char* name, void** cookie) { | |||
519 | AVPN* curr; | |||
520 | AVPN* start = (AVPN*) *cookie; | |||
521 | ||||
522 | #ifdef _AVP_DEBUGGING | |||
523 | dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %p %s %p",avpl,name,*cookie); | |||
524 | #endif | |||
525 | ||||
526 | name = scs_subscribe(avp_strings, name); | |||
527 | ||||
528 | if (!start) start = avpl->null.next; | |||
529 | ||||
530 | for ( curr = start; curr->avp; curr = curr->next ) { | |||
531 | if ( curr->avp->n == name ) { | |||
532 | break; | |||
533 | } | |||
534 | } | |||
535 | ||||
536 | *cookie = curr; | |||
537 | ||||
538 | #ifdef _AVP_DEBUGGING | |||
539 | dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %p",curr); | |||
540 | #endif | |||
541 | ||||
542 | scs_unsubscribe(avp_strings, name); | |||
543 | ||||
544 | return curr->avp; | |||
545 | } | |||
546 | ||||
547 | /** | |||
548 | * extract_avp_by_name: | |||
549 | * @param avpl the avpl from which to try to extract the avp. | |||
550 | * @param name the name of the avp we are looking for. | |||
551 | * | |||
552 | * Extracts from the avpl the next avp whose name is given; | |||
553 | * | |||
554 | * Return value: a pointer to extracted avp if there's one, else NULL. | |||
555 | * | |||
556 | **/ | |||
557 | extern AVP* extract_avp_by_name(AVPL* avpl, char* name) { | |||
558 | AVPN* curr; | |||
559 | AVP* avp = NULL((void*)0); | |||
560 | ||||
561 | #ifdef _AVP_DEBUGGING | |||
562 | dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %p %s",avpl,name); | |||
563 | #endif | |||
564 | ||||
565 | name = scs_subscribe(avp_strings, name); | |||
566 | ||||
567 | for ( curr = avpl->null.next; curr->avp; curr = curr->next ) { | |||
568 | if ( curr->avp->n == name ) { | |||
569 | break; | |||
570 | } | |||
571 | } | |||
572 | ||||
573 | scs_unsubscribe(avp_strings, name); | |||
574 | ||||
575 | if( ! curr->avp ) return NULL((void*)0); | |||
576 | ||||
577 | curr->next->prev = curr->prev; | |||
578 | curr->prev->next = curr->next; | |||
579 | ||||
580 | avp = curr->avp; | |||
581 | ||||
582 | g_slice_free(any_avp_type,(any_avp_type*)curr)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)curr)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)curr )); } while (0); | |||
583 | ||||
584 | (avpl->len)--; | |||
585 | ||||
586 | #ifdef _AVP_DEBUGGING | |||
587 | dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); | |||
588 | #endif | |||
589 | ||||
590 | #ifdef _AVP_DEBUGGING | |||
591 | dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %p",avp); | |||
592 | #endif | |||
593 | ||||
594 | return avp; | |||
595 | } | |||
596 | ||||
597 | ||||
598 | /** | |||
599 | * extract_first_avp: | |||
600 | * @param avpl the avpl from which to try to extract the avp. | |||
601 | * | |||
602 | * Extracts the first avp from the avpl. | |||
603 | * | |||
604 | * Return value: a pointer to extracted avp if there's one, else NULL. | |||
605 | * | |||
606 | **/ | |||
607 | extern AVP* extract_first_avp(AVPL* avpl) { | |||
608 | AVP* avp; | |||
609 | AVPN* node; | |||
610 | ||||
611 | #ifdef _AVP_DEBUGGING | |||
612 | dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %p",avpl); | |||
613 | #endif | |||
614 | ||||
615 | node = avpl->null.next; | |||
616 | ||||
617 | avpl->null.next->prev = &avpl->null; | |||
618 | avpl->null.next = node->next; | |||
619 | ||||
620 | avp = node->avp; | |||
621 | ||||
622 | if (avp) { | |||
623 | g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node )); } while (0); | |||
624 | (avpl->len)--; | |||
625 | #ifdef _AVP_DEBUGGING | |||
626 | dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); | |||
627 | #endif | |||
628 | } | |||
629 | ||||
630 | #ifdef _AVP_DEBUGGING | |||
631 | dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %p",avp); | |||
632 | #endif | |||
633 | ||||
634 | return avp; | |||
635 | ||||
636 | } | |||
637 | ||||
638 | ||||
639 | /** | |||
640 | * extract_last_avp: | |||
641 | * @param avpl the avpl from which to try to extract the avp. | |||
642 | * | |||
643 | * Extracts the last avp from the avpl. | |||
644 | * | |||
645 | * Return value: a pointer to extracted avp if there's one, else NULL. | |||
646 | * | |||
647 | **/ | |||
648 | extern AVP* extract_last_avp(AVPL* avpl) { | |||
649 | AVP* avp; | |||
650 | AVPN* node; | |||
651 | ||||
652 | node = avpl->null.prev; | |||
653 | ||||
654 | avpl->null.prev->next = &avpl->null; | |||
655 | avpl->null.prev = node->prev; | |||
656 | ||||
657 | avp = node->avp; | |||
658 | ||||
659 | if (avp) { | |||
660 | g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node )); } while (0); | |||
661 | (avpl->len)--; | |||
662 | #ifdef _AVP_DEBUGGING | |||
663 | dbg_print(dbg_avpl,4,dbg_fp,"avpl: %p new len: %i",avpl,avpl->len); | |||
664 | #endif | |||
665 | } | |||
666 | ||||
667 | #ifdef _AVP_DEBUGGING | |||
668 | dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",avp); | |||
669 | #endif | |||
670 | ||||
671 | return avp; | |||
672 | ||||
673 | } | |||
674 | ||||
675 | ||||
676 | /** | |||
677 | * delete_avpl: | |||
678 | * @param avpl the avpl from which to try to extract the avp. | |||
679 | * @param avps_too whether or not it should delete the avps as well. | |||
680 | * | |||
681 | * Destroys an avpl and releases the resources it uses. If told to do | |||
682 | * so releases the avps as well. | |||
683 | * | |||
684 | **/ | |||
685 | extern void delete_avpl(AVPL* avpl, bool_Bool avps_too) { | |||
686 | AVP* avp; | |||
687 | #ifdef _AVP_DEBUGGING | |||
688 | dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %p",avpl); | |||
689 | #endif | |||
690 | ||||
691 | while(( avp = extract_last_avp(avpl))) { | |||
692 | if (avps_too) { | |||
693 | delete_avp(avp); | |||
694 | } | |||
695 | } | |||
696 | ||||
697 | scs_unsubscribe(avp_strings,avpl->name); | |||
698 | g_slice_free(any_avp_type,(any_avp_type*)avpl)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)avpl)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)avpl )); } while (0); | |||
699 | } | |||
700 | ||||
701 | ||||
702 | ||||
703 | /** | |||
704 | * get_next_avp: | |||
705 | * @param avpl the avpl from which to try to get the avps. | |||
706 | * @param cookie variable in which to store the state between calls. | |||
707 | * | |||
708 | * Iterates on an avpl to get its avps. | |||
709 | * | |||
710 | * Return value: a pointer to the next avp if there's one, else NULL. | |||
711 | * | |||
712 | **/ | |||
713 | extern AVP* get_next_avp(AVPL* avpl, void** cookie) { | |||
714 | AVPN* node; | |||
715 | ||||
716 | #ifdef _AVP_DEBUGGING | |||
717 | dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %p avpn: %p",avpl,*cookie); | |||
718 | #endif | |||
719 | ||||
720 | if (*cookie) { | |||
721 | node = (AVPN*) *cookie; | |||
722 | } else { | |||
723 | node = avpl->null.next; | |||
724 | } | |||
725 | ||||
726 | *cookie = node->next; | |||
727 | ||||
728 | #ifdef _AVP_DEBUGGING | |||
729 | dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %p",node->avp); | |||
730 | #endif | |||
731 | ||||
732 | return node->avp; | |||
733 | } | |||
734 | ||||
735 | /** | |||
736 | * avpl_to_str: | |||
737 | * @param avpl the avpl to represent. | |||
738 | * | |||
739 | * Creates a newly allocated string containing a representation of an avpl. | |||
740 | * | |||
741 | * Return value: a pointer to the newly allocated string. | |||
742 | * | |||
743 | **/ | |||
744 | char* avpl_to_str(AVPL* avpl) { | |||
745 | AVPN* c; | |||
746 | GString* s = g_string_new(""); | |||
747 | char* avp_s; | |||
748 | char* r; | |||
749 | ||||
750 | for(c=avpl->null.next; c->avp; c = c->next) { | |||
751 | avp_s = avp_to_str(c->avp)(wmem_strdup_printf(((void*)0), "%s%c%s",c->avp->n,c-> avp->o,c->avp->v)); | |||
752 | g_string_append_printf(s," %s;",avp_s); | |||
753 | g_free(avp_s); | |||
754 | } | |||
755 | ||||
756 | r = g_string_free(s,FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((s), ( (0))) : g_string_free_and_steal (s)) : (g_string_free) ((s), ( (0)))); | |||
757 | ||||
758 | /* g_strchug(r); ? */ | |||
759 | return r; | |||
760 | } | |||
761 | ||||
762 | extern char* avpl_to_dotstr(AVPL* avpl) { | |||
763 | AVPN* c; | |||
764 | GString* s = g_string_new(""); | |||
765 | char* avp_s; | |||
766 | char* r; | |||
767 | ||||
768 | for(c=avpl->null.next; c->avp; c = c->next) { | |||
769 | avp_s = avp_to_str(c->avp)(wmem_strdup_printf(((void*)0), "%s%c%s",c->avp->n,c-> avp->o,c->avp->v)); | |||
770 | g_string_append_printf(s," .%s;",avp_s); | |||
771 | g_free(avp_s); | |||
772 | } | |||
773 | ||||
774 | r = g_string_free(s,FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((s), ( (0))) : g_string_free_and_steal (s)) : (g_string_free) ((s), ( (0)))); | |||
775 | ||||
776 | /* g_strchug(r); ? */ | |||
777 | return r; | |||
778 | } | |||
779 | ||||
780 | /** | |||
781 | * merge_avpl: | |||
782 | * @param dst the avpl in which to merge the avps. | |||
783 | * @param src the avpl from which to get the avps. | |||
784 | * @param copy_avps whether avps should be copied instead of referenced. | |||
785 | * | |||
786 | * Adds the avps of src that are not existent in dst into dst. | |||
787 | * | |||
788 | **/ | |||
789 | extern void merge_avpl(AVPL* dst, AVPL* src, bool_Bool copy_avps) { | |||
790 | AVPN* cd = NULL((void*)0); | |||
791 | AVPN* cs = NULL((void*)0); | |||
792 | ||||
793 | #ifdef _AVP_DEBUGGING | |||
794 | dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %p %p",dst,src); | |||
795 | #endif | |||
796 | ||||
797 | cs = src->null.next; | |||
798 | cd = dst->null.next; | |||
799 | ||||
800 | while (cs->avp && cd->avp) { | |||
801 | ||||
802 | int name_diff = strcmp(cd->avp->n, cs->avp->n); | |||
803 | ||||
804 | if (name_diff < 0) { | |||
805 | // dest < source, advance dest to find a better place to insert | |||
806 | cd = cd->next; | |||
807 | } else if (name_diff > 0) { | |||
808 | // dest > source, so it can be definitely inserted here. | |||
809 | insert_avp_before_node(dst, cd, cs->avp, copy_avps); | |||
810 | cs = cs->next; | |||
811 | } else { | |||
812 | // attribute names are equal. Ignore duplicate values but ensure that other values are sorted. | |||
813 | int value_diff = strcmp(cd->avp->v, cs->avp->v); | |||
814 | ||||
815 | if (value_diff < 0) { | |||
816 | // dest < source, do not insert it yet | |||
817 | cd = cd->next; | |||
818 | } else if (value_diff > 0) { | |||
819 | // dest > source, insert AVP before the current dest AVP | |||
820 | insert_avp_before_node(dst, cd, cs->avp, copy_avps); | |||
821 | cs = cs->next; | |||
822 | } else { | |||
823 | // identical AVPs, do not create a duplicate. | |||
824 | cs = cs->next; | |||
825 | } | |||
826 | } | |||
827 | } | |||
828 | ||||
829 | // if there are remaining source AVPs while there are no more destination | |||
830 | // AVPs (cd now represents the NULL item, after the last item), append | |||
831 | // all remaining source AVPs to the end | |||
832 | while (cs->avp) { | |||
833 | insert_avp_before_node(dst, cd, cs->avp, copy_avps); | |||
834 | cs = cs->next; | |||
835 | } | |||
836 | ||||
837 | #ifdef _AVP_DEBUGGING | |||
838 | dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done"); | |||
839 | #endif | |||
840 | ||||
841 | return; | |||
842 | } | |||
843 | ||||
844 | ||||
845 | /** | |||
846 | * new_avpl_from_avpl: | |||
847 | * @param name the name of the new avpl. | |||
848 | * @param avpl the avpl from which to get the avps. | |||
849 | * @param copy_avps whether avps should be copied instead of referenced. | |||
850 | * | |||
851 | * Creates a new avpl containing the same avps as the given avpl | |||
852 | * It will either reference or copy the avps. | |||
853 | * | |||
854 | * Return value: a pointer to the newly allocated string. | |||
855 | * | |||
856 | **/ | |||
857 | extern AVPL* new_avpl_from_avpl(const char* name, AVPL* avpl, bool_Bool copy_avps) { | |||
858 | AVPL* newavpl = new_avpl(name); | |||
859 | void* cookie = NULL((void*)0); | |||
860 | AVP* avp; | |||
861 | AVP* copy; | |||
862 | ||||
863 | #ifdef _AVP_DEBUGGING | |||
864 | dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %p from=%p name='%s'",newavpl,avpl,name); | |||
865 | #endif | |||
866 | ||||
867 | while(( avp = get_next_avp(avpl,&cookie) )) { | |||
868 | if (copy_avps) { | |||
869 | copy = avp_copy(avp); | |||
870 | if ( ! insert_avp(newavpl,copy) ) { | |||
871 | delete_avp(copy); | |||
872 | } | |||
873 | } else { | |||
874 | insert_avp(newavpl,avp); | |||
875 | } | |||
876 | } | |||
877 | ||||
878 | #ifdef _AVP_DEBUGGING | |||
879 | dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done"); | |||
880 | #endif | |||
881 | ||||
882 | return newavpl; | |||
883 | } | |||
884 | ||||
885 | /** | |||
886 | * match_avp: | |||
887 | * @param src an src to be compared against an "op" avp | |||
888 | * @param op the "op" avp that will be matched against the src avp | |||
889 | * | |||
890 | * Checks whether or not two avp's match. | |||
891 | * | |||
892 | * Return value: a pointer to the src avp if there's a match. | |||
893 | * | |||
894 | **/ | |||
895 | extern AVP* match_avp(AVP* src, AVP* op) { | |||
896 | char** splited; | |||
897 | int i; | |||
898 | char* p; | |||
899 | unsigned ls; | |||
900 | unsigned lo; | |||
901 | double fs = 0.0; | |||
902 | double fo = 0.0; | |||
903 | bool_Bool lower = false0; | |||
904 | ||||
905 | #ifdef _AVP_DEBUGGING | |||
906 | dbg_print(dbg_avpl_op,3,dbg_fp,"match_avp: %s%c%s; vs. %s%c%s;",src->n,src->o,src->v,op->n,op->o,op->v); | |||
907 | #endif | |||
908 | ||||
909 | if ( src->n != op->n ) { | |||
910 | return NULL((void*)0); | |||
911 | } | |||
912 | ||||
913 | switch (op->o) { | |||
914 | case AVP_OP_EXISTS'?': | |||
915 | return src; | |||
916 | case AVP_OP_EQUAL'=': | |||
917 | return src->v == op->v ? src : NULL((void*)0); | |||
918 | case AVP_OP_NOTEQUAL'!': | |||
919 | return !( src->v == op->v) ? src : NULL((void*)0); | |||
920 | case AVP_OP_STARTS'^': | |||
921 | return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL((void*)0); | |||
922 | case AVP_OP_ONEOFF'|': | |||
923 | splited = g_strsplit(op->v,"|",0); | |||
924 | if (splited) { | |||
925 | for (i=0;splited[i];i++) { | |||
926 | if(g_str_equal(splited[i],src->v)(strcmp ((const char *) (splited[i]), (const char *) (src-> v)) == 0)) { | |||
927 | g_strfreev(splited); | |||
928 | return src; | |||
929 | } | |||
930 | } | |||
931 | g_strfreev(splited); | |||
932 | } | |||
933 | return NULL((void*)0); | |||
934 | ||||
935 | case AVP_OP_LOWER'<': | |||
936 | lower = true1; | |||
937 | /* FALLTHRU */ | |||
938 | case AVP_OP_HIGHER'>': | |||
939 | ||||
940 | fs = g_ascii_strtod(src->v, NULL((void*)0)); | |||
941 | fo = g_ascii_strtod(op->v, NULL((void*)0)); | |||
942 | ||||
943 | if (lower) { | |||
944 | if (fs<fo) return src; | |||
945 | else return NULL((void*)0); | |||
946 | } else { | |||
947 | if (fs>fo) return src; | |||
948 | else return NULL((void*)0); | |||
949 | } | |||
950 | case AVP_OP_ENDS'$': | |||
951 | /* does this work? */ | |||
952 | ls = (unsigned) strlen(src->v); | |||
953 | lo = (unsigned) strlen(op->v); | |||
954 | ||||
955 | if ( ls < lo ) { | |||
956 | return NULL((void*)0); | |||
957 | } else { | |||
958 | p = src->v + ( ls - lo ); | |||
959 | return g_str_equal(p,op->v)(strcmp ((const char *) (p), (const char *) (op->v)) == 0) ? src : NULL((void*)0); | |||
960 | } | |||
961 | ||||
962 | /* case AVP_OP_TRANSF: */ | |||
963 | /* return do_transform(src,op); */ | |||
964 | case AVP_OP_CONTAINS'~': | |||
965 | return g_strrstr(src->v, op->v) ? src : NULL((void*)0); | |||
966 | } | |||
967 | /* will never get here */ | |||
968 | return NULL((void*)0); | |||
969 | } | |||
970 | ||||
971 | ||||
972 | ||||
973 | /** | |||
974 | * new_avpl_loose_match: | |||
975 | * @param name the name of the resulting avpl | |||
976 | * @param src the data AVPL to be matched against a condition AVPL | |||
977 | * @param op the conditions AVPL that will be matched against the data AVPL | |||
978 | * @param copy_avps whether the avps in the resulting avpl should be copied | |||
979 | * | |||
980 | * Creates a new AVP list containing all data AVPs that matched any of the | |||
981 | * conditions AVPs. If there are no matches, an empty list will be returned. | |||
982 | * | |||
983 | * Note: Loose will always be considered a successful match, it matches zero or | |||
984 | * more conditions. | |||
985 | */ | |||
986 | extern AVPL* new_avpl_loose_match(const char* name, | |||
987 | AVPL* src, | |||
988 | AVPL* op, | |||
989 | bool_Bool copy_avps) { | |||
990 | ||||
991 | AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name)); | |||
992 | AVPN* co = NULL((void*)0); | |||
993 | AVPN* cs = NULL((void*)0); | |||
994 | ||||
995 | #ifdef _AVP_DEBUGGING | |||
996 | dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %p src=%p op=%p name='%s'",newavpl,src,op,name); | |||
997 | #endif | |||
998 | ||||
999 | ||||
1000 | cs = src->null.next; | |||
1001 | co = op->null.next; | |||
1002 | while (cs->avp && co->avp) { | |||
1003 | int name_diff = strcmp(co->avp->n, cs->avp->n); | |||
1004 | ||||
1005 | if (name_diff < 0) { | |||
1006 | // op < source, op is not matching | |||
1007 | co = co->next; | |||
1008 | } else if (name_diff > 0) { | |||
1009 | // op > source, source is not matching | |||
1010 | cs = cs->next; | |||
1011 | } else { | |||
1012 | // attribute match found, let's see if there is any condition (op) that accepts this data AVP. | |||
1013 | AVPN *cond = co; | |||
1014 | do { | |||
1015 | if (match_avp(cs->avp, cond->avp)) { | |||
1016 | insert_avp_before_node(newavpl, newavpl->null.prev->next, cs->avp, copy_avps); | |||
1017 | break; | |||
1018 | } | |||
1019 | cond = cond->next; | |||
1020 | } while (cond->avp && cond->avp->n == cs->avp->n); | |||
1021 | cs = cs->next; | |||
1022 | } | |||
1023 | } | |||
1024 | ||||
1025 | // return matches (possible none) | |||
1026 | return newavpl; | |||
1027 | } | |||
1028 | ||||
1029 | /** | |||
1030 | * new_avpl_pairs_match: | |||
1031 | * @param name the name of the resulting avpl | |||
1032 | * @param src the data AVPL to be matched against a condition AVPL | |||
1033 | * @param op the conditions AVPL that will be matched against the data AVPL | |||
1034 | * @param strict true if every condition must have a matching data AVP, false if | |||
1035 | * it is also acceptable that only one of the condition AVPs for the same | |||
1036 | * attribute is matching. | |||
1037 | * @param copy_avps whether the avps in the resulting avpl should be copied | |||
1038 | * | |||
1039 | * Creates an AVP list by matching pairs of conditions and data AVPs, returning | |||
1040 | * the data AVPs. If strict is true, then each condition must be paired with a | |||
1041 | * matching data AVP. If strict is false, then some conditions are allowed to | |||
1042 | * fail when other conditions for the same attribute do have a match. Note that | |||
1043 | * if the condition AVPL is empty, the result will be a match (an empty list). | |||
1044 | * | |||
1045 | * Return value: a pointer to the newly created avpl containing the | |||
1046 | * matching avps or NULL if there is no match. | |||
1047 | */ | |||
1048 | extern AVPL* new_avpl_pairs_match(const char* name, AVPL* src, AVPL* op, bool_Bool strict, bool_Bool copy_avps) { | |||
1049 | AVPL* newavpl; | |||
1050 | AVPN* co = NULL((void*)0); | |||
1051 | AVPN* cs = NULL((void*)0); | |||
1052 | const char *last_match = NULL((void*)0); | |||
1053 | bool_Bool matched = true1; | |||
1054 | ||||
1055 | newavpl = new_avpl(scs_subscribe(avp_strings, name)); | |||
1056 | ||||
1057 | #ifdef _AVP_DEBUGGING | |||
1058 | dbg_print(dbg_avpl_op,3,dbg_fp,"%s: %p src=%p op=%p name='%s'",G_STRFUNC((const char*) (__func__)),newavpl,src,op,name); | |||
1059 | #endif | |||
1060 | ||||
1061 | cs = src->null.next; | |||
1062 | co = op->null.next; | |||
1063 | while (cs->avp
| |||
1064 | int name_diff = g_strcmp0(co->avp->n, cs->avp->n); | |||
1065 | const char *failed_match = NULL((void*)0); | |||
1066 | ||||
1067 | if (name_diff < 0) { | |||
1068 | // op < source, op has no data avp with same attribute. | |||
1069 | failed_match = co->avp->n; | |||
1070 | co = co->next; | |||
1071 | } else if (name_diff > 0) { | |||
1072 | // op > source, the source avp is not matched by any condition | |||
1073 | cs = cs->next; | |||
1074 | } else { | |||
1075 | // Matching attributes found, now try to find a matching data AVP for the condition. | |||
1076 | if (match_avp(cs->avp, co->avp)) { | |||
1077 | insert_avp_before_node(newavpl, newavpl->null.prev->next, cs->avp, copy_avps); | |||
1078 | last_match = co->avp->n; | |||
1079 | cs = cs->next; | |||
1080 | } else { | |||
1081 | failed_match = co->avp->n; | |||
1082 | } | |||
1083 | co = co->next; | |||
1084 | } | |||
1085 | ||||
1086 | // condition did not match, check if we can continue matching. | |||
1087 | if (failed_match) { | |||
1088 | if (strict) { | |||
1089 | matched = false0; | |||
1090 | break; | |||
1091 | } else if (last_match != failed_match) { | |||
1092 | // None of the conditions so far matched the attribute, check for other candidates | |||
1093 | if (!co->avp || co->avp->n != last_match) { | |||
1094 | matched = false0; | |||
1095 | break; | |||
1096 | } | |||
1097 | } | |||
1098 | } | |||
1099 | } | |||
1100 | ||||
1101 | // if there are any conditions remaining, then those could not be matched | |||
1102 | if (matched && strict && co->avp) { | |||
1103 | matched = false0; | |||
1104 | } | |||
1105 | ||||
1106 | if (matched) { | |||
1107 | // there was a match, accept it | |||
1108 | return newavpl; | |||
1109 | } else { | |||
1110 | // no match, only delete AVPs too if they were copied | |||
1111 | delete_avpl(newavpl, copy_avps); | |||
1112 | return NULL((void*)0); | |||
1113 | } | |||
1114 | } | |||
1115 | ||||
1116 | ||||
1117 | /** | |||
1118 | * new_avpl_from_match: | |||
1119 | * @param mode The matching method, one of AVPL_STRICT, AVPL_LOOSE, AVPL_EVERY. | |||
1120 | * @param name the name of the resulting avpl | |||
1121 | * @param src the data AVPL to be matched against a condition AVPL | |||
1122 | * @param op the conditions AVPL that will be matched against the data AVPL | |||
1123 | * | |||
1124 | * Matches the conditions AVPL against the original AVPL according to the mode. | |||
1125 | * If there is no match, NULL is returned. If there is actually a match, then | |||
1126 | * the matching AVPs (a subset of the data) are returned. | |||
1127 | */ | |||
1128 | extern AVPL* new_avpl_from_match(avpl_match_mode mode, const char* name,AVPL* src, AVPL* op, bool_Bool copy_avps) { | |||
1129 | AVPL* avpl = NULL((void*)0); | |||
1130 | ||||
1131 | switch (mode) { | |||
1132 | case AVPL_STRICT: | |||
1133 | avpl = new_avpl_pairs_match(name, src, op, true1, copy_avps); | |||
1134 | break; | |||
1135 | case AVPL_LOOSE: | |||
1136 | avpl = new_avpl_loose_match(name,src,op,copy_avps); | |||
1137 | break; | |||
1138 | case AVPL_EVERY: | |||
1139 | avpl = new_avpl_pairs_match(name, src, op, false0, copy_avps); | |||
1140 | break; | |||
1141 | case AVPL_NO_MATCH: | |||
1142 | // XXX this seems unused | |||
1143 | avpl = new_avpl_from_avpl(name,src,copy_avps); | |||
1144 | merge_avpl(avpl, op, copy_avps); | |||
1145 | break; | |||
1146 | } | |||
1147 | ||||
1148 | return avpl; | |||
1149 | } | |||
1150 | ||||
1151 | /** | |||
1152 | * delete_avpl_transform: | |||
1153 | * @param op a pointer to the avpl transformation object | |||
1154 | * | |||
1155 | * Destroys an avpl transformation object and releases all the resources it | |||
1156 | * uses. | |||
1157 | * | |||
1158 | **/ | |||
1159 | extern void delete_avpl_transform(AVPL_Transf* op) { | |||
1160 | AVPL_Transf* next; | |||
1161 | ||||
1162 | for (; op ; op = next) { | |||
1163 | next = op->next; | |||
1164 | ||||
1165 | g_free(op->name); | |||
1166 | ||||
1167 | if (op->match) { | |||
1168 | delete_avpl(op->match,true1); | |||
1169 | } | |||
1170 | ||||
1171 | if (op->replace) { | |||
1172 | delete_avpl(op->replace,true1); | |||
1173 | } | |||
1174 | ||||
1175 | g_free(op); | |||
1176 | } | |||
1177 | ||||
1178 | } | |||
1179 | ||||
1180 | ||||
1181 | /** | |||
1182 | * avpl_transform: | |||
1183 | * @param src the source avpl for the transform operation. | |||
1184 | * @param op a pointer to the avpl transformation object to apply. | |||
1185 | * | |||
1186 | * Applies the "op" transformation to an avpl, matches it and eventually | |||
1187 | * replaces or inserts the transformed avps. | |||
1188 | * | |||
1189 | * Return value: whether the transformation was performed or not. | |||
1190 | **/ | |||
1191 | extern void avpl_transform(AVPL* src, AVPL_Transf* op) { | |||
1192 | AVPL* avpl = NULL((void*)0); | |||
1193 | AVPN* cs; | |||
1194 | AVPN* cm; | |||
1195 | AVPN* n; | |||
1196 | ||||
1197 | #ifdef _AVP_DEBUGGING | |||
1198 | dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%p op=%p",src,op); | |||
1199 | #endif | |||
1200 | ||||
1201 | for ( ; op ; op = op->next) { | |||
| ||||
1202 | ||||
1203 | avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, true1); | |||
1204 | ||||
1205 | if (avpl) { | |||
1206 | switch (op->replace_mode) { | |||
1207 | case AVPL_NO_REPLACE: | |||
1208 | delete_avpl(avpl,true1); | |||
1209 | return; | |||
1210 | case AVPL_INSERT: | |||
1211 | merge_avpl(src,op->replace,true1); | |||
1212 | delete_avpl(avpl,true1); | |||
1213 | return; | |||
1214 | case AVPL_REPLACE: | |||
1215 | cs = src->null.next; | |||
1216 | cm = avpl->null.next; | |||
1217 | // Removes AVPs from the source which are in the matched data. | |||
1218 | // Assume that the matched set is a subset of the source. | |||
1219 | while (cs->avp && cm->avp) { | |||
1220 | if (cs->avp->n == cm->avp->n && cs->avp->v == cm->avp->v) { | |||
1221 | n = cs->next; | |||
1222 | ||||
1223 | cs->prev->next = cs->next; | |||
1224 | cs->next->prev = cs->prev; | |||
1225 | ||||
1226 | if (cs->avp) | |||
1227 | delete_avp(cs->avp); | |||
1228 | g_slice_free(any_avp_type,(any_avp_type*)cs)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)cs)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)cs) ); } while (0); | |||
1229 | ||||
1230 | cs = n; | |||
1231 | cm = cm->next; | |||
1232 | } else { | |||
1233 | // Current matched AVP is not equal to the current | |||
1234 | // source AVP. Since there must be a source AVP for | |||
1235 | // each matched AVP, advance current source and not | |||
1236 | // the match AVP. | |||
1237 | cs = cs->next; | |||
1238 | } | |||
1239 | } | |||
1240 | ||||
1241 | merge_avpl(src,op->replace,true1); | |||
1242 | delete_avpl(avpl,true1); | |||
1243 | return; | |||
1244 | } | |||
1245 | } | |||
1246 | } | |||
1247 | } | |||
1248 | ||||
1249 | ||||
1250 | /** | |||
1251 | * new_loal: | |||
1252 | * @param name the name the loal will take. | |||
1253 | * | |||
1254 | * Creates an empty list of avp lists. | |||
1255 | * | |||
1256 | * Return value: a pointer to the newly created loal. | |||
1257 | **/ | |||
1258 | extern LoAL* new_loal(const char* name) { | |||
1259 | LoAL* new_loal_p = (LoAL*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
1260 | ||||
1261 | if (! name) { | |||
1262 | name = "anonymous"; | |||
1263 | } | |||
1264 | ||||
1265 | #ifdef _AVP_DEBUGGING | |||
1266 | dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_p: %p name=%s",new_loal_p,name); | |||
1267 | #endif | |||
1268 | ||||
1269 | new_loal_p->name = scs_subscribe(avp_strings,name); | |||
1270 | new_loal_p->null.avpl = NULL((void*)0); | |||
1271 | new_loal_p->null.next = &new_loal_p->null; | |||
1272 | new_loal_p->null.prev = &new_loal_p->null; | |||
1273 | new_loal_p->len = 0; | |||
1274 | return new_loal_p; | |||
1275 | } | |||
1276 | ||||
1277 | /** | |||
1278 | * loal_append: | |||
1279 | * @param loal the loal on which to operate. | |||
1280 | * @param avpl the avpl to append. | |||
1281 | * | |||
1282 | * Appends an avpl to a loal. | |||
1283 | * | |||
1284 | **/ | |||
1285 | extern void loal_append(LoAL* loal, AVPL* avpl) { | |||
1286 | LoALnode* node = (LoALnode*)g_slice_new(any_avp_type)((any_avp_type*) g_slice_alloc (sizeof (any_avp_type))); | |||
1287 | ||||
1288 | #ifdef _AVP_DEBUGGING | |||
1289 | dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %p",node); | |||
1290 | #endif | |||
1291 | ||||
1292 | node->avpl = avpl; | |||
1293 | node->next = &loal->null; | |||
1294 | node->prev = loal->null.prev; | |||
1295 | ||||
1296 | loal->null.prev->next = node; | |||
1297 | loal->null.prev = node; | |||
1298 | loal->len++; | |||
1299 | } | |||
1300 | ||||
1301 | ||||
1302 | /** | |||
1303 | * extract_first_avpl: | |||
1304 | * @param loal the loal on which to operate. | |||
1305 | * | |||
1306 | * Extracts the first avpl contained in a loal. | |||
1307 | * | |||
1308 | * Return value: a pointer to the extracted avpl. | |||
1309 | * | |||
1310 | **/ | |||
1311 | extern AVPL* extract_first_avpl(LoAL* loal) { | |||
1312 | LoALnode* node; | |||
1313 | AVPL* avpl; | |||
1314 | ||||
1315 | #ifdef _AVP_DEBUGGING | |||
1316 | dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name); | |||
1317 | #endif | |||
1318 | ||||
1319 | node = loal->null.next; | |||
1320 | ||||
1321 | loal->null.next->next->prev = &loal->null; | |||
1322 | loal->null.next = node->next; | |||
1323 | ||||
1324 | loal->len--; | |||
1325 | ||||
1326 | avpl = node->avpl; | |||
1327 | ||||
1328 | if ( avpl ) { | |||
1329 | g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node )); } while (0); | |||
1330 | ||||
1331 | #ifdef _AVP_DEBUGGING | |||
1332 | dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name); | |||
1333 | dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node); | |||
1334 | #endif | |||
1335 | } | |||
1336 | ||||
1337 | return avpl; | |||
1338 | } | |||
1339 | ||||
1340 | /** | |||
1341 | * extract_first_avpl: | |||
1342 | * @param loal the loal on which to operate. | |||
1343 | * | |||
1344 | * Extracts the last avpl contained in a loal. | |||
1345 | * | |||
1346 | * Return value: a pointer to the extracted avpl. | |||
1347 | * | |||
1348 | **/ | |||
1349 | extern AVPL* extract_last_avpl(LoAL* loal){ | |||
1350 | LoALnode* node; | |||
1351 | AVPL* avpl; | |||
1352 | ||||
1353 | node = loal->null.prev; | |||
1354 | ||||
1355 | loal->null.prev->prev->next = &loal->null; | |||
1356 | loal->null.prev = node->prev; | |||
1357 | ||||
1358 | loal->len--; | |||
1359 | ||||
1360 | avpl = node->avpl; | |||
1361 | ||||
1362 | if ( avpl ) { | |||
1363 | g_slice_free(any_avp_type,(any_avp_type*)node)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)node)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)node )); } while (0); | |||
1364 | #ifdef _AVP_DEBUGGING | |||
1365 | dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %p",node); | |||
1366 | #endif | |||
1367 | } | |||
1368 | ||||
1369 | return avpl; | |||
1370 | } | |||
1371 | ||||
1372 | /** | |||
1373 | * extract_first_avpl: | |||
1374 | * @param loal the loal on which to operate. | |||
1375 | * @param cookie pointer to the pointer variable to contain the state between calls | |||
1376 | * | |||
1377 | * At each call will return the following avpl from a loal. The given cookie | |||
1378 | * will be used to manatain the state between calls. | |||
1379 | * | |||
1380 | * Return value: a pointer to the next avpl. | |||
1381 | * | |||
1382 | **/ | |||
1383 | extern AVPL* get_next_avpl(LoAL* loal,void** cookie) { | |||
1384 | LoALnode* node; | |||
1385 | ||||
1386 | #ifdef _AVP_DEBUGGING | |||
1387 | dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%p node=%p",loal,*cookie); | |||
1388 | #endif | |||
1389 | ||||
1390 | if (*cookie) { | |||
1391 | node = (LoALnode*) *cookie; | |||
1392 | } else { | |||
1393 | node = loal->null.next; | |||
1394 | } | |||
1395 | ||||
1396 | *cookie = node->next; | |||
1397 | ||||
1398 | return node->avpl; | |||
1399 | } | |||
1400 | ||||
1401 | /** | |||
1402 | * delete_loal: | |||
1403 | * @param loal the loal to be deleted. | |||
1404 | * @param avpls_too whether avpls contained by the loal should be deleted as well | |||
1405 | * @param avps_too whether avps contained by the avpls should be also deleted | |||
1406 | * | |||
1407 | * Destroys a loal and eventually desstroys avpls and avps. | |||
1408 | * | |||
1409 | **/ | |||
1410 | extern void delete_loal(LoAL* loal, bool_Bool avpls_too, bool_Bool avps_too) { | |||
1411 | AVPL* avpl; | |||
1412 | ||||
1413 | #ifdef _AVP_DEBUGGING | |||
1414 | dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %p",loal); | |||
1415 | #endif | |||
1416 | ||||
1417 | while(( avpl = extract_last_avpl(loal) )) { | |||
1418 | if (avpls_too) { | |||
1419 | delete_avpl(avpl,avps_too); | |||
1420 | } | |||
1421 | } | |||
1422 | ||||
1423 | scs_unsubscribe(avp_strings,loal->name); | |||
1424 | g_slice_free(any_avp_type,(any_avp_type*)loal)do { if (1) g_slice_free1 (sizeof (any_avp_type), ((any_avp_type *)loal)); else (void) ((any_avp_type*) 0 == ((any_avp_type*)loal )); } while (0); | |||
1425 | } | |||
1426 | ||||
1427 | ||||
1428 | ||||
1429 | /**************************************************************************** | |||
1430 | ******************* the following are used in load_loal_from_file | |||
1431 | ****************************************************************************/ | |||
1432 | ||||
1433 | /** | |||
1434 | * load_loal_error: | |||
1435 | * Used by loal_from_file to handle errors while loading. | |||
1436 | **/ | |||
1437 | static LoAL* load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, const char* fmt, ...) { | |||
1438 | va_list list; | |||
1439 | char* desc; | |||
1440 | LoAL* ret = NULL((void*)0); | |||
1441 | char* err; | |||
1442 | ||||
1443 | va_start( list, fmt )__builtin_va_start(list, fmt); | |||
1444 | desc = ws_strdup_vprintf(fmt, list)wmem_strdup_vprintf(((void*)0), fmt, list); | |||
1445 | va_end( list )__builtin_va_end(list); | |||
1446 | ||||
1447 | if (loal) { | |||
1448 | err = ws_strdup_printf("Error Loading LoAL from file: in %s at line: %i, %s",loal->name,linenum,desc)wmem_strdup_printf(((void*)0), "Error Loading LoAL from file: in %s at line: %i, %s" ,loal->name,linenum,desc); | |||
1449 | } else { | |||
1450 | err = ws_strdup_printf("Error Loading LoAL at line: %i, %s",linenum,desc)wmem_strdup_printf(((void*)0), "Error Loading LoAL at line: %i, %s" ,linenum,desc); | |||
1451 | } | |||
1452 | ret = new_loal(err); | |||
1453 | ||||
1454 | g_free(desc); | |||
1455 | g_free(err); | |||
1456 | ||||
1457 | if (fp) fclose(fp); | |||
1458 | if (loal) delete_loal(loal,true1,true1); | |||
1459 | if (curr) delete_avpl(curr,true1); | |||
1460 | ||||
1461 | return ret; | |||
1462 | } | |||
1463 | ||||
1464 | ||||
1465 | /* the maximum length allowed for a line */ | |||
1466 | #define MAX_ITEM_LEN8192 8192 | |||
1467 | ||||
1468 | /* this two ugly things are used for tokenizing */ | |||
1469 | #define AVP_OP_CHAR'=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!' '=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!' | |||
1470 | ||||
1471 | #define AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G' : case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T' :case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g' : case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z' : case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':case '7': case '8': case '9': case '.' 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\ | |||
1472 | case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\ | |||
1473 | case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\ | |||
1474 | case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\ | |||
1475 | case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\ | |||
1476 | case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\ | |||
1477 | case '7': case '8': case '9': case '.' | |||
1478 | ||||
1479 | ||||
1480 | /** | |||
1481 | * loal_from_file: | |||
1482 | * @param filename the file containing a loals text representation. | |||
1483 | * | |||
1484 | * Given a filename it will attempt to load a loal containing a copy of | |||
1485 | * the avpls represented in the file. | |||
1486 | * | |||
1487 | * Return value: if successful a pointer to the new populated loal, else NULL. | |||
1488 | * | |||
1489 | **/ | |||
1490 | extern LoAL* loal_from_file(char* filename) { | |||
1491 | FILE *fp = NULL((void*)0); | |||
1492 | char c; | |||
1493 | int i = 0; | |||
1494 | uint32_t linenum = 1; | |||
1495 | char *linenum_buf; | |||
1496 | char *name; | |||
1497 | char *value; | |||
1498 | char op = '?'; | |||
1499 | LoAL *loal_error, *loal = new_loal(filename); | |||
1500 | AVPL* curr = NULL((void*)0); | |||
1501 | AVP* avp; | |||
1502 | ||||
1503 | enum _load_loal_states { | |||
1504 | START, | |||
1505 | BEFORE_NAME, | |||
1506 | IN_NAME, | |||
1507 | IN_VALUE, | |||
1508 | MY_IGNORE | |||
1509 | } state; | |||
1510 | ||||
1511 | linenum_buf = (char*)g_malloc(MAX_ITEM_LEN8192); | |||
1512 | name = (char*)g_malloc(MAX_ITEM_LEN8192); | |||
1513 | value = (char*)g_malloc(MAX_ITEM_LEN8192); | |||
1514 | #ifndef _WIN32 | |||
1515 | if (! getuid()) { | |||
1516 | loal_error = load_loal_error(fp,loal,curr,linenum,"MATE Will not run as root"); | |||
1517 | goto error; | |||
1518 | } | |||
1519 | #endif | |||
1520 | ||||
1521 | state = START; | |||
1522 | ||||
1523 | if (( fp = ws_fopenfopen(filename,"r") )) { | |||
1524 | while(( c = (char) fgetc(fp) )){ | |||
1525 | ||||
1526 | if ( feof(fp) ) { | |||
1527 | if ( ferror(fp) ) { | |||
1528 | report_read_failure(filename,errno(*__errno_location ())); | |||
1529 | loal_error = load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename); | |||
1530 | goto error; | |||
1531 | } | |||
1532 | break; | |||
1533 | } | |||
1534 | ||||
1535 | if ( c == '\n' ) { | |||
1536 | linenum++; | |||
1537 | } | |||
1538 | ||||
1539 | if ( i >= MAX_ITEM_LEN8192 - 1 ) { | |||
1540 | loal_error = load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded"); | |||
1541 | goto error; | |||
1542 | } | |||
1543 | ||||
1544 | switch(state) { | |||
1545 | case MY_IGNORE: | |||
1546 | switch (c) { | |||
1547 | case '\n': | |||
1548 | state = START; | |||
1549 | i = 0; | |||
1550 | continue; | |||
1551 | default: | |||
1552 | continue; | |||
1553 | } | |||
1554 | case START: | |||
1555 | switch (c) { | |||
1556 | case ' ': case '\t': | |||
1557 | /* ignore whitespace at line start */ | |||
1558 | continue; | |||
1559 | case '\n': | |||
1560 | /* ignore empty lines */ | |||
1561 | i = 0; | |||
1562 | continue; | |||
1563 | case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G' : case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T' :case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g' : case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z' : case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':case '7': case '8': case '9': case '.': | |||
1564 | state = IN_NAME; | |||
1565 | i = 0; | |||
1566 | name[i++] = c; | |||
1567 | name[i] = '\0'; | |||
1568 | snprintf(linenum_buf,MAX_ITEM_LEN8192,"%s:%u",filename,linenum); | |||
1569 | curr = new_avpl(linenum_buf); | |||
1570 | continue; | |||
1571 | case '#': | |||
1572 | state = MY_IGNORE; | |||
1573 | continue; | |||
1574 | default: | |||
1575 | loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c); | |||
1576 | goto error; | |||
1577 | } | |||
1578 | case BEFORE_NAME: | |||
1579 | i = 0; | |||
1580 | name[0] = '\0'; | |||
1581 | switch (c) { | |||
1582 | case '\\': | |||
1583 | c = (char) fgetc(fp); | |||
1584 | if (c != '\n') ungetc(c,fp); | |||
1585 | continue; | |||
1586 | case ' ': | |||
1587 | case '\t': | |||
1588 | continue; | |||
1589 | case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G' : case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T' :case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g' : case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z' : case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':case '7': case '8': case '9': case '.': | |||
1590 | state = IN_NAME; | |||
1591 | ||||
1592 | name[i++] = c; | |||
1593 | name[i] = '\0'; | |||
1594 | continue; | |||
1595 | case '\n': | |||
1596 | loal_append(loal,curr); | |||
1597 | curr = NULL((void*)0); | |||
1598 | state = START; | |||
1599 | continue; | |||
1600 | default: | |||
1601 | loal_error = load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c); | |||
1602 | goto error; | |||
1603 | } | |||
1604 | case IN_NAME: | |||
1605 | switch (c) { | |||
1606 | case ';': | |||
1607 | state = BEFORE_NAME; | |||
1608 | ||||
1609 | op = '?'; | |||
1610 | name[i] = '\0'; | |||
1611 | value[0] = '\0'; | |||
1612 | i = 0; | |||
1613 | ||||
1614 | avp = new_avp(name,value,op); | |||
1615 | ||||
1616 | if (! insert_avp(curr,avp) ) { | |||
1617 | delete_avp(avp); | |||
1618 | } | |||
1619 | ||||
1620 | continue; | |||
1621 | case AVP_OP_CHAR'=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!': | |||
1622 | name[i] = '\0'; | |||
1623 | i = 0; | |||
1624 | op = c; | |||
1625 | state = IN_VALUE; | |||
1626 | continue; | |||
1627 | case AVP_NAME_CHAR'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G' : case 'H': case 'I': case 'J':case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T' :case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':case 'e': case 'f': case 'g' : case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':case 'y': case 'z' : case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':case '7': case '8': case '9': case '.': | |||
1628 | name[i++] = c; | |||
1629 | continue; | |||
1630 | case '\n': | |||
1631 | loal_error = load_loal_error(fp,loal,curr,linenum,"operator expected found new line"); | |||
1632 | goto error; | |||
1633 | default: | |||
1634 | loal_error = load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c); | |||
1635 | goto error; | |||
1636 | } | |||
1637 | case IN_VALUE: | |||
1638 | switch (c) { | |||
1639 | case '\\': | |||
1640 | value[i++] = (char) fgetc(fp); | |||
1641 | continue; | |||
1642 | case ';': | |||
1643 | state = BEFORE_NAME; | |||
1644 | ||||
1645 | value[i] = '\0'; | |||
1646 | i = 0; | |||
1647 | ||||
1648 | avp = new_avp(name,value,op); | |||
1649 | ||||
1650 | if (! insert_avp(curr,avp) ) { | |||
1651 | delete_avp(avp); | |||
1652 | } | |||
1653 | continue; | |||
1654 | case '\n': | |||
1655 | loal_error = load_loal_error(fp,loal,curr,linenum,"';' expected found new line"); | |||
1656 | goto error; | |||
1657 | default: | |||
1658 | value[i++] = c; | |||
1659 | continue; | |||
1660 | } | |||
1661 | } | |||
1662 | } | |||
1663 | fclose (fp); | |||
1664 | ||||
1665 | if (curr) { | |||
1666 | // Premature EOF? It could just be a file that doesn't | |||
1667 | // end in a newline, but hard to say without checking | |||
1668 | // state. Error, discard, add to existing loal? | |||
1669 | delete_avpl(curr,true1); | |||
1670 | } | |||
1671 | ||||
1672 | g_free(linenum_buf); | |||
1673 | g_free(name); | |||
1674 | g_free(value); | |||
1675 | ||||
1676 | return loal; | |||
1677 | ||||
1678 | } else { | |||
1679 | report_open_failure(filename,errno(*__errno_location ()),false0); | |||
1680 | loal_error = load_loal_error(NULL((void*)0),loal,NULL((void*)0),0,"Cannot Open file '%s'",filename); | |||
1681 | } | |||
1682 | ||||
1683 | error: | |||
1684 | g_free(linenum_buf); | |||
1685 | g_free(name); | |||
1686 | g_free(value); | |||
1687 | ||||
1688 | return loal_error; | |||
1689 | } |