#include #include "cdo_int.h" #include "pmlist.h" #include "json/jsmn.h" static char *readLineFromBuffer(char *buffer, size_t *buffersize, char *line, size_t len) { int ichar; size_t ipos = 0; while ( *buffersize ) { ichar = *buffer; (*buffersize)--; buffer++; if ( ichar == '\r' ) { if ( *buffersize ) { ichar = *buffer; if ( ichar == '\n' ) { (*buffersize)--; buffer++; } } break; } if ( ichar == '\n' ) break; line[ipos++] = ichar; if ( ipos >= len ) { fprintf(stderr, "readLineFromBuffer: end of line not found (maxlen = %zu)!\n", len); break; } } line[ipos] = 0; if ( *buffersize == 0 && ipos == 0 ) buffer = NULL; return buffer; } static char *skipSeparator(char *pline) { while ( isspace((int) *pline) ) pline++; if ( *pline == '=' || *pline == ':' ) pline++; while ( isspace((int) *pline) ) pline++; return pline; } static char *getElementName(char *pline, char *name) { while ( isspace((int) *pline) ) pline++; size_t len = strlen(pline); size_t pos = 0; while ( pos < len && !isspace((int) *(pline+pos)) && *(pline+pos) != '=' && *(pline+pos) != ':' ) pos++; strncpy(name, pline, pos); name[pos] = 0; pline += pos; return pline; } static char *getElementValue(char *pline) { while ( isspace((int) *pline) ) pline++; size_t len = strlen(pline); if ( *pline != '"' && *pline != '\'' ) for ( size_t i = 1; i < len; ++i ) if ( pline[i] == '!' ) { pline[i] = 0; len = i; break; } while ( isspace((int) *(pline+len-1)) && len ) { *(pline+len-1) = 0; len--; } return pline; } void cmortablebuf_to_pmlist(list_t *pmlist, size_t buffersize, char *buffer) { char line[4096]; char name[256]; char *pline; const char *listentry[] = {"axis_entry", "variable_entry"}; int nentry = sizeof(listentry)/sizeof(listentry[0]); int linenumber = 0; list_t *kvlist = NULL; while ( (buffer = readLineFromBuffer(buffer, &buffersize, line, sizeof(line))) ) { linenumber++; pline = line; while ( isspace((int) *pline) ) pline++; if ( *pline == '#' || *pline == '!' || *pline == '\0' ) continue; // len = (int) strlen(pline); int ientry = -1; for ( ientry = 0; ientry < nentry; ++ientry ) if ( strncmp(pline, listentry[ientry], strlen(listentry[ientry])) == 0 ) break; if ( ientry < nentry ) { pline += strlen(listentry[ientry]); kvlist = kvlist_new(listentry[ientry]); list_append(pmlist, &kvlist); pline = skipSeparator(pline); pline = getElementValue(pline); if ( *pline ) kvlist_append(kvlist, "name", (const char **)&pline, 1); } else { pline = getElementName(pline, name); pline = skipSeparator(pline); pline = getElementValue(pline); if ( kvlist == NULL ) { kvlist = kvlist_new("Header"); list_append(pmlist, &kvlist); } if ( *pline ) kvlist_append(kvlist, name, (const char **)&pline, 1); } } } // not used int dump_json(const char *js, jsmntok_t *t, size_t count, int level) { int i, j, k; if (count == 0) return 0; if (t->type == JSMN_PRIMITIVE) { printf("%.*s", t->end - t->start, js+t->start); return 1; } else if (t->type == JSMN_STRING) { printf("'%.*s'", t->end - t->start, js+t->start); return 1; } else if (t->type == JSMN_OBJECT) { printf("\n"); // printf("Object: size %d\n", t->size); printf("Object: size %d count %d level %d\n", t->size, (int)count, level); j = 0; for (i = 0; i < t->size; i++) { for (k = 0; k < level; k++) printf(" "); j += dump_json(js, t+1+j, count-j, level+1); printf(": "); j += dump_json(js, t+1+j, count-j, level+1); printf("\n"); } return j+1; } else if (t->type == JSMN_ARRAY) { j = 0; printf("\n"); for (i = 0; i < t->size; i++) { for (k = 0; k < level-1; k++) printf(" "); printf(" - "); j += dump_json(js, t+1+j, count-j, level+1); printf("\n"); } return j+1; } return 0; } static void kvlist_append_json(list_t *kvlist, const char *key, const char *js, jsmntok_t *t, int nvalues) { keyValues_t *keyval = (keyValues_t *) malloc(sizeof(keyValues_t)); keyval->key = strdup(key); keyval->nvalues = nvalues; keyval->values = (char **) malloc(nvalues*sizeof(char*)); for ( int i = 0; i < nvalues; ++i ) { size_t len = t[i].end - t[i].start; char *value = (char*) malloc((len+1)*sizeof(char)); snprintf(value, len+1, "%.*s", (int)len, js+t[i].start); value[len] = 0; // printf("set %s: '%s'\n", key, value); keyval->values[i] = value; } list_append(kvlist, &keyval); } static int json_to_pmlist(list_t *pmlist, const char *js, jsmntok_t *t, int count) { bool debug = false; char name[4096]; int i = 0; int nobj = t[0].size; if ( t[0].type == JSMN_OBJECT ) while ( nobj-- ) { ++i; int pmlname = i; if ( debug ) printf(" object: %.*s\n", t[i].end - t[i].start, js+t[i].start); ++i; if ( t[i].type == JSMN_OBJECT ) { int ic = 0; NEXT: snprintf(name, sizeof(name), "%.*s", t[pmlname].end - t[pmlname].start, js+t[pmlname].start); name[sizeof(name)-1] = 0; // printf("new object: %s\n", name); list_t *kvlist = kvlist_new(name); list_append(pmlist, &kvlist); if ( t[i+2].type == JSMN_OBJECT ) { if ( ic == 0 ) ic = t[i].size; else ic--; ++i; kvlist_append_json(kvlist, "name", js, &t[i], 1); if ( debug ) printf(" name: '%.*s'\n", t[i].end - t[i].start, js+t[i].start); ++i; } int n = t[i].size; while ( n-- ) { ++i; snprintf(name, sizeof(name), "%.*s", t[i].end - t[i].start, js+t[i].start); name[sizeof(name)-1] = 0; if ( debug ) printf(" %.*s:", t[i].end - t[i].start, js+t[i].start); ++i; if ( t[i].type == JSMN_ARRAY ) { int nae = t[i].size; kvlist_append_json(kvlist, name, js, &t[i+1], nae); while ( nae-- ) { ++i; if ( debug ) printf(" '%.*s'", t[i].end - t[i].start, js+t[i].start); } } else { kvlist_append_json(kvlist, name, js, &t[i], 1); if ( debug ) printf(" '%.*s'", t[i].end - t[i].start, js+t[i].start); } if ( debug ) printf("\n"); } if ( ic > 1 ) goto NEXT; } } if ( debug ) printf("Processed %d of %d tokens!\n", i, count-1); return 0; } void cmortablebuf_to_pmlist_json(list_t *pmlist, size_t buffersize, char *buffer, const char *filename) { /* Prepare parser */ jsmn_parser *p = jsmn_new(); int status = jsmn_parse(p, buffer, buffersize); if ( status != 0 ) { switch (status) { case JSMN_ERROR_INVAL: fprintf(stderr, "JSON error: Invalid character in %s (line=%d character='%c')!\n", filename, p->lineno, buffer[p->pos]); break; case JSMN_ERROR_PART: fprintf(stderr, "JSON error: End of string not found in %s (line=%d)!\n", filename, p->lineno); break; default: fprintf(stderr, "JSON error in %s (line=%d)\n", filename, p->lineno); break; } } json_to_pmlist(pmlist, buffer, p->tokens, (int)p->toknext); jsmn_destroy(p); } list_t *cmortable_to_pmlist(FILE *fp, const char *name) { listbuf_t *listbuf = listbuf_new(); if ( listbuf_read(listbuf, fp, name) ) cdoAbort("Read error on CMOR table %s!", name); list_t *pmlist = NULL; if ( listbuf->buffer[0] == '{' ) { pmlist = list_new(sizeof(list_t *), free_kvlist, name); cmortablebuf_to_pmlist_json(pmlist, listbuf->size, listbuf->buffer, name); } else if ( strncmp(listbuf->buffer, "table_id:", 9) == 0 ) { pmlist = list_new(sizeof(list_t *), free_kvlist, name); cmortablebuf_to_pmlist(pmlist, listbuf->size, listbuf->buffer); } else if ( listbuf->buffer[0] == '&' || listbuf->buffer[0] == '#' ) { pmlist = namelistbuf_to_pmlist(listbuf); } else cdoAbort("Invalid CMOR table (file: %s)!", name); listbuf_destroy(listbuf); return pmlist; }