|
|
1.1 root 1: /*
2: * help.c
3: * 9/2/93
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: /etc/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.6" /* 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 help();
49: int lookup();
50: LOOK *lread();
51: int rebuild();
52: void usage();
53:
54: main(argc, argv) int argc; char *argv[];
55: {
56: register char **ap;
57: register int status;
58: char *cp;
59: char *list[2];
60:
61: /* Process command line options. */
62: while (argc > 1 && argv[1][0] == '-') {
63: switch(argv[1][1]) {
64: case 'd': delim = argv[1][2]; break;
65: case 'f': helpfile = &argv[1][2]; break;
66: case 'i': helpindex = &argv[1][2]; break;
67: case 'r': rflag++; break;
68: case 'V':
69: fprintf(stderr, "help: V%s\n", VERSION);
70: break;
71: default: usage(); break;
72: }
73: --argc;
74: ++argv;
75: }
76:
77: /* Open files and read environmental variables. */
78: shf = fopen(helpfile, "r"); /* system helpfile */
79: if (shf == NULL) {
80: fprintf(stderr, "help: cannot open \"%s\"\n", helpfile);
81: exit(1);
82: }
83: if (rflag)
84: exit(rebuild(shf, helpindex));
85: if ((cp = getenv("HELP")) != NULL)
86: uhf = fopen(cp, "r"); /* user helpfile */
87: if ((cp = getenv("PAGER")) != NULL && *cp != '\0' && isatty(fileno(stdout)))
88: ofp = popen(cp, "w");
89: if (ofp == NULL) {
90: ofp = stdout;
91: setbuf(stdout, buf);
92: }
93: ap = ++argv;
94:
95: /* If no args, print help info and LASTERROR info. */
96: status = 0;
97: if (argc < 2) {
98: fprintf(stderr,
99: "The 'help' command prints a brief description of the usage of a command.\n"
100: "For example, to get information about the 'who' command, type:\n"
101: "\thelp who\n"
102: "The 'man' command provides more detailed descriptions of commands.\n"
103: "\n"
104: );
105: if ((list[0] = getenv("LASTERROR")) == NULL)
106: exit(status);
107: list[1] = NULL;
108: ap = list;
109: }
110:
111: /* Print help info on requested topics. */
112: while (*ap != NULL) {
113: if (help(*ap)) {
114: fprintf(stderr, "help: no information on %s\n", *ap);
115: status = 1;
116: }
117: if (*++ap != NULL)
118: fputc('\n', ofp);
119: fflush(ofp);
120: }
121:
122: /* Done, clean up. */
123: if (ofp != stdout)
124: pclose(ofp);
125: if (shf != NULL)
126: fclose(shf);
127: if (uhf != NULL)
128: fclose(uhf);
129: exit(status);
130: }
131:
132: /*
133: * Look for information on a command.
134: * Return 0 if found, 1 if not found.
135: */
136: int
137: help(command) char *command;
138: {
139: register int bad;
140: if (bad = lookup(command, shf, helpindex))
141: bad = lookup(command, uhf, NULL);
142: return bad;
143: }
144:
145: /*
146: * Lookup a command in the given file by looking for DELIM-delimited lines.
147: * The indexfile speeds up lookup when there is a very large system help file.
148: * Return 0 if found, 1 if not found.
149: */
150: int
151: lookup(cmd, fp, ind) register char *cmd; FILE *fp; char *ind;
152: {
153: register LOOK *lp;
154: register FILE *ifp;
155: struct stat sb;
156: long htime;
157: int status;
158:
159: if (fp == NULL)
160: return 1;
161:
162: fstat(fileno(fp), &sb);
163: htime = sb.st_mtime; /* helpfile mtime */
164: if (stat(ind, &sb) < 0 || htime > sb.st_mtime)
165: rebuild(fp, ind);
166: status = 1;
167:
168: if ((ifp = fopen(ind, "r")) == NULL)
169: return status;
170:
171: while ((lp = lread(ifp)) != NULL) {
172: if (strcmp(cmd, lp->l_name) == 0) {
173: fseek(fp, lp->l_seek, SEEK_SET);
174: status = 0;
175:
176: fgets(helpline, NLINE, fp);
177: while (fgets(helpline, NLINE, fp) != NULL) {
178: if (helpline[0] == delim)
179: break;
180: fputs(helpline, ofp);
181: }
182: fputs("\n", ofp);
183: }
184: }
185: fclose(ifp);
186: return status;
187: }
188:
189: /*
190: * Read in a look structure.
191: * Return NULL on end of file or error.
192: */
193: LOOK *
194: lread(fp) register FILE *fp;
195: {
196: register char *cp;
197: static LOOK look;
198: static char name[MAXNAME];
199:
200: if (fread(&look.l_seek, sizeof look.l_seek, 1, fp) != 1)
201: return NULL;
202: for (look.l_name = cp = name; (*cp = getc(fp)) != '\0'; ) {
203: if (feof(fp))
204: return NULL;
205: else if (cp < &name[MAXNAME-1])
206: ++cp;
207: }
208: return &look;
209: }
210:
211: /*
212: * Rebuild an index file.
213: * Return 0 on success, 1 on failure.
214: */
215: int
216: rebuild(fp, ind) FILE *fp; char *ind;
217: {
218: register FILE *ifp;
219: register char *cp, *ep;
220: long seek;
221:
222: if ((ifp = fopen(ind, "w")) == NULL)
223: return 1;
224: for (;;) {
225: seek = ftell(fp);
226: cp = helpline;
227: if (fgets(cp, NLINE, fp) == NULL)
228: break;
229: if (*cp++ != delim)
230: continue; /* line must start with delim */
231: while (*cp==' ' && *cp=='\t')
232: cp++; /* skip whitespace after delim */
233: ep = cp;
234: while (*ep!='\n' && *ep!='\0' && *ep!=' ' && *ep!='\t')
235: ep++; /* scan past keyword */
236: *ep = '\0';
237:
238: /* Write index entry: seek and NUL-terminated keyword. */
239: fwrite(&seek, 1, sizeof seek, ifp);
240: fputs(cp, ifp);
241: fputc('\0', ifp);
242: }
243: fclose(ifp);
244: return 0;
245: }
246:
247: /*
248: * Print usage message and die.
249: */
250: void
251: usage()
252: {
253: fprintf(stderr, USAGE);
254: exit(1);
255: }
256:
257: /* end of help.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.