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