dpmisc.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635
  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. #include "config.h"
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <strings.h>
  40. #include <errno.h>
  41. #include <math.h>
  42. #include "splay-tree.h"
  43. #include "main.h"
  44. #include "dp.h"
  45. #include "dpmisc.h"
  46. #include "dpus.h"
  47. #include "dot.tab.h"
  48. #include "dpcolor.h"
  49. #include "dphl.h"
  50. #include "dpmem.h"
  51. /* parse edge arrow style todo:
  52. * name = aname[anema[anema[aname]]]
  53. * aname = [mod] shape
  54. * mod = ['o'] side
  55. * side = 'l' | 'r'
  56. * shape = box
  57. * | crow
  58. * | curve
  59. * | icurve
  60. * | diamond
  61. * | dot
  62. * | inv
  63. * | none
  64. * | normal
  65. * | tee
  66. * | vee
  67. */
  68. struct dparrow *dp_getarrow(char *s)
  69. {
  70. struct dparrow *ret = NULL;
  71. int t = 0;
  72. ret = (struct dparrow *)dp_calloc(1, sizeof(struct dparrow));
  73. if (s == NULL) {
  74. ret->pe = 1;
  75. return (ret);
  76. }
  77. if (strlen(s) == 0) {
  78. ret->pe = 1;
  79. ret->es = 1;
  80. return (ret);
  81. }
  82. /* the raw name */
  83. ret->name = dp_uniqstr(s);
  84. /* parse the basic shapes */
  85. if (strcasecmp(s, "box") == 0) {
  86. t = DP_EA_BOX;
  87. } else if (strcasecmp(s, "crow") == 0) {
  88. t = DP_EA_CROW;
  89. } else if (strcasecmp(s, "curve") == 0) {
  90. t = DP_EA_CURVE;
  91. } else if (strcasecmp(s, "icurve") == 0) {
  92. t = DP_EA_ICURVE;
  93. } else if (strcasecmp(s, "diamond") == 0) {
  94. t = DP_EA_DIAMOND;
  95. } else if (strcasecmp(s, "dot") == 0) {
  96. t = DP_EA_DOT;
  97. } else if (strcasecmp(s, "inv") == 0) {
  98. t = DP_EA_INV;
  99. } else if (strcasecmp(s, "none") == 0) {
  100. t = DP_EA_NONE;
  101. } else if (strcasecmp(s, "normal") == 0) {
  102. t = DP_EA_NORMAL;
  103. } else if (strcasecmp(s, "tee") == 0) {
  104. t = DP_EA_TEE;
  105. } else if (strcasecmp(s, "vee") == 0) {
  106. t = DP_EA_VEE;
  107. } else {
  108. t = DP_EA_UNKNOWN;
  109. }
  110. /* todo parse the full string with all modifiers */
  111. ret->type = t;
  112. return (ret);
  113. }
  114. /* edge arrow direction */
  115. struct dpdir *dp_getdir(char *s)
  116. {
  117. struct dpdir *ret = NULL;
  118. ret = (struct dpdir *)dp_calloc(1, sizeof(struct dpdir));
  119. if (s == NULL) {
  120. ret->pe = 1;
  121. return (ret);
  122. }
  123. if (strlen(s) == 0) {
  124. ret->pe = 1;
  125. ret->es = 1;
  126. return (ret);
  127. }
  128. if (strcasecmp(s, "none") == 0) {
  129. ret->type = DP_DIR_NONE;
  130. } else if (strcasecmp(s, "both") == 0) {
  131. ret->type = DP_DIR_BOTH;
  132. } else if (strcasecmp(s, "back") == 0) {
  133. ret->type = DP_DIR_BACK;
  134. } else if (strcasecmp(s, "forward") == 0) {
  135. ret->type = DP_DIR_FORWARD;
  136. } else {
  137. /* unknown is type=0 */
  138. ret->pe = 1;
  139. }
  140. return (ret);
  141. }
  142. /* return 0 if str is a number string */
  143. int dp_chknum(char *str)
  144. {
  145. int c = 0;
  146. char *p = NULL;
  147. if (str == NULL) {
  148. return (0);
  149. }
  150. if (strlen(str) == 0) {
  151. return (0);
  152. }
  153. c = 0;
  154. p = str;
  155. while (*p) {
  156. switch (*p) {
  157. case '0':
  158. case '1':
  159. case '2':
  160. case '3':
  161. case '4':
  162. case '5':
  163. case '6':
  164. case '7':
  165. case '8':
  166. case '9':
  167. case ' ':
  168. case ',':
  169. case '.':
  170. case '-': /* for negative numbers */
  171. break;
  172. default:
  173. c++;
  174. break;
  175. }
  176. if (c) {
  177. break;
  178. }
  179. p++;
  180. }
  181. return (c);
  182. }
  183. /* return 1 if is a compass point */
  184. int dp_iscompass(char *compass)
  185. {
  186. int yes = 0;
  187. if (compass == NULL) {
  188. return (0);
  189. }
  190. /* check for valid compass point */
  191. yes = 1;
  192. if (strcmp(compass, "n") == 0) {
  193. } else if (strcmp(compass, "ne") == 0) {
  194. } else if (strcmp(compass, "e") == 0) {
  195. } else if (strcmp(compass, "se") == 0) {
  196. } else if (strcmp(compass, "s") == 0) {
  197. } else if (strcmp(compass, "sw") == 0) {
  198. } else if (strcmp(compass, "w") == 0) {
  199. } else if (strcmp(compass, "nw") == 0) {
  200. } else if (strcmp(compass, "c") == 0) {
  201. /* c is center of node */
  202. } else if (strcmp(compass, "_") == 0) {
  203. } else {
  204. /* not valid */
  205. yes = 0;
  206. }
  207. return (yes);
  208. }
  209. /* is a known shape name, -1 at error */
  210. int dp_isdotshape(char *s)
  211. {
  212. int ret = -1;
  213. if (s == NULL) {
  214. return (-1);
  215. }
  216. if (strlen(s) == 0) {
  217. return (DPSHAPE_ELLIPSE);
  218. }
  219. if (strcasecmp("assembly", s) == 0) {
  220. ret = DPSHAPE_ASSEMBLY;
  221. } else if (strcasecmp("box", s) == 0) {
  222. ret = DPSHAPE_BOX;
  223. } else if (strcasecmp("box3d", s) == 0) {
  224. ret = DPSHAPE_BOX3D;
  225. } else if (strcasecmp("cds", s) == 0) {
  226. ret = DPSHAPE_CDS;
  227. } else if (strcasecmp("circle", s) == 0) {
  228. ret = DPSHAPE_CIRCLE;
  229. } else if (strcasecmp("component", s) == 0) {
  230. ret = DPSHAPE_COMPONENT;
  231. } else if (strcasecmp("cylinder", s) == 0) {
  232. ret = DPSHAPE_CYLINDER;
  233. } else if (strcasecmp("diamond", s) == 0) {
  234. ret = DPSHAPE_DIAMOND;
  235. } else if (strcasecmp("doublecircle", s) == 0) {
  236. ret = DPSHAPE_DOUBLECIRCLE;
  237. } else if (strcasecmp("doubleoctagon", s) == 0) {
  238. ret = DPSHAPE_DOUBLEOCTAGON;
  239. } else if (strcasecmp("egg", s) == 0) {
  240. ret = DPSHAPE_EGG;
  241. } else if (strcasecmp("ellipse", s) == 0) {
  242. ret = DPSHAPE_ELLIPSE;
  243. } else if (strcasecmp("fivepoverhang", s) == 0) {
  244. ret = DPSHAPE_FIVEPOVERHANG;
  245. } else if (strcasecmp("folder", s) == 0) {
  246. ret = DPSHAPE_FOLDER;
  247. } else if (strcasecmp("hexagon", s) == 0) {
  248. ret = DPSHAPE_HEXAGON;
  249. } else if (strcasecmp("house", s) == 0) {
  250. ret = DPSHAPE_HOUSE;
  251. } else if (strcasecmp("insulator", s) == 0) {
  252. ret = DPSHAPE_INSULATOR;
  253. } else if (strcasecmp("invhouse", s) == 0) {
  254. ret = DPSHAPE_INVHOUSE;
  255. } else if (strcasecmp("invtrapezium", s) == 0) {
  256. ret = DPSHAPE_INVTRAPEZIUM;
  257. } else if (strcasecmp("invtriangle", s) == 0) {
  258. ret = DPSHAPE_INVTRIANGLE;
  259. } else if (strcasecmp("larrow", s) == 0) {
  260. ret = DPSHAPE_LARROW;
  261. } else if (strcasecmp("lpromoter", s) == 0) {
  262. ret = DPSHAPE_LPROMOTOR;
  263. } else if (strcasecmp("Mcircle", s) == 0) {
  264. ret = DPSHAPE_MCIRCLE;
  265. } else if (strcasecmp("Mdiamond", s) == 0) {
  266. ret = DPSHAPE_MDIAMOND;
  267. } else if (strcasecmp("Msquare", s) == 0) {
  268. ret = DPSHAPE_MSQUARE;
  269. } else if (strcasecmp("Mrecord", s) == 0) {
  270. /* special */
  271. ret = DPSHAPE_MRECORD;
  272. } else if (strcasecmp("none", s) == 0) {
  273. ret = DPSHAPE_NONE;
  274. } else if (strcasecmp("note", s) == 0) {
  275. ret = DPSHAPE_NOTE;
  276. } else if (strcasecmp("noverhang", s) == 0) {
  277. ret = DPSHAPE_NOVERHANG;
  278. } else if (strcasecmp("octagon", s) == 0) {
  279. ret = DPSHAPE_OCTAGON;
  280. } else if (strcasecmp("oval", s) == 0) {
  281. ret = DPSHAPE_OVAL;
  282. } else if (strcasecmp("parallelogram", s) == 0) {
  283. ret = DPSHAPE_PARALLELOGRAM;
  284. } else if (strcasecmp("pentagon", s) == 0) {
  285. ret = DPSHAPE_PENTAGON;
  286. } else if (strcasecmp("plain", s) == 0) {
  287. ret = DPSHAPE_PLAIN;
  288. } else if (strcasecmp("plaintext", s) == 0) {
  289. ret = DPSHAPE_PLAINTEXT;
  290. } else if (strcasecmp("point", s) == 0) {
  291. ret = DPSHAPE_POINT;
  292. } else if (strcasecmp("polygon", s) == 0) {
  293. ret = DPSHAPE_POLYGON;
  294. } else if (strcasecmp("primersite", s) == 0) {
  295. ret = DPSHAPE_PRIMERSITE;
  296. } else if (strcasecmp("promoter", s) == 0) {
  297. ret = DPSHAPE_PROMOTER;
  298. } else if (strcasecmp("proteasesite", s) == 0) {
  299. ret = DPSHAPE_PROTEASESITE;
  300. } else if (strcasecmp("proteinstab", s) == 0) {
  301. ret = DPSHAPE_PROTEINSTAB;
  302. } else if (strcasecmp("rarrow", s) == 0) {
  303. ret = DPSHAPE_RARROW;
  304. } else if (strcasecmp("record", s) == 0) {
  305. /* special */
  306. ret = DPSHAPE_RECORD;
  307. } else if (strcasecmp("rect", s) == 0) {
  308. ret = DPSHAPE_RECT;
  309. } else if (strcasecmp("rectangle", s) == 0) {
  310. ret = DPSHAPE_RECTANGLE;
  311. } else if (strcasecmp("restrictionsite", s) == 0) {
  312. ret = DPSHAPE_RESTRICTIONSITE;
  313. } else if (strcasecmp("ribosite", s) == 0) {
  314. ret = DPSHAPE_RIBOSITE;
  315. } else if (strcasecmp("rnastab", s) == 0) {
  316. ret = DPSHAPE_RNASTAB;
  317. } else if (strcasecmp("rpromoter", s) == 0) {
  318. ret = DPSHAPE_RPROMOTER;
  319. } else if (strcasecmp("septagon", s) == 0) {
  320. ret = DPSHAPE_SEPTAGON;
  321. } else if (strcasecmp("signature", s) == 0) {
  322. ret = DPSHAPE_SIGNATURE;
  323. } else if (strcasecmp("square", s) == 0) {
  324. ret = DPSHAPE_SQUARE;
  325. } else if (strcasecmp("star", s) == 0) {
  326. ret = DPSHAPE_STAR;
  327. } else if (strcasecmp("tab", s) == 0) {
  328. ret = DPSHAPE_TAB;
  329. } else if (strcasecmp("terminator", s) == 0) {
  330. ret = DPSHAPE_TERMINATOR;
  331. } else if (strcasecmp("threepoverhang", s) == 0) {
  332. ret = DPSHAPE_THREEPOVERHANG;
  333. } else if (strcasecmp("trapezium", s) == 0) {
  334. ret = DPSHAPE_TRAPEZIUM;
  335. } else if (strcasecmp("triangle", s) == 0) {
  336. ret = DPSHAPE_TRIANGLE;
  337. } else if (strcasecmp("tripleoctagon", s) == 0) {
  338. ret = DPSHAPE_TRIPLEOCTAGON;
  339. } else if (strcasecmp("underline", s) == 0) {
  340. ret = DPSHAPE_UNDERLINE;
  341. } else if (strcasecmp("utr", s) == 0) {
  342. ret = DPSHAPE_UTR;
  343. } else {
  344. /* unknown node shape */
  345. ret = -1;
  346. }
  347. return (ret);
  348. }
  349. /* labelloc can be t,b,c, for graph only t,b */
  350. int dp_islabelloc(char *loc)
  351. {
  352. int ret = 0;
  353. if (loc == NULL) {
  354. return (DP_LLC);
  355. }
  356. /* use default 'c' at "" */
  357. if (strlen(loc) == 0) {
  358. return (DP_LLC);
  359. }
  360. if (strcasecmp("t", loc) == 0) {
  361. ret = DP_LLT;
  362. } else if (strcasecmp("b", loc) == 0) {
  363. ret = DP_LLB;
  364. } else if (strcasecmp("c", loc) == 0) {
  365. ret = DP_LLC;
  366. } else {
  367. /* wrong value */
  368. ret = 0;
  369. }
  370. return (ret);
  371. }
  372. /* tmp label char */
  373. static char *clb = NULL;
  374. static size_t clblen = 0;
  375. /* parse */
  376. static struct dppart *dp_2chkrec(struct dpnode *node, int dir)
  377. {
  378. struct dppart *nrec = NULL;
  379. struct dppart *fp = NULL;
  380. char *s = NULL;
  381. int c = 0;
  382. int nf = 0;
  383. char *rs1 = NULL;
  384. char *prs = NULL;
  385. char *prt = NULL;
  386. char *pprt = NULL;
  387. int pos1 = 0;
  388. int maxpos = 0;
  389. int ndir = 0;
  390. char *lastport = NULL;
  391. char *lastfield = NULL;
  392. int hassub = 0;
  393. nrec = (struct dppart *)dp_calloc(1, sizeof(struct dppart));
  394. /* get number of fields now */
  395. s = clb;
  396. c = 0;
  397. nf = 0;
  398. while (*s) {
  399. if ((*s) == '\\') {
  400. s++;
  401. if ((*s) == 0) {
  402. break;
  403. }
  404. } else {
  405. if ((*s) == '{') {
  406. /* increase nesting count */
  407. c++;
  408. } else if ((*s) == '}') {
  409. c--;
  410. } else if ((*s) == '|') {
  411. if (c == 0) {
  412. nf++;
  413. }
  414. } else {
  415. /* nop */
  416. }
  417. }
  418. if (c < 0) {
  419. break;
  420. }
  421. s++;
  422. }
  423. /* todo valgrind says memleak and errors in this routine */
  424. /* tmp fix (nrec->ndpparts + 1) */
  425. nrec->dir = dir;
  426. nrec->ndpparts = (nf + 1);
  427. /* */
  428. nrec->parts = (struct dppart **)dp_calloc(1, ((nrec->ndpparts + 0) * sizeof(struct dppart *)));
  429. maxpos = (nf + 1);
  430. if (yydebug || 0) {
  431. printf("dot %s(): %d parts with direction %d\n", __func__, nrec->ndpparts, nrec->dir);
  432. fflush(stdout);
  433. }
  434. /* tmp buffer for string and port */
  435. rs1 = (char *)dp_calloc(1, clblen + 1);
  436. lastfield = NULL;
  437. prt = (char *)dp_calloc(1, clblen + 1);
  438. pprt = prt;
  439. lastport = NULL;
  440. pos1 = 0;
  441. while (*clb) {
  442. /* get port as in "<portname>" creating string in lastport */
  443. if ((*clb) == '<') {
  444. lastport = NULL;
  445. clb++;
  446. while (*clb) {
  447. if (*clb == '>') {
  448. break;
  449. }
  450. if (*clb == '\\') {
  451. (*pprt) = (*clb);
  452. pprt++;
  453. clb++;
  454. (*pprt) = (*clb);
  455. pprt++;
  456. clb++;
  457. } else {
  458. (*pprt) = (*clb);
  459. pprt++;
  460. clb++;
  461. }
  462. }
  463. lastport = dp_uniqstr(prt);
  464. memset(prt, 0, clblen + 1);
  465. pprt = prt;
  466. if (*clb) {
  467. clb++;
  468. }
  469. } else if ((*clb) == '{') {
  470. clb++;
  471. /* toggle direction */
  472. if (dir == 0) {
  473. /* vertical */
  474. ndir = 1;
  475. } else {
  476. /* horizontal */
  477. ndir = 0;
  478. }
  479. hassub = 1;
  480. fp = dp_2chkrec(node, ndir);
  481. nrec->parts[pos1] = fp;
  482. pos1++;
  483. } else if ((*clb) == '}' || (*clb) == '|') {
  484. fp = (struct dppart *)dp_calloc(1, sizeof(struct dppart));
  485. /* check for "{aa|bb|}" */
  486. if (*clb == '}') {
  487. if (*(clb - 1) == '|') {
  488. lastfield = dp_uniqstr((char *)" ");
  489. }
  490. }
  491. /* for "|aa", "|", "aa||bb" */
  492. if (*clb == '|') {
  493. if (lastfield == NULL) {
  494. lastfield = dp_uniqstr((char *)" ");
  495. }
  496. }
  497. fp->lp = lastfield;
  498. fp->id = lastport;
  499. fp->dir = dir;
  500. if (lastfield || lastport) {
  501. fp->hd = 1;
  502. }
  503. if (fp->hd || fp->id || fp->lp) {
  504. if (hassub == 0) {
  505. if (pos1 >= maxpos) {
  506. printf("dot %s(): pos1=%d maxpos=%d fixme (1)\n", __func__, pos1, maxpos);
  507. }
  508. nrec->parts[pos1] = fp;
  509. pos1++;
  510. } else {
  511. /* nothing if at "...}|..." */
  512. fp = (struct dppart *)dp_free((void *)fp);
  513. if (fp) {
  514. }
  515. }
  516. hassub = 0;
  517. } else {
  518. fp = (struct dppart *)dp_free((void *)fp);
  519. if (fp) {
  520. }
  521. }
  522. lastfield = NULL;
  523. lastport = NULL;
  524. if ((*clb) == '}') {
  525. clb++;
  526. if (rs1) {
  527. rs1 = (char *)dp_free((void *)rs1);
  528. if (rs1) {
  529. }
  530. }
  531. if (prt) {
  532. prt = (char *)dp_free((void *)prt);
  533. if (prt) {
  534. }
  535. }
  536. return (nrec);
  537. }
  538. if (*clb) {
  539. clb++;
  540. }
  541. } else {
  542. prs = rs1;
  543. /* copy field part */
  544. while (*clb) {
  545. if (*clb == '{' || *clb == '}' || *clb == '|' || *clb == '<' || *clb == '>') {
  546. /* stop on ctrl char */
  547. break;
  548. }
  549. /* copy to text part */
  550. if ((*clb) == '\\') {
  551. (*prs) = (*clb);
  552. prs++;
  553. clb++;
  554. (*prs) = (*clb);
  555. prs++;
  556. clb++;
  557. } else {
  558. (*prs) = (*clb);
  559. prs++;
  560. clb++;
  561. }
  562. }
  563. lastfield = dp_uniqstr(rs1);
  564. memset(rs1, 0, (clblen + 1));
  565. }
  566. }
  567. /* */
  568. fp = (struct dppart *)dp_calloc(1, sizeof(struct dppart));
  569. /* example "aa|bb|" or "aa|bb|<pos>" */
  570. if ((*(clb - 1) == '|') || (*(clb - 1) == '>')) {
  571. lastfield = dp_uniqstr((char *)" ");
  572. fp->hd = 1;
  573. }
  574. fp->lp = lastfield;
  575. if (lastfield || lastport) {
  576. fp->hd = 1;
  577. }
  578. fp->id = lastport;
  579. fp->dir = dir;
  580. if (fp->hd || fp->id || fp->lp) {
  581. if (pos1 >= maxpos) {
  582. /* this happens normally */
  583. if (0) {
  584. printf("dot %s(): pos1=%d maxpos=%d fixme (2) id=\"%s\" lp=\"%s\"\n", __func__, pos1, maxpos, lastfield, lastport);
  585. }
  586. fp = (struct dppart *)dp_free((void *)fp);
  587. if (fp) {
  588. }
  589. } else {
  590. nrec->parts[pos1] = fp;
  591. }
  592. } else {
  593. fp = (struct dppart *)dp_free((void *)fp);
  594. if (fp) {
  595. }
  596. }
  597. if (rs1) {
  598. rs1 = (char *)dp_free((void *)rs1);
  599. if (rs1) {
  600. }
  601. }
  602. if (prt) {
  603. prt = (char *)dp_free((void *)prt);
  604. if (prt) {
  605. }
  606. }
  607. return (nrec);
  608. }
  609. static void dp_1chkrecpr(struct dppart *info, int ind)
  610. {
  611. int i = 0;
  612. if (info == NULL) {
  613. printf("dot %s(): nil info\n", __func__);
  614. return;
  615. }
  616. for (i = 0; i < ind; i++) {
  617. printf(" ");
  618. }
  619. printf("%p---begin\n", (void *)info);
  620. for (i = 0; i < ind; i++) {
  621. printf("\t");
  622. }
  623. printf("`%s' `%s' %d parts dir=%d hd=%d\n", info->id, info->lp, info->ndpparts, info->dir, info->hd);
  624. for (i = 0; i < info->ndpparts; i++) {
  625. ind++;
  626. if (info->parts[i]) {
  627. dp_1chkrecpr(info->parts[i], (ind + 1));
  628. }
  629. ind--;
  630. }
  631. for (i = 0; i < ind; i++) {
  632. printf(" ");
  633. }
  634. printf("%p---end\n", (void *)info);
  635. return;
  636. }
  637. /* check 1 node record label */
  638. static int dp_1chkrec(struct dpnode *node)
  639. {
  640. int bo = 0;
  641. int bc = 0;
  642. char *p = NULL;
  643. int status = 0;
  644. struct dppart *inf = NULL;
  645. /* check for matching {} in string */
  646. p = node->label;
  647. status = 0;
  648. if (p == NULL) {
  649. return (0);
  650. }
  651. /* if "" */
  652. if (strlen(p) == 0) {
  653. /* oke */
  654. return (0);
  655. }
  656. bo = 0;
  657. bc = 0;
  658. while ((*p)) {
  659. if ((*p) == '\\') {
  660. p++;
  661. if ((*p) == 0) {
  662. break;
  663. }
  664. } else if (((*p) == '{') || ((*p) == '<')) {
  665. bo++;
  666. } else if (((*p) == '}') || ((*p) == '>')) {
  667. bc++;
  668. } else { /* nop */
  669. }
  670. p++;
  671. }
  672. /* check for matching {} and issue error */
  673. if (bo != bc) {
  674. /* todo change in parse error */
  675. memset(dp_errmsg, 0, (256 - 1));
  676. snprintf(dp_errmsg, (256 - 1),
  677. "dot %s(): mismatch in record label string in node `%s' at line %d\n", __func__, node->name, node->yylineno);
  678. return (1);
  679. }
  680. /* string is oke, parse rest of format string */
  681. clb = node->label;
  682. clblen = strlen(clb);
  683. inf = dp_2chkrec(node, /* direction hor. */ 0);
  684. if (yydebug || 0) {
  685. dp_1chkrecpr(inf, 0);
  686. }
  687. fflush(stdout);
  688. /* tmp label char */
  689. clb = NULL;
  690. clblen = 0;
  691. node->labelinfo = inf;
  692. return (status);
  693. }
  694. /* check nodes with record labels */
  695. static int dp_chkrec(void)
  696. {
  697. int status = 0;
  698. struct dpnlink *nl = NULL;
  699. nl = dp_anodes;
  700. while (nl) {
  701. status = 0;
  702. if (nl->n->shape == DPSHAPE_RECORD || nl->n->shape == DPSHAPE_MRECORD) {
  703. status = dp_1chkrec(nl->n);
  704. }
  705. if (status) {
  706. break;
  707. }
  708. nl = nl->next;
  709. }
  710. return (status);
  711. }
  712. /* check one node html label starting with '<' */
  713. static int dp1_chkhmln(struct dpnode *node)
  714. {
  715. int status = 0;
  716. status = htmlparse(node);
  717. if (status) { /*parse error */
  718. }
  719. return (status);
  720. }
  721. /* check nodes with html labels */
  722. static int dp_chkhtmln(void)
  723. {
  724. int status = 0;
  725. struct dpnlink *nl = NULL;
  726. nl = dp_anodes;
  727. while (nl) {
  728. if (nl->n->name == NULL) {
  729. /* shouldnothappen */
  730. printf("%s(): nil node name for node with label \"%s\"\n", __func__, nl->n->label);
  731. }
  732. if (nl->n->label) {
  733. if (strlen(nl->n->label) > 0) {
  734. /* non-record shape node with optional <> html label */
  735. if (nl->n->htmllabel) {
  736. status = dp1_chkhmln(nl->n);
  737. }
  738. if (yydebug || 0) {
  739. printf("%s(): node \"%s\" html-label=%d ", __func__, nl->n->name, nl->n->htmllabel);
  740. if (nl->n->htmllabel) {
  741. if (nl->n->hlinfo) {
  742. printf("hlinfo=%p mode=%d il=%p tl=%p\n", (void *)nl->n->hlinfo,
  743. nl->n->hlinfo->mode, (void *)nl->n->hlinfo->il, (void *)nl->n->hlinfo->tl);
  744. } else {
  745. printf("hlinfo=nil\n");
  746. }
  747. } else {
  748. printf("\n");
  749. }
  750. }
  751. if (status) {
  752. break;
  753. }
  754. }
  755. }
  756. nl = nl->next;
  757. }
  758. return (status);
  759. }
  760. /* check data, return 0 if oke. */
  761. int dp_datachk(void)
  762. {
  763. int status1 = 0;
  764. int status2 = 0;
  765. /* check nodes with record labels */
  766. status1 = dp_chkrec();
  767. if (yydebug || 0) {
  768. printf("%s(): status=%d dp_chkrec();\n", __func__, status1);
  769. }
  770. /* check nodes with html labels */
  771. status2 = dp_chkhtmln();
  772. if (yydebug || 0) {
  773. printf("%s(): status=%d dp_chkhtmln();\n", __func__, status2);
  774. }
  775. /* check edges with html labels */
  776. /* todo */
  777. if (yydebug || 0) {
  778. printf("%s(): status=%d\n", __func__, status1 + status2);
  779. }
  780. return (status1 + status2);
  781. }
  782. /* parse number, use default at "" string */
  783. struct dpnum *dp_getnum(char *s)
  784. {
  785. struct dpnum *ret = NULL;
  786. double n = 0.0;
  787. char *ep = NULL;
  788. ret = (struct dpnum *)dp_calloc(1, sizeof(struct dpnum));
  789. if (s == NULL) {
  790. /* parse error */
  791. ret->pe = 1;
  792. return (ret);
  793. }
  794. if (strlen(s) == 0) {
  795. ret->es = 1;
  796. /* parse error */
  797. ret->pe = 1;
  798. return (ret);
  799. }
  800. errno = 0;
  801. n = strtod(s, &ep);
  802. if (ep) {
  803. if (strlen(ep)) {
  804. /* parse error */
  805. ret->pe = 1;
  806. return (ret);
  807. }
  808. }
  809. if (errno) {
  810. /* parse error */
  811. ret->pe = 1;
  812. return (ret);
  813. }
  814. /* check for unusual "-0", different languages handle -0 different,
  815. * go language does not implement -0 correctly
  816. * if (n==0){}
  817. */
  818. if (fabs(n) < 0.01) {
  819. if (strchr(s, '-')) {
  820. printf("%s(): number `%s' is negative zero\n", __func__, s);
  821. }
  822. }
  823. ret->number = n;
  824. ret->pe = 0;
  825. ret->es = 0;
  826. return (ret);
  827. }
  828. /* parse int number */
  829. struct dpinum *dp_getinum(char *s)
  830. {
  831. struct dpinum *ret = NULL;
  832. long n = 0;
  833. char *ep = NULL;
  834. ret = (struct dpinum *)dp_calloc(1, sizeof(struct dpinum));
  835. if (s == NULL) {
  836. /* parse error */
  837. ret->pe = 1;
  838. return (ret);
  839. }
  840. if (strlen(s) == 0) {
  841. ret->es = 1;
  842. /* parse error */
  843. ret->pe = 1;
  844. return (ret);
  845. }
  846. errno = 0;
  847. /* base 10 */
  848. n = strtol(s, &ep, 10);
  849. if (ep) {
  850. if (strlen(ep)) {
  851. /* parse error */
  852. ret->pe = 1;
  853. return (ret);
  854. }
  855. }
  856. if (errno) {
  857. /* parse error */
  858. ret->pe = 1;
  859. return (ret);
  860. }
  861. /* check for unusual "-0" */
  862. if (n == 0) {
  863. if (strchr(s, '-')) {
  864. printf("%s(): number `%s' is negative zero\n", __func__, s);
  865. }
  866. }
  867. ret->number = (int)n;
  868. ret->pe = 0;
  869. ret->es = 0;
  870. return (ret);
  871. }
  872. /* parse boolean
  873. * dot accepts also " No " and " Yes " with the spaces,
  874. * this does now accept strings as " true" or " 1 "
  875. */
  876. struct dpbool *dp_getbool(char *s)
  877. {
  878. struct dpbool *ret = NULL;
  879. char *s2 = NULL;
  880. char *p = NULL;
  881. char *q = NULL;
  882. ret = (struct dpbool *)dp_calloc(1, sizeof(struct dpbool));
  883. if (s == NULL) {
  884. /* parse error */
  885. ret->pe = 1;
  886. return (ret);
  887. }
  888. if (strlen(s) == 0) {
  889. /* parse error */
  890. ret->es = 1;
  891. ret->pe = 1;
  892. return (ret);
  893. }
  894. s2 = (char *)dp_calloc(1, (strlen(s) + 1));
  895. /* skip leading spaces */
  896. p = s;
  897. while (*p) {
  898. if (*p != ' ') {
  899. break;
  900. }
  901. p++;
  902. }
  903. /* copy chars until trailing spaces */
  904. q = s2;
  905. while (*p) {
  906. if (*p == ' ') {
  907. break;
  908. }
  909. *q = *p;
  910. p++;
  911. q++;
  912. }
  913. if (strcasecmp(s2, "true") == 0) {
  914. ret->number = 1;
  915. } else if (strcasecmp(s2, "false") == 0) {
  916. ret->number = 0;
  917. } else if (strcasecmp(s2, "1") == 0) {
  918. ret->number = 1;
  919. } else if (strcasecmp(s2, "0") == 0) {
  920. ret->number = 0;
  921. } else if (strcasecmp(s2, "on") == 0) {
  922. ret->number = 1;
  923. } else if (strcasecmp(s2, "off") == 0) {
  924. ret->number = 0;
  925. } else if (strcasecmp(s2, "yes") == 0) {
  926. ret->number = 1;
  927. } else if (strcasecmp(s2, "no") == 0) {
  928. ret->number = 0;
  929. } else {
  930. /* parse error */
  931. ret->pe = 1;
  932. }
  933. s2 = (char *)dp_free((void *)s2);
  934. if (s2) {
  935. }
  936. return (ret);
  937. }
  938. /* parse color */
  939. struct dpcolor *dp_getcolor(int cs, int csnum, char *s)
  940. {
  941. struct dpcolor *ret = NULL;
  942. int tmpi = 0;
  943. ret = (struct dpcolor *)dp_calloc(1, sizeof(struct dpcolor));
  944. if (s == NULL) {
  945. ret->pe = 1;
  946. return (ret);
  947. }
  948. if (strlen(s) == 0) {
  949. ret->pe = 1;
  950. ret->es = 1;
  951. return (ret);
  952. }
  953. if (cs) {
  954. tmpi = dp_findcolor(csnum, s);
  955. } else {
  956. tmpi = dp_findcolor(0, s);
  957. }
  958. if (tmpi == -1) {
  959. ret->pe = 1;
  960. return (ret);
  961. }
  962. if (tmpi == -2) {
  963. ret->islist = 1;
  964. ret->pe = 1;
  965. return (ret);
  966. }
  967. if (tmpi == -3) {
  968. ret->pe = 1;
  969. ret->es = 1;
  970. return (ret);
  971. }
  972. ret->color = tmpi;
  973. return (ret);
  974. }
  975. /* parse style= */
  976. struct dpstyle *dp_getstyle(char *s)
  977. {
  978. struct dpstyle *ret = NULL;
  979. size_t lens = 0;
  980. char *buf = NULL;
  981. char *sep = NULL;
  982. char *token = NULL;
  983. int slwnext = 0;
  984. double n = 0.0;
  985. char *ep = NULL;
  986. ret = (struct dpstyle *)dp_calloc(1, sizeof(struct dpstyle));
  987. if (s == NULL) {
  988. ret->pe = 1;
  989. ret->es = 1;
  990. return (ret);
  991. }
  992. lens = strlen(s);
  993. if (lens == 0) {
  994. ret->pe = 1;
  995. ret->es = 1;
  996. return (ret);
  997. }
  998. /* copy string in tmp buffer */
  999. buf = (char *)dp_calloc(1, (lens + 1));
  1000. strcpy(buf, s);
  1001. /* possible seperators in string */
  1002. sep = dp_uniqstr((char *)",() ");
  1003. slwnext = 0;
  1004. /* strsep() is a replacement for old strtok() */
  1005. token = strtok(buf, sep);
  1006. while (token) {
  1007. if (0) {
  1008. printf("dot %s(): token `%s'\n", __func__, token);
  1009. }
  1010. if (slwnext) {
  1011. /* expect number for setlinewidth */
  1012. errno = 0;
  1013. n = strtod(token, &ep);
  1014. if (ep) {
  1015. if (strlen(ep)) {
  1016. /* parse error on number */
  1017. ret->pe = 1;
  1018. ret->pe_slw = 1;
  1019. break;
  1020. }
  1021. }
  1022. if (errno) {
  1023. /* parse error on number */
  1024. ret->pe = 1;
  1025. ret->pe_slw = 1;
  1026. break;
  1027. }
  1028. if (n < 0) {
  1029. /* parse error on number */
  1030. ret->pe = 1;
  1031. ret->pe_slw = 1;
  1032. break;
  1033. }
  1034. ret->slwset = 1;
  1035. ret->slw = n;
  1036. slwnext = 0;
  1037. } else {
  1038. if (strcasecmp(token, "dashed") == 0) {
  1039. ret->dashed = 1;
  1040. } else if (strcasecmp(token, "dotted") == 0) {
  1041. ret->dotted = 1;
  1042. } else if (strcasecmp(token, "solid") == 0) {
  1043. ret->solid = 1;
  1044. } else if (strcasecmp(token, "invis") == 0) {
  1045. ret->invis = 1;
  1046. } else if (strcasecmp(token, "invisible") == 0) {
  1047. ret->invis = 1;
  1048. } else if (strcasecmp(token, "bold") == 0) {
  1049. ret->bold = 1;
  1050. } else if (strcasecmp(token, "tapered") == 0) {
  1051. ret->tapered = 1;
  1052. } else if (strcasecmp(token, "filled") == 0) {
  1053. ret->filled = 1;
  1054. } else if (strcasecmp(token, "striped") == 0) {
  1055. ret->striped = 1;
  1056. } else if (strcasecmp(token, "wedged") == 0) {
  1057. ret->wedged = 1;
  1058. } else if (strcasecmp(token, "diagonals") == 0) {
  1059. ret->diagonals = 1;
  1060. } else if (strcasecmp(token, "rounded") == 0) {
  1061. ret->rounded = 1;
  1062. } else if (strcasecmp(token, "radial") == 0) {
  1063. ret->radial = 1;
  1064. } else if (strncmp(token, "setlinewidth", 12) == 0) {
  1065. printf("dot %s(): setlinewidth is depreciated, use penwidth instead\n", __func__);
  1066. /* next token must be the number */
  1067. slwnext = 1;
  1068. } else {
  1069. /* something else */
  1070. ret->unknown = dp_uniqstr(token);
  1071. ret->pe = 1;
  1072. ret->pe_unk = 1;
  1073. break;
  1074. }
  1075. }
  1076. token = strtok(NULL, sep);
  1077. }
  1078. /* check for missing number for setlinewidth as last item */
  1079. if (slwnext) {
  1080. ret->pe_exp = 1;
  1081. ret->pe = 1;
  1082. }
  1083. buf = (char *)dp_free((void *)buf);
  1084. if (buf) {
  1085. }
  1086. return (ret);
  1087. }
  1088. /* point (x,y) with optional '!' flag */
  1089. /* neato: if dim=3 is set point can also be %f,%f,%f for (x,y,z) */
  1090. struct dppoint *dp_getpoint(char *s)
  1091. {
  1092. struct dppoint *ret = NULL;
  1093. char *str = NULL;
  1094. int f = 0;
  1095. int n = 0;
  1096. float x = 0.0;
  1097. float y = 0.0;
  1098. ret = (struct dppoint *)dp_calloc(1, sizeof(struct dppoint));
  1099. if (s == NULL) {
  1100. ret->pe = 1;
  1101. return (ret);
  1102. }
  1103. if (strlen(s) == 0) {
  1104. ret->pe = 1;
  1105. return (ret);
  1106. }
  1107. str = (char *)dp_calloc(1, (strlen(s) + 1));
  1108. strcpy(str, s);
  1109. /* if last char is '!' set the flag and erase the '!' from the string */
  1110. if (str[strlen(s) - 1] == '!') {
  1111. f = 1;
  1112. str[strlen(s) - 1] = 0;
  1113. } else {
  1114. f = 0;
  1115. }
  1116. /* in neato data and dim=3 it can be x,y,z */
  1117. errno = 0;
  1118. if (strchr(str, ',')) {
  1119. n = sscanf(str, "%f,%f", &x, &y);
  1120. } else {
  1121. n = sscanf(str, "%f %f", &x, &y);
  1122. }
  1123. if (n != 2 || errno != 0) {
  1124. ret->pe = 1;
  1125. } else {
  1126. ret->flag = f;
  1127. ret->x = x;
  1128. ret->y = y;
  1129. }
  1130. str = (char *)dp_free((void *)str);
  1131. if (str) {
  1132. }
  1133. return (ret);
  1134. }
  1135. /* get rect %f,%f,%f,%f */
  1136. struct dprect *dp_getrect(char *s)
  1137. {
  1138. struct dprect *ret = NULL;
  1139. float x0 = 0;
  1140. float y0 = 0;
  1141. float x1 = 0;
  1142. float y1 = 0;
  1143. int n = 0;
  1144. ret = (struct dprect *)dp_calloc(1, sizeof(struct dprect));
  1145. if (strlen(s) == 0) {
  1146. ret->pe = 1;
  1147. ret->es = 1;
  1148. return (ret);
  1149. }
  1150. errno = 0;
  1151. /* try ',' or ' ' as sep. char */
  1152. if (strchr(s, ',')) {
  1153. n = sscanf(s, "%f,%f,%f,%f", &x0, &y0, &x1, &y1);
  1154. } else {
  1155. /* assume sep. char is a ' ' space */
  1156. n = sscanf(s, "%f %f %f %f", &x0, &y0, &x1, &y1);
  1157. }
  1158. if (n != 4 || errno != 0) {
  1159. /* some parse error */
  1160. ret->pe = 1;
  1161. } else {
  1162. /* oke */
  1163. ret->x0 = x0;
  1164. ret->y0 = y0;
  1165. ret->x1 = x1;
  1166. ret->y1 = y1;
  1167. }
  1168. return (ret);
  1169. }
  1170. /* clusterrank value */
  1171. int dp_getclrank(char *s)
  1172. {
  1173. int ret = 0;
  1174. if (s == NULL) {
  1175. return (0);
  1176. }
  1177. if (strlen(s) == 0) {
  1178. return (0);
  1179. }
  1180. if (strcasecmp(s, "local") == 0) {
  1181. ret = 0;
  1182. } else if (strcasecmp(s, "global") == 0) {
  1183. ret = 1;
  1184. } else if (strcasecmp(s, "none") == 0) {
  1185. ret = 2;
  1186. } else {
  1187. ret = -1;
  1188. }
  1189. return (ret);
  1190. }
  1191. /* margin %f,%f or %f */
  1192. struct dpmargin *dp_getmargin(char *s)
  1193. {
  1194. struct dpmargin *ret = NULL;
  1195. float x = 0;
  1196. float y = 0;
  1197. int n = 0;
  1198. ret = (struct dpmargin *)dp_calloc(1, sizeof(struct dpmargin));
  1199. if (strlen(s) == 0) {
  1200. ret->pe = 1;
  1201. ret->es = 1;
  1202. return (ret);
  1203. }
  1204. errno = 0;
  1205. /* try ',' or ' ' as sep. char */
  1206. if (strchr(s, ',')) {
  1207. n = sscanf(s, "%f,%f", &x, &y);
  1208. } else {
  1209. n = sscanf(s, "%f %f", &x, &y);
  1210. }
  1211. if (errno) {
  1212. ret->pe = 1;
  1213. } else {
  1214. if (n == 1) {
  1215. ret->x = x;
  1216. ret->y = x;
  1217. } else if (n == 2) {
  1218. ret->x = x;
  1219. ret->y = y;
  1220. } else {
  1221. ret->pe = 1;
  1222. }
  1223. }
  1224. return (ret);
  1225. }
  1226. /* outputorder */
  1227. struct dpoo *dp_getoo(char *s)
  1228. {
  1229. struct dpoo *ret = NULL;
  1230. ret = (struct dpoo *)dp_calloc(1, sizeof(struct dpoo));
  1231. if (s == NULL) {
  1232. ret->pe = 1;
  1233. return (ret);
  1234. }
  1235. if (strlen(s) == 0) {
  1236. ret->pe = 1;
  1237. ret->es = 1;
  1238. return (ret);
  1239. }
  1240. if (strcasecmp(s, "breadthfirst") == 0) {
  1241. ret->mode = DP_OO_BF;
  1242. } else if (strcasecmp(s, "nodesfirst") == 0) {
  1243. ret->mode = DP_OO_NF;
  1244. } else if (strcasecmp(s, "edgesfirst") == 0) {
  1245. ret->mode = DP_OO_EF;
  1246. } else {
  1247. ret->pe = 1;
  1248. }
  1249. return (ret);
  1250. }
  1251. /* rank */
  1252. struct dprank *dp_getrank(char *s)
  1253. {
  1254. struct dprank *ret = NULL;
  1255. ret = (struct dprank *)dp_calloc(1, sizeof(struct dprank));
  1256. if (s == NULL) {
  1257. ret->pe = 1;
  1258. return (ret);
  1259. }
  1260. if (strlen(s) == 0) {
  1261. ret->pe = 1;
  1262. ret->es = 1;
  1263. return (ret);
  1264. }
  1265. /* added: rank=none */
  1266. if (strcasecmp(s, "same") == 0) {
  1267. ret->mode = DP_RANK_SAME;
  1268. } else if (strcasecmp(s, "none") == 0) {
  1269. ret->mode = DP_RANK_NONE;
  1270. } else if (strcasecmp(s, "min") == 0) {
  1271. ret->mode = DP_RANK_MIN;
  1272. } else if (strcasecmp(s, "source") == 0) {
  1273. ret->mode = DP_RANK_SRC;
  1274. } else if (strcasecmp(s, "max") == 0) {
  1275. ret->mode = DP_RANK_MAX;
  1276. } else if (strcasecmp(s, "sink") == 0) {
  1277. ret->mode = DP_RANK_SINK;
  1278. } else {
  1279. ret->pe = 1;
  1280. }
  1281. return (ret);
  1282. }
  1283. /* rankdir */
  1284. struct dprankdir *dp_getrankdir(char *s)
  1285. {
  1286. struct dprankdir *ret = NULL;
  1287. ret = (struct dprankdir *)dp_calloc(1, sizeof(struct dprankdir));
  1288. if (s == NULL) {
  1289. ret->pe = 1;
  1290. return (ret);
  1291. }
  1292. if (strlen(s) == 0) {
  1293. ret->pe = 1;
  1294. ret->es = 1;
  1295. return (ret);
  1296. }
  1297. if (strcasecmp(s, "tb") == 0) {
  1298. ret->mode = DP_RANKDIR_TB;
  1299. } else if (strcasecmp(s, "lr") == 0) {
  1300. ret->mode = DP_RANKDIR_LR;
  1301. } else if (strcasecmp(s, "bt") == 0) {
  1302. ret->mode = DP_RANKDIR_BT;
  1303. } else if (strcasecmp(s, "rl") == 0) {
  1304. ret->mode = DP_RANKDIR_RL;
  1305. } else {
  1306. ret->pe = 1;
  1307. }
  1308. return (ret);
  1309. }
  1310. /* ranksep */
  1311. struct dpranksep *dp_getranksep(char *s)
  1312. {
  1313. struct dpranksep *ret = NULL;
  1314. float f = 0;
  1315. int n = 0;
  1316. ret = (struct dpranksep *)dp_calloc(1, sizeof(struct dpranksep));
  1317. if (s == NULL) {
  1318. ret->pe = 1;
  1319. return (ret);
  1320. }
  1321. if (strlen(s) == 0) {
  1322. ret->pe = 1;
  1323. ret->es = 1;
  1324. return (ret);
  1325. }
  1326. errno = 0;
  1327. n = sscanf(s, "%f", &f);
  1328. if (errno) {
  1329. ret->pe = 1;
  1330. return (ret);
  1331. }
  1332. if (n == 1) {
  1333. ret->number = (double)f;
  1334. return (ret);
  1335. }
  1336. errno = 0;
  1337. n = sscanf(s, "%f equally", &f);
  1338. if (errno) {
  1339. ret->pe = 1;
  1340. return (ret);
  1341. }
  1342. if (n == 1) {
  1343. ret->number = (double)f;
  1344. ret->eq = 1;
  1345. return (ret);
  1346. }
  1347. ret->pe = 1;
  1348. return (ret);
  1349. }
  1350. /* ratio */
  1351. struct dpratio *dp_getratio(char *s)
  1352. {
  1353. struct dpratio *ret = NULL;
  1354. float f = 0;
  1355. int n = 0;
  1356. ret = (struct dpratio *)dp_calloc(1, sizeof(struct dpratio));
  1357. if (s == NULL) {
  1358. ret->pe = 1;
  1359. return (ret);
  1360. }
  1361. if (strlen(s) == 0) {
  1362. ret->es = 1;
  1363. ret->pe = 1;
  1364. return (ret);
  1365. }
  1366. if (strcasecmp(s, "fill") == 0) {
  1367. ret->mode = DP_RATIO_FILL;
  1368. } else if (strcasecmp(s, "compress") == 0) {
  1369. ret->mode = DP_RATIO_COM;
  1370. } else if (strcasecmp(s, "expand") == 0) {
  1371. ret->mode = DP_RATIO_EXP;
  1372. } else if (strcasecmp(s, "auto") == 0) {
  1373. ret->mode = DP_RATIO_AUTO;
  1374. } else {
  1375. ret->mode = 0;
  1376. }
  1377. if (ret->mode) {
  1378. return (ret);
  1379. }
  1380. errno = 0;
  1381. n = sscanf(s, "%f", &f);
  1382. if (errno) {
  1383. ret->pe = 1;
  1384. return (ret);
  1385. }
  1386. if (n == 1) {
  1387. ret->number = f;
  1388. } else {
  1389. ret->pe = 1;
  1390. }
  1391. return (ret);
  1392. }
  1393. /* splines */
  1394. struct dpsplines *dp_getsplines(char *s)
  1395. {
  1396. struct dpsplines *ret = NULL;
  1397. ret = (struct dpsplines *)dp_calloc(1, sizeof(struct dpsplines));
  1398. if (s == NULL) {
  1399. ret->pe = 1;
  1400. return (ret);
  1401. }
  1402. if (strlen(s) == 0) {
  1403. ret->mode = DP_SPLINE_NONE;
  1404. return (ret);
  1405. }
  1406. if (strcasecmp(s, "none") == 0) {
  1407. ret->mode = DP_SPLINE_NONE;
  1408. } else if (strcasecmp(s, "line") == 0) {
  1409. ret->mode = DP_SPLINE_LINE;
  1410. } else if (strcasecmp(s, "false") == 0) {
  1411. ret->mode = DP_SPLINE_LINE;
  1412. } else if (strcasecmp(s, "polyline") == 0) {
  1413. ret->mode = DP_SPLINE_POLY;
  1414. } else if (strcasecmp(s, "curved") == 0) {
  1415. ret->mode = DP_SPLINE_CURVED;
  1416. } else if (strcasecmp(s, "ortho") == 0) {
  1417. ret->mode = DP_SPLINE_ORTHO;
  1418. } else if (strcasecmp(s, "spline") == 0) {
  1419. ret->mode = DP_SPLINE_SPLINE;
  1420. } else if (strcasecmp(s, "true") == 0) {
  1421. ret->mode = DP_SPLINE_SPLINE;
  1422. } else {
  1423. ret->pe = 1;
  1424. }
  1425. return (ret);
  1426. }
  1427. /* end */