131703Sbostic /* 231703Sbostic * Copyright (c) 1987 Regents of the University of California. 333054Sbostic * All rights reserved. 433054Sbostic * 533054Sbostic * Redistribution and use in source and binary forms are permitted 634886Sbostic * provided that the above copyright notice and this paragraph are 734886Sbostic * duplicated in all such forms and that any documentation, 834886Sbostic * advertising materials, and other materials related to such 934886Sbostic * distribution and use acknowledge that the software was developed 1034886Sbostic * by the University of California, Berkeley. The name of the 1134886Sbostic * University may not be used to endorse or promote products derived 1234886Sbostic * from this software without specific prior written permission. 1334886Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434886Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534886Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1631703Sbostic */ 1731703Sbostic 1831703Sbostic #ifndef lint 1931703Sbostic char copyright[] = 2031703Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 2131703Sbostic All rights reserved.\n"; 2233054Sbostic #endif /* not lint */ 2331703Sbostic 2431703Sbostic #ifndef lint 25*42402Sbostic static char sccsid[] = "@(#)man.c 5.20 (Berkeley) 05/27/90"; 2633054Sbostic #endif /* not lint */ 2731703Sbostic 2831703Sbostic #include <sys/param.h> 2931703Sbostic #include <sys/file.h> 3040390Sbostic #include <errno.h> 3131703Sbostic #include <ctype.h> 3240390Sbostic #include <string.h> 33*42402Sbostic #include <stdlib.h> 3437892Sbostic #include "pathnames.h" 3531703Sbostic 3640390Sbostic extern int errno; 3731703Sbostic 38*42402Sbostic int f_all, f_cat, f_where; 3940390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname; 4034057Sbostic 4131703Sbostic main(argc, argv) 4233354Sbostic int argc; 4333354Sbostic register char **argv; 4431703Sbostic { 4534057Sbostic extern char *optarg; 4634057Sbostic extern int optind; 47*42402Sbostic int ch, res; 48*42402Sbostic char *section[2], *check_pager(), *getpath(); 4931703Sbostic 5040390Sbostic progname = "man"; 5140390Sbostic while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF) 5234057Sbostic switch((char)ch) { 5340390Sbostic case 'a': 5440390Sbostic f_all = 1; 5531703Sbostic break; 5640390Sbostic case 'c': 5740390Sbostic case '-': /* deprecated */ 5840390Sbostic f_cat = 1; 5940390Sbostic break; 6040390Sbostic case 'm': 6140390Sbostic p_augment = optarg; 6240390Sbostic break; 6331703Sbostic case 'M': 6431703Sbostic case 'P': /* backward compatibility */ 6540390Sbostic p_path = optarg; 6631703Sbostic break; 67*42402Sbostic /* 68*42402Sbostic * "man -f" and "man -k" are backward compatible, undocumented 69*42402Sbostic * ways of calling whatis(1) and apropos(1). 70*42402Sbostic */ 7131703Sbostic case 'f': 7234057Sbostic jump(argv, "-f", "whatis"); 7340390Sbostic /* NOTREACHED */ 7431703Sbostic case 'k': 7534057Sbostic jump(argv, "-k", "apropos"); 7640390Sbostic /* NOTREACHED */ 7732565Sbostic case 'w': 7840390Sbostic f_all = f_where = 1; 7932565Sbostic break; 8031703Sbostic case '?': 8131703Sbostic default: 8234057Sbostic usage(); 8331703Sbostic } 8434057Sbostic argv += optind; 8531703Sbostic 8634057Sbostic if (!*argv) 8734057Sbostic usage(); 8833354Sbostic 8940390Sbostic if (!f_cat) 9031703Sbostic if (!isatty(1)) 9140390Sbostic f_cat = 1; 9240390Sbostic else if (pager = getenv("PAGER")) 9340390Sbostic pager = check_pager(pager); 9431779Sbostic else 9537892Sbostic pager = _PATH_PAGER; 9640390Sbostic 9731703Sbostic if (!(machine = getenv("MACHINE"))) 9831703Sbostic machine = MACHINE; 9940390Sbostic 100*42402Sbostic /* see if checking in a specific section */ 101*42402Sbostic if (argc > 1 && getsection(*argv)) { 102*42402Sbostic section[0] = *argv++; 103*42402Sbostic section[1] = (char *)NULL; 104*42402Sbostic } else { 105*42402Sbostic section[0] = "_default"; 106*42402Sbostic section[1] = (char *)NULL; 107*42402Sbostic } 10840390Sbostic 109*42402Sbostic if (!p_path && !(p_path = getenv("MANPATH")) && 110*42402Sbostic !(p_path = getpath(section)) && !p_augment) { 111*42402Sbostic (void)fprintf(stderr, 112*42402Sbostic "man: no place to search for those manual pages.\n"); 113*42402Sbostic exit(1); 114*42402Sbostic } 11540390Sbostic 116*42402Sbostic for (; *argv; ++argv) { 117*42402Sbostic if (p_augment) 118*42402Sbostic res = manual(p_augment, *argv); 119*42402Sbostic res = manual(p_path, *argv); 120*42402Sbostic if (res || f_where) 121*42402Sbostic continue; 122*42402Sbostic (void)fprintf(stderr, 123*42402Sbostic "man: no entry for %s in the manual.\n", *argv); 124*42402Sbostic exit(1); 125*42402Sbostic } 126*42402Sbostic 12734752Sbostic /* use system(3) in case someone's pager is "pager arg1 arg2" */ 12833809Sbostic if (command) 12933809Sbostic (void)system(command); 13033354Sbostic exit(0); 13133354Sbostic } 13231703Sbostic 13340390Sbostic /* 13431778Sbostic * manual -- 13540390Sbostic * given a path, a directory list and a file name, find a file 13640390Sbostic * that matches; check ${directory}/${dir}/{file name} and 13733809Sbostic * ${directory}/${dir}/${machine}/${file name}. 13831778Sbostic */ 139*42402Sbostic manual(path, name) 14040390Sbostic char *path, *name; 14131703Sbostic { 142*42402Sbostic register int res; 14340390Sbostic register char *end; 14440390Sbostic char fname[MAXPATHLEN + 1]; 14531703Sbostic 14640390Sbostic for (res = 0;; path = end + 1) { 147*42402Sbostic if (!*path) /* foo: */ 148*42402Sbostic break; 149*42402Sbostic if (end = index(path, ':')) { 150*42402Sbostic if (end == path + 1) /* foo::bar */ 151*42402Sbostic continue; 15231703Sbostic *end = '\0'; 15333809Sbostic } 154*42402Sbostic (void)sprintf(fname, "%s/%s.0", path, name); 155*42402Sbostic if (access(fname, R_OK)) { 156*42402Sbostic (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 157*42402Sbostic if (access(fname, R_OK)) 158*42402Sbostic continue; 159*42402Sbostic } 160*42402Sbostic 161*42402Sbostic if (f_where) 162*42402Sbostic (void)printf("man: found in %s.\n", fname); 163*42402Sbostic else if (f_cat) 164*42402Sbostic cat(fname); 165*42402Sbostic else 166*42402Sbostic add(fname); 167*42402Sbostic if (!f_all) 168*42402Sbostic return(1); 169*42402Sbostic res = 1; 17031703Sbostic if (!end) 171*42402Sbostic break; 17233297Sbostic *end = ':'; 17331703Sbostic } 174*42402Sbostic return(res); 17531703Sbostic } 17631703Sbostic 17731778Sbostic /* 17833809Sbostic * cat -- 17933809Sbostic * cat out the file 18031778Sbostic */ 18133809Sbostic cat(fname) 18233809Sbostic char *fname; 18331703Sbostic { 18433809Sbostic register int fd, n; 18533809Sbostic char buf[BUFSIZ]; 18631703Sbostic 18733809Sbostic if (!(fd = open(fname, O_RDONLY, 0))) { 18840390Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 18933809Sbostic exit(1); 19031703Sbostic } 19133809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 19233809Sbostic if (write(1, buf, n) != n) { 19340390Sbostic (void)fprintf(stderr, 19440390Sbostic "man: write: %s\n", strerror(errno)); 19533809Sbostic exit(1); 19633809Sbostic } 19733809Sbostic if (n == -1) { 19840390Sbostic (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 19933809Sbostic exit(1); 20033809Sbostic } 20133809Sbostic (void)close(fd); 20231703Sbostic } 20331703Sbostic 20431778Sbostic /* 20533809Sbostic * add -- 20633809Sbostic * add a file name to the list for future paging 20731778Sbostic */ 20833809Sbostic add(fname) 20933354Sbostic char *fname; 21031703Sbostic { 21133809Sbostic static u_int buflen; 21233809Sbostic static int len; 21333809Sbostic static char *cp; 21433809Sbostic int flen; 21531703Sbostic 21633809Sbostic if (!command) { 21740390Sbostic if (!(command = malloc(buflen = 1024))) 21840390Sbostic enomem(); 21933809Sbostic len = strlen(strcpy(command, pager)); 22033809Sbostic cp = command + len; 22133809Sbostic } 22233809Sbostic flen = strlen(fname); 22333809Sbostic if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 22440390Sbostic if (!(command = realloc(command, buflen += 1024))) 22540390Sbostic enomem(); 22633809Sbostic cp = command + len; 22731703Sbostic } 22833809Sbostic *cp++ = ' '; 22933809Sbostic len += flen + 1; /* +1 = space */ 23033809Sbostic (void)strcpy(cp, fname); 23133809Sbostic cp += flen; 23231703Sbostic } 23331703Sbostic 23431778Sbostic /* 23540390Sbostic * check_pager -- 23640390Sbostic * check the user supplied page information 23740390Sbostic */ 23840390Sbostic char * 23940390Sbostic check_pager(name) 24040390Sbostic char *name; 24140390Sbostic { 24240390Sbostic register char *p; 243*42402Sbostic char *save; 24440390Sbostic 24540390Sbostic /* 24640390Sbostic * if the user uses "more", we make it "more -s"; watch out for 24740390Sbostic * PAGER = "mypager /usr/ucb/more" 24840390Sbostic */ 24940390Sbostic for (p = name; *p && !isspace(*p); ++p); 25040390Sbostic for (; p > name && *p != '/'; --p); 25140390Sbostic if (p != name) 25240390Sbostic ++p; 25340390Sbostic 25440390Sbostic /* make sure it's "more", not "morex" */ 25540390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 25640390Sbostic save = name; 25740390Sbostic /* allocate space to add the "-s" */ 25840390Sbostic if (!(name = 25940390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 26040390Sbostic enomem(); 26140390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 26240390Sbostic } 26340390Sbostic return(name); 26440390Sbostic } 26540390Sbostic 26640390Sbostic /* 26734057Sbostic * jump -- 26834057Sbostic * strip out flag argument and jump 26934057Sbostic */ 27034057Sbostic jump(argv, flag, name) 27134057Sbostic char **argv, *name; 27234057Sbostic register char *flag; 27334057Sbostic { 27434057Sbostic register char **arg; 27534057Sbostic 27634057Sbostic argv[0] = name; 27734057Sbostic for (arg = argv + 1; *arg; ++arg) 27834057Sbostic if (!strcmp(*arg, flag)) 27934057Sbostic break; 28034057Sbostic for (; *arg; ++arg) 28134057Sbostic arg[0] = arg[1]; 28234057Sbostic execvp(name, argv); 283*42402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 28434057Sbostic exit(1); 28534057Sbostic } 28634057Sbostic 28734057Sbostic /* 28834057Sbostic * usage -- 28940390Sbostic * print usage message and die 29034057Sbostic */ 29134057Sbostic usage() 29234057Sbostic { 29340390Sbostic (void)fprintf(stderr, 29440390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 29534057Sbostic exit(1); 29634057Sbostic } 297