131703Sbostic /* 231703Sbostic * Copyright (c) 1987 Regents of the University of California. 333054Sbostic * All rights reserved. 433054Sbostic * 542741Sbostic * %sccs.include.redist.c% 631703Sbostic */ 731703Sbostic 831703Sbostic #ifndef lint 931703Sbostic char copyright[] = 1031703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1131703Sbostic All rights reserved.\n"; 1233054Sbostic #endif /* not lint */ 1331703Sbostic 1431703Sbostic #ifndef lint 15*54706Sbostic static char sccsid[] = "@(#)man.c 5.26 (Berkeley) 07/06/92"; 1633054Sbostic #endif /* not lint */ 1731703Sbostic 1831703Sbostic #include <sys/param.h> 1931703Sbostic #include <sys/file.h> 2040390Sbostic #include <errno.h> 2131703Sbostic #include <ctype.h> 2240390Sbostic #include <string.h> 2342402Sbostic #include <stdlib.h> 2437892Sbostic #include "pathnames.h" 2531703Sbostic 2640390Sbostic extern int errno; 2731703Sbostic 2844938Sbostic int f_all, f_cat, f_how, f_where; 2940390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname; 3044597Strent extern char **arorder, *pathbuf; 3134057Sbostic 3231703Sbostic main(argc, argv) 3333354Sbostic int argc; 3433354Sbostic register char **argv; 3531703Sbostic { 3634057Sbostic extern char *optarg; 3734057Sbostic extern int optind; 3842402Sbostic int ch, res; 3944418Strent char *section[2], *check_pager(), *getpath(), **getorder(), *tmp; 4031703Sbostic 4140390Sbostic progname = "man"; 4244938Sbostic while ((ch = getopt(argc, argv, "-acfhkM:m:P:w")) != EOF) 4334057Sbostic switch((char)ch) { 4440390Sbostic case 'a': 4540390Sbostic f_all = 1; 4631703Sbostic break; 4740390Sbostic case 'c': 4840390Sbostic case '-': /* deprecated */ 4940390Sbostic f_cat = 1; 5040390Sbostic break; 5144938Sbostic case 'h': 5244938Sbostic f_how = 1; 5344938Sbostic break; 5440390Sbostic case 'm': 5540390Sbostic p_augment = optarg; 5640390Sbostic break; 5731703Sbostic case 'M': 5831703Sbostic case 'P': /* backward compatibility */ 5940390Sbostic p_path = optarg; 6031703Sbostic break; 6142402Sbostic /* 6242402Sbostic * "man -f" and "man -k" are backward compatible, undocumented 6342402Sbostic * ways of calling whatis(1) and apropos(1). 6442402Sbostic */ 6531703Sbostic case 'f': 6634057Sbostic jump(argv, "-f", "whatis"); 6740390Sbostic /* NOTREACHED */ 6831703Sbostic case 'k': 6934057Sbostic jump(argv, "-k", "apropos"); 7040390Sbostic /* NOTREACHED */ 7132565Sbostic case 'w': 7240390Sbostic f_all = f_where = 1; 7332565Sbostic break; 7431703Sbostic case '?': 7531703Sbostic default: 7634057Sbostic usage(); 7731703Sbostic } 7834057Sbostic argv += optind; 7931703Sbostic 8034057Sbostic if (!*argv) 8134057Sbostic usage(); 8233354Sbostic 8344938Sbostic if (!f_cat && !f_how) 8431703Sbostic if (!isatty(1)) 8540390Sbostic f_cat = 1; 8640390Sbostic else if (pager = getenv("PAGER")) 8740390Sbostic pager = check_pager(pager); 8831779Sbostic else 8937892Sbostic pager = _PATH_PAGER; 9040390Sbostic 9131703Sbostic if (!(machine = getenv("MACHINE"))) 9231703Sbostic machine = MACHINE; 9340390Sbostic 9442402Sbostic /* see if checking in a specific section */ 9542402Sbostic if (argc > 1 && getsection(*argv)) { 9642402Sbostic section[0] = *argv++; 9742402Sbostic section[1] = (char *)NULL; 9842402Sbostic } else { 9942402Sbostic section[0] = "_default"; 10042402Sbostic section[1] = (char *)NULL; 10142402Sbostic } 10240390Sbostic 10344418Strent arorder = getorder(); 10444418Strent if (p_path || (p_path = getenv("MANPATH"))) { 10544418Strent char buf[MAXPATHLEN], **av; 10644418Strent 10744418Strent tmp = strtok(p_path, ":"); 10844418Strent while (tmp) { 10952473Sbostic (void)snprintf(buf, sizeof(buf), "%s/", tmp); 11044418Strent for (av = arorder; *av; ++av) 11144418Strent cadd(buf, strlen(buf), *av); 11252473Sbostic tmp = strtok(NULL, ":"); 11344418Strent } 11444418Strent p_path = pathbuf; 11544418Strent } else if (!(p_path = getpath(section)) && !p_augment) { 11642402Sbostic (void)fprintf(stderr, 11744418Strent "man: no place to search for those manual pages.\n"); 11842402Sbostic exit(1); 11942402Sbostic } 12040390Sbostic 12142402Sbostic for (; *argv; ++argv) { 12242402Sbostic if (p_augment) 12342402Sbostic res = manual(p_augment, *argv); 12442402Sbostic res = manual(p_path, *argv); 125*54706Sbostic if (!res && !f_where) 126*54706Sbostic (void)fprintf(stderr, 127*54706Sbostic "man: no entry for %s in the manual.\n", *argv); 12842402Sbostic } 12942402Sbostic 13034752Sbostic /* use system(3) in case someone's pager is "pager arg1 arg2" */ 13133809Sbostic if (command) 13233809Sbostic (void)system(command); 13333354Sbostic exit(0); 13433354Sbostic } 13531703Sbostic 13640390Sbostic /* 13731778Sbostic * manual -- 13840390Sbostic * given a path, a directory list and a file name, find a file 13940390Sbostic * that matches; check ${directory}/${dir}/{file name} and 14033809Sbostic * ${directory}/${dir}/${machine}/${file name}. 14131778Sbostic */ 14242402Sbostic manual(path, name) 14340390Sbostic char *path, *name; 14431703Sbostic { 14542402Sbostic register int res; 14640390Sbostic register char *end; 14740390Sbostic char fname[MAXPATHLEN + 1]; 14831703Sbostic 14940390Sbostic for (res = 0;; path = end + 1) { 15042402Sbostic if (!*path) /* foo: */ 15142402Sbostic break; 15242402Sbostic if (end = index(path, ':')) { 15342402Sbostic if (end == path + 1) /* foo::bar */ 15442402Sbostic continue; 15531703Sbostic *end = '\0'; 15633809Sbostic } 15742402Sbostic (void)sprintf(fname, "%s/%s.0", path, name); 15842402Sbostic if (access(fname, R_OK)) { 15942402Sbostic (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 16042402Sbostic if (access(fname, R_OK)) 16142402Sbostic continue; 16242402Sbostic } 16342402Sbostic 16442402Sbostic if (f_where) 16542402Sbostic (void)printf("man: found in %s.\n", fname); 16642402Sbostic else if (f_cat) 16742402Sbostic cat(fname); 16844938Sbostic else if (f_how) 16944938Sbostic how(fname); 17042402Sbostic else 17142402Sbostic add(fname); 17242402Sbostic if (!f_all) 17342402Sbostic return(1); 17442402Sbostic res = 1; 17531703Sbostic if (!end) 17642402Sbostic break; 17733297Sbostic *end = ':'; 17831703Sbostic } 17942402Sbostic return(res); 18031703Sbostic } 18131703Sbostic 18231778Sbostic /* 18344938Sbostic * how -- 18444938Sbostic * display how information 18544938Sbostic */ 18644938Sbostic how(fname) 18744938Sbostic char *fname; 18844938Sbostic { 18944938Sbostic register FILE *fp; 19044938Sbostic 19144938Sbostic register int lcnt, print; 19244938Sbostic register char *p; 19344938Sbostic char buf[BUFSIZ]; 19444938Sbostic 19544938Sbostic if (!(fp = fopen(fname, "r"))) { 19644938Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 19744938Sbostic exit(1); 19844938Sbostic } 19944938Sbostic #define S1 "SYNOPSIS" 20044938Sbostic #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 20144938Sbostic #define D1 "DESCRIPTION" 20244938Sbostic #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 20344938Sbostic for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 20444938Sbostic if (!strncmp(buf, S1, sizeof(S1) - 1) || 20544938Sbostic !strncmp(buf, S2, sizeof(S2) - 1)) { 20644938Sbostic print = 1; 20744938Sbostic continue; 20844938Sbostic } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 20944938Sbostic !strncmp(buf, D2, sizeof(D2) - 1)) 21044938Sbostic return; 21144938Sbostic if (!print) 21244938Sbostic continue; 21344938Sbostic if (*buf == '\n') 21444938Sbostic ++lcnt; 21544938Sbostic else { 21644938Sbostic for(; lcnt; --lcnt) 21744938Sbostic (void)putchar('\n'); 21844938Sbostic for (p = buf; isspace(*p); ++p); 21944938Sbostic (void)fputs(p, stdout); 22044938Sbostic } 22144938Sbostic } 22244938Sbostic (void)fclose(fp); 22344938Sbostic } 22444938Sbostic /* 22533809Sbostic * cat -- 22633809Sbostic * cat out the file 22731778Sbostic */ 22833809Sbostic cat(fname) 22933809Sbostic char *fname; 23031703Sbostic { 23133809Sbostic register int fd, n; 23233809Sbostic char buf[BUFSIZ]; 23331703Sbostic 23444938Sbostic if ((fd = open(fname, O_RDONLY, 0)) < 0) { 23540390Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 23633809Sbostic exit(1); 23731703Sbostic } 23833809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 23933809Sbostic if (write(1, buf, n) != n) { 24040390Sbostic (void)fprintf(stderr, 24140390Sbostic "man: write: %s\n", strerror(errno)); 24233809Sbostic exit(1); 24333809Sbostic } 24433809Sbostic if (n == -1) { 24540390Sbostic (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 24633809Sbostic exit(1); 24733809Sbostic } 24833809Sbostic (void)close(fd); 24931703Sbostic } 25031703Sbostic 25131778Sbostic /* 25233809Sbostic * add -- 25333809Sbostic * add a file name to the list for future paging 25431778Sbostic */ 25533809Sbostic add(fname) 25633354Sbostic char *fname; 25731703Sbostic { 25833809Sbostic static u_int buflen; 25933809Sbostic static int len; 26033809Sbostic static char *cp; 26133809Sbostic int flen; 26231703Sbostic 26333809Sbostic if (!command) { 26440390Sbostic if (!(command = malloc(buflen = 1024))) 26540390Sbostic enomem(); 26633809Sbostic len = strlen(strcpy(command, pager)); 26733809Sbostic cp = command + len; 26833809Sbostic } 26933809Sbostic flen = strlen(fname); 27033809Sbostic if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 27140390Sbostic if (!(command = realloc(command, buflen += 1024))) 27240390Sbostic enomem(); 27333809Sbostic cp = command + len; 27431703Sbostic } 27533809Sbostic *cp++ = ' '; 27633809Sbostic len += flen + 1; /* +1 = space */ 27733809Sbostic (void)strcpy(cp, fname); 27833809Sbostic cp += flen; 27931703Sbostic } 28031703Sbostic 28131778Sbostic /* 28240390Sbostic * check_pager -- 28340390Sbostic * check the user supplied page information 28440390Sbostic */ 28540390Sbostic char * 28640390Sbostic check_pager(name) 28740390Sbostic char *name; 28840390Sbostic { 28940390Sbostic register char *p; 29042402Sbostic char *save; 29140390Sbostic 29240390Sbostic /* 29340390Sbostic * if the user uses "more", we make it "more -s"; watch out for 29440390Sbostic * PAGER = "mypager /usr/ucb/more" 29540390Sbostic */ 29640390Sbostic for (p = name; *p && !isspace(*p); ++p); 29740390Sbostic for (; p > name && *p != '/'; --p); 29840390Sbostic if (p != name) 29940390Sbostic ++p; 30040390Sbostic 30140390Sbostic /* make sure it's "more", not "morex" */ 30240390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 30340390Sbostic save = name; 30440390Sbostic /* allocate space to add the "-s" */ 30540390Sbostic if (!(name = 30640390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 30740390Sbostic enomem(); 30840390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 30940390Sbostic } 31040390Sbostic return(name); 31140390Sbostic } 31240390Sbostic 31340390Sbostic /* 31434057Sbostic * jump -- 31534057Sbostic * strip out flag argument and jump 31634057Sbostic */ 31734057Sbostic jump(argv, flag, name) 31834057Sbostic char **argv, *name; 31934057Sbostic register char *flag; 32034057Sbostic { 32134057Sbostic register char **arg; 32234057Sbostic 32334057Sbostic argv[0] = name; 32434057Sbostic for (arg = argv + 1; *arg; ++arg) 32534057Sbostic if (!strcmp(*arg, flag)) 32634057Sbostic break; 32734057Sbostic for (; *arg; ++arg) 32834057Sbostic arg[0] = arg[1]; 32934057Sbostic execvp(name, argv); 33042402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 33134057Sbostic exit(1); 33234057Sbostic } 33334057Sbostic 33434057Sbostic /* 33534057Sbostic * usage -- 33640390Sbostic * print usage message and die 33734057Sbostic */ 33834057Sbostic usage() 33934057Sbostic { 34040390Sbostic (void)fprintf(stderr, 34140390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 34234057Sbostic exit(1); 34334057Sbostic } 344