gvgen.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * @file
  3. * @brief generate graphs
  4. */
  5. /*************************************************************************
  6. * Copyright (c) 2011 AT&T Intellectual Property
  7. * All rights reserved. This program and the accompanying materials
  8. * are made available under the terms of the Eclipse Public License v1.0
  9. * which accompanies this distribution, and is available at
  10. * https://www.eclipse.org/legal/epl-v10.html
  11. *
  12. * Contributors: Details at https://graphviz.org
  13. *************************************************************************/
  14. /*
  15. * Written by Emden Gansner
  16. */
  17. #include "config.h"
  18. #include <limits.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <getopt.h>
  24. #include "graph_generator.h"
  25. #include "openFile.h"
  26. #include <util/exit.h>
  27. typedef enum { unknown, grid, circle, complete, completeb,
  28. path, tree, torus, cylinder, mobius, randomg, randomt, ball,
  29. sierpinski, hypercube, star, wheel, trimesh
  30. } GraphType;
  31. typedef struct {
  32. unsigned graphSize1;
  33. unsigned graphSize2;
  34. unsigned cnt;
  35. unsigned parm1;
  36. unsigned parm2;
  37. int Verbose;
  38. int isPartial;
  39. int foldVal;
  40. int directed;
  41. FILE *outfile;
  42. char* pfx;
  43. char* name;
  44. } opts_t;
  45. static char *cmd;
  46. static char *Usage = "Usage: %s [-dv?] [options]\n\
  47. -c<n> : cycle \n\
  48. -C<x,y> : cylinder \n\
  49. -g[f]<h,w> : grid (folded if f is used)\n\
  50. -G[f]<h,w> : partial grid (folded if f is used)\n\
  51. -h<x> : hypercube \n\
  52. -k<x> : complete \n\
  53. -b<x,y> : complete bipartite\n\
  54. -B<x,y> : ball\n\
  55. -i<n> : generate <n> random\n\
  56. -m<x> : triangular mesh\n\
  57. -M<x,y> : x by y Moebius strip\n\
  58. -n<prefix> : use <prefix> in node names (\"\")\n\
  59. -N<name> : use <name> for the graph (\"\")\n\
  60. -o<outfile> : put output in <outfile> (stdout)\n\
  61. -p<x> : path \n\
  62. -r<x>,<n> : random graph\n\
  63. -R<n> : random rooted tree on <n> vertices\n\
  64. -s<x> : star\n\
  65. -S<x> : 2D sierpinski\n\
  66. -S<x>,<d> : <d>D sierpinski (<d> = 2,3)\n\
  67. -t<x> : binary tree \n\
  68. -t<x>,<n> : n-ary tree \n\
  69. -T<x,y> : torus \n\
  70. -T<x,y,t1,t2> : twisted torus \n\
  71. -w<x> : wheel\n\
  72. -d : directed graph\n\
  73. -v : verbose mode\n\
  74. -? : print usage\n";
  75. static void usage(int v)
  76. {
  77. fprintf(v ? stderr : stdout, Usage, cmd);
  78. graphviz_exit(v);
  79. }
  80. static void errexit(int opt) {
  81. fprintf(stderr, "in flag -%c\n", (char)opt);
  82. usage(1);
  83. }
  84. /* readPos:
  85. * Read and return a single unsigned int from s, guaranteed to be >= 1.
  86. * A pointer to the next available character from s is stored in e.
  87. * Return 0 on error.
  88. */
  89. static unsigned readPos(char *s, char **e) {
  90. static const unsigned MIN = 1;
  91. const unsigned long d = strtoul(s, e, 10);
  92. if (s == *e || d > UINT_MAX) {
  93. fprintf(stderr, "ill-formed integer \"%s\" ", s);
  94. return 0;
  95. }
  96. if (d < MIN) {
  97. fprintf(stderr, "integer \"%s\" less than %d", s, MIN);
  98. return 0;
  99. }
  100. return (unsigned)d;
  101. }
  102. /* readOne:
  103. * Return non-zero on error.
  104. */
  105. static int readOne(char *s, unsigned *ip) {
  106. const unsigned d = readPos(s, &(char *){NULL});
  107. if (d > 0) {
  108. *ip = d;
  109. return 0;
  110. }
  111. return -1;
  112. }
  113. /* setOne:
  114. * Return non-zero on error.
  115. */
  116. static int setOne(char *s, opts_t* opts)
  117. {
  118. return readOne(s, &opts->graphSize1);
  119. }
  120. /* setTwo:
  121. * Return non-zero on error.
  122. */
  123. static int setTwo(char *s, opts_t* opts)
  124. {
  125. char *next;
  126. unsigned d = readPos(s, &next);
  127. if (d == 0)
  128. return -1;
  129. opts->graphSize1 = d;
  130. if (*next != ',') {
  131. fprintf(stderr, "ill-formed int pair \"%s\" ", s);
  132. return -1;
  133. }
  134. s = next + 1;
  135. d = readPos(s, &(char *){NULL});
  136. if (d > 1) {
  137. opts->graphSize2 = d;
  138. return 0;
  139. }
  140. return -1;
  141. }
  142. /* setTwoTwoOpt:
  143. * Read 2 numbers
  144. * Read 2 more optional numbers
  145. * Return non-zero on error.
  146. */
  147. static int setTwoTwoOpt(char *s, opts_t *opts, unsigned dflt) {
  148. char *next;
  149. unsigned d = readPos(s, &next);
  150. if (d == 0)
  151. return -1;
  152. opts->graphSize1 = d;
  153. if (*next != ',') {
  154. fprintf(stderr, "ill-formed int pair \"%s\" ", s);
  155. return -1;
  156. }
  157. s = next + 1;
  158. d = readPos(s, &next);
  159. if (d == 0) {
  160. return 0;
  161. }
  162. opts->graphSize2 = d;
  163. if (*next != ',') {
  164. opts->parm1 = opts->parm2 = dflt;
  165. return 0;
  166. }
  167. s = next + 1;
  168. d = readPos(s, &next);
  169. if (d == 0)
  170. return -1;
  171. opts->parm1 = d;
  172. if (*next != ',') {
  173. opts->parm2 = dflt;
  174. return 0;
  175. }
  176. s = next + 1;
  177. return readOne(s, &opts->parm2);
  178. }
  179. /* setTwoOpt:
  180. * Return non-zero on error.
  181. */
  182. static int setTwoOpt(char *s, opts_t *opts, unsigned dflt) {
  183. char *next;
  184. unsigned d = readPos(s, &next);
  185. if (d == 0)
  186. return -1;
  187. opts->graphSize1 = d;
  188. if (*next != ',') {
  189. opts->graphSize2 = dflt;
  190. return 0;
  191. }
  192. s = next + 1;
  193. d = readPos(s, &(char *){NULL});
  194. if (d > 1) {
  195. opts->graphSize2 = d;
  196. return 0;
  197. }
  198. return -1;
  199. }
  200. static char* setFold(char *s, opts_t* opts)
  201. {
  202. char *next;
  203. if (*s == 'f') {
  204. next = s+1;
  205. opts->foldVal = 1;
  206. }
  207. else
  208. next = s;
  209. return next;
  210. }
  211. static char *optList = ":i:M:m:n:N:c:C:dg:G:h:k:b:B:o:p:r:R:s:S:X:t:T:vw:";
  212. static GraphType init(int argc, char *argv[], opts_t* opts)
  213. {
  214. int c;
  215. GraphType graphType = unknown;
  216. cmd = argv[0];
  217. opterr = 0;
  218. while ((c = getopt(argc, argv, optList)) != -1) {
  219. switch (c) {
  220. case 'c':
  221. graphType = circle;
  222. if (setOne(optarg, opts))
  223. errexit(c);
  224. break;
  225. case 'C':
  226. graphType = cylinder;
  227. if (setTwo(optarg, opts))
  228. errexit(c);
  229. break;
  230. case 'M':
  231. graphType = mobius;
  232. if (setTwo(optarg, opts))
  233. errexit(c);
  234. break;
  235. case 'd':
  236. opts->directed = 1;
  237. break;
  238. case 'G':
  239. opts->isPartial = 1;
  240. // fall through
  241. case 'g':
  242. graphType = grid;
  243. optarg = setFold (optarg, opts);
  244. if (setTwo(optarg, opts))
  245. errexit(c);
  246. break;
  247. case 'h':
  248. graphType = hypercube;
  249. if (setOne(optarg, opts))
  250. errexit(c);
  251. break;
  252. case 'k':
  253. graphType = complete;
  254. if (setOne(optarg, opts))
  255. errexit(c);
  256. break;
  257. case 'b':
  258. graphType = completeb;
  259. if (setTwo(optarg, opts))
  260. errexit(c);
  261. break;
  262. case 'B':
  263. graphType = ball;
  264. if (setTwo(optarg, opts))
  265. errexit(c);
  266. break;
  267. case 'm':
  268. graphType = trimesh;
  269. if (setOne(optarg, opts))
  270. errexit(c);
  271. break;
  272. case 'r':
  273. graphType = randomg;
  274. if (setTwo(optarg, opts))
  275. errexit(c);
  276. break;
  277. case 'R':
  278. graphType = randomt;
  279. if (setOne(optarg, opts))
  280. errexit(c);
  281. break;
  282. case 'n':
  283. opts->pfx = optarg;
  284. break;
  285. case 'N':
  286. opts->name = optarg;
  287. break;
  288. case 'o':
  289. opts->outfile = openFile(cmd, optarg, "w");
  290. break;
  291. case 'p':
  292. graphType = path;
  293. if (setOne(optarg, opts))
  294. errexit(c);
  295. break;
  296. case 'S':
  297. graphType = sierpinski;
  298. if (setTwoOpt(optarg, opts, 2))
  299. errexit(c);
  300. if (opts->graphSize2 > 3) {
  301. fprintf(stderr, "%uD Sierpinski not implemented - use 2 or 3 ",
  302. opts->graphSize2);
  303. errexit(c);
  304. }
  305. break;
  306. case 's':
  307. graphType = star;
  308. if (setOne(optarg, opts))
  309. errexit(c);
  310. break;
  311. case 't':
  312. graphType = tree;
  313. if (setTwoOpt(optarg, opts, 2))
  314. errexit(c);
  315. break;
  316. case 'T':
  317. graphType = torus;
  318. if (setTwoTwoOpt(optarg, opts, 0))
  319. errexit(c);
  320. break;
  321. case 'i':
  322. if (readOne(optarg, &opts->cnt))
  323. errexit(c);
  324. break;
  325. case 'v':
  326. opts->Verbose = 1;
  327. break;
  328. case 'w':
  329. graphType = wheel;
  330. if (setOne(optarg, opts))
  331. errexit(c);
  332. break;
  333. case '?':
  334. if (optopt == '?')
  335. usage(0);
  336. else
  337. fprintf(stderr, "Unrecognized flag \"-%c\" - ignored\n",
  338. optopt);
  339. break;
  340. default:
  341. fprintf(stderr, "Unexpected error\n");
  342. usage(EXIT_FAILURE);
  343. }
  344. }
  345. argc -= optind;
  346. argv += optind;
  347. if (!opts->outfile)
  348. opts->outfile = stdout;
  349. if (graphType == unknown) {
  350. fprintf(stderr, "Graph type not set\n");
  351. usage(1);
  352. }
  353. return graphType;
  354. }
  355. static opts_t opts;
  356. static void dirfn(unsigned t, unsigned h) {
  357. if (h > 0)
  358. fprintf(opts.outfile, " %s%u -> %s%u\n", opts.pfx, t, opts.pfx, h);
  359. else
  360. fprintf(opts.outfile, " %s%u\n", opts.pfx, t);
  361. }
  362. static void undirfn(unsigned t, unsigned h) {
  363. if (h > 0)
  364. fprintf(opts.outfile, " %s%u -- %s%u\n", opts.pfx, t, opts.pfx, h);
  365. else
  366. fprintf(opts.outfile, " %s%u\n", opts.pfx, t);
  367. }
  368. static void
  369. closeOpen (void)
  370. {
  371. if (opts.directed)
  372. fprintf(opts.outfile, "}\ndigraph {\n");
  373. else
  374. fprintf(opts.outfile, "}\ngraph {\n");
  375. }
  376. int main(int argc, char *argv[])
  377. {
  378. GraphType graphType;
  379. edgefn ef;
  380. opts.pfx = "";
  381. opts.name = "";
  382. opts.cnt = 1;
  383. graphType = init(argc, argv, &opts);
  384. if (opts.directed) {
  385. fprintf(opts.outfile, "digraph %s{\n", opts.name);
  386. ef = dirfn;
  387. }
  388. else {
  389. fprintf(opts.outfile, "graph %s{\n", opts.name);
  390. ef = undirfn;
  391. }
  392. switch (graphType) {
  393. case grid:
  394. makeSquareGrid(opts.graphSize1, opts.graphSize2,
  395. opts.foldVal, opts.isPartial, ef);
  396. break;
  397. case circle:
  398. makeCircle(opts.graphSize1, ef);
  399. break;
  400. case path:
  401. makePath(opts.graphSize1, ef);
  402. break;
  403. case tree:
  404. if (opts.graphSize2 == 2)
  405. makeBinaryTree(opts.graphSize1, ef);
  406. else
  407. makeTree(opts.graphSize1, opts.graphSize2, ef);
  408. break;
  409. case trimesh:
  410. makeTriMesh(opts.graphSize1, ef);
  411. break;
  412. case ball:
  413. makeBall(opts.graphSize1, opts.graphSize2, ef);
  414. break;
  415. case torus:
  416. if (opts.parm1 == 0 && opts.parm2 == 0)
  417. makeTorus(opts.graphSize1, opts.graphSize2, ef);
  418. else
  419. makeTwistedTorus(opts.graphSize1, opts.graphSize2, opts.parm1, opts.parm2, ef);
  420. break;
  421. case cylinder:
  422. makeCylinder(opts.graphSize1, opts.graphSize2, ef);
  423. break;
  424. case mobius:
  425. makeMobius(opts.graphSize1, opts.graphSize2, ef);
  426. break;
  427. case sierpinski:
  428. if (opts.graphSize2 == 2)
  429. makeSierpinski(opts.graphSize1, ef);
  430. else
  431. makeTetrix(opts.graphSize1, ef);
  432. break;
  433. case complete:
  434. makeComplete(opts.graphSize1, ef);
  435. break;
  436. case randomg:
  437. makeRandom (opts.graphSize1, opts.graphSize2, ef);
  438. break;
  439. case randomt:
  440. {
  441. treegen_t* tg = makeTreeGen (opts.graphSize1);
  442. for (unsigned i = 1; i <= opts.cnt; i++) {
  443. makeRandomTree (tg, ef);
  444. if (i != opts.cnt) closeOpen ();
  445. }
  446. freeTreeGen (tg);
  447. }
  448. makeRandom (opts.graphSize1, opts.graphSize2, ef);
  449. break;
  450. case completeb:
  451. makeCompleteB(opts.graphSize1, opts.graphSize2, ef);
  452. break;
  453. case hypercube:
  454. makeHypercube(opts.graphSize1, ef);
  455. break;
  456. case star:
  457. makeStar(opts.graphSize1, ef);
  458. break;
  459. case wheel:
  460. makeWheel(opts.graphSize1, ef);
  461. break;
  462. default:
  463. /* can't happen */
  464. break;
  465. }
  466. fprintf(opts.outfile, "}\n");
  467. graphviz_exit(0);
  468. }