* Copyright (c) 1987 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1987 Regents of the University of California.\n\
static char sccsid
[] = "@(#)man.c 5.8 (Berkeley) %G%";
#define DEF_PAGER "/usr/ucb/more -s"
#define DEF_PATH "/usr/man:/usr/new/man:/usr/local/man"
#define LOCAL_PATH "/usr/local/man"
#define LOCAL_NAME "local"
#define NEW_PATH "/usr/new/man"
/* this array maps a character (ex: '4') to an offset in stanlist */
#define secno(x) (seclist[(int)(x - '0')])
static int seclist
[] = { -1, 1, 4, 5, 6, 7, 3, 8, 2, -1, -1 };
/* sub directory list, ordered for searching */
DIR stanlist
[] = { /* standard sub-directory list */
"notused", "", "cat1", "1st", "cat8", "8th",
"cat6", "6th", "cat2", "2nd", "cat3", "3rd",
"cat4", "4th", "cat5", "5th", "cat7", "7th",
"cat3f", "3rd (F)", "cat.old", "old", NULL
, NULL
,
}, sec1list
[] = { /* section one list */
"notused", "", "cat1", "1st", "cat8", "8th",
"cat6", "6th", "cat.old", "old", NULL
, NULL
,
static DIR *dirlist
; /* list of directories to search */
static int nomore
; /* copy file to stdout */
static char *defpath
, /* default search path */
*locpath
, /* local search path */
*machine
, /* machine type */
*manpath
, /* current search path */
*newpath
, /* new search path */
*pager
; /* requested pager */
for (--argc
, ++argv
; argc
&& (*argv
)[0] == '-'; --argc
, ++argv
)
case 0: /* just write to stdout */
case 'P': /* backward compatibility */
fprintf(stderr
, "%s: missing path\n", *argv
);
* "man -f" and "man -k" are undocumented ways of calling
* whatis(1) and apropos(1). Just strip out the flag
for (arg
= argv
; arg
[0] = arg
[1]; ++arg
);
execvp(*arg_start
, arg_start
);
fputs("whatis: Command not found.\n", stderr
);
for (arg
= argv
; *arg
= arg
[1]; ++arg
);
execvp(*arg_start
, arg_start
);
fputs("apropos: Command not found.\n", stderr
);
else if (pager
= getenv("PAGER")) {
* if the user uses "more", we make it "more -s"
* watch out for PAGER = "mypager /usr/ucb/more"
for (C
= pager
; *C
&& !isspace(*C
); ++C
);
for (; C
> pager
&& *C
!= '/'; --C
);
/* make sure it's "more", not "morex" */
if (!strncmp(C
, "more", 4) && (!C
[4] || isspace(C
[4]))) {
* sizeof is 1 more than # of chars, so,
* allocate for the rest of the PAGER
* environment variable, a space, and the EOS.
if (!(pager
= malloc((u_int
)(strlen(C
) + sizeof(DEF_PAGER
) + 1)))) {
fputs("man: out of space.\n", stderr
);
(void)sprintf(pager
, "%s %s", DEF_PAGER
, C
);
if (!(machine
= getenv("MACHINE")))
if (!defpath
&& !(defpath
= getenv("MANPATH")))
for (; *defpath
&& *defpath
== ':'; ++defpath
);
/* Gentlemen... start your kludges! */
* Section 1 requests are really for section 1, 6, 8, in the
* standard, local and new directories and section old. Since
* old isn't broken up into a directory of cat[1-8], we just
* treat it like a subdirectory of the others.
case '1': case '2': case '4': case '5': case '6':
section
= secno((*argv
)[0]);
/* sect. 3 requests are for either section 3, or section 3F. */
if (!(*argv
)[1]) { /* "3" */
section
= secno((*argv
)[0]);
fprintf(stderr
, "man: what do you want from the %s section of the manual?\n", stanlist
[section
].msg
);
else if (((*argv
)[1] == 'f' || (*argv
)[1] == 'F') && !(*argv
)[2]) {
fprintf(stderr
, "man: what do you want from the %s section of the manual?\n", stanlist
[S_THREEF
].msg
);
* Requests for the new or local sections can have subsection
* numbers appended to them, i.e. "local3" is really
if (!(*argv
)[1]) /* "l" */
section
= NO_SECTION
; /* "l2" */
else if (isdigit((*argv
)[1]) && !(*argv
)[2])
section
= secno((*argv
)[1]);
lex
= strcmp(LOCAL_NAME
, *argv
);
section
= NO_SECTION
; /* "local2" */
else if (lex
< 0 && isdigit((*argv
)[sizeof(LOCAL_NAME
) - 1]) && !(*argv
)[sizeof(LOCAL_NAME
)])
section
= secno((*argv
)[sizeof(LOCAL_NAME
) - 1]);
fputs("man: what do you want from the local section of the manual?\n", stderr
);
if (!(*argv
)[1]) /* "n" */
section
= NO_SECTION
; /* "n2" */
else if (isdigit((*argv
)[1]) && !(*argv
)[2])
section
= secno((*argv
)[1]);
lex
= strcmp(NEW_NAME
, *argv
);
section
= NO_SECTION
; /* "new2" */
else if (lex
< 0 && isdigit((*argv
)[sizeof(NEW_NAME
) - 1]) && !(*argv
)[sizeof(NEW_NAME
)])
section
= secno((*argv
)[sizeof(NEW_NAME
) - 1]);
fputs("man: what do you want from the new section of the manual?\n", stderr
);
if (!(*argv
)[1] || !strcmp(*argv
, stanlist
[S_OLD
].msg
)) {
fprintf(stderr
, "man: what do you want from the %s section of the manual?\n", stanlist
[section
].msg
);
* This is really silly, but I wanted to put out rational
* errors, not just "I couldn't find it." This if statement
* knows an awful lot about what gets assigned to what in
* the switch statement we just passed through. Sorry.
if (!manual(section
, *argv
))
if (section
== NO_SECTION
)
fprintf(stderr
, "No entry for %s in the local manual.\n", *argv
);
fprintf(stderr
, "No entry for %s in the %s section of the local manual.\n", *argv
, stanlist
[section
].msg
);
else if (manpath
== newpath
)
if (section
== NO_SECTION
)
fprintf(stderr
, "No entry for %s in the new manual.\n", *argv
);
fprintf(stderr
, "No entry for %s in the %s section of the new manual.\n", *argv
, stanlist
[section
].msg
);
else if (dirlist
== sec1list
)
fprintf(stderr
, "No entry for %s in the 1st section of the manual.\n", *argv
);
else if (section
== NO_SECTION
)
fprintf(stderr
, "No entry for %s in the manual.\n", *argv
);
fprintf(stderr
, "No entry for %s in the %s section of the manual.\n", *argv
, stanlist
[section
].msg
);
* given a section number and a file name go through the directory
* list and find a file that matches.
register char *beg
, *end
;
for (beg
= manpath
;; beg
= end
+ 1) {
if (end
= index(beg
, ':'))
if (section
== NO_SECTION
)
for (dir
= dirlist
; (++dir
)->name
;) {
if (find(beg
, dir
->name
, name
))
else if (find(beg
, stanlist
[section
].name
, name
))
* given a directory path, a sub-directory and a file name,
* see if a file exists in ${directory}/${dir}/{file name}
* or in ${directory}/${dir}/${machine}/${file name}.
char fname
[MAXPATHLEN
+ 1];
(void)sprintf(fname
, "%s/%s/%s.0", beg
, dir
, name
);
if (!access(fname
, R_OK
)) {
(void)sprintf(fname
, "%s/%s/%s/%s.0", beg
, dir
, machine
, name
);
if (!access(fname
, R_OK
)) {
if (!(fd
= open(fname
, O_RDONLY
, 0))) {
while ((n
= read(fd
, buf
, sizeof(buf
))) > 0)
if (write(1, buf
, n
) != n
) {
* use system(2) in case someone's pager is
(void)sprintf(buf
, "%s %s", pager
, fname
);
* print out a usage message and die
fputs("usage: man [-] [-M path] [section] title ...\n", stderr
);