The Assimilation Project  based on Assimilation version 0.5.1441048221
 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);
73 FSTATIC char * JSONquotestring(char * s);
81 FSTATIC gboolean _configcontext_JSON_parse_array(GScanner* scan, GSList** retval);
83 FSTATIC void _configcontext_value_vfinalize(gpointer vself);
85 FSTATIC void _key_free(gpointer vself);
86 FSTATIC void _configcontext_JSON_errmsg(GScanner*, gchar*, gboolean);
87 
88 #ifdef BROKEN_G_SLIST_FREE_FULL
89 void assim_slist_free_full(GSList* list, void (*)(gpointer));
90 #endif
91 
101 #ifdef BROKEN_G_SLIST_FREE_FULL
102 void
103 assim_slist_free_full(GSList* list, void (*datafree)(gpointer))
104 {
105  GSList* this = NULL;
106  GSList* next = NULL;
107  //fprintf(stderr, "Freeing GSList at %p\n", list);
108 
109  for (this=list; this; this=next) {
110  next=this->next;
111  //fprintf(stderr, "........Freeing GSList data at %p\n", this->data);
112  if (this->data) {
113  datafree(this->data);
114  }else{
115  fprintf(stderr, "........NO GSList data (NULL) at %p\n"
116  , this->data);
117  }
118  //fprintf(stderr, "........Freeing GSList element at %p\n", this);
119  memset(this, 0, sizeof(*this));
120  g_slist_free_1(this);
121  }
122 }
123 #endif
124 
125 FSTATIC void
126 _key_free(gpointer vself)
127 {
128  //g_message("Freeing key pointer at %p\n", vself);
129  g_free(vself);
130 }
131 
132 
135 configcontext_new(gsize objsize)
136 {
137  AssimObj * baseobj = NULL;
138  ConfigContext * newcontext = NULL;
139 
140  if (objsize < sizeof(ConfigContext)) {
141  objsize = sizeof(ConfigContext);
142  }
143  baseobj = assimobj_new(objsize);
144  newcontext = NEWSUBCLASS(ConfigContext, baseobj);
145  newcontext->getint = _configcontext_getint;
146  newcontext->setdouble = _configcontext_setdouble;
147  newcontext->getdouble = _configcontext_getdouble;
148  newcontext->setint = _configcontext_setint;
149  newcontext->appendint = _configcontext_appendint;
150  newcontext->getbool = _configcontext_getbool;
151  newcontext->setbool = _configcontext_setbool;
153  newcontext->getstring = _configcontext_getstring;
154  newcontext->setstring = _configcontext_setstring;
156  newcontext->getframe = _configcontext_getframe;
157  newcontext->setframe = _configcontext_setframe;
158  newcontext->getaddr = _configcontext_getaddr;
159  newcontext->setaddr = _configcontext_setaddr;
161  newcontext->getconfig = _configcontext_getconfig;
162  newcontext->setconfig = _configcontext_setconfig;
164  newcontext->getarray = _configcontext_getarray;
165  newcontext->setarray = _configcontext_setarray;
166  newcontext->gettype = _configcontext_gettype;
167  newcontext->getvalue = _configcontext_getvalue;
168  newcontext->keys = _configcontext_keys;
169  newcontext->keycount = _configcontext_keycount;
170  newcontext->delkey = _configcontext_delkey;
171  newcontext->_values = g_hash_table_new_full(g_str_hash, g_str_equal, _key_free
175  return newcontext;
176 }
177 
179 FSTATIC void
181 {
182  ConfigContext* self = CASTTOCLASS(ConfigContext, aself);
183 #if 0
184  {
185  char * s = self->baseclass.toString(&self->baseclass);
186  g_warning("%s.%d: Finalizing %p: %s", __FUNCTION__, __LINE__, aself, s);
187  g_free(s); s = NULL;
188  }
189 #endif
190 
191  if (self->_values) {
192  g_hash_table_destroy(self->_values);
193  self->_values = NULL;
194  }
195  FREECLASSOBJ(self);
196 }
197 
199 FSTATIC gint
200 _configcontext_key_compare(gconstpointer a, gconstpointer b)
201 {
202  return strcmp((const char *)a, (const char*)b);
203 }
204 
206 FSTATIC void
207 _configcontext_delkey(const ConfigContext* cfg, const char * key)
208 {
209  g_hash_table_remove(cfg->_values, key);
210 }
212 FSTATIC guint
214 {
215  GHashTableIter iter;
216  gpointer key;
217  gpointer data;
218  guint ret = 0;
219 
220  g_hash_table_iter_init(&iter, cfg->_values);
221  while (g_hash_table_iter_next(&iter, &key, &data)) {
222  ++ret;
223  }
224  return ret;
225 }
226 
228 FSTATIC GSList*
230 {
231  GSList* keylist = NULL;
232  GHashTableIter iter;
233  gpointer key;
234  gpointer data;
235 
236  if (!cfg->_values) {
237  return NULL;
238  }
239 
240  g_hash_table_iter_init(&iter, cfg->_values);
241  while (g_hash_table_iter_next(&iter, &key, &data)) {
242  keylist = g_slist_prepend(keylist, key);
243  }
244  keylist= g_slist_sort(keylist, _configcontext_key_compare);
245  return keylist;
246 }
247 
248 
251 _configcontext_gettype(const ConfigContext* self, const char *name)
252 {
253  ConfigValue* cfg = self->getvalue(self, name);
254  if (cfg == NULL) {
255  return CFG_EEXIST;
256  }
257  return cfg->valtype;
258 }
259 
262 _configcontext_getvalue(const ConfigContext* self, const char *name)
263 {
264  gpointer ret = g_hash_table_lookup(self->_values, name);
265  if (ret != NULL) {
266  return CASTTOCLASS(ConfigValue, ret);
267  }
268  return NULL;
269 }
270 
272 FSTATIC gint64
274  , const char *name)
275 {
276  gpointer ret = g_hash_table_lookup(self->_values, name);
277  ConfigValue* cfg;
278 
279  if (ret == NULL) {
280  return -1;
281  }
282  cfg = CASTTOCLASS(ConfigValue, ret);
283  if (cfg->valtype != CFG_INT64) {
284  return -1;
285  }
286 
287  return cfg->u.intvalue;
288 }
289 
291 FSTATIC void
293  , const char *name
294  , gint value)
295 {
297  char * cpname = g_strdup(name);
298 
299  val->u.intvalue = value;
300  g_hash_table_replace(self->_values, cpname, val);
301 }
302 FSTATIC gboolean
303 _configcontext_appendint(ConfigContext*self, const char *name, gint value)
304 {
305  ConfigValue* array = self->getvalue(self, name);
306  ConfigValue* appendvalue;
307  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
308  appendvalue = _configcontext_value_new(CFG_INT64);
309  appendvalue->u.intvalue = value;
310  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
311  return TRUE;
312 }
313 FSTATIC double
315 {
316  ConfigValue* doubleval = self->getvalue(self, name);
317  // @TODO: Ought to return NaN (Not a Number) instead of -G_MAXDOUBLE on failure...
318  g_return_val_if_fail(doubleval != NULL && doubleval->valtype == CFG_FLOAT, -G_MAXDOUBLE);
319  return doubleval->u.floatvalue;
320 }
321 FSTATIC void
322 _configcontext_setdouble(ConfigContext*self, const char *name, double value)
323 {
325  doubleval->u.floatvalue = value;
326  g_hash_table_replace(self->_values, g_strdup(name), doubleval);
327 }
328 FSTATIC gboolean
329 _configcontext_appenddouble(ConfigContext*self, const char *name, double value)
330 {
331  ConfigValue* array = self->getvalue(self, name);
332  ConfigValue* appendvalue;
333  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
334  appendvalue = _configcontext_value_new(CFG_FLOAT);
335  appendvalue->u.floatvalue = value;
336  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
337  return TRUE;
338 }
339 
341 FSTATIC gboolean
343  , const char *name)
344 {
345  gpointer ret = g_hash_table_lookup(self->_values, name);
346  ConfigValue* cfg;
347 
348  if (ret == NULL) {
349  return -1;
350  }
351  cfg = CASTTOCLASS(ConfigValue, ret);
352  if (cfg->valtype != CFG_BOOL) {
353  return -1;
354  }
355 
356  return (gboolean)cfg->u.intvalue;
357 }
358 
360 FSTATIC void
362  , const char *name
363  , gint value)
364 {
366  char * cpname = g_strdup(name);
367 
368  val->u.intvalue = value;
369  g_hash_table_replace(self->_values, cpname, val);
370 }
371 
372 FSTATIC gboolean
373 _configcontext_appendbool(ConfigContext* self, const char *name, gboolean value)
374 {
375  ConfigValue* array = self->getvalue(self, name);
376  ConfigValue* appendvalue;
377  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
378  appendvalue = _configcontext_value_new(CFG_BOOL);
379  appendvalue->u.intvalue = value;
380  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
381  return TRUE;
382 }
383 
385 FSTATIC const char*
387  , const char *name)
388 {
389  gpointer ret = g_hash_table_lookup(self->_values, name);
390  ConfigValue* cfg;
391 
392  if (ret == NULL) {
393  return NULL;
394  }
395  cfg = CASTTOCLASS(ConfigValue, ret);
396  if (cfg->valtype != CFG_STRING) {
397  return NULL;
398  }
399  return cfg->u.strvalue;
400 }
401 
403 FSTATIC void
405  ,const char *name
406  ,const char *value)
407 {
409 
410  val->u.strvalue = g_strdup(value);
411  g_hash_table_replace(self->_values, g_strdup(name), val);
412 }
413 
414 FSTATIC gboolean
415 _configcontext_appendstring(ConfigContext* self, const char *name, const char *value)
416 {
417  ConfigValue* array = self->getvalue(self, name);
418  ConfigValue* appendvalue;
419  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
420  appendvalue = _configcontext_value_new(CFG_STRING);
421  appendvalue->u.strvalue = g_strdup(value);
422  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
423  return TRUE;
424 }
425 
426 FSTATIC GSList*
427 _configcontext_getarray(const ConfigContext* self, const char *name)
428 {
429  gpointer ret = g_hash_table_lookup(self->_values, name);
430  ConfigValue* cfg;
431 
432  if (ret == NULL) {
433  return NULL;
434  }
435  cfg = CASTTOCLASS(ConfigValue, ret);
436  if (cfg->valtype != CFG_ARRAY) {
437  g_warning("getarray called on object of type %d", cfg->valtype);
438  return NULL;
439  }
440  //g_warning("getarray[%s] on %s gives %p", name, self->baseclass.toString(self), cfg->u.arrayvalue);
441  return cfg->u.arrayvalue;
442 }
443 FSTATIC void
444 _configcontext_setarray(ConfigContext*self, const char *name, GSList*value)
445 {
446  char * cpname = g_strdup(name);
448  val->u.arrayvalue = value;
449 
451  g_hash_table_replace(self->_values, cpname, val);
452 }
453 
457  , const char *name)
458 {
459  gpointer ret = g_hash_table_lookup(self->_values, name);
460  ConfigValue* cfg;
461 
462  if (ret == NULL) {
463  return NULL;
464  }
465  cfg = CASTTOCLASS(ConfigValue, ret);
466  if (cfg->valtype != CFG_NETADDR) {
467  return NULL;
468  }
469  return cfg->u.addrvalue;
470 }
471 
473 FSTATIC void
475  , const char * name
476  , NetAddr* addr)
477 {
478  char * cpname = g_strdup(name);
480 
481  REF(addr);
482  val->u.addrvalue = addr;
483  g_hash_table_replace(self->_values, cpname, val);
484 }
485 
486 FSTATIC gboolean
488 {
489  ConfigValue* array = self->getvalue(self, name);
490  ConfigValue* appendvalue;
491  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
492  appendvalue = _configcontext_value_new(CFG_NETADDR);
493  REF(value);
494  appendvalue->u.addrvalue = value;
495  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
496  return TRUE;
497 }
498 
500 FSTATIC Frame*
502  , const char *name)
503 {
504  gpointer ret = g_hash_table_lookup(self->_values, name);
505  ConfigValue* cfg;
506 
507  if (ret == NULL) {
508  return NULL;
509  }
510  cfg = CASTTOCLASS(ConfigValue, ret);
511  if (cfg->valtype != CFG_FRAME) {
512  return NULL;
513  }
514  return cfg->u.framevalue;
515 }
516 
518 FSTATIC void
520  , const char * name
521  , Frame* frame)
522 {
524  char * cpname = g_strdup(name);
526 
527  REF(frame);
528  val->u.framevalue = frame;
529  g_hash_table_replace(self->_values, cpname, val);
530 }
531 
534 _configcontext_getconfig(const ConfigContext* self , const char* name)
535 {
536  gpointer ret = g_hash_table_lookup(self->_values, name);
537  ConfigValue* cfg;
538 
539  if (ret == NULL) {
540  return NULL;
541  }
542  cfg = CASTTOCLASS(ConfigValue, ret);
543  if (cfg->valtype != CFG_CFGCTX) {
544  return NULL;
545  }
546  return cfg->u.cfgctxvalue;
547 }
549 FSTATIC void
551 {
552  char * cpname = g_strdup(name);
554 
555  REF(value);
556  val->u.cfgctxvalue = value;
557  g_hash_table_replace(self->_values, cpname, val);
558 }
559 FSTATIC gboolean
561 {
562  ConfigValue* array = self->getvalue(self, name);
563  ConfigValue* appendvalue;
564  g_return_val_if_fail(array != NULL && array->valtype == CFG_ARRAY, FALSE);
565  appendvalue = _configcontext_value_new(CFG_CFGCTX);
566  REF(value);
567  appendvalue->u.cfgctxvalue = value;
568  array->u.arrayvalue = g_slist_append(array->u.arrayvalue, appendvalue);
569  return TRUE;
570 }
571 
573 FSTATIC char*
574 _configcontext_getstr(const ConfigContext* self , const char* name)
575 {
576  ConfigValue* cfval = self->getvalue(self, name);
577  if (cfval == NULL) {
578  return NULL;
579  }
580  return configcontext_elem_toString(cfval);
581 }
582 
586 {
587  AssimObj* aret;
588  ConfigValue* ret;
589 
590  aret = assimobj_new(sizeof(ConfigValue));
591  ret = NEWSUBCLASS(ConfigValue, aret);
592  ret->valtype = t;
593  memset(&ret->u, 0, sizeof(ret->u));
595  return ret;
596 }
597 
599 FSTATIC void
601 {
602  ConfigValue* self;
603  //fprintf(stderr, "configcontext_value_vfinalize(%p)\n", vself);
604  self = CASTTOCLASS(ConfigValue, vself);
605  UNREF(self);
606  vself = NULL;
607 }
608 FSTATIC void
610 {
611  ConfigValue* self;
612 
613  //fprintf(stderr, "configcontext_value_finalize(%p)\n", aself);
614  self = CASTTOCLASS(ConfigValue, aself);
615  //fprintf(stderr, "configcontext_value_finalize(%p): %d\n"
616  //, aself, self->valtype);
617  switch (self->valtype) {
618  case CFG_STRING:
619  g_free(self->u.strvalue); self->u.strvalue = NULL;
620  break;
621  case CFG_CFGCTX: {
622  UNREF(self->u.cfgctxvalue);
623  break;
624  }
625  case CFG_NETADDR: {
626  UNREF(self->u.addrvalue);
627  break;
628  }
629  case CFG_FRAME: {
630  UNREF(self->u.framevalue);
631  break;
632  }
633  case CFG_ARRAY: {
634  GSList* list = self->u.arrayvalue;
636  self->u.arrayvalue = NULL;
637  break;
638  }
639 
640  default: {
641  // Do nothing
642  break;
643  }
644  }
645  self->valtype = CFG_EEXIST;
646  memset(self, 0, sizeof(*self));
647  FREECLASSOBJ(self);
648  self = NULL;
649  aself = NULL;
650 }
651 
652 
653 #define JSONREPLACES "\\\"\b\f\n\r\t"
654 #define JSONREPLACEMENTS "\\\"bfnrt"
655 FSTATIC char *
658 {
659  GString* ret;
660  char * str;
661  const char * replacechars = JSONREPLACES;
662  ret = g_string_sized_new(strlen(s)+5);
663  g_string_append_c(ret, '"');
664 
665 
666  for (str=s; *str; ++str ) {
667  const char * found;
668  if (NULL != (found=strchr(replacechars, *str ))) {
669  size_t offset = found-replacechars;
670  g_string_append_c(ret, '\\');
671  g_string_append_c(ret, JSONREPLACEMENTS[offset]);
672  }else{
673  g_string_append_c(ret, *str);
674  }
675  }
676  g_string_append_c(ret, '"');
677  return g_string_free(ret, FALSE);
678 }
679 
681 FSTATIC char *
682 _configcontext_toString(gconstpointer aself)
683 {
684  const ConfigContext* self = CASTTOCONSTCLASS(ConfigContext, aself);
685 
686  GString* gsret = g_string_new("{");
687  GSList* keyelem;
688  GSList* nextkeyelem;
689  const char * comma = "";
690 
691  if (!self->_values) {
692  return NULL;
693  }
694  for (keyelem = self->keys(self); keyelem; keyelem = nextkeyelem) {
695  char * thiskey = keyelem->data;
696  ConfigValue* val = self->getvalue(self, thiskey);
697  gchar* elem = configcontext_elem_toString(val);
698  g_string_append_printf(gsret, "%s\"%s\":%s", comma, thiskey, elem);
699  g_free(elem);
700  comma=",";
701  nextkeyelem = keyelem->next;
702  g_slist_free1(keyelem);
703  keyelem = NULL;
704  }
705  g_string_append(gsret, "}");
706  return g_string_free(gsret, FALSE);
707 }
709 WINEXPORT char *
711 {
712  switch (val->valtype) {
713  case CFG_BOOL:
714  return g_strdup(val->u.intvalue? "true" : "false");
715 
716  case CFG_INT64:
717  return g_strdup_printf(FMT_64BIT"d", val->u.intvalue);
718 
719  case CFG_FLOAT:
720  return g_strdup_printf("%g", val->u.floatvalue);
721 
722  case CFG_STRING: {
723  //g_message("Got string pointer: %p", val->u.strvalue);
724  //g_message("Got string: %s", val->u.strvalue);
725  return JSONquotestring(val->u.strvalue);
726  }
727 
728  case CFG_CFGCTX: {
729  return val->u.cfgctxvalue->baseclass.toString(val->u.cfgctxvalue);
730  }
731  case CFG_ARRAY: {
732  const char * acomma = "";
733  GString* ret = g_string_new("[");
734  GSList* this;
735 
736  for (this = val->u.arrayvalue; this; this = this->next) {
737  ConfigValue* val = CASTTOCLASS(ConfigValue, this->data);
738  gchar* elem = configcontext_elem_toString(val);
739  g_string_append_printf(ret, "%s%s", acomma, elem);
740  g_free(elem);
741  acomma=",";
742  }
743  g_string_append(ret, "]");
744  return g_string_free(ret, FALSE);
745  }
746  case CFG_NETADDR: {
747  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.addrvalue);
750  char* tostring = obj->toString(obj);
751  gchar* retstr = JSONquotestring(tostring);
752  g_free(tostring); tostring = NULL;
753  return retstr;
754  }
755  case CFG_FRAME: {
756  AssimObj* obj = CASTTOCLASS(AssimObj, val->u.framevalue);
757  char* tostring = obj->toString(obj);
758  gchar* retstr = JSONquotestring(tostring);
759 
760  FREE(tostring); tostring=NULL;
761  return retstr;
762  }
763  case CFG_EEXIST:
764  case CFG_NULL:
765  return g_strdup("null");
766 
767  }//endswitch
768  /*NOTREACHED*/
769  return g_strdup("null");
770 }
773 FSTATIC void
774 _configcontext_JSON_errmsg(GScanner* _unused_scanner, gchar*message, gboolean _unused_isError)
775 {
776  (void)_unused_scanner;
777  (void)_unused_isError;
778  g_warning("%s.%d: JSON syntax error: %s", __FUNCTION__, __LINE__, message);
779 }
780 
785 FSTATIC GScanner*
787 {
788  static GScannerConfig config;
789  GScanner* retval;
790  // Legal JSON keywords are true, false, and null
791  // There are no 'identifiers' as such.
792  static char firstchars[] = "tfn";
793  static char subsequentchars[] = "aelrsu";
794  static char whitespace[] = " \t\n\r\f";
795  static char hash_comment[] = "#\n";
796  static char True[] = "true";
797  static char False[] = "false";
798  static char Null[] = "null";
799  memset(&config, 0, sizeof(config));
800 
801  // For more info on what these settings do, see
802  // http://developer.gnome.org/glib/2.32/glib-Lexical-Scanner.html
803 
804  config.cset_skip_characters = whitespace;
805  config.cset_identifier_first = firstchars;
806  config.cset_identifier_nth = subsequentchars;
807  config.case_sensitive = TRUE;
808  config.skip_comment_multi = FALSE;
809  config.scan_comment_multi = FALSE;
810  config.cpair_comment_single = hash_comment; // NOTE: JSON extension: Allow # comments
811  config.skip_comment_single = TRUE; // Ignore # comments
812  config.scan_identifier = TRUE;
813  config.scan_identifier_1char = FALSE;
814  config.scan_identifier_NULL = FALSE;
815  config.scan_symbols = TRUE; // ???
816  config.scan_binary = FALSE;
817  config.scan_octal = FALSE;
818  config.scan_float = TRUE;
819  config.scan_hex = FALSE;
820  config.scan_hex_dollar = FALSE;
821  config.scan_string_sq = FALSE;
822  config.scan_string_dq = TRUE;
823  config.numbers_2_int = TRUE;
824  config.int_2_float = FALSE;
825  config.identifier_2_string = FALSE;
826  config.char_2_token = TRUE;
827  config.symbol_2_token = FALSE; // ???
828  config.scope_0_fallback = TRUE;
829  config.store_int64 = TRUE;
830 
831  retval = g_scanner_new(&config);
832  if (retval) {
833  g_scanner_scope_add_symbol(retval, 0, True, True);
834  g_scanner_scope_add_symbol(retval, 0, False, False);
835  g_scanner_scope_add_symbol(retval, 0, Null, Null);
836  retval->msg_handler = _configcontext_JSON_errmsg;
837  }
838  return retval;
839 }
840 
841 #define TOKEN_COLON ':'
842 #define GULP (void)g_scanner_get_next_token(scan)
843 
844 #define SYNERROR(scan, token, symbol, msg) \
845  {g_warning("%s.%d: JSON syntax error.", __FUNCTION__, __LINE__);g_scanner_unexp_token(scan, token, "keyword", "keyword", symbol, msg, TRUE);}
846 
849 configcontext_new_JSON_string(const char * jsontext)
850 {
851  GScanner* scanner = _configcontext_JSON_GScanner_new();
852  ConfigContext* ret;
853 
854  g_scanner_input_text(scanner, jsontext, strlen(jsontext));
856  g_scanner_destroy(scanner);
857  return ret;
858 }
859 
863 {
865 
866  if (ret != NULL && g_scanner_get_next_token(scan) != G_TOKEN_EOF) {
867  SYNERROR(scan, G_TOKEN_EOF, NULL, NULL);
868  UNREF(ret);
869  }
870  return ret;
871 }
872 
876 {
877  ConfigContext* ret;
878  ConfigContext* membersret;
879  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_CURLY) {
880  GULP;
881  SYNERROR(scan, G_TOKEN_LEFT_CURLY, NULL, NULL);
882  return NULL;
883  }
884  GULP; // Swallow '{'
885  ret = configcontext_new(0);
886  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_CURLY) {
887  // Empty 'object' - which is just fine...
888  GULP;
889  return ret;
890  }
891 
892  membersret = _configcontext_JSON_parse_members(scan, ret);
893  if (membersret == NULL) {
894  UNREF(ret);
895  return NULL;
896  }
897 
898  if (g_scanner_get_next_token(scan) != G_TOKEN_RIGHT_CURLY) {
899  // Syntax error...
900  SYNERROR(scan, G_TOKEN_RIGHT_CURLY, NULL, NULL);
901  UNREF(ret);
902  return NULL;
903  }
904  return ret;
905 }
909 {
910  while (g_scanner_peek_next_token(scan) == G_TOKEN_STRING) {
912  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
913  GULP;
914  }else{
915  break;
916  }
917  }
918  return cfg;
919 }
920 
921 // Parse a JSON "name": value pair
924 {
925  char * name = NULL;
926  ConfigValue* value;
927  // "name" : _value_ pairs
928  //
929  // Name is always a string -
930  // Value can be any of:
931  // string
932  // number
933  // object
934  // array
935  // true (a symbol)
936  // false (a symbol)
937  // null (a symbol)
938  if (g_scanner_peek_next_token(scan) != G_TOKEN_STRING) {
939  return NULL;
940  }
941  GULP;
942  // Get value of G_TOKEN_STRING
943  name = g_strdup(scan->value.v_string);
944  if (g_scanner_peek_next_token(scan) != TOKEN_COLON) {
945  SYNERROR(scan, TOKEN_COLON, NULL, NULL);
946  // Syntax error
947  g_free(name); name = NULL;
948  return NULL;
949  }
950  GULP; // Swallow TOKEN_COLON
951  if (g_scanner_peek_next_token(scan) == TOKEN_COLON) {
952  return NULL;
953  }
954  // Next is a value...
955  value = _configcontext_JSON_parse_value(scan);
956  if (value == NULL) {
957  // Syntax error - already noted by the lower layers...
958  g_free(name); name = NULL;
959  return NULL;
960  }
961  g_hash_table_replace(cfg->_values, name, value);
962  return cfg;
963 }
964 
967 {
968  guint toktype = g_scanner_peek_next_token(scan);
969  switch(toktype) {
970  case G_TOKEN_STRING:{ // String
972  ConfigValue* val;
973  NetAddr* encoded;
974  GULP;
975  // See if we can convert it to a NetAddr...
977  if ((encoded = netaddr_string_new(scan->value.v_string)) != NULL) {
979  val->u.addrvalue = encoded;
980  encoded = NULL;
981  }else{
983  val->u.strvalue = g_strdup(scan->value.v_string);
984  }
985  return val;
986  }
987 
988  case '-': { // Minus sign (negative number)
989  ConfigValue* val;
990  GULP; // Throw away the negative sign
991  toktype = g_scanner_peek_next_token(scan);
992  if (toktype == G_TOKEN_INT) {
994  GULP;
995  val->u.intvalue = -scan->value.v_int64;
996  return val;
997  }else if (toktype == G_TOKEN_FLOAT) {
999  GULP;
1000  val->u.floatvalue = -scan->value.v_float;
1001  return val;
1002  }else{
1003  g_warning("Got token type %u after -", g_scanner_get_next_token(scan));
1004  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol after -.");
1005  return NULL;
1006  }
1007  return val;
1008  }
1009  break;
1010 
1011  case G_TOKEN_INT: { // Integer
1013  GULP;
1014  val->u.intvalue = scan->value.v_int64;
1015  return val;
1016  }
1017  break;
1018 
1019  case G_TOKEN_FLOAT: { // Double value
1021  GULP;
1022  val->u.floatvalue = scan->value.v_float;
1023  return val;
1024  }
1025  break;
1026 
1027  case G_TOKEN_SYMBOL: { // true, false, null
1028  GULP;
1029  if (strcmp(scan->value.v_string, "true") == 0 || strcmp(scan->value.v_string, "false") == 0) {
1031  val->u.intvalue = (strcmp(scan->value.v_string, "true") == 0);
1032  return val;
1033  }else if (strcmp(scan->value.v_string, "null") == 0) {
1035  }else{
1036  SYNERROR(scan, G_TOKEN_NONE, NULL, "- expecting JSON value");
1037  // Syntax error
1038  return NULL;
1039  }
1040  }
1041  break;
1042 
1043 
1044  case G_TOKEN_LEFT_CURLY:{ // Object
1045  ConfigValue* val;
1046  ConfigContext* child;
1047  child = _configcontext_JSON_parse_object(scan);
1048  if (child == NULL) {
1049  // Syntax error - detected by child object
1050  return NULL;
1051  }
1053  val->u.cfgctxvalue = child;
1054  return val;
1055  }
1056  break;
1057 
1058 
1059  case G_TOKEN_LEFT_BRACE: { // Array
1060  ConfigValue* val;
1061  GSList* child = NULL;
1062  if (!_configcontext_JSON_parse_array(scan, &child)) {
1063  // Syntax error - detected by child object
1064  return NULL;
1065  }
1067  val->u.arrayvalue = child;
1068  return val;
1069  }
1070  break;
1071 
1072  // Things we don't support...
1073  default:
1074  // Syntax error
1075  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1076  //GULP;
1077  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1078  return NULL;
1079  }
1080  /*NOTREACHED*/
1081  g_warning("Got token type %u", g_scanner_get_next_token(scan));
1082  SYNERROR(scan, G_TOKEN_NONE, NULL, "Unexpected symbol.");
1083  return NULL;
1084 }
1085 FSTATIC gboolean
1086 _configcontext_JSON_parse_array(GScanner* scan, GSList** retval)
1087 {
1088  *retval = NULL;
1089  if (g_scanner_peek_next_token(scan) != G_TOKEN_LEFT_BRACE) {
1090  GULP;
1091  SYNERROR(scan, G_TOKEN_LEFT_BRACE, NULL, NULL);
1092  // Syntax error
1093  return FALSE;
1094  }
1095  GULP; // Swallow left square bracket (G_TOKEN_LEFT_BRACE)
1096  while (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE
1097  && !g_scanner_eof(scan)) {
1098  ConfigValue * value;
1099 
1100  // Parse the value
1101  value = _configcontext_JSON_parse_value(scan);
1102  if (value == NULL) {
1103  if (*retval != NULL) {
1105  *retval = NULL;
1106  return FALSE;
1107  }
1108  }else{
1109  *retval = g_slist_append(*retval, value);
1110  }
1111  // Expect a comma
1112  if (g_scanner_peek_next_token(scan) == G_TOKEN_COMMA) {
1113  GULP;
1114  }else if (g_scanner_peek_next_token(scan) != G_TOKEN_RIGHT_BRACE) {
1115  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1116  GULP;
1117  return FALSE;
1118  }
1119  }
1120  if (g_scanner_peek_next_token(scan) == G_TOKEN_RIGHT_BRACE) {
1121  GULP;
1122  return TRUE;
1123  }
1124  SYNERROR(scan, G_TOKEN_RIGHT_BRACE, NULL, NULL);
1125  return FALSE;
1126 }
#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 void _configcontext_JSON_errmsg(GScanner *, gchar *, gboolean)
Output a scanning error message for our JSON parsing.
double(* getdouble)(const ConfigContext *, const char *name)
Get double value.
Definition: configcontext.h:80
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 WINEXPORT
Definition: projectcommon.h:45
#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.
WINEXPORT char * configcontext_elem_toString(ConfigValue *val)
Convert a ConfigContext element (ConfigValue) to a String.
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.