|
|
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.