The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups 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->setint = _configcontext_setint;
146  newcontext->appendint = _configcontext_appendint;
147  newcontext->getbool = _configcontext_getbool;
148  newcontext->setbool = _configcontext_setbool;
150  newcontext->getstring = _configcontext_getstring;
151  newcontext->setstring = _configcontext_setstring;
153  newcontext->getframe = _configcontext_getframe;
154  newcontext->setframe = _configcontext_setframe;
155  newcontext->getaddr = _configcontext_getaddr;
156  newcontext->setaddr = _configcontext_setaddr;
158  newcontext->getconfig = _configcontext_getconfig;
159  newcontext->setconfig = _configcontext_setconfig;
161  newcontext->getarray = _configcontext_getarray;
162  newcontext->setarray = _configcontext_setarray;
163  newcontext->gettype = _configcontext_gettype;
164  newcontext->getvalue = _configcontext_getvalue;
165  newcontext->keys = _configcontext_keys;
166  newcontext->keycount = _configcontext_keycount;
167  newcontext->delkey = _configcontext_delkey;
168  newcontext->_values = g_hash_table_new_full(g_str_hash, g_str_equal, _key_free
172  return newcontext;
173 }
174 
176 FSTATIC void
178 {
179  ConfigContext* self = CASTTOCLASS(ConfigContext, aself);
180 #if 0
181  {
182  char * s = self->baseclass.toString(&self->baseclass);
183  g_warning("%s.%d: Finalizing %p: %s", __FUNCTION__, __LINE__, aself, s);
184  g_free(s); s = NULL;
185  }
186 #endif
187 
188  if (self->_values) {
189  g_hash_table_destroy(self->_values);
190  self->_values = NULL;
191  }
192  FREECLASSOBJ(self);
193 }
194 
196 FSTATIC gint
197 _configcontext_key_compare(gconstpointer a, gconstpointer b)
198 {
199  return strcmp((const char *)a, (const char*)b);
200 }
201 
203 FSTATIC void
204 _configcontext_delkey(const ConfigContext* cfg, const char * key)
205 {
206  g_hash_table_remove(cfg->_values, key);
207 }
209 FSTATIC guint
211 {
212  GHashTableIter iter;
213  gpointer key;
214  gpointer data;
215  guint ret = 0;
216 
217  g_hash_table_iter_init(&iter, cfg->_values);
218  while (g_hash_table_iter_next(&iter, &key, &data)) {
219  ++ret;
220  }
221  return ret;
222 }
223 
225 FSTATIC GSList*
227 {
228  GSList* keylist = NULL;
229  GHashTableIter iter;
230  gpointer key;
231  gpointer data;
232 
233  if (!cfg->_values) {
234  return NULL;
235  }
236 
237  g_hash_table_iter_init(&iter, cfg->_values);
238  while (g_hash_table_iter_next(&iter, &key, &data)) {
239  keylist = g_slist_prepend(keylist, key);
240  }
241  keylist= g_slist_sort(keylist, _configcontext_key_compare);
242  return keylist;
243 }
244 
245 
248 _configcontext_gettype(const ConfigContext* self, const char *name)
249 {
250  ConfigValue* cfg = self->getvalue(self, name);
251  if (cfg == NULL) {
252  return CFG_EEXIST;
253  }
254  return cfg->valtype;
255 }
256 
259 _configcontext_getvalue(const ConfigContext* self, const char *name)
260 {
261  gpointer ret = g_hash_table_lookup(self->_values, name);
262  if (ret != NULL) {
263  return CASTTOCLASS(ConfigValue, ret);
264  }
265  return NULL;
266 }
267 
269 FSTATIC gint64
271  , const char *name)
272 {
273  gpointer ret = g_hash_table_lookup(self->_values, name);
274  ConfigValue* cfg;
275 
276  if (ret == NULL) {
277  return -1;
278  }
279  cfg = CASTTOCLASS(ConfigValue, ret);
280  if (cfg->valtype != CFG_INT64) {
281  return -1;
282  }
283 
284  return cfg->u.intvalue;
285 }
286 
288 FSTATIC void
290  , const char *name
291  , gint value)
292 {
294  char * cpname = g_strdup(name);
295 
296  val->u.intvalue = value;
297  g_hash_table_replace(self->_values, cpname, val);
298 }
299 FSTATIC gboolean
300 _configcontext_appendint(ConfigContext*self, const char *name, gint value)
301 {
302  ConfigValue* array = self->getvalue(self, name);
303  ConfigValue* appendvalue;
304  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
305  appendvalue = _configcontext_value_new(CFG_INT64);
306  appendvalue->u.intvalue = value;
307  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
308  return TRUE;
309 }
310 FSTATIC double
312 {
313  ConfigValue* doubleval = self->getvalue(self, name);
314  // @TODO: Ought to return NaN (Not a Number) instead of -G_MAXDOUBLE on failure...
315  g_return_val_if_fail(doubleval != NULL && doubleval->valtype == CFG_FLOAT, -G_MAXDOUBLE);
316  return doubleval->u.floatvalue;
317 }
318 FSTATIC void
319 _configcontext_setdouble(ConfigContext*self, const char *name, double value)
320 {
322  doubleval->u.floatvalue = value;
323  g_hash_table_replace(self->_values, g_strdup(name), doubleval);
324 }
325 FSTATIC gboolean
326 _configcontext_appenddouble(ConfigContext*self, const char *name, double value)
327 {
328  ConfigValue* array = self->getvalue(self, name);
329  ConfigValue* appendvalue;
330  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
331  appendvalue = _configcontext_value_new(CFG_FLOAT);
332  appendvalue->u.floatvalue = value;
333  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
334  return TRUE;
335 }
336 
338 FSTATIC gboolean
340  , const char *name)
341 {
342  gpointer ret = g_hash_table_lookup(self->_values, name);
343  ConfigValue* cfg;
344 
345  if (ret == NULL) {
346  return -1;
347  }
348  cfg = CASTTOCLASS(ConfigValue, ret);
349  if (cfg->valtype != CFG_BOOL) {
350  return -1;
351  }
352 
353  return (gboolean)cfg->u.intvalue;
354 }
355 
357 FSTATIC void
359  , const char *name
360  , gint value)
361 {
363  char * cpname = g_strdup(name);
364 
365  val->u.intvalue = value;
366  g_hash_table_replace(self->_values, cpname, val);
367 }
368 
369 FSTATIC gboolean
370 _configcontext_appendbool(ConfigContext* self, const char *name, gboolean value)
371 {
372  ConfigValue* array = self->getvalue(self, name);
373  ConfigValue* appendvalue;
374  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
375  appendvalue = _configcontext_value_new(CFG_BOOL);
376  appendvalue->u.intvalue = value;
377  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
378  return TRUE;
379 }
380 
382 FSTATIC const char*
384  , const char *name)
385 {
386  gpointer ret = g_hash_table_lookup(self->_values, name);
387  ConfigValue* cfg;
388 
389  if (ret == NULL) {
390  return NULL;
391  }
392  cfg = CASTTOCLASS(ConfigValue, ret);
393  if (cfg->valtype != CFG_STRING) {
394  return NULL;
395  }
396  return cfg->u.strvalue;
397 }
398 
400 FSTATIC void
402  ,const char *name
403  ,const char *value)
404 {
406 
407  val->u.strvalue = g_strdup(value);
408  g_hash_table_replace(self->_values, g_strdup(name), val);
409 }
410 
411 FSTATIC gboolean
412 _configcontext_appendstring(ConfigContext* self, const char *name, const char *value)
413 {
414  ConfigValue* array = self->getvalue(self, name);
415  ConfigValue* appendvalue;
416  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
417  appendvalue = _configcontext_value_new(CFG_STRING);
418  appendvalue->u.strvalue = g_strdup(value);
419  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
420  return TRUE;
421 }
422 
423 FSTATIC GSList*
424 _configcontext_getarray(const ConfigContext* self, const char *name)
425 {
426  gpointer ret = g_hash_table_lookup(self->_values, name);
427  ConfigValue* cfg;
428 
429  if (ret == NULL) {
430  return NULL;
431  }
432  cfg = CASTTOCLASS(ConfigValue, ret);
433  if (cfg->valtype != CFG_ARRAY) {
434  g_warning("getarray called on object of type %d", cfg->valtype);
435  return NULL;
436  }
437  //g_warning("getarray[%s] on %s gives %p", name, self->baseclass.toString(self), cfg->u.arrayvalue);
438  return cfg->u.arrayvalue;
439 }
440 FSTATIC void
441 _configcontext_setarray(ConfigContext*self, const char *name, GSList*value)
442 {
443  char * cpname = g_strdup(name);
445  val->u.arrayvalue = value;
446 
448  g_hash_table_replace(self->_values, cpname, val);
449 }
450 
454  , const char *name)
455 {
456  gpointer ret = g_hash_table_lookup(self->_values, name);
457  ConfigValue* cfg;
458 
459  if (ret == NULL) {
460  return NULL;
461  }
462  cfg = CASTTOCLASS(ConfigValue, ret);
463  if (cfg->valtype != CFG_NETADDR) {
464  return NULL;
465  }
466  return cfg->u.addrvalue;
467 }
468 
470 FSTATIC void
472  , const char * name
473  , NetAddr* addr)
474 {
475  char * cpname = g_strdup(name);
477 
478  REF(addr);
479  val->u.addrvalue = addr;
480  g_hash_table_replace(self->_values, cpname, val);
481 }
482 
483 FSTATIC gboolean
485 {
486  ConfigValue* array = self->getvalue(self, name);
487  ConfigValue* appendvalue;
488  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
489  appendvalue = _configcontext_value_new(CFG_NETADDR);
490  REF(value);
491  appendvalue->u.addrvalue = value;
492  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
493  return TRUE;
494 }
495 
497 FSTATIC Frame*
499  , const char *name)
500 {
501  gpointer ret = g_hash_table_lookup(self->_values, name);
502  ConfigValue* cfg;
503 
504  if (ret == NULL) {
505  return NULL;
506  }
507  cfg = CASTTOCLASS(ConfigValue, ret);
508  if (cfg->valtype != CFG_FRAME) {
509  return NULL;
510  }
511  return cfg->u.framevalue;
512 }
513 
515 FSTATIC void
517  , const char * name
518  , Frame* frame)
519 {
521  char * cpname = g_strdup(name);
523 
524  REF(frame);
525  val->u.framevalue = frame;
526  g_hash_table_replace(self->_values, cpname, val);
527 }
528 
531 _configcontext_getconfig(const ConfigContext* self , const char* name)
532 {
533  gpointer ret = g_hash_table_lookup(self->_values, name);
534  ConfigValue* cfg;
535 
536  if (ret == NULL) {
537  return NULL;
538  }
539  cfg = CASTTOCLASS(ConfigValue, ret);
540  if (cfg->valtype != CFG_CFGCTX) {
541  return NULL;
542  }
543  return cfg->u.cfgctxvalue;
544 }
546 FSTATIC void
548 {
549  char * cpname = g_strdup(name);
551 
552  REF(value);
553  val->u.cfgctxvalue = value;
554  g_hash_table_replace(self->_values, cpname, val);
555 }
556 FSTATIC gboolean
558 {
559  ConfigValue* array = self->getvalue(self, name);
560  ConfigValue* appendvalue;
561  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
562  appendvalue = _configcontext_value_new(CFG_CFGCTX);
563  REF(value);
564  appendvalue->u.cfgctxvalue = value;
565  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
566  return TRUE;
567 }
568 
570 FSTATIC char*
571 _configcontext_getstr(const ConfigContext* self , const char* name)
572 {
573  ConfigValue* cfval = self->getvalue(self, name);
574  if (cfval == NULL) {
575  return NULL;
576  }
577  return _configcontext_elem_toString(cfval);
578 }
579 
583 {
584  AssimObj* aret;
585  ConfigValue* ret;
586 
587  aret = assimobj_new(sizeof(ConfigValue));
588  ret = NEWSUBCLASS(ConfigValue, aret);
589  ret->valtype = t;
590  memset(&ret->u, 0, sizeof(ret->u));
592  return ret;
593 }
594 
596 FSTATIC void
598 {
599  ConfigValue* self;
600  //fprintf(stderr, "configcontext_value_vfinalize(%p)\n", vself);
601  self = CASTTOCLASS(ConfigValue, vself);
602  UNREF(self);
603  vself = NULL;
604 }
605 FSTATIC void
607 {
608  ConfigValue* self;
609 
610  //fprintf(stderr, "configcontext_value_finalize(%p)\n", aself);
611  self = CASTTOCLASS(ConfigValue, aself);
612  //fprintf(stderr, "configcontext_value_finalize(%p): %d\n"
613  //, aself, self->valtype);
614  switch (self->valtype) {
615  case CFG_STRING:
616  g_free(self->u.strvalue); self->u.strvalue = NULL;
617  break;
618  case CFG_CFGCTX: {
619  UNREF(self->u.cfgctxvalue);
620  break;
621  }
622  case CFG_NETADDR: {
623  UNREF(self->u.addrvalue);
624  break;
625  }
626  case CFG_FRAME: {
627  UNREF(self->u.framevalue);
628  break;
629  }
630  case CFG_ARRAY: {
631  GSList* list = self->u.arrayvalue;
633  self->u.arrayvalue = NULL;
634  break;
635  }
636 
637  default: {
638  // Do nothing
639  break;
640  }
641  }
642  self->valtype = CFG_EEXIST;
643  memset(self, 0, sizeof(*self));
644  FREECLASSOBJ(self);
645  self = NULL;
646  aself = NULL;
647 }
648 
649 
650 #define JSONREPLACES "\\\"\b\f\n\r\t"
651 #define JSONREPLACEMENTS "\\\"bfnrt"
652 FSTATIC char *
655 {
656  GString* ret;
657  char * str;
658  const char * replacechars = JSONREPLACES;
659  ret = g_string_sized_new(strlen(s)+5);
660  g_string_append_c(ret, '"');
661 
662 
663  for (str=s; *str; ++str ) {
664  const char * found;
665  if (NULL != (found=strchr(replacechars, *str ))) {
666  size_t offset = found-replacechars;
667  g_string_append_c(ret, '\\');
668  g_string_append_c(ret, JSONREPLACEMENTS[offset]);
669  }else{
670  g_string_append_c(ret, *str);
671  }
672  }
673  g_string_append_c(ret, '"');
674  return g_string_free(ret, FALSE);
675 }
676 
678 FSTATIC char *
679 _configcontext_toString(gconstpointer aself)
680 {
681  const ConfigContext* self = CASTTOCONSTCLASS(ConfigContext, aself);
682 
683  GString* gsret = g_string_new("{");
684  GSList* keyelem;
685  GSList* nextkeyelem;
686  const char * comma = "";
687 
688  if (!self->_values) {
689  return NULL;
690  }
691  for (keyelem = self->keys(self); keyelem; keyelem = nextkeyelem) {
692  char * thiskey = keyelem->data;
693  ConfigValue* val = self->getvalue(self, thiskey);
694  gchar* elem = _configcontext_elem_toString(val);
695  g_string_append_printf(gsret, "%s\"%s\":%s", comma, thiskey, elem);
696  g_free(elem);
697  comma=",";
698  nextkeyelem = keyelem->next;
699  g_slist_free1(keyelem);
700  keyelem = NULL;
701  }
702  g_string_append(gsret, "}");
703  return g_string_free(gsret, FALSE);
704 }
706 FSTATIC char *
708 {
709  switch (val->valtype) {
710  case CFG_BOOL:
711  return g_strdup(val->u.intvalue? "true" : "false");
712 
713  case CFG_INT64:
714  return g_strdup_printf(FMT_64BIT"d", val->u.intvalue);
715 
716  case CFG_FLOAT:
717  return g_strdup_printf("%g", val->u.floatvalue);
718 
719  case CFG_STRING: {
720  //g_message("Got string pointer: %p", val->u.strvalue);
721  //g_message("Got string: %s", val->u.strvalue);
722  return JSONquotestring(val->u.strvalue);
723  }
724 
725  case CFG_CFGCTX: {
726  return val->u.cfgctxvalue->baseclass.toString(val->u.cfgctxvalue);
727  }
728  case CFG_ARRAY: {
729  const char * acomma = "";
730  GString* ret = g_string_new("[");
731  GSList* this;
732 
733  for (this = val->u.arrayvalue; this; this = this->next) {
734  ConfigValue* val = CASTTOCLASS(ConfigValue, this->data);
735  gchar* elem = _configcontext_elem_toString(val);
736  g_string_append_printf(ret, "%s%s", acomma, elem);
737  g_free(elem);
738  acomma=",";
739  }
740  g_string_append(ret, "]");
741  return g_string_free(ret, FALSE);
742  }
743  case CFG_NETADDR: {
744  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.addrvalue);
747  char* tostring = obj->toString(obj);
748  gchar* retstr = JSONquotestring(tostring);
749  g_free(tostring); tostring = NULL;
750  return retstr;
751  }
752  case CFG_FRAME: {
753  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.framevalue);
754  char* tostring = obj->toString(obj);
755  gchar* retstr = JSONquotestring(tostring);
756 
757  FREE(tostring); tostring=NULL;
758  return retstr;
759  }
760  case CFG_EEXIST:
761  case CFG_NULL:
762  return g_strdup("null");
763 
764  }//endswitch
765  /*NOTREACHED*/
766  return g_strdup("null");
767 }
768 
773 FSTATIC GScanner*
775 {
776  static GScannerConfig config;
777  GScanner* retval;
778  // Legal JSON keywords are true, false, and null
779  // There are no 'identifiers' as such.
780  static char firstchars[] = "tfn";
781  static char subsequentchars[] = "aelrsu";
782  static char whitespace[] = " \t\n\r\f";
783  static char hash_comment[] = "#\n";
784  static char True[] = "true";
785  static char False[] = "false";
786  static char Null[] = "null";
787  memset(&config, 0, sizeof(config));
788 
789  // For more info on what these settings do, see
790  // http://developer.gnome.org/glib/2.32/glib-Lexical-Scanner.html
791 
792  config.cset_skip_characters = whitespace;
793  config.cset_identifier_first = firstchars;
794  config.cset_identifier_nth = subsequentchars;
795  config.case_sensitive = TRUE;
796  config.skip_comment_multi = FALSE;
797  config.scan_comment_multi = FALSE;
798  config.cpair_comment_single = hash_comment; // NOTE: JSON extension: Allow # comments
799  config.skip_comment_single = TRUE; // Ignore # comments
800  config.scan_identifier = TRUE;
801  config.scan_identifier_1char = FALSE;
802  config.scan_identifier_NULL = FALSE;
803  config.scan_symbols = TRUE; // ???
804  config.scan_binary = FALSE;
805  config.scan_octal = FALSE;
806  config.scan_float = TRUE;
807  config.scan_hex = FALSE;
808  config.scan_hex_dollar = FALSE;
809  config.scan_string_sq = FALSE;
810  config.scan_string_dq = TRUE;
811  config.numbers_2_int = TRUE;
812  config.int_2_float = FALSE;
813  config.identifier_2_string = FALSE;
814  config.char_2_token = TRUE;
815  config.symbol_2_token = FALSE; // ???
816  config.scope_0_fallback = TRUE;
817  config.store_int64 = TRUE;
818 
819  retval = g_scanner_new(&config);
820  if (retval) {
821  g_scanner_scope_add_symbol(retval, 0, True, True);
822  g_scanner_scope_add_symbol(retval, 0, False, False);
823  g_scanner_scope_add_symbol(retval, 0, Null, Null);
824  }
825  return retval;
826 }
827 
828 #define TOKEN_COLON ':'
829 #define GULP (void)g_scanner_get_next_token(scan)
830 
831 #define SYNERROR(scan, token, symbol, msg) \
832  {g_warning("In Function %s line %d", __FUNCTION__, __LINE__);g_scanner_unexp_token(scan, token, "keyword", "keyword", symbol, msg, TRUE);}
833 
836 configcontext_new_JSON_string(const char * jsontext)
837 {
838  GScanner* scanner = _configcontext_JSON_GScanner_new();
839  ConfigContext* ret;
840 
841  g_scanner_input_text(scanner, jsontext, strlen(jsontext));
843  g_scanner_destroy(scanner);
844  return ret;
845 }
846 
850 {
852 
853  if (ret != NULL && g_scanner_get_next_token(scan) != G_TOKEN_EOF) {
854  SYNERROR(scan, G_TOKEN_EOF, NULL, NULL);
855  UNREF(ret);
856  }
857  return ret;
858 }
859 
863 {
864  ConfigContext* ret;
865  ConfigContext* membersret;
866  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_CURLY) {
867  GULP;
868  SYNERROR(scan, G_TOKEN_LEFT_CURLY, NULL, NULL);
869  return NULL;
870  }
871  GULP; // Swallow '{'
872  ret = configcontext_new(0);
873  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_CURLY) {
874  // Empty 'object' - which is just fine...
875  GULP;
876  return ret;
877  }
878 
879  membersret = _configcontext_JSON_parse_members(scan, ret);
880  if (membersret == NULL) {
881  UNREF(ret);
882  return NULL;
883  }
884 
885  if (g_scanner_get_next_token(scan) != G_TOKEN_RIGHT_CURLY) {
886  // Syntax error...
887  SYNERROR(scan, G_TOKEN_RIGHT_CURLY, NULL, NULL);
888  UNREF(ret);
889  return NULL;
890  }
891  return ret;
892 }
896 {
897  while (g_scanner_peek_next_token(scan) == G_TOKEN_STRING) {
899  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
900  GULP;
901  }else{
902  break;
903  }
904  }
905  return cfg;
906 }
907 
908 // Parse a JSON "name": value pair
911 {
912  char * name = NULL;
913  ConfigValue* value;
914  // "name" : _value_ pairs
915  //
916  // Name is always a string -
917  // Value can be any of:
918  // string
919  // number
920  // object
921  // array
922  // true (a symbol)
923  // false (a symbol)
924  // null (a symbol)
925  if (g_scanner_peek_next_token(scan) != G_TOKEN_STRING) {
926  return NULL;
927  }
928  GULP;
929  // Get value of G_TOKEN_STRING
930  name = g_strdup(scan->value.v_string);
931  if (g_scanner_peek_next_token(scan) != TOKEN_COLON) {
932  SYNERROR(scan, TOKEN_COLON, NULL, NULL);
933  // Syntax error
934  g_free(name); name = NULL;
935  return NULL;
936  }
937  GULP; // Swallow TOKEN_COLON
938  if (g_scanner_peek_next_token(scan) == TOKEN_COLON) {
939  return NULL;
940  }
941  // Next is a value...
942  value = _configcontext_JSON_parse_value(scan);
943  if (value == NULL) {
944  // Syntax error - already noted by the lower layers...
945  g_free(name); name = NULL;
946  return NULL;
947  }
948  g_hash_table_replace(cfg->_values, name, value);
949  return cfg;
950 }
951 
954 {
955  guint toktype = g_scanner_peek_next_token(scan);
956  switch(toktype) {
957  case G_TOKEN_STRING:{ // String
959  ConfigValue* val;
960  NetAddr* encoded;
961  GULP;
962  // See if we can convert it to a NetAddr...
964  if ((encoded = netaddr_string_new(scan->value.v_string)) != NULL) {
966  val->u.addrvalue = encoded;
967  encoded = NULL;
968  }else{
970  val->u.strvalue = g_strdup(scan->value.v_string);
971  }
972  return val;
973  }
974 
975  case G_TOKEN_INT: { // Integer
977  GULP;
978  val->u.intvalue = scan->value.v_int64;
979  return val;
980  }
981  break;
982 
983  case G_TOKEN_FLOAT: { // Double value
985  GULP;
986  val->u.floatvalue = scan->value.v_float;
987  return val;
988  }
989  break;
990 
991  case G_TOKEN_SYMBOL: { // true, false, null
992  GULP;
993  if (strcmp(scan->value.v_string, "true") == 0 || strcmp(scan->value.v_string, "false") == 0) {
995  val->u.intvalue = (strcmp(scan->value.v_string, "true") == 0);
996  return val;
997  }else if (strcmp(scan->value.v_string, "null") == 0) {
999  }else{
1000  SYNERROR(scan, G_TOKEN_NONE, NULL, "- expecting JSON value");
1001  // Syntax error
1002  return NULL;
1003  }
1004  }
1005  break;
1006 
1007 
1008  case G_TOKEN_LEFT_CURLY:{ // Object
1009  ConfigValue* val;
1010  ConfigContext* child;
1011  child = _configcontext_JSON_parse_object(scan);
1012  if (child == NULL) {
1013  // Syntax error - detected by child object
1014  return NULL;
1015  }
1017  val->u.cfgctxvalue = child;
1018  return val;
1019  }
1020  break;
1021 
1022 
1023  case G_TOKEN_LEFT_BRACE: { // Array
1024  ConfigValue* val;
1025  GSList* child = NULL;
1026  if (!_configcontext_JSON_parse_array(scan, &child)) {
1027  // Syntax error - detected by child object
1028  return NULL;
1029  }
1031  val->u.arrayvalue = child;
1032  return val;
1033  }
1034  break;
1035 
1036  // Things we don't support...
1037  default:
1038  // Syntax error
1039  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1040  //GULP;
1041  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1042  return NULL;
1043  }
1044  /*NOTREACHED*/
1045  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1046  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1047  return NULL;
1048 }
1049 FSTATIC gboolean
1050 _configcontext_JSON_parse_array(GScanner* scan, GSList** retval)
1051 {
1052  *retval = NULL;
1053  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_BRACE) {
1054  GULP;
1055  SYNERROR(scan, G_TOKEN_LEFT_BRACE, NULL, NULL);
1056  // Syntax error
1057  return FALSE;
1058  }
1059  GULP; // Swallow left square bracket (G_TOKEN_LEFT_BRACE)
1060  while (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE
1061  && !g_scanner_eof(scan)) {
1062  ConfigValue * value;
1063 
1064  // Parse the value
1065  value = _configcontext_JSON_parse_value(scan);
1066  if (value == NULL) {
1067  if (*retval != NULL) {
1069  *retval = NULL;
1070  return FALSE;
1071  }
1072  }else{
1073  *retval = g_slist_append(*retval, value);
1074  }
1075  // Expect a comma
1076  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
1077  GULP;
1078  }else if (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE) {
1079  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1080  GULP;
1081  return FALSE;
1082  }
1083  }
1084  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_BRACE) {
1085  GULP;
1086  return TRUE;
1087  }
1088  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1089  return FALSE;
1090 }
#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.
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.
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.