Xref: news-dnh.mv.net comp.os.msdos.djgpp:444 Path: news-dnh.mv.net!mv!news.sprintlink.net!cs.utexas.edu!convex!not-for-mail From: rosenkra AT convex DOT com (William Rosenkranz) Newsgroups: comp.os.msdos.djgpp Subject: whatis(1) system (part01/02) Date: 19 Jun 1995 00:13:10 -0500 Organization: Engineering, Convex Computer Corporation, Richardson, Tx USA Lines: 3418 Nntp-Posting-Host: convex1.convex.com Summary: unix whatis system Keywords: unix manual man whatis apropos To: djgpp AT sun DOT soe DOT clarkson DOT edu Dj-Gateway: from newsgroup comp.os.msdos.djgpp whatis (part01/02) this is a whatis(1) system. it is used in conjunction with man(1) that i also posted. man is standalone, but without apropos and whatis, the -k and -f switches in man will not work. -bill rosenkranz rosenkra AT convex DOT com ---------------------------- cut here ---------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by William Rosenkranz on Mon Jun 19 00:41:03 1995 # # This archive contains: # whatis # # Error checking via sum(1) will be performed. LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH if sum -r /dev/null 2>&1 then sumopt='-r' else sumopt='' fi echo mkdir - whatis mkdir whatis echo x - whatis/README.all cat >whatis/README.all <<'@EOF' README (man, whatis, 95/06/18) ------------------------------ someone (stanb AT netcom DOT com) had asked for a man(1) command for reading manpages. i am posting such a system which includes: man - read online manpages apropos - list relevant manpages on a given topic (same as "man -k word") whatis - give 1-line description of a command (same as "man -f word") whatisin - list information about what is in sections of the manual mkwhatis - tool to help build whatis database note that man does not have its own pager. man calls the pager and gives it a filename. what man does is find the file (in known places) and figures out what to run (pager, whatis, apropos, etc.). in this regard it is really pretty simple minded. the hard part is getting, organizing, formatting, and maintaining the manpages. for example, i have hundreds of manpages on my systems. the typical unix system might have over a thousand manpages. these programs function more or less the same as the unix (BSD) commands with some exceptions: - man does not invoke nroff. your manpages should be preformatted. - every unix flavor has its own way of doing man so some of the switches on these commands may not correspond with all unix (or posix) ways of dealing with this. - the whatis database itself is different than how unix does it. but it is similar, and no two unix systems do it the same anyway. as it stands, these programs assumes the following directory structure: c:\usr\man main location of manpages, whatis db, etc c:\usr\man\man[0-9lno] dirs containing *unformatted* manpages) c:\usr\man\cat[0-9lno] dirs containing *formatted* manpages) c:\usr\man\whatis._?_ whatis databases for each section (you have to build these based on your collection of manpages) c:\usr\man\whatisin.___ whatisin database man will ONLY look in the cat* directories, and does not format the manpages. you will need nroff for this (cawf, groff, etc). i also have an nroff that i wrote years ago that is PD. or you can format the manpages on a unix system and download them to your PC. everything is configurable, both in the source and via the environment. for example, the c:\usr\man path can be overridded with: - setting environment variable MANPATH - using the commandline switch "-M path" on each command - changing the executables with a binary editor (i have left space in the source for such patches) - changing the source and recompiling caveats: - i am providing this free, with no restrictions. it is 100% my code (does not contain any unix code). - i will not help in any way to fix anything or add new features. this system runs fine under both Unix and on my atari ST (with gcc) so it should port easily, though i have not tried it under DOS or with djgpp. - i will not reformat the source to correspond to someone's notion of style. this is my prefered style, after 10 years of C coding and 20 years of fortran coding. :-) - if you don't like it, either a) fix it yourself, or b) don't use it. it is free, after all. Install: - Unpack everything into separate directories (./man, ./whatis). - The files are all ascii (no binary files). there are no CF-LF (just LF) so if you need CR-LF, you have to fix this yourself. - go to each dir (./man and ./whatis) and look at the makefile. change (at least) the following for your particular setup: CC how to invoke compiler LD how to link .o files MANTOP main location to place manpages (install) MANDIR specific location for manpage source CATDIR specific location for formatted manpages BINDIR location to install executables (man, whatis, etc) DEFS in man, you should specify what you have available (eg, if you have ul(1) and want the -ul switch to function, define HAS_UL). you probably want to define MSDOS, __GNUC__, and possibly undefine unix. in general, check all the macros in upper case in the makefile. note that i could have used sed in the makefile to patch names in the program, but i don't know how good make is on the PC. - man invokes the PAGER and other programs via the system(3) call. on unix (and on my atari), system will search PATH for executables so you don't need a full path. if this is not the case with djgpp, then you will have to alter ./man/man.c to build a full path for executing PAGER, cat, ul, whatis, apropos, etc. - type: make all will build the executables make install will install the execs and manpages make clobber will clean up after the make all. you may also consider doing "make dirs" before make install when building man. this creates the directory structure. you should do man before whatis. - if successful, you should be all set. i have provided formatted manpages (man.1, whatis.1, whatis.5, apropos.1, whatisin.1) from the manpage sources (man.man, whatis.man, whatis.ma5, etc). these were piped through "ul -t dumb" to remove any bold/underline escape sequences. so the formatted manpages are pure ascii. if you have a PAGER that groks how to handle nroff bold, etc, then you may want to reformat the manpages. you should at a minimum build man. it will allow you to read manpages. if you are up for it, the whatis capability might be desirable. whatis contains a 1-line description of every manpage you have on your system. for more information, see the file ./whatis/whatis.5 and whatis.1. note: i have not included any manpages here other than those for these programs themselves. don't ask me for a manpage on ls(1). Environment: these programs recognize several environment variables: MANPAGER man if set, this pager is used by man. on my atari, i have a special pager that resets fonts, based on what -T does in nroff on my system. this gives me bold, etc. PAGER man if MANPAGER is not set, this pager is used. the default is less. MANPATH man, location of the manpages, top level. the whatis default is c:\usr\man. at the moment, MANPATH apropos is a single path, not a list. whatisin for more, grep the sources for "getenv" or read the manpages. note that man will invoke other programs as follows (using system(3)): man file PAGER man -k word apropos man -f name whatis you can also invoke apropos and whatis by themselves, of course. that's about all i have time for. have fun... -bill rosenkranz rosenkra AT convex DOT com @EOF set `sum $sumopt /dev/null 2>&1 if [ X"`cat /tmp/uud$$ 2>&1`" = Xok ] then unpacker=uudecode else echo Compiling unpacker for non-ascii files pwd=`pwd`; cd /tmp cat >unpack$$.c <<'EOF' #include #define C (*p++ - ' ' & 077) main() { int n; char buf[128], *p, a,b; scanf("begin %o ", &n); gets(buf); if (freopen(buf, "w", stdout) == NULL) { perror(buf); exit(1); } while (gets(p=buf) && (n=C)) { while (n>0) { a = C; if (n-- > 0) putchar(a << 2 | (b=C) >> 4); if (n-- > 0) putchar(b << 4 | (a=C) >> 2); if (n-- > 0) putchar(a << 6 | C); } } exit(0); } EOF cc -o unpack$$ unpack$$.c rm unpack$$.c cd $pwd unpacker=/tmp/unpack$$ fi rm -f /tmp/uud$$ echo x - whatis/README '[non-ascii]' $unpacker <<'@eof' begin 644 whatis/README M=VAA=&ES+"!W:&%T:7-I;BP AT 87!R;W!O2!O9B!W:&%T(&$@X M8V]M;6%N9"P AT 971C+B!I@EC;VUP&5C=71A8FQE#0H)8V]M;6]N+F,)8V]M;6]N('-O=7)C92!C;V1E(&9OX M@EC;VUP@EC;VUP0T*=VAI8V@@=VEL;"!C;VYT86EN('1H92!D871A8F%S97,N(%1H:7,@:7,@X M=&AE('-A;64 AT 96YV:7)O;FUE;G0@=F%R:6%B;&4-"G5S960 AT 8GD@;6%N*#$IX M("AM:6YE+"!A="!L96%S="DN($EF('EO=2!D;VXG="!S970@:70@*&%N9"!IX M9B!Y;W4 AT 9&]N)W0-"F]V97)R:61E('=I=&@@=&AE("U0('-W:71C:"!O;B!TX M:&5S92!C;VUM86YD2!I6]U&5CX M=71A8FQE6]U('-H;W5L9 T*<')O8F%B;'D AT 8V]P>2!M:W=H871I6]U2!I;G-T96%D+B!)="!I7=O" H0E-$*2!P6]UF4@2!F=6YC=&EO;G,-"@DT"61E=FEC97,L(&AA7,@861M:6X AT 8V]M;6%N9',-"@DY"75N=7-E9 T*"6P);&]CX M86P-"@EN"6YE=PT*"6\);VQD#0H-"E1O(&-H86YG92!T:&ES(&QI@T*whatis/apropos.1 <<'@EOF' APROPOS(1) APROPOS(1) NAME apropos - find pertinent online documentation SYNOPSIS apropos [ -P path ] [ -s section ] word... DESCRIPTION The apropos command displays a one line synopsis of each online documentation file whose name or description contains a specified word or whose keywords listed in the whatis databases matches the specified word. Once you know what you are looking for, use man(1) to read the appropriate documentation. The argument word is considered separately from each other word. The case of letters is ignored. OPTIONS The following switch options are recognized: -P path if a valid path is given, apropos searches for the databases there (see ENVIRONMENT). -s section search only for items from the specified section. This should be a single character representing a section of the manual, i.e., from the list: 0123456789lno EXAMPLE Try apropos editor and apropos disk to get a feel for what apropos does. ENVIRONMENT Apropos searches for the database file in the directory contained in the MANPATH environment variable. Note that the -P option overrides this. If neither MANPATH or -P are specified, a default path of ``d:/usr/man'' is used. NOTES Apropos performs a simple string search. For example, apropos man finds all instances of command, manipulate, mantissa, permanent, and so forth. FILES MANPATH/whatis._?_ online documentation database file SEE ALSO man(1), whatis(1), whatisin(1), whereis(1) - 1 - Formatted: June 18, 1995 APROPOS(1) APROPOS(1) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION apropos 2.0.1 92/9/12 rosenkra - 2 - Formatted: June 18, 1995 @EOF set `sum $sumopt whatis/apropos.c <<'@EOF' #undef DEBUG /* * apropos - find pertinent on-line documentation * * apropos name ... */ static char *rcsid_apropos_c = "$Id: apropos.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; static char *version = "apropos 2.0 92/09/11 rosenkra AT convex DOT com"; static char *myname = "apropos"; /* * $Log: apropos.c,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #include #include #include #include #include "whatis.h" /* * we only need one record here. we read a record and check all the * command line args against it for a match */ struct rec r; char *libpath = MANPATH; /* path to database files (-P) */ int debugging = 0; /* for -d */ /* * fcn prototypes */ void apropos (int, int, int, char **); int match_up (char *, char *); int advance (char *, char *); int cmp_ign_case (int, int); void usage (int); int parse_record (char *, struct rec *); void print_record (int, struct rec *); #ifdef CHECK_MAGIC int check_magic (void); #endif /*------------------------------*/ /* main */ /*------------------------------*/ void main (int argc, char *argv[]) { int sect = -1; int verbose = 0; char *lpath; char *ps; /* * see if there is MANPATH in env. use it over default... */ if ((lpath = getenv ("MANPATH")) != (char *) NULL) libpath = lpath; else if ((lpath = getenv ("MANDIR")) != (char *) NULL) libpath = lpath; #ifdef DEBUG else fprintf (stderr, "apropos: environment variable MANPATH not set, using default\n"); #endif /* * parse args */ for (argc--, argv++; argc && **argv == '-'; argc--, argv++) { switch (*(*argv+1)) { case 'P': /* path for db */ case 'M': argc--, argv++; if (argc < 1) usage (1); libpath = *argv; break; case 's': /* specific section */ argc--, argv++; if (argc < 1) usage (1); sect = **argv; break; case 'd': /* debug mode */ debugging = 1; break; case 'v': /* version */ printf ("%s\n", version); exit (0); break; case 'h': /* help */ usage (0); break; case '-': switch (*(*argv+2)) { case 'v': /* --version */ printf ("%s\n", version); exit (0); break; case 'h': /* --help */ usage (0); break; } break; } } /* * apropos what? */ if (argc == 0) { fprintf (stderr, "%s: you must specify an argument. consider using whatisin.\n", myname); usage (1); } /* * not documented: if first arg is a number, use it for section... */ if (isdigit(**argv)) { sect = **argv; argc--, argv++; } /* * do it. if specific section, search it only. else search all * sections */ if (sect != -1) { apropos (verbose, sect, argc, argv); } else { for (ps = SECTIONS; *ps; ps++) { sect = *ps; apropos (verbose, sect, argc, argv); } } exit (0); } /*------------------------------*/ /* apropos */ /*------------------------------*/ void apropos (int verbose, int sect, int argc, char **argv) { #define MAX_ARGS 100 char dbname[256]; char buf[REC_SIZE]; char srch[REC_SIZE]; register char **vp; int notfound[MAX_ARGS]; int i, j; /* * FIXME: we should allocate space for the notfound list. */ if (argc > MAX_ARGS) argc = MAX_ARGS; /* * set up db name. section is really a single ascii char, not an * int. this is so we can have whatis for local, new, etc. */ if (sect == -1) /* orig behavior (just single "whatis" file, never used here) */ sprintf (dbname, "%s%s%s", libpath, SLASH, WHATIS); else /* new: whatis._[0-9lno]_ */ sprintf (dbname, "%s%s%s._%c_", libpath, SLASH, WHATIS, sect); /* * reopen stdin as this file... */ if (debugging) fprintf (stderr, "checking database file %s...\n", dbname); if (freopen (dbname, "r", stdin) == (FILE *) NULL) { /* if (verbose || debugging)*/ if (debugging) fprintf (stderr, "%s: could not access file %s\n", myname, dbname); return; } #ifdef CHECK_MAGIC /* * check file's magic */ if (check_magic ()) { fprintf (stderr, "%s: magic number is wrong for file %s\n", myname, dbname); return; } #endif /* * read file and compare. first assume we will not find anything * and flag list... */ for (i = 0; i < MAX_ARGS; i++) notfound[i] = 1; while (1) { /* * get raw record from file */ fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) break; if (debugging) fprintf (stderr, "%s", buf); /* * skip comment or blank lines */ if (buf[0] == '#' || buf[0] == '\0' || buf[0] == '\n') continue; /* * parse the record and store in r */ parse_record (buf, &r); if (debugging) { fprintf(stderr,"name: %s\n",r.name ? r.name : "(NULL)"); fprintf(stderr,"section: %s\n",r.section ? r.section:"(NULL)"); fprintf(stderr,"subsect: %s\n",r.subsect ? r.subsect:"(NULL)"); fprintf(stderr,"desc: %s\n",r.desc ? r.desc : "(NULL)"); } /* * compare record's name field to all args from orig * command line. if we find one, flag notfound list */ for (i = 0, vp = argv; i < argc && *vp; vp++, i++) { /* * make a long list of things to search */ srch[0] = '\0'; if (r.name) { strcat (srch, r.name); strcat (srch, " "); } if (r.desc) { strcat (srch, r.desc); strcat (srch, " "); } for (j = 0; j < MAX_ALIAS; j++) { if (r.alias[j] == NULL) break; strcat (srch, r.alias[j]); strcat (srch, " "); } for (j = 0; j < MAX_KEYW; j++) { if (r.keyw[j] == NULL) break; strcat (srch, r.keyw[j]); strcat (srch, " "); } /* * check for a match... */ if (match_up (srch, *vp)) { print_record (verbose, &r); notfound[i] = 0; } } } /* * print a message if we didn't find anything for the cmdline arg */ if (verbose) { for (i = 0; i < argc; i++) { if (notfound[i]) { printf ("nothing appropriate in section %c for %s\n", sect, argv[i]); } } } return; } /*------------------------------*/ /* match_up */ /*------------------------------*/ int match_up (char *buf, char *str) { /* * search for string in str from a list contained in buf. this part * just advances a ptr to buf and calls a lower level routine. ret 1 * if there is a match, else 0. */ register char *pbuf; for (pbuf = buf; *pbuf; pbuf++) if (advance (pbuf, str)) return (1); return (0); } /*------------------------------*/ /* advance */ /*------------------------------*/ int advance (char *s1, char *s2) { /* * main matching driver. advances along each string. cmp_ign_case does * theactual char match. ret 1 if match, else 0. search is finished when * s2 is at EOS. */ while (*s1 && *s2 && ((*s1 == *s2) || cmp_ign_case ((int) (*s1), (int) (*s2)))) s1++, s2++; if (*s2 == 0) return (1); return (0); } /*------------------------------*/ /* cmp_ign_case */ /*------------------------------*/ int cmp_ign_case (int c1, int c2) { /* * char matching part. ignores case. must be alpha chars only! if * chars match, ret 1, else 0. c1 should probably always be alpha, * but check anyway. c2 comes from user. check it first for possible * quick exit. compare in lower case (since that is more probable * and the tolower could be skipped). * * consider inlining this... */ if (!isalpha (c2) || !isalpha (c1)) return (0); if (isupper (c1)) c1 = tolower (c1); if (isupper (c2)) c2 = tolower (c2); return (c1 == c2); } /*------------------------------*/ /* usage */ /*------------------------------*/ void usage (int excode) { #define U fprintf U(stderr,"usage: %s [-P path] [-s section] name ...\n", myname); U(stderr," -P path alternative path to databases (MANPATH)\n"); U(stderr," -s section limit search to single section, not all\n"); U(stderr," name name of a keyword (any single word).\n"); exit (excode); } @EOF set `sum $sumopt whatis/apropos.man <<'@EOF' @.\" $Id: apropos.man,v 2.0 1992/09/13 05:09:30 rosenkra Exp $ @.\" @.\" $Log: apropos.man,v $ @.\" Revision 2.0 1992/09/13 05:09:30 rosenkra @.\" total rewrite. this is first rev. @.\" @.TH APROPOS 1 @.SH NAME apropos \- find pertinent online documentation @.SH SYNOPSIS @.B apropos [ @.B \-P @.I path ] [ @.B \-s @.I section ] @.IR word ... @.SH DESCRIPTION The @.B apropos command displays a one line synopsis of each online documentation file whose name or description contains a specified @.I word or whose keywords listed in the @.I whatis databases matches the specified @.IR word . Once you know what you are looking for, use @.IR man (1) to read the appropriate documentation. @.PP The argument @.I word is considered separately from each other word. The case of letters is ignored. @.SH OPTIONS The following switch options are recognized: @.IP "\fB\-P \fIpath\fR" if a valid @.I path is given, @.B apropos searches for the databases there (see ENVIRONMENT). @.IP "\fB\-s \fIsection\fR" search only for items from the specified @.IR section . This should be a single character representing a section of the manual, i.e., from the list: @.nf 0123456789lno @.fi @.SH EXAMPLE Try \*(lqapropos editor\*(rq and \*(lqapropos disk\*(rq to get a feel for what @.B apropos does. @.SH ENVIRONMENT @.B Apropos searches for the database file in the directory contained in the @.B MANPATH environment variable. Note that the @.B \-P option overrides this. If neither @.B MANPATH or @.B \-P are specified, a default path of ``d:/usr/man'' is used. @.SH NOTES @.B Apropos performs a simple string search. For example, \*(lqapropos man\*(rq finds all instances of command, manipulate, mantissa, permanent, and so forth. @.SH FILES @.nf MANPATH/whatis._?_ online documentation database file @.fi @.SH "SEE ALSO" man(1), whatis(1), whatisin(1), whereis(1) @.SH AUTHOR Bill Rosenkranz @.br rosenkra AT convex DOT com @.SH VERSION apropos 2.0.1 92/9/12 rosenkra @EOF set `sum $sumopt whatis/common.c <<'@EOF' /* * common.c - stuff used by all programs */ static char *rcsid_common_c = "$Id: common.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; /* * $Log: common.c,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #include #include #include #include "whatis.h" extern int debugging; /*------------------------------*/ /* parse_record */ /*------------------------------*/ /* * macros to make parsing easier */ #define EOS '\0' #define NL '\n' #define FIELDSEP '%' #define ITEMSEP ',' #define END_OF_STRING(c) (c==EOS || c==NL) #define END_OF_FIELD(c) (c==FIELDSEP) #define END_OF_ITEM(c) (c==ITEMSEP) #define ADVANCE_FIELD \ while(!END_OF_STRING(*ps) && !END_OF_FIELD(*ps)){ps++;} \ if(END_OF_STRING(*ps)){*ps=EOS;return(lastone?0:1);} \ *ps++ = EOS; #define ADVANCE_ITEM \ while(!END_OF_STRING(*ps) && !END_OF_ITEM(*ps) && !END_OF_FIELD(*ps)){ps++;} \ if(END_OF_STRING(*ps)){*ps=EOS;return(lastone?0:1);} \ if(END_OF_FIELD(*ps)){*ps++ = EOS;break;} \ *ps++ = EOS; int parse_record (char *raw, struct rec *r) { /* * parse record. caller provides raw record and space for parsed * structure. ret 0 if all ok, else 1 (incomplete record, etc). * raw input is a null terminated string (with/without newline). */ char *ps = raw; int i; int lastone = 0; /* * set up default (empty) */ r->name = NULL; r->alias[0] = NULL; r->alias[1] = NULL; r->section = NULL; r->subsect = NULL; r->desc = NULL; r->xref[0] = NULL; r->xref[1] = NULL; r->keyw[0] = NULL; r->keyw[1] = NULL; /* * read name (required!) */ r->name = ps; ADVANCE_FIELD; /* * read any aliases (optional) */ if (ps[0] == '_' && (END_OF_FIELD(ps[1]) || END_OF_STRING(ps[1]))) { r->alias[0] = NULL; ADVANCE_FIELD; } else { for (i = 0; i < MAX_ALIAS-1; i++) { if (*ps == EOS) { r->alias[i] = NULL; return (1); } r->alias[i] = ps; r->alias[i+1] = NULL; ADVANCE_ITEM; } } /* * read section (required!) */ r->section = ps; ADVANCE_FIELD; /* * read subsection (optional) */ r->subsect = ps; ADVANCE_FIELD; if (r->subsect[0] == '_') r->subsect = NULL; /* * read description (required) */ r->desc = ps; ADVANCE_FIELD; /* * read any xrefs (optional) */ if (ps[0] == '_' && (END_OF_FIELD(ps[1]) || END_OF_STRING(ps[1]))) { r->xref[0] = NULL; ADVANCE_FIELD; } else { for (i = 0; i < MAX_XREF-1; i++) { if (*ps == EOS) { r->xref[i] = NULL; return (1); } r->xref[i] = ps; r->xref[i+1] = NULL; ADVANCE_ITEM; } } /* * read any keywords (optional) */ lastone = 1; if (ps[0] == '_' && (END_OF_FIELD(ps[1]) || END_OF_STRING(ps[1]))) { r->keyw[0] = NULL; return (1); } else { for (i = 0; i < MAX_KEYW-1; i++) { if (*ps == EOS) { r->keyw[i] = NULL; return (0); } r->keyw[i] = ps; r->keyw[i+1] = NULL; ADVANCE_ITEM; } } return (0); } /*------------------------------*/ /* print_record */ /*------------------------------*/ void print_record (int verbose, struct rec *r) { /* * print record. one line, just: * * name(sect[subsect]) - description. * * if verbose, add aliases, see also, and keywords, if any */ int i; if (r->name) printf ("%s", r->name); if (r->section) { printf ("(%s", r->section); if (r->subsect) printf ("%s", r->subsect); printf (") -"); } else printf (" -"); if (r->desc) printf (" %s\n", r->desc); else printf (" unknown (no description in database)\n"); if (!verbose) return; if (r->alias[0] != NULL) { printf ("\tprimary manpage:\n"); for (i = 0; r->alias[i] != NULL; i++) printf ("\t\t%s\n", r->alias[i]); } if (r->xref[0] != NULL) { printf ("\tsee also:\n"); for (i = 0; r->xref[i] != NULL; i++) printf ("\t\t%s\n", r->xref[i]); } if (r->keyw[0] != NULL) { printf ("\tkeywords:\n"); for (i = 0; r->keyw[i] != NULL; i++) printf ("\t\t%s\n", r->keyw[i]); } printf ("\n"); return; } #ifdef CHECK_MAGIC /*------------------------------*/ /* check_magic */ /*------------------------------*/ int check_magic (void) { /* * check magic "number" of file. if ok, return 0. else 1. * should be first line of file. check only MAGIC_CHECK_LEN bytes. */ char buf[REC_SIZE]; fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) return (1); if (debugging) fprintf (stderr, "magic: %s", buf); if (!strncmp (buf, MAGIC, MAGIC_CHECK_LEN)) return (0); return (1); } #endif /*CHECK_MAGIC*/ @EOF set `sum $sumopt whatis/makefile <<'@EOF' # makefile for whatis,whatisin,apropos # # version: # # $Id$ # # $Log$ # # compiler (use second set for MiNT): #SYSINC = c:/u/gcc/include #SYSLIB = c:/u/gcc/lib #SPECL = -nostdlib $(SYSLIB)/crt0.o SYSINC = SYSLIB = SPECL = #CC = gcc -z -Wall -v -I$(SYSINC) #LD = gcc -z -Wall -v -L$(SYSLIB) $(SPECL) CC = cc -Aa LD = cc -Aa #LIBS32 = -liio -lgnu #LIBS16 = -liio16 -lgnu16 LIBS32 = LIBS16 = USRLIBS = # if -mshort, use LIBS16... LIBS = $(USRLIBS) $(LIBS32) # compile/link options: DEFS = #-DCHECK_MAGIC OPT = #-O -fomit-frame-pointer DEBUG = #-DDEBUG PROF = # use -mshort for 16-bit version (make sure to change libs) ARCH = MISC = CFLAGS = $(DEBUG) $(PROF) $(ARCH) $(MISC) $(OPT) $(DEFS) LDFLAGS = $(DEBUG) $(PROF) $(ARCH) $(MISC) # targets, etc: EXE =#.exe SECT = 1 SUBSECT = TARG1 = whatis$(EXE) TARG2 = whatisin$(EXE) TARG3 = apropos$(EXE) TARGETS = $(TARG1) $(TARG2) $(TARG3) MANPAG1 = whatis.$(SECT) MANSRC1 = whatis.man MANPAG2 = whatisin.$(SECT) MANSRC2 = whatisin.man MANPAG3 = apropos.$(SECT) MANSRC3 = apropos.man MANPAG4 = whatis.5 MANSRC4 = whatis.ma5 MANPAGES = $(MANPAG1) $(MANPAG2) $(MANPAG3) $(MANPAG4) # commands used here: ECHO = echo CP = cp -p COMPRESS = compress RM = rm -f # headers, sources, and objects: HEADERS = whatis.h SRCS1 = whatis.c SRCS2 = whatisin.c SRCS3 = apropos.c COMSRC = common.c SRCS = $(SRCS1) $(SRCS2) $(SRCS3) $(COMSRC) OBJS1 = whatis.o OBJS2 = whatisin.o OBJS3 = apropos.o COMOBJ = common.o OBJS = $(OBJS1) $(OBJS2) $(OBJS3) $(COMOBJ) DATABASES = whatisin.___ whatis._1_ whatis._2_ whatis._4_ \ whatis._5_ whatis._7_ whatis._8_ #whatis._6_ whatis._3_ # distribution files (add others as needed): OTHERS = readme makefile $(MANSRC) todo DISTFILES = $(OTHERS) $(SRCS) $(HEADERS) LOG = compile.err # install directories, etc: #SLASH =\\ #BINDIR = c:\usr\bin #MANTOP = c:\usr\man #MANDIR = $(MANDIR)$(SLASH)man$(SECT) #MANDI5 = $(MANDIR)$(SLASH)man5 #CATDIR = $(MANTOP)$(SLASH)cat$(SECT) #CATDI5 = $(MANTOP)$(SLASH)cat5 SLASH =/ BINDIR = /mnt/rosenkra/test/bin MANTOP = /mnt/rosenkra/test/man MANDIR = $(MANTOP)$(SLASH)man$(SECT) MANDI5 = $(MANTOP)$(SLASH)man5 CATDIR = $(MANTOP)$(SLASH)cat$(SECT) CATDI5 = $(MANTOP)$(SLASH)cat5 # install commands # INST_BIN = cp -p INST_MAN = cp -p # directions... # directions: @$(ECHO) type make all to built $(TARGETS) @$(ECHO) type make install to build/install $(TARGET) @$(ECHO) type make clean to remove objects @$(ECHO) type make clobber to remove objects and $(TARGETS) @$(ECHO) these should be done in this order # main target (make all)... # all: $(TARGETS) mkwhatis$(EXE) $(TARG1): $(COMOBJ) $(OBJS1) $(LD) $(LDFLAGS) -o $(TARG1) $(OBJS1) $(COMOBJ) $(LIBS) @$(ECHO) done making $(TARG1) $(TARG2): $(COMOBJ) $(OBJS2) $(LD) $(LDFLAGS) -o $(TARG2) $(OBJS2) $(COMOBJ) $(LIBS) @$(ECHO) done making $(TARG2) $(TARG3): $(COMOBJ) $(OBJS3) $(LD) $(LDFLAGS) -o $(TARG3) $(OBJS3) $(COMOBJ) $(LIBS) @$(ECHO) done making $(TARG3) mkwhatis$(EXE): mkwhatis.o $(LD) $(LDFLAGS) -o mkwhatis$(EXE) mkwhatis.o $(LIBS) # manpage (use built-in .man.cat rule)... # manpage: $(MANPAGES) $(MANPAG1): $(MANSRC1) nroff -man $(MANSRC1)|ul -t dumb|cat -s >$(MANPAG1) $(MANPAG2): $(MANSRC2) nroff -man $(MANSRC2)|ul -t dumb|cat -s >$(MANPAG2) $(MANPAG3): $(MANSRC3) nroff -man $(MANSRC3)|ul -t dumb|cat -s >$(MANPAG3) $(MANPAG4): $(MANSRC4) nroff -man $(MANSRC4)|ul -t dumb|cat -s >$(MANPAG4) install: install_bin install_man install_mkwhatis install_databases install_mkwhatis: mkwhatis$(EXE) $(INST_BIN) mkwhatis$(EXE) $(BINDIR)$(SLASH)mkwhatis$(EXE) nroff -man mkwhatis.ma8|ul -t dumb|cat -s >mkwhatis.8 $(INST_MAN) mkwhatis.ma8 $(MANDIR)$(SLASH)mkwhatis.8 $(INST_MAN) mkwhatis.8 $(CATDIR)$(SLASH)mkwhatis.8 touch install_mkwhatis install_bin: $(TARGETS) $(INST_BIN) $(TARG1) $(BINDIR)$(SLASH)$(TARG1) $(INST_BIN) $(TARG2) $(BINDIR)$(SLASH)$(TARG2) $(INST_BIN) $(TARG3) $(BINDIR)$(SLASH)$(TARG3) touch install_bin install_man: $(MANPAGES) $(INST_MAN) $(MANSRC1) $(MANDIR)$(SLASH)$(MANPAG1) $(INST_MAN) $(MANSRC2) $(MANDIR)$(SLASH)$(MANPAG2) $(INST_MAN) $(MANSRC3) $(MANDIR)$(SLASH)$(MANPAG3) $(INST_MAN) $(MANSRC4) $(MANDI5)$(SLASH)$(MANPAG4) $(INST_MAN) $(MANPAG1) $(CATDIR)$(SLASH)$(MANPAG1) $(INST_MAN) $(MANPAG2) $(CATDIR)$(SLASH)$(MANPAG2) $(INST_MAN) $(MANPAG3) $(CATDIR)$(SLASH)$(MANPAG3) $(INST_MAN) $(MANPAG4) $(CATDI5)$(SLASH)$(MANPAG4) touch install_man install_databases: $(INST_MAN) $(DATABASES) $(MANTOP) touch install_databases # others... # clean: $(RM) $(OBJS) $(LOG) core mkwhatis.o clobber: clean $(RM) $(TARGETS) mkwhatis $(RM) install_bin install_man $(RM) install_mkwhatis install_databases # dependencies... # $(COMOBJ): $(HEADERS) $(OBJS1): $(HEADERS) $(OBJS2): $(HEADERS) $(OBJS3): $(HEADERS) @EOF set `sum $sumopt whatis/mkwhatis.8 <<'@EOF' MKWHATIS(8) MKWHATIS(8) NAME mkwhatis - tool for making entries in whatis(1) databases SYNOPSIS mkwhatis manpage... DESCRIPTION mkwhatis reads the input files (which should be manpage source files) and extracts information for the database used by whatis(1). It is not perfect, but should help substantially in this otherwise tedious task. NOTES For the format of the whatis database, see whatis(5). whatis assumes manpages that look like this: .TH FOO 1X <-- section, subsection .SH NAME foo \- blah blah blah <-- name, desc .SH DESCIPTION . . . .SH "SEE ALSO" bar(1), foobar(5) <-- cross references .SH SOMETHING (or eof) or .TH FOO 1 LOCAL . . . It does not handle sourced files (aliases), ie: .so man1/foo.1 At a minimum, you will have to add keywords yourself. SEE ALSO man(1), whatis(1), whatisin(1), apropos(1), whatis(5) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION mkwhatis 2.0.1 92/9/12 rosenkra - 1 - Formatted: June 18, 1995 @EOF set `sum $sumopt whatis/mkwhatis.c <<'@EOF' /* * 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 $"; static char *version = "mkwhatis 2.0 92/09/13 rosenkra AT convex DOT com"; static char *myname = "mkwhatis"; /* * $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,"%s\n", version); fprintf (stderr, "usage: %s [-A | -N | -S | -B] file...\n", myname); exit (1); } } /* * args are manpage source files */ for ( ; argc && *argv; argc--, argv++) { if ((stream = fopen (*argv, "r")) == (FILE *) NULL) { fprintf (stderr, "%s: could not open %s\n", myname, *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; } @EOF set `sum $sumopt whatis/mkwhatis.ma8 <<'@EOF' @.\" $Id: mkwhatis.ma8,v 2.0 1992/09/13 05:09:30 rosenkra Exp $ @.\" @.\" $Log: mkwhatis.ma8,v $ @.\" Revision 2.0 1992/09/13 05:09:30 rosenkra @.\" total rewrite. this is first rev. @.\" @.TH MKWHATIS 8 @.SH NAME mkwhatis \- tool for making entries in whatis(1) databases @.SH SYNOPSIS @.B mkwhatis @.IR manpage ... @.SH DESCRIPTION @.B mkwhatis reads the input files (which should be manpage source files) and extracts information for the database used by @.IR whatis (1). It is not perfect, but should help substantially in this otherwise tedious task. @.SH NOTES For the format of the @.I whatis database, see @.IR whatis (5). @.PP @.B whatis assumes manpages that look like this: @.nf \&.TH FOO 1X <-- section, subsection \&.SH NAME foo \\- blah blah blah <-- name, desc \&.SH DESCIPTION \&. \&. \&. \&.SH "SEE ALSO" bar(1), foobar(5) <-- cross references \&.SH SOMETHING (or eof) or \&.TH FOO 1 LOCAL \&. \&. \&. @.fi It does @.I not handle sourced files (aliases), ie: @.nf \&.so man1/foo.1 @.fi At a minimum, you will have to add keywords yourself. @.SH "SEE ALSO" man(1), whatis(1), whatisin(1), apropos(1), whatis(5) @.SH AUTHOR Bill Rosenkranz @.br rosenkra AT convex DOT com @.SH VERSION mkwhatis 2.0.1 92/9/12 rosenkra @EOF set `sum $sumopt whatis/whatis.1 <<'@EOF' WHATIS(1) WHATIS(1) NAME whatis - show description of word SYNOPSIS whatis [ -l ] [ -P path ] [ -s section ] word... DESCRIPTION The whatis command displays a one line synopsis of each online documentation file whose name matches the specified word. To read the actual online documentation, use the man(1) command. Word is considered separately from each other word. The case of letters is significant. OPTIONS The following switch options are recognized: -l a more verbose (long) output is given containing the one line description plus a list of keywords, cross references, and the primary manual page, if any. -P path if a valid path is given, whatis searches for the databases there (see ENVIRONMENT). -s section search only for items from the specified section. This should be a single character representing a section of the manual, i.e., from the list: 0123456789lno ENVIRONMENT Whatis searches for the database file in the directory contained in the MANPATH environment variable. Note that the -P option overrides this. If neither MANPATH or -P are specified, a default path of ``d:/usr/man'' is used. FILES MANPATH/whatis._?_ online documentation database file SEE ALSO apropos(1), man(1), whatisin(1), whereis(1) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION whatis v2.0.1 92/9/12 rosenkra - 1 - Formatted: June 18, 1995 @EOF set `sum $sumopt whatis/whatis.5 <<'@EOF' WHATIS(5) WHATIS(5) NAME whatis - format of whatis(1) database DESCRIPTION These files are used by whatis(1), apropos(1), and whatisin(1). The databases are kept in separate file for each section of the manual, i.e., whatis._0_ whatis._1_ whatis._2_ etc. whatis._l_ whatis._n_ whatis._o_ Each line is either a comment or data. Comments are blank lines or those whose first character is a `#'. The format for each data line of the 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 manual 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-separated list. (optional) Optional or unspecified fields contain only a `_' char. Here is an example: unixmode%_%5%_%Extended Filename Standard%sh(1)%MiNT,file SEE ALSO whatis(1), apropos(1), whatisin(1), mkwhatis(8) - 1 - Formatted: June 18, 1995 WHATIS(5) WHATIS(5) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION whatis.5 v2.0.1 92/9/12 rosenkra - 2 - Formatted: June 18, 1995 @EOF set `sum $sumopt whatis/manifest <<'@EOF' README.all top level readme for man and whatis README readme for whatis makefile makefile to build apropos, whatis, and whatisin apropos.1 formated manpage for apropos program apropos.c source for apropos program apropos.man unformatted manpage for apropos (nroff -man) whatis.1 formated manpage for whatis program whatis.5 formated manpage for whatis database format whatis.man unformatted manpage for whatis program (nroff -man) whatis.ma5 unformatted manpage for whatis database format (nroff -man) whatis.c source for whatis program whatis.h ditto whatisin.1 formated manpage for whatisin program whatisin.man unformatted manpage for whatisin (nroff -man) whatisin.c source for whatisin program common.c common source code for apropos, whatis, etc. mkwhatis.8 formated manpage for mkwhatis program mkwhatis.ma8 unformatted manpage for mkwhatis (nroff -man) mkwhatis.c source for mkwhatis program. this is a tool to help build the whatis databases from unformatted manpages whatis._?_ example whatis databases. the number corresponds to the section of the manual (1=commands, 2=system calls, etc) whatisin.___ whatisin database manifest this file @EOF set `sum $sumopt whatis/whatis.c <<'@EOF' #undef DEBUG #undef CHECK_MAGIC /* * whatis - show description of word from man database * * whatis [-l] [-P path] [-s sect] name ... * * bugs: * - need more error checking (of data in database) * - perhaps a "magic number" for the database? it is * written, but #ifdef CHECK_MAGIC. * * todo: * - allow "-s n name name -s m name ..." * - allow continuation lines in database: * * name\ * %1\ * %... */ static char *rcsid_whatis_c = "$Id: whatis.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; static char *version = "whatis 2.0 92/09/13 rosenkra AT convex DOT com"; static char *myname = "whatis"; /* * $Log: whatis.c,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #include #include #include #include #include "whatis.h" /* * we only need one record here. we read a record and check all the * command line args against it for a match */ struct rec r; char *libpath = MANPATH; /* path to database files (-P) */ int debugging = 0; /* for -d */ /* * fcn prototypes */ void whatis (int, int, int, char **); void usage (int); int parse_record (char *, struct rec *); void print_record (int, struct rec *); #ifdef CHECK_MAGIC int check_magic (void); #endif /*------------------------------*/ /* main */ /*------------------------------*/ void main (int argc, char *argv[]) { int sect = -1; int verbose = 0; char *lpath; char *ps; /* * see if there is MANPATH in env. use it over default... */ if ((lpath = getenv ("MANPATH")) != (char *) NULL) libpath = lpath; else if ((lpath = getenv ("MANDIR")) != (char *) NULL) libpath = lpath; #ifdef DEBUG else fprintf (stderr, "whatis: environment variable MANPATH not set, using default\n"); #endif /* * parse args */ for (argc--, argv++; argc && **argv == '-'; argc--, argv++) { switch (*(*argv+1)) { case 'P': /* path for db */ case 'M': argc--, argv++; if (argc < 1) usage (1); libpath = *argv; break; case 's': /* specific section */ argc--, argv++; if (argc < 1) usage (1); sect = **argv; break; case 'l': /* long (verbose) */ verbose = 1; break; case 'd': /* debug mode */ debugging = 1; break; case 'v': /* version */ printf ("%s\n", version); exit (0); break; case 'h': /* help */ usage (0); break; case '-': switch (*(*argv+2)) { case 'v': /* --version */ printf ("%s\n", version); exit (0); break; case 'h': /* --help */ usage (0); break; } break; } } /* * whatis what? */ if (argc == 0) { fprintf (stderr, "%s: you must specify an argument. consider using whatisin.\n", myname); usage (1); } /* * not documented: if first arg is a number, use it for section... */ if (isdigit(**argv)) { sect = **argv; argc--, argv++; } /* * do it. if specific section, search it only. else search all * sections */ if (sect != -1) { whatis (verbose, sect, argc, argv); } else { for (ps = SECTIONS; *ps; ps++) { sect = *ps; whatis (verbose, sect, argc, argv); } } exit (0); } /*------------------------------*/ /* whatis */ /*------------------------------*/ void whatis (int verbose, int sect, int argc, char **argv) { #define MAX_ARGS 100 char dbname[256]; char buf[REC_SIZE]; register char **vp; int notfound[MAX_ARGS]; int i; /* * FIXME: we should allocate space for the notfound list. */ if (argc > MAX_ARGS) argc = MAX_ARGS; /* * set up db name. section is really a single ascii char, not an * int. this is so we can have whatis for local, new, etc. */ if (sect == -1) /* orig behavior (just single "whatis" file, never used here) */ sprintf (dbname, "%s%s%s", libpath, SLASH, WHATIS); else /* new: whatis._[0-9lno]_ */ sprintf (dbname, "%s%s%s._%c_", libpath, SLASH, WHATIS, sect); /* * reopen stdin as this file... */ if (debugging) fprintf (stderr, "checking database file %s...\n", dbname); if (freopen (dbname, "r", stdin) == (FILE *) NULL) { /* if (verbose || debugging)*/ if (debugging) fprintf (stderr, "%s: could not access file %s\n", myname, dbname); return; } #ifdef CHECK_MAGIC /* * check file's magic */ if (check_magic ()) { fprintf (stderr, "%s: magic number is wrong for file %s\n", myname, dbname); return; } #endif /* * read file and compare. first assume we will not find anything * and flag list... */ for (i = 0; i < MAX_ARGS; i++) notfound[i] = 1; while (1) { /* * get raw record from file */ fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) break; if (debugging) fprintf (stderr, "%s", buf); /* * skip comment or blank lines */ if (buf[0] == '#' || buf[0] == '\0' || buf[0] == '\n') continue; /* * parse the record and store in r */ parse_record (buf, &r); if (debugging) { fprintf (stderr, "name: %s\n", r.name ? r.name : "(NULL)"); fprintf (stderr, "section: %s\n", r.section ? r.section : "(NULL)"); fprintf (stderr, "subsect: %s\n", r.subsect ? r.subsect : "(NULL)"); fprintf (stderr, "desc: %s\n", r.desc ? r.desc : "(NULL)"); } /* * compare record's name field to all args from orig * command line. if we find one, flag notfound list */ for (i = 0, vp = argv; i < argc && *vp; vp++, i++) { if (!strncmp (r.name, *vp, strlen (*vp))) { print_record (verbose, &r); notfound[i] = 0; } } } /* * print a message if we didn't find anything for the cmdline arg */ if (verbose) { for (i = 0; i < argc; i++) { if (notfound[i]) { printf ("nothing found in section %c for %s\n", sect, argv[i]); } } } return; } /*------------------------------*/ /* usage */ /*------------------------------*/ void usage (int excode) { #define U fprintf U(stderr,"usage: %s [-l] [-P path] [-s section] name ...\n", myname); U(stderr," -l long list\n"); U(stderr," -P path alternative path to databases (MANPATH)\n"); U(stderr," -s section search single section, not all\n"); U(stderr," name valid name of a command, etc. if name is unknown,\n"); U(stderr," consider using whatisin(1) or apropos(1).\n"); exit (excode); } @EOF set `sum $sumopt whatis/whatis.h <<'@EOF' /* * whatis.h */ static char *rcsid_whatis_h = "$Id: whatis.h,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; /* * $Log: whatis.h,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #ifdef CHECK_MAGIC #define MAGIC "WHATIS/ST" /* file's magic */ #define MAGIC_CHECK_LEN 9 /* how much of magic has to match? */ /* rest is comment. this MAGIC is */ /* for whatis._?_ files */ #endif #if defined(unix) || defined(__unix) #define MANPATH "/usr/man\0\0<-----------patch space------------->" /* db is $MANPATH/whatis._?_ */ #else #define MANPATH "c:\\usr\\man\0\0<-----------patch space------------->" /* db is $MANPATH/whatis._?_ */ #endif #define WHATIS "whatis" /* db name (root) */ #define WHATISIN "whatisin" /* list of sections */ #define SECTIONS "0123456789lno\0\0<----------patch space------------->" /* list of sections */ #if defined(unix) || defined(__unix) #define SLASH "/" /* use "/" for unix, UNIXMODE */ #else #define SLASH "\\" /* use "/" for unix, UNIXMODE */ #endif #define REC_SIZE 1024 /* max line length in database */ #define MAX_ALIAS 10 /* max number of aliases, */ #define MAX_XREF 50 /* cross refs, and */ #define MAX_KEYW 50 /* keywords */ /* * record structure (after reading from file) */ struct rec { char *name; char *alias[MAX_ALIAS]; char *section; char *subsect; char *desc; char *xref[MAX_XREF]; char *keyw[MAX_KEYW]; }; @EOF set `sum $sumopt 0T*+DE2('=H871I')E9G,EX M:V5Y=V]R9',-"@T*+F9I#0HN25 @;F%M92 Q- AT T*<')O9W)A;2]R;W5T:6YEX M+V5T8R!N86UE+@T**')E<75I2!D97-C&UO9&4E7R4U)5\E17AT96YD960 AT X M1FEL96YA;64 AT 4W1A;F1A"YC;VT-"BY32"!615)324].#0IW:&%T:7,NX ;-2!V,BXP+C$@.3(O.2\Q,B!R;W-E;FMR80T* X X end @eof set `sum $sumopt whatis/whatis.man <<'@EOF' @.\" $Id: whatis.man,v 2.0 1992/09/13 05:09:30 rosenkra Exp $ @.\" @.\" $Log: whatis.man,v $ @.\" Revision 2.0 1992/09/13 05:09:30 rosenkra @.\" total rewrite. this is first rev. @.\" @.TH WHATIS 1 @.SH NAME whatis \- show description of word @.SH SYNOPSIS @.B whatis [ @.B \-l ] [ @.B \-P @.I path ] [ @.B \-s @.I section ] @.IR word ... @.SH DESCRIPTION The @.B whatis command displays a one line synopsis of each online documentation file whose name matches the specified @.IR word . To read the actual online documentation, use the @.IR man (1) command. @.PP @.I Word is considered separately from each other word. The case of letters is significant. @.SH OPTIONS The following switch options are recognized: @.IP \fB\-l\fR a more verbose (long) output is given containing the one line description plus a list of keywords, cross references, and the primary manual page, if any. @.IP "\fB\-P \fIpath\fR" if a valid @.I path is given, @.B whatis searches for the databases there (see ENVIRONMENT). @.IP "\fB\-s \fIsection\fR" search only for items from the specified @.IR section . This should be a single character representing a section of the manual, i.e., from the list: @.nf 0123456789lno @.fi @.SH ENVIRONMENT @.B Whatis searches for the database file in the directory contained in the @.B MANPATH environment variable. Note that the @.B \-P option overrides this. If neither @.B MANPATH or @.B \-P are specified, a default path of ``d:/usr/man'' is used. @.SH FILES @.nf MANPATH/whatis._?_ online documentation database file @.fi @.SH "SEE ALSO" apropos(1), man(1), whatisin(1), whereis(1) @.SH AUTHOR Bill Rosenkranz @.br rosenkra AT convex DOT com @.SH VERSION whatis v2.0.1 92/9/12 rosenkra @EOF set `sum $sumopt whatis/whatisin.1 <<'@EOF' WHATISIN(1) WHATISIN(1) NAME whatisin - show contents of online documentation section SYNOPSIS whatisin [ -P path ] [ section ] DESCRIPTION The whatisin command displays a one line synopsis of each file in a specified online documentation section. To read the actual online documentation, use the man(1) command. The argument section specifies a section similar to those in the 4.2 BSD UNIX Programmer's Manual (as explained below). In this case, the description of that section is printed along with a full list of all documentation in that section. If no section is specified, whatisin displays a list of sections. OPTIONS The following switch options are recognized: -P path if a valid path is given, whatisin searches for the databases there (see ENVIRONMENT). SECTION NAMES The sections of the manual are based on the Unix Programmer's Manual: Sect UNIX Manual Description ---- ----------- ----------- 0 General overview of features and documentation 1 Commands commands (like those in n )2 System calls low-level library calls (C) 3 Subroutines standard user calls (C) 4 Special files things like emacs .CMD files 5 File formats things like arc file formats 6 Games games manual 7 Miscellaneous miscellaneous information 8 Maintenance system administration commands In addition, whatisin recognizes the following section names: l local files specific to local system n new files added since current software release o old files from previous software release ENVIRONMENT Whatisin searches for the database file in the directory contained in the MANPATH environment variable. Note that the -P option overrides this. If neither MANPATH or -P are specified, a default path of ``d:/usr/man'' is used. - 1 - Formatted: June 18, 1995 WHATISIN(1) WHATISIN(1) FILES MANPATH/whatisin.___ manual section list (contents) MANPATH/whatis._?_ online documentation database files SEE ALSO apropos(1), man(1), whatis(1), whereis(1) AUTHOR Bill Rosenkranz rosenkra AT convex DOT com VERSION whatisin 2.0.1 92/9/12 rosenkra - 2 - Formatted: June 18, 1995 @EOF set `sum $sumopt whatis/whatisin.c <<'@EOF' #undef DEBUG #undef CHECK_MAGIC /* * whatisin - show list of documentation sections * * whatisin [-P path] [section] * * reads both $MANPATH/whatisin and $MANPATH/whatis._?_ files * * bugs: * - need more error checking (of data in database) * - perhaps a "magic number" for the whatis database? it is * written, but #ifdef CHECK_MAGIC. * * todo: * - invoke PAGER (or MANPAGER) on list if sections specified * - allow continuation lines in whatis database: * * name\ * %1\ * %... */ static char *rcsid_whatisin_c = "$Id: whatisin.c,v 2.0 1992/09/13 05:02:44 rosenkra Exp $"; static char *version = "whatisin 2.0 92/09/13 rosenkra AT convex DOT com"; static char *myname = "whatisin"; /* * $Log: whatisin.c,v $ * Revision 2.0 1992/09/13 05:02:44 rosenkra * total rewrite. this if first rev of this file. * * */ #include #include #include #include "whatis.h" /* * we only need one record here. we read a record and check all the * command line args against it for a match */ struct rec r; char *libpath = MANPATH; int debugging = 0; /* for -d */ /* * fcn prototypes */ void whatisin (int, char **); void contents (int); int parse_record (char *, struct rec *); void print_record (int, struct rec *); void usage (int); #ifdef CHECK_MAGIC int check_magic (void); #endif /*------------------------------*/ /* main */ /*------------------------------*/ void main (int argc, char *argv[]) { char *lpath; /* * see if there is MANPATH in env. use it over default... */ if ((lpath = getenv ("MANPATH")) != (char *) NULL) libpath = lpath; else if ((lpath = getenv ("MANDIR")) != (char *) NULL) libpath = lpath; #ifdef DEBUG else fprintf (stderr, "whatisin: environment variable MANPATH not set, using default\n"); #endif /* * parse args */ for (argc--, argv++; argc && **argv == '-'; argc--, argv++) { switch (*(*argv+1)) { case 'P': /* path for db */ case 'M': argc--, argv++; if (argc < 1) usage (1); libpath = *argv; break; case 'd': /* debug mode */ debugging = 1; break; case 'v': /* version */ printf ("%s\n", version); exit (0); break; case 'h': /* help */ usage (0); break; case '-': switch (*(*argv+2)) { case 'v': /* --version */ printf ("%s\n", version); exit (0); break; case 'h': /* --help */ usage (0); break; } break; } } /* * do it. if no args, print file containing description of sections. * else print contents of sections in argv list */ if (argc < 1) whatisin (argc, argv); else while (argc) whatisin (argc--, argv++); exit (0); } /*------------------------------*/ /* whatisin */ /*------------------------------*/ void whatisin (int argc, char **argv) { char dbname[256]; char buf[REC_SIZE]; int doall = 0; int sect; int foundit = 0; /* * if no args specified, we only want a description of each section. * otherwise, set sect to that specified in argv. should be single * char (0-9,l,n,o, etc). */ if (argc == 0) doall++; else { doall = 0; sect = **argv; } /* * set up name of whatisin database and open it */ sprintf (dbname, "%s%s%s.___", libpath, SLASH, WHATISIN); if (freopen (dbname, "r", stdin) == (FILE *) NULL) { fprintf (stderr, "%s: could not access file %s\n", myname, dbname); exit (1); } if (doall) { /* * just copy whatisin file. skip lines starting with # */ while (1) { fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) break; if (buf[0] == '#') continue; fputs (buf, stdout); } } else { /* * look for line describing section */ while (1) { fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) break; if (buf[0] == sect) { foundit++; break; } } if (foundit) { /* * print header info then get print all the * things in that section. contents will reopen * stdin as the particular whatis database. */ printf ("Section Description\n"); printf ("------- -----------\n"); printf ("%s\n\n", buf); printf ("Contents\n"); printf ("--------\n"); contents (sect); printf ("\n"); } else { fprintf (stderr, "%s: no section %c\n", myname, sect); exit (1); } } return; } /*------------------------------*/ /* contents */ /*------------------------------*/ void contents (int sect) { char dbname[256]; char buf[REC_SIZE]; /* * set up db name. section is really a single ascii char, not an * int. this is so we can have whatis for local, new, etc. */ if (sect == -1) /* orig behavior (just single "whatis" file, never used here) */ sprintf (dbname, "%s%s%s", libpath, SLASH, WHATIS); else /* new: whatis._[0-9lno]_ */ sprintf (dbname, "%s%s%s._%c_", libpath, SLASH, WHATIS, sect); /* * reopen stdin as this file... */ if (debugging) fprintf (stderr, "checking database file %s...\n", dbname); if (freopen (dbname, "r", stdin) == (FILE *) NULL) { fprintf (stderr, "%s: could not access file %s\n", myname, dbname); exit (1); } #ifdef CHECK_MAGIC /* * check file's magic */ if (check_magic ()) { fprintf (stderr, "%s: magic number is wrong for file %s\n", myname, dbname); exit (1); } #endif /* * read file and print lines */ while (1) { /* * get raw record from file */ fgets (buf, REC_SIZE-1, stdin); if (feof (stdin)) break; if (debugging) fprintf (stderr, "%s", buf); /* * skip comment or blank lines */ if (buf[0] == '#' || buf[0] == '\0' || buf[0] == '\n') continue; /* * parse the record and store in r */ parse_record (buf, &r); if (debugging) { fprintf (stderr, "name: %s\n", r.name ? r.name : "(NULL)"); fprintf (stderr, "section: %s\n", r.section ? r.section : "(NULL)"); fprintf (stderr, "subsect: %s\n", r.subsect ? r.subsect : "(NULL)"); fprintf (stderr, "desc: %s\n", r.desc ? r.desc : "(NULL)"); } /* * print record (short form) */ print_record (0, &r); } return; } /*------------------------------*/ /* usage */ /*------------------------------*/ void usage (int excode) { #define U fprintf U(stderr,"usage: %s [-P path] [section ...]\n", myname); U(stderr," -P path alternative path to databases (MANPATH)\n"); U(stderr," section valid name of a manual section (single char). to get a\n"); U(stderr," list, invoke whatisin with no args.\n"); exit (excode); #undef U } @EOF set `sum $sumopt whatis/whatisin.man <<'@EOF' @.\" $Id: whatisin.man,v 2.0 1992/09/13 05:09:30 rosenkra Exp $ @.\" @.\" $Log: whatisin.man,v $ @.\" Revision 2.0 1992/09/13 05:09:30 rosenkra @.\" total rewrite. this is first rev. @.\" @.TH WHATISIN 1 @.SH NAME whatisin \- show contents of online documentation section @.SH SYNOPSIS @.B whatisin [ @.B \-P @.I path ] [ @.I section ] @.SH DESCRIPTION The @.B whatisin command displays a one line synopsis of each file in a specified online documentation section. To read the actual online documentation, use the @.IR man (1) command. @.PP The argument @.I section specifies a \*(lqsection\*(rq similar to those in the 4.2 BSD UNIX Programmer's Manual (as explained below). In this case, the description of that section is printed along with a full list of all documentation in that section. @.PP If no section is specified, @.B whatisin displays a list of sections. @.SH OPTIONS The following switch options are recognized: @.IP "\fB\-P \fIpath\fR" if a valid @.I path is given, @.B whatisin searches for the databases there (see ENVIRONMENT). @.SH "SECTION NAMES" The sections of the manual are based on the Unix Programmer's Manual: @.sp @.nf Sect UNIX Manual Description ---- ----------- ----------- 0 General overview of features and documentation 1 Commands commands (like those in \bin) 2 System calls low-level library calls (C) 3 Subroutines standard user calls (C) 4 Special files things like emacs .CMD files 5 File formats things like arc file formats 6 Games games manual 7 Miscellaneous miscellaneous information 8 Maintenance system administration commands @.fi @.sp In addition, @.B whatisin recognizes the following section names: @.sp @.nf l local files specific to local system n new files added since current software release o old files from previous software release @.fi @.SH ENVIRONMENT @.B Whatisin searches for the database file in the directory contained in the @.B MANPATH environment variable. Note that the @.B \-P option overrides this. If neither @.B MANPATH or @.B \-P are specified, a default path of ``d:/usr/man'' is used. @.SH FILES @.nf MANPATH/whatisin.___ manual section list (contents) MANPATH/whatis._?_ online documentation database files @.fi @.SH "SEE ALSO" apropos(1), man(1), whatis(1), whereis(1) @.SH AUTHOR Bill Rosenkranz @.br rosenkra AT convex DOT com @.SH VERSION whatisin 2.0.1 92/9/12 rosenkra @EOF set `sum $sumopt