e0381e22 |
1 | #!/bin/sh |
2 | # |
3 | # mangen - generate manual entries for library |
4 | # |
5 | # modification history |
6 | # 02g,16jul93,abh Added compatibility for FORTRAN "C" style comments. See |
7 | # STAR programming guidelines for template. |
8 | # 02f,08may90,jdi nroff lines: took out colrm, added tbl and -Tlp. |
9 | # 02e,12mar90,jdi made NOMANUAL work for module entries; |
10 | # added CS/CE macros to routine declarations in lib synopsis. |
11 | # 02d,25jan90,rbr works with "#!/bin/awk -f" and the like |
12 | # 02c,10apr89,dnw changed to always put individual routine manual entries in |
13 | # chapter 2 instead of in (summary chapter + 1), so driver |
14 | # routines end up in 2 rather than 4. |
15 | # 02b,05apr89,dnw removed NOT_GENERIC filter |
16 | # added removing of mg.out and mgr.out before starting |
17 | # 02a,05nov87,jlf changed to allow mangen'ing of scripts |
18 | # changed so routine definitions that don't fit on one |
19 | # one line, have a '...' appended in synopses. |
20 | # changed documentation format so mangen can be mangen'ed. |
21 | # |
22 | # |
23 | # SYNOPSIS |
24 | # mangen [-d] [-n] [-l] chapter file |
25 | # |
26 | # DESCRIPTION |
27 | # generates: <name>.<chapter#> (manual entry for module) |
28 | # and if "-l": <name>.<chapter#+1> (manual entries for each routine) |
29 | # |
30 | # where <name> is the "root" of the "tail" of the specified file |
31 | # (i.e. if file="/usr/dave/gronk.c", then name="gronk"); |
32 | # and <chapter#> is the single digit chapter number |
33 | # (i.e. just the specified chapter number if one was given, |
34 | # or the number from the table below if a chapter name was given). |
35 | # |
36 | # <chapter> can be any digit or any of the following chapter abbreviations: |
37 | # |
38 | # # abbr name what |
39 | # = ==== =========== ==================================== |
40 | # 0 con* |
41 | # over* conventions - conventions and overview material |
42 | # 1 lib* libraries - subroutine library summaries |
43 | # 2 routines - individual library routines |
44 | # 3 task* |
45 | # tsk* |
46 | # dr* drivers - tasks and drivers |
47 | # 4 tool* tools - Unix development/maintenence tools |
48 | # |
49 | # NOTE: Specifying the chapter as "lib" automatically selects the -l option. |
50 | # |
51 | # "-l" flag causes a special library module style manual entry to be created. |
52 | # The manual entry for a library has a specially constructed synopsis section |
53 | # that contains the titles and calling sequence of each routine in the library. |
54 | # Also a seperate manual entry is generated for each of the routines in the |
55 | # library. These routine manual entries will be put in a file named libxxx.2. |
56 | # |
57 | # "-d" flag causes the intermediate nroff source files to NOT be deleted. |
58 | # These are called "mg.out" and "mgr.out" for the module manual entry |
59 | # and individual routine entries (only if -l option specified), respectively. |
60 | # This option is useful for debugging manual entries that don't look the |
61 | # way you expected. |
62 | # |
63 | # "-n" flag causes nroff sources not to be deleted, and not to be nroffed |
64 | # either. In this case, "mg.out" (and "mgr.out") will be the ONLY output |
65 | # from mangen. |
66 | # |
67 | # EXAMPLE: |
68 | # % mangen lib /usr/vw/lib/lstlib.c |
69 | # will create "lstlib.1" and "liblst.2" in the current directory. |
70 | #C< |
71 | |
72 | trap "rm -f mg.out mgr.out /tmp/mangen$$; exit" 1 2 3 15 |
73 | |
74 | rm -f mg.out mgr.out # start with a clean slate |
75 | |
76 | # set home to directory that contains this script |
77 | |
78 | home=`expr $0 : '\(.*/\)[^/]' '|' ./` |
79 | |
80 | dontdelete=0 |
81 | dontnroff=0 |
82 | lib=0 |
83 | chapter=0 |
84 | |
85 | while (test $# -gt 1) |
86 | do |
87 | case "$1" in |
88 | -d) dontdelete=1 ;; |
89 | -l) lib=1 ;; |
90 | -n) dontdelete=1; dontnroff=1 ;; |
91 | [0-9]) chapter=$1 ;; |
92 | con* | over*) chapter=0 ;; |
93 | lib*) chapter=1; lib=1 ;; |
94 | task* | tsk* | dr*) chapter=3 ;; |
95 | tool*) chapter=4 ;; |
96 | *) echo "flag not recognized:" $1; exit 1 ;; |
97 | esac |
98 | shift |
99 | done |
100 | |
101 | # remove path |
102 | |
103 | name=`basename $1` |
104 | |
105 | # remove trailing component, eg. ".xx" |
106 | |
107 | section=`expr $name : '\(.*\)\..*' '|' $name` |
108 | |
109 | # create awk program found at end of this script, and |
110 | # make substitutions in the awk program source |
111 | |
112 | awk '/^#START_AWK$/,/^#STOP_AWK$/' <$0 | \ |
113 | sed -e "s^\%filename^$name^g" \ |
114 | -e "s/\%chapter/$chapter/g" \ |
115 | -e "s/\%lib/$lib/" \ |
116 | >/tmp/mangen$$ |
117 | |
118 | # generate the nroff source of the manual entries |
119 | |
120 | awk -f /tmp/mangen$$ <$1 |
121 | |
122 | rm /tmp/mangen$$ |
123 | |
124 | # nroff them unless -n option |
125 | |
126 | if (test $dontnroff -eq 0) then |
127 | #tbl mg.out | nroff -man -Tman >$section.$chapter |
128 | #tbl mg.out | nroff -man -Tlp >$section.$chapter |
129 | #tbl mg.out | nroff -mangen -Tlp >$section.$chapter |
130 | tbl mg.out | nroff >$section.$chapter |
131 | else |
132 | mv mg.out $section.$chapter |
133 | fi |
134 | |
135 | if (test $lib -eq 1) then |
136 | if (test $dontnroff -eq 0) then |
137 | #tbl mgr.out | nroff -man -Tman >$section.2 |
138 | #tbl mgr.out | nroff -mangen -Tlp >$section.2 |
139 | tbl mgr.out | nroff >$section.2 |
140 | else |
141 | mv mgr.out $section.2 |
142 | fi |
143 | fi |
144 | # delete the nroff source, unless -d or -n option |
145 | |
146 | if (test $dontdelete -eq 0) then |
147 | rm -f mg.out mgr.out |
148 | fi |
149 | |
150 | exit 0 |
151 | |
152 | #START_AWK |
153 | |
154 | # mangen.awk - awk program to generate manual entries |
155 | |
156 | # the variable "s" holds the current state of the scan: |
157 | # |
158 | # title - get title line (initial state |
159 | # mh0 - skip to start of modification history |
160 | # mh - skip to end of modification history |
161 | # desc0 - skip to start of module description |
162 | # desc - process module description |
163 | # |
164 | # the following additional states are used if the "lib" flag is specified: |
165 | # |
166 | # rtn - skip to start of next routine |
167 | # rtitle - skip to, and process, routine title line |
168 | # rdesc - skip to, and process, routine description |
169 | # rsy0 - skip to start of routine synopsis |
170 | # rsy - process routine synopsis |
171 | |
172 | |
173 | BEGIN { |
174 | blanks = " " |
175 | |
176 | # the following values preceded by a "%" are substituted |
177 | # for by a "sed" program |
178 | |
179 | filename = "%filename" # source filename |
180 | chapter = %chapter # chapter number |
181 | lib = %lib # 1 = make routine entries, 0 = don't |
182 | |
183 | # initialize |
184 | |
185 | dbg = 0 # 1 = output debug stuff |
186 | s = "title" # initial state |
187 | |
188 | # get module name w/o the extension and the output file names |
189 | |
190 | dot = index (filename, ".") |
191 | |
192 | if (dot == 0) |
193 | modname = filename |
194 | else |
195 | modname = substr (filename, 1, dot - 1) |
196 | |
197 | outfile = "mg.out" |
198 | rtnfile = "mgr.out" |
199 | } |
200 | |
201 | dbg == 1 { |
202 | print s "\n" $0 >outfile |
203 | } |
204 | |
205 | # ignore lint directive lines |
206 | |
207 | /LINTLIBRARY/ {next} |
208 | /ARGSUSED/ {next} |
209 | /VARARGS/ {next} |
210 | |
211 | # get ss = line without leading '/* ' or '* ' or '# ' and trailing '*/' |
212 | # subhead = subheading (all caps at beginning of line w/ optional ':') |
213 | # subheadl = remainder of subheading line following ':' |
214 | |
215 | { |
216 | # detab line |
217 | |
218 | nf = split ($0, words, "\t") |
219 | |
220 | if (nf == 0) |
221 | l = "" |
222 | else |
223 | { |
224 | l = words[1] |
225 | |
226 | for (i = 2; i <= nf; i++) |
227 | l = l substr(" ", 1, 8-(length(l) % 8)) words[i] |
228 | } |
229 | |
230 | # strip off leading and trailing comment indicators |
231 | |
232 | if ((l ~ /^C>/) || (l ~ /^\/\*/)) |
233 | { |
234 | if ((l ~ /^C> /) || (l ~ /^\/\* /)) |
235 | start = 4 |
236 | else |
237 | start = 3 |
238 | } |
239 | else if ((l ~ /^C/) || (l ~ /^\*/)) |
240 | { |
241 | if ((l ~ /^C /) || (l ~ /^\* /)) |
242 | start = 3 |
243 | else |
244 | start = 2 |
245 | } |
246 | else if (l ~ /^\#/) |
247 | { |
248 | if (l ~ /^\# /) |
249 | start = 3 |
250 | else |
251 | start = 2 |
252 | } |
253 | else |
254 | start = 1 |
255 | |
256 | end = length (l) |
257 | |
258 | if ((l ~ /C<$/) || (l ~ /\*\/$/)) |
259 | end = end - 2 |
260 | |
261 | ss = substr (l, start, end - start + 1) |
262 | |
263 | |
264 | # check for sub heading line |
265 | |
266 | if ((ss !~ /^[A-Z][^a-z]*:/) && \ |
267 | (ss !~ /^[A-Z][^a-z]*$/)) |
268 | subhead = "" |
269 | else |
270 | { |
271 | colon = index (ss, ":") |
272 | |
273 | if (colon == 0) |
274 | { |
275 | subhead = ss |
276 | subheadl = "" |
277 | } |
278 | else |
279 | { |
280 | subhead = substr (ss, 1, colon - 1) |
281 | |
282 | subheadl = substr (ss, colon + 2) |
283 | if (subheadl ~ /^ *$/) |
284 | subheadl = "" |
285 | } |
286 | } |
287 | } |
288 | |
289 | # get module name and title: 1st line in file |
290 | |
291 | s == "title" { |
292 | # This gets rid of .yacc first lines ("%{"), and the first |
293 | # line or two of a script ("#!/bin/sh", etc.). |
294 | |
295 | if (NF == 1 || index($1, "#!")) |
296 | next |
297 | |
298 | # check that title matches module name |
299 | |
300 | dot = index ($2, ".") |
301 | if (dot == 0) |
302 | titlename = $2 |
303 | else |
304 | titlename = substr (ss, 1, dot - 1) |
305 | |
306 | if (titlename != modname) |
307 | { |
308 | print "ERROR: on line " NR \ |
309 | ": module name inconsistent w/ file name." |
310 | exit |
311 | } |
312 | |
313 | title = ss |
314 | |
315 | s = "mh0" |
316 | next |
317 | } |
318 | |
319 | # skip modification history: skip, looking for 'modification history' then blank |
320 | |
321 | s == "mh0" { |
322 | if (l ~ /modification history/) |
323 | s = "mh" |
324 | next |
325 | } |
326 | |
327 | s == "mh" { |
328 | if (ss ~ /^ *$/) |
329 | { |
330 | s = "desc0" |
331 | xdesc = 0 |
332 | } |
333 | next |
334 | } |
335 | |
336 | # get module description: ignore leading blank lines; turn capital lines |
337 | # into subheadings; accumulate rest looking for '*/' |
338 | |
339 | s == "desc0" { |
340 | if (l !~ /^ *$/) |
341 | { |
342 | ignore = 0 |
343 | s = "desc" |
344 | } |
345 | } |
346 | |
347 | s == "desc" { |
348 | # suppress manual entry if NOMANUAL specified |
349 | |
350 | if (l ~ /NO[ _-]?MANUAL/) |
351 | { |
352 | ignorelib = 1 |
353 | } |
354 | |
355 | # check for end of description section |
356 | |
357 | if ((l ~ /^\#*C</) || (l ~ /^\#*\*\//)) |
358 | { |
359 | if (lib == 0) |
360 | exit |
361 | else |
362 | { |
363 | s = "rtn" |
364 | next |
365 | } |
366 | } |
367 | |
368 | |
369 | # check for description section missing entirely |
370 | |
371 | if ((l ~ /-----------------------------/) || (l ~ /\*\*\*\*\*\*\*\*\*\*/)) |
372 | { |
373 | print "ERROR: on line " NR ": module description missing." |
374 | exit |
375 | } |
376 | |
377 | |
378 | # skip leading blank lines |
379 | |
380 | if ((xdesc == 0) && (ss ~ /^ *$/)) |
381 | next |
382 | |
383 | |
384 | # check for subheading line and accumulate description |
385 | |
386 | if (subhead == "") |
387 | { |
388 | if (!ignore) |
389 | desc[++xdesc] = ss |
390 | } |
391 | else |
392 | { |
393 | if (subhead ~ /^INTERNAL/) |
394 | ignore = 1 |
395 | else |
396 | { |
397 | desc[++xdesc] = ".SH " subhead |
398 | if (subheadl != "") |
399 | desc[++xdesc] = subheadl |
400 | ignore = 0 |
401 | } |
402 | } |
403 | |
404 | next |
405 | } |
406 | |
407 | # skip to routine start: skip looking for '**********' |
408 | |
409 | s == "rtn" { |
410 | if ((l ~ /--------------------------/) || (l ~ /\*\*\*\*\*\*\*\*\*\*/)) |
411 | { rtitle = ""; rnm = ""; xrdesc = 0; xrsy = 0; s = "rtitle" } |
412 | next |
413 | } |
414 | |
415 | # get routine title: skip looking for 1st non-blank line |
416 | |
417 | s == "rtitle" { |
418 | if (ss !~ /^ *$/) |
419 | { rtitle = ss; rnm = $2; ignore = 0; s = "rdesc" } |
420 | next |
421 | } |
422 | |
423 | # get routine description: skip leading blank lines; make capital lines |
424 | # be subheadings; accumulate rest looking for '*/' or blank line |
425 | |
426 | s == "rdesc" { |
427 | # check for end of routine description |
428 | |
429 | if ((l ~ /^C</) || (l ~ /^\*\//) || (l ~ /^ *$/)) |
430 | { |
431 | s = "rsy0" |
432 | next |
433 | } |
434 | |
435 | # skip leading blank lines |
436 | |
437 | if (xrdesc == 0 && ss ~ /^ *$/) |
438 | next |
439 | |
440 | # suppress manual entry if NOMANUAL specified |
441 | |
442 | if (l ~ /NO[ _-]?MANUAL/) |
443 | { |
444 | s = "rtn" |
445 | next |
446 | } |
447 | |
448 | # check for sub heading and accumulate routine description |
449 | # ignore INTERNAL sections |
450 | |
451 | if (subhead == "") |
452 | { |
453 | if (!ignore) |
454 | rdesc[++xrdesc] = ss |
455 | } |
456 | else |
457 | { |
458 | if (subhead ~ /^INTERNAL/) |
459 | ignore = 1 |
460 | else |
461 | { |
462 | rdesc[++xrdesc] = ".SH " subhead |
463 | if (subheadl != "") |
464 | rdesc[++xrdesc] = subheadl |
465 | ignore = 0 |
466 | } |
467 | } |
468 | next |
469 | } |
470 | |
471 | # get routine synopsis: throw away local routines; check declared name matches |
472 | # title; accumulate rest looking for "{"; then output routine manual |
473 | |
474 | s == "rsy0" { |
475 | # skip to next non-blank line |
476 | |
477 | if (l ~ /^ *$/) |
478 | next |
479 | |
480 | # found the function declaration line |
481 | # quit processing of local functions: don't make manual |
482 | |
483 | l = substr (ss, 1, index (ss, "(") - 1) |
484 | n = split (l, words) |
485 | |
486 | if ((words[1] == "LOCAL") || (words[1] == "static")) |
487 | { |
488 | s = "rtn" |
489 | next |
490 | } |
491 | |
492 | # check that declared name matches name in title |
493 | |
494 | if ((words[n] != rnm) && (words[n] != ("*" rnm))) |
495 | { |
496 | print "ERROR on line " NR \ |
497 | ": title inconsistent with declaration:\n" rtitle "\n" l |
498 | } |
499 | |
500 | # save routine declaration line |
501 | |
502 | rsy [1] = ss |
503 | xrsy = 1 |
504 | maxlen = 0 |
505 | mingap = 100 |
506 | s = "rsy" |
507 | next |
508 | } |
509 | |
510 | s == "rsy" { |
511 | # accumulate synopsis til '{' or blank line, then output manual |
512 | |
513 | # if ((l !~ /^ *{/) && (l !~ /^ *$/)) |
514 | if ((l !~ /^ *\{/) && (l !~ /^ *$/)) |
515 | { |
516 | xrsy++ |
517 | |
518 | # get real part up to ';' and note longest declaration |
519 | |
520 | is = index (l, ";") |
521 | |
522 | if (is == 0) |
523 | { |
524 | rsy[xrsy] = "" |
525 | |
526 | ic = index (l, $1) |
527 | } |
528 | else |
529 | { |
530 | if (($1 == "FAST") || ($1 == "register") || ($1 == "*")) |
531 | i = index (l, $2) |
532 | else |
533 | i = index (l, $1) |
534 | |
535 | rsy [xrsy] = substr (l, i, is - i + 1) |
536 | |
537 | ic = index (l, "/*") |
538 | } |
539 | |
540 | # get comment if any |
541 | |
542 | if (ic == 0) |
543 | rsyc [xrsy] = "" |
544 | else |
545 | { |
546 | rsyc [xrsy] = substr (l, ic) |
547 | rsyci [xrsy] = ic |
548 | } |
549 | |
550 | # note maximum length of line |
551 | |
552 | len = length (l) |
553 | if (len > maxlen) |
554 | maxlen = len |
555 | |
556 | # note minimum gap between code and comment |
557 | |
558 | if ((ic != 0) && (is != 0)) |
559 | { |
560 | gap = ic - is - 1 + i - 5 |
561 | if (gap < mingap) |
562 | mingap = gap |
563 | } |
564 | } |
565 | else |
566 | { |
567 | # end of synopsis reached; output routine name, then |
568 | # manual for this routine, then form-feed |
569 | |
570 | s = "rtn" |
571 | |
572 | print rnm >rtnfile |
573 | stitle [++xrtn] = rtitle |
574 | ssy [xrtn] = rsy[1] |
575 | |
576 | # print name and title |
577 | |
578 | print ".TH " rnm " 2" \ |
579 | " \"\" \"ALICE Reference Manual\"" >rtnfile |
580 | print ".ad b" >rtnfile |
581 | print ".SH NAME\n" rtitle >rtnfile |
582 | |
583 | # print routine synopsis |
584 | |
585 | # figure out if we should squeeze decls and comments |
586 | |
587 | squeeze = 0 |
588 | if (maxlen > 60) |
589 | { |
590 | squeeze = maxlen - 60 |
591 | if (squeeze > (mingap - 1)) |
592 | squeeze = mingap - 1 |
593 | } |
594 | |
595 | print ".SH SYNOPSIS" >rtnfile |
596 | print ".CS" >rtnfile |
597 | print ".nf" >rtnfile |
598 | print rsy[1] >rtnfile |
599 | for (i = 2; i <= xrsy; i++) |
600 | { |
601 | if (rsyc[i] == "") |
602 | n = 0 |
603 | else |
604 | n = rsyci[i] - length(rsy[i]) - 5 - squeeze |
605 | print " " rsy[i] substr(blanks,0,n) rsyc[i] >rtnfile |
606 | } |
607 | print ".fi" >rtnfile |
608 | print ".CE" >rtnfile |
609 | |
610 | # print description |
611 | |
612 | if ((xrdesc != 0) && (rdesc[1] !~ /^\.SH/)) |
613 | print ".SH DESCRIPTION" >rtnfile |
614 | |
615 | seealso = 0 |
616 | |
617 | for (i = 1; i <= xrdesc; i++) |
618 | { |
619 | print rdesc[i] >rtnfile |
620 | |
621 | if (rdesc[i] ~ /^.SH SEE ALSO/) |
622 | { |
623 | print modname "(" chapter ")," >rtnfile |
624 | seealso = 1 |
625 | } |
626 | } |
627 | |
628 | # print see also if not already done above |
629 | |
630 | if (seealso == 0) |
631 | { |
632 | print ".SH SEE ALSO" >rtnfile |
633 | print modname "(" chapter ")" >rtnfile |
634 | } |
635 | # form-feed |
636 | |
637 | print "\f" >rtnfile |
638 | } |
639 | |
640 | next |
641 | } |
642 | |
643 | # end of file: output module manual |
644 | |
645 | END { |
646 | if (!ignorelib) |
647 | { |
648 | # print name and title |
649 | |
650 | print ".TH " modname " " chapter \ |
651 | " \"\" \"ALICE Reference Manual\"" >outfile |
652 | print ".ad b" >outfile |
653 | print ".SH NAME\n" title >outfile |
654 | |
655 | |
656 | # print specially constructed synopsis, if library |
657 | # If no routines, say so. |
658 | |
659 | if (lib == 1) |
660 | { |
661 | print ".SH SYNOPSIS" >outfile |
662 | print ".nf" >outfile |
663 | for (i = 1; i <= xrtn; i++) |
664 | print stitle[i] >outfile |
665 | print "" >outfile |
666 | if (xrtn == 0) |
667 | print "NO CALLABLE ROUTINES" >outfile |
668 | print ".CS" >outfile |
669 | for (i = 1; i <= xrtn; i++) |
670 | { |
671 | if (substr(ssy[i], length (ssy[i])) == ")") |
672 | print ssy[i] >outfile |
673 | else |
674 | print ssy[i], "..." >outfile |
675 | } |
676 | print ".CE" >outfile |
677 | print ".fi" >outfile |
678 | } |
679 | |
680 | |
681 | # print module description |
682 | |
683 | if ((xdesc != 0) && (desc[1] !~ /^\.SH/)) |
684 | print ".SH DESCRIPTION" >outfile |
685 | for (i = 1; i <= xdesc; i++) |
686 | print desc[i] >outfile |
687 | } |
688 | } |
689 | #STOP_AWK |