/** # Parser for interactive bview */ enum ParamsType { pstring, pint, punsigned, pbool, pfloat, pdouble, pcolormap }; typedef struct { char * key; enum ParamsType type; void * val; int n; } Params; static bool atobool (char * s) { if (!strcmp (s, "true")) return true; if (!strcmp (s, "false")) return false; return atoi (s) != 0; } static bool args (Params * p, char * val) { static char * name[] = { "string", "int", "unsigned", "bool", "float", "double", "colormap" }; switch (p->type) { case pstring: if (val[0] != '"') { fprintf (stderr, "expecting a string for '%s' got '%s'\n", p->key, val); return false; } if (val[strlen(val) - 1] != '"') { fprintf (stderr, "unterminated quoted string '%s'\n", val); return false; } val[strlen(val) - 1] = '\0'; char * s = &val[1]; int nc = 0; // number of non-blank characters while (*s != '\0') { if (!strchr (" \t\n\r", *s)) nc++; s++; } *((char **)p->val) = nc > 0 ? &val[1] : NULL; break; case pcolormap: if (!strcmp (val, "jet")) *((Colormap *)p->val) = jet; else if (!strcmp (val, "cool_warm")) *((Colormap *)p->val) = cool_warm; else if (!strcmp (val, "gray")) *((Colormap *)p->val) = gray; else if (!strcmp (val, "randomap")) *((Colormap *)p->val) = randomap; else { fprintf (stderr, "unknown colormap '%s'\n", val); return false; } break; case pint: case punsigned: case pbool: case pdouble: case pfloat: if (val[0] == '"') { fprintf (stderr, "expecting a %s for '%s' got %s\n", name[p->type], p->key, val); return false; } if (!p->n) { switch (p->type) { case pint: *((int *)p->val) = atoi(val); break; case punsigned: *((unsigned *)p->val) = atoi(val); break; case pbool: *((bool *)p->val) = atobool(val); break; case pfloat: *((float *)p->val) = atof(val); break; case pdouble: *((double *)p->val) = atof(val); break; default: assert (false); } } else { if (val[0] != '{') { fprintf (stderr, "expecting an array for '%s' got %s\n", p->key, val); return false; } val++; int i = 0; char c = ','; while (i < p->n && c != '}') { char * s = strchr (val, ','); if (!s) s = strchr (val, '}'); if (!s) { fprintf (stderr, "expecting an array for '%s' got %s\n", p->key, val); return false; } c = *s; *s++ = '\0'; switch (p->type) { case pint: ((int *)p->val)[i++] = atoi (val); break; case punsigned: ((unsigned *)p->val)[i++] = atoi (val); break; case pbool: ((bool *)p->val)[i++] = atobool (val); break; case pfloat: ((float *)p->val)[i++] = atof (val); break; case pdouble: ((double *)p->val)[i++] = atof (val); break; default: assert (false); } val = s; } if (c != '}') { fprintf (stderr, "expecting '}' for '%s' got %s\n", p->key, val); return false; } } break; default: assert (false); } return true; } static char * find_comma (char * s) { int par = 0; while (*s != '\0') { if (*s == ',' && par == 0) { *s = '\0'; return s + 1; } if (*s == '{') par++; else if (*s == '}') par--; s++; } return NULL; } static char * mystrtok (char * str, const char * delim) { static char * s = NULL; char * start = str ? str : s; bool string = false; s = start; while (*s != '\0') { if (*s == '"') string = !string; if (!string && strchr(delim, *s)) break; s++; } if (*s != '\0') *s++ = '\0'; return start; } int parse_params (Params * params) { char * s; int i = 0, n = 0; Params * p = params; while (p->key) p++, n++; if (!(s = mystrtok (NULL, ");")) || s[0] == '\n') return false; while (s && *s != '\0') { char * next = find_comma (s), * key = s; if ((s = strchr (key, '='))) { s[0] = '\0', s++; i = -1; Params * p = params; while (p->key && strcmp(p->key, key)) p++; if (!p->key) { fprintf (stderr, "unknown key '%s'\n", key); return false; } if (!args (p, s)) return false; } else { if (i < 0) { fprintf (stderr, "anonymous value '%s' after keys\n", key); return false; } if (i >= n) { fprintf (stderr, "too many parameters: '%s' %d %d\n", key, i, n); return false; } if (!args (¶ms[i], key)) return false; i++; } s = next; } return true; }