1*31703Sbostic /* 2*31703Sbostic * Copyright (c) 1987 Regents of the University of California. 3*31703Sbostic * All rights reserved. The Berkeley software License Agreement 4*31703Sbostic * specifies the terms and conditions for redistribution. 5*31703Sbostic */ 6*31703Sbostic 7*31703Sbostic #ifndef lint 8*31703Sbostic char copyright[] = 9*31703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 10*31703Sbostic All rights reserved.\n"; 11*31703Sbostic #endif not lint 12*31703Sbostic 13*31703Sbostic #ifndef lint 14*31703Sbostic static char sccsid[] = "@(#)man.c 5.1 (Berkeley) 06/29/87"; 15*31703Sbostic #endif not lint 16*31703Sbostic 17*31703Sbostic #include <sys/param.h> 18*31703Sbostic #include <sys/file.h> 19*31703Sbostic #include <ctype.h> 20*31703Sbostic 21*31703Sbostic #define DEF_PAGER "more -s" /* paging filter */ 22*31703Sbostic #define DEF_PATH "/usr/man" /* default path */ 23*31703Sbostic #define NO 0 /* no/false */ 24*31703Sbostic #define YES 1 /* yes/true */ 25*31703Sbostic 26*31703Sbostic /* 27*31703Sbostic * See code for more info on this kludge; suffice it to say that the 28*31703Sbostic * local, new and old defines *have* to map into the dirlist array 29*31703Sbostic * correctly. Notice also that cat1 is in array slot 1, etc. etc. 30*31703Sbostic * Continue to notice that it's also ordered for searching, i.e. 31*31703Sbostic * slots 1 - N are in the order you wish to search the directories. 32*31703Sbostic */ 33*31703Sbostic #define NO_SECTION 0 34*31703Sbostic #define LOCAL_SECTION 9 35*31703Sbostic #define NEW_SECTION 10 36*31703Sbostic #define OLD_SECTION 11 37*31703Sbostic #define isname(x) (x==LOCAL_SECTION || x==NEW_SECTION || x==OLD_SECTION) 38*31703Sbostic static char *machine, /* machine type */ 39*31703Sbostic *manpath, /* search path */ 40*31703Sbostic *pager, /* pager */ 41*31703Sbostic *dirlist[] = { /* sub-directory list */ 42*31703Sbostic "notused", "cat1", "cat2", "cat3", 43*31703Sbostic "cat4", "cat5", "cat6", "cat7", 44*31703Sbostic "cat8", "local", "new", "old", 45*31703Sbostic NULL, 46*31703Sbostic }; 47*31703Sbostic 48*31703Sbostic static int nomore; /* don't use more */ 49*31703Sbostic 50*31703Sbostic main(argc, argv) 51*31703Sbostic int argc; 52*31703Sbostic char **argv; 53*31703Sbostic { 54*31703Sbostic int section; 55*31703Sbostic char **arg_start, **arg, 56*31703Sbostic *getenv(); 57*31703Sbostic 58*31703Sbostic arg_start = argv; 59*31703Sbostic for (--argc, ++argv; argc && (*argv)[0] == '-'; --argc, ++argv) 60*31703Sbostic switch((*argv)[1]) { 61*31703Sbostic case 0: /* just write to stdout */ 62*31703Sbostic nomore = YES; 63*31703Sbostic break; 64*31703Sbostic case 'M': 65*31703Sbostic case 'P': /* backward compatibility */ 66*31703Sbostic if ((*argv)[2]) 67*31703Sbostic manpath = *argv + 2; 68*31703Sbostic else { 69*31703Sbostic if (argc < 2) { 70*31703Sbostic fprintf(stderr, "%s: missing path\n", *argv); 71*31703Sbostic exit(1); 72*31703Sbostic } 73*31703Sbostic --argc; 74*31703Sbostic manpath = *++argv; 75*31703Sbostic } 76*31703Sbostic break; 77*31703Sbostic /* 78*31703Sbostic * "man -f" and "man -k" are undocumented ways of calling 79*31703Sbostic * whatis(1) and apropos(1). Just strip out the flag 80*31703Sbostic * argument and jump. 81*31703Sbostic */ 82*31703Sbostic case 'f': 83*31703Sbostic for (arg = argv; arg[0] = arg[1]; ++arg); 84*31703Sbostic *arg_start = "whatis"; 85*31703Sbostic execvp(*arg_start, arg_start); 86*31703Sbostic fputs("whatis: Command not found.\n", stderr); 87*31703Sbostic exit(1); 88*31703Sbostic case 'k': 89*31703Sbostic for (arg = argv; *arg = arg[1]; ++arg); 90*31703Sbostic *arg_start = "apropos"; 91*31703Sbostic execvp(*arg_start, arg_start); 92*31703Sbostic fputs("apropos: Command not found.\n", stderr); 93*31703Sbostic exit(1); 94*31703Sbostic case '?': 95*31703Sbostic default: 96*31703Sbostic usage(); 97*31703Sbostic } 98*31703Sbostic if (!argc) 99*31703Sbostic usage(); 100*31703Sbostic 101*31703Sbostic if (!nomore) 102*31703Sbostic if (!isatty(1)) 103*31703Sbostic nomore = YES; 104*31703Sbostic else if (!(pager = getenv("PAGER"))) 105*31703Sbostic pager = DEF_PAGER; 106*31703Sbostic if (!(machine = getenv("MACHINE"))) 107*31703Sbostic machine = MACHINE; 108*31703Sbostic if (!manpath && !(manpath = getenv("MANPATH"))) 109*31703Sbostic manpath = DEF_PATH; 110*31703Sbostic for (; *manpath && *manpath == ':'; ++manpath); 111*31703Sbostic 112*31703Sbostic for (; *argv; ++argv) { 113*31703Sbostic section = NO_SECTION; 114*31703Sbostic switch(**argv) { 115*31703Sbostic /* 116*31703Sbostic * hardwired section numbers, fix here if they do; note, 117*31703Sbostic * only works for single digits. 118*31703Sbostic */ 119*31703Sbostic case '1': case '2': case '3': case '4': 120*31703Sbostic case '5': case '6': case '7': case '8': 121*31703Sbostic if (!(*argv)[1]) { 122*31703Sbostic section = (*argv)[0] - '0'; 123*31703Sbostic if (!*++argv) { 124*31703Sbostic fprintf(stderr, "man: what do you want from section %d?\n", section); 125*31703Sbostic exit(1); 126*31703Sbostic } 127*31703Sbostic } 128*31703Sbostic break; 129*31703Sbostic /* 130*31703Sbostic * backward compatibility: manl == local, mann == new, 131*31703Sbostic * mano == old; 132*31703Sbostic */ 133*31703Sbostic case 'l': 134*31703Sbostic if (!*argv[1] || !strcmp(*argv, dirlist[LOCAL_SECTION])) { 135*31703Sbostic section = LOCAL_SECTION; 136*31703Sbostic goto argtest; 137*31703Sbostic } 138*31703Sbostic break; 139*31703Sbostic case 'n': 140*31703Sbostic if (!*argv[1] || !strcmp(*argv, dirlist[NEW_SECTION])) { 141*31703Sbostic section = NEW_SECTION; 142*31703Sbostic goto argtest; 143*31703Sbostic } 144*31703Sbostic break; 145*31703Sbostic case 'o': 146*31703Sbostic if (!*argv[1] || !strcmp(*argv, dirlist[OLD_SECTION])) { 147*31703Sbostic section = OLD_SECTION; 148*31703Sbostic argtest: if (!*++argv) { 149*31703Sbostic fprintf(stderr, "man: what do you want from the %s section?\n", dirlist[section]); 150*31703Sbostic exit(1); 151*31703Sbostic } 152*31703Sbostic } 153*31703Sbostic break; 154*31703Sbostic } 155*31703Sbostic if (!manual(section, *argv)) 156*31703Sbostic if (section == NO_SECTION) 157*31703Sbostic fprintf(stderr, "No manual entry for %s.\n", *argv); 158*31703Sbostic else if (isname(section)) 159*31703Sbostic fprintf(stderr, "No entry for %s in the %s section of the manual.\n", *argv, dirlist[section]); 160*31703Sbostic else 161*31703Sbostic fprintf(stderr, "No entry for %s in section %d of the manual.\n", *argv, section); 162*31703Sbostic } 163*31703Sbostic exit(0); 164*31703Sbostic } 165*31703Sbostic 166*31703Sbostic static 167*31703Sbostic manual(section, name) 168*31703Sbostic int section; 169*31703Sbostic char *name; 170*31703Sbostic { 171*31703Sbostic register char *beg, *end, **dir; 172*31703Sbostic char *index(); 173*31703Sbostic 174*31703Sbostic for (beg = manpath;; beg = end + 1) { 175*31703Sbostic if (end = index(beg, ':')) 176*31703Sbostic *end = '\0'; 177*31703Sbostic if (section == NO_SECTION) { 178*31703Sbostic /* notice the +1... */ 179*31703Sbostic for (dir = dirlist + 1; *dir; ++dir) 180*31703Sbostic if (find(beg, *dir, name)) 181*31703Sbostic return(YES); 182*31703Sbostic } 183*31703Sbostic else if (find(beg, dirlist[section], name)) 184*31703Sbostic return(YES); 185*31703Sbostic if (!end) 186*31703Sbostic return(NO); 187*31703Sbostic } 188*31703Sbostic /*NOTREACHED*/ 189*31703Sbostic } 190*31703Sbostic 191*31703Sbostic static 192*31703Sbostic find(beg, dir, name) 193*31703Sbostic char *beg, *dir, *name; 194*31703Sbostic { 195*31703Sbostic char fname[MAXPATHLEN + 1]; 196*31703Sbostic 197*31703Sbostic (void)sprintf(fname, "%s/%s/%s", beg, dir, name); 198*31703Sbostic if (!access(fname, R_OK)) { 199*31703Sbostic show(fname); 200*31703Sbostic return(YES); 201*31703Sbostic } 202*31703Sbostic (void)sprintf(fname, "%s/%s/%s/%s", beg, dir, machine, name); 203*31703Sbostic if (!access(fname, R_OK)) { 204*31703Sbostic show(fname); 205*31703Sbostic return(YES); 206*31703Sbostic } 207*31703Sbostic return(NO); 208*31703Sbostic } 209*31703Sbostic 210*31703Sbostic static 211*31703Sbostic show(fname) 212*31703Sbostic char *fname; 213*31703Sbostic { 214*31703Sbostic register int fd, n; 215*31703Sbostic char buf[BUFSIZ]; 216*31703Sbostic 217*31703Sbostic if (nomore) { 218*31703Sbostic if (!(fd = open(fname, O_RDONLY, 0))) { 219*31703Sbostic perror("man: open"); 220*31703Sbostic exit(1); 221*31703Sbostic } 222*31703Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 223*31703Sbostic if (write(1, buf, n) != n) { 224*31703Sbostic perror("man: write"); 225*31703Sbostic exit(1); 226*31703Sbostic } 227*31703Sbostic if (n == -1) { 228*31703Sbostic perror("man: read"); 229*31703Sbostic exit(1); 230*31703Sbostic } 231*31703Sbostic (void)close(fd); 232*31703Sbostic } 233*31703Sbostic else { 234*31703Sbostic /* 235*31703Sbostic * use system(2) in case someone's pager is 236*31703Sbostic * "command arg1 arg2" 237*31703Sbostic */ 238*31703Sbostic (void)sprintf(buf, "%s %s", pager, fname); 239*31703Sbostic (void)system(buf); 240*31703Sbostic } 241*31703Sbostic } 242*31703Sbostic 243*31703Sbostic static 244*31703Sbostic usage() 245*31703Sbostic { 246*31703Sbostic fputs("usage: man [-] [-M path] [section] title ...\n", stderr); 247*31703Sbostic exit(1); 248*31703Sbostic } 249