1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)man.c 5.21 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/file.h> 20 #include <errno.h> 21 #include <ctype.h> 22 #include <string.h> 23 #include <stdlib.h> 24 #include "pathnames.h" 25 26 extern int errno; 27 28 int f_all, f_cat, f_where; 29 char *command, *machine, *p_augment, *p_path, *pager, *progname; 30 31 main(argc, argv) 32 int argc; 33 register char **argv; 34 { 35 extern char *optarg; 36 extern int optind; 37 int ch, res; 38 char *section[2], *check_pager(), *getpath(); 39 40 progname = "man"; 41 while ((ch = getopt(argc, argv, "-acfkM:m:P:w")) != EOF) 42 switch((char)ch) { 43 case 'a': 44 f_all = 1; 45 break; 46 case 'c': 47 case '-': /* deprecated */ 48 f_cat = 1; 49 break; 50 case 'm': 51 p_augment = optarg; 52 break; 53 case 'M': 54 case 'P': /* backward compatibility */ 55 p_path = optarg; 56 break; 57 /* 58 * "man -f" and "man -k" are backward compatible, undocumented 59 * ways of calling whatis(1) and apropos(1). 60 */ 61 case 'f': 62 jump(argv, "-f", "whatis"); 63 /* NOTREACHED */ 64 case 'k': 65 jump(argv, "-k", "apropos"); 66 /* NOTREACHED */ 67 case 'w': 68 f_all = f_where = 1; 69 break; 70 case '?': 71 default: 72 usage(); 73 } 74 argv += optind; 75 76 if (!*argv) 77 usage(); 78 79 if (!f_cat) 80 if (!isatty(1)) 81 f_cat = 1; 82 else if (pager = getenv("PAGER")) 83 pager = check_pager(pager); 84 else 85 pager = _PATH_PAGER; 86 87 if (!(machine = getenv("MACHINE"))) 88 machine = MACHINE; 89 90 /* see if checking in a specific section */ 91 if (argc > 1 && getsection(*argv)) { 92 section[0] = *argv++; 93 section[1] = (char *)NULL; 94 } else { 95 section[0] = "_default"; 96 section[1] = (char *)NULL; 97 } 98 99 if (!p_path && !(p_path = getenv("MANPATH")) && 100 !(p_path = getpath(section)) && !p_augment) { 101 (void)fprintf(stderr, 102 "man: no place to search for those manual pages.\n"); 103 exit(1); 104 } 105 106 for (; *argv; ++argv) { 107 if (p_augment) 108 res = manual(p_augment, *argv); 109 res = manual(p_path, *argv); 110 if (res || f_where) 111 continue; 112 (void)fprintf(stderr, 113 "man: no entry for %s in the manual.\n", *argv); 114 exit(1); 115 } 116 117 /* use system(3) in case someone's pager is "pager arg1 arg2" */ 118 if (command) 119 (void)system(command); 120 exit(0); 121 } 122 123 /* 124 * manual -- 125 * given a path, a directory list and a file name, find a file 126 * that matches; check ${directory}/${dir}/{file name} and 127 * ${directory}/${dir}/${machine}/${file name}. 128 */ 129 manual(path, name) 130 char *path, *name; 131 { 132 register int res; 133 register char *end; 134 char fname[MAXPATHLEN + 1]; 135 136 for (res = 0;; path = end + 1) { 137 if (!*path) /* foo: */ 138 break; 139 if (end = index(path, ':')) { 140 if (end == path + 1) /* foo::bar */ 141 continue; 142 *end = '\0'; 143 } 144 (void)sprintf(fname, "%s/%s.0", path, name); 145 if (access(fname, R_OK)) { 146 (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 147 if (access(fname, R_OK)) 148 continue; 149 } 150 151 if (f_where) 152 (void)printf("man: found in %s.\n", fname); 153 else if (f_cat) 154 cat(fname); 155 else 156 add(fname); 157 if (!f_all) 158 return(1); 159 res = 1; 160 if (!end) 161 break; 162 *end = ':'; 163 } 164 return(res); 165 } 166 167 /* 168 * cat -- 169 * cat out the file 170 */ 171 cat(fname) 172 char *fname; 173 { 174 register int fd, n; 175 char buf[BUFSIZ]; 176 177 if (!(fd = open(fname, O_RDONLY, 0))) { 178 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 179 exit(1); 180 } 181 while ((n = read(fd, buf, sizeof(buf))) > 0) 182 if (write(1, buf, n) != n) { 183 (void)fprintf(stderr, 184 "man: write: %s\n", strerror(errno)); 185 exit(1); 186 } 187 if (n == -1) { 188 (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 189 exit(1); 190 } 191 (void)close(fd); 192 } 193 194 /* 195 * add -- 196 * add a file name to the list for future paging 197 */ 198 add(fname) 199 char *fname; 200 { 201 static u_int buflen; 202 static int len; 203 static char *cp; 204 int flen; 205 206 if (!command) { 207 if (!(command = malloc(buflen = 1024))) 208 enomem(); 209 len = strlen(strcpy(command, pager)); 210 cp = command + len; 211 } 212 flen = strlen(fname); 213 if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 214 if (!(command = realloc(command, buflen += 1024))) 215 enomem(); 216 cp = command + len; 217 } 218 *cp++ = ' '; 219 len += flen + 1; /* +1 = space */ 220 (void)strcpy(cp, fname); 221 cp += flen; 222 } 223 224 /* 225 * check_pager -- 226 * check the user supplied page information 227 */ 228 char * 229 check_pager(name) 230 char *name; 231 { 232 register char *p; 233 char *save; 234 235 /* 236 * if the user uses "more", we make it "more -s"; watch out for 237 * PAGER = "mypager /usr/ucb/more" 238 */ 239 for (p = name; *p && !isspace(*p); ++p); 240 for (; p > name && *p != '/'; --p); 241 if (p != name) 242 ++p; 243 244 /* make sure it's "more", not "morex" */ 245 if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 246 save = name; 247 /* allocate space to add the "-s" */ 248 if (!(name = 249 malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 250 enomem(); 251 (void)sprintf(name, "%s %s", save, "-s"); 252 } 253 return(name); 254 } 255 256 /* 257 * jump -- 258 * strip out flag argument and jump 259 */ 260 jump(argv, flag, name) 261 char **argv, *name; 262 register char *flag; 263 { 264 register char **arg; 265 266 argv[0] = name; 267 for (arg = argv + 1; *arg; ++arg) 268 if (!strcmp(*arg, flag)) 269 break; 270 for (; *arg; ++arg) 271 arg[0] = arg[1]; 272 execvp(name, argv); 273 (void)fprintf(stderr, "%s: Command not found.\n", name); 274 exit(1); 275 } 276 277 /* 278 * usage -- 279 * print usage message and die 280 */ 281 usage() 282 { 283 (void)fprintf(stderr, 284 "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 285 exit(1); 286 } 287