Bladeren bron

Added find_json_token()

Sergey Lyubka 11 jaren geleden
bovenliggende
commit
7a8397ccfd
3 gewijzigde bestanden met toevoegingen van 61 en 34 verwijderingen
  1. 35 7
      frozen.c
  2. 3 5
      frozen.h
  3. 23 22
      unit_test.c

+ 35 - 7
frozen.c

@@ -93,8 +93,8 @@ static int capture_ptr(struct frozen *f, const char *ptr, int type) {
 static int capture_len(struct frozen *f, int token_index, const char *ptr) {
   if (f->tokens == 0 || f->max_tokens == 0) return 0;
   EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID);
-  f->tokens[token_index].num_children = (f->num_tokens - 1) - token_index;
   f->tokens[token_index].len = ptr - f->tokens[token_index].ptr;
+  f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index;
   return 0;
 }
 
@@ -131,6 +131,7 @@ static int parse_string(struct frozen *f) {
 }
 
 // number = [ '-' ] digit { digit }
+// TODO(lsm): add support for floats
 static int parse_number(struct frozen *f) {
   int ch = cur(f);
   TRY(capture_ptr(f, f->cur, JSON_TYPE_NUMBER));
@@ -155,10 +156,9 @@ static int parse_array(struct frozen *f) {
   return 0;
 }
 
-static int compare(const struct frozen *f, const char *str, int len) {
+static int compare(const char *s, const char *str, int len) {
   int i = 0;
-  if (left(f) < len) return 0;
-  while (i < len && f->cur[i] == str[i]) i++;
+  while (i < len && s[i] == str[i]) i++;
   return i == len ? 1 : 0;
 }
 
@@ -171,15 +171,15 @@ static int parse_value(struct frozen *f) {
     TRY(parse_object(f));
   } else if (ch == '[') {
     TRY(parse_array(f));
-  } else if (ch == 'n' && compare(f, "null", 4)) {
+  } else if (ch == 'n' && left(f) > 4 && compare(f->cur, "null", 4)) {
     TRY(capture_ptr(f, f->cur, JSON_TYPE_NULL));
     f->cur += 4;
     capture_len(f, f->num_tokens - 1, f->cur);
-  } else if (ch == 't' && compare(f, "true", 4)) {
+  } else if (ch == 't' && left(f) > 4 && compare(f->cur, "true", 4)) {
     TRY(capture_ptr(f, f->cur, JSON_TYPE_TRUE));
     f->cur += 4;
     capture_len(f, f->num_tokens - 1, f->cur);
-  } else if (ch == 'f' && compare(f, "false", 5)) {
+  } else if (ch == 'f' && left(f) > 5 && compare(f->cur, "false", 5)) {
     TRY(capture_ptr(f, f->cur, JSON_TYPE_FALSE));
     f->cur += 5;
     capture_len(f, f->num_tokens - 1, f->cur);
@@ -242,3 +242,31 @@ int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) {
 
   return frozen.cur - s;
 }
+
+static int path_part_len(const char *p) {
+  int i = 0;
+  while (p[i] != '\0' && p[i] != '.') i++;
+  return i;
+}
+
+const struct json_token *find_json_token(const struct json_token *toks,
+                                         const char *path) {
+  if (path == 0 && path[0] == '\0') return 0;
+  for (;;) {
+    int i, n = path_part_len(path);
+    if (n == 0) return 0;
+    if (toks++->type != JSON_TYPE_OBJECT) return 0;
+    for (i = 0; i < toks[-1].num_desc; i++, toks++) {
+      if (toks[i].type != JSON_TYPE_STRING) return 0;
+      if (toks[i].len == n && compare(path, toks[i].ptr, n)) return &toks[++i];
+      if (toks[i + 1].type == JSON_TYPE_ARRAY ||
+          toks[i + 1].type == JSON_TYPE_OBJECT) {
+        i += toks[i + 1].num_desc;
+      }
+    }
+    toks += i;
+    path += n;
+    if (path[0] == '.') path++;
+  }
+  return 0;
+}

+ 3 - 5
frozen.h

@@ -25,7 +25,7 @@ extern "C" {
 struct json_token {
   const char *ptr;    // Points to the beginning of the token
   int len;            // Token length
-  int num_children;   // Number of children for array and objects
+  int num_desc;       // For arrays and object, total number of descendants
   int type;           // Type of the token, possible values below
 
 #define JSON_TYPE_EOF     0   // End of parsed tokens marker
@@ -44,13 +44,11 @@ struct json_token {
 #define JSON_TOKEN_ARRAY_TOO_SMALL    -3
 #define JSON_OUTPUT_BUFFER_TOO_SMALL  -4
 
-// Parse JSON string, store tokens in tokens_array. Last token has type
-// JSON_TYPE_EOF. Return offset in json string where parsing ended,
-// or negative error code on failure
 int parse_json(const char *json_string, int json_string_length,
                struct json_token *tokens_array, int size_of_tokens_array);
 
-int find_json_token(const struct json_token *toks, int num_toks, const char *p);
+const struct json_token *find_json_token(const struct json_token *toks,
+                                         const char *path);
 
 #ifdef __cplusplus
 }

+ 23 - 22
unit_test.c

@@ -125,34 +125,35 @@ static const char *test_errors(void) {
   ASSERT(cmp_token(&ar[21], "{}", JSON_TYPE_OBJECT));
   ASSERT(ar[22].type == JSON_TYPE_EOF);
 
-  ASSERT(ar[0].num_children == 21);
-  ASSERT(ar[1].num_children == 0);
-  ASSERT(ar[2].num_children == 0);
-  ASSERT(ar[3].num_children == 0);
-  ASSERT(ar[4].num_children == 0);
-  ASSERT(ar[5].num_children == 0);
-  ASSERT(ar[6].num_children == 0);
-  ASSERT(ar[7].num_children == 0);
-  ASSERT(ar[8].num_children == 0);
-  ASSERT(ar[9].num_children == 0);
-  ASSERT(ar[10].num_children == 0);
-  ASSERT(ar[11].num_children == 0);
-  ASSERT(ar[12].num_children == 3);
-  ASSERT(ar[13].num_children == 0);
-  ASSERT(ar[14].num_children == 0);
-  ASSERT(ar[15].num_children == 0);
-  ASSERT(ar[16].num_children == 0);
-  ASSERT(ar[17].num_children == 4);
-  ASSERT(ar[18].num_children == 0);
-  ASSERT(ar[19].num_children == 0);
-  ASSERT(ar[20].num_children == 0);
-  ASSERT(ar[21].num_children == 0);
+  return NULL;
+}
+
+static const char *test_config(void) {
+  static const char *config_str = "{ listening_ports: [ 80, 443 ] } ";
+  struct json_token tokens[100];
+  int tokens_size = sizeof(tokens) / sizeof(tokens[0]);
+
+  ASSERT(parse_json(config_str, strlen(config_str), tokens, tokens_size) > 0);
+  ASSERT(tokens[0].type == JSON_TYPE_OBJECT);
+  ASSERT(tokens[1].type == JSON_TYPE_STRING);
+  ASSERT(tokens[2].type == JSON_TYPE_ARRAY);
+  ASSERT(tokens[3].type == JSON_TYPE_NUMBER);
+  ASSERT(tokens[4].type == JSON_TYPE_NUMBER);
+
+  ASSERT(find_json_token(tokens, "foo.bar") == NULL);
+  ASSERT(find_json_token(tokens, "listening_ports") == &tokens[2]);
+#if 0
+  ASSERT(find_json_token(tokens, "listening_ports[0]") == &tokens[3]);
+  ASSERT(find_json_token(tokens, "listening_ports[1]") == &tokens[4]);
+  ASSERT(find_json_token(tokens, "listening_ports[3]") == NULL);
+#endif
 
   return NULL;
 }
 
 static const char *run_all_tests(void) {
   RUN_TEST(test_errors);
+  RUN_TEST(test_config);
   return NULL;
 }