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*44597Strent static char sccsid[] = "@(#)man.c 5.23 (Berkeley) 06/29/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; 30*44597Strent 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"; 4240390Sbostic while ((ch = getopt(argc, argv, "-acfkM: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; 5140390Sbostic case 'm': 5240390Sbostic p_augment = optarg; 5340390Sbostic break; 5431703Sbostic case 'M': 5531703Sbostic case 'P': /* backward compatibility */ 5640390Sbostic p_path = optarg; 5731703Sbostic break; 5842402Sbostic /* 5942402Sbostic * "man -f" and "man -k" are backward compatible, undocumented 6042402Sbostic * ways of calling whatis(1) and apropos(1). 6142402Sbostic */ 6231703Sbostic case 'f': 6334057Sbostic jump(argv, "-f", "whatis"); 6440390Sbostic /* NOTREACHED */ 6531703Sbostic case 'k': 6634057Sbostic jump(argv, "-k", "apropos"); 6740390Sbostic /* NOTREACHED */ 6832565Sbostic case 'w': 6940390Sbostic f_all = f_where = 1; 7032565Sbostic break; 7131703Sbostic case '?': 7231703Sbostic default: 7334057Sbostic usage(); 7431703Sbostic } 7534057Sbostic argv += optind; 7631703Sbostic 7734057Sbostic if (!*argv) 7834057Sbostic usage(); 7933354Sbostic 8040390Sbostic if (!f_cat) 8131703Sbostic if (!isatty(1)) 8240390Sbostic f_cat = 1; 8340390Sbostic else if (pager = getenv("PAGER")) 8440390Sbostic pager = check_pager(pager); 8531779Sbostic else 8637892Sbostic pager = _PATH_PAGER; 8740390Sbostic 8831703Sbostic if (!(machine = getenv("MACHINE"))) 8931703Sbostic machine = MACHINE; 9040390Sbostic 9142402Sbostic /* see if checking in a specific section */ 9242402Sbostic if (argc > 1 && getsection(*argv)) { 9342402Sbostic section[0] = *argv++; 9442402Sbostic section[1] = (char *)NULL; 9542402Sbostic } else { 9642402Sbostic section[0] = "_default"; 9742402Sbostic section[1] = (char *)NULL; 9842402Sbostic } 9940390Sbostic 10044418Strent arorder = getorder(); 10144418Strent if (p_path || (p_path = getenv("MANPATH"))) { 10244418Strent char buf[MAXPATHLEN], **av; 10344418Strent 10444418Strent tmp = strtok(p_path, ":"); 10544418Strent while (tmp) { 10644418Strent (void)sprintf(buf, "%s/", tmp); 10744418Strent for (av = arorder; *av; ++av) 10844418Strent cadd(buf, strlen(buf), *av); 10944418Strent tmp = strtok((char *)NULL, ":"); 11044418Strent } 11144418Strent p_path = pathbuf; 11244418Strent } else if (!(p_path = getpath(section)) && !p_augment) { 11342402Sbostic (void)fprintf(stderr, 11444418Strent "man: no place to search for those manual pages.\n"); 11542402Sbostic exit(1); 11642402Sbostic } 11740390Sbostic 11842402Sbostic for (; *argv; ++argv) { 11942402Sbostic if (p_augment) 12042402Sbostic res = manual(p_augment, *argv); 12142402Sbostic res = manual(p_path, *argv); 12242402Sbostic if (res || f_where) 12342402Sbostic continue; 12442402Sbostic (void)fprintf(stderr, 12542402Sbostic "man: no entry for %s in the manual.\n", *argv); 12642402Sbostic exit(1); 12742402Sbostic } 12842402Sbostic 12934752Sbostic /* use system(3) in case someone's pager is "pager arg1 arg2" */ 13033809Sbostic if (command) 13133809Sbostic (void)system(command); 13233354Sbostic exit(0); 13333354Sbostic } 13431703Sbostic 13540390Sbostic /* 13631778Sbostic * manual -- 13740390Sbostic * given a path, a directory list and a file name, find a file 13840390Sbostic * that matches; check ${directory}/${dir}/{file name} and 13933809Sbostic * ${directory}/${dir}/${machine}/${file name}. 14031778Sbostic */ 14142402Sbostic manual(path, name) 14240390Sbostic char *path, *name; 14331703Sbostic { 14442402Sbostic register int res; 14540390Sbostic register char *end; 14640390Sbostic char fname[MAXPATHLEN + 1]; 14731703Sbostic 14840390Sbostic for (res = 0;; path = end + 1) { 14942402Sbostic if (!*path) /* foo: */ 15042402Sbostic break; 15142402Sbostic if (end = index(path, ':')) { 15242402Sbostic if (end == path + 1) /* foo::bar */ 15342402Sbostic continue; 15431703Sbostic *end = '\0'; 15533809Sbostic } 15642402Sbostic (void)sprintf(fname, "%s/%s.0", path, name); 15742402Sbostic if (access(fname, R_OK)) { 15842402Sbostic (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 15942402Sbostic if (access(fname, R_OK)) 16042402Sbostic continue; 16142402Sbostic } 16242402Sbostic 16342402Sbostic if (f_where) 16442402Sbostic (void)printf("man: found in %s.\n", fname); 16542402Sbostic else if (f_cat) 16642402Sbostic cat(fname); 16742402Sbostic else 16842402Sbostic add(fname); 16942402Sbostic if (!f_all) 17042402Sbostic return(1); 17142402Sbostic res = 1; 17231703Sbostic if (!end) 17342402Sbostic break; 17433297Sbostic *end = ':'; 17531703Sbostic } 17642402Sbostic return(res); 17731703Sbostic } 17831703Sbostic 17931778Sbostic /* 18033809Sbostic * cat -- 18133809Sbostic * cat out the file 18231778Sbostic */ 18333809Sbostic cat(fname) 18433809Sbostic char *fname; 18531703Sbostic { 18633809Sbostic register int fd, n; 18733809Sbostic char buf[BUFSIZ]; 18831703Sbostic 18933809Sbostic if (!(fd = open(fname, O_RDONLY, 0))) { 19040390Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 19133809Sbostic exit(1); 19231703Sbostic } 19333809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 19433809Sbostic if (write(1, buf, n) != n) { 19540390Sbostic (void)fprintf(stderr, 19640390Sbostic "man: write: %s\n", strerror(errno)); 19733809Sbostic exit(1); 19833809Sbostic } 19933809Sbostic if (n == -1) { 20040390Sbostic (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 20133809Sbostic exit(1); 20233809Sbostic } 20333809Sbostic (void)close(fd); 20431703Sbostic } 20531703Sbostic 20631778Sbostic /* 20733809Sbostic * add -- 20833809Sbostic * add a file name to the list for future paging 20931778Sbostic */ 21033809Sbostic add(fname) 21133354Sbostic char *fname; 21231703Sbostic { 21333809Sbostic static u_int buflen; 21433809Sbostic static int len; 21533809Sbostic static char *cp; 21633809Sbostic int flen; 21731703Sbostic 21833809Sbostic if (!command) { 21940390Sbostic if (!(command = malloc(buflen = 1024))) 22040390Sbostic enomem(); 22133809Sbostic len = strlen(strcpy(command, pager)); 22233809Sbostic cp = command + len; 22333809Sbostic } 22433809Sbostic flen = strlen(fname); 22533809Sbostic if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 22640390Sbostic if (!(command = realloc(command, buflen += 1024))) 22740390Sbostic enomem(); 22833809Sbostic cp = command + len; 22931703Sbostic } 23033809Sbostic *cp++ = ' '; 23133809Sbostic len += flen + 1; /* +1 = space */ 23233809Sbostic (void)strcpy(cp, fname); 23333809Sbostic cp += flen; 23431703Sbostic } 23531703Sbostic 23631778Sbostic /* 23740390Sbostic * check_pager -- 23840390Sbostic * check the user supplied page information 23940390Sbostic */ 24040390Sbostic char * 24140390Sbostic check_pager(name) 24240390Sbostic char *name; 24340390Sbostic { 24440390Sbostic register char *p; 24542402Sbostic char *save; 24640390Sbostic 24740390Sbostic /* 24840390Sbostic * if the user uses "more", we make it "more -s"; watch out for 24940390Sbostic * PAGER = "mypager /usr/ucb/more" 25040390Sbostic */ 25140390Sbostic for (p = name; *p && !isspace(*p); ++p); 25240390Sbostic for (; p > name && *p != '/'; --p); 25340390Sbostic if (p != name) 25440390Sbostic ++p; 25540390Sbostic 25640390Sbostic /* make sure it's "more", not "morex" */ 25740390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 25840390Sbostic save = name; 25940390Sbostic /* allocate space to add the "-s" */ 26040390Sbostic if (!(name = 26140390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 26240390Sbostic enomem(); 26340390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 26440390Sbostic } 26540390Sbostic return(name); 26640390Sbostic } 26740390Sbostic 26840390Sbostic /* 26934057Sbostic * jump -- 27034057Sbostic * strip out flag argument and jump 27134057Sbostic */ 27234057Sbostic jump(argv, flag, name) 27334057Sbostic char **argv, *name; 27434057Sbostic register char *flag; 27534057Sbostic { 27634057Sbostic register char **arg; 27734057Sbostic 27834057Sbostic argv[0] = name; 27934057Sbostic for (arg = argv + 1; *arg; ++arg) 28034057Sbostic if (!strcmp(*arg, flag)) 28134057Sbostic break; 28234057Sbostic for (; *arg; ++arg) 28334057Sbostic arg[0] = arg[1]; 28434057Sbostic execvp(name, argv); 28542402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 28634057Sbostic exit(1); 28734057Sbostic } 28834057Sbostic 28934057Sbostic /* 29034057Sbostic * usage -- 29140390Sbostic * print usage message and die 29234057Sbostic */ 29334057Sbostic usage() 29434057Sbostic { 29540390Sbostic (void)fprintf(stderr, 29640390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 29734057Sbostic exit(1); 29834057Sbostic } 299