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