Bug Summary

File:builds/wireshark/wireshark/plugins/epan/mate/mate_util.c
Warning:line 141, column 9
Null pointer passed to 1st parameter expecting 'nonnull'

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)) {
25
Assuming the condition is false
26
Taking false branch
137 (*ip)++;
138 } else {
139 ip = g_new0(unsigned, 1)((unsigned *) g_malloc0_n ((1), sizeof (unsigned)));
140
141 len = strlen(s);
27
Null pointer passed to 1st parameter expecting 'nonnull'
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);
23
Passing null pointer value via 2nd parameter 's'
24
Calling 'scs_subscribe'
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
20.1
'copy_avp' is true
? avp_copy(avp) : avp;
21
'?' condition is true
22
Calling 'avp_copy'
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
13.1
Field 'avp' is non-null
&& co->avp) {
5
Assuming field 'avp' is non-null
6
Loop condition is true. Entering loop body
13
Taking false branch
14
Loop condition is true. Entering loop body
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) {
7
Assuming 'name_diff' is >= 0
8
Taking false branch
15
Assuming 'name_diff' is >= 0
16
Taking false branch
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) {
9
Assuming 'name_diff' is <= 0
10
Taking false branch
17
Assuming 'name_diff' is <= 0
18
Taking false branch
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)) {
11
Taking false branch
19
Taking true branch
1075 insert_avp_before_node(newavpl, newavpl->null.prev->next, cs->avp, copy_avps);
20
Calling 'insert_avp_before_node'
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) {
12
Assuming 'failed_match' is null
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) {
3
Control jumps to 'case AVPL_EVERY:' at line 1136
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);
4
Calling 'new_avpl_pairs_match'
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) {
1
Loop condition is true. Entering loop body
1200
1201 avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, true1);
2
Calling 'new_avpl_from_match'
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()) {
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") )) {
1522 while(( c = (char) fgetc(fp) )){
1523
1524 if ( feof(fp) ) {
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' ) {
1534 linenum++;
1535 }
1536
1537 if ( i >= MAX_ITEM_LEN8192 - 1 ) {
1538 loal_error = load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded");
1539 goto error;
1540 }
1541
1542 switch(state) {
1543 case MY_IGNORE:
1544 switch (c) {
1545 case '\n':
1546 state = START;
1547 i = 0;
1548 continue;
1549 default:
1550 continue;
1551 }
1552 case START:
1553 switch (c) {
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}