]>
Commit | Line | Data |
---|---|---|
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 |