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.26 (Berkeley) 07/06/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 (void)fprintf(stderr, 127 "man: no entry for %s in the manual.\n", *argv); 128 } 129 130 /* use system(3) in case someone's pager is "pager arg1 arg2" */ 131 if (command) 132 (void)system(command); 133 exit(0); 134 } 135 136 /* 137 * manual -- 138 * given a path, a directory list and a file name, find a file 139 * that matches; check ${directory}/${dir}/{file name} and 140 * ${directory}/${dir}/${machine}/${file name}. 141 */ 142 manual(path, name) 143 char *path, *name; 144 { 145 register int res; 146 register char *end; 147 char fname[MAXPATHLEN + 1]; 148 149 for (res = 0;; path = end + 1) { 150 if (!*path) /* foo: */ 151 break; 152 if (end = index(path, ':')) { 153 if (end == path + 1) /* foo::bar */ 154 continue; 155 *end = '\0'; 156 } 157 (void)sprintf(fname, "%s/%s.0", path, name); 158 if (access(fname, R_OK)) { 159 (void)sprintf(fname, "%s/%s/%s.0", path, machine, name); 160 if (access(fname, R_OK)) 161 continue; 162 } 163 164 if (f_where) 165 (void)printf("man: found in %s.\n", fname); 166 else if (f_cat) 167 cat(fname); 168 else if (f_how) 169 how(fname); 170 else 171 add(fname); 172 if (!f_all) 173 return(1); 174 res = 1; 175 if (!end) 176 break; 177 *end = ':'; 178 } 179 return(res); 180 } 181 182 /* 183 * how -- 184 * display how information 185 */ 186 how(fname) 187 char *fname; 188 { 189 register FILE *fp; 190 191 register int lcnt, print; 192 register char *p; 193 char buf[BUFSIZ]; 194 195 if (!(fp = fopen(fname, "r"))) { 196 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 197 exit(1); 198 } 199 #define S1 "SYNOPSIS" 200 #define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS" 201 #define D1 "DESCRIPTION" 202 #define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN" 203 for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) { 204 if (!strncmp(buf, S1, sizeof(S1) - 1) || 205 !strncmp(buf, S2, sizeof(S2) - 1)) { 206 print = 1; 207 continue; 208 } else if (!strncmp(buf, D1, sizeof(D1) - 1) || 209 !strncmp(buf, D2, sizeof(D2) - 1)) 210 return; 211 if (!print) 212 continue; 213 if (*buf == '\n') 214 ++lcnt; 215 else { 216 for(; lcnt; --lcnt) 217 (void)putchar('\n'); 218 for (p = buf; isspace(*p); ++p); 219 (void)fputs(p, stdout); 220 } 221 } 222 (void)fclose(fp); 223 } 224 /* 225 * cat -- 226 * cat out the file 227 */ 228 cat(fname) 229 char *fname; 230 { 231 register int fd, n; 232 char buf[BUFSIZ]; 233 234 if ((fd = open(fname, O_RDONLY, 0)) < 0) { 235 (void)fprintf(stderr, "man: %s: %s\n", fname, strerror(errno)); 236 exit(1); 237 } 238 while ((n = read(fd, buf, sizeof(buf))) > 0) 239 if (write(1, buf, n) != n) { 240 (void)fprintf(stderr, 241 "man: write: %s\n", strerror(errno)); 242 exit(1); 243 } 244 if (n == -1) { 245 (void)fprintf(stderr, "man: read: %s\n", strerror(errno)); 246 exit(1); 247 } 248 (void)close(fd); 249 } 250 251 /* 252 * add -- 253 * add a file name to the list for future paging 254 */ 255 add(fname) 256 char *fname; 257 { 258 static u_int buflen; 259 static int len; 260 static char *cp; 261 int flen; 262 263 if (!command) { 264 if (!(command = malloc(buflen = 1024))) 265 enomem(); 266 len = strlen(strcpy(command, pager)); 267 cp = command + len; 268 } 269 flen = strlen(fname); 270 if (len + flen + 2 > buflen) { /* +2 == space, EOS */ 271 if (!(command = realloc(command, buflen += 1024))) 272 enomem(); 273 cp = command + len; 274 } 275 *cp++ = ' '; 276 len += flen + 1; /* +1 = space */ 277 (void)strcpy(cp, fname); 278 cp += flen; 279 } 280 281 /* 282 * check_pager -- 283 * check the user supplied page information 284 */ 285 char * 286 check_pager(name) 287 char *name; 288 { 289 register char *p; 290 char *save; 291 292 /* 293 * if the user uses "more", we make it "more -s"; watch out for 294 * PAGER = "mypager /usr/ucb/more" 295 */ 296 for (p = name; *p && !isspace(*p); ++p); 297 for (; p > name && *p != '/'; --p); 298 if (p != name) 299 ++p; 300 301 /* make sure it's "more", not "morex" */ 302 if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){ 303 save = name; 304 /* allocate space to add the "-s" */ 305 if (!(name = 306 malloc((u_int)(strlen(save) + sizeof("-s") + 1)))) 307 enomem(); 308 (void)sprintf(name, "%s %s", save, "-s"); 309 } 310 return(name); 311 } 312 313 /* 314 * jump -- 315 * strip out flag argument and jump 316 */ 317 jump(argv, flag, name) 318 char **argv, *name; 319 register char *flag; 320 { 321 register char **arg; 322 323 argv[0] = name; 324 for (arg = argv + 1; *arg; ++arg) 325 if (!strcmp(*arg, flag)) 326 break; 327 for (; *arg; ++arg) 328 arg[0] = arg[1]; 329 execvp(name, argv); 330 (void)fprintf(stderr, "%s: Command not found.\n", name); 331 exit(1); 332 } 333 334 /* 335 * usage -- 336 * print usage message and die 337 */ 338 usage() 339 { 340 (void)fprintf(stderr, 341 "usage: man [-ac] [-M path] [-m path] [section] title ...\n"); 342 exit(1); 343 } 344