Bug Summary

File:builds/wireshark/wireshark/plugins/epan/mate/mate_util.c
Warning:line 1522, column 22
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

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