/* * mkwhatis - read/print "SEE ALSO" or NAME section of unformatted manpage * * finds .SH "SEE ALSO" or .SH NAME line and prints next line(s) until * either EOF or first char of line is '.' * * this is a tool to help build the whatis(1) databases. the idea is * to feed it a list of manpages (source form). it does a reasonable * job, but is not perfect. you may have to do some editing... * * the format for each line of the whatis databases is: * * name%aliases%section%subsection%description%xrefs%keywords * * name program/routine/etc name. (required) * alias if this sources another manpage or refered by another * name. a comma-separated list. (optional) * section number [0-9nlo] (required) * subsection single capital letter (optional) * description what this is, ascii string (required) * xref basically "SEE ALSO". a comma-separated list (optional) * keywords any descriptive keywords. comma-sep list (optional) * * optional fields contain only a '_' char. * * here is an example: * * unixmode%_%5%_%Extended Filename Standard%tcsh(1),sh(1)%TOS,MiNT,file,glob,links,shell,standard * * it assumes manpage (src) that look like this: * * .TH FOO 1X <-- gives section, subsection * .SH NAME * foo \- blah blah blah <-- gives name, desc * .SH DESCIPTION * . * . * . * .SH "SEE ALSO" * bar(1), foobar(5) <-- gives xref * .SH SOMETHING (or eof) * * or * .TH FOO 1 LOCAL <-- gives section, subsection * . * . * . * * it does NOT handle sourced files (aliases), ie: * * .so man1/foo.1 * * at a minimum, you will have to add keywords yourself. */ static char *rcsid_mkwhatis_c = "$Id: mkwhatis.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; /* * $Log: mkwhatis.c,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #include #include #include #define EOS '\0' #define NL '\n' #define CR '\r' #define TAB '\t' #define SPC ' ' #define DOT '.' #define DASH '-' #define NAME "NAME" #define SEE_ALSO "SEE ALSO" #define SEE_ALSO_Q "\"SEE ALSO" #define PR_NULL_FIELD printf("%%_"); #define B_SIZE 1024 char buf[B_SIZE]; FILE *stream; void read_xref (void); char *skipwhite (char *); char *skipword (char *); char *finddash (char *); void kill_newline (char *); void main (int argc, char *argv[]) { char *ps; int sec; int subsec; int got_xref = 0; int got_name = 0; for (argc--, argv++; argc && **argv == '-'; argc--, argv++) { switch (*(*argv+1)) { default: fprintf (stderr, "usage: mkwhatis [-A | -N | -S | -B] file...\n"); exit (1); } } /* * args are manpage source files */ for ( ; argc && *argv; argc--, argv++) { if ((stream = fopen (*argv, "r")) == (FILE *) NULL) { fprintf (stderr, "mkwhatis: could not open %s\n", *argv); continue; } got_xref = 0; got_name = 0; while (1) { fgets (buf, B_SIZE-1, stream); if (feof (stream)) { /* if we exit loop here, things were probably ok, but there was no SEE ALSO. put out an appropriate ending... */ if (got_name && !got_xref) printf ("%%_%%_\n"); else printf ("\n"); goto next1; /* ERROR? */ } kill_newline (buf); /* * look for .TH or .SH */ if (buf[0] != DOT) continue; if (buf[1] == 'T' && buf[2] == 'H') { ps = buf; /* skip .TH */ if ((ps = skipword (ps)) && *ps == EOS) goto next1; /* ERROR */ if ((ps = skipwhite (ps)) && *ps == EOS) goto next1; /* ERROR */ /* skip FOO */ if ((ps = skipword (ps)) && *ps == EOS) goto next1; /* ERROR */ if ((ps = skipwhite (ps)) && *ps == EOS) goto next1; /* ERROR */ if (*ps) sec = *ps; else sec = '1'; /* assume */ subsec = EOS; /* none */ /* skip sect */ if ((ps = skipword (ps)) && *ps == EOS) continue; if ((ps = skipwhite (ps)) && *ps == EOS) continue; if (*ps) subsec = *ps; } else if (buf[1] == 'S' && buf[2] == 'H') { ps = buf; /* skip .SH */ if ((ps = skipword (ps)) && *ps == EOS) goto next1; /* ERROR */ if ((ps = skipwhite (ps)) && *ps == EOS) goto next1; /* ERROR */ if (!strncmp (ps, NAME, 4)) { char *dsh; fgets (buf, B_SIZE-1, stream); if (feof (stream)) { goto next1; /* ERROR */ } kill_newline (buf); ps = buf; if ((ps = finddash (ps)) && *ps == EOS) goto next1; /* ERROR */ /* skip past dash to desc */ dsh = ps; if ((ps = skipword (ps)) && *ps == EOS) goto next1; /* ERROR */ if ((ps = skipwhite (ps)) && *ps == EOS) goto next1; /* ERROR */ /* find end of name, going backwards from dash */ if (dsh[-1] == '\\') dsh--; while (dsh > buf && (dsh[-1] == SPC || dsh[-1] == TAB)) dsh--; *dsh = EOS; /* check for name */ if (buf[0] == EOS) goto next1; /* ERROR */ printf ("%s", buf); /* name */ PR_NULL_FIELD; /* alias */ printf ("%%%c", sec); /* section */ if (subsec) /* subsect */ printf ("%%%c", subsec); else PR_NULL_FIELD; if (ps && *ps) /* desc */ printf ("%%%s", ps); else PR_NULL_FIELD; got_name = 1; } else if (strncmp (ps, SEE_ALSO, 8) == 0 || strncmp (ps, SEE_ALSO_Q, 9) == 0) { got_xref = 1; printf ("%%"); /* xref */ read_xref (); break; /* normal exit! */ } } } if (!got_xref) PR_NULL_FIELD; /* xref */ PR_NULL_FIELD; /* keywords */ printf ("\n"); next1: ; fclose(stream); } exit(0); } /*------------------------------*/ /* read_xref */ /*------------------------------*/ void read_xref (void) { char *ps; while (1) { fgets (buf, B_SIZE-1, stream); if (feof (stream) || buf[0] == '.') return; kill_newline (buf); /* fputs (buf, stdout);*/ for (ps = buf; *ps; ps++) { if (*ps == SPC) continue; putchar (*ps); } } return; } /*------------------------------*/ /* skipwhite */ /*------------------------------*/ char *skipwhite (char *ps) { while (*ps && (*ps == SPC || *ps == TAB)) ps++; return (ps); } /*------------------------------*/ /* skipword */ /*------------------------------*/ char *skipword (char *ps) { while (*ps && (*ps != SPC && *ps != TAB)) ps++; return (ps); } /*------------------------------*/ /* finddash */ /*------------------------------*/ char *finddash (char *ps) { while (*ps && *ps != DASH) ps++; return (ps); } /*------------------------------*/ /* kill_newline */ /*------------------------------*/ void kill_newline (char *ps) { while (*ps) { if (*ps == NL || *ps == CR) { *ps = EOS; return; } ps++; } return; }