/*      $NetBSD: jsondump.c,v 1.2 2020/05/25 20:47:24 christos Exp $    */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "../jsmn.h"

/*
* An example of reading JSON from stdin and printing its content to stdout.
* The output looks like YAML, but I'm not sure if it's really compatible.
*/

static int dump(const char *js, jsmntok_t *t, size_t count, int indent) {
       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");
               j = 0;
               for (i = 0; i < t->size; i++) {
                       for (k = 0; k < indent; k++) printf("  ");
                       j += dump(js, t+1+j, count-j, indent+1);
                       printf(": ");
                       j += dump(js, t+1+j, count-j, indent+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 < indent-1; k++) printf("  ");
                       printf("   - ");
                       j += dump(js, t+1+j, count-j, indent+1);
                       printf("\n");
               }
               return j+1;
       }
       return 0;
}

int main() {
       int r;
       int eof_expected = 0;
       char *js = NULL;
       size_t jslen = 0;
       char buf[BUFSIZ];

       jsmn_parser p;
       jsmntok_t *tok;
       size_t tokcount = 2;

       /* Prepare parser */
       jsmn_init(&p);

       /* Allocate some tokens as a start */
       tok = malloc(sizeof(*tok) * tokcount);
       if (tok == NULL) {
               fprintf(stderr, "malloc(): errno=%d\n", errno);
               return 3;
       }

       for (;;) {
               /* Read another chunk */
               r = fread(buf, 1, sizeof(buf), stdin);
               if (r < 0) {
                       fprintf(stderr, "fread(): %d, errno=%d\n", r, errno);
                       return 1;
               }
               if (r == 0) {
                       if (eof_expected != 0) {
                               return 0;
                       } else {
                               fprintf(stderr, "fread(): unexpected EOF\n");
                               return 2;
                       }
               }

               js = realloc(js, jslen + r + 1);
               if (js == NULL) {
                       fprintf(stderr, "realloc(): errno=%d\n", errno);
                       return 3;
               }
               strncpy(js + jslen, buf, r);
               jslen = jslen + r;

again:
               r = jsmn_parse(&p, js, jslen, tok, tokcount);
               if (r < 0) {
                       if (r == JSMN_ERROR_NOMEM) {
                               tokcount = tokcount * 2;
                               tok = realloc(tok, sizeof(*tok) * tokcount);
                               if (tok == NULL) {
                                       fprintf(stderr, "realloc(): errno=%d\n", errno);
                                       return 3;
                               }
                               goto again;
                       }
               } else {
                       dump(js, tok, p.toknext, 0);
                       eof_expected = 1;
               }
       }

       return 0;
}