1GVPR(1) General Commands Manual GVPR(1)
2
3
4
6 gvpr - graph pattern scanning and processing language
7 ( previously known as gpr )
8
10 gvpr [-icV?] [ -o outfile ] [ -a args ] [ 'prog' | -f progfile ] [
11 files ]
12
14 gvpr is a graph stream editor inspired by awk. It copies input graphs
15 to its output, possibly transforming their structure and attributes,
16 creating new graphs, or printing arbitrary information. The graph
17 model is that provided by libagraph(3). In particular, gvpr reads and
18 writes graphs using the dot language.
19
20 Basically, gvpr traverses each input graph, denoted by $G, visiting
21 each node and edge, matching it with the predicate-action rules sup‐
22 plied in the input program. The rules are evaluated in order. For
23 each predicate evaluating to true, the corresponding action is per‐
24 formed. During the traversal, the current node or edge being visited
25 is denoted by $.
26
27 For each input graph, there is a target subgraph, denoted by $T, ini‐
28 tially empty and used to accumulate chosen entities, and an output
29 graph, $O, used for final processing and then written to output. By
30 default, the output graph is the target graph. The output graph can be
31 set in the program or, in a limited sense, on the command line.
32
34 The following options are supported:
35
36 -a args
37 The string args is split into whitespace-separated tokens, with
38 the individual tokens available as strings in the gvpr program
39 as ARGV[0],...,ARGV[ARGC-1]. Whitespace characters within sin‐
40 gle or double quoted substrings, or preceded by a backslash, are
41 ignored as separators. In general, a backslash character turns
42 off any special meaning of the following character. Note that
43 the tokens derived from multiple -a flags are concatenated.
44
45 -c Use the source graph as the output graph.
46
47 -i Derive the node-induced subgraph extension of the output graph
48 in the context of its root graph.
49
50 -o outfile
51 Causes the output stream to be written to the specified file; by
52 default, output is written to stdout.
53
54 -f progfile
55 Use the contents of the specified file as the program to execute
56 on the input. If progfile contains a slash character, the name
57 is taken as the pathname of the file. Otherwise, gvpr will use
58 the directories specified in the environment variable GPRPATH to
59 look for the file. If -f is not given, gvpr will use the first
60 non-option argument as the program.
61
62 -V Causes the program to print version information and exit.
63
64 -? Causes the program to print usage information and exit.
65
67 The following operand is supported:
68
69 files Names of files containing 1 or more graphs in the dot language.
70 If no -f option is given, the first name is removed from the
71 list and used as the input program. If the list of files is
72 empty, stdin will be used.
73
75 A gvpr program consists of a list of predicate-action clauses, having
76 one of the forms:
77
78 BEGIN { action }
79
80 BEG_G { action }
81
82 N [ predicate ] { action }
83
84 E [ predicate ] { action }
85
86 END_G { action }
87
88 END { action }
89
90 A program can contain at most one of each of the BEGIN, BEG_G, END_G
91 and END clauses. There can be any number of N and E statements, the
92 first applied to nodes, the second to edges. The top-level semantics
93 of a gvpr program are:
94
95 Evaluate the BEGIN clause, if any.
96 For each input graph G {
97 Set G as the current graph and current object.
98 Evaluate the BEG_G clause, if any.
99 For each node and edge in G {
100 Set the node or edge as the current object.
101 Evaluate the N or E clauses, as appropriate.
102 }
103 Set G as the current object.
104 Evaluate the END_G clause, if any.
105 }
106 Evaluate the END clause, if any.
107
108 The actions of the BEGIN, BEG_G, END_G and END clauses are performed
109 when the clauses are evaluated. For N or E clauses, either the predi‐
110 cate or action may be omitted. If there is no predicate with an
111 action, the action is performed on every node or edge, as appropriate.
112 If there is no action and the predicate evaluates to true, the associ‐
113 ated node or edge is added to the target graph.
114
115 Predicates and actions are sequences of statements in the C dialect
116 supported by the libexpr(3) library. The only difference between pred‐
117 icates and actions is that the former must have a type that may inter‐
118 preted as either true or false. Here the usual C convention is fol‐
119 lowed, in which a non-zero value is considered true. This would include
120 non-empty strings and non-empty references to nodes, edges, etc. How‐
121 ever, if a string can be converted to an integer, this value is used.
122
123 In addition to the usual C base types (void, int, char, float, long,
124 unsigned and double), gvpr provides string as a synonym for char*, and
125 the graph-based types node_t, edge_t, graph_t and obj_t. The obj_t
126 type can be viewed as a supertype of the other 3 concrete types; the
127 correct base type is maintained dynamically. Besides these base types,
128 the only other supported type expressions are (associative) arrays.
129
130 Constants follow C syntax, but strings may be quoted with either "..."
131 or '...'. In certain contexts, string values are interpreted as pat‐
132 terns for the purpose of regular expression matching. Patterns use
133 ksh(1) file match pattern syntax. gvpr accepts C++ comments as well as
134 cpp-type comments. For the latter, if a line begins with a '#' charac‐
135 ter, the rest of the line is ignored.
136
137 A statement can be a declaration of a function, a variable or an array,
138 or an executable statement. For declarations, there is a single scope.
139 Array declarations have the form:
140
141 type array [ var ]
142
143 where the var is optional. As in C, variables and arrays must be
144 declared. In particular, an undeclared variable will be interpreted as
145 the name of an attribute of a node, edge or graph, depending on the
146 context.
147
148 Executable statements can be one of the following:
149 { [ statement ... ] }
150 expression // commonly var = expression
151 if( expression ) statement [ else statement ]
152 for( expression ; expression ; expression ) statement
153 for( array [ var ]) statement
154 while( expression ) statement
155 switch( expression ) case statements
156 break [ expression ]
157 continue [ expression ]
158 return [ expression ]
159 Items in brackets are optional.
160
161 In the second form of the for statement, the variable var is set to
162 each value used as an index in the specified array and then the associ‐
163 ated statement is evaluated. Function definitions can only appear in
164 the BEGIN clause.
165
166 Expressions include the usual C expressions. String comparisons using
167 == and != treat the right hand operand as a pattern. gvpr will attempt
168 to use an expression as a string or numeric value as appropriate.
169
170 Expressions of graphical type (i.e., graph_t, node_t, edge_t, obj_t)
171 may be followed by a field reference in the form of .name. The result‐
172 ing value is the value of the attribute named name of the given object.
173 In addition, in certain contexts an undeclared, unmodified identifier
174 is taken to be an attribute name. Specifically, such identifiers denote
175 attributes of the current node or edge, respectively, in N and E
176 clauses, and the current graph in BEG_G and END_G clauses.
177
178 As usual in the libagraph(3) model, attributes are string-valued. In
179 addition, gvpr supports certain pseudo-attributes of graph objects, not
180 necessarily string-valued. These reflect intrinsic properties of the
181 graph objects and cannot be set by the user.
182
183 head : node_t
184 the head of an edge.
185
186 tail : node_t
187 the tail of an edge.
188
189 name : string
190 the name of an edge, node or graph. The name of an edge has the
191 form "<tail-name><edge-op><head-name>[<key>]", where <edge-op>
192 is "->" or "--" depending on whether the graph is directed or
193 not. The bracket part [<key>] only appears if the edge has a
194 non-trivial key.
195
196 indegree : int
197 the indegree of a node.
198
199 outdegree : int
200 the outdegree of a node.
201
202 degree : int
203 the degree of a node.
204
205 root : graph_t
206 the root graph of an object. The root of a root graph is itself.
207
208 parent : graph_t
209 the parent graph of a subgraph. The parent of a root graph is
210 NULL
211
212 n_edges : int
213 the number of edges in the graph
214
215 n_nodes : int
216 the number of nodes in the graph
217
218 directed : int
219 true (non-zero) if the graph is directed
220
221 strict : int
222 true (non-zero) if the graph is strict
223
225 The following functions are built into gvpr. Those functions returning
226 references to graph objects return NULL in case of failure.
227
228 Graphs and subgraph
229 graph(s : string, t : string) : graph_t
230 creates a graph whose name is s and whose type is specified by
231 the string t. Ignoring case, the characters U, D, S, N have the
232 interpretation undirected, directed, strict, and non-strict,
233 respectively. If t is empty, a directed, non-strict graph is
234 generated.
235
236 subg(g : graph_t, s : string) : graph_t
237 creates a subgraph in graph g with name s. If the subgraph
238 already exists, it is returned.
239
240 isSubg(g : graph_t, s : string) : graph_t
241 returns the subgraph in graph g with name s, if it exists, or
242 NULL otherwise.
243
244 fstsubg(g : graph_t) : graph_t
245 returns the first subgraph in graph g, or NULL if none exists.
246
247 nxtsubg(sg : graph_t) : graph_t
248 returns the next subgraph after sg, or NULL.
249
250 isDirect(g : graph_t) : int
251 returns true if and only if g is directed.
252
253 isStrict(g : graph_t) : int
254 returns true if and only if g is strict.
255
256 nNodes(g : graph_t) : int
257 returns the number of nodes in g.
258
259 nEdges(g : graph_t) : int
260 returns the number of edges in g.
261
262 Nodes
263 node(sg : graph_t, s : string) : node_t
264 creates a node in graph g of name s. If such a node already
265 exists, it is returned.
266
267 subnode(sg : graph_t, n : node_t) : node_t
268 inserts the node n into the subgraph g. Returns the node.
269
270 fstnode(g : graph_t) : node_t
271 returns the first node in graph g, or NULL if none exists.
272
273 nxtnode(n : node_t) : node_t
274 returns the next node after n, or NULL.
275
276 isNode(sg : graph_t, s : string) : node_t
277 looks for a node in graph g of name s. If such a node exists, it
278 is returned. Otherwise, NULL is returned.
279
280 Edges
281 edge(t : node_t, h : node_t, s : string) : edge_t
282 creates an edge with tail node t, head node h and name s. If the
283 graph is undirected, the distinction between head and tail nodes
284 is unimportant. If such an edge already exists, it is returned.
285
286 subedge(g : graph_t, e : edge_t) : edge_t
287 inserts the edge e into the subgraph g. Returns the edge.
288
289 isEdge(t : node_t, h : node_t, s : string) : edge_t
290 looks for an edge with tail node t, head node h and name s. If
291 the graph is undirected, the distinction between head and tail
292 nodes is unimportant. If such an edge exists, it is returned.
293 Otherwise, NULL is returned.
294
295 fstout(n : node_t) : edge_t
296 returns the first out edge of node n.
297
298 nxtout(e : edge_t) : edge_t
299 returns the next out edge after e.
300
301 fstin(n : node_t) : edge_t
302 returns the first in edge of node n.
303
304 nxtin(e : edge_t) : edge_t
305 returns the next in edge after e.
306
307 fstedge(n : node_t) : edge_t
308 returns the first edge of node n.
309
310 nxtedge(e : edge_t, node_t) : edge_t
311 returns the next edge after e.
312
313 Graph I/O
314 write(g : graph_t) : void
315 prints g in dot format onto the output stream.
316
317 writeG(g : graph_t, fname : string) : void
318 prints g in dot format into the file fname.
319
320 fwriteG(g : graph_t, fd : int) : void
321 prints g in dot format onto the open stream denoted by the inte‐
322 ger fd.
323
324 readG(fname : string) : graph_t
325 returns a graph read from the file fname. The graph should be in
326 dot format. If no graph can be read, NULL is returned.
327
328 freadG(fd : int) : graph_t
329 returns the next graph read from the open stream fd. Returns
330 NULL at end of file.
331
332 Graph miscellany
333 delete(g : graph_t, x : obj_t) : void
334 deletes object x from graph g. If g is NULL, the function uses
335 the root graph of x. If x is a graph or subgraph, it is closed
336 unless x is locked.
337
338 isIn(g : graph_t, x : obj_t) : int
339 returns true if x is in subgraph g. If x is a graph, this indi‐
340 cates that g is the immediate parent graph of x.
341
342 clone(g : graph_t, x : obj_t) : obj_t
343 creates a clone of object x in graph g. In particular, the new
344 object has the same name/value attributes and structure as the
345 original object. If an object with the same key as x already
346 exists, its attributes are overlaid by those of x and the object
347 is returned. If an edge is cloned, both endpoints are implic‐
348 itly cloned. If a graph is cloned, all nodes, edges and sub‐
349 graphs are implicitly cloned. If x is a graph, g may be NULL,
350 in which case the cloned object will be a new root graph.
351
352 copy(g : graph_t, x : obj_t) : obj_t
353 creates a copy of object x in graph g, where the new object has
354 the same name/value attributes as the original object. If an
355 object with the same key as x already exists, its attributes are
356 overlaid by those of x and the object is returned. Note that
357 this is a shallow copy. If x is a graph, none of its nodes,
358 edges or subgraphs are copied into the new graph. If x is an
359 edge, the endpoints are created if necessary, but they are not
360 cloned. If x is a graph, g may be NULL, in which case the
361 cloned object will be a new root graph.
362
363 copyA(src : obj_t, tgt : obj_t) : int
364 copies the attributes of object src to object tgt, overwriting
365 any attribute values tgt may initially have.
366
367 induce(g : graph_t) : void
368 extends g to its node-induced subgraph extension in its root
369 graph.
370
371 aget(src : obj_t, name : string) : string
372 returns the value of attribute name in object src. This is use‐
373 ful for those cases when name conflicts with one of the keywords
374 such as "head" or "root". Returns NULL on failure or if the
375 attribute is not defined.
376
377 aset(src : obj_t, name : string, value : string) : int
378 sets the value of attribute name in object src to value.
379 Returns 0 on success, non-zero on failure. See aget above.
380
381 getDflt(g : graph_t, kind : string, name : string) : string
382 returns the default value of attribute name in objects in g of
383 the given kind. For nodes, edges, and graphs, kind should be
384 "N", "E", and "G", respectively. Returns NULL on failure or if
385 the attribute is not defined.
386
387 setDflt(g : graph_t, kind : string, name : string, value : string) :
388 int
389 sets the default value of attribute name to value in objects in
390 g of the given kind. For nodes, edges, and graphs, kind should
391 be "N", "E", and "G", respectively. Returns 0 on success, non-
392 zero on failure. See setDflt above.
393
394 compOf(g : graph_t, n : node_t) : graph_t
395 returns the connected component of the graph g containing node
396 n, as a subgraph of g. The subgraph only contains the nodes. One
397 can use induce to add the edges. The function fails and returns
398 NULL if n is not in g. Connectivity is based on the underlying
399 undirected graph of g.
400
401 kindOf(obj : obj_t) : string
402 returns an indication of what kind of graph object is the argu‐
403 ment. For nodes, edges, and graphs, it returns should be "N",
404 "E", and "G", respectively.
405
406 lock(g : graph_t, v : int) : int
407 implements graph locking on root graphs. If the integer v is
408 positive, the graph is set so that future calls to delete have
409 no immediate effect. If v is zero, the graph is unlocked. If
410 there has been a call to delete the graph while it was locked,
411 the graph is closed. If v is negative, nothing is done. In all
412 cases, the previous lock value is returned.
413
414 Strings
415 sprintf(fmt : string, ...) : string
416 returns the string resulting from formatting the values of the
417 expressions occurring after fmt according to the printf(3) for‐
418 mat fmt
419
420 gsub(str : string, pat : string) : string
421
422 gsub(str : string, pat : string, repl : string) : string
423 returns str with all substrings matching pat deleted or replaced
424 by repl, respectively.
425
426 sub(str : string, pat : string) : string
427
428 sub(str : string, pat : string, repl : string) : string
429 returns str with the leftmost substring matching pat deleted or
430 replaced by repl, respectively. The characters '^' and '$' may
431 be used at the beginning and end, respectively, of pat to anchor
432 the pattern to the beginning or end of str.
433
434 substr(str : string, idx : int) : string
435
436 substr(str : string, idx : int, len : int) : string
437 returns the substring of str starting at position idx to the end
438 of the string or of length len, respectively. Indexing starts
439 at 0. If idx is negative or idx is greater than the length of
440 str, a fatal error occurs. Similarly, in the second case, if len
441 is negative or idx + len is greater than the length of str, a
442 fatal error occurs.
443
444 length(s : string) : int
445 returns the length of the string s.
446
447 index(s : string, t : string) : int
448 returns the index of the character in string s where the left‐
449 most copy of string t can be found, or -1 if t is not a sub‐
450 string of s.
451
452 match(s : string, p : string) : int
453 returns the index of the character in string s where the left‐
454 most match of pattern p can be found, or -1 if no substring of s
455 matches p.
456
457 canon(s : string) : string
458 returns a version of s appropriate to be used as an identifier
459 in a dot file.
460
461 xOf(s : string) : string
462 returns the string "x" if s has the form "x,y", where both x and
463 y are numeric.
464
465 yOf(s : string) : string
466 returns the string "y" if s has the form "x,y", where both x and
467 y are numeric.
468
469 llOf(s : string) : string
470 returns the string "llx,lly" if s has the form
471 "llx,lly,urx,ury", where all of llx, lly, urx, and ury are
472 numeric.
473
474 urOf(s)
475 urOf(s : string) : string returns the string "urx,ury" if s has
476 the form "llx,lly,urx,ury", where all of llx, lly, urx, and ury
477 are numeric.
478
479 sscanf(s : string, fmt : string, ...) : int
480 scans the string s, extracting values according to the sscanf(3)
481 format fmt. The values are stored in the addresses following
482 fmt, addresses having the form &v, where v is some declared
483 variable of the correct type. Returns the number of items suc‐
484 cessfully scanned.
485
486 I/O
487 print(...) : void
488 print( expr, ... ) prints a string representation of each argu‐
489 ment in turn onto stdout, followed by a newline.
490
491 printf(fmt : string, ...) : int
492
493 printf(fd : int, fmt : string, ...) : int
494 prints the string resulting from formatting the values of the
495 expressions following fmt according to the printf(3) format fmt.
496 Returns 0 on success. By default, it prints on stdout. If the
497 optional integer fd is given, output is written on the open
498 stream associated with fd.
499
500 scanf(fmt : string, ...) : int
501
502 scanf(fd : int, fmt : string, ...) : int
503 scans in values from an input stream according to the scanf(3)
504 format fmt. The values are stored in the addresses following
505 fmt, addresses having the form &v, where v is some declared
506 variable of the correct type. By default, it reads from stdin.
507 If the optional integer fd is given, input is read from the open
508 stream associated with fd. Returns the number of items success‐
509 fully scanned.
510
511 openF(s : string, t : string) : int
512 opens the file s as an I/O stream. The string argument t speci‐
513 fies how the file is opened. The arguments are the same as for
514 the C function fopen(3). It returns an integer denoting the
515 stream, or -1 on error.
516
517 As usual, streams 0, 1 and 2 are already open as stdin, stdout,
518 and stderr, respectively. Since gvpr may use stdin to read the
519 input graphs, the user should avoid using this stream.
520
521 closeF(fd : int) : int
522 closes the open stream denoted by the integer fd. Streams 0, 1
523 and 2 cannot be closed. Returns 0 on success.
524
525 readL(fd : int) : string
526 returns the next line read from the input stream fd. It returns
527 the empty string "" on end of file. Note that the newline char‐
528 acter is left in the returned string.
529
530 Math
531 exp(d : double) : double
532 returns e to the dth power.
533
534 log(d : double) : double
535 returns the natural log of d.
536
537 sqrt(d : double) : double
538 returns the square root of the double d.
539
540 pow(d : double, x : double) : double
541 returns d raised to the xth power.
542
543 cos(d : double) : double
544 returns the cosine of d.
545
546 sin(d : double) : double
547 returns the sine of d.
548
549 atan2(y : double, x : double) : double
550 returns the arctangent of y/x in the range -pi to pi.
551
552 Miscellaneous
553 exit() : void
554
555 exit(v : int) : void
556 causes gvpr to exit with the exit code v. v defaults to 0 if
557 omitted.
558
559 rand() : double
560 returns a pseudo-random double between 0 and 1.
561
562 srand() : int
563
564 srand(v : int) : int
565 sets a seed for the random number generator. The optional argu‐
566 ment gives the seed; if it is omitted, the current time is used.
567 The previous seed value is returned. srand should be called
568 before any calls to rand.
569
571 gvpr provides certain special, built-in variables, whose values are set
572 automatically by gvpr depending on the context. Except as noted, the
573 user cannot modify their values.
574
575 $ : obj_t
576 denotes the current object (node, edge, graph) depending on the
577 context. It is not available in BEGIN or END clauses.
578
579 $F : string
580 is the name of the current input file.
581
582 $G : graph_t
583 denotes the current graph being processed. It is not available
584 in BEGIN or END clauses.
585
586 $O : graph_t
587 denotes the output graph. Before graph traversal, it is initial‐
588 ized to the target graph. After traversal and any END_G actions,
589 if it refers to a non-empty graph, that graph is printed onto
590 the output stream. It is only valid in N, E and END_G clauses.
591 The output graph may be set by the user.
592
593 $T : graph_t
594 denotes the current target graph. It is a subgraph of $G and is
595 available only in N, E and END_G clauses.
596
597 $tgtname : string
598 denotes the name of the target graph. By default, it is set to
599 "gvpr_result". If used multiple times during the execution of
600 gvpr, the name will be appended with an integer. This variable
601 may be set by the user.
602
603 $tvroot : node_t
604 indicates the starting node for a (directed or undirected)
605 depth-first traversal of the graph (cf. $tvtype below). The
606 default value is NULL for each input graph.
607
608 $tvtype : tvtype_t
609 indicates how gvpr traverses a graph. At present, it can only
610 take one of six values: TV_flat, TV_dfs, TV_fwd, TV_ref, TV_bfs,
611 TV_ne, and TV_en. TV_flat is the default. The meaning of these
612 values is discussed below.
613
614 ARGC : int
615 denotes the number of arguments specified by the -a args com‐
616 mand-line argument.
617
618 ARGV : string array
619 denotes the array of arguments specified by the -a args command-
620 line argument. The ith argument is given by ARGV[i].
621
623 There are several symbolic constants defined by gvpr.
624
625 NULL : obj_t
626 a null object reference, equivalent to 0.
627
628 TV_flat : tvtype_t
629 a simple, flat traversal, with graph objects visited in seem‐
630 ingly arbitrary order.
631
632 TV_ne : tvtype_t
633 a traversal which first visits all of the nodes, then all of the
634 edges.
635
636 TV_en : tvtype_t
637 a traversal which first visits all of the edges, then all of the
638 nodes.
639
640 TV_dfs : tvtype_t
641 a traversal of the graph using a depth-first search on the
642 underlying undirected graph. To do the traversal, gvpr will
643 check the value of $tvroot. If this has the same value that it
644 had previously (at the start, the previous value is initialized
645 to NULL.), gvpr will simply look for some unvisited node and
646 traverse its connected component. On the other hand, if $tvroot
647 has changed, its connected component will be toured, assuming it
648 has not been previously visited or, if $tvroot is NULL, the tra‐
649 versal will stop. Note that using TV_dfs and $tvroot, it is pos‐
650 sible to create an infinite loop.
651
652 TV_fwd : tvtype_t
653 a traversal of the graph using a depth-first search on the graph
654 following only forward arcs. In
655
656 TV_bfs : tvtype_t
657 a traversal of the graph using a bread-first search on the graph
658 ignoring edge directions. See the item on TV_dfs above for the
659 role of $tvroot. libagraph(3), edges in undirected graphs are
660 given an arbitrary direction, which is used for this traversal.
661 The choice of roots for the traversal is the same as described
662 for TV_dfs above.
663
664 TV_rev : tvtype_t
665 a traversal of the graph using a depth-first search on the graph
666 following only reverse arcs. In libagraph(3), edges in undi‐
667 rected graphs are given an arbitrary direction, which is used
668 for this traversal. The choice of roots for the traversal is the
669 same as described for TV_dfs above.
670
672 gvpr -i 'N[color=="blue"]' file.dot
673
674 Generate the node-induced subgraph of all nodes with color blue.
675
676 gvpr -c 'N[color=="blue"]{color = "red"}' file.dot
677
678 Make all blue nodes red.
679
680 BEGIN { int n, e; int tot_n = 0; int tot_e = 0; }
681 BEG_G {
682 n = nNodes($G);
683 e = nEdges($G);
684 printf ("%d nodes %d edges %s0, n, e, $G.name);
685 tot_n += n;
686 tot_e += e;
687 }
688 END { printf ("%d nodes %d edges total0, tot_n, tot_e) }
689
690 Version of the program gc.
691
692 gvpr -c ""
693
694 Equivalent to nop.
695
696 BEG_G { graph_t g = graph ("merge", "S"); }
697 E {
698 node_t h = clone(g,$.head);
699 node_t t = clone(g,$.tail);
700 edge_t e = edge(t,h,"");
701 e.weight = e.weight + 1;
702 }
703 END_G { $O = g; }
704
705 Produces a strict version of the input graph, where the weight
706 attribute of an edge indicates how many edges from the input graph the
707 edge represents.
708
709 BEGIN {node_t n; int deg[]}
710 E{deg[head]++; deg[tail]++; }
711 END_G {
712 for (deg[n]) {
713 printf ("deg[%s] = %d0, n.name, deg[n]);
714 }
715 }
716
717 Computes the degrees of nodes with edges.
718
720 GPRPATH
721 Colon-separated list of directories to be searched to find the
722 file specified by the -f option.
723
725 When the program is given as a command line argument, the usual shell
726 interpretation takes place, which may affect some of the special names
727 in gvpr. To avoid this, it is best to wrap the program in single
728 quotes.
729
730 The constants TV_flat, TV_dfs, TV_fwd, and TV_rev
731
732 There is a single global scope, except for formal function parameters,
733 and even these can interfere with the type system. Also, the extent of
734 all variables is the entire life of the program. It might be prefer‐
735 able for scope to reflect the natural nesting of the clauses, or for
736 the program to at least reset locally declared variables. For now, it
737 is advisable to use distinct names for all variables.
738
739 If a function ends with a complex statement, such as an IF statement,
740 with each branch doing a return, type checking may fail. Functions
741 should use a return at the end.
742
743 The expr library does not support string values of (char*)0. This
744 means we can't distinguish between "" and (char*)0 edge keys. For the
745 purposes of looking up and creating edges, we translate "" to be
746 (char*)0, since this latter value is necessary in order to look up any
747 edge with a matching head and tail.
748
749 The language inherits the usual C problems such as dangling references
750 and the confusion between '=' and '=='.
751
753 Emden R. Gansner <erg@research.att.com>
754
756 awk(1), gc(1), dot(1), nop(1), libexpr(3), libagraph(3)
757
758
759
760 1 November 2005 GVPR(1)