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