2 * MATE -- Meta Analysis Tracing Engine
3 * Utility Library: Single Copy Strings and Attribute Value Pairs
5 * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "mate_util.h"
30 #include <wsutil/file_util.h>
32 /***************************************************************************
34 ***************************************************************************
35 * This is a macro that computes the difference between the raw address
36 * values of two pointers (rather than the difference between the pointers)
38 ***************************************************************************/
39 #define ADDRDIFF(p,q) (((char *)(void *)(p)) - ((char *)(void *)(q)))
42 /***************************************************************************
44 ***************************************************************************
45 * This is the debug facility of the thing.
46 ***************************************************************************/
49 * which: a pointer to the current level of debugging for a feature
50 * how: the level over which this message should be printed out
51 * where: the file on which to print (g_message if null)
52 * fmt, ...: what to print
55 void dbg_print(const gint* which, gint how, FILE* where, const gchar* fmt, ... ) {
56 static gchar debug_buffer[DEBUG_BUFFER_SIZE];
59 if ( ! which || *which < how ) return;
61 va_start( list, fmt );
62 g_vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE,fmt,list);
66 g_message("%s", debug_buffer);
68 fputs(debug_buffer,where);
75 /***************************************************************************
77 ***************************************************************************
78 * Strings repeat more often than don't. In order to save memory
79 * we'll keep only one copy of each as key to a hash with a count of
80 * subscribers as value.
81 ***************************************************************************/
86 * Initializes the scs hash.
89 struct _scs_collection {
90 GHashTable* hash; /* key: a string value: guint number of subscribers */
93 /* ToDo? free any string,ctr entries pointed to by the hash table ??
94 * XXX: AFAIKT destroy_scs_collection() might be called only when reading a
95 * mate config file. Since reading a new config file can apparently currently
96 * only be done once after starting Wireshark, in theory this fcn
97 * currently should never be called since there will never be an existing
98 * scs_collection to be destroyed.
100 static void destroy_scs_collection(SCS_collection* c) {
101 if (c->hash) g_hash_table_destroy(c->hash);
104 static SCS_collection* scs_init(void) {
105 SCS_collection* c = (SCS_collection *)g_malloc(sizeof(SCS_collection));
107 c->hash = g_hash_table_new(g_str_hash,g_str_equal);
115 * @param c the scs hash
118 * Checks if the given string exists already and if so it increases the count of
119 * subsscribers and returns a pointer to the stored string. If not It will copy
120 * the given string store it in the hash and return the pointer to the copy.
121 * Remember, containment is handled internally, take care of your own strings.
123 * Return value: a pointer to the subscribed string.
125 gchar* scs_subscribe(SCS_collection* c, const gchar* s) {
130 g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer *)&orig,(gpointer *)&ip);
135 ip = g_slice_new(guint);
140 if (len <= SCS_SMALL_SIZE) {
141 len = SCS_SMALL_SIZE;
142 } else if (len <= SCS_MEDIUM_SIZE) {
143 len = SCS_MEDIUM_SIZE;
144 } else if (len <= SCS_LARGE_SIZE) {
145 len = SCS_LARGE_SIZE;
146 } else if (len < SCS_HUGE_SIZE) {
150 g_warning("mate SCS: string truncated due to huge size");
153 orig = (gchar *)g_slice_alloc(len);
154 g_strlcpy(orig,s,len);
156 g_hash_table_insert(c->hash,orig,ip);
164 * @param c the scs hash
167 * decreases the count of subscribers, if zero frees the internal copy of
170 void scs_unsubscribe(SCS_collection* c, gchar* s) {
175 g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer *)&orig,(gpointer *)&ip);
179 g_hash_table_remove(c->hash,orig);
183 if (len < SCS_SMALL_SIZE) {
184 len = SCS_SMALL_SIZE;
185 } else if (len < SCS_MEDIUM_SIZE) {
186 len = SCS_MEDIUM_SIZE;
187 } else if (len < SCS_LARGE_SIZE) {
188 len = SCS_LARGE_SIZE;
193 g_slice_free1(len, orig);
194 g_slice_free(guint,ip);
200 g_warning("unsubscribe: not subscribed");
205 * scs_subscribe_printf:
206 * @param fmt a format string ...
208 * Formats the input and subscribes it.
210 * Return value: the stored copy of the formated string.
213 gchar* scs_subscribe_printf(SCS_collection* c, gchar* fmt, ...) {
215 static gchar buf[SCS_HUGE_SIZE];
217 va_start( list, fmt );
218 g_vsnprintf(buf, SCS_HUGE_SIZE, fmt, list);
221 return scs_subscribe(c,buf);
224 /***************************************************************************
226 ***************************************************************************
227 * The Thing operates mainly on avps, avpls and loals
228 * - attribute value pairs (two strings: the name and the value and an operator)
229 * - avp lists a somehow sorted list of avps
230 * - loal (list of avp lists) an arbitrarily sorted list of avpls
233 ***************************************************************************/
236 typedef union _any_avp_type {
245 static SCS_collection* avp_strings = NULL;
247 #ifdef _AVP_DEBUGGING
248 static FILE* dbg_fp = NULL;
250 static int dbg_level = 0;
251 static int* dbg = &dbg_level;
253 static int dbg_avp_level = 0;
254 static int* dbg_avp = &dbg_avp_level;
256 static int dbg_avp_op_level = 0;
257 static int* dbg_avp_op = &dbg_avp_op_level;
259 static int dbg_avpl_level = 0;
260 static int* dbg_avpl = &dbg_avpl_level;
262 static int dbg_avpl_op_level = 0;
263 static int* dbg_avpl_op = &dbg_avpl_op_level;
267 * @param fp the file in which to send debugging output.
268 * @param general a pointer to the level of debugging of facility "general"
269 * @param avp a pointer to the level of debugging of facility "avp"
270 * @param avp_op a pointer to the level of debugging of facility "avp_op"
271 * @param avpl a pointer to the level of debugging of facility "avpl"
272 * @param avpl_op a pointer to the level of debugging of facility "avpl_op"
274 * If enabled sets up the debug facilities for the avp library.
277 extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) {
283 dbg_avpl_op = avpl_op;
286 #endif /* _AVP_DEBUGGING */
291 * (Re)Initializes the avp library.
294 extern void avp_init(void) {
296 if (avp_strings) destroy_scs_collection(avp_strings);
297 avp_strings = scs_init();
302 * new_avp_from_finfo:
303 * @param name the name the avp will have.
304 * @param finfo the field_info from which to fetch the data.
306 * Creates an avp from a field_info record.
308 * Return value: a pointer to the newly created avp.
311 extern AVP* new_avp_from_finfo(const gchar* name, field_info* finfo) {
312 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type);
316 new_avp_val->n = scs_subscribe(avp_strings, name);
318 repr = fvalue_to_string_repr(&finfo->value,FTREPR_DISPLAY,NULL);
321 value = scs_subscribe(avp_strings, repr);
322 #ifdef _AVP_DEBUGGING
323 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value);
326 #ifdef _AVP_DEBUGGING
327 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev);
329 value = scs_subscribe(avp_strings, "");
332 new_avp_val->v = value;
334 new_avp_val->o = '=';
336 #ifdef _AVP_DEBUGGING
337 dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %X %s%c%s;",(guint32) new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
346 * @param name the name the avp will have.
347 * @param value the value the avp will have.
348 * @param o the operator of this avp.
350 * Creates an avp given every parameter.
352 * Return value: a pointer to the newly created avp.
355 extern AVP* new_avp(const gchar* name, const gchar* value, gchar o) {
356 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type);
358 new_avp_val->n = scs_subscribe(avp_strings, name);
359 new_avp_val->v = scs_subscribe(avp_strings, value);
362 #ifdef _AVP_DEBUGGING
363 dbg_print(dbg_avp,1,dbg_fp,"new_avp_val: %X %s%c%s;",(guint32) new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
371 * @param avp the avp to delete.
373 * Destroys an avp and releases the resources it uses.
376 extern void delete_avp(AVP* avp) {
377 #ifdef _AVP_DEBUGGING
378 dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %X %s%c%s;",(guint32) avp,avp->n,avp->o,avp->v);
381 scs_unsubscribe(avp_strings, avp->n);
382 scs_unsubscribe(avp_strings, avp->v);
383 g_slice_free(any_avp_type,(any_avp_type*)avp);
389 * @param from the avp to be copied.
391 * Creates an avp whose name op and value are copies of the given one.
393 * Return value: a pointer to the newly created avp.
396 extern AVP* avp_copy(AVP* from) {
397 AVP* new_avp_val = (AVP*)g_slice_new(any_avp_type);
399 new_avp_val->n = scs_subscribe(avp_strings, from->n);
400 new_avp_val->v = scs_subscribe(avp_strings, from->v);
401 new_avp_val->o = from->o;
403 #ifdef _AVP_DEBUGGING
404 dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %X %s%c%s;",(guint32) new_avp_val,new_avp_val->n,new_avp_val->o,new_avp_val->v);
412 * @param name the name the avpl will have.
414 * Creates an empty avpl.
416 * Return value: a pointer to the newly created avpl.
419 extern AVPL* new_avpl(const gchar* name) {
420 AVPL* new_avpl_p = (AVPL*)g_slice_new(any_avp_type);
422 #ifdef _AVP_DEBUGGING
423 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl_p: %X name=%s",new_avpl_p,name);
426 new_avpl_p->name = name ? scs_subscribe(avp_strings, name) : scs_subscribe(avp_strings, "");
428 new_avpl_p->null.avp = NULL;
429 new_avpl_p->null.next = &new_avpl_p->null;
430 new_avpl_p->null.prev = &new_avpl_p->null;
436 extern void rename_avpl(AVPL* avpl, gchar* name) {
437 scs_unsubscribe(avp_strings,avpl->name);
438 avpl->name = scs_subscribe(avp_strings,name);
443 * @param avpl the avpl in which to insert.
444 * @param avp the avp to be inserted.
446 * Inserts the given AVP into the given AVPL if an identical one isn't yet there.
448 * Return value: whether it was inserted or not.
450 * BEWARE: Check the return value, you might need to delete the avp if
451 * it is not inserted.
453 extern gboolean insert_avp(AVPL* avpl, AVP* avp) {
454 AVPN* new_avp_val = (AVPN*)g_slice_new(any_avp_type);
457 new_avp_val->avp = avp;
459 #ifdef _AVP_DEBUGGING
460 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %X",new_avp_val);
461 dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %X %X %s%c%s;",avpl,avp,avp->n,avp->o,avp->v);
464 /* get to the insertion point */
465 for(c=avpl->null.next; c->avp; c = c->next) {
467 if ( avp->n == c->avp->n ) {
469 if (avp->v > c->avp->v) {
473 if (avp->v == c->avp->v) {
474 if (avp->o == AVP_OP_EQUAL) {
475 #ifdef _AVP_DEBUGGING
476 dbg_print(dbg_avpl_op,7,dbg_fp,"delete_avpn: %X",new_avp_val);
478 g_slice_free(any_avp_type,(any_avp_type*)new_avp_val);
484 if (avp->n > c->avp->n) {
489 #ifdef _AVP_DEBUGGING
490 dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %X in %X before %X;",avp,avpl,c);
493 new_avp_val->next = c;
494 new_avp_val->prev = c->prev;
495 c->prev->next = new_avp_val;
496 c->prev = new_avp_val;
500 #ifdef _AVP_DEBUGGING
501 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
509 * @param avpl the avpl from which to try to get the avp.
510 * @param name the name of the avp we are looking for.
511 * @param cookie variable in which to store the state between calls.
513 * Gets pointer to the next avp whose name is given; uses cookie to store its
514 * state between calls.
516 * Return value: a pointer to the next matching avp if there's one, else NULL.
519 extern AVP* get_avp_by_name(AVPL* avpl, gchar* name, void** cookie) {
521 AVPN* start = (AVPN*) *cookie;
523 #ifdef _AVP_DEBUGGING
524 dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %X %s %X",avpl,name,*cookie);
527 name = scs_subscribe(avp_strings, name);
529 if (!start) start = avpl->null.next;
531 for ( curr = start; curr->avp; curr = curr->next ) {
532 if ( curr->avp->n == name ) {
539 #ifdef _AVP_DEBUGGING
540 dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %X",curr);
543 scs_unsubscribe(avp_strings, name);
549 * extract_avp_by_name:
550 * @param avpl the avpl from which to try to extract the avp.
551 * @param name the name of the avp we are looking for.
553 * Extracts from the avpl the next avp whose name is given;
555 * Return value: a pointer to extracted avp if there's one, else NULL.
558 extern AVP* extract_avp_by_name(AVPL* avpl, gchar* name) {
562 #ifdef _AVP_DEBUGGING
563 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %X %s",avpl,name);
566 name = scs_subscribe(avp_strings, name);
568 for ( curr = avpl->null.next; curr->avp; curr = curr->next ) {
569 if ( curr->avp->n == name ) {
574 scs_unsubscribe(avp_strings, name);
576 if( ! curr->avp ) return NULL;
578 curr->next->prev = curr->prev;
579 curr->prev->next = curr->next;
583 g_slice_free(any_avp_type,(any_avp_type*)curr);
587 #ifdef _AVP_DEBUGGING
588 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
591 #ifdef _AVP_DEBUGGING
592 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %X",avp);
601 * @param avpl the avpl from which to try to extract the avp.
603 * Extracts the fisrt avp from the avpl.
605 * Return value: a pointer to extracted avp if there's one, else NULL.
608 extern AVP* extract_first_avp(AVPL* avpl) {
612 #ifdef _AVP_DEBUGGING
613 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %X",avpl);
616 node = avpl->null.next;
618 avpl->null.next->prev = &avpl->null;
619 avpl->null.next = node->next;
624 g_slice_free(any_avp_type,(any_avp_type*)node);
626 #ifdef _AVP_DEBUGGING
627 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
631 #ifdef _AVP_DEBUGGING
632 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %X",avp);
642 * @param avpl the avpl from which to try to extract the avp.
644 * Extracts the last avp from the avpl.
646 * Return value: a pointer to extracted avp if there's one, else NULL.
649 extern AVP* extract_last_avp(AVPL* avpl) {
653 node = avpl->null.prev;
655 avpl->null.prev->next = &avpl->null;
656 avpl->null.prev = node->prev;
661 g_slice_free(any_avp_type,(any_avp_type*)node);
663 #ifdef _AVP_DEBUGGING
664 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
668 #ifdef _AVP_DEBUGGING
669 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",avp);
679 * @param avpl the avpl from which to try to extract the avp.
680 * @param avps_too whether or not it should delete the avps as well.
682 * Destroys an avpl and releases the resources it uses. If told to do
683 * so releases the avps as well.
686 extern void delete_avpl(AVPL* avpl, gboolean avps_too) {
688 #ifdef _AVP_DEBUGGING
689 dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %X",avpl);
692 while(( avp = extract_last_avp(avpl))) {
698 scs_unsubscribe(avp_strings,avpl->name);
699 g_slice_free(any_avp_type,(any_avp_type*)avpl);
706 * @param avpl the avpl from which to try to get the avps.
707 * @param cookie variable in which to store the state between calls.
709 * Iterates on an avpl to get its avps.
711 * Return value: a pointer to the next avp if there's one, else NULL.
714 extern AVP* get_next_avp(AVPL* avpl, void** cookie) {
717 #ifdef _AVP_DEBUGGING
718 dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %X avpn: %X",avpl,*cookie);
722 node = (AVPN*) *cookie;
724 node = avpl->null.next;
727 *cookie = node->next;
729 #ifdef _AVP_DEBUGGING
730 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",node->avp);
738 * @param avpl the avpl to represent.
740 * Creates a newly allocated string containing a representation of an avpl.
742 * Return value: a pointer to the newly allocated string.
745 gchar* avpl_to_str(AVPL* avpl) {
747 GString* s = g_string_new("");
751 for(c=avpl->null.next; c->avp; c = c->next) {
752 avp_s = avp_to_str(c->avp);
753 g_string_append_printf(s," %s;",avp_s);
758 g_string_free(s,FALSE);
760 /* g_strchug(r); ? */
764 extern gchar* avpl_to_dotstr(AVPL* avpl) {
766 GString* s = g_string_new("");
770 for(c=avpl->null.next; c->avp; c = c->next) {
771 avp_s = avp_to_str(c->avp);
772 g_string_append_printf(s," .%s;",avp_s);
777 g_string_free(s,FALSE);
779 /* g_strchug(r); ? */
785 * @param dst the avpl in which to merge the avps.
786 * @param src the avpl from which to get the avps.
787 * @param copy_avps whether avps should be copied instead of referenced.
789 * Adds the avps of src that are not existent in dst into dst.
791 * Return value: a pointer to the newly allocated string.
794 extern void merge_avpl(AVPL* dst, AVPL* src, gboolean copy_avps) {
800 #ifdef _AVP_DEBUGGING
801 dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %X %X",dst,src);
810 c = ADDRDIFF(cd->avp->n,cs->avp->n);
816 if (cd->avp) cd = cd->next;
819 copy = avp_copy(cs->avp);
820 if ( ! insert_avp(dst,copy) ) {
824 insert_avp(dst,cs->avp);
829 if ( ! cd->avp || ! (cd->avp->v == cs->avp->v) ) {
831 copy = avp_copy(cs->avp);
832 if ( ! insert_avp(dst,copy) ) {
836 insert_avp(dst,cs->avp);
840 if (cd->avp) cd = cd->next;
844 #ifdef _AVP_DEBUGGING
845 dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done");
854 * @name: the name of the new avpl.
855 * @avpl: the avpl from which to get the avps.
856 * @copy_avps: whether avps should be copied instead of referenced.
858 * Creates a new avpl containing the same avps as the given avpl
859 * It will either reference or copie the avps.
861 * Return value: a pointer to the newly allocated string.
864 extern AVPL* new_avpl_from_avpl(const gchar* name, AVPL* avpl, gboolean copy_avps) {
865 AVPL* newavpl = new_avpl(name);
870 #ifdef _AVP_DEBUGGING
871 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %X from=%X name='%s'",newavpl,avpl,name);
874 while(( avp = get_next_avp(avpl,&cookie) )) {
876 copy = avp_copy(avp);
877 if ( ! insert_avp(newavpl,copy) ) {
881 insert_avp(newavpl,avp);
885 #ifdef _AVP_DEBUGGING
886 dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done");
894 * @param src an src to be compared agains an "op" avp
895 * @param op the "op" avp that will be matched against the src avp
897 * Checks whether or not two avp's match.
899 * Return value: a pointer to the src avp if there's a match.
902 extern AVP* match_avp(AVP* src, AVP* op) {
910 gboolean lower = FALSE;
912 #ifdef _AVP_DEBUGGING
913 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);
916 if ( src->n != op->n ) {
924 return src->v == op->v ? src : NULL;
925 case AVP_OP_NOTEQUAL:
926 return !( src->v == op->v) ? src : NULL;
928 return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL;
930 splited = g_strsplit(op->v,"|",0);
932 for (i=0;splited[i];i++) {
933 if(g_str_equal(splited[i],src->v)) {
947 fs = (float) g_ascii_strtod(src->v, NULL);
948 fo = (float) g_ascii_strtod(op->v, NULL);
951 if (fs<fo) return src;
954 if (fs>fo) return src;
958 /* does this work? */
959 ls = (guint) strlen(src->v);
960 lo = (guint) strlen(op->v);
965 p = src->v + ( ls - lo );
966 return g_str_equal(p,op->v) ? src : NULL;
969 /* case AVP_OP_TRANSF: */
970 /* return do_transform(src,op); */
971 case AVP_OP_CONTAINS:
975 /* will never get here */
981 /* TODO: rename me */
983 * new_avpl_loose_match:
984 * @param name the name of the resulting avpl
985 * @param src avpl to be matched agains an "op" avpl
986 * @param op the "op" avpl that will be matched against the src avpl
987 * @param copy_avps whether the avps in the resulting avpl should be copied
989 * creates an avp list containing any avps in src matching any avps in op
990 * it will eventually create an empty list in none match
992 * Return value: a pointer to the newly created avpl containing the
995 extern AVPL* new_avpl_loose_match(const gchar* name,
998 gboolean copy_avps) {
1000 AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name));
1007 #ifdef _AVP_DEBUGGING
1008 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1012 cs = src->null.next;
1025 c = ADDRDIFF(co->avp->n, cs->avp->n);
1028 if (co->avp) co = co->next;
1030 if (cs->avp) cs = cs->next;
1032 m = match_avp(cs->avp,co->avp);
1037 if ( ! insert_avp(newavpl,copy) ) {
1041 insert_avp(newavpl,m);
1047 if (cs->avp) cs = cs->next;
1052 #ifdef _AVP_DEBUGGING
1053 dbg_print(dbg_avpl_op,6,dbg_fp,"new_avpl_loose_match: done!");
1059 /* TODO: rename me */
1061 * new_avpl_every_match:
1062 * @param name the name of the resulting avpl
1063 * @param src avpl to be matched agains an "op" avpl
1064 * @param op the "op" avpl that will be matched against the src avpl
1065 * @param copy_avps whether the avps in the resulting avpl should be copied
1067 * creates an avp list containing any avps in src matching every avp in op
1068 * it will not create a list if there is not a match for every attribute in op
1070 * Return value: a pointer to the newly created avpl containing the
1073 extern AVPL* new_avpl_every_match(const gchar* name, AVPL* src, AVPL* op, gboolean copy_avps) {
1082 #ifdef _AVP_DEBUGGING
1083 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1085 if (src->len == 0) return NULL;
1087 newavpl = new_avpl(scs_subscribe(avp_strings, name));
1094 cs = src->null.next;
1106 c = ADDRDIFF(co->avp->n,cs->avp->n);
1109 delete_avpl(newavpl,TRUE);
1117 m = match_avp(cs->avp,co->avp);
1126 if ( ! insert_avp(newavpl,copy) ) {
1130 insert_avp(newavpl,m);
1143 delete_avpl(newavpl,TRUE);
1149 /* TODO: rename me */
1151 * new_avpl_exact_match:
1152 * @param name the name of the resulting avpl
1153 * @param src avpl to be matched agains an "op" avpl
1154 * @param op the "op" avpl that will be matched against the src avpl
1155 * @param copy_avps whether the avps in the resulting avpl should be copied
1157 * creates an avp list containing every avp in src matching every avp in op
1158 * it will not create a list unless every avp in op is matched only once
1159 * to every avp in op.
1161 * Return value: a pointer to the newly created avpl containing the
1164 extern AVPL* new_avpl_exact_match(const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps) {
1165 AVPL* newavpl = new_avpl(name);
1172 #ifdef _AVP_DEBUGGING
1173 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1179 if (src->len == 0) {
1180 delete_avpl(newavpl,FALSE);
1184 cs = src->null.next;
1188 c = ADDRDIFF(co->avp->n,cs->avp->n);
1191 delete_avpl(newavpl,TRUE);
1196 delete_avpl(newavpl,TRUE);
1200 m = match_avp(cs->avp,co->avp);
1208 if ( ! insert_avp(newavpl,copy) ) {
1212 insert_avp(newavpl,m);
1220 delete_avpl(newavpl,TRUE);
1224 delete_avpl(newavpl,TRUE);
1231 /* should never be reached */
1235 extern AVPL* new_avpl_from_match(avpl_match_mode mode, const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps) {
1240 avpl = new_avpl_exact_match(name,src,op,copy_avps);
1243 avpl = new_avpl_loose_match(name,src,op,copy_avps);
1246 avpl = new_avpl_every_match(name,src,op,copy_avps);
1249 avpl = new_avpl_from_avpl(name,src,copy_avps);
1250 merge_avpl(avpl, op, copy_avps);
1258 * delete_avpl_transform:
1259 * @param op a pointer to the avpl transformation object
1261 * Destroys an avpl transformation object and releases all the resources it
1265 extern void delete_avpl_transform(AVPL_Transf* op) {
1268 for (; op ; op = next) {
1274 delete_avpl(op->match,TRUE);
1278 delete_avpl(op->replace,TRUE);
1289 * @param src the source avpl for the transform operation.
1290 * @param op a pointer to the avpl transformation object to apply.
1292 * Applies the "op" transformation to an avpl, matches it and eventually
1293 * replaces or inserts the transformed avps.
1295 * Return value: whether the transformation was performed or not.
1297 extern void avpl_transform(AVPL* src, AVPL_Transf* op) {
1303 #ifdef _AVP_DEBUGGING
1304 dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%X op=%X",src,op);
1307 for ( ; op ; op = op->next) {
1309 avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, TRUE);
1312 switch (op->replace_mode) {
1313 case AVPL_NO_REPLACE:
1314 delete_avpl(avpl,TRUE);
1317 merge_avpl(src,op->replace,TRUE);
1318 delete_avpl(avpl,TRUE);
1321 cs = src->null.next;
1322 cm = avpl->null.next;
1324 if (cm->avp && cs->avp->n == cm->avp->n && cs->avp->v == cm->avp->v) {
1327 cs->prev->next = cs->next;
1328 cs->next->prev = cs->prev;
1329 g_slice_free(any_avp_type,(any_avp_type*)cs);
1338 merge_avpl(src,op->replace,TRUE);
1339 delete_avpl(avpl,TRUE);
1349 * @param name the name the loal will take.
1351 * Creates an empty list of avp lists.
1353 * Return value: a pointer to the newly created loal.
1355 extern LoAL* new_loal(const gchar* name) {
1356 LoAL* new_loal_p = (LoAL*)g_slice_new(any_avp_type);
1362 #ifdef _AVP_DEBUGGING
1363 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_p: %X name=%s",new_loal_p,name);
1366 new_loal_p->name = scs_subscribe(avp_strings,name);
1367 new_loal_p->null.avpl = NULL;
1368 new_loal_p->null.next = &new_loal_p->null;
1369 new_loal_p->null.prev = &new_loal_p->null;
1370 new_loal_p->len = 0;
1376 * @param loal the loal on which to operate.
1377 * @param avpl the avpl to append.
1379 * Appends an avpl to a loal.
1382 extern void loal_append(LoAL* loal, AVPL* avpl) {
1383 LoALnode* node = (LoALnode*)g_slice_new(any_avp_type);
1385 #ifdef _AVP_DEBUGGING
1386 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %X",node);
1390 node->next = &loal->null;
1391 node->prev = loal->null.prev;
1393 loal->null.prev->next = node;
1394 loal->null.prev = node;
1400 * extract_first_avpl:
1401 * @param loal the loal on which to operate.
1403 * Extracts the first avpl contained in a loal.
1405 * Return value: a pointer to the extracted avpl.
1408 extern AVPL* extract_first_avpl(LoAL* loal) {
1412 #ifdef _AVP_DEBUGGING
1413 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name);
1416 node = loal->null.next;
1418 loal->null.next->next->prev = &loal->null;
1419 loal->null.next = node->next;
1426 g_slice_free(any_avp_type,(any_avp_type*)node);
1428 #ifdef _AVP_DEBUGGING
1429 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name);
1430 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
1438 * extract_first_avpl:
1439 * @param loal the loal on which to operate.
1441 * Extracts the last avpl contained in a loal.
1443 * Return value: a pointer to the extracted avpl.
1446 extern AVPL* extract_last_avpl(LoAL* loal){
1450 node = loal->null.prev;
1452 loal->null.prev->prev->next = &loal->null;
1453 loal->null.prev = node->prev;
1460 g_slice_free(any_avp_type,(any_avp_type*)node);
1461 #ifdef _AVP_DEBUGGING
1462 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
1470 * extract_first_avpl:
1471 * @param loal the loal on which to operate.
1472 * @param cookie pointer to the pointer variable to contain the state between calls
1474 * At each call will return the following avpl from a loal. The given cookie
1475 * will be used to manatain the state between calls.
1477 * Return value: a pointer to the next avpl.
1480 extern AVPL* get_next_avpl(LoAL* loal,void** cookie) {
1483 #ifdef _AVP_DEBUGGING
1484 dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%X node=%X",loal,*cookie);
1488 node = (LoALnode*) *cookie;
1490 node = loal->null.next;
1493 *cookie = node->next;
1500 * @param loal the loal to be deleted.
1501 * @param avpls_too whether avpls contained by the loal should be deleted as well
1502 * @param avps_too whether avps contained by the avpls should be also deleted
1504 * Destroys a loal and eventually desstroys avpls and avps.
1507 extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too) {
1510 #ifdef _AVP_DEBUGGING
1511 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %X",loal);
1514 while(( avpl = extract_last_avpl(loal) )) {
1516 delete_avpl(avpl,avps_too);
1520 scs_unsubscribe(avp_strings,loal->name);
1521 g_slice_free(any_avp_type,(any_avp_type*)loal);
1526 /****************************************************************************
1527 ******************* the following are used in load_loal_from_file
1528 ****************************************************************************/
1532 * Used by loal_from_file to handle errors while loading.
1534 static LoAL* load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, const gchar* fmt, ...) {
1540 va_start( list, fmt );
1541 desc = g_strdup_vprintf(fmt, list);
1545 err = g_strdup_printf("Error Loading LoAL from file: in %s at line: %i, %s",loal->name,linenum,desc);
1546 ret = new_loal(err);
1552 if (loal) delete_loal(loal,TRUE,TRUE);
1553 if (curr) delete_avpl(curr,TRUE);
1559 /* the maximum length allowed for a line */
1560 #define MAX_ITEM_LEN 8192
1562 /* this two ugly things are used for tokenizing */
1563 #define AVP_OP_CHAR '=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!'
1565 #define AVP_NAME_CHAR 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\
1566 case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\
1567 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\
1568 case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\
1569 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\
1570 case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\
1571 case '7': case '8': case '9': case '.'
1576 * @param filename the file containing a loals text representation.
1578 * Given a filename it will attempt to load a loal containing a copy of
1579 * the avpls represented in the file.
1581 * Return value: if successful a pointer to the new populated loal, else NULL.
1584 extern LoAL* loal_from_file(gchar* filename) {
1588 guint32 linenum = 1;
1589 gchar linenum_buf[MAX_ITEM_LEN];
1590 gchar name[MAX_ITEM_LEN];
1591 gchar value[MAX_ITEM_LEN];
1593 LoAL *loal = new_loal(filename);
1597 enum _load_loal_states {
1607 return load_loal_error(fp,loal,curr,linenum,"MATE Will not run as root");
1613 if (( fp = ws_fopen(filename,"r") )) {
1614 while(( c = (gchar) fgetc(fp) )){
1618 report_read_failure(filename,errno);
1619 return load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename);
1628 if ( i >= MAX_ITEM_LEN - 1 ) {
1629 return load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded");
1644 case ' ': case '\t':
1645 /* ignore whitespace at line start */
1648 /* ignore empty lines */
1656 g_snprintf(linenum_buf,sizeof(linenum_buf),"%s:%u",filename,linenum);
1657 curr = new_avpl(linenum_buf);
1663 return load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1670 c = (gchar) fgetc(fp);
1671 if (c != '\n') ungetc(c,fp);
1683 loal_append(loal,curr);
1687 return load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1692 state = BEFORE_NAME;
1699 avp = new_avp(name,value,op);
1701 if (! insert_avp(curr,avp) ) {
1716 return load_loal_error(fp,loal,curr,linenum,"operator expected found new line");
1718 return load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c);
1723 value[i++] = (gchar) fgetc(fp);
1726 state = BEFORE_NAME;
1731 avp = new_avp(name,value,op);
1733 if (! insert_avp(curr,avp) ) {
1738 return load_loal_error(fp,loal,curr,linenum,"';' expected found new line");
1750 report_open_failure(filename,errno,FALSE);
1751 return load_loal_error(NULL,loal,NULL,0,"Cannot Open file '%s'",filename);