The Assimilation Project  based on Assimilation version 0.5.1432262126
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
configcontext.c
Go to the documentation of this file.
1 // vim: smartindent number
24 #include <configcontext.h>
25 #include <memory.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 
30 #define BROKEN_G_SLIST_FREE_FULL 1
31 #undef BROKEN_G_SLIST_FREE_FULL
32 
33 #ifdef BROKEN_G_SLIST_FREE_FULL
34 # undef g_slist_free_full
35 # define g_slist_free_full assim_slist_free_full
36 #endif
37 
43 FSTATIC void _configcontext_delkey(const ConfigContext*, const char *);
44 FSTATIC gint64 _configcontext_getint(const ConfigContext*, const char *name);
45 FSTATIC void _configcontext_setint(ConfigContext*, const char *name, gint value);
46 FSTATIC gboolean _configcontext_appendint(ConfigContext*, const char *name, gint value);
47 FSTATIC double _configcontext_getdouble(const ConfigContext*, const char *name);
48 FSTATIC void _configcontext_setdouble(ConfigContext*, const char *name, double value);
49 FSTATIC gboolean _configcontext_appenddouble(ConfigContext*, const char *name, double value);
50 FSTATIC gboolean _configcontext_getbool(const ConfigContext*, const char *name);
51 FSTATIC void _configcontext_setbool(ConfigContext*, const char *name, gboolean value);
52 FSTATIC gboolean _configcontext_appendbool(ConfigContext*, const char *name, gboolean value);
53 FSTATIC const char* _configcontext_getstring(const ConfigContext*, const char *name);
54 FSTATIC void _configcontext_setstring(ConfigContext*, const char *name, const char *value);
55 FSTATIC gboolean _configcontext_appendstring(ConfigContext*, const char *name, const char *value);
56 FSTATIC GSList* _configcontext_getarray(const ConfigContext*, const char *name);
57 FSTATIC void _configcontext_setarray(ConfigContext*, const char *name, GSList*value);
60 FSTATIC gboolean _configcontext_appendaddr(ConfigContext* self, const char * name, NetAddr* value);
64  _configcontext_getconfig(const ConfigContext*, const char*);
65 FSTATIC char* _configcontext_getstr(const ConfigContext*, const char*);
68 FSTATIC gint _configcontext_key_compare(gconstpointer a, gconstpointer b);
69 
70 
71 
72 FSTATIC char * _configcontext_toString(gconstpointer aself);
74 FSTATIC char * JSONquotestring(char * s);
82 FSTATIC gboolean _configcontext_JSON_parse_array(GScanner* scan, GSList** retval);
84 FSTATIC void _configcontext_value_vfinalize(gpointer vself);
86 FSTATIC void _key_free(gpointer vself);
87 #ifdef BROKEN_G_SLIST_FREE_FULL
88 void assim_slist_free_full(GSList* list, void (*)(gpointer));
89 #endif
90 
100 #ifdef BROKEN_G_SLIST_FREE_FULL
101 void
102 assim_slist_free_full(GSList* list, void (*datafree)(gpointer))
103 {
104  GSList* this = NULL;
105  GSList* next = NULL;
106  //fprintf(stderr, "Freeing GSList at %p\n", list);
107 
108  for (this=list; this; this=next) {
109  next=this->next;
110  //fprintf(stderr, "........Freeing GSList data at %p\n", this->data);
111  if (this->data) {
112  datafree(this->data);
113  }else{
114  fprintf(stderr, "........NO GSList data (NULL) at %p\n"
115  , this->data);
116  }
117  //fprintf(stderr, "........Freeing GSList element at %p\n", this);
118  memset(this, 0, sizeof(*this));
119  g_slist_free_1(this);
120  }
121 }
122 #endif
123 
124 FSTATIC void
125 _key_free(gpointer vself)
126 {
127  //g_message("Freeing key pointer at %p\n", vself);
128  g_free(vself);
129 }
130 
131 
134 configcontext_new(gsize objsize)
135 {
136  AssimObj * baseobj = NULL;
137  ConfigContext * newcontext = NULL;
138 
139  if (objsize < sizeof(ConfigContext)) {
140  objsize = sizeof(ConfigContext);
141  }
142  baseobj = assimobj_new(objsize);
143  newcontext = NEWSUBCLASS(ConfigContext, baseobj);
144  newcontext->getint = _configcontext_getint;
145  newcontext->setdouble = _configcontext_setdouble;
146  newcontext->getdouble = _configcontext_getdouble;
147  newcontext->setint = _configcontext_setint;
148  newcontext->appendint = _configcontext_appendint;
149  newcontext->getbool = _configcontext_getbool;
150  newcontext->setbool = _configcontext_setbool;
152  newcontext->getstring = _configcontext_getstring;
153  newcontext->setstring = _configcontext_setstring;
155  newcontext->getframe = _configcontext_getframe;
156  newcontext->setframe = _configcontext_setframe;
157  newcontext->getaddr = _configcontext_getaddr;
158  newcontext->setaddr = _configcontext_setaddr;
160  newcontext->getconfig = _configcontext_getconfig;
161  newcontext->setconfig = _configcontext_setconfig;
163  newcontext->getarray = _configcontext_getarray;
164  newcontext->setarray = _configcontext_setarray;
165  newcontext->gettype = _configcontext_gettype;
166  newcontext->getvalue = _configcontext_getvalue;
167  newcontext->keys = _configcontext_keys;
168  newcontext->keycount = _configcontext_keycount;
169  newcontext->delkey = _configcontext_delkey;
170  newcontext->_values = g_hash_table_new_full(g_str_hash, g_str_equal, _key_free
174  return newcontext;
175 }
176 
178 FSTATIC void
180 {
181  ConfigContext* self = CASTTOCLASS(ConfigContext, aself);
182 #if 0
183  {
184  char * s = self->baseclass.toString(&self->baseclass);
185  g_warning("%s.%d: Finalizing %p: %s", __FUNCTION__, __LINE__, aself, s);
186  g_free(s); s = NULL;
187  }
188 #endif
189 
190  if (self->_values) {
191  g_hash_table_destroy(self->_values);
192  self->_values = NULL;
193  }
194  FREECLASSOBJ(self);
195 }
196 
198 FSTATIC gint
199 _configcontext_key_compare(gconstpointer a, gconstpointer b)
200 {
201  return strcmp((const char *)a, (const char*)b);
202 }
203 
205 FSTATIC void
206 _configcontext_delkey(const ConfigContext* cfg, const char * key)
207 {
208  g_hash_table_remove(cfg->_values, key);
209 }
211 FSTATIC guint
213 {
214  GHashTableIter iter;
215  gpointer key;
216  gpointer data;
217  guint ret = 0;
218 
219  g_hash_table_iter_init(&iter, cfg->_values);
220  while (g_hash_table_iter_next(&iter, &key, &data)) {
221  ++ret;
222  }
223  return ret;
224 }
225 
227 FSTATIC GSList*
229 {
230  GSList* keylist = NULL;
231  GHashTableIter iter;
232  gpointer key;
233  gpointer data;
234 
235  if (!cfg->_values) {
236  return NULL;
237  }
238 
239  g_hash_table_iter_init(&iter, cfg->_values);
240  while (g_hash_table_iter_next(&iter, &key, &data)) {
241  keylist = g_slist_prepend(keylist, key);
242  }
243  keylist= g_slist_sort(keylist, _configcontext_key_compare);
244  return keylist;
245 }
246 
247 
250 _configcontext_gettype(const ConfigContext* self, const char *name)
251 {
252  ConfigValue* cfg = self->getvalue(self, name);
253  if (cfg == NULL) {
254  return CFG_EEXIST;
255  }
256  return cfg->valtype;
257 }
258 
261 _configcontext_getvalue(const ConfigContext* self, const char *name)
262 {
263  gpointer ret = g_hash_table_lookup(self->_values, name);
264  if (ret != NULL) {
265  return CASTTOCLASS(ConfigValue, ret);
266  }
267  return NULL;
268 }
269 
271 FSTATIC gint64
273  , const char *name)
274 {
275  gpointer ret = g_hash_table_lookup(self->_values, name);
276  ConfigValue* cfg;
277 
278  if (ret == NULL) {
279  return -1;
280  }
281  cfg = CASTTOCLASS(ConfigValue, ret);
282  if (cfg->valtype != CFG_INT64) {
283  return -1;
284  }
285 
286  return cfg->u.intvalue;
287 }
288 
290 FSTATIC void
292  , const char *name
293  , gint value)
294 {
296  char * cpname = g_strdup(name);
297 
298  val->u.intvalue = value;
299  g_hash_table_replace(self->_values, cpname, val);
300 }
301 FSTATIC gboolean
302 _configcontext_appendint(ConfigContext*self, const char *name, gint value)
303 {
304  ConfigValue* array = self->getvalue(self, name);
305  ConfigValue* appendvalue;
306  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
307  appendvalue = _configcontext_value_new(CFG_INT64);
308  appendvalue->u.intvalue = value;
309  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
310  return TRUE;
311 }
312 FSTATIC double
314 {
315  ConfigValue* doubleval = self->getvalue(self, name);
316  // @TODO: Ought to return NaN (Not a Number) instead of -G_MAXDOUBLE on failure...
317  g_return_val_if_fail(doubleval != NULL && doubleval->valtype == CFG_FLOAT, -G_MAXDOUBLE);
318  return doubleval->u.floatvalue;
319 }
320 FSTATIC void
321 _configcontext_setdouble(ConfigContext*self, const char *name, double value)
322 {
324  doubleval->u.floatvalue = value;
325  g_hash_table_replace(self->_values, g_strdup(name), doubleval);
326 }
327 FSTATIC gboolean
328 _configcontext_appenddouble(ConfigContext*self, const char *name, double value)
329 {
330  ConfigValue* array = self->getvalue(self, name);
331  ConfigValue* appendvalue;
332  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
333  appendvalue = _configcontext_value_new(CFG_FLOAT);
334  appendvalue->u.floatvalue = value;
335  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
336  return TRUE;
337 }
338 
340 FSTATIC gboolean
342  , const char *name)
343 {
344  gpointer ret = g_hash_table_lookup(self->_values, name);
345  ConfigValue* cfg;
346 
347  if (ret == NULL) {
348  return -1;
349  }
350  cfg = CASTTOCLASS(ConfigValue, ret);
351  if (cfg->valtype != CFG_BOOL) {
352  return -1;
353  }
354 
355  return (gboolean)cfg->u.intvalue;
356 }
357 
359 FSTATIC void
361  , const char *name
362  , gint value)
363 {
365  char * cpname = g_strdup(name);
366 
367  val->u.intvalue = value;
368  g_hash_table_replace(self->_values, cpname, val);
369 }
370 
371 FSTATIC gboolean
372 _configcontext_appendbool(ConfigContext* self, const char *name, gboolean value)
373 {
374  ConfigValue* array = self->getvalue(self, name);
375  ConfigValue* appendvalue;
376  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
377  appendvalue = _configcontext_value_new(CFG_BOOL);
378  appendvalue->u.intvalue = value;
379  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
380  return TRUE;
381 }
382 
384 FSTATIC const char*
386  , const char *name)
387 {
388  gpointer ret = g_hash_table_lookup(self->_values, name);
389  ConfigValue* cfg;
390 
391  if (ret == NULL) {
392  return NULL;
393  }
394  cfg = CASTTOCLASS(ConfigValue, ret);
395  if (cfg->valtype != CFG_STRING) {
396  return NULL;
397  }
398  return cfg->u.strvalue;
399 }
400 
402 FSTATIC void
404  ,const char *name
405  ,const char *value)
406 {
408 
409  val->u.strvalue = g_strdup(value);
410  g_hash_table_replace(self->_values, g_strdup(name), val);
411 }
412 
413 FSTATIC gboolean
414 _configcontext_appendstring(ConfigContext* self, const char *name, const char *value)
415 {
416  ConfigValue* array = self->getvalue(self, name);
417  ConfigValue* appendvalue;
418  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
419  appendvalue = _configcontext_value_new(CFG_STRING);
420  appendvalue->u.strvalue = g_strdup(value);
421  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
422  return TRUE;
423 }
424 
425 FSTATIC GSList*
426 _configcontext_getarray(const ConfigContext* self, const char *name)
427 {
428  gpointer ret = g_hash_table_lookup(self->_values, name);
429  ConfigValue* cfg;
430 
431  if (ret == NULL) {
432  return NULL;
433  }
434  cfg = CASTTOCLASS(ConfigValue, ret);
435  if (cfg->valtype != CFG_ARRAY) {
436  g_warning("getarray called on object of type %d", cfg->valtype);
437  return NULL;
438  }
439  //g_warning("getarray[%s] on %s gives %p", name, self->baseclass.toString(self), cfg->u.arrayvalue);
440  return cfg->u.arrayvalue;
441 }
442 FSTATIC void
443 _configcontext_setarray(ConfigContext*self, const char *name, GSList*value)
444 {
445  char * cpname = g_strdup(name);
447  val->u.arrayvalue = value;
448 
450  g_hash_table_replace(self->_values, cpname, val);
451 }
452 
456  , const char *name)
457 {
458  gpointer ret = g_hash_table_lookup(self->_values, name);
459  ConfigValue* cfg;
460 
461  if (ret == NULL) {
462  return NULL;
463  }
464  cfg = CASTTOCLASS(ConfigValue, ret);
465  if (cfg->valtype != CFG_NETADDR) {
466  return NULL;
467  }
468  return cfg->u.addrvalue;
469 }
470 
472 FSTATIC void
474  , const char * name
475  , NetAddr* addr)
476 {
477  char * cpname = g_strdup(name);
479 
480  REF(addr);
481  val->u.addrvalue = addr;
482  g_hash_table_replace(self->_values, cpname, val);
483 }
484 
485 FSTATIC gboolean
487 {
488  ConfigValue* array = self->getvalue(self, name);
489  ConfigValue* appendvalue;
490  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
491  appendvalue = _configcontext_value_new(CFG_NETADDR);
492  REF(value);
493  appendvalue->u.addrvalue = value;
494  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
495  return TRUE;
496 }
497 
499 FSTATIC Frame*
501  , const char *name)
502 {
503  gpointer ret = g_hash_table_lookup(self->_values, name);
504  ConfigValue* cfg;
505 
506  if (ret == NULL) {
507  return NULL;
508  }
509  cfg = CASTTOCLASS(ConfigValue, ret);
510  if (cfg->valtype != CFG_FRAME) {
511  return NULL;
512  }
513  return cfg->u.framevalue;
514 }
515 
517 FSTATIC void
519  , const char * name
520  , Frame* frame)
521 {
523  char * cpname = g_strdup(name);
525 
526  REF(frame);
527  val->u.framevalue = frame;
528  g_hash_table_replace(self->_values, cpname, val);
529 }
530 
533 _configcontext_getconfig(const ConfigContext* self , const char* name)
534 {
535  gpointer ret = g_hash_table_lookup(self->_values, name);
536  ConfigValue* cfg;
537 
538  if (ret == NULL) {
539  return NULL;
540  }
541  cfg = CASTTOCLASS(ConfigValue, ret);
542  if (cfg->valtype != CFG_CFGCTX) {
543  return NULL;
544  }
545  return cfg->u.cfgctxvalue;
546 }
548 FSTATIC void
550 {
551  char * cpname = g_strdup(name);
553 
554  REF(value);
555  val->u.cfgctxvalue = value;
556  g_hash_table_replace(self->_values, cpname, val);
557 }
558 FSTATIC gboolean
560 {
561  ConfigValue* array = self->getvalue(self, name);
562  ConfigValue* appendvalue;
563  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
564  appendvalue = _configcontext_value_new(CFG_CFGCTX);
565  REF(value);
566  appendvalue->u.cfgctxvalue = value;
567  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
568  return TRUE;
569 }
570 
572 FSTATIC char*
573 _configcontext_getstr(const ConfigContext* self , const char* name)
574 {
575  ConfigValue* cfval = self->getvalue(self, name);
576  if (cfval == NULL) {
577  return NULL;
578  }
579  return _configcontext_elem_toString(cfval);
580 }
581 
585 {
586  AssimObj* aret;
587  ConfigValue* ret;
588 
589  aret = assimobj_new(sizeof(ConfigValue));
590  ret = NEWSUBCLASS(ConfigValue, aret);
591  ret->valtype = t;
592  memset(&ret->u, 0, sizeof(ret->u));
594  return ret;
595 }
596 
598 FSTATIC void
600 {
601  ConfigValue* self;
602  //fprintf(stderr, "configcontext_value_vfinalize(%p)\n", vself);
603  self = CASTTOCLASS(ConfigValue, vself);
604  UNREF(self);
605  vself = NULL;
606 }
607 FSTATIC void
609 {
610  ConfigValue* self;
611 
612  //fprintf(stderr, "configcontext_value_finalize(%p)\n", aself);
613  self = CASTTOCLASS(ConfigValue, aself);
614  //fprintf(stderr, "configcontext_value_finalize(%p): %d\n"
615  //, aself, self->valtype);
616  switch (self->valtype) {
617  case CFG_STRING:
618  g_free(self->u.strvalue); self->u.strvalue = NULL;
619  break;
620  case CFG_CFGCTX: {
621  UNREF(self->u.cfgctxvalue);
622  break;
623  }
624  case CFG_NETADDR: {
625  UNREF(self->u.addrvalue);
626  break;
627  }
628  case CFG_FRAME: {
629  UNREF(self->u.framevalue);
630  break;
631  }
632  case CFG_ARRAY: {
633  GSList* list = self->u.arrayvalue;
635  self->u.arrayvalue = NULL;
636  break;
637  }
638 
639  default: {
640  // Do nothing
641  break;
642  }
643  }
644  self->valtype = CFG_EEXIST;
645  memset(self, 0, sizeof(*self));
646  FREECLASSOBJ(self);
647  self = NULL;
648  aself = NULL;
649 }
650 
651 
652 #define JSONREPLACES "\\\"\b\f\n\r\t"
653 #define JSONREPLACEMENTS "\\\"bfnrt"
654 FSTATIC char *
657 {
658  GString* ret;
659  char * str;
660  const char * replacechars = JSONREPLACES;
661  ret = g_string_sized_new(strlen(s)+5);
662  g_string_append_c(ret, '"');
663 
664 
665  for (str=s; *str; ++str ) {
666  const char * found;
667  if (NULL != (found=strchr(replacechars, *str ))) {
668  size_t offset = found-replacechars;
669  g_string_append_c(ret, '\\');
670  g_string_append_c(ret, JSONREPLACEMENTS[offset]);
671  }else{
672  g_string_append_c(ret, *str);
673  }
674  }
675  g_string_append_c(ret, '"');
676  return g_string_free(ret, FALSE);
677 }
678 
680 FSTATIC char *
681 _configcontext_toString(gconstpointer aself)
682 {
683  const ConfigContext* self = CASTTOCONSTCLASS(ConfigContext, aself);
684 
685  GString* gsret = g_string_new("{");
686  GSList* keyelem;
687  GSList* nextkeyelem;
688  const char * comma = "";
689 
690  if (!self->_values) {
691  return NULL;
692  }
693  for (keyelem = self->keys(self); keyelem; keyelem = nextkeyelem) {
694  char * thiskey = keyelem->data;
695  ConfigValue* val = self->getvalue(self, thiskey);
696  gchar* elem = _configcontext_elem_toString(val);
697  g_string_append_printf(gsret, "%s\"%s\":%s", comma, thiskey, elem);
698  g_free(elem);
699  comma=",";
700  nextkeyelem = keyelem->next;
701  g_slist_free1(keyelem);
702  keyelem = NULL;
703  }
704  g_string_append(gsret, "}");
705  return g_string_free(gsret, FALSE);
706 }
708 FSTATIC char *
710 {
711  switch (val->valtype) {
712  case CFG_BOOL:
713  return g_strdup(val->u.intvalue? "true" : "false");
714 
715  case CFG_INT64:
716  return g_strdup_printf(FMT_64BIT"d", val->u.intvalue);
717 
718  case CFG_FLOAT:
719  return g_strdup_printf("%g", val->u.floatvalue);
720 
721  case CFG_STRING: {
722  //g_message("Got string pointer: %p", val->u.strvalue);
723  //g_message("Got string: %s", val->u.strvalue);
724  return JSONquotestring(val->u.strvalue);
725  }
726 
727  case CFG_CFGCTX: {
728  return val->u.cfgctxvalue->baseclass.toString(val->u.cfgctxvalue);
729  }
730  case CFG_ARRAY: {
731  const char * acomma = "";
732  GString* ret = g_string_new("[");
733  GSList* this;
734 
735  for (this = val->u.arrayvalue; this; this = this->next) {
736  ConfigValue* val = CASTTOCLASS(ConfigValue, this->data);
737  gchar* elem = _configcontext_elem_toString(val);
738  g_string_append_printf(ret, "%s%s", acomma, elem);
739  g_free(elem);
740  acomma=",";
741  }
742  g_string_append(ret, "]");
743  return g_string_free(ret, FALSE);
744  }
745  case CFG_NETADDR: {
746  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.addrvalue);
749  char* tostring = obj->toString(obj);
750  gchar* retstr = JSONquotestring(tostring);
751  g_free(tostring); tostring = NULL;
752  return retstr;
753  }
754  case CFG_FRAME: {
755  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.framevalue);
756  char* tostring = obj->toString(obj);
757  gchar* retstr = JSONquotestring(tostring);
758 
759  FREE(tostring); tostring=NULL;
760  return retstr;
761  }
762  case CFG_EEXIST:
763  case CFG_NULL:
764  return g_strdup("null");
765 
766  }//endswitch
767  /*NOTREACHED*/
768  return g_strdup("null");
769 }
770 
775 FSTATIC GScanner*
777 {
778  static GScannerConfig config;
779  GScanner* retval;
780  // Legal JSON keywords are true, false, and null
781  // There are no 'identifiers' as such.
782  static char firstchars[] = "tfn";
783  static char subsequentchars[] = "aelrsu";
784  static char whitespace[] = " \t\n\r\f";
785  static char hash_comment[] = "#\n";
786  static char True[] = "true";
787  static char False[] = "false";
788  static char Null[] = "null";
789  memset(&config, 0, sizeof(config));
790 
791  // For more info on what these settings do, see
792  // http://developer.gnome.org/glib/2.32/glib-Lexical-Scanner.html
793 
794  config.cset_skip_characters = whitespace;
795  config.cset_identifier_first = firstchars;
796  config.cset_identifier_nth = subsequentchars;
797  config.case_sensitive = TRUE;
798  config.skip_comment_multi = FALSE;
799  config.scan_comment_multi = FALSE;
800  config.cpair_comment_single = hash_comment; // NOTE: JSON extension: Allow # comments
801  config.skip_comment_single = TRUE; // Ignore # comments
802  config.scan_identifier = TRUE;
803  config.scan_identifier_1char = FALSE;
804  config.scan_identifier_NULL = FALSE;
805  config.scan_symbols = TRUE; // ???
806  config.scan_binary = FALSE;
807  config.scan_octal = FALSE;
808  config.scan_float = TRUE;
809  config.scan_hex = FALSE;
810  config.scan_hex_dollar = FALSE;
811  config.scan_string_sq = FALSE;
812  config.scan_string_dq = TRUE;
813  config.numbers_2_int = TRUE;
814  config.int_2_float = FALSE;
815  config.identifier_2_string = FALSE;
816  config.char_2_token = TRUE;
817  config.symbol_2_token = FALSE; // ???
818  config.scope_0_fallback = TRUE;
819  config.store_int64 = TRUE;
820 
821  retval = g_scanner_new(&config);
822  if (retval) {
823  g_scanner_scope_add_symbol(retval, 0, True, True);
824  g_scanner_scope_add_symbol(retval, 0, False, False);
825  g_scanner_scope_add_symbol(retval, 0, Null, Null);
826  }
827  return retval;
828 }
829 
830 #define TOKEN_COLON ':'
831 #define GULP (void)g_scanner_get_next_token(scan)
832 
833 #define SYNERROR(scan, token, symbol, msg) \
834  {g_warning("In Function %s line %d", __FUNCTION__, __LINE__);g_scanner_unexp_token(scan, token, "keyword", "keyword", symbol, msg, TRUE);}
835 
838 configcontext_new_JSON_string(const char * jsontext)
839 {
840  GScanner* scanner = _configcontext_JSON_GScanner_new();
841  ConfigContext* ret;
842 
843  g_scanner_input_text(scanner, jsontext, strlen(jsontext));
845  g_scanner_destroy(scanner);
846  return ret;
847 }
848 
852 {
854 
855  if (ret != NULL && g_scanner_get_next_token(scan) != G_TOKEN_EOF) {
856  SYNERROR(scan, G_TOKEN_EOF, NULL, NULL);
857  UNREF(ret);
858  }
859  return ret;
860 }
861 
865 {
866  ConfigContext* ret;
867  ConfigContext* membersret;
868  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_CURLY) {
869  GULP;
870  SYNERROR(scan, G_TOKEN_LEFT_CURLY, NULL, NULL);
871  return NULL;
872  }
873  GULP; // Swallow '{'
874  ret = configcontext_new(0);
875  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_CURLY) {
876  // Empty 'object' - which is just fine...
877  GULP;
878  return ret;
879  }
880 
881  membersret = _configcontext_JSON_parse_members(scan, ret);
882  if (membersret == NULL) {
883  UNREF(ret);
884  return NULL;
885  }
886 
887  if (g_scanner_get_next_token(scan) != G_TOKEN_RIGHT_CURLY) {
888  // Syntax error...
889  SYNERROR(scan, G_TOKEN_RIGHT_CURLY, NULL, NULL);
890  UNREF(ret);
891  return NULL;
892  }
893  return ret;
894 }
898 {
899  while (g_scanner_peek_next_token(scan) == G_TOKEN_STRING) {
901  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
902  GULP;
903  }else{
904  break;
905  }
906  }
907  return cfg;
908 }
909 
910 // Parse a JSON "name": value pair
913 {
914  char * name = NULL;
915  ConfigValue* value;
916  // "name" : _value_ pairs
917  //
918  // Name is always a string -
919  // Value can be any of:
920  // string
921  // number
922  // object
923  // array
924  // true (a symbol)
925  // false (a symbol)
926  // null (a symbol)
927  if (g_scanner_peek_next_token(scan) != G_TOKEN_STRING) {
928  return NULL;
929  }
930  GULP;
931  // Get value of G_TOKEN_STRING
932  name = g_strdup(scan->value.v_string);
933  if (g_scanner_peek_next_token(scan) != TOKEN_COLON) {
934  SYNERROR(scan, TOKEN_COLON, NULL, NULL);
935  // Syntax error
936  g_free(name); name = NULL;
937  return NULL;
938  }
939  GULP; // Swallow TOKEN_COLON
940  if (g_scanner_peek_next_token(scan) == TOKEN_COLON) {
941  return NULL;
942  }
943  // Next is a value...
944  value = _configcontext_JSON_parse_value(scan);
945  if (value == NULL) {
946  // Syntax error - already noted by the lower layers...
947  g_free(name); name = NULL;
948  return NULL;
949  }
950  g_hash_table_replace(cfg->_values, name, value);
951  return cfg;
952 }
953 
956 {
957  guint toktype = g_scanner_peek_next_token(scan);
958  switch(toktype) {
959  case G_TOKEN_STRING:{ // String
961  ConfigValue* val;
962  NetAddr* encoded;
963  GULP;
964  // See if we can convert it to a NetAddr...
966  if ((encoded = netaddr_string_new(scan->value.v_string)) != NULL) {
968  val->u.addrvalue = encoded;
969  encoded = NULL;
970  }else{
972  val->u.strvalue = g_strdup(scan->value.v_string);
973  }
974  return val;
975  }
976 
977  case '-': { // Minus sign (negative number)
978  ConfigValue* val;
979  GULP; // Throw away the negative sign
980  toktype = g_scanner_peek_next_token(scan);
981  if (toktype == G_TOKEN_INT) {
983  GULP;
984  val->u.intvalue = -scan->value.v_int64;
985  return val;
986  }else if (toktype == G_TOKEN_FLOAT) {
988  GULP;
989  val->u.floatvalue = -scan->value.v_float;
990  return val;
991  }else{
992  g_warning("Got token type %u after -", g_scanner_get_next_token(scan));
993  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol after -.");
994  return NULL;
995  }
996  return val;
997  }
998  break;
999 
1000  case G_TOKEN_INT: { // Integer
1002  GULP;
1003  val->u.intvalue = scan->value.v_int64;
1004  return val;
1005  }
1006  break;
1007 
1008  case G_TOKEN_FLOAT: { // Double value
1010  GULP;
1011  val->u.floatvalue = scan->value.v_float;
1012  return val;
1013  }
1014  break;
1015 
1016  case G_TOKEN_SYMBOL: { // true, false, null
1017  GULP;
1018  if (strcmp(scan->value.v_string, "true") == 0 || strcmp(scan->value.v_string, "false") == 0) {
1020  val->u.intvalue = (strcmp(scan->value.v_string, "true") == 0);
1021  return val;
1022  }else if (strcmp(scan->value.v_string, "null") == 0) {
1024  }else{
1025  SYNERROR(scan, G_TOKEN_NONE, NULL, "- expecting JSON value");
1026  // Syntax error
1027  return NULL;
1028  }
1029  }
1030  break;
1031 
1032 
1033  case G_TOKEN_LEFT_CURLY:{ // Object
1034  ConfigValue* val;
1035  ConfigContext* child;
1036  child = _configcontext_JSON_parse_object(scan);
1037  if (child == NULL) {
1038  // Syntax error - detected by child object
1039  return NULL;
1040  }
1042  val->u.cfgctxvalue = child;
1043  return val;
1044  }
1045  break;
1046 
1047 
1048  case G_TOKEN_LEFT_BRACE: { // Array
1049  ConfigValue* val;
1050  GSList* child = NULL;
1051  if (!_configcontext_JSON_parse_array(scan, &child)) {
1052  // Syntax error - detected by child object
1053  return NULL;
1054  }
1056  val->u.arrayvalue = child;
1057  return val;
1058  }
1059  break;
1060 
1061  // Things we don't support...
1062  default:
1063  // Syntax error
1064  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1065  //GULP;
1066  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1067  return NULL;
1068  }
1069  /*NOTREACHED*/
1070  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1071  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1072  return NULL;
1073 }
1074 FSTATIC gboolean
1075 _configcontext_JSON_parse_array(GScanner* scan, GSList** retval)
1076 {
1077  *retval = NULL;
1078  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_BRACE) {
1079  GULP;
1080  SYNERROR(scan, G_TOKEN_LEFT_BRACE, NULL, NULL);
1081  // Syntax error
1082  return FALSE;
1083  }
1084  GULP; // Swallow left square bracket (G_TOKEN_LEFT_BRACE)
1085  while (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE
1086  && !g_scanner_eof(scan)) {
1087  ConfigValue * value;
1088 
1089  // Parse the value
1090  value = _configcontext_JSON_parse_value(scan);
1091  if (value == NULL) {
1092  if (*retval != NULL) {
1094  *retval = NULL;
1095  return FALSE;
1096  }
1097  }else{
1098  *retval = g_slist_append(*retval, value);
1099  }
1100  // Expect a comma
1101  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
1102  GULP;
1103  }else if (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE) {
1104  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1105  GULP;
1106  return FALSE;
1107  }
1108  }
1109  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_BRACE) {
1110  GULP;
1111  return TRUE;
1112  }
1113  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1114  return FALSE;
1115 }
#define JSONREPLACES
FSTATIC ConfigContext * _configcontext_JSON_parse_object(GScanner *scan)
Parse a JSON object.
gboolean(* appendint)(ConfigContext *, const char *name, gint value)
Set integer value.
Definition: configcontext.h:76
ConfigContext * configcontext_new_JSON_string(const char *jsontext)
Construct a ConfigContext object from the given JSON string.
const char *(* getstring)(const ConfigContext *, const char *name)
Get String value.
Definition: configcontext.h:86
#define GULP
enum ConfigValType valtype
Definition: configcontext.h:59
FSTATIC void _configcontext_value_vfinalize(gpointer vself)
FSTATIC void _configcontext_setdouble(ConfigContext *, const char *name, double value)
FSTATIC Frame * _configcontext_getframe(const ConfigContext *, const char *name)
Return the Frame class value of a name.
FSTATIC NetAddr * _configcontext_getaddr(const ConfigContext *, const char *)
Return the NetAddr value of a name.
double(* getdouble)(const ConfigContext *, const char *name)
Get double value.
Definition: configcontext.h:80
FSTATIC char * _configcontext_elem_toString(ConfigValue *val)
Convert a ConfigContext element (ConfigValue) to a String.
FSTATIC ConfigContext * _configcontext_JSON_parse_string(const char *json)
FSTATIC gboolean _configcontext_appendstring(ConfigContext *, const char *name, const char *value)
FSTATIC void _key_free(gpointer vself)
char * strvalue
Definition: configcontext.h:64
void assim_slist_free_full(GSList *list, void(*datafree)(gpointer))
HAVE_G_GET_MONOTONIC_TIME.
FSTATIC char * JSONquotestring(char *s)
Escape characters in a string according to JSON conventions...
gboolean(* appendbool)(ConfigContext *, const char *name, gboolean)
Set bool value.
Definition: configcontext.h:79
This is the base Frame class object (in-memory TLV (type, length, value)) for every general component...
Definition: frame.h:43
FSTATIC gint64 _configcontext_getint(const ConfigContext *, const char *name)
Get an integer value.
FSTATIC void _configcontext_value_finalize(AssimObj *aself)
#define JSONREPLACEMENTS
FSTATIC gboolean _configcontext_appenddouble(ConfigContext *, const char *name, double value)
void(* setbool)(ConfigContext *, const char *name, gboolean)
Set bool value.
Definition: configcontext.h:78
void(* setconfig)(ConfigContext *, const char *, ConfigContext *)
Set ConfigContext value.
Definition: configcontext.h:96
#define FSTATIC
Definition: projectcommon.h:31
#define SYNERROR(scan, token, symbol, msg)
FSTATIC void _configcontext_setint(ConfigContext *, const char *name, gint value)
Set a name to an integer value.
enum ConfigValType(* gettype)(const ConfigContext *, const char *)
Return type.
Definition: configcontext.h:99
gint64(* getint)(const ConfigContext *, const char *name)
Get integer value.
Definition: configcontext.h:74
FSTATIC GSList * _configcontext_keys(const ConfigContext *)
Return a GSList of all the keys in a ConfigContext object.
#define FREECLASSOBJ(obj)
Free a C-class object.
Definition: proj_classes.h:76
ConfigContext * cfgctxvalue
Definition: configcontext.h:65
void(* setaddr)(ConfigContext *, const char *, NetAddr *)
Set NetAddr value.
Definition: configcontext.h:93
void(* setframe)(ConfigContext *, const char *, Frame *)
Set Frame value.
Definition: configcontext.h:91
NetAddr *(* getaddr)(const ConfigContext *, const char *name)
Get NetAddr value.
Definition: configcontext.h:92
FSTATIC gboolean _configcontext_appendconfig(ConfigContext *, const char *, ConfigContext *)
union _ConfigValue::@2 u
AssimObj baseclass
Definition: configcontext.h:72
#define __FUNCTION__
FSTATIC gboolean _configcontext_appendaddr(ConfigContext *self, const char *name, NetAddr *value)
GSList *(* getarray)(const ConfigContext *, const char *name)
Get array value.
Definition: configcontext.h:84
gboolean(* appendstring)(ConfigContext *, const char *name, const char *value)
Set String value.
Definition: configcontext.h:88
FSTATIC gboolean _configcontext_appendint(ConfigContext *, const char *name, gint value)
void(* setarray)(ConfigContext *, const char *name, GSList *)
Set array value.
Definition: configcontext.h:85
FSTATIC void _configcontext_setaddr(ConfigContext *, const char *name, NetAddr *)
Set the NetAddr value of a name.
Frame * framevalue
Definition: configcontext.h:67
FSTATIC void _configcontext_finalize(AssimObj *self)
Finalize (free) a ConfigContext object.
FSTATIC enum ConfigValType _configcontext_gettype(const ConfigContext *, const char *name)
Return a the type of value associated with a given name.
#define FMT_64BIT
Format designator for a 64 bit integer.
Definition: projectcommon.h:32
#define FREE(m)
Our interface to free.
Definition: projectcommon.h:29
#define REF(obj)
Definition: assimobj.h:39
#define TOKEN_COLON
FSTATIC ConfigContext * _configcontext_JSON_parse_members(GScanner *scan, ConfigContext *cfg)
Parse a JSON (object) members (a list of "name" : "value" pairs)
#define CASTTOCONSTCLASS(Cclass, obj)
Safely cast 'obj' to const C-class 'class' - verifying that it was registered as being of type class ...
Definition: proj_classes.h:71
gboolean(* getbool)(const ConfigContext *, const char *name)
Get boolean value.
Definition: configcontext.h:77
GSList *(* keys)(const ConfigContext *)
Return list of keys.
void(* setdouble)(ConfigContext *, const char *name, double value)
Definition: configcontext.h:81
FSTATIC ConfigContext * _configcontext_JSON_parse_objandEOF(GScanner *scan)
Parse complete JSON object followed by EOF.
GSList * arrayvalue
Definition: configcontext.h:63
Implements Configuration Context class.
gboolean(* appendaddr)(ConfigContext *, const char *, NetAddr *)
Set NetAddr value.
Definition: configcontext.h:94
FSTATIC void _configcontext_setstring(ConfigContext *, const char *name, const char *value)
Set a name to a string value.
void(* setint)(ConfigContext *, const char *name, gint value)
Set integer value.
Definition: configcontext.h:75
FSTATIC ConfigValue * _configcontext_value_new(enum ConfigValType)
Create a ConfigValue object (containing an object and its type)
void(* setstring)(ConfigContext *, const char *name, const char *value)
Definition: configcontext.h:87
FSTATIC void _configcontext_setarray(ConfigContext *, const char *name, GSList *value)
GHashTable * _values
table of Values
Definition: configcontext.h:73
AssimObj * assimobj_new(guint objsize)
Definition: assimobj.c:74
FSTATIC char * _configcontext_getstr(const ConfigContext *, const char *)
Return a string value (toString) associated with a given name.
ConfigValType
Definition: configcontext.h:44
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
NetAddr * addrvalue
Definition: configcontext.h:66
FSTATIC double _configcontext_getdouble(const ConfigContext *, const char *name)
The NetAddr class class represents a general network address - whether IP, MAC, or any other type of ...
Definition: netaddr.h:43
FSTATIC gboolean _configcontext_appendbool(ConfigContext *, const char *name, gboolean value)
FSTATIC void _configcontext_setconfig(ConfigContext *, const char *, ConfigContext *)
Save/Set a ConfigContext value associated with a given name.
FSTATIC void _configcontext_setbool(ConfigContext *, const char *name, gboolean value)
#define g_slist_free_full
Definition: projectcommon.h:73
FSTATIC char * _configcontext_toString(gconstpointer aself)
Convert a ConfigContext to a printable string (in JSON notation)
Frame *(* getframe)(const ConfigContext *, const char *)
Get Frame value.
Definition: configcontext.h:90
FSTATIC GScanner * _configcontext_JSON_GScanner_new(void)
Create a GScanner object that is set up to scan JSON text.
ConfigContext *(* getconfig)(const ConfigContext *, const char *name)
Get ConfigContext value.
Definition: configcontext.h:95
FSTATIC gboolean _configcontext_getbool(const ConfigContext *, const char *name)
Get an boolean value.
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
guint(* keycount)(const ConfigContext *)
Return number of keys in object.
FSTATIC void _configcontext_setframe(ConfigContext *, const char *name, Frame *)
Set the signature frame to the given SignFrame.
ConfigValue *(* getvalue)(const ConfigContext *, const char *)
Return ConfigValue Object.
FSTATIC GSList * _configcontext_getarray(const ConfigContext *, const char *name)
FSTATIC ConfigValue * _configcontext_JSON_parse_value(GScanner *scan)
FSTATIC gboolean _configcontext_JSON_parse_array(GScanner *scan, GSList **retval)
gboolean(* appendconfig)(ConfigContext *, const char *, ConfigContext *)
Set ConfigContext value.
Definition: configcontext.h:97
ConfigContext * configcontext_new(gsize objsize)
Construct a new ConfigContext object - with no values defaulted.
void(* delkey)(const ConfigContext *, const char *)
Delete the object with the given key.
FSTATIC ConfigValue * _configcontext_getvalue(const ConfigContext *, const char *name)
Return a the value structure associated with a given name.
double floatvalue
Definition: configcontext.h:62
NetAddr * netaddr_string_new(const char *addrstr)
Create a NetAddr from an ipv4, ipv6 or MAC address string.
Definition: netaddr.c:915
FSTATIC guint _configcontext_keycount(const ConfigContext *)
Return the number of keys in a ConfigContext object.
#define CASTTOCLASS(Cclass, obj)
Safely cast 'obj' to C-class 'class' - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
FSTATIC void _configcontext_delkey(const ConfigContext *, const char *)
Delete the key with the given value.
struct _ConfigContext ConfigContext
This is the base ConfigContext class object providing configuration context for our clients...
Definition: configcontext.h:42
#define NEWSUBCLASS(Cclass, obj)
Definition: proj_classes.h:67
gint64 intvalue
Definition: configcontext.h:61
FSTATIC gint _configcontext_key_compare(gconstpointer a, gconstpointer b)
Compare two string keys (for GSList sorting)
FSTATIC ConfigContext * _configcontext_JSON_parse_pair(GScanner *scan, ConfigContext *cfg)
FSTATIC const char * _configcontext_getstring(const ConfigContext *, const char *name)
Return the value of a string name.
FSTATIC ConfigContext * _configcontext_getconfig(const ConfigContext *, const char *)
Return a the a ConfigContext value associated with a given name.