You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

json_parse.c 5.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <getopt.h>
  5. #include <stddef.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include "apps_config.h"
  11. /* XXX for a regular program, these should be <json-c/foo.h>
  12. * but that's inconvenient when building in the json-c source tree.
  13. */
  14. #include "json_object.h"
  15. #include "json_tokener.h"
  16. #include "json_util.h"
  17. #ifdef HAVE_SYS_RESOURCE_H
  18. #include <sys/resource.h>
  19. #include <sys/time.h>
  20. #endif
  21. #ifndef JSON_NORETURN
  22. #if defined(_MSC_VER)
  23. #define JSON_NORETURN __declspec(noreturn)
  24. #elif defined(__OS400__)
  25. #define JSON_NORETURN
  26. #else
  27. /* 'cold' attribute is for optimization, telling the computer this code
  28. * path is unlikely.
  29. */
  30. #define JSON_NORETURN __attribute__((noreturn, cold))
  31. #endif
  32. #endif
  33. static int formatted_output = JSON_C_TO_STRING_SPACED;
  34. static int show_output = 1;
  35. static int strict_mode = 0;
  36. static int color = 0;
  37. static const char *fname = NULL;
  38. #ifndef HAVE_JSON_TOKENER_GET_PARSE_END
  39. #define json_tokener_get_parse_end(tok) ((tok)->char_offset)
  40. #endif
  41. JSON_NORETURN static void usage(const char *argv0, int exitval, const char *errmsg);
  42. static void showmem(void);
  43. static int parseit(int fd, int (*callback)(struct json_object *));
  44. static int showobj(struct json_object *new_obj);
  45. static void showmem(void)
  46. {
  47. #ifdef HAVE_GETRUSAGE
  48. struct rusage rusage;
  49. memset(&rusage, 0, sizeof(rusage));
  50. getrusage(RUSAGE_SELF, &rusage);
  51. fprintf(stderr, "maxrss: %ld KB\n", rusage.ru_maxrss);
  52. #endif
  53. }
  54. static int parseit(int fd, int (*callback)(struct json_object *))
  55. {
  56. struct json_object *obj;
  57. char buf[32768];
  58. ssize_t ret;
  59. int depth = JSON_TOKENER_DEFAULT_DEPTH;
  60. json_tokener *tok;
  61. tok = json_tokener_new_ex(depth);
  62. if (!tok)
  63. {
  64. fprintf(stderr, "unable to allocate json_tokener: %s\n", strerror(errno));
  65. return 1;
  66. }
  67. json_tokener_set_flags(tok, JSON_TOKENER_STRICT
  68. #ifdef JSON_TOKENER_ALLOW_TRAILING_CHARS
  69. | JSON_TOKENER_ALLOW_TRAILING_CHARS
  70. #endif
  71. );
  72. // XXX push this into some kind of json_tokener_parse_fd API?
  73. // json_object_from_fd isn't flexible enough, and mirroring
  74. // everything you can do with a tokener into json_util.c seems
  75. // like the wrong approach.
  76. size_t total_read = 0;
  77. while ((ret = read(fd, buf, sizeof(buf))) > 0)
  78. {
  79. size_t retu = (size_t)ret; // We know it's positive
  80. total_read += retu;
  81. size_t start_pos = 0;
  82. while (start_pos != retu)
  83. {
  84. obj = json_tokener_parse_ex(tok, &buf[start_pos], retu - start_pos);
  85. enum json_tokener_error jerr = json_tokener_get_error(tok);
  86. size_t parse_end = json_tokener_get_parse_end(tok);
  87. if (obj == NULL && jerr != json_tokener_continue)
  88. {
  89. const char *aterr = (start_pos + parse_end < (int)sizeof(buf)) ?
  90. &buf[start_pos + parse_end] : "";
  91. fflush(stdout);
  92. size_t fail_offset = total_read - retu + start_pos + parse_end;
  93. fprintf(stderr, "Failed at offset %lu: %s %c\n", (unsigned long)fail_offset,
  94. json_tokener_error_desc(jerr), aterr[0]);
  95. json_tokener_free(tok);
  96. return 1;
  97. }
  98. if (obj != NULL)
  99. {
  100. int cb_ret = callback(obj);
  101. json_object_put(obj);
  102. if (cb_ret != 0)
  103. {
  104. json_tokener_free(tok);
  105. return 1;
  106. }
  107. }
  108. start_pos += json_tokener_get_parse_end(tok);
  109. assert(start_pos <= retu);
  110. }
  111. }
  112. if (ret < 0)
  113. {
  114. fprintf(stderr, "error reading fd %d: %s\n", fd, strerror(errno));
  115. }
  116. json_tokener_free(tok);
  117. return 0;
  118. }
  119. static int showobj(struct json_object *new_obj)
  120. {
  121. if (new_obj == NULL)
  122. {
  123. fprintf(stderr, "%s: Failed to parse\n", fname);
  124. return 1;
  125. }
  126. fprintf(stderr, "Successfully parsed object from %s\n", fname);
  127. if (show_output)
  128. {
  129. const char *output;
  130. output = json_object_to_json_string_ext(new_obj, formatted_output | color);
  131. printf("%s\n", output);
  132. }
  133. showmem();
  134. return 0;
  135. }
  136. static void usage(const char *argv0, int exitval, const char *errmsg)
  137. {
  138. FILE *fp = stdout;
  139. if (exitval != 0)
  140. fp = stderr;
  141. if (errmsg != NULL)
  142. fprintf(fp, "ERROR: %s\n\n", errmsg);
  143. fprintf(fp, "Usage: %s [-f|-F <arg>] [-n] [-s]\n", argv0);
  144. fprintf(fp, " -f - Format the output to stdout with JSON_C_TO_STRING_PRETTY (default is JSON_C_TO_STRING_SPACED)\n");
  145. fprintf(fp, " -F - Format the output to stdout with <arg>, e.g. 0 for JSON_C_TO_STRING_PLAIN\n");
  146. fprintf(fp, " -n - No output\n");
  147. fprintf(fp, " -c - color\n");
  148. fprintf(fp, " -s - Parse in strict mode, flags:\n");
  149. fprintf(fp, " JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS\n");
  150. fprintf(fp, " Diagnostic information will be emitted to stderr\n");
  151. fprintf(fp, "\nWARNING WARNING WARNING\n");
  152. fprintf(fp, "This is a prototype, it may change or be removed at any time!\n");
  153. exit(exitval);
  154. }
  155. int main(int argc, char **argv)
  156. {
  157. int opt;
  158. while ((opt = getopt(argc, argv, "fF:hnsc")) != -1)
  159. {
  160. switch (opt)
  161. {
  162. case 'f': formatted_output = JSON_C_TO_STRING_PRETTY; break;
  163. case 'F': formatted_output = atoi(optarg); break;
  164. case 'n': show_output = 0; break;
  165. case 's': strict_mode = 1; break;
  166. case 'c': color = JSON_C_TO_STRING_COLOR; break;
  167. case 'h': usage(argv[0], 0, NULL);
  168. default: /* '?' */ usage(argv[0], EXIT_FAILURE, "Unknown arguments");
  169. }
  170. }
  171. if (optind >= argc)
  172. {
  173. usage(argv[0], EXIT_FAILURE, "Expected argument after options");
  174. }
  175. fname = argv[optind];
  176. int fd = open(argv[optind], O_RDONLY, 0);
  177. showmem();
  178. if (parseit(fd, showobj) != 0)
  179. exit(EXIT_FAILURE);
  180. showmem();
  181. exit(EXIT_SUCCESS);
  182. }