131703Sbostic /* 231703Sbostic * Copyright (c) 1987 Regents of the University of California. 331703Sbostic * All rights reserved. The Berkeley software License Agreement 431703Sbostic * specifies the terms and conditions for redistribution. 531703Sbostic */ 631703Sbostic 731703Sbostic #ifndef lint 831703Sbostic char copyright[] = 931703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1031703Sbostic All rights reserved.\n"; 1131703Sbostic #endif not lint 1231703Sbostic 1331703Sbostic #ifndef lint 14*31713Sbostic static char sccsid[] = "@(#)man.c 5.2 (Berkeley) 06/30/87"; 1531703Sbostic #endif not lint 1631703Sbostic 1731703Sbostic #include <sys/param.h> 1831703Sbostic #include <sys/file.h> 1931703Sbostic #include <ctype.h> 2031703Sbostic 21*31713Sbostic #define DEF_PAGER "more -s" 22*31713Sbostic #define DEF_PATH "/usr/man:/usr/local/man" 23*31713Sbostic #define LOCAL_PATH "/usr/local/man" 24*31713Sbostic #define LOCAL_NAME "local" 25*31713Sbostic #define NO 0 26*31713Sbostic #define YES 1 2731703Sbostic 2831703Sbostic #define NO_SECTION 0 29*31713Sbostic #define S_THREEF 9 30*31713Sbostic #define S_NEW 10 31*31713Sbostic #define S_OLD 11 32*31713Sbostic 33*31713Sbostic /* this array maps a character (ex: '4') to an offset in dirlist */ 34*31713Sbostic #define secno(x) (seclist[(int)(x - '0')]) 35*31713Sbostic static int seclist[] = { -1, 1, 4, 5, 6, 7, 3, 8, 2, -1, -1 }; 36*31713Sbostic 37*31713Sbostic /* sub directory list, ordered for searching */ 38*31713Sbostic typedef struct something_meaningful { 39*31713Sbostic char *name, 40*31713Sbostic *msg; 41*31713Sbostic } DIR; 42*31713Sbostic 43*31713Sbostic DIR dirlist[] = { /* sub-directory list */ 44*31713Sbostic "notused", "", "cat1", "1st", "cat8", "8th", 45*31713Sbostic "cat6", "6th", "cat2", "2nd", "cat3", "3rd", 46*31713Sbostic "cat4", "4th", "cat5", "5th", "cat7", "7th", 47*31713Sbostic "cat3f", "3rd (F)", "new", "new", "old", "old", 48*31713Sbostic NULL, NULL, 4931703Sbostic }; 5031703Sbostic 51*31713Sbostic static int nomore; /* copy file to stdout */ 52*31713Sbostic static char *defpath, /* default search path */ 53*31713Sbostic *locpath, /* local search path */ 54*31713Sbostic *machine, /* machine type */ 55*31713Sbostic *manpath, /* current search path */ 56*31713Sbostic *pager; /* requested pager */ 5731703Sbostic 5831703Sbostic main(argc, argv) 5931703Sbostic int argc; 60*31713Sbostic register char **argv; 6131703Sbostic { 6231703Sbostic int section; 6331703Sbostic char **arg_start, **arg, 6431703Sbostic *getenv(); 6531703Sbostic 6631703Sbostic arg_start = argv; 6731703Sbostic for (--argc, ++argv; argc && (*argv)[0] == '-'; --argc, ++argv) 6831703Sbostic switch((*argv)[1]) { 6931703Sbostic case 0: /* just write to stdout */ 7031703Sbostic nomore = YES; 7131703Sbostic break; 7231703Sbostic case 'M': 7331703Sbostic case 'P': /* backward compatibility */ 7431703Sbostic if ((*argv)[2]) 7531703Sbostic manpath = *argv + 2; 7631703Sbostic else { 7731703Sbostic if (argc < 2) { 7831703Sbostic fprintf(stderr, "%s: missing path\n", *argv); 7931703Sbostic exit(1); 8031703Sbostic } 8131703Sbostic --argc; 8231703Sbostic manpath = *++argv; 8331703Sbostic } 8431703Sbostic break; 8531703Sbostic /* 8631703Sbostic * "man -f" and "man -k" are undocumented ways of calling 8731703Sbostic * whatis(1) and apropos(1). Just strip out the flag 8831703Sbostic * argument and jump. 8931703Sbostic */ 9031703Sbostic case 'f': 9131703Sbostic for (arg = argv; arg[0] = arg[1]; ++arg); 9231703Sbostic *arg_start = "whatis"; 9331703Sbostic execvp(*arg_start, arg_start); 9431703Sbostic fputs("whatis: Command not found.\n", stderr); 9531703Sbostic exit(1); 9631703Sbostic case 'k': 9731703Sbostic for (arg = argv; *arg = arg[1]; ++arg); 9831703Sbostic *arg_start = "apropos"; 9931703Sbostic execvp(*arg_start, arg_start); 10031703Sbostic fputs("apropos: Command not found.\n", stderr); 10131703Sbostic exit(1); 10231703Sbostic case '?': 10331703Sbostic default: 10431703Sbostic usage(); 10531703Sbostic } 10631703Sbostic if (!argc) 10731703Sbostic usage(); 10831703Sbostic 10931703Sbostic if (!nomore) 11031703Sbostic if (!isatty(1)) 11131703Sbostic nomore = YES; 11231703Sbostic else if (!(pager = getenv("PAGER"))) 11331703Sbostic pager = DEF_PAGER; 11431703Sbostic if (!(machine = getenv("MACHINE"))) 11531703Sbostic machine = MACHINE; 116*31713Sbostic if (!defpath && !(defpath = getenv("MANPATH"))) 117*31713Sbostic defpath = DEF_PATH; 118*31713Sbostic locpath = LOCAL_PATH; 119*31713Sbostic for (; *defpath && *defpath == ':'; ++defpath); 12031703Sbostic 12131703Sbostic for (; *argv; ++argv) { 12231703Sbostic section = NO_SECTION; 123*31713Sbostic manpath = DEF_PATH; 12431703Sbostic switch(**argv) { 125*31713Sbostic /* hardwired section numbers, fix here if they change */ 126*31713Sbostic case '1': case '2': case '4': case '5': case '6': 127*31713Sbostic case '7': case '8': 12831703Sbostic if (!(*argv)[1]) { 129*31713Sbostic section = secno((*argv)[0]); 130*31713Sbostic goto numtest; 131*31713Sbostic } 132*31713Sbostic break; 133*31713Sbostic case '3': 134*31713Sbostic if (!(*argv)[1]) { /* "3" */ 135*31713Sbostic section = secno((*argv)[0]); 136*31713Sbostic numtest: if (!*++argv) { 137*31713Sbostic fprintf(stderr, "man: what do you want from the %s section of the manual?\n", dirlist[section].msg); 138*31713Sbostic exit(1); 139*31713Sbostic } 140*31713Sbostic } /* "3[fF]" */ 141*31713Sbostic if (((*argv)[1] == 'f' || (*argv)[1] == 'F') && !(*argv)[2]) { 142*31713Sbostic section = S_THREEF; 14331703Sbostic if (!*++argv) { 144*31713Sbostic fprintf(stderr, "man: what do you want from the %s section of the manual?\n", dirlist[S_THREEF].msg); 14531703Sbostic exit(1); 14631703Sbostic } 14731703Sbostic } 14831703Sbostic break; 149*31713Sbostic case 'l': /* local */ 150*31713Sbostic if (!(*argv)[1]) /* "l" */ 151*31713Sbostic section = NO_SECTION; /* "l2" */ 152*31713Sbostic else if (isdigit((*argv)[1]) && !(*argv)[2]) 153*31713Sbostic section = secno((*argv)[1]); 154*31713Sbostic else { 155*31713Sbostic int lex; 156*31713Sbostic lex = strcmp(LOCAL_NAME, *argv); 157*31713Sbostic if (!lex) /* "local" */ 158*31713Sbostic section = NO_SECTION; /* "local2" */ 159*31713Sbostic else if (lex < 0 && isdigit((*argv)[sizeof(LOCAL_NAME) - 1]) && !(*argv)[sizeof(LOCAL_NAME)]) 160*31713Sbostic section = secno((*argv)[sizeof(LOCAL_NAME) - 1]); 161*31713Sbostic else 162*31713Sbostic break; 16331703Sbostic } 164*31713Sbostic if (!*++argv) { 165*31713Sbostic fputs("man: what do you want from the local section of the manual?\n", stderr); 166*31713Sbostic exit(1); 167*31713Sbostic } 168*31713Sbostic manpath = locpath; 16931703Sbostic break; 170*31713Sbostic case 'n': /* new */ 171*31713Sbostic if (!*argv[1] || !strcmp(*argv, dirlist[S_NEW].name)) { 172*31713Sbostic section = S_NEW; 173*31713Sbostic goto strtest; 17431703Sbostic } 17531703Sbostic break; 176*31713Sbostic case 'o': /* old */ 177*31713Sbostic if (!*argv[1] || !strcmp(*argv, dirlist[S_OLD].name)) { 178*31713Sbostic section = S_OLD; 179*31713Sbostic strtest: if (!*++argv) { 180*31713Sbostic fprintf(stderr, "man: what do you want from the %s section of the manual?\n", dirlist[section].msg); 18131703Sbostic exit(1); 18231703Sbostic } 18331703Sbostic } 18431703Sbostic break; 18531703Sbostic } 18631703Sbostic if (!manual(section, *argv)) 187*31713Sbostic if (manpath == locpath) 188*31713Sbostic fprintf(stderr, "No entry for %s in the %s section of the local manual.\n", *argv, dirlist[section].msg); 189*31713Sbostic else if (section == NO_SECTION) 190*31713Sbostic fprintf(stderr, "No entry for %s in the manual.\n", *argv); 19131703Sbostic else 192*31713Sbostic fprintf(stderr, "No entry for %s in the %s section of the manual.\n", *argv, dirlist[section].msg); 19331703Sbostic } 19431703Sbostic exit(0); 19531703Sbostic } 19631703Sbostic 19731703Sbostic static 19831703Sbostic manual(section, name) 19931703Sbostic int section; 20031703Sbostic char *name; 20131703Sbostic { 202*31713Sbostic register DIR *dir; 203*31713Sbostic register char *beg, *end; 20431703Sbostic char *index(); 20531703Sbostic 20631703Sbostic for (beg = manpath;; beg = end + 1) { 20731703Sbostic if (end = index(beg, ':')) 20831703Sbostic *end = '\0'; 20931703Sbostic if (section == NO_SECTION) { 210*31713Sbostic for (dir = dirlist + 1; dir->name; ++dir) 211*31713Sbostic if (find(beg, dir->name, name)) 21231703Sbostic return(YES); 21331703Sbostic } 214*31713Sbostic else if (find(beg, dirlist[section].name, name)) 21531703Sbostic return(YES); 21631703Sbostic if (!end) 21731703Sbostic return(NO); 21831703Sbostic } 21931703Sbostic /*NOTREACHED*/ 22031703Sbostic } 22131703Sbostic 22231703Sbostic static 22331703Sbostic find(beg, dir, name) 22431703Sbostic char *beg, *dir, *name; 22531703Sbostic { 22631703Sbostic char fname[MAXPATHLEN + 1]; 22731703Sbostic 228*31713Sbostic (void)sprintf(fname, "%s/%s/%s.0", beg, dir, name); 22931703Sbostic if (!access(fname, R_OK)) { 23031703Sbostic show(fname); 23131703Sbostic return(YES); 23231703Sbostic } 233*31713Sbostic (void)sprintf(fname, "%s/%s/%s/%s.0", beg, dir, machine, name); 23431703Sbostic if (!access(fname, R_OK)) { 23531703Sbostic show(fname); 23631703Sbostic return(YES); 23731703Sbostic } 23831703Sbostic return(NO); 23931703Sbostic } 24031703Sbostic 24131703Sbostic static 24231703Sbostic show(fname) 24331703Sbostic char *fname; 24431703Sbostic { 24531703Sbostic register int fd, n; 24631703Sbostic char buf[BUFSIZ]; 24731703Sbostic 24831703Sbostic if (nomore) { 24931703Sbostic if (!(fd = open(fname, O_RDONLY, 0))) { 25031703Sbostic perror("man: open"); 25131703Sbostic exit(1); 25231703Sbostic } 25331703Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 25431703Sbostic if (write(1, buf, n) != n) { 25531703Sbostic perror("man: write"); 25631703Sbostic exit(1); 25731703Sbostic } 25831703Sbostic if (n == -1) { 25931703Sbostic perror("man: read"); 26031703Sbostic exit(1); 26131703Sbostic } 26231703Sbostic (void)close(fd); 26331703Sbostic } 26431703Sbostic else { 26531703Sbostic /* 26631703Sbostic * use system(2) in case someone's pager is 26731703Sbostic * "command arg1 arg2" 26831703Sbostic */ 26931703Sbostic (void)sprintf(buf, "%s %s", pager, fname); 27031703Sbostic (void)system(buf); 27131703Sbostic } 27231703Sbostic } 27331703Sbostic 27431703Sbostic static 27531703Sbostic usage() 27631703Sbostic { 27731703Sbostic fputs("usage: man [-] [-M path] [section] title ...\n", stderr); 27831703Sbostic exit(1); 27931703Sbostic } 280