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@gmail.com>
9 * Ethereal - Network traffic analyzer
10 * By Gerald Combs <gerald@ethereal.com>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include "mate_util.h"
31 /***************************************************************************
33 ***************************************************************************
34 * This is the debug facility of the thing.
35 ***************************************************************************/
38 * which: a pointer to the current level of debugging for a feature
39 * how: the level over which this message should be printed out
40 * where: the file on which to print (g_message if null)
41 * fmt, ...: what to print
44 void dbg_print(const gint* which, gint how, FILE* where, const gchar* fmt, ... ) {
45 static gchar debug_buffer[DEBUG_BUFFER_SIZE];
48 if ( ! which || *which < how ) return;
50 va_start( list, fmt );
51 g_vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE,fmt,list);
55 g_message(debug_buffer);
57 fputs(debug_buffer,where);
64 /***************************************************************************
66 ***************************************************************************
67 * Strings repeat more often than don't. In order to save memory
68 * we'll keep only one copy of each as key to a hash with a count of
69 * subscribers as value.
70 ***************************************************************************/
74 * @collection: the scs hash
76 * Initializes the scs hash.
79 /* Don't call variables "small" or "huge". They are keywords for the MSVC compiler. Rename them to "mate_small" and "mate_huge"*/
80 struct _scs_collection {
81 GHashTable* hash; /* key: a string value: guint number of subscribers */
83 GMemChunk* mate_small;
84 GMemChunk* mate_medium;
85 GMemChunk* mate_large;
89 extern void destroy_scs_collection(SCS_collection* c) {
90 if ( c->ctrs ) g_mem_chunk_destroy(c->ctrs);
91 if ( c->mate_small ) g_mem_chunk_destroy(c->mate_small);
92 if ( c->mate_medium ) g_mem_chunk_destroy(c->mate_medium);
93 if ( c->mate_large ) g_mem_chunk_destroy(c->mate_large);
94 if ( c->mate_huge ) g_mem_chunk_destroy(c->mate_huge);
96 if (c->hash) g_hash_table_destroy(c->hash);
99 extern SCS_collection* scs_init(void) {
100 SCS_collection* c = g_malloc(sizeof(SCS_collection));
102 c->hash = g_hash_table_new(g_str_hash,g_str_equal);
104 c->ctrs = g_mem_chunk_new("ints_scs_chunk", sizeof(guint),
105 sizeof(guint) * SCS_SMALL_CHUNK_SIZE, G_ALLOC_AND_FREE);
107 c->mate_small = g_mem_chunk_new("small_scs_chunk", SCS_SMALL_SIZE,
108 SCS_SMALL_SIZE * SCS_SMALL_CHUNK_SIZE, G_ALLOC_AND_FREE);
110 c->mate_medium = g_mem_chunk_new("medium_scs_chunk", SCS_MEDIUM_SIZE,
111 SCS_MEDIUM_SIZE * SCS_MEDIUM_CHUNK_SIZE, G_ALLOC_AND_FREE);
113 c->mate_large = g_mem_chunk_new("large_scs_chunk", SCS_LARGE_SIZE,
114 SCS_LARGE_SIZE * SCS_LARGE_CHUNK_SIZE, G_ALLOC_AND_FREE);
116 c->mate_huge = g_mem_chunk_new("huge_scs_chunk", SCS_HUGE_SIZE,
117 SCS_HUGE_SIZE * SCS_HUGE_CHUNK_SIZE, G_ALLOC_AND_FREE);
124 * @collection: the scs hash
127 * Checks if the given string exists already and if so it increases the count of
128 * subsscribers and returns a pointer to the stored string. If not It will copy
129 * the given string store it in the hash and return the pointer to the copy.
130 * Remember, containment is handled internally, take care of your own strings.
132 * Return value: a pointer to the subscribed string.
134 gchar* scs_subscribe(SCS_collection* c, const gchar* s) {
138 GMemChunk* chunk = NULL;
140 g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer*)&orig,(gpointer*)&ip);
145 ip = g_mem_chunk_alloc(c->ctrs);
150 if (len <= SCS_SMALL_SIZE) {
151 chunk = c->mate_small;
152 len = SCS_SMALL_SIZE;
153 } else if (len <= SCS_MEDIUM_SIZE) {
154 chunk = c->mate_medium;
155 len = SCS_MEDIUM_SIZE;
156 } else if (len <= SCS_LARGE_SIZE) {
157 chunk = c->mate_large;
158 len = SCS_LARGE_SIZE;
159 } else if (len < SCS_HUGE_SIZE) {
160 chunk = c->mate_huge;
163 chunk = c->mate_huge;
165 g_warning("mate SCS: string truncated to huge size");
168 orig = g_mem_chunk_alloc(chunk);
171 g_hash_table_insert(c->hash,orig,ip);
179 * @collection: the scs hash
182 * decreases the count of subscribers, if zero frees the internal copy of
185 void scs_unsubscribe(SCS_collection* c, gchar* s) {
189 GMemChunk* chunk = NULL;
191 g_hash_table_lookup_extended(c->hash,(gconstpointer)s,(gpointer*)&orig,(gpointer*)&ip);
195 g_hash_table_remove(c->hash,orig);
199 if (len < SCS_SMALL_SIZE) {
200 chunk = c->mate_small;
201 } else if (len < SCS_MEDIUM_SIZE) {
202 chunk = c->mate_medium;
203 } else if (len < SCS_LARGE_SIZE) {
204 chunk = c->mate_large;
206 chunk = c->mate_huge;
209 g_mem_chunk_free(chunk,orig);
210 g_mem_chunk_free(c->ctrs,ip);
216 g_warning("unsusbcribe: not subscribed");
221 * scs_subscribe_printf:
222 * @fmt: a format string ...
224 * Formats the input and subscribes it.
226 * Return value: the stored copy of the formated string.
229 gchar* scs_subscribe_printf(SCS_collection* c, gchar* fmt, ...) {
231 static gchar buf[SCS_HUGE_SIZE];
233 va_start( list, fmt );
234 g_vsnprintf(buf, SCS_HUGE_SIZE-1 ,fmt, list);
237 return scs_subscribe(c,buf);
240 static gchar* scs_subscribe_int(SCS_collection* c, int i) {
241 static gchar buf[SCS_SMALL_SIZE];
243 g_snprintf(buf, SCS_SMALL_SIZE-1 ,"%i", i);
245 return scs_subscribe(c,buf);
248 static gchar* scs_subscribe_float(SCS_collection* c, float f) {
249 static gchar buf[SCS_SMALL_SIZE];
251 g_snprintf(buf, SCS_SMALL_SIZE-1 ,"%f", f);
253 return scs_subscribe(c,buf);
256 /***************************************************************************
258 ***************************************************************************
259 * The Thing operates mainly on avps, avpls and loals
260 * - attribute value pairs (two strings: the name and the value and an opeartor)
261 * - avp lists a somehow sorted list of avps
262 * - loal (list of avp lists) an arbitrarily sorted list of avpls
265 ***************************************************************************/
268 typedef union _any_avp_type {
277 static GMemChunk* avp_chunk = NULL;
278 static SCS_collection* avp_strings = NULL;
280 #ifdef _AVP_DEBUGGING
281 static FILE* dbg_fp = NULL;
283 static int dbg_level = 0;
284 static int* dbg = &dbg_level;
286 static int dbg_avp_level = 0;
287 static int* dbg_avp = &dbg_avp_level;
289 static int dbg_avp_op_level = 0;
290 static int* dbg_avp_op = &dbg_avp_op_level;
292 static int dbg_avpl_level = 0;
293 static int* dbg_avpl = &dbg_avpl_level;
295 static int dbg_avpl_op_level = 0;
296 static int* dbg_avpl_op = &dbg_avpl_op_level;
300 * @fp: the file in which to send debugging output.
301 * @general: a pointer to the level of debugging of facility "general"
302 * @avp: a pointer to the level of debugging of facility "avp"
303 * @avp_op: a pointer to the level of debugging of facility "avp_op"
304 * @avpl: a pointer to the level of debugging of facility "avpl"
305 * @avpl_op: a pointer to the level of debugging of facility "avpl_op"
307 * If enabled set's up the debug facilities for the avp library.
310 extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) {
316 dbg_avpl_op = avpl_op;
319 #endif /* _AVP_DEBUGGING */
323 * @chunk_size: the initial chunk's size.
325 * (Re)Initializes the avp library.
328 extern void avp_init(void) {
330 if (avp_strings) destroy_scs_collection(avp_strings);
331 avp_strings = scs_init();
333 if ( avp_chunk ) g_mem_chunk_destroy(avp_chunk);
334 avp_chunk = g_mem_chunk_new("avp_chunk", sizeof(any_avp_type),
335 AVP_CHUNK_SIZE, G_ALLOC_AND_FREE);
341 * new_avp_from_finfo:
342 * @name: the name the avp will have.
343 * @finfo: the field_info from which to fetch the data.
345 * Creates an avp from a field_info record.
347 * Return value: a pointer to the newly created avp.
350 extern AVP* new_avp_from_finfo(const gchar* name, field_info* finfo) {
351 AVP* new = g_mem_chunk_alloc(avp_chunk);
354 new->n = scs_subscribe(avp_strings, name);
356 if (finfo->value.ftype->get_value_integer) {
357 value = scs_subscribe_int(avp_strings, fvalue_get_integer(&finfo->value));
358 #ifdef _AVP_DEBUGGING
359 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from integer: %s",value);
361 } else if (finfo->value.ftype->val_to_string_repr) {
362 value = scs_subscribe(avp_strings, fvalue_to_string_repr(&finfo->value,FTREPR_DISPLAY,NULL));
363 #ifdef _AVP_DEBUGGING
364 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value);
366 } else if (finfo->value.ftype->get_value_floating) {
367 value = scs_subscribe_float(avp_strings, (float) fvalue_get_floating(&finfo->value));
368 #ifdef _AVP_DEBUGGING
369 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from float: %s",value);
372 #ifdef _AVP_DEBUGGING
373 dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev);
375 value = scs_subscribe(avp_strings, "");
382 #ifdef _AVP_DEBUGGING
383 dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
392 * @name: the name the avp will have.
393 * @value: the value the avp will have.
394 * @o: the operator of this avp.
396 * Creates an avp given every parameter.
398 * Return value: a pointer to the newly created avp.
401 extern AVP* new_avp(const gchar* name, const gchar* value, gchar o) {
402 AVP* new = g_mem_chunk_alloc(avp_chunk);
404 new->n = scs_subscribe(avp_strings, name);
405 new->v = scs_subscribe(avp_strings, value);
408 #ifdef _AVP_DEBUGGING
409 dbg_print(dbg_avp,1,dbg_fp,"new_avp: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
417 * @avp: the avp to delete.
419 * Destroys an avp and releases the resources it uses.
422 extern void delete_avp(AVP* avp) {
423 #ifdef _AVP_DEBUGGING
424 dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %X %s%c%s;",(guint32) avp,avp->n,avp->o,avp->v);
427 scs_unsubscribe(avp_strings, avp->n);
428 scs_unsubscribe(avp_strings, avp->v);
429 g_mem_chunk_free(avp_chunk,avp);
435 * @from: the avp to be copied.
437 * Creates an avp whose name op and value are copyes of the given one.
439 * Return value: a pointer to the newly created avp.
442 extern AVP* avp_copy(AVP* from) {
443 AVP* new = g_mem_chunk_alloc(avp_chunk);
445 new->n = scs_subscribe(avp_strings, from->n);
446 new->v = scs_subscribe(avp_strings, from->v);
449 #ifdef _AVP_DEBUGGING
450 dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
457 static void rename_avp(AVP* avp, gchar* name) {
459 avp->n = scs_subscribe(avp_strings,name);
460 scs_unsubscribe(avp_strings,s);
465 * @name: the name the avpl will have.
467 * Creates an empty avpl.
469 * Return value: a pointer to the newly created avpl.
472 extern AVPL* new_avpl(const gchar* name) {
473 AVPL* new_avpl = g_mem_chunk_alloc(avp_chunk);
475 #ifdef _AVP_DEBUGGING
476 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl: %X name=%s",new_avpl,name);
479 new_avpl->name = name ? scs_subscribe(avp_strings, name) : scs_subscribe(avp_strings, "");
481 new_avpl->null.avp = NULL;
482 new_avpl->null.next = &new_avpl->null;
483 new_avpl->null.prev = &new_avpl->null;
489 extern void rename_avpl(AVPL* avpl, gchar* name) {
490 scs_unsubscribe(avp_strings,avpl->name);
491 avpl->name = scs_subscribe(avp_strings,name);
496 * @avpl: the avpl in which to insert.
497 * @avp: the avp to be inserted.
499 * Inserts the given AVP into the given AVPL if an identical one isn't yet there.
501 * Return value: whether it was inserted or not.
503 * BEWARE: Check the return value, you might need to delete the avp if
504 * it is not inserted.
506 extern gboolean insert_avp(AVPL* avpl, AVP* avp) {
507 AVPN* new = g_mem_chunk_alloc(avp_chunk);
512 #ifdef _AVP_DEBUGGING
513 dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %X",new);
514 dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %X %X %s%c%s;",avpl,avp,avp->n,avp->o,avp->v);
517 /* get to the insertion point */
518 for(c=avpl->null.next; c->avp; c = c->next) {
520 if ( avp->n == c->avp->n ) {
522 if (avp->v > c->avp->v) {
526 if (avp->v == c->avp->v) {
527 if (avp->o == AVP_OP_EQUAL) {
528 #ifdef _AVP_DEBUGGING
529 dbg_print(dbg_avpl_op,7,dbg_fp,"delete_avpn: %X",new);
531 g_mem_chunk_free(avp_chunk,new);
537 if (avp->n > c->avp->n) {
542 #ifdef _AVP_DEBUGGING
543 dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %X in %X before %X;",avp,avpl,c);
553 #ifdef _AVP_DEBUGGING
554 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
562 * @avpl: the avpl from which to try to get the avp.
563 * @name: the name of the avp we are looking for.
564 * @cookie: variable in which to store the state between calls.
566 * Gets pointer to the next avp whose name is given; uses cookie to store its
567 * state between calls.
569 * Return value: a pointer to the next matching avp if there's one, else NULL.
572 extern AVP* get_avp_by_name(AVPL* avpl, gchar* name, void** cookie) {
574 AVPN* start = (AVPN*) *cookie;
576 #ifdef _AVP_DEBUGGING
577 dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %X %s %X",avpl,name,*cookie);
580 name = scs_subscribe(avp_strings, name);
582 if (!start) start = avpl->null.next;
584 for ( curr = start; curr->avp; curr = curr->next ) {
585 if ( curr->avp->n == name ) {
592 #ifdef _AVP_DEBUGGING
593 dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %X",curr);
596 scs_unsubscribe(avp_strings, name);
602 * extract_avp_by_name:
603 * @avpl: the avpl from which to try to extract the avp.
604 * @name: the name of the avp we are looking for.
606 * Extracts from the avpl the next avp whose name is given;
608 * Return value: a pointer to extracted avp if there's one, else NULL.
611 extern AVP* extract_avp_by_name(AVPL* avpl, gchar* name) {
615 #ifdef _AVP_DEBUGGING
616 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %X %s",avpl,name);
619 name = scs_subscribe(avp_strings, name);
621 for ( curr = avpl->null.next; curr->avp; curr = curr->next ) {
622 if ( curr->avp->n == name ) {
627 scs_unsubscribe(avp_strings, name);
629 if( ! curr->avp ) return NULL;
631 curr->next->prev = curr->prev;
632 curr->prev->next = curr->next;
636 g_mem_chunk_free(avp_chunk,curr);
640 #ifdef _AVP_DEBUGGING
641 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
644 #ifdef _AVP_DEBUGGING
645 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %X",avp);
654 * @avpl: the avpl from which to try to extract the avp.
656 * Extracts the fisrt avp from the avpl.
658 * Return value: a pointer to extracted avp if there's one, else NULL.
661 extern AVP* extract_first_avp(AVPL* avpl) {
665 #ifdef _AVP_DEBUGGING
666 dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %X",avpl);
669 node = avpl->null.next;
671 avpl->null.next->prev = &avpl->null;
672 avpl->null.next = node->next;
677 g_mem_chunk_free(avp_chunk,node);
679 #ifdef _AVP_DEBUGGING
680 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
684 #ifdef _AVP_DEBUGGING
685 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %X",avp);
695 * @avpl: the avpl from which to try to extract the avp.
697 * Extracts the last avp from the avpl.
699 * Return value: a pointer to extracted avp if there's one, else NULL.
702 extern AVP* extract_last_avp(AVPL* avpl) {
706 node = avpl->null.prev;
708 avpl->null.prev->next = &avpl->null;
709 avpl->null.prev = node->prev;
714 g_mem_chunk_free(avp_chunk,node);
716 #ifdef _AVP_DEBUGGING
717 dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
721 #ifdef _AVP_DEBUGGING
722 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",avp);
732 * @avpl: the avpl from which to try to extract the avp.
733 * @avps_too: whether or not it should delete the avps as well.
735 * Destroys an avpl and releases the resources it uses. If told to do
736 * so releases the avps as well.
739 extern void delete_avpl(AVPL* avpl, gboolean avps_too) {
741 #ifdef _AVP_DEBUGGING
742 dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %X",avpl);
745 while(( avp = extract_last_avp(avpl))) {
751 scs_unsubscribe(avp_strings,avpl->name);
752 g_mem_chunk_free(avp_chunk,avpl);
759 * @avpl: the avpl from which to try to get the avps.
760 * @cookie: variable in which to store the state between calls.
762 * Iterates on an avpl to get its avps.
764 * Return value: a pointer to the next avp if there's one, else NULL.
767 extern AVP* get_next_avp(AVPL* avpl, void** cookie) {
770 #ifdef _AVP_DEBUGGING
771 dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %X avpn: %X",avpl,*cookie);
775 node = (AVPN*) *cookie;
777 node = avpl->null.next;
780 *cookie = node->next;
782 #ifdef _AVP_DEBUGGING
783 dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",node->avp);
791 * @avpl: the avpl to represent.
793 * Creates a newly allocated string containing a representation of an avpl.
795 * Return value: a pointer to the newly allocated string.
798 gchar* avpl_to_str(AVPL* avpl) {
800 GString* s = g_string_new("");
804 for(c=avpl->null.next; c->avp; c = c->next) {
805 avp_s = avp_to_str(c->avp);
806 g_string_sprintfa(s," %s;",avp_s);
811 g_string_free(s,FALSE);
813 /* g_strchug(r); ? */
817 extern gchar* avpl_to_dotstr(AVPL* avpl) {
819 GString* s = g_string_new("");
823 for(c=avpl->null.next; c->avp; c = c->next) {
824 avp_s = avp_to_str(c->avp);
825 g_string_sprintfa(s," .%s;",avp_s);
830 g_string_free(s,FALSE);
832 /* g_strchug(r); ? */
838 * @dst: the avpl in which to merge the avps.
839 * @src: the avpl from which to get the avps.
840 * @copy: whether avps should be copied instead of referenced.
842 * Adds the avps of src that are not existent in dst into dst.
844 * Return value: a pointer to the newly allocated string.
847 extern void merge_avpl(AVPL* dst, AVPL* src, gboolean copy_avps) {
853 #ifdef _AVP_DEBUGGING
854 dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %X %X",dst,src);
863 c = (guint) cd->avp->n - (guint) cs->avp->n;
869 if (cd->avp) cd = cd->next;
872 copy = avp_copy(cs->avp);
873 if ( ! insert_avp(dst,copy) ) {
877 insert_avp(dst,cs->avp);
882 if ( ! cd->avp || ! (cd->avp->v == cs->avp->v) ) {
884 copy = avp_copy(cs->avp);
885 if ( ! insert_avp(dst,copy) ) {
889 insert_avp(dst,cs->avp);
893 if (cd->avp) cd = cd->next;
897 #ifdef _AVP_DEBUGGING
898 dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done");
907 * @name: the name of the new avpl.
908 * @avpl: the avpl from which to get the avps.
909 * @copy_avps: whether avps should be copied instead of referenced.
911 * Creates a new avpl containing the same avps as the given avpl
912 * It will either reference or copie the avps.
914 * Return value: a pointer to the newly allocated string.
917 extern AVPL* new_avpl_from_avpl(const gchar* name, AVPL* avpl, gboolean copy_avps) {
918 AVPL* newavpl = new_avpl(name);
923 #ifdef _AVP_DEBUGGING
924 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %X from=%X name='%s'",newavpl,avpl,name);
927 while(( avp = get_next_avp(avpl,&cookie) )) {
929 copy = avp_copy(avp);
930 if ( ! insert_avp(newavpl,copy) ) {
934 insert_avp(newavpl,avp);
938 #ifdef _AVP_DEBUGGING
939 dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done");
947 * @src: an src to be compared agains an "op" avp
948 * @op: the "op" avp that will be matched against the src avp
950 * Checks whether or not two avp's match.
952 * Return value: a pointer to the src avp if there's a match.
955 extern AVP* match_avp(AVP* src, AVP* op) {
963 gboolean lower = FALSE;
965 #ifdef _AVP_DEBUGGING
966 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);
969 if ( src->n != op->n ) {
977 return src->v == op->v ? src : NULL;
978 case AVP_OP_NOTEQUAL:
979 return !( src->v == op->v) ? src : NULL;
981 return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL;
983 splited = g_strsplit(op->v,"|",0);
985 for (i=0;splited[i];i++) {
986 if(g_str_equal(splited[i],src->v)) {
999 fs = (float) strtod(src->v, NULL);
1000 fo = (float) strtod(src->v, NULL);
1003 if (fs<fo) return src;
1006 if (fs>fo) return src;
1010 /* does this work? */
1011 ls = strlen(src->v);
1017 p = src->v + ( ls - lo );
1018 return g_str_equal(p,op->v) ? src : NULL;
1021 /* case AVP_OP_TRANSF: */
1022 /* return do_transform(src,op); */
1023 case AVP_OP_CONTAINS:
1027 /* will never get here */
1033 /* TODO: rename me */
1035 * new_avpl_loose_match:
1036 * @name: the name of the resulting avpl
1037 * @src: avpl to be matched agains an "op" avpl
1038 * @op: the "op" avpl that will be matched against the src avpl
1039 * @copy_avps: whether the avps in the resulting avpl should be copied
1041 * creates an avp list containing any avps in src matching any avps in op
1042 * it will eventually create an empty list in none match
1044 * Return value: a pointer to the newly created avpl containing the
1047 extern AVPL* new_avpl_loose_match(const gchar* name,
1050 gboolean copy_avps) {
1052 AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name));
1059 #ifdef _AVP_DEBUGGING
1060 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1064 cs = src->null.next;
1077 c = (guint) co->avp->n - (guint) cs->avp->n;
1080 if (co->avp) co = co->next;
1082 if (cs->avp) cs = cs->next;
1084 m = match_avp(cs->avp,co->avp);
1089 if ( ! insert_avp(newavpl,copy) ) {
1093 insert_avp(newavpl,m);
1099 if (cs->avp) cs = cs->next;
1104 #ifdef _AVP_DEBUGGING
1105 dbg_print(dbg_avpl_op,6,dbg_fp,"new_avpl_loose_match: done!");
1111 /* TODO: rename me */
1113 * new_avpl_every_match:
1114 * @name: the name of the resulting avpl
1115 * @src: avpl to be matched agains an "op" avpl
1116 * @op: the "op" avpl that will be matched against the src avpl
1117 * @copy_avps: whether the avps in the resulting avpl should be copied
1119 * creates an avp list containing any avps in src matching every avp in op
1120 * it will not create a list if there is not a match for every attribute in op
1122 * Return value: a pointer to the newly created avpl containing the
1125 extern AVPL* new_avpl_every_match(const gchar* name, AVPL* src, AVPL* op, gboolean copy_avps) {
1134 #ifdef _AVP_DEBUGGING
1135 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1137 if (src->len == 0) return NULL;
1139 newavpl = new_avpl(scs_subscribe(avp_strings, name));
1146 cs = src->null.next;
1158 c = (guint) co->avp->n - (guint) cs->avp->n;
1161 delete_avpl(newavpl,TRUE);
1169 m = match_avp(cs->avp,co->avp);
1178 if ( ! insert_avp(newavpl,copy) ) {
1182 insert_avp(newavpl,m);
1195 delete_avpl(newavpl,TRUE);
1201 /* TODO: rename me */
1203 * new_avpl_exact_match:
1204 * @name: the name of the resulting avpl
1205 * @src: avpl to be matched agains an "op" avpl
1206 * @op: the "op" avpl that will be matched against the src avpl
1207 * @copy_avps: whether the avps in the resulting avpl should be copied
1209 * creates an avp list containing every avp in src matching every avp in op
1210 * it will not create a list unless every avp in op is matched only once
1211 * to every avp in op.
1213 * Return value: a pointer to the newly created avpl containing the
1216 extern AVPL* new_avpl_exact_match(const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps) {
1217 AVPL* newavpl = new_avpl(name);
1224 #ifdef _AVP_DEBUGGING
1225 dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
1231 if (src->len == 0) {
1232 delete_avpl(newavpl,FALSE);
1236 cs = src->null.next;
1240 c = (guint) co->avp->n - (guint) cs->avp->n;
1243 delete_avpl(newavpl,TRUE);
1248 delete_avpl(newavpl,TRUE);
1252 m = match_avp(cs->avp,co->avp);
1260 if ( ! insert_avp(newavpl,copy) ) {
1264 insert_avp(newavpl,m);
1272 delete_avpl(newavpl,TRUE);
1276 delete_avpl(newavpl,TRUE);
1283 /* should never be reached */
1287 extern AVPL* new_avpl_from_match(avpl_match_mode mode, const gchar* name,AVPL* src, AVPL* op, gboolean copy_avps) {
1292 avpl = new_avpl_exact_match(name,src,op,copy_avps);
1295 avpl = new_avpl_loose_match(name,src,op,copy_avps);
1298 avpl = new_avpl_every_match(name,src,op,copy_avps);
1301 avpl = new_avpl_from_avpl(name,src,copy_avps);
1302 merge_avpl(avpl, op, copy_avps);
1310 * new_avpl_transform:
1312 * creates an empty avpl transformation
1314 * Return value: a pointer to the newly created avpl transformation
1316 static AVPL_Transf* new_avpl_transform(gchar* name, AVPL* mixed, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
1317 AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
1320 t->name = g_strdup(name);
1321 t->match = new_avpl("match");
1322 t->replace = new_avpl("replace");
1323 t->match_mode = match_mode;
1324 t->replace_mode = replace_mode;
1328 while (( avp = extract_first_avp(mixed) )) {
1329 if (*(avp->n) == '.') {
1330 rename_avp(avp,((avp->n)+1));
1331 insert_avp(t->replace, avp);
1333 insert_avp(t->match, avp);
1342 * delete_avpl_transform:
1343 * @it: a pointer to the avpl transformation object
1345 * Destroys an avpl transformation object and releases all the resources it
1349 extern void delete_avpl_transform(AVPL_Transf* op) {
1352 for (; op ; op = next) {
1358 delete_avpl(op->match,TRUE);
1362 delete_avpl(op->replace,TRUE);
1373 * @src: the source avpl for the transform operation.
1374 * @op: a pointer to the avpl transformation object to apply.
1376 * Applies the "op" transformation to an avpl, matches it and eventually
1377 * replaces or inserts the transformed avps.
1379 * Return value: whether the transformation was performed or not.
1381 extern void avpl_transform(AVPL* src, AVPL_Transf* op) {
1387 #ifdef _AVP_DEBUGGING
1388 dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%X op=%X",src,op);
1391 for ( ; op ; op = op->next) {
1393 avpl = new_avpl_from_match(op->match_mode, src->name,src, op->match, TRUE);
1396 switch (op->replace_mode) {
1397 case AVPL_NO_REPLACE:
1398 delete_avpl(avpl,TRUE);
1401 merge_avpl(src,op->replace,TRUE);
1402 delete_avpl(avpl,TRUE);
1405 cs = src->null.next;
1406 cm = avpl->null.next;
1408 if (cm->avp && cs->avp->n == cm->avp->n && cs->avp->v == cm->avp->v) {
1411 cs->prev->next = cs->next;
1412 cs->next->prev = cs->prev;
1413 g_mem_chunk_free(avp_chunk,cs);
1422 merge_avpl(src,op->replace,TRUE);
1423 delete_avpl(avpl,TRUE);
1433 * @name: the name the loal will take.
1435 * Creates an empty list of avp lists.
1437 * Return value: a pointer to the newly created loal.
1439 extern LoAL* new_loal(const gchar* name) {
1440 LoAL* new_loal = g_mem_chunk_alloc(avp_chunk);
1446 #ifdef _AVP_DEBUGGING
1447 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal: %X name=%s",new_loal,name);
1450 new_loal->name = scs_subscribe(avp_strings,name);
1451 new_loal->null.avpl = NULL;
1452 new_loal->null.next = &new_loal->null;
1453 new_loal->null.prev = &new_loal->null;
1460 * @loal: the loal on which to operate.
1461 * @avpl: the avpl to append.
1463 * Appends an avpl to a loal.
1466 extern void loal_append(LoAL* loal, AVPL* avpl) {
1467 LoALnode* node = g_mem_chunk_alloc(avp_chunk);
1469 #ifdef _AVP_DEBUGGING
1470 dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %X",node);
1474 node->next = &loal->null;
1475 node->prev = loal->null.prev;
1477 loal->null.prev->next = node;
1478 loal->null.prev = node;
1484 * extract_first_avpl:
1485 * @loal: the loal on which to operate.
1487 * Extracts the first avpl contained in a loal.
1489 * Return value: a pointer to the extracted avpl.
1492 extern AVPL* extract_first_avpl(LoAL* loal) {
1496 #ifdef _AVP_DEBUGGING
1497 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name);
1500 node = loal->null.next;
1502 loal->null.next->next->prev = &loal->null;
1503 loal->null.next = node->next;
1510 g_mem_chunk_free(avp_chunk,node);
1512 #ifdef _AVP_DEBUGGING
1513 dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name);
1514 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
1522 * extract_first_avpl:
1523 * @loal: the loal on which to operate.
1525 * Extracts the last avpl contained in a loal.
1527 * Return value: a pointer to the extracted avpl.
1530 extern AVPL* extract_last_avpl(LoAL* loal){
1534 node = loal->null.prev;
1536 loal->null.prev->prev->next = &loal->null;
1537 loal->null.prev = node->prev;
1544 g_mem_chunk_free(avp_chunk,node);
1545 #ifdef _AVP_DEBUGGING
1546 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
1554 * extract_first_avpl:
1555 * @loal: the loal on which to operate.
1556 * @cookie pointer to the pointer variable to contain the state between calls
1558 * At each call will return the following avpl from a loal. The given cookie
1559 * will be used to manatain the state between calls.
1561 * Return value: a pointer to the next avpl.
1564 extern AVPL* get_next_avpl(LoAL* loal,void** cookie) {
1567 #ifdef _AVP_DEBUGGING
1568 dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%X node=%X",loal,*cookie);
1572 node = (LoALnode*) *cookie;
1574 node = loal->null.next;
1577 *cookie = node->next;
1584 * @loal: the loal to be deleted.
1585 * @avpls_too: whether avpls contained by the loal should be deleted as well
1586 * @avps_too: whether avps contained by the avpls should be also deleted
1588 * Destroys a loal and eventually desstroys avpls and avps.
1591 extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too) {
1594 #ifdef _AVP_DEBUGGING
1595 dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %X",loal);
1598 while(( avpl = extract_last_avpl(loal) )) {
1600 delete_avpl(avpl,avps_too);
1604 scs_unsubscribe(avp_strings,loal->name);
1605 g_mem_chunk_free(avp_chunk,loal);
1610 /****************************************************************************
1611 ******************* the following are used in load_loal_from_file
1612 ****************************************************************************/
1616 * Used by loal_from_file to handle errors while loading.
1618 static LoAL* load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, const gchar* fmt, ...) {
1624 va_start( list, fmt );
1625 desc = g_strdup_vprintf(fmt, list);
1629 err = g_strdup_printf("Error Loading LoAL from file: in %s at line: %i, %s",loal->name,linenum,desc);
1630 ret = new_loal(err);
1636 if (loal) delete_loal(loal,TRUE,TRUE);
1637 if (curr) delete_avpl(curr,TRUE);
1643 /* the maximum length allowed for a line */
1644 #define MAX_ITEM_LEN 8192
1646 /* this two ugly things are used for tokenizing */
1647 #define AVP_OP_CHAR '=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!'
1649 #define AVP_NAME_CHAR 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\
1650 case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\
1651 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\
1652 case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\
1653 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\
1654 case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\
1655 case '7': case '8': case '9': case '.'
1660 * @filename: the file containing a loals text representation.
1662 * Given a filename it will attempt to load a loal containing a copy of
1663 * the avpls represented in the file.
1665 * Return value: if successful a pointer to the new populated loal, else NULL.
1668 extern LoAL* loal_from_file(gchar* filename) {
1672 guint32 linenum = 1;
1673 gchar linenum_buf[MAX_ITEM_LEN];
1674 gchar name[MAX_ITEM_LEN];
1675 gchar value[MAX_ITEM_LEN];
1677 LoAL *loal = new_loal(filename);
1681 enum _load_loal_states {
1691 return load_loal_error(fp,loal,curr,linenum,"MATE Will not run as root");
1697 if (( fp = fopen(filename,"r") )) {
1698 while(( c = (gchar) fgetc(fp) )){
1702 report_read_failure(filename,errno);
1703 return load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename);
1712 if ( i >= MAX_ITEM_LEN - 1 ) {
1713 return load_loal_error(fp,loal,curr,linenum,"Maximum item length exceeded");
1729 case ' ': case '\t':
1730 /* ignore whitespace at line start */
1733 /* ignore empty lines */
1741 g_snprintf(linenum_buf,sizeof(linenum_buf),"%s:%u",filename,linenum);
1742 curr = new_avpl(linenum_buf);
1748 return load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1756 if (c != '\n') ungetc(c,fp);
1768 loal_append(loal,curr);
1772 return load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
1777 state = BEFORE_NAME;
1784 avp = new_avp(name,value,op);
1786 if (! insert_avp(curr,avp) ) {
1801 return load_loal_error(fp,loal,curr,linenum,"operator expected found new line");
1803 return load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c);
1808 value[i++] = fgetc(fp);
1811 state = BEFORE_NAME;
1816 avp = new_avp(name,value,op);
1818 if (! insert_avp(curr,avp) ) {
1823 return load_loal_error(fp,loal,curr,linenum,"';' expected found new line");
1835 report_open_failure(filename,errno,FALSE);
1836 return load_loal_error(NULL,loal,NULL,0,"Cannot Open file '%s'",filename);