|
|
1.1 root 1: /*
2: * help.c
3: * 10/7/91
4: * Usage: help [ -dc ] [ -ffile ] [ -ifile] [ -r ] [ topic ] ...
5: * Options:
6: * -dc Use c as delimiter character (default: '#')
7: * -ffile Use file as helpfile (default: /etc/helpfile)
8: * -iindex Use index as helpindex (default: /�tc/helpindex)
9: * -r Rebuild helpindex and exit
10: * Print command help information as given in HELPFILE.
11: * Also looks for user-specific information in file $HELP.
12: * Pipes output through $PAGER if defined.
13: */
14:
15: #include <stdio.h>
16: #include <sys/stat.h>
17:
18: /* Externals. */
19: char *getenv();
20:
21: /* Manifest constants. */
22: #define VERSION "1.3" /* Version number */
23: #define NLINE 512 /* Longest helpfile line */
24: #define DELIM '#' /* Default delimiter */
25: #define HELPFILE "/etc/helpfile" /* Default helpfile */
26: #define HELPINDEX "/etc/helpindex" /* Default helpindex */
27: #define MAXNAME 80 /* Max name length */
28: #define USAGE "Usage: help [ -dc ] [ -ffile ] [ -ifile] [ -r ] [ topic ] ...\n"
29:
30: /* Structure to speed lookup time. */
31: typedef struct look {
32: long l_seek; /* seek into helpfile */
33: char *l_name; /* topic */
34: } LOOK;
35:
36: /* Globals. */
37: char buf[BUFSIZ]; /* Input buffer */
38: char delim = DELIM; /* Help file delimiter */
39: char *helpfile = HELPFILE; /* Help file */
40: char *helpindex = HELPINDEX; /* Help index */
41: char helpline[NLINE]; /* Help file text line */
42: FILE *ofp = NULL; /* Output file */
43: int rflag; /* Rebuild helpindex */
44: FILE *shf; /* System helpfile */
45: FILE *uhf; /* User helpfile */
46:
47: /* Forward. */
48: int fastlook();
49: int help();
50: int lookup();
51: LOOK *lread();
52: int rebuild();
53: void usage();
54:
55: main(argc, argv) int argc; char *argv[];
56: {
57: register char **ap;
58: register int status;
59: char *cp;
60: char *list[2];
61:
62: /* Process command line options. */
63: while (argc > 1 && argv[1][0] == '-') {
64: switch(argv[1][1]) {
65: case 'd': delim = argv[1][2]; break;
66: case 'f': helpfile = &argv[1][2]; break;
67: case 'i': helpindex = &argv[1][2]; break;
68: case 'r': rflag++; break;
69: case 'V':
70: fprintf(stderr, "help: V%s\n", VERSION);
71: break;
72: default: usage(); break;
73: }
74: --argc;
75: ++argv;
76: }
77:
78: /* Open files and read environmental variables. */
79: shf = fopen(helpfile, "r"); /* system helpfile */
80: if (rflag)
81: exit(rebuild(shf, helpindex));
82: if ((cp = getenv("HELP")) != NULL)
83: uhf = fopen(cp, "r"); /* user helpfile */
84: if ((cp = getenv("PAGER")) != NULL && *cp != '\0' && isatty(fileno(stdout)))
85: ofp = popen(cp, "w");
86: if (ofp == NULL) {
87: ofp = stdout;
88: setbuf(stdout, buf);
89: }
90: ap = ++argv;
91:
92: /* If no args, print help info and LASTERROR info. */
93: status = 0;
94: if (argc < 2) {
95: fprintf(stderr,
96: "The 'help' command prints a brief description of the usage of a command.\n"
97: "For example, to get information about the 'who' command, type:\n"
98: "\thelp who\n"
99: "The 'man' command provides more detailed descriptions of commands.\n"
100: "\n"
101: );
102: if ((list[0] = getenv("LASTERROR")) == NULL)
103: exit(status);
104: list[1] = NULL;
105: ap = list;
106: }
107:
108: /* Print help info on requested topics. */
109: while (*ap != NULL) {
110: if (help(*ap)) {
111: fprintf(stderr, "help: no information on %s\n", *ap);
112: status = 1;
113: }
114: if (*++ap != NULL)
115: fputc('\n', ofp);
116: fflush(ofp);
117: }
118:
119: /* Done, clean up. */
120: if (ofp != stdout)
121: pclose(ofp);
122: if (shf != NULL)
123: fclose(shf);
124: if (uhf != NULL)
125: fclose(uhf);
126: exit(status);
127: }
128:
129: /*
130: * Possibly seek the helpfile 'fp' to the right place based on helpindex 'ind'.
131: * Return 0 if found, 1 if not found.
132: * Rebuild the index file if it is out of date.
133: */
134: int
135: fastlook(cmd, fp, ind) char *cmd; FILE *fp; char *ind;
136: {
137: register LOOK *lp;
138: register FILE *ifp;
139: struct stat sb;
140: long htime;
141: int status;
142:
143: fstat(fileno(fp), &sb);
144: htime = sb.st_mtime; /* helpfile mtime */
145: if (stat(ind, &sb) < 0 || htime > sb.st_mtime)
146: rebuild(fp, ind);
147: status = 1;
148: if ((ifp = fopen(ind, "r")) == NULL)
149: return status;
150: while ((lp = lread(ifp)) != NULL) {
151: if (strcmp(cmd, lp->l_name) == 0) {
152: fseek(fp, lp->l_seek, SEEK_SET);
153: status = 0;
154: break;
155: }
156: }
157: fclose(ifp);
158: return status;
159: }
160:
161: /*
162: * Look for information on a command.
163: * The #if OLD code looks for command information bracketed by '.HS' and '.HE';
164: * it is conditionalized out because
165: * online documentation is now cooked, not raw.
166: * After the #if OLD code, look for information in system helpfile,
167: * then in user helpfile.
168: * Return 0 if found, 1 if not found.
169: */
170: int
171: help(command) char *command;
172: {
173: register int bad;
174:
175: bad = 1;
176:
177: #if OLD
178: register FILE *hf;
179:
180: sprintf(buf, "/usr/man/cmd/%s", command);
181: if ((hf = fopen(buf, "r")) == NULL) {
182: strcat(buf, "m");
183: if ((hf = fopen(buf, "r")) == NULL)
184: goto other;
185: }
186: for (;;) {
187: if (fgets(helpline, NLINE, hf) == NULL)
188: break;
189: if (strcmp(helpline, ".HS\n") == 0) {
190: bad = 0;
191: break;
192: }
193: }
194: if (!bad)
195: while (fgets(helpline, NLINE, hf) != NULL
196: && strcmp(helpline, ".HE\n") != 0)
197: fputs(helpline, ofp);
198: fclose(hf);
199: other:
200: if (bad)
201: /* fall through to conditional below... */
202: #endif
203:
204: if (bad = lookup(command, shf, helpindex))
205: bad = lookup(command, uhf, NULL);
206: return bad;
207: }
208:
209: /*
210: * Lookup a command in the given file by looking for DELIM-delimited lines.
211: * The indexfile speeds up lookup when there is a very large system help file.
212: * Return 0 if found, 1 if not found.
213: */
214: int
215: lookup(cmd, fp, ind) register char *cmd; FILE *fp; char *ind;
216: {
217: if (fp == NULL)
218: return 1;
219: if (ind != NULL && fastlook(cmd, fp, ind))
220: return 1;
221: while (fgets(helpline, NLINE, fp) != NULL) {
222: if (helpline[0] == delim) {
223: helpline[strlen(helpline)-1] = '\0';
224: if (strcmp(cmd, helpline+1) == 0) {
225: while (fgets(helpline, NLINE, fp) != NULL) {
226: if (helpline[0] == delim)
227: break;
228: fputs(helpline, ofp);
229: }
230: return 0;
231: }
232: }
233: }
234: return 1;
235: }
236:
237: /*
238: * Read in a look structure.
239: * Return NULL on end of file or error.
240: */
241: LOOK *
242: lread(fp) register FILE *fp;
243: {
244: register char *cp;
245: static LOOK look;
246: static char name[MAXNAME];
247:
248: if (fread(&look.l_seek, sizeof look.l_seek, 1, fp) != 1)
249: return NULL;
250: for (look.l_name = cp = name; (*cp = getc(fp)) != '\0'; ) {
251: if (feof(fp))
252: return NULL;
253: else if (cp < &name[MAXNAME-1])
254: ++cp;
255: }
256: return &look;
257: }
258:
259: /*
260: * Rebuild an index file.
261: * Return 0 on success, 1 on failure.
262: */
263: int
264: rebuild(fp, ind) FILE *fp; char *ind;
265: {
266: register FILE *ifp;
267: register char *cp, *ep;
268: long seek;
269:
270: if ((ifp = fopen(ind, "w")) == NULL)
271: return 1;
272: for (;;) {
273: seek = ftell(fp);
274: cp = helpline;
275: if (fgets(cp, NLINE, fp) == NULL)
276: break;
277: if (*cp++ != delim)
278: continue; /* line must start with delim */
279: while (*cp==' ' && *cp=='\t')
280: cp++; /* skip whitespace after delim */
281: ep = cp;
282: while (*ep!='\n' && *ep!='\0' && *ep!=' ' && *ep!='\t')
283: ep++; /* scan past keyword */
284: *ep = '\0';
285:
286: /* Write index entry: seek and NUL-terminated keyword. */
287: fwrite(&seek, 1, sizeof seek, ifp);
288: fputs(cp, ifp);
289: fputc('\0', ifp);
290: }
291: fclose(ifp);
292: return 0;
293: }
294:
295: /*
296: * Print usage message and die.
297: */
298: void
299: usage()
300: {
301: fprintf(stderr, USAGE);
302: exit(1);
303: }
304:
305: /* end of help.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.