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*63536Sbostic static char sccsid[] = "@(#)man.c 5.28 (Berkeley) 06/18/93"; 1633054Sbostic #endif /* not lint */ 1731703Sbostic 1831703Sbostic #include <sys/param.h> 19*63536Sbostic 20*63536Sbostic #include <ctype.h> 2140390Sbostic #include <errno.h> 22*63536Sbostic #include <fcntl.h> 23*63536Sbostic #include <stdio.h> 24*63536Sbostic #include <stdlib.h> 2540390Sbostic #include <string.h> 26*63536Sbostic #include <unistd.h> 27*63536Sbostic 2837892Sbostic #include "pathnames.h" 2931703Sbostic 3040390Sbostic extern int errno; 3131703Sbostic 3244938Sbostic int f_all, f_cat, f_how, f_where; 3340390Sbostic char *command, *machine, *p_augment, *p_path, *pager, *progname; 3444597Strent extern char **arorder, *pathbuf; 3534057Sbostic 3631703Sbostic main(argc, argv) 3733354Sbostic int argc; 3833354Sbostic register char **argv; 3931703Sbostic { 4034057Sbostic extern char *optarg; 4134057Sbostic extern int optind; 4242402Sbostic int ch, res; 4344418Strent char *section[2], *check_pager(), *getpath(), **getorder(), *tmp; 4431703Sbostic 4540390Sbostic progname = "man"; 4644938Sbostic while ((ch = getopt(argc, argv, "-acfhkM:m:P:w")) != EOF) 4734057Sbostic switch((char)ch) { 4840390Sbostic case 'a': 4940390Sbostic f_all = 1; 5031703Sbostic break; 5140390Sbostic case 'c': 5240390Sbostic case '-': /* deprecated */ 5340390Sbostic f_cat = 1; 5440390Sbostic break; 5544938Sbostic case 'h': 5644938Sbostic f_how = 1; 5744938Sbostic break; 5840390Sbostic case 'm': 5940390Sbostic p_augment = optarg; 6040390Sbostic break; 6131703Sbostic case 'M': 6231703Sbostic case 'P': /* backward compatibility */ 6340390Sbostic p_path = optarg; 6431703Sbostic break; 6542402Sbostic /* 6642402Sbostic * "man -f" and "man -k" are backward compatible, undocumented 6742402Sbostic * ways of calling whatis(1) and apropos(1). 6842402Sbostic */ 6931703Sbostic case 'f': 7034057Sbostic jump(argv, "-f", "whatis"); 7140390Sbostic /* NOTREACHED */ 7231703Sbostic case 'k': 7334057Sbostic jump(argv, "-k", "apropos"); 7440390Sbostic /* NOTREACHED */ 7532565Sbostic case 'w': 7640390Sbostic f_all = f_where = 1; 7732565Sbostic break; 7831703Sbostic case '?': 7931703Sbostic default: 8034057Sbostic usage(); 8131703Sbostic } 8234057Sbostic argv += optind; 8331703Sbostic 8434057Sbostic if (!*argv) 8534057Sbostic usage(); 8633354Sbostic 8744938Sbostic if (!f_cat && !f_how) 8831703Sbostic if (!isatty(1)) 8940390Sbostic f_cat = 1; 9040390Sbostic else if (pager = getenv("PAGER")) 9140390Sbostic pager = check_pager(pager); 9231779Sbostic else 9337892Sbostic pager = _PATH_PAGER; 9440390Sbostic 9531703Sbostic if (!(machine = getenv("MACHINE"))) 9631703Sbostic machine = MACHINE; 9740390Sbostic 9842402Sbostic /* see if checking in a specific section */ 9942402Sbostic if (argc > 1 && getsection(*argv)) { 10042402Sbostic section[0] = *argv++; 10142402Sbostic section[1] = (char *)NULL; 10242402Sbostic } else { 10342402Sbostic section[0] = "_default"; 10442402Sbostic section[1] = (char *)NULL; 10542402Sbostic } 10640390Sbostic 10744418Strent arorder = getorder(); 10844418Strent if (p_path || (p_path = getenv("MANPATH"))) { 10944418Strent char buf[MAXPATHLEN], **av; 11044418Strent 11163515Sbostic tmp = strtok(p_path, ":"); 11244418Strent while (tmp) { 11352473Sbostic (void)snprintf(buf, sizeof(buf), "%s/", tmp); 11444418Strent for (av = arorder; *av; ++av) 11563515Sbostic cadd(buf, strlen(buf), *av); 11663515Sbostic tmp = strtok(NULL, ":"); 11744418Strent } 11844418Strent p_path = pathbuf; 11944418Strent } else if (!(p_path = getpath(section)) && !p_augment) { 12042402Sbostic (void)fprintf(stderr, 12144418Strent "man: no place to search for those manual pages.\n"); 12242402Sbostic exit(1); 12342402Sbostic } 12440390Sbostic 12542402Sbostic for (; *argv; ++argv) { 12642402Sbostic if (p_augment) 12742402Sbostic res = manual(p_augment, *argv); 12842402Sbostic res = manual(p_path, *argv); 12954706Sbostic if (!res && !f_where) 13054706Sbostic (void)fprintf(stderr, 13154706Sbostic "man: no entry for %s in the manual.\n", *argv); 13242402Sbostic } 13342402Sbostic 13434752Sbostic /* use system(3) in case someone's pager is "pager arg1 arg2" */ 13533809Sbostic if (command) 13633809Sbostic (void)system(command); 13733354Sbostic exit(0); 13833354Sbostic } 13931703Sbostic 14040390Sbostic /* 14131778Sbostic * manual -- 14240390Sbostic * given a path, a directory list and a file name, find a file 14340390Sbostic * that matches; check ${directory}/${dir}/{file name} and 14433809Sbostic * ${directory}/${dir}/${machine}/${file name}. 14531778Sbostic */ 14642402Sbostic manual(path, name) 14740390Sbostic char *path, *name; 14831703Sbostic { 14942402Sbostic register int res; 15063515Sbostic register char *cp; 15140390Sbostic char fname[MAXPATHLEN + 1]; 15231703Sbostic 15363515Sbostic for (res = 0; path != NULL && *path != '\0'; path = cp) { 15463515Sbostic if (cp = strchr(path, ':')) { 15563515Sbostic if (cp == path + 1) { /* foo::bar */ 15663515Sbostic ++cp; 15742402Sbostic continue; 15863515Sbostic } 15963515Sbostic *cp = '\0'; 16033809Sbostic } 161*63536Sbostic (void)snprintf(fname, sizeof(fname), "%s/%s.0", path, name); 16242402Sbostic if (access(fname, R_OK)) { 163*63536Sbostic (void)snprintf(fname, sizeof(fname), 164*63536Sbostic "%s/%s/%s.0", path, machine, name); 16563515Sbostic if (access(fname, R_OK)) { 166*63536Sbostic if (cp != NULL) 167*63536Sbostic *cp++ = ':'; 16842402Sbostic continue; 16963515Sbostic } 17042402Sbostic } 17142402Sbostic 17242402Sbostic if (f_where) 17342402Sbostic (void)printf("man: found in %s.\n", fname); 17442402Sbostic else if (f_cat) 17542402Sbostic cat(fname); 17644938Sbostic else if (f_how) 17744938Sbostic how(fname); 17842402Sbostic else 17942402Sbostic add(fname); 18042402Sbostic if (!f_all) 18142402Sbostic return(1); 18242402Sbostic res = 1; 183*63536Sbostic if (cp != NULL) 18463515Sbostic *cp++ = ':'; 18531703Sbostic } 18642402Sbostic return(res); 18731703Sbostic } 18831703Sbostic 18931778Sbostic /* 19044938Sbostic * how -- 19144938Sbostic * display how information 19244938Sbostic */ 19344938Sbostic how(fname) 19444938Sbostic char *fname; 19544938Sbostic { 19644938Sbostic register FILE *fp; 19744938Sbostic 19844938Sbostic register int lcnt, print; 19944938Sbostic register char *p; 20044938Sbostic char buf[BUFSIZ]; 20144938Sbostic 20244938Sbostic if (!(fp = fopen(fname, "r"))) { 20344938Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 20444938Sbostic exit(1); 20544938Sbostic } 20644938Sbostic #define S1 "SYNOPSIS" 20744938Sbostic #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 20844938Sbostic #define D1 "DESCRIPTION" 20944938Sbostic #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 21044938Sbostic for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 21144938Sbostic if (!strncmp(buf, S1, sizeof(S1) - 1) || 21244938Sbostic !strncmp(buf, S2, sizeof(S2) - 1)) { 21344938Sbostic print = 1; 21444938Sbostic continue; 21544938Sbostic } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 21644938Sbostic !strncmp(buf, D2, sizeof(D2) - 1)) 21744938Sbostic return; 21844938Sbostic if (!print) 21944938Sbostic continue; 22044938Sbostic if (*buf == '\n') 22144938Sbostic ++lcnt; 22244938Sbostic else { 22344938Sbostic for(; lcnt; --lcnt) 22444938Sbostic (void)putchar('\n'); 22544938Sbostic for (p = buf; isspace(*p); ++p); 22644938Sbostic (void)fputs(p, stdout); 22744938Sbostic } 22844938Sbostic } 22944938Sbostic (void)fclose(fp); 23044938Sbostic } 23144938Sbostic /* 23233809Sbostic * cat -- 23333809Sbostic * cat out the file 23431778Sbostic */ 23533809Sbostic cat(fname) 23633809Sbostic char *fname; 23731703Sbostic { 23833809Sbostic register int fd, n; 23933809Sbostic char buf[BUFSIZ]; 24031703Sbostic 24144938Sbostic if ((fd = open(fname, O_RDONLY, 0)) < 0) { 24240390Sbostic (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 24333809Sbostic exit(1); 24431703Sbostic } 24533809Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 24633809Sbostic if (write(1, buf, n) != n) { 24740390Sbostic (void)fprintf(stderr, 24840390Sbostic "man: write: %s\n", strerror(errno)); 24933809Sbostic exit(1); 25033809Sbostic } 25133809Sbostic if (n == -1) { 25240390Sbostic (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 25333809Sbostic exit(1); 25433809Sbostic } 25533809Sbostic (void)close(fd); 25631703Sbostic } 25731703Sbostic 25831778Sbostic /* 25933809Sbostic * add -- 26033809Sbostic * add a file name to the list for future paging 26131778Sbostic */ 26233809Sbostic add(fname) 26333354Sbostic char *fname; 26431703Sbostic { 26533809Sbostic static u_int buflen; 26633809Sbostic static int len; 26733809Sbostic static char *cp; 26833809Sbostic int flen; 26931703Sbostic 27033809Sbostic if (!command) { 27140390Sbostic if (!(command = malloc(buflen = 1024))) 27240390Sbostic enomem(); 27333809Sbostic len = strlen(strcpy(command, pager)); 27433809Sbostic cp = command + len; 27533809Sbostic } 27633809Sbostic flen = strlen(fname); 27733809Sbostic if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 27840390Sbostic if (!(command = realloc(command, buflen += 1024))) 27940390Sbostic enomem(); 28033809Sbostic cp = command + len; 28131703Sbostic } 28233809Sbostic *cp++ = ' '; 28333809Sbostic len += flen + 1; /* +1 = space */ 28433809Sbostic (void)strcpy(cp, fname); 28533809Sbostic cp += flen; 28631703Sbostic } 28731703Sbostic 28831778Sbostic /* 28940390Sbostic * check_pager -- 29040390Sbostic * check the user supplied page information 29140390Sbostic */ 29240390Sbostic char * 29340390Sbostic check_pager(name) 29440390Sbostic char *name; 29540390Sbostic { 29640390Sbostic register char *p; 29742402Sbostic char *save; 29840390Sbostic 29940390Sbostic /* 30040390Sbostic * if the user uses "more", we make it "more -s"; watch out for 30140390Sbostic * PAGER = "mypager /usr/ucb/more" 30240390Sbostic */ 30340390Sbostic for (p = name; *p && !isspace(*p); ++p); 30440390Sbostic for (; p > name && *p != '/'; --p); 30540390Sbostic if (p != name) 30640390Sbostic ++p; 30740390Sbostic 30840390Sbostic /* make sure it's "more", not "morex" */ 30940390Sbostic if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 31040390Sbostic save = name; 31140390Sbostic /* allocate space to add the "-s" */ 31240390Sbostic if (!(name = 31340390Sbostic malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 31440390Sbostic enomem(); 31540390Sbostic (void)sprintf(name, "%s %s", save, "-s"); 31640390Sbostic } 31740390Sbostic return(name); 31840390Sbostic } 31940390Sbostic 32040390Sbostic /* 32134057Sbostic * jump -- 32234057Sbostic * strip out flag argument and jump 32334057Sbostic */ 32434057Sbostic jump(argv, flag, name) 32534057Sbostic char **argv, *name; 32634057Sbostic register char *flag; 32734057Sbostic { 32834057Sbostic register char **arg; 32934057Sbostic 33034057Sbostic argv[0] = name; 33134057Sbostic for (arg = argv + 1; *arg; ++arg) 33234057Sbostic if (!strcmp(*arg, flag)) 33334057Sbostic break; 33434057Sbostic for (; *arg; ++arg) 33534057Sbostic arg[0] = arg[1]; 33634057Sbostic execvp(name, argv); 33742402Sbostic (void)fprintf(stderr, "%s: Command not found.\n", name); 33834057Sbostic exit(1); 33934057Sbostic } 34034057Sbostic 34134057Sbostic /* 34234057Sbostic * usage -- 34340390Sbostic * print usage message and die 34434057Sbostic */ 34534057Sbostic usage() 34634057Sbostic { 34740390Sbostic (void)fprintf(stderr, 34840390Sbostic "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 34934057Sbostic exit(1); 35034057Sbostic } 351