man.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1986-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. */
/* All rights reserved. */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* man
* links to apropos, whatis, and catman
* This version uses more for underlining and paging.
*/
#include <stdio.h>
#include <ctype.h>
#include <sgtty.h>
#include <signal.h>
#include <string.h>
#include <malloc.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <limits.h>
#include <wchar.h>
/*
* The default search path for man subtrees.
*/
#define MAKEWHATIS "/usr/lib/makewhatis"
#define WHATIS "windex"
/*
* Names for formatting and display programs. The values given
* below are reasonable defaults, but sites with source may
* wish to modify them to match the local environment. The
* value for TCAT is particularly problematic as there's no
* accepted standard value available for it. (The definition
* below assumes C.A.T. troff output and prints it).
*/
#define MAXTOKENS 64
#define DOT_SO ".so "
#define PREPROC_SPEC "'\\\" "
(void) printf
/*
* Directory mapping of old directories to new directories
*/
typedef struct {
char *old_name;
char *new_name;
} map_entry;
{ "3b", "3ucb" },
{ "3e", "3elf" },
{ "3g", "3gen" },
{ "3k", "3kstat" },
{ "3n", "3socket" },
{ "3r", "3rt" },
{ "3s", "3c" },
{ "3t", "3thr" },
{ "3x", "3curses" },
{ "3xc", "3xcurses" },
{ "3xn", "3xnet" }
};
/*
* A list of known preprocessors to precede the formatter itself
* in the formatting pipeline. Preprocessors are specified by
* starting a manual page with a line of the form:
* '\" X
* where X is a string consisting of letters from the p_tag fields
* below.
*/
static const struct preprocessor {
char p_tag;
char *p_nroff,
*p_troff;
} preprocessors [] = {
{'c', "cw", "cw"},
{'p', "pic", "pic"},
{'r', "refer", "refer"},
{'t', "tbl", "tbl"},
{'v', "vgrind -f", "vgrind -f"},
{0, 0, 0}
};
struct suffix {
char *ds;
char *fs;
};
/*
* Subdirectories to search for unformatted/formatted man page
* versions, in nroff and troff variations. The searching
* code in manual() is structured to expect there to be two
* subdirectories apiece, the first for unformatted files
* and the second for formatted ones.
*/
#define MAN_USAGE "\
usage:\tman [-] [-adFlrt] [-M path] [-T macro-package ] [ -s section ] \
name ...\n\
\tman [-M path] -k keyword ...\n\tman [-M path] -f file ..."
#define CATMAN_USAGE "\
usage:\tcatman [-p] [-c|-ntw] [-M path] [-T macro-package ] [sections]"
static char *opts[] = {
"FfkrP:M:T:ts:lad", /* man */
"wpnP:M:T:tc" /* catman */
};
struct man_node {
char *path; /* mandir path */
char **secv; /* submandir suffices */
};
/*
* flags (options)
*/
static int nomore;
static int troffit;
static int debug;
static int Tflag;
static int sargs;
static int margs;
static int force;
static int found;
static int list;
static int all;
static int whatis;
static int apropos;
static int catmando;
static int nowhatis;
static int whatonly;
static int compargs; /* -c option for catman */
static char macros[MAXPATHLEN];
static char *manpath;
static char *mansec;
static char *pager;
static char *troffcmd;
static char *troffcat;
static char **subdirs;
static char *check_config(char *);
static struct man_node *build_manpath(char **);
static void get_all_sect(struct man_node *);
static int makecat(char *, char **, int);
static int getdirs(char *, char ***, short);
static void lookup_windex(char *, char *);
static void more(char **, int);
static void cleanup(char **);
static void bye(int);
static char **split(char *, char);
static void lower(char *);
static int cmp(const void *, const void *);
static void mandir(char **, char *, char *);
static int searchdir(char *, char *, char *);
static int windex(char **, char *, char *);
static int compare(char *, char *);
static int format(char *, char *, char *, char *);
static char *addlocale(char *);
static int get_manconfig(FILE *, char *);
static void malloc_error(void);
static int sgmlcheck(const char *);
static char *map_section(char *, char *);
/*
* This flag is used when the SGML-to-troff converter
* is absent - all the SGML searches are bypassed.
*/
static int no_sroff = 0;
/*
* This flag is used to describe the case where we've found
* an SGML formatted manpage in the sman directory, we haven't
* found a troff formatted manpage, and we don't have the SGML to troff
* conversion utility on the system.
*/
static int sman_no_man_no_sroff;
static char *newsection = NULL;
int
{
int badopts = 0;
int c;
char **pathv, **p;
char *cmdname;
no_sroff = 1;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* get user defined stuff
*/
/*
* get base part of command name
*/
cmdname++;
else
whatis++;
exit(2);
}
goto doargs;
catmando++;
opterr = 0;
switch (c) {
/*
* man specific options
*/
case 'k':
apropos++;
/*FALLTHROUGH*/
case 'f':
whatis++;
break;
case 'F':
force++; /* do lookups the hard way */
break;
case 's':
sargs++;
break;
case 'r':
break;
case 'l':
list++; /* implies all */
/*FALLTHROUGH*/
case 'a':
all++;
break;
case 'd':
/*
* catman specific options
*/
case 'p':
debug++;
break;
case 'n':
nowhatis++;
break;
case 'w':
whatonly++;
break;
case 'c': /* n|troff compatibility */
if (no_sroff)
"catman: SGML conversion not "
"available -- -c flag ignored\n"));
else
compargs++;
continue;
/*
* shared options
*/
case 'P': /* Backwards compatibility */
case 'M': /* Respecify path for man pages. */
margs++;
break;
case 'T': /* Respecify man macros */
Tflag++;
break;
case 't':
troffit++;
break;
case '?':
badopts++;
}
/*
* Bad options or no args?
* (catman doesn't need args)
*/
exit(2);
}
"-c option cannot be used with [-w][-n][-t]\n"));
exit(2);
}
exit(2);
}
nomore++;
/*
* Collect environment information.
*/
if (troffit) {
} else {
}
/* release pathv allocated by split() */
p = pathv;
while (*p) {
free(*p);
p++;
}
if (catmando) {
exit(0);
}
/*
* The manual routine contains windows during which
* termination would leave a temp file behind. Thus
* we blanket the whole thing with a clean-up routine.
*/
}
nomore++;
} else if (whatis)
else
}
return (0);
/*NOTREACHED*/
}
/*
* This routine builds the manpage structure from MANPATH.
*/
static struct man_node *
build_manpath(char **pathv)
{
char **p;
char **q;
char **r;
int s;
s = sizeof (struct man_node);
for (p = pathv; *p; p++) {
q = split(*p, ',');
if (catmando) {
gettext("%s is not accessible.\n"),
q[0]);
}
} else {
else
malloc_error();
}
for (r = q; *r != NULL; r++)
free(*r);
free(q);
}
return (manpage);
}
/*
* Stores the mandir path into the manp structure.
*/
static void
{
char *s;
int i = 0;
s = *pv;
while (*s != NULL && *s != ',')
i++, s++;
malloc_error();
}
/*
* Stores the mandir's corresponding sections (submandir
* directories) into the manp structure.
*/
static void
{
char *sections;
char **sectp;
if (sargs) {
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
"%s: from -M option, MANSECTS=%s\n"),
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
"%s: from %s, MANSECTS=%s\n"),
} else {
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* if man.cf has not been found or sections has not been specified
*/
if (debug)
"%s: search the sections lexicographically\n"),
}
}
/*
* Get suffices of all sub-mandir directories in a mandir.
*/
static void
{
char **dirv;
char **dv;
char **p;
int plen;
int maxentries = MAXTOKENS;
int entries = 0;
return;
/*
* sortdir() allocates memory for dirv and dirv[].
*/
/*
* allocates memory for manp->secv only if it's NULL
*/
malloc_error();
}
++plen;
/* release memory allocated by sortdir */
continue;
}
/* release memory allocated by sortdir */
continue;
}
/*
* copy the string in (*dv + plen) to *p
*/
if (*p == NULL)
malloc_error();
p++;
entries++;
if (entries == maxentries) {
maxentries += MAXTOKENS;
sizeof (char *) * maxentries);
malloc_error();
}
/* release memory allocated by sortdir */
}
*p = 0;
/* release memory allocated by sortdir */
}
/*
* Format man pages (build cat pages); if no
* sections are specified, build all of them.
* When building cat pages:
* catman() tries to build cat pages for locale specific
* man dirs first. Then, catman() tries to build cat pages
* regardless of the locale.
* When building windex file:
* catman() tries to build windex file for locale specific
* man dirs first. Then, catman() tries to build windex file
* regardless of the locale.
*/
static void
{
char **dv;
int changed;
struct man_node *p;
int ndirs = 0;
char *ldir;
int i;
/*
* TRANSLATION_NOTE - message for catman -p
*/
if (debug)
"\nmandir path = %s\n"), p->path);
ndirs = 0;
/*
* Build cat pages
* addlocale() allocates memory and returns it
*/
if (!whatonly) {
if (*localedir != '\0') {
if (defaultmandir)
defaultmandir = 0;
/* getdirs allocate memory for dv */
if (ndirs != 0) {
/* release memory by getdirs */
for (i = 0; i < ndirs; i++) {
}
}
}
/* default man dir is always processed */
defaultmandir = 1;
/* release memory allocated by getdirs */
for (i = 0; i < ndirs; i++) {
}
}
/*
* Build whatis database
* print error message if locale is set and man dir not found
* won't build it at all if -c option is on
*/
if (*localedir != '\0') {
/* just count the number of ndirs */
MAKEWHATIS, ldir);
}
}
/* whatis database of the default man dir */
/* will be always built in C locale. */
MAKEWHATIS, p->path);
}
/* release memory allocated by addlocale() */
}
}
/*
* Build cat pages for given sections
*/
static int
{
struct dirent *d;
int i, fmt;
manflag = 1;
smanflag = 1;
continue;
}
/*
* TRANSLATION_NOTE - message for catman -p
*/
if (debug)
"Building cat pages for mandir = %s\n"), path);
(void) umask(02);
/*
* TRANSLATION_NOTE - message for catman -p
*/
if (debug)
catdir);
else {
continue;
}
}
}
/*
* if it is -c option of catman, if there is no
* coresponding man dir for sman files to go to,
* make the man dir
*/
continue;
}
}
if (smanflag) {
continue;
> 0)
fmt++;
}
}
continue;
> 0)
fmt++;
}
}
if (manflag)
if (smanflag)
}
return (fmt);
}
/*
* Get all "man" and "sman" dirs under a given manpath
* and return the number found
* If -c option is on, only count sman dirs
*/
static int
{
struct dirent *d;
int n = 0;
int i = 0;
int maxentries = MAXDIRS;
char **dv;
if (debug) {
if (*localedir != '\0')
}
return (0);
}
if (flag) {
/* allocate memory for dirv */
malloc_error();
}
sgml_flag = 1;
i++;
}
man_flag = 1;
if (flag) {
malloc_error();
dv++;
n = i;
}
if (flag) {
malloc_error();
dv++;
}
n++;
}
if (flag) {
int entries = maxentries;
maxentries += MAXTOKENS;
sizeof (char *) * maxentries);
malloc_error();
}
}
}
return (n);
}
/*
* Find matching whatis or apropos entries
* whatapro() tries to handle the windex file of the locale specific
* man dirs first, then tries to handle the windex file of the default
*/
static void
{
char *p;
struct man_node *b;
int ndirs = 0;
char *ldir;
/*
* TRANSLATION_NOTE - message for man -d
* %s takes a parameter to -k option.
*/
/*
* get base part of name
*/
if (!apropos) {
p = word;
else
p++;
} else {
p = word;
}
if (*localedir != '\0') {
/* addlocale() allocates memory and returns it */
if (defaultmandir)
defaultmandir = 0;
if (ndirs != 0) {
/*
* TRANSLATION_NOTE - message for man -d
*/
lookup_windex(whatpath, p);
}
/* release memory allocated by addlocale() */
}
defaultmandir = 1;
/*
* TRANSLATION_NOTE - message for man -d
*/
lookup_windex(whatpath, p);
}
}
static void
{
char **pp;
return;
}
if (apropos) {
malloc_error();
}
"Invalid character in keyword\n"));
exit(1);
}
break;
}
} else {
/*
* release memory allocated by
* strdup() in bfsearch()
*/
}
}
if (word_wchar)
}
/*
* case-insensitive compare unless upper case is used
* ie) "mount" matches mount, Mount, MOUNT
* "Mount" matches Mount, MOUNT
* "MOUNT" matches MOUNT only
* If matched return 0. Otherwise, return 1.
*/
static int
{
for (; (*ws == 0) ||
if (*ws == 0)
return (0);
return (1);
}
/*
* Invoke PAGER with all matching man pages
*/
static void
{
char **vp;
/*
* Dont bother.
*/
return;
return;
}
/*
* Build arg list
*/
}
}
/*
* Get rid of dregs.
*/
static void
{
char **vp;
}
}
/*
* Clean things up after receiving a signal.
*/
/*ARGSUSED*/
static void
{
exit(1);
/*NOTREACHED*/
}
/*
* Split a string by specified separator.
* ignore empty components/adjacent separators.
* returns vector to all tokens
*/
static char **
{
int maxentries = MAXTOKENS;
int entries = 0;
malloc_error();
tp++; /* ignore */
continue;
}
if (tp) {
/* a component found */
malloc_error();
tp++;
vp++;
} else {
/* the last component */
malloc_error();
vp++;
}
entries++;
if (entries == maxentries) {
maxentries += MAXTOKENS;
maxentries * sizeof (char *));
malloc_error();
}
}
*vp = 0;
return (tokv);
}
/*
* Convert paths to full paths if necessary
*
*/
static void
{
char *cwd;
char *p;
struct man_node *b;
perror("getcwd");
exit(1);
}
if (*(b->path) == '/')
continue;
malloc_error();
}
/*
* resetting b->path
*/
b->path = p;
}
/*
* release memory allocated by getcwd()
*/
}
/*
* Map (in place) to lower case
*/
static void
lower(char *s)
{
if (s == 0)
return;
while (*s) {
if (isupper(*s))
*s = tolower(*s);
s++;
}
}
/*
* compare for sort()
* sort first by section-spec, then by prefix {sman, man, cat, fmt}
* note: prefix is reverse sorted so that "sman" and "man" always
* comes before {cat, fmt}
*/
static int
{
int n;
/* by section; sman always before man dirs */
return (n);
/* by prefix reversed */
}
/*
* Find a man page ...
* Loop through each path specified,
* first try the lookup method (whatis database),
* and if it doesn't exist, do the hard way.
*/
static void
{
struct man_node *p;
int ndirs = 0;
char *ldir;
char *ldirs[2];
/*
* for each path in MANPATH
*/
found = 0;
/*
* TRANSLATION_NOTE - message for man -d
*/
if (*localedir != '\0') {
/* addlocale() allocates memory and returns it */
if (defaultmandir)
defaultmandir = 0;
/*
* TRANSLATION_NOTE - message for man -d
*/
if (debug)
"localedir = %s, ldir = %s\n"),
if (ndirs != 0) {
if (force ||
}
/* release memory allocated by addlocale() */
}
defaultmandir = 1;
/*
* locale mandir not valid, man page in locale
* mandir not found, or -a option present
*/
}
break;
}
if (found) {
} else {
if (sargs) {
} else {
}
if (sman_no_man_no_sroff)
"for '%s' but it cannot be displayed.)\n"),
}
sman_no_man_no_sroff = 0;
}
/*
* For a specified manual directory,
* read, store, & sort section subdirs,
* for each section specified
* find and search matching subdirs
*/
static void
{
char **dirv;
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* opendir(%s) returned 0
*/
if (debug)
" opendir on %s failed\n"), path);
return;
}
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
/*
* sordir() allocates memory for dirv and dirv[].
*/
/*
* Search in the order specified by MANSECTS
*/
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* ex. section = 3c
*/
if (*dv[0] == 's')
plen++;
if (**secv == '\\') {
continue;
/* check to see if directory name changed */
if (!all &&
== NULL) {
continue;
}
if (newsection == NULL)
newsection = "";
continue;
}
}
continue;
if (!all) {
/* release memory allocated by sortdir() */
while (*pdv) {
pdv++;
}
/* release memory allocated by sortdir() */
return;
}
/*
* if we found a match in the man dir skip
* the corresponding cat dir if it exists
*/
dv++;
}
}
/* release memory allocated by sortdir() */
while (*pdv) {
pdv++;
}
}
/*
* Sort directories.
*/
static void
{
struct dirent *d;
char **dv;
int maxentries = MAXDIRS;
int entries = 0;
continue;
/* check if it matches sman, man, cat format */
malloc_error();
dv++;
entries++;
if (entries == maxentries) {
maxentries += MAXDIRS;
sizeof (char *) * maxentries);
malloc_error();
}
}
}
*dv = 0;
}
/*
* Search a section subdirectory for a
* given man page, return 1 for success
*/
static int
{
char *last;
int nlen;
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* ex. scanning = man3c
*/
return (0);
}
sman_no_man_no_sroff = 1;
return (0);
}
return (1);
}
}
return (0);
}
/*
* Check the hash table of old directory names to see if there is a
* new directory name.
* Returns new directory name if a match; after checking to be sure
* directory exists.
* Otherwise returns NULL
*/
static char *
{
int i;
int len;
char fullpath[MAXPATHLEN];
if (list) /* -l option fall through */
return (NULL);
} else {
}
} else {
return (NULL);
}
}
}
return (NULL);
}
/*
* Use windex database for quick lookup of man pages
* instead of mandir() (brute force search)
*/
static int
{
int found_in_windex = 0;
char *tmp[] = {0, 0, 0, 0};
return (-1);
return (0);
}
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
" search in = %s file\n"), whatfile);
return (-1); /* force search in mandir */
}
/*
* Save and split sections
* section() allocates memory for sp->ds
*/
/*
* Search in the order specified
* by MANSECTS
*/
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* ex. search an entry to match printf.3c
*/
if (debug)
/*
* For every whatis entry that
* was matched
*/
if (**secv == '\\') {
continue;
/* check to see if directory name changed */
if (!all &&
== NULL) {
continue;
}
if (newsection == NULL)
newsection = "";
continue;
}
}
/*
* here to form "sman", "man", "cat"|"fmt" in
* order
*/
if (!no_sroff) {
for (i = 1; i < 4; i++)
} else {
for (i = 0; i < 3; i++)
}
if (exist)
break;
}
if (!exist) {
"%s entry incorrect: %s(%s) not found.\n"),
continue;
}
/*
* By now we have a match
*/
found_in_windex = 1;
if (!all)
goto finish;
}
}
/*
* release memory allocated by section()
*/
sp++;
}
/*
* If we didn't find a match, return failure as if we didn't find
* the windex at all. Why? Well, if you create a windex, then upgrade
* to a later release that contains new man pages, and forget to
* recreate the windex (since we don't do that automatically), you
* won't see any new man pages since they aren't in the windex.
* Pretending we didn't see a windex at all if there are no matches
* forces a search of the underlying directory. After all, the
* goal of the windex is to enable searches (man -k) and speed things
* up, not to _prevent_ you from seeing new man pages, so this seems
* ok. The only problem is when there are multiple entries (different
* sections), and some are in and some are out. Say you do 'man ls',
* and ls(1) isn't in the windex, but ls(1B) is. In that case, we
* will find a match in ls(1B), and you'll see that man page.
* That doesn't seem bad since if you specify the section the search
* will be restricted too. So in the example above, if you do
* 'man -s 1 ls' you'll get ls(1).
*/
if (found_in_windex)
return (0);
else
return (-1);
}
/*
* Return pointers to the section-spec
* and file-suffix of a whatis entry
*/
static void
{
char *lp, *p;
p = strchr(s, ')');
gettext("mangled windex entry:\n\t%s\n"), s);
return;
}
*p = 0;
/*
* copy the string pointed to by lp
*/
malloc_error();
/*
* release memory in s
* s has been allocated memory in bfsearch()
*/
free(s);
/*
* split section-specifier if file-name
* suffix differs from section-suffix
*/
*p++ = 0;
} else
}
/*
* Binary file search to find matching man
* pages in whatis database.
*/
static int
{
char **vp;
int c;
bot = 0;
for (;;) {
do {
mid++;
} while (c != EOF && c != '\n');
break;
case -2:
case -1:
case 0:
break;
continue;
case 1:
case 2:
continue;
}
break;
}
*matchv = 0;
}
case -2:
*matchv = 0;
case -1:
case 0:
malloc_error();
else
matchv++;
break;
case 1:
case 2:
continue;
}
break;
}
case -1:
case 0:
malloc_error();
else
matchv++;
continue;
}
break;
}
*matchv = 0;
}
static int
{
char *entbuf;
char *s;
int mbcurmax = MB_CUR_MAX;
malloc_error();
}
s = entbuf;
while (*s) {
if (*s == '\t' || *s == ' ') {
*s = '\0';
break;
}
if (mlen == -1) {
"Invalid character in windex file.\n"));
exit(1);
}
s += mlen;
}
if (comp == 0) {
return (0);
} else if (comp < 0) {
return (-2);
} else {
return (2);
}
}
/*
* Format a man page and follow .so references
* if necessary.
*/
static int
{
char *tmpname;
int catonly = 0;
int tempfd;
char *ptr;
char *new_m;
char *tmpsubdir;
found++;
catonly++;
if (*dir == 's') {
++plen;
} else
if (list) {
return (-1);
}
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
" formatted = %s\n"), catpname);
/*
* Take care of indirect references to other man pages;
* We follow .so chains, replacing title with the .so'ed
* file at each stage, and keeping track of how many times
* we've done so, so that we can avoid looping.
*/
*soed = 0;
socount = 0;
for (;;) {
char *cp;
char *s;
char *new_s;
if (catonly)
break;
/*
* Grab manpname's first line, stashing it in manbuf.
*/
gettext("Can't find referent of "
".so in %s\n"), soed);
return (-1);
}
return (-1);
}
manpname);
return (-1);
}
break;
return (-1);
}
new_s++;
(void) sprintf(s, "%s%s/%s",
}
if (cp)
*cp = '\0';
/*
* Compensate for sloppy typists by stripping
* trailing white space.
*/
*cp = '\0';
/*
* Go off and find the next link in the chain.
*/
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
}
/*
* Make symlinks if so'ed and cattin'
*/
return (1);
}
/*
* Obtain the cat page that corresponds to the man page.
* If it already exists, is up to date, and if we haven't
* been told not to use it, use it as it stands.
*/
regencat = updatedcat = 0;
/*
* Construct a shell command line for formatting manpname.
* The resulting file goes initially into /tmp. If possible,
* it will later be moved to catpname.
*/
int pipestage = 0;
int needcol = 0;
"Reformatting page. Please Wait..."));
(*newsection != '\0')) {
"\nThe directory name has been changed "
"to %s\n"), newsection);
}
}
/*
* in catman command, if the file exists in sman dir already,
* don't need to convert the file in man dir to cat dir
*/
return (1);
/*
* cd to path so that relative .so commands will work
* correctly
*/
/*
* check to see whether it is a sgml file
* assume sgml symbol(>!DOCTYPE) can be found in the first
* BUFSIZ bytes
*/
return (-1);
}
return (-1);
}
sgml_flag = 1;
if (defaultmandir && *localedir) {
} else {
}
} else if (*dir == 's') {
return (-1);
}
/*
* Check for special formatting requirements by examining
* manpname's first line preprocessor specifications.
*/
sizeof (PREPROC_SPEC) - 1) == 0) {
char *ptp;
const struct preprocessor *pp;
/*
* Check for a preprocessor we know about.
*/
break;
}
gettext("unknown preprocessor "
"specifier %c\n"), *ptp);
return (-1);
}
/*
* Add it to the pipeline.
*/
/*
* Special treatment: if tbl is among the
* preprocessors and we'll process with
* nroff, we have to pass things through
* col at the end of the pipeline.
*/
needcol++;
ptp++;
}
}
/*
* if catman, use the cat page name
* otherwise, dup template and create another
* (needed for multiple pages)
*/
if (catmando)
else {
malloc_error();
}
if (! Tflag) {
if (*localedir != '\0') {
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
"\nlocale macros = %s "),
macros);
/*
* TRANSLATION_NOTE - message for man -d or catman -p
*/
if (debug)
"\nmacros = %s\n"),
macros);
}
}
if (sgml_flag == 1) {
if (check_flag == 0) {
"%s: null file\n"), tmpdir);
return (-1);
}
if (debug)
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* Error message if sys(%s) failed
*/
"sys(%s) fail!\n"), tmpbuf);
gettext(" aborted (sorry)\n"));
/* release memory for tmpname */
if (!catmando) {
}
return (-1);
} else if (debug == 0) {
== NULL) {
"%s: null file\n"), tmpdir);
/* release memory for tmpname */
if (!catmando)
return (-1);
}
/* if the file is empty, */
/* it's a fragment, do nothing */
== NULL) {
/* release memory for tmpname */
if (!catmando)
return (1);
}
sizeof (DOT_SO) - 1) == 0) {
if (!compargs) {
check_flag = 1;
/* release memory for tmpname */
if (!catmando)
goto so_again;
} else {
"/tmp/sman_XXXXXX");
if ((tempfd == -1) ||
== NULL) {
"%s: null file\n"),
tmpdir);
if (tempfd != -1)
/* release memory for tmpname */
if (!catmando)
return (-1);
}
} else {
/*
* TRANSLATION_NOTE - message for catman -c
* Error message if unable to get file name
*/
gettext("file not found\n"));
return (-1);
}
}
}
}
else
} else
else
} else
/* Reformat the page. */
/*
* TRANSLATION_NOTE - message for man -d or catman -p
* Error message if sys(%s) failed
*/
"sys(%s) fail!\n"), cmdbuf);
/* release memory for tmpname */
if (!catmando)
return (-1);
}
if (catmando)
return (1);
/*
* Attempt to move the cat page to its proper home.
*/
catpname);
updatedcat = 0;
else if (debug == 0)
if (debug) {
/* release memory for tmpname */
if (!catmando)
return (1);
}
}
/*
* Save file name (dup if necessary)
* to view later
* fix for 1123802 - don't save names if we are invoked as catman
*/
if (!catmando) {
char **tmpp;
int dup;
char *newpage;
if (regencat && !updatedcat)
else {
malloc_error();
}
/* make sure we don't add a dup */
dup = 0;
dup = 1;
break;
}
}
if (!dup)
gettext("Internal pages array overflow!\n"));
exit(1);
}
}
return (regencat);
}
/*
* Add <localedir> to the path.
*/
static char *
{
char *tmp;
malloc_error();
return (tmp);
}
/*
* From the configuration file "man.cf", get the order of suffices of
* sub-mandirs to be used in the search path for a given mandir.
*/
static char *
check_config(char *path)
{
char *sect;
char fname[MAXPATHLEN];
return (NULL);
else {
return (NULL);
}
return (++sect);
else
return (NULL);
}
}
/*
* This routine is for getting the MANSECTS entry from man.cf.
* It sets submandir to the line in man.cf that contains
* MANSECTS=sections[,sections]...
*/
static int
{
char *s, *t, *rc;
/*
* skip leading blanks
*/
for (t = buf; *t != '\0'; t++) {
if (!isspace(*t))
break;
}
/*
* skip line that starts with '#' or empty line
*/
if (*t == '#' || *t == '\0')
continue;
break;
}
/*
* the man.cf file doesn't have a MANSECTS entry
*/
return (-1);
*s = '\0'; /* replace '\n' with '\0' */
return (0);
}
static void
malloc_error(void)
{
"Memory allocation failed.\n"));
exit(1);
}
static int
{
const char *s2 = SGML_SYMBOL;
int len;
while (*s1) {
/*
* Assume the first character of SGML_SYMBOL(*s2) is '<'.
* Therefore, not necessary to do toupper(*s1) here.
*/
/*
* *s1 is '<'. Check the following substring matches
* with "!DOCTYPE".
*/
s1++;
== 0) {
/*
* SGML_SYMBOL found
*/
return (1);
}
continue;
/*
* *s1 is an ASCII char
* Skip one character
*/
s1++;
continue;
} else {
/*
* *s1 is a non-ASCII char or
* the first byte of the multibyte char.
* Skip one character
*/
if (len == -1)
len = 1;
continue;
}
}
/*
* SGML_SYMBOL not found
*/
return (0);
}
#ifdef notdef
/*
* This routine is for debugging purposes. It prints out all the
* mandir paths.
*/
{
struct man_node *p;
"in printmandir, printing each mandir path ...\n");
}
}
/*
* This routine is for debugging purposes. It prints out the
* corresponding sections (submandir directories) of a mandir.
*/
void
printsect(char **s)
{
char **p;
for (p = s; *p; p++)
(void) printf("\t%s\n", *p);
}
#endif