jgf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*
  2. * Copyright 2021
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * These are the four essential freedoms with GNU GPL software:
  18. * 1: freedom to run the program, for any purpose
  19. * 2: freedom to study how the program works, and change it to make it do what you wish
  20. * 3: freedom to redistribute copies to help your Free Software friends
  21. * 4: freedom to distribute copies of your modified versions to your Free Software friends
  22. * , ,
  23. * / \
  24. * ((__-^^-,-^^-__))
  25. * `-_---' `---_-'
  26. * `--|o` 'o|--'
  27. * \ ` /
  28. * ): :(
  29. * :o_o:
  30. * "-"
  31. *
  32. * SPDX-License-Identifier: GPL-3.0+
  33. * License-Filename: LICENSE
  34. */
  35. /* parse jgf json graph data using json.c */
  36. /* todo the gtk+ libs seem already have a json parser, test if that can be used instead of json.c */
  37. #include "config.h"
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <zlib.h>
  42. #include "splay-tree.h"
  43. #include "main.h"
  44. #include "hier.h"
  45. #include "uniqnode.h"
  46. #include "uniqstr.h"
  47. #include "jgf.h"
  48. #include "json.h"
  49. #include "dpmem.h"
  50. #include "dot.tab.h" /* for yydebug */
  51. /* update sizes */
  52. #undef LIBJSON_DEFAULT_STACK_SIZE
  53. #undef LIBJSON_DEFAULT_BUFFER_SIZE
  54. #define LIBJSON_DEFAULT_STACK_SIZE (4*256)
  55. #define LIBJSON_DEFAULT_BUFFER_SIZE (4*4096)
  56. static splay_tree jgftree = NULL;
  57. /* no errors */
  58. static int jgferror = 0;
  59. /* debug option */
  60. static int jgfdebug = 0;
  61. static char *jgfstring_of_errors[] = {
  62. [JSON_ERROR_NO_MEMORY] = "out of memory",
  63. [JSON_ERROR_BAD_CHAR] = "bad character",
  64. [JSON_ERROR_POP_EMPTY] = "stack empty",
  65. [JSON_ERROR_POP_UNEXPECTED_MODE] = "pop unexpected mode",
  66. [JSON_ERROR_NESTING_LIMIT] = "nesting limit",
  67. [JSON_ERROR_DATA_LIMIT] = "data limit",
  68. [JSON_ERROR_COMMENT_NOT_ALLOWED] = "comment not allowed by config",
  69. [JSON_ERROR_UNEXPECTED_CHAR] = "unexpected char",
  70. [JSON_ERROR_UNICODE_MISSING_LOW_SURROGATE] = "missing unicode low surrogate",
  71. [JSON_ERROR_UNICODE_UNEXPECTED_LOW_SURROGATE] = "unexpected unicode low surrogate",
  72. [JSON_ERROR_COMMA_OUT_OF_STRUCTURE] = "error comma out of structure",
  73. [JSON_ERROR_CALLBACK] = "error in a callback",
  74. [JSON_ERROR_UTF8] = "utf8 validation error"
  75. };
  76. static void jgfparse_clear(void)
  77. {
  78. if (jgftree) {
  79. jgftree = splay_tree_delete(jgftree);
  80. }
  81. return;
  82. }
  83. /* static int jgfprocess_file(json_parser * parser, FILE * input, int *retlines, int *retcols) okd */
  84. static int jgfprocess_file(json_parser * parser, gzFile zinput, int *retlines, int *retcols)
  85. {
  86. char buffer[(32 * 1024)];
  87. int ret = 0;
  88. int32_t read = 0;
  89. int lines = 0;
  90. int col = 0;
  91. uint32_t i = 0;
  92. uint32_t processed = 0;
  93. lines = 1;
  94. col = 0;
  95. while (1) {
  96. read = gzread(zinput, (char *)buffer, (32 * 1024));
  97. /* read = fread(buffer, 1, (32 * 1024), input); old */
  98. if (read <= 0) {
  99. /* eof */
  100. break;
  101. }
  102. ret = json_parser_string(parser, buffer, read, &processed);
  103. for (i = 0; i < processed; i++) {
  104. if (buffer[i] == '\n') {
  105. col = 0;
  106. lines++;
  107. } else {
  108. col++;
  109. }
  110. }
  111. if (ret) {
  112. /* at parse error stop. */
  113. break;
  114. }
  115. }
  116. if (retlines) {
  117. *retlines = lines;
  118. }
  119. if (retcols) {
  120. *retcols = col;
  121. }
  122. return ret;
  123. }
  124. #define MODE_NONE 0
  125. #define MODE_INGRAPH 1
  126. #define MODE_INNODE 2
  127. #define MODE_INEDGE 3
  128. static int nkeys = 0;
  129. static int nodenr = 0;
  130. static char *nodelabel = NULL;
  131. static char *nodename = NULL;
  132. static char *fn = NULL;
  133. static char *tn = NULL;
  134. static int inesource = 0;
  135. static int inetarget = 0;
  136. static int inelabel = 0;
  137. static char *elabel = NULL;
  138. static int inlabel = 0;
  139. static int mode = 0;
  140. static struct gml_graph *curg = NULL;
  141. static void jgfaddnode(char *nnodename, int nr)
  142. {
  143. splay_tree_node node1 = NULL;
  144. node1 = splay_tree_lookup(jgftree, (splay_tree_key) nnodename);
  145. if (node1) {
  146. printf("%s(): node \"%s\" did already exist\n", __func__, nnodename);
  147. return;
  148. }
  149. if (jgfdebug || 0) {
  150. printf("%s(): adding node \"%s\"\n", __func__, nnodename);
  151. }
  152. splay_tree_insert(jgftree, (splay_tree_key) nnodename, (splay_tree_value) nr);
  153. return;
  154. }
  155. static void do_string(char *str)
  156. {
  157. if (mode == MODE_INNODE) {
  158. if (inlabel) {
  159. nodelabel = uniqstr(str);
  160. inlabel = 0;
  161. }
  162. } else if (mode == MODE_INEDGE) {
  163. if (inelabel) {
  164. elabel = uniqstr(str);
  165. inelabel = 0;
  166. }
  167. if (inesource) {
  168. fn = uniqstr(str);
  169. inesource = 0;
  170. }
  171. if (inetarget) {
  172. tn = uniqstr(str);
  173. inetarget = 0;
  174. }
  175. } else {
  176. }
  177. return;
  178. }
  179. static void do_data(void)
  180. {
  181. struct gml_node *fnn = NULL;
  182. struct gml_node *tnn = NULL;
  183. /* struct gml_node *nn = NULL; todo */
  184. splay_tree_node node1 = NULL;
  185. splay_tree_node node2 = NULL;
  186. char *ns = NULL;
  187. if (jgftree == NULL) {
  188. jgftree = splay_tree_new(splay_tree_compare_strings, NULL, NULL);
  189. }
  190. if (mode == MODE_INEDGE) {
  191. if (fn && tn) {
  192. /* if from or to node name does not exist yet, add it as nodes */
  193. node1 = splay_tree_lookup(jgftree, (splay_tree_key) fn);
  194. if (node1 == NULL) {
  195. printf("%s(): from \"%s\" did not exist\n", __func__, fn);
  196. /* uniq node number starting at 1 */
  197. maingraph->nodenum++;
  198. nodenr = maingraph->nodenum;
  199. ns = uniqstr(fn);
  200. jgfaddnode(ns, nodenr);
  201. add_new_node(curg, maingraph, nodenr, /* pvnl->nr */ (-1), ns, ns, /* ncolor */ 0x00ffffff, /* nbcolor */ 0, /* rlabel */
  202. NULL, /* hlabel */ NULL, /* fontcolor */ 0, /* ishtml */ 0);
  203. }
  204. node1 = splay_tree_lookup(jgftree, (splay_tree_key) fn);
  205. fnn = uniqnode(curg, node1->value);
  206. /* */
  207. node2 = splay_tree_lookup(jgftree, (splay_tree_key) tn);
  208. if (node2 == NULL) {
  209. printf("%s(): to \"%s\" did not exist\n", __func__, tn);
  210. /* uniq node number starting at 1 */
  211. maingraph->nodenum++;
  212. nodenr = maingraph->nodenum;
  213. ns = uniqstr(tn);
  214. jgfaddnode(ns, nodenr);
  215. add_new_node(curg, maingraph, nodenr, /* pvnl->nr */ (-1), ns, ns, /* ncolor */ 0x00ffffff, /* nbcolor */ 0, /* rlabel */
  216. NULL, /* hlabel */ NULL, /* fontcolor */ 0, /* ishtml */ 0);
  217. }
  218. node2 = splay_tree_lookup(jgftree, (splay_tree_key) tn);
  219. tnn = uniqnode(curg, node2->value);
  220. if (fnn && tnn) {
  221. if (fnn == tnn) {
  222. /* add selfedge count at this node */
  223. fnn->nselfedges++;
  224. } else {
  225. add_new_edge(curg, maingraph, /* foundsource */ fnn->nr, /* foundtarget */ tnn->nr,
  226. elabel,
  227. /* ecolor */ 0, /* style */ 0, /* fcompass */ NULL, /* tcompass */ NULL,
  228. /* constraint */ 1, /* ishtml */ 0);
  229. }
  230. }
  231. }
  232. fn = NULL;
  233. tn = NULL;
  234. elabel = NULL;
  235. }
  236. if (mode == MODE_INNODE) {
  237. if (nodename) {
  238. node1 = splay_tree_lookup(jgftree, (splay_tree_key) nodename);
  239. if (jgfdebug || 0) {
  240. printf("%s(): %p for node name %s\n", __func__, (void *)node1, nodename);
  241. }
  242. /* */
  243. if (node1 == NULL) {
  244. /* add new node with uniq node number starting at 1 */
  245. maingraph->nodenum++;
  246. nodenr = maingraph->nodenum;
  247. /* in jgf all nodes are located in rootgraph
  248. * use -1 for foundid then gml id check is not applied.
  249. */
  250. if (nodelabel == NULL) {
  251. nodelabel = nodename;
  252. }
  253. jgfaddnode(nodename, nodenr);
  254. add_new_node(curg, maingraph, nodenr, /* pvnl->nr */ (-1), nodename, nodelabel, /* ncolor */ 0x00ffffff, /* nbcolor */ 0, /* rlabel */
  255. NULL, /* hlabel */ NULL, /* fontcolor */ 0, /* ishtml */ 0);
  256. }
  257. /* */
  258. }
  259. nodename = NULL;
  260. nodelabel = NULL;
  261. }
  262. return;
  263. }
  264. static int do_key(char *str)
  265. {
  266. if (jgfdebug || 0) {
  267. printf("%s(): key=\"%s\" mode=%d\n", __func__, str, mode);
  268. }
  269. if (strcmp(str, "graph") == 0) {
  270. mode = MODE_INGRAPH;
  271. return (0);
  272. }
  273. if (strcmp(str, "graphs") == 0) {
  274. mode = MODE_INGRAPH;
  275. return (0);
  276. }
  277. if (nkeys == 0) {
  278. if (mode == MODE_NONE) {
  279. /* error first key should have been a graph or graphs */
  280. return (JSON_ERROR_UNEXPECTED_CHAR);
  281. }
  282. }
  283. nkeys++;
  284. /* skip all data until graph seen */
  285. if (mode == MODE_NONE) {
  286. return (0);
  287. }
  288. if (strcmp(str, "nodes") == 0) {
  289. mode = MODE_INNODE;
  290. return (0);
  291. }
  292. if (strcmp(str, "edges") == 0) {
  293. mode = MODE_INEDGE;
  294. return (0);
  295. }
  296. if (mode == MODE_INNODE) {
  297. if (strcmp(str, "label") == 0) {
  298. nodelabel = NULL;
  299. inlabel = 1;
  300. } else if (strcmp(str, "id") == 0) {
  301. } else if (strcmp(str, "metadata") == 0) {
  302. } else if (strcmp(str, "fillcolor") == 0) {
  303. } else if (strcmp(str, "bordercolor") == 0) {
  304. } else if (strcmp(str, "fontcolor") == 0) {
  305. } else {
  306. nodename = uniqstr(str);
  307. }
  308. } else if (mode == MODE_INEDGE) {
  309. if (strcmp(str, "source") == 0) {
  310. inesource = 1;
  311. } else if (strcmp(str, "target") == 0) {
  312. inetarget = 1;
  313. } else if (strcmp(str, "relation") == 0) {
  314. } else if (strcmp(str, "label") == 0) {
  315. inelabel = 1;
  316. } else {
  317. }
  318. } else {
  319. }
  320. return (0);
  321. }
  322. static int my_callback(void *userdata, int type, const char *data, uint32_t length)
  323. {
  324. int status = 0;
  325. FILE *output = (userdata) ? userdata : stdout;
  326. switch (type) {
  327. case JSON_OBJECT_BEGIN:
  328. if (jgfdebug || 0) {
  329. fprintf(output, "entering %s\n", (type == JSON_ARRAY_BEGIN) ? "array" : "object");
  330. }
  331. break;
  332. case JSON_ARRAY_BEGIN:
  333. if (jgfdebug || 0) {
  334. fprintf(output, "entering %s\n", (type == JSON_ARRAY_BEGIN) ? "array" : "object");
  335. }
  336. break;
  337. case JSON_OBJECT_END:
  338. if (jgfdebug || 0) {
  339. fprintf(output, "leaving %s\n", (type == JSON_ARRAY_END) ? "array" : "object");
  340. }
  341. do_data();
  342. break;
  343. case JSON_ARRAY_END:
  344. if (jgfdebug || 0) {
  345. fprintf(output, "leaving %s\n", (type == JSON_ARRAY_END) ? "array" : "object");
  346. }
  347. break;
  348. case JSON_KEY:
  349. if (jgfdebug || 0) {
  350. fprintf(output, "value \"%*s\" key\n", length, data);
  351. }
  352. status = do_key((char *)data);
  353. if (jgfdebug || 0) {
  354. printf("%d status\n", status);
  355. }
  356. break;
  357. case JSON_STRING:
  358. if (jgfdebug || 0) {
  359. fprintf(output, "value \"%*s\" string\n", length, data);
  360. }
  361. do_string((char *)data);
  362. break;
  363. case JSON_INT:
  364. if (jgfdebug || 0) {
  365. fprintf(output, "value \"%*s\" int\n", length, data);
  366. }
  367. break;
  368. case JSON_FLOAT:
  369. if (jgfdebug || 0) {
  370. fprintf(output, "value \"%*s\" float\n", length, data);
  371. }
  372. break;
  373. case JSON_NULL:
  374. if (jgfdebug || 0) {
  375. fprintf(output, "constant null\n");
  376. }
  377. break;
  378. case JSON_TRUE:
  379. if (jgfdebug || 0) {
  380. fprintf(output, "constant true\n");
  381. }
  382. break;
  383. case JSON_FALSE:
  384. if (jgfdebug || 0) {
  385. fprintf(output, "constant false\n");
  386. }
  387. break;
  388. default:
  389. /* shouldnothappen */
  390. printf("%s(): in default\n", __func__);
  391. break;
  392. }
  393. return (status);
  394. }
  395. static void wrapped_dp_free(void *p)
  396. {
  397. void *pp = NULL;
  398. if (p) {
  399. pp = dp_free(p);
  400. if (pp) {
  401. }
  402. }
  403. return;
  404. }
  405. /* int jgfparse(struct gml_graph *g, FILE * jgfinput, char *fname, char *argv0) old */
  406. int jgfparse(struct gml_graph *g, gzFile jgfinput, char *fname, char *argv0)
  407. {
  408. json_config jgfconfig;
  409. json_parser jgfparser;
  410. int ret = 0;
  411. int jgfcol = 0;
  412. int jgflines = 0;
  413. yydebug = 0;
  414. /* optional turn on debug */
  415. if (argv0) {
  416. if (strcmp(argv0, "gml4gtkd") == 0) {
  417. yydebug = 1;
  418. }
  419. }
  420. /* todo make a parse tree first. */
  421. nkeys = 0;
  422. curg = g;
  423. mode = MODE_NONE;
  424. /* no errors */
  425. jgferror = 0;
  426. memset(&jgfparser, 0, sizeof(json_parser));
  427. memset(&jgfconfig, 0, sizeof(json_config));
  428. /* read buffer size */
  429. jgfconfig.buffer_initial_size = LIBJSON_DEFAULT_BUFFER_SIZE;
  430. /* unlimited {} nesting */
  431. jgfconfig.max_nesting = 0;
  432. /* max. allowed memory usage */
  433. jgfconfig.max_data = 0;
  434. /* allow c style comments */
  435. jgfconfig.allow_c_comments = 1;
  436. /* allow yaml # style coments */
  437. jgfconfig.allow_yaml_comments = 1;
  438. /* wrap to own dpmem.c calloc/realloc/free */
  439. jgfconfig.user_calloc = dp_calloc;
  440. jgfconfig.user_realloc = dp_realloc;
  441. jgfconfig.user_free = wrapped_dp_free;
  442. /* debug option */
  443. jgfdebug = yydebug;
  444. ret = json_parser_init(&jgfparser, &jgfconfig, &my_callback, /* (void *)userdata */ NULL);
  445. if (ret) {
  446. /* shouldnothappen */
  447. }
  448. /* parse */
  449. ret = jgfprocess_file(&jgfparser, jgfinput, &jgflines, &jgfcol);
  450. if (ret) {
  451. fprintf(stderr, "jgf %s(): parse error at line %d, col %d code=%d %s in file %s\n", __func__, jgflines, jgfcol, ret,
  452. jgfstring_of_errors[ret], fname);
  453. memset(parsermessage, 0, 256);
  454. snprintf(parsermessage, (256 - 1), "jgf %s(): parse error at line %d, col %d code=%d %s in file %s\n", __func__,
  455. jgflines, jgfcol, ret, jgfstring_of_errors[ret], fname);
  456. jgfparse_clear();
  457. json_parser_free(&jgfparser);
  458. return (1);
  459. }
  460. ret = json_parser_is_done(&jgfparser);
  461. if (ret == 0) {
  462. /* parser is not in final state */
  463. fprintf(stderr, "jgf %s(): is_done parse error at line %d, col %d code=%d %s in file %s\n", __func__, jgflines,
  464. jgfcol, ret, jgfstring_of_errors[ret], fname);
  465. memset(parsermessage, 0, 256);
  466. snprintf(parsermessage, (256 - 1), "jgf %s(): is_done parse error at line %d, col %d code=%d %s in file %s\n",
  467. __func__, jgflines, jgfcol, ret, jgfstring_of_errors[ret], fname);
  468. jgfparse_clear();
  469. json_parser_free(&jgfparser);
  470. return (1);
  471. }
  472. jgfparse_clear();
  473. json_parser_free(&jgfparser);
  474. /* parsed oke. */
  475. return (0);
  476. }
  477. /* end. */