131703Sbostic /* 231703Sbostic * Copyright (c) 1987 Regents of the University of California. 333054Sbostic * All rights reserved. 433054Sbostic * 5*42741Sbostic * %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*42741Sbostic static char sccsid[] = "@(#)man.c 5.21 (Berkeley) 06/01/90"; 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 2842402Sbostic int f_all, f_cat, f_where; 2940390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname; 3034057Sbostic 3131703Sbostic main(argc, argv) 3233354Sbostic int argc; 3333354Sbostic register char **argv; 3431703Sbostic { 3534057Sbostic extern char *optarg; 3634057Sbostic extern int optind; 3742402Sbostic int ch, res; 3842402Sbostic char *section[2], *check_pager(), *getpath(); 3931703Sbostic 4040390Sbostic progname = "man"; 4140390Sbostic while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF) 4234057Sbostic switch((char)ch) { 4340390Sbostic case 'a': 4440390Sbostic f_all = 1; 4531703Sbostic break; 4640390Sbostic case 'c': 4740390Sbostic case '-': /* deprecated */ 4840390Sbostic f_cat = 1; 4940390Sbostic break; 5040390Sbostic case 'm': 5140390Sbostic p_augment = optarg; 5240390Sbostic break; 5331703Sbostic case 'M': 5431703Sbostic case 'P': /* backward compatibility */ 5540390Sbostic p_path = optarg; 5631703Sbostic break; 5742402Sbostic /* 5842402Sbostic * "man -f" and "man -k" are backward compatible, undocumented 5942402Sbostic * ways of calling whatis(1) and apropos(1). 6042402Sbostic */ 6131703Sbostic case 'f': 6234057Sbostic jump(argv, "-f", "whatis"); 6340390Sbostic /* NOTREACHED */ 6431703Sbostic case 'k': 6534057Sbostic jump(argv, "-k", "apropos"); 6640390Sbostic /* NOTREACHED */ 6732565Sbostic case 'w': 6840390Sbostic f_all = f_where = 1; 6932565Sbostic break; 7031703Sbostic case '?': 7131703Sbostic default: 7234057Sbostic usage(); 7331703Sbostic } 7434057Sbostic argv += optind; 7531703Sbostic 7634057Sbostic if (!*argv) 7734057Sbostic usage(); 7833354Sbostic 7940390Sbostic if (!f_cat) 8031703Sbostic if (!isatty(1)) 8140390Sbostic f_cat = 1; 8240390Sbostic else if (pager = getenv("PAGER")) 8340390Sbostic pager = check_pager(pager); 8431779Sbostic else 8537892Sbostic pager = _PATH_PAGER; 8640390Sbostic 8731703Sbostic if (!(machine = getenv("MACHINE"))) 8831703Sbostic machine = MACHINE; 8940390Sbostic 9042402Sbostic /* see if checking in a specific section */ 9142402Sbostic if (argc > 1 && getsection(*argv)) { 9242402Sbostic section[0] = *argv++; 9342402Sbostic section[1] = (char *)NULL; 9442402Sbostic } else { 9542402Sbostic section[0] = "_default"; 9642402Sbostic section[1] = (char *)NULL; 9742402Sbostic } 9840390Sbostic 9942402Sbostic if (!p_path && !(p_path = getenv("MANPATH")) && 10042402Sbostic !(p_path = getpath(section)) && !p_augment) { 10142402Sbostic (void)fprintf(stderr, 10242402Sbostic "man: no place to search for those manual pages.\n"); 10342402Sbostic exit(1); 10442402Sbostic } 10540390Sbostic 10642402Sbostic for (; *argv; ++argv) { 10742402Sbostic if (p_augment) 10842402Sbostic res = manual(p_augment, *argv); 10942402Sbostic res = manual(p_path, *argv); 11042402Sbostic if (res || f_where) 11142402Sbostic continue; 11242402Sbostic (void)fprintf(stderr, 11342402Sbostic "man: no entry for %s in the manual.\n", *argv); 11442402Sbostic exit(1); 11542402Sbostic } 11642402Sbostic 11734752Sbostic /* use system(3) in case someone's pager is "pager arg1 arg2" */ 11833809Sbostic if (command) 11933809Sbostic (void)system(command); 12033354Sbostic exit(0); 12133354Sbostic } 12231703Sbostic 12340390Sbostic /* 12431778Sbostic * manual -- 12540390Sbostic * given a path, a directory list and a file name, find a file 12640390Sbostic * that matches; check ${directory}/${dir}/{file name} and 12733809Sbostic * ${directory}/${dir}/${machine}/${file name}. 12831778Sbostic */ 12942402Sbostic manual(path, name) 13040390Sbostic char *path, *name; 13131703Sbostic { 13242402Sbostic register int res; 13340390Sbostic register char *end; 13440390Sbostic char fname[MAXPATHLEN + 1]; 13531703Sbostic 13640390Sbostic for (res = 0;; path = end + 1) { 13742402Sbostic if (!*path) /* foo: */ 13842402Sbostic break; 13942402Sbostic if (end = index(path, ':')) { 14042402Sbostic if (end == path + 1) /* foo::bar */ 14142402Sbostic continue; 14231703Sbostic *end = '\0'; 14333809Sbostic } 14442402Sbostic (void)sprintf(fname, "%s/%s.0", path, name); 14542402Sbostic if (access(fname, R_OK)) { 14642402Sbostic (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 14742402Sbostic if (access(fname, R_OK)) 14842402Sbostic continue; 14942402Sbostic } 15042402Sbostic 15142402Sbostic if (f_where) 15242402Sbostic (void)printf("man: found in %s.\n", fname); 15342402Sbostic else if (f_cat) 15442402Sbostic cat(fname); 15542402Sbostic else 15642402Sbostic add(fname); 15742402Sbostic if (!f_all) 15842402Sbostic return(1); 15942402Sbostic res = 1; 16031703Sbostic if (!end) 16142402Sbostic break; 16233297Sbostic *end = ':'; 16331703Sbostic } 16442402Sbostic return(res); 16531703Sbostic } 16631703Sbostic 16731778Sbostic /* 16833809Sbostic * cat -- 16933809Sbostic * cat out the file 17031778Sbostic */ 17133809Sbostic cat(fname) 17233809Sbostic char *fname; 17331703Sbostic { 17433809Sbostic register int fd, n; 17533809Sbostic char buf[BUFSIZ]; 17631703Sbostic 17733809Sbostic if (!(fd = open(fname, O_RDONLY, 0))) { 17840390Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 17933809Sbostic exit(1); 18031703Sbostic } 18133809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 18233809Sbostic if (write(1, buf, n) != n) { 18340390Sbostic (void)fprintf(stderr, 18440390Sbostic "man: write: %s\n", strerror(errno)); 18533809Sbostic exit(1); 18633809Sbostic } 18733809Sbostic if (n == -1) { 18840390Sbostic (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 18933809Sbostic exit(1); 19033809Sbostic } 19133809Sbostic (void)close(fd); 19231703Sbostic } 19331703Sbostic 19431778Sbostic /* 19533809Sbostic * add -- 19633809Sbostic * add a file name to the list for future paging 19731778Sbostic */ 19833809Sbostic add(fname) 19933354Sbostic char *fname; 20031703Sbostic { 20133809Sbostic static u_int buflen; 20233809Sbostic static int len; 20333809Sbostic static char *cp; 20433809Sbostic int flen; 20531703Sbostic 20633809Sbostic if (!command) { 20740390Sbostic if (!(command = malloc(buflen = 1024))) 20840390Sbostic enomem(); 20933809Sbostic len = strlen(strcpy(command, pager)); 21033809Sbostic cp = command + len; 21133809Sbostic } 21233809Sbostic flen = strlen(fname); 21333809Sbostic if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 21440390Sbostic if (!(command = realloc(command, buflen += 1024))) 21540390Sbostic enomem(); 21633809Sbostic cp = command + len; 21731703Sbostic } 21833809Sbostic *cp++ = ' '; 21933809Sbostic len += flen + 1; /* +1 = space */ 22033809Sbostic (void)strcpy(cp, fname); 22133809Sbostic cp += flen; 22231703Sbostic } 22331703Sbostic 22431778Sbostic /* 22540390Sbostic * check_pager -- 22640390Sbostic * check the user supplied page information 22740390Sbostic */ 22840390Sbostic char * 22940390Sbostic check_pager(name) 23040390Sbostic char *name; 23140390Sbostic { 23240390Sbostic register char *p; 23342402Sbostic char *save; 23440390Sbostic 23540390Sbostic /* 23640390Sbostic * if the user uses "more", we make it "more -s"; watch out for 23740390Sbostic * PAGER = "mypager /usr/ucb/more" 23840390Sbostic */ 23940390Sbostic for (p = name; *p && !isspace(*p); ++p); 24040390Sbostic for (; p > name && *p != '/'; --p); 24140390Sbostic if (p != name) 24240390Sbostic ++p; 24340390Sbostic 24440390Sbostic /* make sure it's "more", not "morex" */ 24540390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 24640390Sbostic save = name; 24740390Sbostic /* allocate space to add the "-s" */ 24840390Sbostic if (!(name = 24940390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 25040390Sbostic enomem(); 25140390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 25240390Sbostic } 25340390Sbostic return(name); 25440390Sbostic } 25540390Sbostic 25640390Sbostic /* 25734057Sbostic * jump -- 25834057Sbostic * strip out flag argument and jump 25934057Sbostic */ 26034057Sbostic jump(argv, flag, name) 26134057Sbostic char **argv, *name; 26234057Sbostic register char *flag; 26334057Sbostic { 26434057Sbostic register char **arg; 26534057Sbostic 26634057Sbostic argv[0] = name; 26734057Sbostic for (arg = argv + 1; *arg; ++arg) 26834057Sbostic if (!strcmp(*arg, flag)) 26934057Sbostic break; 27034057Sbostic for (; *arg; ++arg) 27134057Sbostic arg[0] = arg[1]; 27234057Sbostic execvp(name, argv); 27342402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 27434057Sbostic exit(1); 27534057Sbostic } 27634057Sbostic 27734057Sbostic /* 27834057Sbostic * usage -- 27940390Sbostic * print usage message and die 28034057Sbostic */ 28134057Sbostic usage() 28234057Sbostic { 28340390Sbostic (void)fprintf(stderr, 28440390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 28534057Sbostic exit(1); 28634057Sbostic } 287