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.25 (Berkeley) 02/12/92"; 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_how, f_where; 29 char *command, *machine, *p_augment, *p_path, *pager, *progname; 30 extern char **arorder, *pathbuf; 31 32 main(argc, argv) 33 int argc; 34 register char **argv; 35 { 36 extern char *optarg; 37 extern int optind; 38 int ch, res; 39 char *section[2], *check_pager(), *getpath(), **getorder(), *tmp; 40 41 progname = "man"; 42 while ((ch = getopt(argc, argv, "-acfhkM:m:P:w")) != EOF) 43 switch((char)ch) { 44 case 'a': 45 f_all = 1; 46 break; 47 case 'c': 48 case '-': /* deprecated */ 49 f_cat = 1; 50 break; 51 case 'h': 52 f_how = 1; 53 break; 54 case 'm': 55 p_augment = optarg; 56 break; 57 case 'M': 58 case 'P': /* backward compatibility */ 59 p_path = optarg; 60 break; 61 /* 62 * "man -f" and "man -k" are backward compatible, undocumented 63 * ways of calling whatis(1) and apropos(1). 64 */ 65 case 'f': 66 jump(argv, "-f", "whatis"); 67 /* NOTREACHED */ 68 case 'k': 69 jump(argv, "-k", "apropos"); 70 /* NOTREACHED */ 71 case 'w': 72 f_all = f_where = 1; 73 break; 74 case '?': 75 default: 76 usage(); 77 } 78 argv += optind; 79 80 if (!*argv) 81 usage(); 82 83 if (!f_cat && !f_how) 84 if (!isatty(1)) 85 f_cat = 1; 86 else if (pager = getenv("PAGER")) 87 pager = check_pager(pager); 88 else 89 pager = _PATH_PAGER; 90 91 if (!(machine = getenv("MACHINE"))) 92 machine = MACHINE; 93 94 /* see if checking in a specific section */ 95 if (argc > 1 && getsection(*argv)) { 96 section[0] = *argv++; 97 section[1] = (char *)NULL; 98 } else { 99 section[0] = "_default"; 100 section[1] = (char *)NULL; 101 } 102 103 arorder = getorder(); 104 if (p_path || (p_path = getenv("MANPATH"))) { 105 char buf[MAXPATHLEN], **av; 106 107 tmp = strtok(p_path, ":"); 108 while (tmp) { 109 (void)snprintf(buf, sizeof(buf), "%s/", tmp); 110 for (av = arorder; *av; ++av) 111 cadd(buf, strlen(buf), *av); 112 tmp = strtok(NULL, ":"); 113 } 114 p_path = pathbuf; 115 } else if (!(p_path = getpath(section)) && !p_augment) { 116 (void)fprintf(stderr, 117 "man: no place to search for those manual pages.\n"); 118 exit(1); 119 } 120 121 for (; *argv; ++argv) { 122 if (p_augment) 123 res = manual(p_augment, *argv); 124 res = manual(p_path, *argv); 125 if (res || f_where) 126 continue; 127 (void)fprintf(stderr, 128 "man: no entry for %s in the manual.\n", *argv); 129 exit(1); 130 } 131 132 /* use system(3) in case someone's pager is "pager arg1 arg2" */ 133 if (command) 134 (void)system(command); 135 exit(0); 136 } 137 138 /* 139 * manual -- 140 * given a path, a directory list and a file name, find a file 141 * that matches; check ${directory}/${dir}/{file name} and 142 * ${directory}/${dir}/${machine}/${file name}. 143 */ 144 manual(path, name) 145 char *path, *name; 146 { 147 register int res; 148 register char *end; 149 char fname[MAXPATHLEN + 1]; 150 151 for (res = 0;; path = end + 1) { 152 if (!*path) /* foo: */ 153 break; 154 if (end = index(path, ':')) { 155 if (end == path + 1) /* foo::bar */ 156 continue; 157 *end = '\0'; 158 } 159 (void)sprintf(fname, "%s/%s.0", path, name); 160 if (access(fname, R_OK)) { 161 (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 162 if (access(fname, R_OK)) 163 continue; 164 } 165 166 if (f_where) 167 (void)printf("man: found in %s.\n", fname); 168 else if (f_cat) 169 cat(fname); 170 else if (f_how) 171 how(fname); 172 else 173 add(fname); 174 if (!f_all) 175 return(1); 176 res = 1; 177 if (!end) 178 break; 179 *end = ':'; 180 } 181 return(res); 182 } 183 184 /* 185 * how -- 186 * display how information 187 */ 188 how(fname) 189 char *fname; 190 { 191 register FILE *fp; 192 193 register int lcnt, print; 194 register char *p; 195 char buf[BUFSIZ]; 196 197 if (!(fp = fopen(fname, "r"))) { 198 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 199 exit(1); 200 } 201 #define S1 "SYNOPSIS" 202 #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 203 #define D1 "DESCRIPTION" 204 #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 205 for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 206 if (!strncmp(buf, S1, sizeof(S1) - 1) || 207 !strncmp(buf, S2, sizeof(S2) - 1)) { 208 print = 1; 209 continue; 210 } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 211 !strncmp(buf, D2, sizeof(D2) - 1)) 212 return; 213 if (!print) 214 continue; 215 if (*buf == '\n') 216 ++lcnt; 217 else { 218 for(; lcnt; --lcnt) 219 (void)putchar('\n'); 220 for (p = buf; isspace(*p); ++p); 221 (void)fputs(p, stdout); 222 } 223 } 224 (void)fclose(fp); 225 } 226 /* 227 * cat -- 228 * cat out the file 229 */ 230 cat(fname) 231 char *fname; 232 { 233 register int fd, n; 234 char buf[BUFSIZ]; 235 236 if ((fd = open(fname, O_RDONLY, 0)) < 0) { 237 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 238 exit(1); 239 } 240 while ((n = read(fd, buf, sizeof(buf))) > 0) 241 if (write(1, buf, n) != n) { 242 (void)fprintf(stderr, 243 "man: write: %s\n", strerror(errno)); 244 exit(1); 245 } 246 if (n == -1) { 247 (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 248 exit(1); 249 } 250 (void)close(fd); 251 } 252 253 /* 254 * add -- 255 * add a file name to the list for future paging 256 */ 257 add(fname) 258 char *fname; 259 { 260 static u_int buflen; 261 static int len; 262 static char *cp; 263 int flen; 264 265 if (!command) { 266 if (!(command = malloc(buflen = 1024))) 267 enomem(); 268 len = strlen(strcpy(command, pager)); 269 cp = command + len; 270 } 271 flen = strlen(fname); 272 if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 273 if (!(command = realloc(command, buflen += 1024))) 274 enomem(); 275 cp = command + len; 276 } 277 *cp++ = ' '; 278 len += flen + 1; /* +1 = space */ 279 (void)strcpy(cp, fname); 280 cp += flen; 281 } 282 283 /* 284 * check_pager -- 285 * check the user supplied page information 286 */ 287 char * 288 check_pager(name) 289 char *name; 290 { 291 register char *p; 292 char *save; 293 294 /* 295 * if the user uses "more", we make it "more -s"; watch out for 296 * PAGER = "mypager /usr/ucb/more" 297 */ 298 for (p = name; *p && !isspace(*p); ++p); 299 for (; p > name && *p != '/'; --p); 300 if (p != name) 301 ++p; 302 303 /* make sure it's "more", not "morex" */ 304 if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 305 save = name; 306 /* allocate space to add the "-s" */ 307 if (!(name = 308 malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 309 enomem(); 310 (void)sprintf(name, "%s %s", save, "-s"); 311 } 312 return(name); 313 } 314 315 /* 316 * jump -- 317 * strip out flag argument and jump 318 */ 319 jump(argv, flag, name) 320 char **argv, *name; 321 register char *flag; 322 { 323 register char **arg; 324 325 argv[0] = name; 326 for (arg = argv + 1; *arg; ++arg) 327 if (!strcmp(*arg, flag)) 328 break; 329 for (; *arg; ++arg) 330 arg[0] = arg[1]; 331 execvp(name, argv); 332 (void)fprintf(stderr, "%s: Command not found.\n", name); 333 exit(1); 334 } 335 336 /* 337 * usage -- 338 * print usage message and die 339 */ 340 usage() 341 { 342 (void)fprintf(stderr, 343 "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 344 exit(1); 345 } 346