gmlparse.y 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. %require "3.0"
  11. /* By default, Bison emits a parser using symbols prefixed with "yy". Graphviz
  12. * contains multiple Bison-generated parsers, so we alter this prefix to avoid
  13. * symbol clashes.
  14. */
  15. %define api.prefix {gml}
  16. %{
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <arith.h>
  20. #include <gml2gv.h>
  21. #include <assert.h>
  22. #include <cgraph/list.h>
  23. #include <util/agxbuf.h>
  24. #include <util/alloc.h>
  25. #include <util/exit.h>
  26. static gmlgraph* G;
  27. static gmlnode* N;
  28. static gmledge* E;
  29. static Dt_t* L;
  30. DEFINE_LIST(dts, Dt_t *)
  31. static dts_t liststk;
  32. static void free_attr(void *attr);
  33. static char *sortToStr(unsigned short sort);
  34. static void free_node(void *node) {
  35. gmlnode *p = node;
  36. if (!p) return;
  37. if (p->attrlist) dtclose (p->attrlist);
  38. free (p);
  39. }
  40. static void free_edge(void *edge) {
  41. gmledge *p = edge;
  42. if (!p) return;
  43. if (p->attrlist) dtclose (p->attrlist);
  44. free (p);
  45. }
  46. static void free_graph(void *graph) {
  47. gmlgraph *p = graph;
  48. if (!p) return;
  49. if (p->nodelist)
  50. dtclose (p->nodelist);
  51. if (p->edgelist)
  52. dtclose (p->edgelist);
  53. if (p->attrlist)
  54. dtclose (p->attrlist);
  55. if (p->graphlist)
  56. dtclose (p->graphlist);
  57. free (p);
  58. }
  59. static Dtdisc_t nodeDisc = {
  60. .key = offsetof(gmlnode, attrlist),
  61. .size = sizeof(Dt_t *),
  62. .link = offsetof(gmlnode, link),
  63. .freef = free_node,
  64. };
  65. static Dtdisc_t edgeDisc = {
  66. .key = offsetof(gmledge, attrlist),
  67. .size = sizeof(Dt_t *),
  68. .link = offsetof(gmledge, link),
  69. .freef = free_edge,
  70. };
  71. static Dtdisc_t attrDisc = {
  72. .key = offsetof(gmlattr, name),
  73. .size = sizeof(char *),
  74. .link = offsetof(gmlattr, link),
  75. .freef = free_attr,
  76. };
  77. static Dtdisc_t graphDisc = {
  78. .key = offsetof(gmlgraph, nodelist),
  79. .size = sizeof(Dt_t *),
  80. .link = offsetof(gmlgraph, link),
  81. .freef = free_graph,
  82. };
  83. static void
  84. cleanup (void)
  85. {
  86. while (!dts_is_empty(&liststk)) {
  87. Dt_t *dt = dts_pop_back(&liststk);
  88. dtclose(dt);
  89. }
  90. dts_free(&liststk);
  91. if (L) {
  92. dtclose (L);
  93. L = NULL;
  94. }
  95. if (N) {
  96. free_node(N);
  97. N = NULL;
  98. }
  99. if (E) {
  100. free_edge(E);
  101. E = NULL;
  102. }
  103. if (G) {
  104. free_graph(G);
  105. G = NULL;
  106. }
  107. }
  108. static void
  109. pushAlist (void)
  110. {
  111. Dt_t* lp = dtopen (&attrDisc, Dtqueue);
  112. if (L) {
  113. dts_push_back(&liststk, L);
  114. }
  115. L = lp;
  116. }
  117. static Dt_t*
  118. popAlist (void)
  119. {
  120. Dt_t* lp = L;
  121. if (!dts_is_empty(&liststk))
  122. L = dts_pop_back(&liststk);
  123. else
  124. L = NULL;
  125. return lp;
  126. }
  127. static void
  128. popG (void)
  129. {
  130. G = G->parent;
  131. }
  132. static void
  133. pushG (void)
  134. {
  135. gmlgraph* g = gv_alloc(sizeof(gmlgraph));
  136. g->attrlist = dtopen(&attrDisc, Dtqueue);
  137. g->nodelist = dtopen(&nodeDisc, Dtqueue);
  138. g->edgelist = dtopen(&edgeDisc, Dtqueue);
  139. g->graphlist = dtopen(&graphDisc, Dtqueue);
  140. g->parent = G;
  141. g->directed = -1;
  142. if (G)
  143. dtinsert (G->graphlist, g);
  144. G = g;
  145. }
  146. static gmlnode*
  147. mkNode (void)
  148. {
  149. gmlnode* np = gv_alloc(sizeof(gmlnode));
  150. np->attrlist = dtopen (&attrDisc, Dtqueue);
  151. np->id = NULL;
  152. return np;
  153. }
  154. static gmledge*
  155. mkEdge (void)
  156. {
  157. gmledge* ep = gv_alloc(sizeof(gmledge));
  158. ep->attrlist = dtopen (&attrDisc, Dtqueue);
  159. ep->source = NULL;
  160. ep->target = NULL;
  161. return ep;
  162. }
  163. static gmlattr *mkAttr(char* name, unsigned short sort, unsigned short kind,
  164. char* str, Dt_t* list) {
  165. gmlattr* gp = gv_alloc(sizeof(gmlattr));
  166. assert (name || sort);
  167. if (!name)
  168. name = gv_strdup (sortToStr (sort));
  169. gp->sort = sort;
  170. gp->kind = kind;
  171. gp->name = name;
  172. if (str)
  173. gp->u.value = str;
  174. else {
  175. if (dtsize (list) == 0) {
  176. dtclose (list);
  177. list = 0;
  178. }
  179. gp->u.lp = list;
  180. }
  181. /* fprintf (stderr, "[%x] %hu %hu \"%s\" \"%s\" \n", gp, sort, kind, (name?name:""), (str?str:"")); */
  182. return gp;
  183. }
  184. static int
  185. setDir (char* d)
  186. {
  187. gmlgraph* g;
  188. int dir = atoi (d);
  189. free (d);
  190. if (dir < 0) dir = -1;
  191. else if (dir > 0) dir = 1;
  192. else dir = 0;
  193. G->directed = dir;
  194. if (dir >= 0) {
  195. for (g = G->parent; g; g = g->parent) {
  196. if (g->directed < 0)
  197. g->directed = dir;
  198. else if (g->directed != dir)
  199. return 1;
  200. }
  201. }
  202. return 0;
  203. }
  204. %}
  205. %union {
  206. int i;
  207. char *str;
  208. gmlnode* np;
  209. gmledge* ep;
  210. gmlattr* ap;
  211. Dt_t* list;
  212. }
  213. %token GRAPH NODE EDGE DIRECTED SOURCE TARGET
  214. %token XVAL YVAL WVAL HVAL LABEL GRAPHICS LABELGRAPHICS TYPE FILL
  215. %token OUTLINE OUTLINESTYLE OUTLINEWIDTH WIDTH
  216. %token STYLE LINE POINT
  217. %token TEXT FONTSIZE FONTNAME COLOR
  218. %token <str> INTEGER REAL STRING ID NAME
  219. %token <list> LIST
  220. %type <np> node
  221. %type <ep> edge
  222. %type <list> attrlist
  223. %type <ap> alistitem
  224. %%
  225. graph : optalist hdr body {gmllexeof(); if (G->parent) popG(); }
  226. | error { cleanup(); YYABORT; }
  227. |
  228. ;
  229. hdr : GRAPH { pushG(); }
  230. ;
  231. body : '[' optglist ']'
  232. ;
  233. optglist : glist
  234. | /* empty */
  235. ;
  236. glist : glist glistitem
  237. | glistitem
  238. ;
  239. glistitem : node { dtinsert (G->nodelist, $1); }
  240. | edge { dtinsert (G->edgelist, $1); }
  241. | hdr body
  242. | DIRECTED INTEGER {
  243. if (setDir($2)) {
  244. yyerror("mixed directed and undirected graphs");
  245. cleanup ();
  246. YYABORT;
  247. }
  248. }
  249. | ID INTEGER { dtinsert (G->attrlist, mkAttr(gv_strdup("id"), 0, INTEGER, $2, 0)); }
  250. | alistitem { dtinsert (G->attrlist, $1); }
  251. ;
  252. node : NODE { N = mkNode(); } '[' nlist ']' { $$ = N; N = NULL; }
  253. ;
  254. nlist : nlist nlistitem
  255. | nlistitem
  256. ;
  257. nlistitem : ID INTEGER { N->id = $2; }
  258. | alistitem { dtinsert (N->attrlist, $1); }
  259. ;
  260. edge : EDGE { E = mkEdge(); } '[' elist ']' { $$ = E; E = NULL; }
  261. ;
  262. elist : elist elistitem
  263. | elistitem
  264. ;
  265. elistitem : SOURCE INTEGER { E->source = $2; }
  266. | TARGET INTEGER { E->target = $2; }
  267. | ID INTEGER { dtinsert (E->attrlist, mkAttr(gv_strdup("id"), 0, INTEGER, $2, 0)); }
  268. | alistitem { dtinsert (E->attrlist, $1); }
  269. ;
  270. attrlist : '[' {pushAlist(); } optalist ']' { $$ = popAlist(); }
  271. ;
  272. optalist : alist
  273. | /* empty */
  274. ;
  275. alist : alist alistitem { dtinsert (L, $2); }
  276. | alistitem { dtinsert (L, $1); }
  277. ;
  278. alistitem : NAME INTEGER { $$ = mkAttr ($1, 0, INTEGER, $2, 0); }
  279. | NAME REAL { $$ = mkAttr ($1, 0, REAL, $2, 0); }
  280. | NAME STRING { $$ = mkAttr ($1, 0, STRING, $2, 0); }
  281. | NAME attrlist { $$ = mkAttr ($1, 0, LIST, 0, $2); }
  282. | XVAL REAL { $$ = mkAttr (0, XVAL, REAL, $2, 0); }
  283. | XVAL INTEGER { $$ = mkAttr (0, XVAL, REAL, $2, 0); }
  284. | YVAL REAL { $$ = mkAttr (0, YVAL, REAL, $2, 0); }
  285. | WVAL REAL { $$ = mkAttr (0, WVAL, REAL, $2, 0); }
  286. | HVAL REAL { $$ = mkAttr (0, HVAL, REAL, $2, 0); }
  287. | LABEL STRING { $$ = mkAttr (0, LABEL, STRING, $2, 0); }
  288. | GRAPHICS attrlist { $$ = mkAttr (0, GRAPHICS, LIST, 0, $2); }
  289. | LABELGRAPHICS attrlist { $$ = mkAttr (0, LABELGRAPHICS, LIST, 0, $2); }
  290. | TYPE STRING { $$ = mkAttr (0, TYPE, STRING, $2, 0); }
  291. | FILL STRING { $$ = mkAttr (0, FILL, STRING, $2, 0); }
  292. | OUTLINE STRING { $$ = mkAttr (0, OUTLINE, STRING, $2, 0); }
  293. | OUTLINESTYLE STRING { $$ = mkAttr (0, OUTLINESTYLE, STRING, $2, 0); }
  294. | OUTLINEWIDTH INTEGER { $$ = mkAttr (0, OUTLINEWIDTH, INTEGER, $2, 0); }
  295. | WIDTH REAL { $$ = mkAttr (0, WIDTH, REAL, $2, 0); }
  296. | WIDTH INTEGER { $$ = mkAttr (0, WIDTH, INTEGER, $2, 0); }
  297. | STYLE STRING { $$ = mkAttr (0, STYLE, STRING, $2, 0); }
  298. | STYLE attrlist { $$ = mkAttr (0, STYLE, LIST, 0, $2); }
  299. | LINE attrlist { $$ = mkAttr (0, LINE, LIST, 0, $2); }
  300. | POINT attrlist { $$ = mkAttr (0, POINT, LIST, 0, $2); }
  301. | TEXT STRING { $$ = mkAttr (0, TEXT, STRING, $2, 0); }
  302. | FONTNAME STRING { $$ = mkAttr (0, FONTNAME, STRING, $2, 0); }
  303. | FONTSIZE INTEGER { $$ = mkAttr (0, FONTNAME, INTEGER, $2, 0); }
  304. | COLOR STRING { $$ = mkAttr (0, COLOR, STRING, $2, 0); }
  305. ;
  306. %%
  307. static void free_attr(void *attr) {
  308. gmlattr *p = attr;
  309. if (!p) return;
  310. if (p->kind == LIST && p->u.lp)
  311. dtclose (p->u.lp);
  312. else
  313. free (p->u.value);
  314. free (p->name);
  315. free (p);
  316. }
  317. static void deparseList (Dt_t* alist, agxbuf* xb); /* forward declaration */
  318. static void
  319. deparseAttr (gmlattr* ap, agxbuf* xb)
  320. {
  321. if (ap->kind == LIST) {
  322. agxbprint (xb, "%s ", ap->name);
  323. deparseList (ap->u.lp, xb);
  324. }
  325. else if (ap->kind == STRING) {
  326. agxbprint (xb, "%s \"%s\"", ap->name, ap->u.value);
  327. }
  328. else {
  329. agxbprint (xb, "%s %s", ap->name, ap->u.value);
  330. }
  331. }
  332. static void
  333. deparseList (Dt_t* alist, agxbuf* xb)
  334. {
  335. gmlattr* ap;
  336. agxbput (xb, "[ ");
  337. if (alist) for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  338. deparseAttr (ap, xb);
  339. agxbputc (xb, ' ');
  340. }
  341. agxbput (xb, "]");
  342. }
  343. static void
  344. unknown (Agobj_t* obj, gmlattr* ap, agxbuf* xb)
  345. {
  346. char* str;
  347. if (ap->kind == LIST) {
  348. deparseList (ap->u.lp, xb);
  349. str = agxbuse (xb);
  350. }
  351. else
  352. str = ap->u.value;
  353. agsafeset (obj, ap->name, str, "");
  354. }
  355. static void addNodeLabelGraphics(Agnode_t* np, Dt_t* alist, agxbuf* unk) {
  356. gmlattr* ap;
  357. int cnt = 0;
  358. if (!alist)
  359. return;
  360. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  361. if (ap->sort == TEXT) {
  362. agsafeset (np, "label", ap->u.value, "");
  363. }
  364. else if (ap->sort == COLOR) {
  365. agsafeset (np, "fontcolor", ap->u.value, "");
  366. }
  367. else if (ap->sort == FONTSIZE) {
  368. agsafeset (np, "fontsize", ap->u.value, "");
  369. }
  370. else if (ap->sort == FONTNAME) {
  371. agsafeset (np, "fontname", ap->u.value, "");
  372. }
  373. else {
  374. if (cnt)
  375. agxbputc (unk, ' ');
  376. else {
  377. agxbput (unk, "[ ");
  378. }
  379. deparseAttr (ap, unk);
  380. cnt++;
  381. }
  382. }
  383. if (cnt) {
  384. agxbput (unk, " ]");
  385. agsafeset (np, "LabelGraphics", agxbuse (unk), "");
  386. }
  387. else
  388. agxbclear (unk);
  389. }
  390. static void
  391. addEdgeLabelGraphics (Agedge_t* ep, Dt_t* alist, agxbuf* xb, agxbuf* unk)
  392. {
  393. gmlattr* ap;
  394. char* x = "0";
  395. char* y = "0";
  396. int cnt = 0;
  397. if (!alist)
  398. return;
  399. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  400. if (ap->sort == TEXT) {
  401. agsafeset (ep, "label", ap->u.value, "");
  402. }
  403. else if (ap->sort == COLOR) {
  404. agsafeset (ep, "fontcolor", ap->u.value, "");
  405. }
  406. else if (ap->sort == FONTSIZE) {
  407. agsafeset (ep, "fontsize", ap->u.value, "");
  408. }
  409. else if (ap->sort == FONTNAME) {
  410. agsafeset (ep, "fontname", ap->u.value, "");
  411. }
  412. else if (ap->sort == XVAL) {
  413. x = ap->u.value;
  414. }
  415. else if (ap->sort == YVAL) {
  416. y = ap->u.value;
  417. }
  418. else {
  419. if (cnt)
  420. agxbputc (unk, ' ');
  421. else {
  422. agxbput (unk, "[ ");
  423. }
  424. deparseAttr (ap, unk);
  425. cnt++;
  426. }
  427. }
  428. agxbprint (xb, "%s,%s", x, y);
  429. agsafeset (ep, "lp", agxbuse (xb), "");
  430. if (cnt) {
  431. agxbput (unk, " ]");
  432. agsafeset (ep, "LabelGraphics", agxbuse (unk), "");
  433. }
  434. else
  435. agxbclear (unk);
  436. }
  437. static void
  438. addNodeGraphics (Agnode_t* np, Dt_t* alist, agxbuf* xb, agxbuf* unk)
  439. {
  440. gmlattr* ap;
  441. char* x = "0";
  442. char* y = "0";
  443. char buf[BUFSIZ];
  444. double d;
  445. int cnt = 0;
  446. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  447. if (ap->sort == XVAL) {
  448. x = ap->u.value;
  449. }
  450. else if (ap->sort == YVAL) {
  451. y = ap->u.value;
  452. }
  453. else if (ap->sort == WVAL) {
  454. d = atof (ap->u.value);
  455. snprintf(buf, sizeof(buf), "%.04f", d/72.0);
  456. agsafeset (np, "width", buf, "");
  457. }
  458. else if (ap->sort == HVAL) {
  459. d = atof (ap->u.value);
  460. snprintf(buf, sizeof(buf), "%.04f", d/72.0);
  461. agsafeset (np, "height", buf, "");
  462. }
  463. else if (ap->sort == TYPE) {
  464. agsafeset (np, "shape", ap->u.value, "");
  465. }
  466. else if (ap->sort == FILL) {
  467. agsafeset (np, "color", ap->u.value, "");
  468. }
  469. else if (ap->sort == OUTLINE) {
  470. agsafeset (np, "pencolor", ap->u.value, "");
  471. }
  472. else if (ap->sort == WIDTH || ap->sort == OUTLINEWIDTH) {
  473. agsafeset (np, "penwidth", ap->u.value, "");
  474. }
  475. else if (ap->sort == STYLE || ap->sort == OUTLINESTYLE) {
  476. agsafeset (np, "style", ap->u.value, "");
  477. }
  478. else {
  479. if (cnt)
  480. agxbputc (unk, ' ');
  481. else {
  482. agxbput (unk, "[ ");
  483. }
  484. deparseAttr (ap, unk);
  485. cnt++;
  486. }
  487. }
  488. agxbprint (xb, "%s,%s", x, y);
  489. agsafeset (np, "pos", agxbuse (xb), "");
  490. if (cnt) {
  491. agxbput (unk, " ]");
  492. agsafeset (np, "graphics", agxbuse (unk), "");
  493. }
  494. else
  495. agxbclear (unk);
  496. }
  497. static void
  498. addEdgePoint (Agedge_t* ep, Dt_t* alist, agxbuf* xb)
  499. {
  500. gmlattr* ap;
  501. char* x = "0";
  502. char* y = "0";
  503. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  504. if (ap->sort == XVAL) {
  505. x = ap->u.value;
  506. }
  507. else if (ap->sort == YVAL) {
  508. y = ap->u.value;
  509. }
  510. else {
  511. fprintf (stderr, "non-X/Y field in point attribute");
  512. unknown ((Agobj_t*)ep, ap, xb);
  513. }
  514. }
  515. if (agxblen(xb)) agxbputc (xb, ' ');
  516. agxbprint (xb, "%s,%s", x, y);
  517. }
  518. static void
  519. addEdgePos (Agedge_t* ep, Dt_t* alist, agxbuf* xb)
  520. {
  521. gmlattr* ap;
  522. if (!alist) return;
  523. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  524. if (ap->sort == POINT) {
  525. addEdgePoint (ep, ap->u.lp, xb);
  526. }
  527. else {
  528. fprintf (stderr, "non-point field in line attribute");
  529. unknown ((Agobj_t*)ep, ap, xb);
  530. }
  531. }
  532. agsafeset (ep, "pos", agxbuse (xb), "");
  533. }
  534. static void
  535. addEdgeGraphics (Agedge_t* ep, Dt_t* alist, agxbuf* xb, agxbuf* unk)
  536. {
  537. gmlattr* ap;
  538. int cnt = 0;
  539. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  540. if (ap->sort == WIDTH) {
  541. agsafeset (ep, "penwidth", ap->u.value, "");
  542. }
  543. else if (ap->sort == STYLE) {
  544. agsafeset (ep, "style", ap->u.value, "");
  545. }
  546. else if (ap->sort == FILL) {
  547. agsafeset (ep, "color", ap->u.value, "");
  548. }
  549. else if (ap->sort == LINE) {
  550. addEdgePos (ep, ap->u.lp, xb);
  551. }
  552. else {
  553. if (cnt)
  554. agxbputc (unk, ' ');
  555. else {
  556. agxbput (unk, "[ ");
  557. }
  558. deparseAttr (ap, unk);
  559. cnt++;
  560. }
  561. }
  562. if (cnt) {
  563. agxbput (unk, " ]");
  564. agsafeset (ep, "graphics", agxbuse (unk), "");
  565. }
  566. else
  567. agxbclear(unk);
  568. }
  569. static void
  570. addAttrs (Agobj_t* obj, Dt_t* alist, agxbuf* xb, agxbuf* unk)
  571. {
  572. gmlattr* ap;
  573. for (ap = dtfirst(alist); ap; ap = dtnext (alist, ap)) {
  574. if (ap->sort == GRAPHICS) {
  575. if (AGTYPE(obj) == AGNODE)
  576. addNodeGraphics ((Agnode_t*)obj, ap->u.lp, xb, unk);
  577. else if (AGTYPE(obj) == AGEDGE)
  578. addEdgeGraphics ((Agedge_t*)obj, ap->u.lp, xb, unk);
  579. else
  580. unknown (obj, ap, xb);
  581. }
  582. else if (ap->sort == LABELGRAPHICS) {
  583. if (AGTYPE(obj) == AGNODE)
  584. addNodeLabelGraphics ((Agnode_t*)obj, ap->u.lp, unk);
  585. else if (AGTYPE(obj) == AGEDGE)
  586. addEdgeLabelGraphics ((Agedge_t*)obj, ap->u.lp, xb, unk);
  587. else
  588. unknown (obj, ap, xb);
  589. }
  590. else
  591. unknown (obj, ap, xb);
  592. }
  593. }
  594. static Agraph_t *mkGraph(gmlgraph *graph, Agraph_t *parent, char *name,
  595. agxbuf *xb, agxbuf *unk) {
  596. Agraph_t* g;
  597. Agnode_t* n;
  598. Agnode_t* h;
  599. Agedge_t* e;
  600. gmlnode* np;
  601. gmledge* ep;
  602. gmlgraph* gp;
  603. if (parent) {
  604. g = agsubg (parent, NULL, 1);
  605. }
  606. else if (graph->directed >= 1)
  607. g = agopen (name, Agdirected, 0);
  608. else
  609. g = agopen (name, Agundirected, 0);
  610. if (!parent && L) {
  611. addAttrs ((Agobj_t*)g, L, xb, unk);
  612. }
  613. for (np = dtfirst(graph->nodelist); np; np = dtnext(graph->nodelist, np)) {
  614. if (!np->id) {
  615. fprintf (stderr, "node without an id attribute");
  616. graphviz_exit (1);
  617. }
  618. n = agnode (g, np->id, 1);
  619. addAttrs ((Agobj_t*)n, np->attrlist, xb, unk);
  620. }
  621. for (ep = dtfirst(graph->edgelist); ep; ep = dtnext(graph->edgelist, ep)) {
  622. if (!ep->source) {
  623. fprintf (stderr, "edge without an source attribute");
  624. graphviz_exit (1);
  625. }
  626. if (!ep->target) {
  627. fprintf (stderr, "node without an target attribute");
  628. graphviz_exit (1);
  629. }
  630. n = agnode (g, ep->source, 1);
  631. h = agnode (g, ep->target, 1);
  632. e = agedge (g, n, h, NULL, 1);
  633. addAttrs ((Agobj_t*)e, ep->attrlist, xb, unk);
  634. }
  635. for (gp = dtfirst(graph->graphlist); gp; gp = dtnext(graph->graphlist, gp)) {
  636. mkGraph (gp, g, NULL, xb, unk);
  637. }
  638. addAttrs ((Agobj_t*)g, graph->attrlist, xb, unk);
  639. return g;
  640. }
  641. Agraph_t*
  642. gml_to_gv (char* name, FILE* fp, int cnt, int* errors)
  643. {
  644. Agraph_t* g;
  645. int error;
  646. if (cnt == 0)
  647. initgmlscan(fp);
  648. else
  649. initgmlscan(0);
  650. L = NULL;
  651. pushAlist ();
  652. gmlparse ();
  653. error = gmlerrors();
  654. *errors |= error;
  655. if (!G || error)
  656. g = NULL;
  657. else {
  658. agxbuf xb = {0};
  659. agxbuf unk = {0};
  660. g = mkGraph (G, NULL, name, &xb, &unk);
  661. agxbfree (&xb);
  662. agxbfree(&unk);
  663. }
  664. cleanup ();
  665. return g;
  666. }
  667. static char *sortToStr(unsigned short sort) {
  668. char* s;
  669. switch (sort) {
  670. case GRAPH :
  671. s = "graph"; break;
  672. case NODE :
  673. s = "node"; break;
  674. case EDGE :
  675. s = "edge"; break;
  676. case DIRECTED :
  677. s = "directed"; break;
  678. case ID :
  679. s = "id"; break;
  680. case SOURCE :
  681. s = "source"; break;
  682. case TARGET :
  683. s = "target"; break;
  684. case XVAL :
  685. s = "xval"; break;
  686. case YVAL :
  687. s = "yval"; break;
  688. case WVAL :
  689. s = "wval"; break;
  690. case HVAL :
  691. s = "hval"; break;
  692. case LABEL :
  693. s = "label"; break;
  694. case GRAPHICS :
  695. s = "graphics"; break;
  696. case LABELGRAPHICS :
  697. s = "labelGraphics"; break;
  698. case TYPE :
  699. s = "type"; break;
  700. case FILL :
  701. s = "fill"; break;
  702. case OUTLINE :
  703. s = "outline"; break;
  704. case OUTLINESTYLE :
  705. s = "outlineStyle"; break;
  706. case OUTLINEWIDTH :
  707. s = "outlineWidth"; break;
  708. case WIDTH :
  709. s = "width"; break;
  710. case STYLE :
  711. s = "style"; break;
  712. case LINE :
  713. s = "line"; break;
  714. case POINT :
  715. s = "point"; break;
  716. case TEXT :
  717. s = "text"; break;
  718. case FONTSIZE :
  719. s = "fontSize"; break;
  720. case FONTNAME :
  721. s = "fontName"; break;
  722. case COLOR :
  723. s = "color"; break;
  724. case INTEGER :
  725. s = "integer"; break;
  726. case REAL :
  727. s = "real"; break;
  728. case STRING :
  729. s = "string"; break;
  730. case NAME :
  731. s = "name"; break;
  732. case LIST :
  733. s = "list"; break;
  734. case '[' :
  735. s = "["; break;
  736. case ']' :
  737. s = "]"; break;
  738. default :
  739. s = NULL;break;
  740. }
  741. return s;
  742. }