GAME: Play the number guessing game -> PLAY NOW

libjson.c - libjson - A simple JSON parser

libjson

A simple JSON parser
git clone git@soophie.de:/srv/git/libjson
log | files | refs | readme

libjson.c (5744B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <stdbool.h>
      4 #include <string.h>
      5 #include <ctype.h>
      6 #include <inttypes.h>
      7 
      8 #include "libjson.h"
      9 
     10 char *json_str(json_ptr_t json_ptr) {
     11   jsmntok_t token = json_ptr.tokens[json_ptr.ptr];
     12   int token_len = token.end - token.start;
     13   char *str = malloc(token_len + 1);
     14   memcpy(str, json_ptr.str + token.start, token_len);
     15   str[token_len] = '\0';
     16   return str;
     17 }
     18 
     19 json_ptr_t json_ptr(jsmntok_t *tokens, int len, const char *str) {
     20   return (json_ptr_t) {
     21     .tokens = tokens,
     22     .len = len,
     23     .ptr = 0,
     24     .str = str,
     25     .err = JSON_OK,
     26   };
     27 }
     28 
     29 json_ptr_t json_err(json_ptr_t json_ptr, json_err_t json_err) {
     30   json_ptr.err = json_err;
     31   return json_ptr;
     32 }
     33 
     34 int json_size(json_ptr_t json_ptr) {
     35   return json_ptr.tokens[json_ptr.ptr].size;
     36 }
     37 
     38 json_ptr_t json_parse(jsmntok_t tokens[], int tokens_len, const char *str) {
     39   jsmn_parser parser;
     40   jsmn_init(&parser);
     41   int len = jsmn_parse(&parser, str, strlen(str), tokens, tokens_len);
     42   json_ptr_t ptr = json_ptr(tokens, len, str);
     43   if (len < 0) {
     44     return json_err(ptr, JSON_ERR_INVALID_FORMAT);
     45   }
     46   return ptr;
     47 }
     48 
     49 /**
     50   Increments the `jsmntok_t` pointer until the child `JSMN_OBJECT` or
     51   `JSMN_ARRAY` is traversed and the pointer points to the next entry.
     52   If no errors occured, the return code is `0`.
     53 */
     54 void json_seek(json_ptr_t *json_ptr) {
     55   jsmntok_t token_root = json_ptr->tokens[json_ptr->ptr];
     56   if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {
     57     json_err(*json_ptr, JSON_ERR_INVALID_TYPE);
     58     return;
     59   }
     60   jsmntok_t token;
     61   for (int i = 0; i < token_root.size; i++) {
     62     if (token_root.type == JSMN_OBJECT) {
     63       token = json_ptr->tokens[++json_ptr->ptr]; // key
     64     }
     65     token = json_ptr->tokens[++json_ptr->ptr]; // value
     66     if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {
     67       json_seek(json_ptr);
     68       if (json_ptr->err) {
     69         return;
     70       }
     71     }
     72   }
     73 }
     74 
     75 json_ptr_t json_get(json_ptr_t json_ptr, const char *key) {
     76   jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];
     77   if (token_root.type != JSMN_OBJECT) {
     78     return json_err(json_ptr, JSON_ERR_INVALID_TYPE);
     79   }
     80   jsmntok_t token;
     81   int token_len;
     82   while (json_ptr.ptr < json_ptr.len) {
     83     token = json_ptr.tokens[++json_ptr.ptr]; // key
     84     token_len = token.end - token.start;
     85     char token_key[token_len + 1];
     86     memcpy(token_key, json_ptr.str + token.start, token_len);
     87     token_key[token_len] = '\0';
     88     if (strncmp(json_ptr.str + token.start, key, token_len) == 0) {
     89       json_ptr.ptr++;
     90       return json_ptr;
     91     }
     92     token = json_ptr.tokens[++json_ptr.ptr]; // value
     93     if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {
     94       json_seek(&json_ptr);
     95       if (json_ptr.err) {
     96         return json_ptr;
     97       }
     98     }
     99   }
    100   return json_err(json_ptr, JSON_ERR_INVALID_MISSING);
    101 }
    102 
    103 json_ptr_t json_at(json_ptr_t json_ptr, int idx) {
    104   jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];
    105   if (token_root.type != JSMN_ARRAY) {
    106     return json_err(json_ptr, JSON_ERR_INVALID_TYPE);
    107   }
    108   if (idx >= token_root.size) {
    109     return json_err(json_ptr, JSON_ERR_INVALID_SIZE);
    110   }
    111   jsmntok_t token;
    112   int token_idx = 0;
    113   while (json_ptr.ptr < json_ptr.len) {
    114     token = json_ptr.tokens[++json_ptr.ptr];
    115     if (token_idx == idx) {
    116       return json_ptr;
    117     }
    118     if (token.type == JSMN_OBJECT || token.type == JSMN_ARRAY) {
    119       json_seek(&json_ptr);
    120       if (json_ptr.err) {
    121         return json_ptr;
    122       }
    123     }
    124     token_idx++;
    125   }
    126   return json_err(json_ptr, JSON_ERR_INVALID_MISSING);
    127 }
    128 
    129 json_ptr_t json_query(json_ptr_t json_ptr, const char *query) {
    130   jsmntok_t token_root = json_ptr.tokens[json_ptr.ptr];
    131   if (token_root.type != JSMN_OBJECT && token_root.type != JSMN_ARRAY) {
    132     return json_err(json_ptr, JSON_ERR_INVALID_TYPE);
    133   }
    134   jsmntok_t token;
    135   int i = 0;
    136   int query_len = strlen(query);
    137   while (i < query_len) {
    138     token = json_ptr.tokens[json_ptr.ptr];
    139     char c = query[i];
    140     if (c == '.') {
    141       if (token.type != JSMN_OBJECT) {
    142         return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_OBJECT
    143       }
    144       i++;
    145       int j = i;
    146       bool found = false;
    147       for (; j < query_len; j++) {
    148         if (!isalpha(query[j])) {
    149           int key_len = j - i;
    150           if (key_len == 0) {
    151             return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);
    152           }
    153           char key[key_len + 1];
    154           memcpy(key, query + i, key_len);
    155           key[key_len] = '\0';
    156           json_ptr = json_get(json_ptr, key);
    157           i += key_len;
    158           found = true;
    159           break;
    160         }
    161       }
    162       if (!found) {
    163         int key_len = j - i;
    164         if (key_len == 0) {
    165           return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);
    166         }
    167         char key[key_len + 1];
    168         memcpy(key, query + i, key_len);
    169         key[key_len] = '\0';
    170         json_ptr = json_get(json_ptr, key);
    171         i += key_len;
    172       }
    173       continue;
    174     }
    175     if (c == '[') {
    176       if (token.type != JSMN_ARRAY) {
    177         return json_err(json_ptr, JSON_ERR_INVALID_TYPE); // expected JSMN_ARRAY
    178       }
    179       i++;
    180       for (int j = i; j < query_len; j++) {
    181         if (query[j] == ']') {
    182           int idx_len = j - i;
    183           if (idx_len == 0) {
    184             return json_err(json_ptr, JSON_ERR_INVALID_FORMAT);
    185           }
    186           char idx[idx_len + 1];
    187           memcpy(idx, query + i, idx_len);
    188           idx[idx_len] = '\0';
    189           int index = strtoimax(idx, NULL, 10);
    190           json_ptr = json_at(json_ptr, index);
    191           i += idx_len + 1;
    192           break;
    193         }
    194       }
    195       continue;
    196     }
    197     if (!isalpha(c)) {
    198       return json_err(json_ptr, JSON_ERR_INVALID_FORMAT); // invalid char
    199     }
    200     i++;
    201   }
    202   return json_ptr;
    203 }