json_process.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*
  2. * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
  3. *
  4. * Jansson is free software; you can redistribute it and/or modify
  5. * it under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #ifdef HAVE_CONFIG_H
  8. #include <jansson_private_config.h>
  9. #endif
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <jansson.h>
  15. #ifdef HAVE_LOCALE_H
  16. #include <locale.h>
  17. #endif
  18. #if _WIN32
  19. #include <io.h> /* for _setmode() */
  20. #include <fcntl.h> /* for _O_BINARY */
  21. static const char dir_sep = '\\';
  22. #else
  23. static const char dir_sep = '/';
  24. #endif
  25. struct config {
  26. int indent;
  27. int compact;
  28. int preserve_order;
  29. int ensure_ascii;
  30. int sort_keys;
  31. int strip;
  32. int use_env;
  33. int have_hashseed;
  34. int hashseed;
  35. int precision;
  36. } conf;
  37. #define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
  38. /* Return a pointer to the first non-whitespace character of str.
  39. Modifies str so that all trailing whitespace characters are
  40. replaced by '\0'. */
  41. static const char *strip(char *str)
  42. {
  43. size_t length;
  44. char *result = str;
  45. while (*result && l_isspace(*result))
  46. result++;
  47. length = strlen(result);
  48. if (length == 0)
  49. return result;
  50. while (l_isspace(result[length - 1]))
  51. result[--length] = '\0';
  52. return result;
  53. }
  54. static char *loadfile(FILE *file)
  55. {
  56. long fsize, ret;
  57. char *buf;
  58. fseek(file, 0, SEEK_END);
  59. fsize = ftell(file);
  60. fseek(file, 0, SEEK_SET);
  61. buf = malloc(fsize+1);
  62. ret = fread(buf, 1, fsize, file);
  63. if (ret != fsize)
  64. exit(1);
  65. buf[fsize] = '\0';
  66. return buf;
  67. }
  68. static void read_conf(FILE *conffile)
  69. {
  70. char *buffer, *line, *val;
  71. buffer = loadfile(conffile);
  72. for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) {
  73. if (!strncmp(line, "export ", 7))
  74. continue;
  75. val = strchr(line, '=');
  76. if (!val) {
  77. printf("invalid configuration line\n");
  78. break;
  79. }
  80. *val++ = '\0';
  81. if (!strcmp(line, "JSON_INDENT"))
  82. conf.indent = atoi(val);
  83. if (!strcmp(line, "JSON_COMPACT"))
  84. conf.compact = atoi(val);
  85. if (!strcmp(line, "JSON_ENSURE_ASCII"))
  86. conf.ensure_ascii = atoi(val);
  87. if (!strcmp(line, "JSON_PRESERVE_ORDER"))
  88. conf.preserve_order = atoi(val);
  89. if (!strcmp(line, "JSON_SORT_KEYS"))
  90. conf.sort_keys = atoi(val);
  91. if (!strcmp(line, "JSON_REAL_PRECISION"))
  92. conf.precision = atoi(val);
  93. if (!strcmp(line, "STRIP"))
  94. conf.strip = atoi(val);
  95. if (!strcmp(line, "HASHSEED")) {
  96. conf.have_hashseed = 1;
  97. conf.hashseed = atoi(val);
  98. } else {
  99. conf.have_hashseed = 0;
  100. }
  101. }
  102. free(buffer);
  103. }
  104. static int cmpfile(const char *str, const char *path, const char *fname)
  105. {
  106. char filename[1024], *buffer;
  107. int ret;
  108. FILE *file;
  109. sprintf(filename, "%s%c%s", path, dir_sep, fname);
  110. file = fopen(filename, "rb");
  111. if (!file) {
  112. if (conf.strip)
  113. strcat(filename, ".strip");
  114. else
  115. strcat(filename, ".normal");
  116. file = fopen(filename, "rb");
  117. }
  118. if (!file) {
  119. printf("Error: test result file could not be opened.\n");
  120. exit(1);
  121. }
  122. buffer = loadfile(file);
  123. if (strcmp(buffer, str) != 0)
  124. ret = 1;
  125. else
  126. ret = 0;
  127. free(buffer);
  128. fclose(file);
  129. return ret;
  130. }
  131. int use_conf(char *test_path)
  132. {
  133. int ret;
  134. size_t flags = 0;
  135. char filename[1024], errstr[1024];
  136. char *buffer;
  137. FILE *infile, *conffile;
  138. json_t *json;
  139. json_error_t error;
  140. sprintf(filename, "%s%cinput", test_path, dir_sep);
  141. if (!(infile = fopen(filename, "rb"))) {
  142. fprintf(stderr, "Could not open \"%s\"\n", filename);
  143. return 2;
  144. }
  145. sprintf(filename, "%s%cenv", test_path, dir_sep);
  146. conffile = fopen(filename, "rb");
  147. if (conffile) {
  148. read_conf(conffile);
  149. fclose(conffile);
  150. }
  151. if (conf.indent < 0 || conf.indent > 31) {
  152. fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent);
  153. fclose(infile);
  154. return 2;
  155. }
  156. if (conf.indent)
  157. flags |= JSON_INDENT(conf.indent);
  158. if (conf.compact)
  159. flags |= JSON_COMPACT;
  160. if (conf.ensure_ascii)
  161. flags |= JSON_ENSURE_ASCII;
  162. if (conf.preserve_order)
  163. flags |= JSON_PRESERVE_ORDER;
  164. if (conf.sort_keys)
  165. flags |= JSON_SORT_KEYS;
  166. if (conf.precision < 0 || conf.precision > 31) {
  167. fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
  168. conf.precision);
  169. fclose(infile);
  170. return 2;
  171. }
  172. if (conf.precision)
  173. flags |= JSON_REAL_PRECISION(conf.precision);
  174. if (conf.have_hashseed)
  175. json_object_seed(conf.hashseed);
  176. if (conf.strip) {
  177. /* Load to memory, strip leading and trailing whitespace */
  178. buffer = loadfile(infile);
  179. json = json_loads(strip(buffer), 0, &error);
  180. free(buffer);
  181. }
  182. else
  183. json = json_loadf(infile, 0, &error);
  184. fclose(infile);
  185. if (!json) {
  186. sprintf(errstr, "%d %d %d\n%s\n",
  187. error.line, error.column, error.position,
  188. error.text);
  189. ret = cmpfile(errstr, test_path, "error");
  190. return ret;
  191. }
  192. buffer = json_dumps(json, flags);
  193. ret = cmpfile(buffer, test_path, "output");
  194. free(buffer);
  195. json_decref(json);
  196. return ret;
  197. }
  198. static int getenv_int(const char *name)
  199. {
  200. char *value, *end;
  201. long result;
  202. value = getenv(name);
  203. if(!value)
  204. return 0;
  205. result = strtol(value, &end, 10);
  206. if(*end != '\0')
  207. return 0;
  208. return (int)result;
  209. }
  210. int use_env()
  211. {
  212. int indent, precision;
  213. size_t flags = 0;
  214. json_t *json;
  215. json_error_t error;
  216. #ifdef _WIN32
  217. /* On Windows, set stdout and stderr to binary mode to avoid
  218. outputting DOS line terminators */
  219. _setmode(_fileno(stdout), _O_BINARY);
  220. _setmode(_fileno(stderr), _O_BINARY);
  221. #endif
  222. indent = getenv_int("JSON_INDENT");
  223. if(indent < 0 || indent > 31) {
  224. fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
  225. return 2;
  226. }
  227. if(indent > 0)
  228. flags |= JSON_INDENT(indent);
  229. if(getenv_int("JSON_COMPACT") > 0)
  230. flags |= JSON_COMPACT;
  231. if(getenv_int("JSON_ENSURE_ASCII"))
  232. flags |= JSON_ENSURE_ASCII;
  233. if(getenv_int("JSON_PRESERVE_ORDER"))
  234. flags |= JSON_PRESERVE_ORDER;
  235. if(getenv_int("JSON_SORT_KEYS"))
  236. flags |= JSON_SORT_KEYS;
  237. precision = getenv_int("JSON_REAL_PRECISION");
  238. if(precision < 0 || precision > 31) {
  239. fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
  240. precision);
  241. return 2;
  242. }
  243. if(getenv("HASHSEED"))
  244. json_object_seed(getenv_int("HASHSEED"));
  245. if(precision > 0)
  246. flags |= JSON_REAL_PRECISION(precision);
  247. if(getenv_int("STRIP")) {
  248. /* Load to memory, strip leading and trailing whitespace */
  249. size_t size = 0, used = 0;
  250. char *buffer = NULL, *buf_ck = NULL;
  251. while(1) {
  252. size_t count;
  253. size = (size == 0 ? 128 : size * 2);
  254. buf_ck = realloc(buffer, size);
  255. if(!buf_ck) {
  256. fprintf(stderr, "Unable to allocate %d bytes\n", (int)size);
  257. free(buffer);
  258. return 1;
  259. }
  260. buffer = buf_ck;
  261. count = fread(buffer + used, 1, size - used, stdin);
  262. if(count < size - used) {
  263. buffer[used + count] = '\0';
  264. break;
  265. }
  266. used += count;
  267. }
  268. json = json_loads(strip(buffer), 0, &error);
  269. free(buffer);
  270. }
  271. else
  272. json = json_loadf(stdin, 0, &error);
  273. if(!json) {
  274. fprintf(stderr, "%d %d %d\n%s\n",
  275. error.line, error.column,
  276. error.position, error.text);
  277. return 1;
  278. }
  279. json_dumpf(json, stdout, flags);
  280. json_decref(json);
  281. return 0;
  282. }
  283. int main(int argc, char *argv[])
  284. {
  285. int i;
  286. char *test_path = NULL;
  287. #ifdef HAVE_SETLOCALE
  288. setlocale(LC_ALL, "");
  289. #endif
  290. if (argc < 2) {
  291. goto usage;
  292. }
  293. for (i = 1; i < argc; i++) {
  294. if (!strcmp(argv[i], "--strip"))
  295. conf.strip = 1;
  296. else if (!strcmp(argv[i], "--env"))
  297. conf.use_env = 1;
  298. else
  299. test_path = argv[i];
  300. }
  301. if (conf.use_env)
  302. return use_env();
  303. else
  304. {
  305. if (!test_path)
  306. goto usage;
  307. return use_conf(test_path);
  308. }
  309. usage:
  310. fprintf(stderr, "argc =%d\n", argc);
  311. fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]);
  312. return 2;
  313. }