Home | History | Annotate | Download | only in src
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  4466  dk208809  * Common Development and Distribution License (the "License").
      6  4466  dk208809  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  6639      samf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.	*/
     27     0    stevel /*		All rights reserved.					*/
     28     0    stevel 
     29     0    stevel /*
     30     0    stevel  * University Copyright- Copyright (c) 1982, 1986, 1988
     31     0    stevel  * The Regents of the University of California
     32     0    stevel  * All Rights Reserved
     33     0    stevel  *
     34     0    stevel  * University Acknowledgment- Portions of this document are derived from
     35     0    stevel  * software developed by the University of California, Berkeley, and its
     36     0    stevel  * contributors.
     37     0    stevel  */
     38     0    stevel 
     39     0    stevel 
     40     0    stevel /*
     41     0    stevel  * man
     42     0    stevel  * links to apropos, whatis, and catman
     43     0    stevel  * This version uses more for underlining and paging.
     44     0    stevel  */
     45     0    stevel 
     46     0    stevel #include <stdio.h>
     47     0    stevel #include <ctype.h>
     48     0    stevel #include <sgtty.h>
     49     0    stevel #include <sys/param.h>
     50     0    stevel #include <sys/types.h>
     51     0    stevel #include <sys/stat.h>
     52     0    stevel #include <signal.h>
     53     0    stevel #include <string.h>
     54     0    stevel #include <malloc.h>
     55     0    stevel #include <dirent.h>
     56     0    stevel #include <errno.h>
     57     0    stevel #include <fcntl.h>
     58     0    stevel #include <locale.h>
     59     0    stevel #include <stdlib.h>
     60     0    stevel #include <unistd.h>
     61     0    stevel #include <memory.h>
     62     0    stevel #include <limits.h>
     63     0    stevel #include <wchar.h>
     64     0    stevel 
     65     0    stevel #define	MACROF 	"tmac.an"		/* name of <locale> macro file */
     66     0    stevel #define	TMAC_AN	"-man"		/* default macro file */
     67     0    stevel 
     68     0    stevel /*
     69     0    stevel  * The default search path for man subtrees.
     70     0    stevel  */
     71     0    stevel 
     72     0    stevel #define	MANDIR		"/usr/share/man" 	/* default mandir */
     73     0    stevel #define	MAKEWHATIS	"/usr/lib/makewhatis"
     74     0    stevel #define	WHATIS		"windex"
     75     0    stevel #define	TEMPLATE	"/tmp/mpXXXXXX"
     76     0    stevel #define	CONFIG		"man.cf"
     77     0    stevel 
     78     0    stevel /*
     79     0    stevel  * Names for formatting and display programs.  The values given
     80     0    stevel  * below are reasonable defaults, but sites with source may
     81     0    stevel  * wish to modify them to match the local environment.  The
     82     0    stevel  * value for TCAT is particularly problematic as there's no
     83     0    stevel  * accepted standard value available for it.  (The definition
     84     0    stevel  * below assumes C.A.T. troff output and prints it).
     85     0    stevel  */
     86     0    stevel 
     87     0    stevel #define	MORE	"more -s" 		/* default paging filter */
     88     0    stevel #define	CAT_S	"/usr/bin/cat -s"	/* for '-' opt (no more) */
     89     0    stevel #define	CAT_	"/usr/bin/cat"		/* for when output is not a tty */
     90     0    stevel #define	TROFF	"troff"			/* local name for troff */
     91     0    stevel #define	TCAT	"lp -c -T troff"	/* command to "display" troff output */
     92     0    stevel 
     93     0    stevel #define	SOLIMIT		10	/* maximum allowed .so chain length */
     94     0    stevel #define	MAXDIRS		128	/* max # of subdirs per manpath */
     95     0    stevel #define	MAXPAGES	32	/* max # for multiple pages */
     96     0    stevel #define	PLEN		3	/* prefix length {man, cat, fmt} */
     97     0    stevel #define	TMPLEN		7	/* length of tmpfile prefix */
     98     0    stevel #define	MAXTOKENS 	64
     99     0    stevel #define	MAXSUFFIX	20	/* length of section suffix */
    100     0    stevel 
    101     0    stevel #define	DOT_SO		".so "
    102     0    stevel #define	PREPROC_SPEC	"'\\\" "
    103     0    stevel 
    104     0    stevel #define	DPRINTF		if (debug && !catmando) \
    105     0    stevel 				(void) printf
    106     0    stevel 
    107     0    stevel #define	sys(s)		(debug ? ((void)puts(s), 0) : system(s))
    108     0    stevel #define	eq(a, b)	(strcmp(a, b) == 0)
    109     0    stevel #define	match(a, b, c)	(strncmp(a, b, c) == 0)
    110     0    stevel 
    111     0    stevel #define	ISDIR(A)	((A.st_mode & S_IFMT) == S_IFDIR)
    112     0    stevel 
    113     0    stevel #define	SROFF_CMD	"/usr/lib/sgml/sgml2roff" /* sgml converter */
    114     0    stevel #define	MANDIRNAME	"man"			  /* man directory */
    115     0    stevel #define	SGMLDIR		"sman"			  /* sman directory */
    116     0    stevel #define	SGML_SYMBOL	"<!DOCTYPE"	/* a sgml file should contain this */
    117     0    stevel #define	SGML_SYMBOL_LEN		9	/* length of SGML_SYMBOL */
    118     0    stevel 
    119     0    stevel /*
    120     0    stevel  * Directory mapping of old directories to new directories
    121     0    stevel  */
    122     0    stevel 
    123     0    stevel typedef struct {
    124     0    stevel 	char *old_name;
    125     0    stevel 	char *new_name;
    126     0    stevel } map_entry;
    127     0    stevel 
    128     0    stevel static const map_entry map[] = {
    129     0    stevel 					{ "3b", "3ucb" },
    130     0    stevel 					{ "3e", "3elf" },
    131     0    stevel 					{ "3g", "3gen" },
    132     0    stevel 					{ "3k", "3kstat" },
    133     0    stevel 					{ "3n", "3socket" },
    134     0    stevel 					{ "3r", "3rt" },
    135     0    stevel 					{ "3s", "3c" },
    136     0    stevel 					{ "3t", "3thr" },
    137     0    stevel 					{ "3x", "3curses" },
    138     0    stevel 					{ "3xc", "3xcurses" },
    139     0    stevel 					{ "3xn", "3xnet" }
    140     0    stevel };
    141     0    stevel 
    142     0    stevel /*
    143     0    stevel  * A list of known preprocessors to precede the formatter itself
    144     0    stevel  * in the formatting pipeline.  Preprocessors are specified by
    145     0    stevel  * starting a manual page with a line of the form:
    146     0    stevel  *	'\" X
    147     0    stevel  * where X is a string consisting of letters from the p_tag fields
    148     0    stevel  * below.
    149     0    stevel  */
    150     0    stevel static const struct preprocessor {
    151     0    stevel 	char	p_tag;
    152     0    stevel 	char	*p_nroff,
    153     0    stevel 		*p_troff;
    154     0    stevel } preprocessors [] = {
    155     0    stevel 	{'c',	"cw",				"cw"},
    156     0    stevel 	{'e',	"neqn /usr/share/lib/pub/eqnchar",
    157     0    stevel 			"eqn /usr/share/lib/pub/eqnchar"},
    158     0    stevel 	{'p',	"pic",				"pic"},
    159     0    stevel 	{'r',	"refer",			"refer"},
    160     0    stevel 	{'t',	"tbl",				"tbl"},
    161     0    stevel 	{'v',	"vgrind -f",			"vgrind -f"},
    162     0    stevel 	{0,	0,				0}
    163     0    stevel };
    164     0    stevel 
    165     0    stevel struct suffix {
    166     0    stevel 	char *ds;
    167     0    stevel 	char *fs;
    168     0    stevel };
    169     0    stevel 
    170     0    stevel /*
    171  6639      samf  * Flags that control behavior of build_manpath()
    172  6639      samf  *
    173  6639      samf  *   BMP_ISPATH 	pathv is a vector constructed from PATH.
    174  6639      samf  *                	Perform appropriate path translations for
    175  6639      samf  * 			manpath.
    176  6639      samf  *   BMP_APPEND_MANDIR	Add /usr/share/man to the end if it
    177  6639      samf  *			hasn't already appeared earlier.
    178  6639      samf  *   BMP_FALLBACK_MANDIR Append /usr/share/man only if no other
    179  6639      samf  *			manpath (including derived from PATH)
    180  6639      samf  * 			elements are valid.
    181  6639      samf  */
    182  6639      samf #define	BMP_ISPATH		1
    183  6639      samf #define	BMP_APPEND_MANDIR	2
    184  6639      samf #define	BMP_FALLBACK_MANDIR	4
    185  6639      samf 
    186  6639      samf /*
    187  6639      samf  * When doing equality comparisons of directories, device and inode
    188  6639      samf  * comparisons are done.  The dupsec and dupnode structures are used
    189  6639      samf  * to form a list of lists for this processing.
    190  6639      samf  */
    191  6639      samf struct secnode {
    192  6639      samf 	char		*secp;
    193  6639      samf 	struct secnode	*next;
    194  6639      samf };
    195  6639      samf struct dupnode {
    196  6639      samf 	dev_t		dev;	/* from struct stat st_dev */
    197  6639      samf 	ino_t		ino;	/* from struct stat st_ino */
    198  6639      samf 	struct secnode	*secl;	/* sections already considered */
    199  6639      samf 	struct dupnode	*next;
    200  6639      samf };
    201  6639      samf 
    202  6639      samf /*
    203  6639      samf  * Map directories that may appear in PATH to the corresponding
    204  6639      samf  * man directory
    205  6639      samf  */
    206  6639      samf static struct pathmap {
    207  6639      samf 	char	*bindir;
    208  6639      samf 	char	*mandir;
    209  6639      samf 	dev_t	dev;
    210  6639      samf 	ino_t	ino;
    211  6639      samf } bintoman[] = {
    212  6639      samf 	{"/sbin",		"/usr/share/man,1m",			0, 0},
    213  6639      samf 	{"/usr/sbin",		"/usr/share/man,1m",			0, 0},
    214  6639      samf 	{"/usr/ucb",		"/usr/share/man,1b",			0, 0},
    215  7172      samf 	{"/usr/bin/X11",	"/usr/X11/share/man",			0, 0},
    216  6639      samf 	/*
    217  6639      samf 	 * Restrict to section 1 so that whatis /usr/{,xpg4,xpg6}/bin/ls
    218  6639      samf 	 * does not confuse users with section 1 and 1b
    219  6639      samf 	 */
    220  6639      samf 	{"/usr/bin",		"/usr/share/man,1,1m,1s,1t,1c,1f", 	0, 0},
    221  6639      samf 	{"/usr/xpg4/bin",	"/usr/share/man,1",			0, 0},
    222  6639      samf 	{"/usr/xpg6/bin",	"/usr/share/man,1",			0, 0},
    223  6639      samf 	{NULL,			NULL,					0, 0}
    224  6639      samf };
    225  6639      samf 
    226  6639      samf /*
    227     0    stevel  * Subdirectories to search for unformatted/formatted man page
    228     0    stevel  * versions, in nroff and troff variations.  The searching
    229     0    stevel  * code in manual() is structured to expect there to be two
    230     0    stevel  * subdirectories apiece, the first for unformatted files
    231     0    stevel  * and the second for formatted ones.
    232     0    stevel  */
    233     0    stevel static char	*nroffdirs[] = { "man", "cat", 0 };
    234     0    stevel static char	*troffdirs[] = { "man", "fmt", 0 };
    235     0    stevel 
    236     0    stevel #define	MAN_USAGE "\
    237  6639      samf usage:\tman [-] [-adFlprt] [-M path] [-T macro-package ] [ -s section ] \
    238     0    stevel name ...\n\
    239     0    stevel \tman [-M path] -k keyword ...\n\tman [-M path] -f file ..."
    240     0    stevel #define	CATMAN_USAGE "\
    241     0    stevel usage:\tcatman [-p] [-c|-ntw] [-M path] [-T macro-package ] [sections]"
    242     0    stevel 
    243     0    stevel static char *opts[] = {
    244  6639      samf 	"FfkrpP:M:T:ts:lad",	/* man */
    245     0    stevel 	"wpnP:M:T:tc"		/* catman */
    246     0    stevel };
    247     0    stevel 
    248     0    stevel struct man_node {
    249     0    stevel 	char *path;		/* mandir path */
    250     0    stevel 	char **secv;		/* submandir suffices */
    251  6639      samf 	int  defsrch;		/* hint for man -p to avoid section list */
    252  6639      samf 	int  frompath;		/* hint for man -d and catman -p */
    253     0    stevel 	struct man_node *next;
    254     0    stevel };
    255     0    stevel 
    256     0    stevel static char	*pages[MAXPAGES];
    257     0    stevel static char	**endp = pages;
    258     0    stevel 
    259     0    stevel /*
    260     0    stevel  * flags (options)
    261     0    stevel  */
    262     0    stevel static int	nomore;
    263     0    stevel static int	troffit;
    264     0    stevel static int	debug;
    265     0    stevel static int	Tflag;
    266     0    stevel static int	sargs;
    267     0    stevel static int	margs;
    268     0    stevel static int	force;
    269     0    stevel static int	found;
    270     0    stevel static int	list;
    271     0    stevel static int	all;
    272     0    stevel static int	whatis;
    273     0    stevel static int	apropos;
    274     0    stevel static int	catmando;
    275     0    stevel static int	nowhatis;
    276     0    stevel static int	whatonly;
    277     0    stevel static int	compargs;	/* -c option for catman */
    278  6639      samf static int	printmp;
    279     0    stevel 
    280     0    stevel static char	*CAT	= CAT_;
    281     0    stevel static char	macros[MAXPATHLEN];
    282     0    stevel static char	*mansec;
    283     0    stevel static char	*pager;
    284     0    stevel static char	*troffcmd;
    285     0    stevel static char	*troffcat;
    286     0    stevel static char	**subdirs;
    287     0    stevel 
    288     0    stevel static char *check_config(char *);
    289  6639      samf static struct man_node *build_manpath(char **, int);
    290     0    stevel static void getpath(struct man_node *, char **);
    291     0    stevel static void getsect(struct man_node *, char **);
    292     0    stevel static void get_all_sect(struct man_node *);
    293     0    stevel static void catman(struct man_node *, char **, int);
    294     0    stevel static int makecat(char *, char **, int);
    295     0    stevel static int getdirs(char *, char ***, short);
    296     0    stevel static void whatapro(struct man_node *, char *, int);
    297  6639      samf static void lookup_windex(char *, char *, char **);
    298     0    stevel static int icmp(wchar_t *, wchar_t *);
    299     0    stevel static void more(char **, int);
    300     0    stevel static void cleanup(char **);
    301     0    stevel static void bye(int);
    302     0    stevel static char **split(char *, char);
    303  6639      samf static void freev(char **);
    304  4466  dk208809 static void fullpaths(struct man_node **);
    305     0    stevel static void lower(char *);
    306     0    stevel static int cmp(const void *, const void *);
    307     0    stevel static void manual(struct man_node *, char *);
    308     0    stevel static void mandir(char **, char *, char *);
    309     0    stevel static void sortdir(DIR *, char ***);
    310     0    stevel static int searchdir(char *, char *, char *);
    311     0    stevel static int windex(char **, char *, char *);
    312     0    stevel static void section(struct suffix *, char *);
    313  6639      samf static int bfsearch(FILE *, char **, char *, char **);
    314  6639      samf static int compare(char *, char *, char **);
    315     0    stevel static int format(char *, char *, char *, char *);
    316     0    stevel static char *addlocale(char *);
    317     0    stevel static int get_manconfig(FILE *, char *);
    318     0    stevel static void	malloc_error(void);
    319     0    stevel static int	sgmlcheck(const char *);
    320     0    stevel static char *map_section(char *, char *);
    321  4466  dk208809 static void free_manp(struct man_node *manp);
    322  6639      samf static void init_bintoman(void);
    323  6639      samf static char *path_to_manpath(char *);
    324  6639      samf static int dupcheck(struct man_node *, struct dupnode **);
    325  6639      samf static void free_dupnode(struct dupnode *);
    326  6639      samf static void print_manpath(struct man_node *, char *);
    327     0    stevel 
    328     0    stevel /*
    329     0    stevel  * This flag is used when the SGML-to-troff converter
    330     0    stevel  * is absent - all the SGML searches are bypassed.
    331     0    stevel  */
    332     0    stevel static int no_sroff = 0;
    333     0    stevel 
    334     0    stevel /*
    335     0    stevel  * This flag is used to describe the case where we've found
    336     0    stevel  * an SGML formatted manpage in the sman directory, we haven't
    337     0    stevel  * found a troff formatted manpage, and we don't have the SGML to troff
    338     0    stevel  * conversion utility on the system.
    339     0    stevel  */
    340     0    stevel static int sman_no_man_no_sroff;
    341     0    stevel 
    342     0    stevel static char language[PATH_MAX + 1]; 	/* LC_MESSAGES */
    343     0    stevel static char localedir[PATH_MAX + 1];	/* locale specific path component */
    344     0    stevel 
    345     0    stevel static int	defaultmandir = 1;	/* if processing default mandir, 1 */
    346     0    stevel 
    347     0    stevel static char *newsection = NULL;
    348     0    stevel 
    349     0    stevel int
    350     0    stevel main(int argc, char *argv[])
    351     0    stevel {
    352     0    stevel 	int badopts = 0;
    353     0    stevel 	int c;
    354  6639      samf 	char **pathv;
    355     0    stevel 	char *cmdname;
    356  6639      samf 	char *manpath = NULL;
    357     0    stevel 	static struct man_node	*manpage = NULL;
    358  6639      samf 	int bmp_flags = 0;
    359     0    stevel 
    360     0    stevel 	if (access(SROFF_CMD, F_OK | X_OK) != 0)
    361     0    stevel 		no_sroff = 1;
    362     0    stevel 
    363     0    stevel 	(void) setlocale(LC_ALL, "");
    364     0    stevel 	(void) strcpy(language, setlocale(LC_MESSAGES, (char *)0));
    365     0    stevel 	if (strcmp("C", language) != 0)
    366     0    stevel 		(void) sprintf(localedir, "%s", language);
    367     0    stevel 
    368     0    stevel #if !defined(TEXT_DOMAIN)
    369     0    stevel #define	TEXT_DOMAIN "SYS_TEST"
    370     0    stevel #endif
    371     0    stevel 	(void) textdomain(TEXT_DOMAIN);
    372     0    stevel 
    373     0    stevel 	(void) strcpy(macros, TMAC_AN);
    374     0    stevel 
    375     0    stevel 	/*
    376     0    stevel 	 * get base part of command name
    377     0    stevel 	 */
    378     0    stevel 	if ((cmdname = strrchr(argv[0], '/')) != NULL)
    379     0    stevel 		cmdname++;
    380     0    stevel 	else
    381     0    stevel 		cmdname = argv[0];
    382     0    stevel 
    383     0    stevel 	if (eq(cmdname, "apropos") || eq(cmdname, "whatis")) {
    384     0    stevel 		whatis++;
    385     0    stevel 		apropos = (*cmdname == 'a');
    386     0    stevel 		if ((optind = 1) == argc) {
    387     0    stevel 			(void) fprintf(stderr, gettext("%s what?\n"), cmdname);
    388     0    stevel 			exit(2);
    389     0    stevel 		}
    390     0    stevel 		goto doargs;
    391     0    stevel 	} else if (eq(cmdname, "catman"))
    392     0    stevel 		catmando++;
    393     0    stevel 
    394     0    stevel 	opterr = 0;
    395     0    stevel 	while ((c = getopt(argc, argv, opts[catmando])) != -1)
    396     0    stevel 		switch (c) {
    397     0    stevel 
    398     0    stevel 		/*
    399     0    stevel 		 * man specific options
    400     0    stevel 		 */
    401     0    stevel 		case 'k':
    402     0    stevel 			apropos++;
    403     0    stevel 			/*FALLTHROUGH*/
    404     0    stevel 		case 'f':
    405     0    stevel 			whatis++;
    406     0    stevel 			break;
    407     0    stevel 		case 'F':
    408     0    stevel 			force++;	/* do lookups the hard way */
    409     0    stevel 			break;
    410     0    stevel 		case 's':
    411     0    stevel 			mansec = optarg;
    412     0    stevel 			sargs++;
    413     0    stevel 			break;
    414     0    stevel 		case 'r':
    415     0    stevel 			nomore++, troffit++;
    416     0    stevel 			break;
    417     0    stevel 		case 'l':
    418     0    stevel 			list++;		/* implies all */
    419     0    stevel 			/*FALLTHROUGH*/
    420     0    stevel 		case 'a':
    421     0    stevel 			all++;
    422     0    stevel 			break;
    423     0    stevel 		case 'd':
    424  6639      samf 			debug++;
    425  6639      samf 			break;
    426     0    stevel 		/*
    427  6639      samf 		 * man and catman use -p differently.  In catman it
    428  6639      samf 		 * enables debug mode and in man it prints the (possibly
    429  6639      samf 		 * derived from PATH or name operand) MANPATH.
    430     0    stevel 		 */
    431     0    stevel 		case 'p':
    432  6639      samf 			if (catmando == 0) {
    433  6639      samf 				printmp++;
    434  6639      samf 			} else {
    435  6639      samf 				debug++;
    436  6639      samf 			}
    437     0    stevel 			break;
    438     0    stevel 		case 'n':
    439     0    stevel 			nowhatis++;
    440     0    stevel 			break;
    441     0    stevel 		case 'w':
    442     0    stevel 			whatonly++;
    443     0    stevel 			break;
    444     0    stevel 		case 'c':	/* n|troff compatibility */
    445     0    stevel 			if (no_sroff)
    446     0    stevel 				(void) fprintf(stderr, gettext(
    447  8107        Pu 				    "catman: SGML conversion not "
    448     0    stevel 				    "available -- -c flag ignored\n"));
    449     0    stevel 			else
    450     0    stevel 				compargs++;
    451     0    stevel 			continue;
    452     0    stevel 
    453     0    stevel 		/*
    454     0    stevel 		 * shared options
    455     0    stevel 		 */
    456     0    stevel 		case 'P':	/* Backwards compatibility */
    457     0    stevel 		case 'M':	/* Respecify path for man pages. */
    458     0    stevel 			manpath = optarg;
    459     0    stevel 			margs++;
    460     0    stevel 			break;
    461     0    stevel 		case 'T':	/* Respecify man macros */
    462     0    stevel 			(void) strcpy(macros, optarg);
    463     0    stevel 			Tflag++;
    464     0    stevel 			break;
    465     0    stevel 		case 't':
    466     0    stevel 			troffit++;
    467     0    stevel 			break;
    468     0    stevel 		case '?':
    469     0    stevel 			badopts++;
    470     0    stevel 		}
    471     0    stevel 
    472     0    stevel 	/*
    473     0    stevel 	 *  Bad options or no args?
    474  6639      samf 	 *	(man -p and catman don't need args)
    475     0    stevel 	 */
    476  6639      samf 	if (badopts || (!catmando && !printmp && optind == argc)) {
    477     0    stevel 		(void) fprintf(stderr, "%s\n", catmando ?
    478     0    stevel 		    gettext(CATMAN_USAGE) : gettext(MAN_USAGE));
    479     0    stevel 		exit(2);
    480     0    stevel 	}
    481     0    stevel 
    482     0    stevel 	if (compargs && (nowhatis || whatonly || troffit)) {
    483     0    stevel 		(void) fprintf(stderr, "%s\n", gettext(CATMAN_USAGE));
    484     0    stevel 		(void) fprintf(stderr, gettext(
    485  8107        Pu 		    "-c option cannot be used with [-w][-n][-t]\n"));
    486     0    stevel 		exit(2);
    487     0    stevel 	}
    488     0    stevel 
    489     0    stevel 	if (sargs && margs && catmando) {
    490     0    stevel 		(void) fprintf(stderr, "%s\n", gettext(CATMAN_USAGE));
    491     0    stevel 		exit(2);
    492     0    stevel 	}
    493     0    stevel 
    494     0    stevel 	if (troffit == 0 && nomore == 0 && !isatty(fileno(stdout)))
    495     0    stevel 		nomore++;
    496     0    stevel 
    497     0    stevel 	/*
    498     0    stevel 	 * Collect environment information.
    499     0    stevel 	 */
    500     0    stevel 	if (troffit) {
    501     0    stevel 		if ((troffcmd = getenv("TROFF")) == NULL)
    502     0    stevel 			troffcmd = TROFF;
    503     0    stevel 		if ((troffcat = getenv("TCAT")) == NULL)
    504     0    stevel 			troffcat = TCAT;
    505     0    stevel 	} else {
    506     0    stevel 		if (((pager = getenv("PAGER")) == NULL) ||
    507     0    stevel 		    (*pager == NULL))
    508     0    stevel 			pager = MORE;
    509     0    stevel 	}
    510     0    stevel 
    511     0    stevel doargs:
    512     0    stevel 	subdirs = troffit ? troffdirs : nroffdirs;
    513     0    stevel 
    514  6639      samf 	init_bintoman();
    515  6639      samf 
    516  6639      samf 	if (manpath == NULL && (manpath = getenv("MANPATH")) == NULL) {
    517  6639      samf 		if ((manpath = getenv("PATH")) != NULL) {
    518  6639      samf 			bmp_flags = BMP_ISPATH | BMP_APPEND_MANDIR;
    519  6639      samf 		} else {
    520  6639      samf 			manpath = MANDIR;
    521  6639      samf 		}
    522  6639      samf 	}
    523  6639      samf 
    524     0    stevel 	pathv = split(manpath, ':');
    525     0    stevel 
    526  6639      samf 	manpage = build_manpath(pathv, bmp_flags);
    527     0    stevel 
    528     0    stevel 	/* release pathv allocated by split() */
    529  6639      samf 	freev(pathv);
    530     0    stevel 
    531  4466  dk208809 	fullpaths(&manpage);
    532     0    stevel 
    533     0    stevel 	if (catmando) {
    534     0    stevel 		catman(manpage, argv+optind, argc-optind);
    535     0    stevel 		exit(0);
    536     0    stevel 	}
    537     0    stevel 
    538     0    stevel 	/*
    539     0    stevel 	 * The manual routine contains windows during which
    540     0    stevel 	 * termination would leave a temp file behind.  Thus
    541     0    stevel 	 * we blanket the whole thing with a clean-up routine.
    542     0    stevel 	 */
    543     0    stevel 	if (signal(SIGINT, SIG_IGN) == SIG_DFL) {
    544     0    stevel 		(void) signal(SIGINT, bye);
    545     0    stevel 		(void) signal(SIGQUIT, bye);
    546     0    stevel 		(void) signal(SIGTERM, bye);
    547     0    stevel 	}
    548     0    stevel 
    549  6639      samf 	/*
    550  6639      samf 	 * "man -p" without operands
    551  6639      samf 	 */
    552  6639      samf 	if ((printmp != 0) && (optind == argc)) {
    553  6639      samf 		print_manpath(manpage, NULL);
    554  6639      samf 		exit(0);
    555  6639      samf 	}
    556  6639      samf 
    557     0    stevel 	for (; optind < argc; optind++) {
    558     0    stevel 		if (strcmp(argv[optind], "-") == 0) {
    559     0    stevel 			nomore++;
    560     0    stevel 			CAT = CAT_S;
    561  6639      samf 		} else {
    562  6639      samf 			char *cmd;
    563  6639      samf 			static struct man_node *mp;
    564  6639      samf 			char *pv[2];
    565  6639      samf 
    566  6639      samf 			/*
    567  6639      samf 			 * If full path to command specified, customize
    568  6639      samf 			 * manpath accordingly
    569  6639      samf 			 */
    570  6639      samf 			if ((cmd = strrchr(argv[optind], '/')) != NULL) {
    571  6639      samf 				*cmd = '\0';
    572  6639      samf 				if ((pv[0] = strdup(argv[optind])) == NULL) {
    573  6639      samf 					malloc_error();
    574  6639      samf 				}
    575  6639      samf 				pv[1] = NULL;
    576  6639      samf 				*cmd = '/';
    577  6639      samf 				mp = build_manpath(pv,
    578  6639      samf 				    BMP_ISPATH|BMP_FALLBACK_MANDIR);
    579  6639      samf 			} else {
    580  6639      samf 				mp = manpage;
    581  6639      samf 			}
    582  6639      samf 
    583  6639      samf 			if (whatis) {
    584  6639      samf 				whatapro(mp, argv[optind], apropos);
    585  6639      samf 			} else if (printmp != 0) {
    586  6639      samf 				print_manpath(mp, argv[optind]);
    587  6639      samf 			} else {
    588  6639      samf 				manual(mp, argv[optind]);
    589  6639      samf 			}
    590  6639      samf 
    591  6639      samf 			if (mp != NULL && mp != manpage) {
    592  6639      samf 				free(pv[0]);
    593  6639      samf 				free_manp(mp);
    594  6639      samf 			}
    595  6639      samf 		}
    596     0    stevel 	}
    597     0    stevel 	return (0);
    598     0    stevel 	/*NOTREACHED*/
    599     0    stevel }
    600     0    stevel 
    601     0    stevel /*
    602  6639      samf  * This routine builds the manpage structure from MANPATH or PATH,
    603  6639      samf  * depending on flags.  See BMP_* definitions above for valid
    604  6639      samf  * flags.
    605  6639      samf  *
    606  6639      samf  * Assumes pathv elements were malloc'd, as done by split().
    607  6639      samf  * Elements may be freed and reallocated to have different contents.
    608     0    stevel  */
    609     0    stevel 
    610     0    stevel static struct man_node *
    611  6639      samf build_manpath(char **pathv, int flags)
    612     0    stevel {
    613     0    stevel 	struct man_node *manpage = NULL;
    614     0    stevel 	struct man_node *currp = NULL;
    615     0    stevel 	struct man_node *lastp = NULL;
    616     0    stevel 	char **p;
    617     0    stevel 	char **q;
    618  6639      samf 	char *mand = NULL;
    619  6639      samf 	char *mandir = MANDIR;
    620     0    stevel 	int s;
    621  6639      samf 	struct dupnode *didup = NULL;
    622     0    stevel 
    623     0    stevel 	s = sizeof (struct man_node);
    624  6639      samf 	for (p = pathv; *p; ) {
    625     0    stevel 
    626  6639      samf 		if (flags & BMP_ISPATH) {
    627  6639      samf 			if ((mand = path_to_manpath(*p)) == NULL) {
    628  6639      samf 				goto next;
    629  6639      samf 			}
    630  6639      samf 			free(*p);
    631  6639      samf 			*p = mand;
    632  6639      samf 		}
    633     0    stevel 		q = split(*p, ',');
    634     0    stevel 
    635     0    stevel 		if (access(q[0], R_OK|X_OK) != 0) {
    636     0    stevel 			if (catmando) {
    637     0    stevel 				(void) fprintf(stderr,
    638  8107        Pu 				    gettext("%s is not accessible.\n"),
    639  8107        Pu 				    q[0]);
    640     0    stevel 				(void) fflush(stderr);
    641     0    stevel 			}
    642     0    stevel 		} else {
    643     0    stevel 
    644  6639      samf 			/*
    645  6639      samf 			 * Some element exists.  Do not append MANDIR as a
    646  6639      samf 			 * fallback.
    647  6639      samf 			 */
    648  6639      samf 			flags &= ~BMP_FALLBACK_MANDIR;
    649     0    stevel 
    650  6639      samf 			if ((currp = (struct man_node *)calloc(1, s)) == NULL) {
    651     0    stevel 				malloc_error();
    652  6639      samf 			}
    653  6639      samf 
    654  6639      samf 			currp->frompath = (flags & BMP_ISPATH);
    655  6639      samf 
    656  6639      samf 			if (manpage == NULL) {
    657  6639      samf 				lastp = manpage = currp;
    658  6639      samf 			}
    659     0    stevel 
    660     0    stevel 			getpath(currp, p);
    661     0    stevel 			getsect(currp, p);
    662     0    stevel 
    663  6639      samf 			/*
    664  6639      samf 			 * If there are no new elements in this path,
    665  6639      samf 			 * do not add it to the manpage list
    666  6639      samf 			 */
    667  6639      samf 			if (dupcheck(currp, &didup) != 0) {
    668  6639      samf 				freev(currp->secv);
    669  6639      samf 				free(currp);
    670  6639      samf 			} else {
    671  6639      samf 				currp->next = NULL;
    672  6639      samf 				if (currp != manpage) {
    673  6639      samf 					lastp->next = currp;
    674  6639      samf 				}
    675  6639      samf 				lastp = currp;
    676  6639      samf 			}
    677     0    stevel 		}
    678  6639      samf 		freev(q);
    679  6639      samf next:
    680  6639      samf 		/*
    681  6639      samf 		 * Special handling of appending MANDIR.
    682  6639      samf 		 * After all pathv elements have been processed, append MANDIR
    683  6639      samf 		 * if needed.
    684  6639      samf 		 */
    685  6639      samf 		if (p == &mandir) {
    686  6639      samf 			break;
    687  6639      samf 		}
    688  6639      samf 		p++;
    689  6639      samf 		if (*p != NULL) {
    690  6639      samf 			continue;
    691  6639      samf 		}
    692  6639      samf 		if (flags & (BMP_APPEND_MANDIR|BMP_FALLBACK_MANDIR)) {
    693  6639      samf 			p = &mandir;
    694  6639      samf 			flags &= ~BMP_ISPATH;
    695  6639      samf 		}
    696  6639      samf 	}
    697  6639      samf 
    698  6639      samf 	free_dupnode(didup);
    699     0    stevel 
    700     0    stevel 	return (manpage);
    701     0    stevel }
    702     0    stevel 
    703     0    stevel /*
    704     0    stevel  * Stores the mandir path into the manp structure.
    705     0    stevel  */
    706     0    stevel 
    707     0    stevel static void
    708     0    stevel getpath(struct man_node *manp, char **pv)
    709     0    stevel {
    710     0    stevel 	char *s;
    711     0    stevel 	int i = 0;
    712     0    stevel 
    713     0    stevel 	s = *pv;
    714     0    stevel 
    715     0    stevel 	while (*s != NULL && *s != ',')
    716     0    stevel 		i++, s++;
    717     0    stevel 
    718     0    stevel 	manp->path = (char *)malloc(i+1);
    719     0    stevel 	if (manp->path == NULL)
    720     0    stevel 		malloc_error();
    721     0    stevel 	(void) strncpy(manp->path, *pv, i);
    722     0    stevel 	*(manp->path + i) = '\0';
    723     0    stevel }
    724     0    stevel 
    725     0    stevel /*
    726     0    stevel  * Stores the mandir's corresponding sections (submandir
    727     0    stevel  * directories) into the manp structure.
    728     0    stevel  */
    729     0    stevel 
    730     0    stevel static void
    731     0    stevel getsect(struct man_node *manp, char **pv)
    732     0    stevel {
    733     0    stevel 	char *sections;
    734     0    stevel 	char **sectp;
    735     0    stevel 
    736     0    stevel 	if (sargs) {
    737     0    stevel 		manp->secv = split(mansec, ',');
    738     0    stevel 
    739     0    stevel 		for (sectp = manp->secv; *sectp; sectp++)
    740     0    stevel 			lower(*sectp);
    741     0    stevel 	} else if ((sections = strchr(*pv, ',')) != NULL) {
    742  6639      samf 		if (debug) {
    743  6639      samf 			if (manp->frompath != 0) {
    744  6639      samf /*
    745  6639      samf  * TRANSLATION_NOTE - message for man -d or catman -p
    746  6639      samf  * ex. /usr/share/man: derived from PATH, MANSECTS=,1b
    747  6639      samf  */
    748  6639      samf 				(void) printf(gettext(
    749  8107        Pu 				    "%s: derived from PATH, MANSECTS=%s\n"),
    750  8107        Pu 				    manp->path, sections);
    751  6639      samf 			} else {
    752     0    stevel /*
    753     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
    754     0    stevel  * ex. /usr/share/man: from -M option, MANSECTS=,1,2,3c
    755     0    stevel  */
    756  6639      samf 				(void) fprintf(stdout, gettext(
    757  8107        Pu 				    "%s: from -M option, MANSECTS=%s\n"),
    758  8107        Pu 				    manp->path, sections);
    759  6639      samf 			}
    760  6639      samf 		}
    761     0    stevel 		manp->secv = split(++sections, ',');
    762     0    stevel 		for (sectp = manp->secv; *sectp; sectp++)
    763     0    stevel 			lower(*sectp);
    764     0    stevel 
    765     0    stevel 		if (*manp->secv == NULL)
    766     0    stevel 			get_all_sect(manp);
    767     0    stevel 	} else if ((sections = check_config(*pv)) != NULL) {
    768  6639      samf 		manp->defsrch = 1;
    769     0    stevel /*
    770     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
    771     0    stevel  * ex. /usr/share/man: from man.cf, MANSECTS=1,1m,1c,1f
    772     0    stevel  */
    773     0    stevel 		if (debug)
    774     0    stevel 			(void) fprintf(stdout, gettext(
    775  8107        Pu 			    "%s: from %s, MANSECTS=%s\n"),
    776     0    stevel 			    manp->path, CONFIG, sections);
    777     0    stevel 		manp->secv = split(sections, ',');
    778     0    stevel 
    779     0    stevel 		for (sectp = manp->secv; *sectp; sectp++)
    780     0    stevel 			lower(*sectp);
    781     0    stevel 
    782     0    stevel 		if (*manp->secv == NULL)
    783     0    stevel 			get_all_sect(manp);
    784     0    stevel 	} else {
    785  6639      samf 		manp->defsrch = 1;
    786     0    stevel /*
    787     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
    788     0    stevel  * if man.cf has not been found or sections has not been specified
    789     0    stevel  * man/catman searches the sections lexicographically.
    790     0    stevel  */
    791     0    stevel 		if (debug)
    792     0    stevel 			(void) fprintf(stdout, gettext(
    793     0    stevel 			    "%s: search the sections lexicographically\n"),
    794     0    stevel 			    manp->path);
    795     0    stevel 		manp->secv = NULL;
    796     0    stevel 		get_all_sect(manp);
    797     0    stevel 	}
    798     0    stevel }
    799     0    stevel 
    800     0    stevel /*
    801     0    stevel  * Get suffices of all sub-mandir directories in a mandir.
    802     0    stevel  */
    803     0    stevel 
    804     0    stevel static void
    805     0    stevel get_all_sect(struct man_node *manp)
    806     0    stevel {
    807     0    stevel 	DIR *dp;
    808     0    stevel 	char **dirv;
    809     0    stevel 	char **dv;
    810     0    stevel 	char **p;
    811     0    stevel 	char prev[MAXSUFFIX];
    812     0    stevel 	char tmp[MAXSUFFIX];
    813     0    stevel 	int  plen;
    814     0    stevel 	int	maxentries = MAXTOKENS;
    815     0    stevel 	int	entries = 0;
    816     0    stevel 
    817     0    stevel 	if ((dp = opendir(manp->path)) == 0)
    818     0    stevel 		return;
    819     0    stevel 
    820     0    stevel 	/*
    821     0    stevel 	 * sortdir() allocates memory for dirv and dirv[].
    822     0    stevel 	 */
    823     0    stevel 	sortdir(dp, &dirv);
    824     0    stevel 
    825     0    stevel 	(void) closedir(dp);
    826     0    stevel 
    827     0    stevel 	if (manp->secv == NULL) {
    828     0    stevel 		/*
    829     0    stevel 		 * allocates memory for manp->secv only if it's NULL
    830     0    stevel 		 */
    831     0    stevel 		manp->secv = (char **)malloc(maxentries * sizeof (char *));
    832     0    stevel 		if (manp->secv == NULL)
    833     0    stevel 			malloc_error();
    834     0    stevel 	}
    835     0    stevel 
    836     0    stevel 	(void) memset(tmp, 0, MAXSUFFIX);
    837     0    stevel 	(void) memset(prev, 0, MAXSUFFIX);
    838     0    stevel 	for (dv = dirv, p = manp->secv; *dv; dv++) {
    839     0    stevel 		plen = PLEN;
    840     0    stevel 		if (match(*dv, SGMLDIR, PLEN+1))
    841     0    stevel 			++plen;
    842     0    stevel 
    843     0    stevel 		if (strcmp(*dv, CONFIG) == 0) {
    844     0    stevel 			/* release memory allocated by sortdir */
    845     0    stevel 			free(*dv);
    846     0    stevel 			continue;
    847     0    stevel 		}
    848     0    stevel 
    849     0    stevel 		(void) sprintf(tmp, "%s", *dv + plen);
    850     0    stevel 
    851     0    stevel 		if (strcmp(prev, tmp) == 0) {
    852     0    stevel 			/* release memory allocated by sortdir */
    853     0    stevel 			free(*dv);
    854     0    stevel 			continue;
    855     0    stevel 		}
    856     0    stevel 
    857     0    stevel 		(void) sprintf(prev, "%s", *dv + plen);
    858     0    stevel 		/*
    859     0    stevel 		 * copy the string in (*dv + plen) to *p
    860     0    stevel 		 */
    861     0    stevel 		*p = strdup(*dv + plen);
    862     0    stevel 		if (*p == NULL)
    863     0    stevel 			malloc_error();
    864     0    stevel 		p++;
    865     0    stevel 		entries++;
    866     0    stevel 		if (entries == maxentries) {
    867     0    stevel 			maxentries += MAXTOKENS;
    868     0    stevel 			manp->secv = (char **)realloc(manp->secv,
    869  8107        Pu 			    sizeof (char *) * maxentries);
    870     0    stevel 			if (manp->secv == NULL)
    871     0    stevel 				malloc_error();
    872     0    stevel 			p = manp->secv + entries;
    873     0    stevel 		}
    874     0    stevel 		/* release memory allocated by sortdir */
    875     0    stevel 		free(*dv);
    876     0    stevel 	}
    877     0    stevel 	*p = 0;
    878     0    stevel 	/* release memory allocated by sortdir */
    879     0    stevel 	free(dirv);
    880     0    stevel }
    881     0    stevel 
    882     0    stevel /*
    883     0    stevel  * Format man pages (build cat pages); if no
    884     0    stevel  * sections are specified, build all of them.
    885     0    stevel  * When building cat pages:
    886     0    stevel  *	catman() tries to build cat pages for locale specific
    887     0    stevel  *	man dirs first.  Then, catman() tries to build cat pages
    888     0    stevel  *	for the default man dir (for C locale like /usr/share/man)
    889     0    stevel  *	regardless of the locale.
    890     0    stevel  * When building windex file:
    891     0    stevel  *	catman() tries to build windex file for locale specific
    892     0    stevel  *	man dirs first.  Then, catman() tries to build windex file
    893     0    stevel  *	for the default man dir (for C locale like /usr/share/man)
    894     0    stevel  *	regardless of the locale.
    895     0    stevel  */
    896     0    stevel 
    897     0    stevel static void
    898     0    stevel catman(struct man_node *manp, char **argv, int argc)
    899     0    stevel {
    900     0    stevel 	char cmdbuf[BUFSIZ];
    901     0    stevel 	char **dv;
    902     0    stevel 	int changed;
    903     0    stevel 	struct man_node *p;
    904     0    stevel 	int ndirs = 0;
    905     0    stevel 	char *ldir;
    906     0    stevel 	int	i;
    907  6639      samf 	struct dupnode *dnp = NULL;
    908  6639      samf 	char   **realsecv;
    909  6639      samf 	char   *fakesecv[2] = { " catman ", NULL };
    910     0    stevel 
    911     0    stevel 	for (p = manp; p != NULL; p = p->next) {
    912  6639      samf 		/*
    913  6639      samf 		 * prevent catman from doing very heavy lifting multiple
    914  6639      samf 		 * times on some directory
    915  6639      samf 		 */
    916  6639      samf 		realsecv = p->secv;
    917  6639      samf 		p->secv = fakesecv;
    918  6639      samf 		if (dupcheck(p, &dnp) != 0) {
    919  6639      samf 			p->secv = realsecv;
    920  6639      samf 			continue;
    921  6639      samf 		}
    922  6639      samf 
    923     0    stevel /*
    924     0    stevel  * TRANSLATION_NOTE - message for catman -p
    925     0    stevel  * ex. mandir path = /usr/share/man
    926     0    stevel  */
    927     0    stevel 		if (debug)
    928     0    stevel 			(void) fprintf(stdout, gettext(
    929  8107        Pu 			    "\nmandir path = %s\n"), p->path);
    930     0    stevel 		ndirs = 0;
    931  6639      samf 
    932     0    stevel 		/*
    933     0    stevel 		 * Build cat pages
    934     0    stevel 		 * addlocale() allocates memory and returns it
    935     0    stevel 		 */
    936     0    stevel 		ldir = addlocale(p->path);
    937     0    stevel 		if (!whatonly) {
    938     0    stevel 			if (*localedir != '\0') {
    939     0    stevel 				if (defaultmandir)
    940     0    stevel 					defaultmandir = 0;
    941     0    stevel 				/* getdirs allocate memory for dv */
    942     0    stevel 				ndirs = getdirs(ldir, &dv, 1);
    943     0    stevel 				if (ndirs != 0) {
    944     0    stevel 					changed = argc ?
    945  8107        Pu 					    makecat(ldir, argv, argc) :
    946  8107        Pu 					    makecat(ldir, dv, ndirs);
    947     0    stevel 					/* release memory by getdirs */
    948     0    stevel 					for (i = 0; i < ndirs; i++) {
    949     0    stevel 						free(dv[i]);
    950     0    stevel 					}
    951     0    stevel 					free(dv);
    952     0    stevel 				}
    953     0    stevel 			}
    954     0    stevel 
    955     0    stevel 			/* default man dir is always processed */
    956     0    stevel 			defaultmandir = 1;
    957     0    stevel 			ndirs = getdirs(p->path, &dv, 1);
    958     0    stevel 			changed = argc ?
    959  8107        Pu 			    makecat(p->path, argv, argc) :
    960  8107        Pu 			    makecat(p->path, dv, ndirs);
    961     0    stevel 			/* release memory allocated by getdirs */
    962     0    stevel 			for (i = 0; i < ndirs; i++) {
    963     0    stevel 				free(dv[i]);
    964     0    stevel 			}
    965     0    stevel 			free(dv);
    966     0    stevel 		}
    967     0    stevel 		/*
    968     0    stevel 		 * Build whatis database
    969     0    stevel 		 *  print error message if locale is set and man dir not found
    970     0    stevel 		 *  won't build it at all if -c option is on
    971     0    stevel 		 */
    972     0    stevel 		if (!compargs && (whatonly || (!nowhatis && changed))) {
    973     0    stevel 			if (*localedir != '\0') {
    974     0    stevel 				/* just count the number of ndirs */
    975     0    stevel 				if ((ndirs = getdirs(ldir, NULL, 0)) != 0) {
    976     0    stevel 					(void) sprintf(cmdbuf,
    977  8107        Pu 					    "/usr/bin/sh %s %s",
    978  8107        Pu 					    MAKEWHATIS, ldir);
    979     0    stevel 					(void) sys(cmdbuf);
    980     0    stevel 				}
    981     0    stevel 			}
    982     0    stevel 			/* whatis database of the default man dir */
    983     0    stevel 			/* will be always built in C locale. */
    984     0    stevel 			(void) sprintf(cmdbuf,
    985  8107        Pu 			    "/usr/bin/sh %s %s",
    986  8107        Pu 			    MAKEWHATIS, p->path);
    987     0    stevel 			(void) sys(cmdbuf);
    988     0    stevel 		}
    989     0    stevel 		/* release memory allocated by addlocale() */
    990     0    stevel 		free(ldir);
    991     0    stevel 	}
    992  6639      samf 	free_dupnode(dnp);
    993     0    stevel }
    994     0    stevel 
    995     0    stevel /*
    996     0    stevel  * Build cat pages for given sections
    997     0    stevel  */
    998     0    stevel 
    999     0    stevel static int
   1000     0    stevel makecat(char *path, char **dv, int ndirs)
   1001     0    stevel {
   1002     0    stevel 	DIR *dp, *sdp;
   1003     0    stevel 	struct dirent *d;
   1004     0    stevel 	struct stat sbuf;
   1005     0    stevel 	char mandir[MAXPATHLEN+1];
   1006     0    stevel 	char smandir[MAXPATHLEN+1];
   1007     0    stevel 	char catdir[MAXPATHLEN+1];
   1008     0    stevel 	char *dirp, *sdirp;
   1009     0    stevel 	int i, fmt;
   1010     0    stevel 	int manflag, smanflag;
   1011     0    stevel 
   1012     0    stevel 	for (i = fmt = 0; i < ndirs; i++) {
   1013     0    stevel 		(void) snprintf(mandir, MAXPATHLEN, "%s/%s%s",
   1014  8107        Pu 		    path, MANDIRNAME, dv[i]);
   1015     0    stevel 		(void) snprintf(smandir, MAXPATHLEN, "%s/%s%s",
   1016  8107        Pu 		    path, SGMLDIR, dv[i]);
   1017     0    stevel 		(void) snprintf(catdir, MAXPATHLEN, "%s/%s%s",
   1018  8107        Pu 		    path, subdirs[1], dv[i]);
   1019     0    stevel 		dirp = strrchr(mandir, '/') + 1;
   1020     0    stevel 		sdirp = strrchr(smandir, '/') + 1;
   1021     0    stevel 
   1022     0    stevel 		manflag = smanflag = 0;
   1023     0    stevel 
   1024     0    stevel 		if ((dp = opendir(mandir)) != NULL)
   1025     0    stevel 			manflag = 1;
   1026     0    stevel 
   1027     0    stevel 		if (!no_sroff && (sdp = opendir(smandir)) != NULL)
   1028     0    stevel 			smanflag = 1;
   1029     0    stevel 
   1030     0    stevel 		if (dp == 0 && sdp == 0) {
   1031     0    stevel 			if (strcmp(mandir, CONFIG) == 0)
   1032     0    stevel 				perror(mandir);
   1033     0    stevel 			continue;
   1034     0    stevel 		}
   1035     0    stevel /*
   1036     0    stevel  * TRANSLATION_NOTE - message for catman -p
   1037     0    stevel  * ex. Building cat pages for mandir = /usr/share/man/ja
   1038     0    stevel  */
   1039     0    stevel 		if (debug)
   1040     0    stevel 			(void) fprintf(stdout, gettext(
   1041     0    stevel 			    "Building cat pages for mandir = %s\n"), path);
   1042     0    stevel 
   1043     0    stevel 		if (!compargs && stat(catdir, &sbuf) < 0) {
   1044     0    stevel 			(void) umask(02);
   1045     0    stevel /*
   1046     0    stevel  * TRANSLATION_NOTE - message for catman -p
   1047     0    stevel  * ex. mkdir /usr/share/man/ja/cat3c
   1048     0    stevel  */
   1049     0    stevel 			if (debug)
   1050     0    stevel 				(void) fprintf(stdout, gettext("mkdir %s\n"),
   1051  8107        Pu 				    catdir);
   1052     0    stevel 			else {
   1053     0    stevel 				if (mkdir(catdir, 0755) < 0) {
   1054     0    stevel 					perror(catdir);
   1055     0    stevel 					continue;
   1056     0    stevel 				}
   1057     0    stevel 				(void) chmod(catdir, 0755);
   1058     0    stevel 			}
   1059     0    stevel 		}
   1060     0    stevel 
   1061     0    stevel 		/*
   1062     0    stevel 		 * if it is -c option of catman, if there is no
   1063     0    stevel 		 * coresponding man dir for sman files to go to,
   1064     0    stevel 		 * make the man dir
   1065     0    stevel 		 */
   1066     0    stevel 
   1067     0    stevel 		if (compargs && !manflag) {
   1068     0    stevel 			if (mkdir(mandir, 0755) < 0) {
   1069     0    stevel 				perror(mandir);
   1070     0    stevel 				continue;
   1071     0    stevel 			}
   1072     0    stevel 			(void) chmod(mandir, 0755);
   1073     0    stevel 		}
   1074     0    stevel 
   1075     0    stevel 		if (smanflag) {
   1076     0    stevel 			while ((d = readdir(sdp))) {
   1077     0    stevel 				if (eq(".", d->d_name) || eq("..", d->d_name))
   1078     0    stevel 					continue;
   1079     0    stevel 
   1080     0    stevel 				if (format(path, sdirp, (char *)0, d->d_name)
   1081  8107        Pu 				    > 0)
   1082     0    stevel 					fmt++;
   1083     0    stevel 			}
   1084     0    stevel 		}
   1085     0    stevel 
   1086     0    stevel 		if (manflag && !compargs) {
   1087     0    stevel 			while ((d = readdir(dp))) {
   1088     0    stevel 				if (eq(".", d->d_name) || eq("..", d->d_name))
   1089     0    stevel 					continue;
   1090     0    stevel 
   1091     0    stevel 				if (format(path, dirp, (char *)0, d->d_name)
   1092  8107        Pu 				    > 0)
   1093     0    stevel 					fmt++;
   1094     0    stevel 			}
   1095     0    stevel 		}
   1096     0    stevel 
   1097     0    stevel 		if (manflag)
   1098     0    stevel 			(void) closedir(dp);
   1099     0    stevel 
   1100     0    stevel 		if (smanflag)
   1101     0    stevel 			(void) closedir(sdp);
   1102     0    stevel 
   1103     0    stevel 	}
   1104     0    stevel 	return (fmt);
   1105     0    stevel }
   1106     0    stevel 
   1107     0    stevel 
   1108     0    stevel /*
   1109     0    stevel  * Get all "man" and "sman" dirs under a given manpath
   1110     0    stevel  * and return the number found
   1111     0    stevel  * If -c option is on, only count sman dirs
   1112     0    stevel  */
   1113     0    stevel 
   1114     0    stevel static int
   1115     0    stevel getdirs(char *path, char ***dirv, short flag)
   1116     0    stevel {
   1117     0    stevel 	DIR *dp;
   1118     0    stevel 	struct dirent *d;
   1119     0    stevel 	int n = 0;
   1120     0    stevel 	int plen, sgml_flag, man_flag;
   1121     0    stevel 	int i = 0;
   1122     0    stevel 	int	maxentries = MAXDIRS;
   1123     0    stevel 	char	**dv;
   1124     0    stevel 
   1125     0    stevel 	if ((dp = opendir(path)) == 0) {
   1126     0    stevel 		if (debug) {
   1127     0    stevel 			if (*localedir != '\0')
   1128     0    stevel 				(void) printf(gettext("\
   1129     0    stevel locale is %s, search in %s\n"), localedir, path);
   1130     0    stevel 			perror(path);
   1131     0    stevel 		}
   1132     0    stevel 		return (0);
   1133     0    stevel 	}
   1134     0    stevel 
   1135     0    stevel 	if (flag) {
   1136     0    stevel 		/* allocate memory for dirv */
   1137     0    stevel 		*dirv = (char **)malloc(sizeof (char *) *
   1138  8107        Pu 		    maxentries);
   1139     0    stevel 		if (*dirv == NULL)
   1140     0    stevel 			malloc_error();
   1141     0    stevel 		dv = *dirv;
   1142     0    stevel 	}
   1143     0    stevel 	while ((d = readdir(dp))) {
   1144     0    stevel 		plen = PLEN;
   1145     0    stevel 		man_flag = sgml_flag = 0;
   1146     0    stevel 		if (match(d->d_name, SGMLDIR, PLEN+1)) {
   1147     0    stevel 			plen = PLEN + 1;
   1148     0    stevel 			sgml_flag = 1;
   1149     0    stevel 			i++;
   1150     0    stevel 		}
   1151     0    stevel 
   1152     0    stevel 		if (match(subdirs[0], d->d_name, PLEN))
   1153     0    stevel 			man_flag = 1;
   1154     0    stevel 
   1155     0    stevel 		if (compargs && sgml_flag) {
   1156     0    stevel 			if (flag) {
   1157     0    stevel 				*dv = strdup(d->d_name+plen);
   1158     0    stevel 				if (*dv == NULL)
   1159     0    stevel 					malloc_error();
   1160     0    stevel 				dv++;
   1161     0    stevel 				n = i;
   1162     0    stevel 			}
   1163     0    stevel 		} else if (!compargs && (sgml_flag || man_flag)) {
   1164     0    stevel 			if (flag) {
   1165     0    stevel 				*dv = strdup(d->d_name+plen);
   1166     0    stevel 				if (*dv == NULL)
   1167     0    stevel 					malloc_error();
   1168     0    stevel 				dv++;
   1169     0    stevel 			}
   1170     0    stevel 			n++;
   1171     0    stevel 		}
   1172     0    stevel 		if (flag) {
   1173     0    stevel 			if ((dv - *dirv) == maxentries) {
   1174     0    stevel 				int entries = maxentries;
   1175     0    stevel 				maxentries += MAXTOKENS;
   1176     0    stevel 				*dirv = (char **)realloc(*dirv,
   1177  8107        Pu 				    sizeof (char *) * maxentries);
   1178     0    stevel 				if (*dirv == NULL)
   1179     0    stevel 					malloc_error();
   1180     0    stevel 				dv = *dirv + entries;
   1181     0    stevel 			}
   1182     0    stevel 		}
   1183     0    stevel 	}
   1184     0    stevel 
   1185     0    stevel 	(void) closedir(dp);
   1186     0    stevel 	return (n);
   1187     0    stevel }
   1188     0    stevel 
   1189     0    stevel 
   1190     0    stevel /*
   1191     0    stevel  * Find matching whatis or apropos entries
   1192     0    stevel  * whatapro() tries to handle the windex file of the locale specific
   1193     0    stevel  * man dirs first, then tries to handle the windex file of the default
   1194     0    stevel  * man dir (of C locale like /usr/share/man).
   1195     0    stevel  */
   1196     0    stevel 
   1197     0    stevel static void
   1198     0    stevel whatapro(struct man_node *manp, char *word, int apropos)
   1199     0    stevel {
   1200     0    stevel 	char whatpath[MAXPATHLEN+1];
   1201     0    stevel 	char *p;
   1202     0    stevel 	struct man_node *b;
   1203     0    stevel 	int ndirs = 0;
   1204     0    stevel 	char *ldir;
   1205     0    stevel 
   1206     0    stevel 
   1207     0    stevel /*
   1208     0    stevel  * TRANSLATION_NOTE - message for man -d
   1209     0    stevel  * %s takes a parameter to -k option.
   1210     0    stevel  */
   1211     0    stevel 	DPRINTF(gettext("word = %s \n"), word);
   1212     0    stevel 
   1213     0    stevel 	/*
   1214     0    stevel 	 * get base part of name
   1215     0    stevel 	 */
   1216     0    stevel 	if (!apropos) {
   1217     0    stevel 		if ((p = strrchr(word, '/')) == NULL)
   1218     0    stevel 			p = word;
   1219     0    stevel 		else
   1220     0    stevel 			p++;
   1221     0    stevel 	} else {
   1222     0    stevel 		p = word;
   1223     0    stevel 	}
   1224     0    stevel 
   1225     0    stevel 	for (b = manp; b != NULL; b = b->next) {
   1226     0    stevel 
   1227     0    stevel 		if (*localedir != '\0') {
   1228     0    stevel 			/* addlocale() allocates memory and returns it */
   1229     0    stevel 			ldir = addlocale(b->path);
   1230     0    stevel 			if (defaultmandir)
   1231     0    stevel 				defaultmandir = 0;
   1232     0    stevel 			ndirs = getdirs(ldir, NULL, 0);
   1233     0    stevel 			if (ndirs != 0) {
   1234     0    stevel 				(void) sprintf(whatpath, "%s/%s", ldir, WHATIS);
   1235     0    stevel /*
   1236     0    stevel  * TRANSLATION_NOTE - message for man -d
   1237     0    stevel  * ex. mandir path = /usr/share/man/ja
   1238     0    stevel  */
   1239     0    stevel 				DPRINTF(gettext("\nmandir path = %s\n"), ldir);
   1240  6639      samf 				lookup_windex(whatpath, p, b->secv);
   1241     0    stevel 			}
   1242     0    stevel 			/* release memory allocated by addlocale() */
   1243     0    stevel 			free(ldir);
   1244     0    stevel 		}
   1245     0    stevel 
   1246     0    stevel 		defaultmandir = 1;
   1247     0    stevel 		(void) sprintf(whatpath, "%s/%s", b->path, WHATIS);
   1248     0    stevel /*
   1249     0    stevel  * TRANSLATION_NOTE - message for man -d
   1250     0    stevel  * ex. mandir path = /usr/share/man
   1251     0    stevel  */
   1252     0    stevel 		DPRINTF(gettext("\nmandir path = %s\n"), b->path);
   1253     0    stevel 
   1254  6639      samf 		lookup_windex(whatpath, p, b->secv);
   1255     0    stevel 	}
   1256     0    stevel }
   1257     0    stevel 
   1258     0    stevel 
   1259     0    stevel static void
   1260  6639      samf lookup_windex(char *whatpath, char *word, char **secv)
   1261     0    stevel {
   1262     0    stevel 	FILE *fp;
   1263     0    stevel 	char *matches[MAXPAGES];
   1264     0    stevel 	char **pp;
   1265     0    stevel 	wchar_t	wbuf[BUFSIZ];
   1266     0    stevel 	wchar_t *word_wchar = NULL;
   1267     0    stevel 	wchar_t	*ws;
   1268     0    stevel 	size_t	word_len, ret;
   1269     0    stevel 
   1270     0    stevel 	if ((fp = fopen(whatpath, "r")) == NULL) {
   1271     0    stevel 		perror(whatpath);
   1272     0    stevel 		return;
   1273     0    stevel 	}
   1274     0    stevel 
   1275     0    stevel 	if (apropos) {
   1276     0    stevel 		word_len = strlen(word) + 1;
   1277     0    stevel 		if ((word_wchar = (wchar_t *)malloc(sizeof (wchar_t) *
   1278  8107        Pu 		    word_len)) == NULL) {
   1279     0    stevel 			malloc_error();
   1280     0    stevel 		}
   1281     0    stevel 		ret = mbstowcs(word_wchar, (const char *)word, word_len);
   1282     0    stevel 		if (ret == (size_t)-1) {
   1283     0    stevel 			(void) fprintf(stderr, gettext(
   1284  8107        Pu 			    "Invalid character in keyword\n"));
   1285     0    stevel 			exit(1);
   1286     0    stevel 		}
   1287     0    stevel 		while (fgetws(wbuf, BUFSIZ, fp) != NULL)
   1288     0    stevel 			for (ws = wbuf; *ws; ws++)
   1289     0    stevel 				if (icmp(word_wchar, ws) == 0) {
   1290     0    stevel 					(void) printf("%ws", wbuf);
   1291     0    stevel 					break;
   1292     0    stevel 				}
   1293     0    stevel 	} else {
   1294  6639      samf 		if (bfsearch(fp, matches, word, secv))
   1295     0    stevel 			for (pp = matches; *pp; pp++) {
   1296     0    stevel 				(void) printf("%s", *pp);
   1297     0    stevel 				/*
   1298     0    stevel 				 * release memory allocated by
   1299     0    stevel 				 * strdup() in bfsearch()
   1300     0    stevel 				 */
   1301     0    stevel 				free(*pp);
   1302     0    stevel 			}
   1303     0    stevel 	}
   1304     0    stevel 	(void) fclose(fp);
   1305     0    stevel 	if (word_wchar)
   1306     0    stevel 		free(word_wchar);
   1307     0    stevel 
   1308     0    stevel }
   1309     0    stevel 
   1310     0    stevel 
   1311     0    stevel /*
   1312     0    stevel  * case-insensitive compare unless upper case is used
   1313     0    stevel  * ie)	"mount" matches mount, Mount, MOUNT
   1314     0    stevel  *	"Mount" matches Mount, MOUNT
   1315     0    stevel  *	"MOUNT" matches MOUNT only
   1316     0    stevel  *	If matched return 0.  Otherwise, return 1.
   1317     0    stevel  */
   1318     0    stevel 
   1319     0    stevel static int
   1320     0    stevel icmp(wchar_t *ws, wchar_t *wt)
   1321     0    stevel {
   1322     0    stevel 	for (; (*ws == 0) ||
   1323  8107        Pu 	    (*ws == (iswupper(*ws) ? *wt: towlower(*wt)));
   1324  8107        Pu 	    ws++, wt++)
   1325     0    stevel 		if (*ws == 0)
   1326     0    stevel 			return (0);
   1327     0    stevel 
   1328     0    stevel 	return (1);
   1329     0    stevel }
   1330     0    stevel 
   1331     0    stevel 
   1332     0    stevel /*
   1333     0    stevel  * Invoke PAGER with all matching man pages
   1334     0    stevel  */
   1335     0    stevel 
   1336     0    stevel static void
   1337     0    stevel more(char **pages, int plain)
   1338     0    stevel {
   1339     0    stevel 	char cmdbuf[BUFSIZ];
   1340     0    stevel 	char **vp;
   1341     0    stevel 
   1342     0    stevel 	/*
   1343     0    stevel 	 * Dont bother.
   1344     0    stevel 	 */
   1345     0    stevel 	if (list || (*pages == 0))
   1346     0    stevel 		return;
   1347     0    stevel 
   1348     0    stevel 	if (plain && troffit) {
   1349     0    stevel 		cleanup(pages);
   1350     0    stevel 		return;
   1351     0    stevel 	}
   1352     0    stevel 	(void) sprintf(cmdbuf, "%s", troffit ? troffcat :
   1353     0    stevel 	    plain ? CAT : pager);
   1354     0    stevel 
   1355     0    stevel 	/*
   1356     0    stevel 	 * Build arg list
   1357     0    stevel 	 */
   1358     0    stevel 	for (vp = pages; vp < endp; vp++) {
   1359     0    stevel 		(void) strcat(cmdbuf, " ");
   1360     0    stevel 		(void) strcat(cmdbuf, *vp);
   1361     0    stevel 	}
   1362     0    stevel 	(void) sys(cmdbuf);
   1363     0    stevel 	cleanup(pages);
   1364     0    stevel }
   1365     0    stevel 
   1366     0    stevel 
   1367     0    stevel /*
   1368     0    stevel  * Get rid of dregs.
   1369     0    stevel  */
   1370     0    stevel 
   1371     0    stevel static void
   1372     0    stevel cleanup(char **pages)
   1373     0    stevel {
   1374     0    stevel 	char **vp;
   1375     0    stevel 
   1376     0    stevel 	for (vp = pages; vp < endp; vp++) {
   1377     0    stevel 		if (match(TEMPLATE, *vp, TMPLEN))
   1378     0    stevel 			(void) unlink(*vp);
   1379     0    stevel 		free(*vp);
   1380     0    stevel 	}
   1381     0    stevel 
   1382     0    stevel 	endp = pages;	/* reset */
   1383     0    stevel }
   1384     0    stevel 
   1385     0    stevel 
   1386     0    stevel /*
   1387     0    stevel  * Clean things up after receiving a signal.
   1388     0    stevel  */
   1389     0    stevel 
   1390     0    stevel /*ARGSUSED*/
   1391     0    stevel static void
   1392     0    stevel bye(int sig)
   1393     0    stevel {
   1394     0    stevel 	cleanup(pages);
   1395     0    stevel 	exit(1);
   1396     0    stevel 	/*NOTREACHED*/
   1397     0    stevel }
   1398     0    stevel 
   1399     0    stevel 
   1400     0    stevel /*
   1401     0    stevel  * Split a string by specified separator.
   1402     0    stevel  *    ignore empty components/adjacent separators.
   1403     0    stevel  *    returns vector to all tokens
   1404     0    stevel  */
   1405     0    stevel 
   1406     0    stevel static char **
   1407     0    stevel split(char *s1, char sep)
   1408     0    stevel {
   1409     0    stevel 	char **tokv, **vp;
   1410     0    stevel 	char *mp, *tp;
   1411     0    stevel 	int maxentries = MAXTOKENS;
   1412     0    stevel 	int entries = 0;
   1413     0    stevel 
   1414     0    stevel 	tokv = vp = (char **)malloc(maxentries * sizeof (char *));
   1415     0    stevel 	if (tokv == NULL)
   1416     0    stevel 		malloc_error();
   1417     0    stevel 	mp = s1;
   1418     0    stevel 	for (; mp && *mp; mp = tp) {
   1419     0    stevel 		tp = strchr(mp, sep);
   1420     0    stevel 		if (mp == tp) {		/* empty component */
   1421     0    stevel 			tp++;			/* ignore */
   1422     0    stevel 			continue;
   1423     0    stevel 		}
   1424     0    stevel 		if (tp) {
   1425     0    stevel 			/* a component found */
   1426     0    stevel 			size_t	len;
   1427     0    stevel 
   1428     0    stevel 			len = tp - mp;
   1429     0    stevel 			*vp = (char *)malloc(sizeof (char) * len + 1);
   1430     0    stevel 			if (*vp == NULL)
   1431     0    stevel 				malloc_error();
   1432     0    stevel 			(void) strncpy(*vp, mp, len);
   1433     0    stevel 			*(*vp + len) = '\0';
   1434     0    stevel 			tp++;
   1435     0    stevel 			vp++;
   1436     0    stevel 		} else {
   1437     0    stevel 			/* the last component */
   1438     0    stevel 			*vp = strdup(mp);
   1439     0    stevel 			if (*vp == NULL)
   1440     0    stevel 				malloc_error();
   1441     0    stevel 			vp++;
   1442     0    stevel 		}
   1443     0    stevel 		entries++;
   1444     0    stevel 		if (entries == maxentries) {
   1445     0    stevel 			maxentries += MAXTOKENS;
   1446     0    stevel 			tokv = (char **)realloc(tokv,
   1447  8107        Pu 			    maxentries * sizeof (char *));
   1448     0    stevel 			if (tokv == NULL)
   1449     0    stevel 				malloc_error();
   1450     0    stevel 			vp = tokv + entries;
   1451     0    stevel 		}
   1452     0    stevel 	}
   1453     0    stevel 	*vp = 0;
   1454     0    stevel 	return (tokv);
   1455     0    stevel }
   1456     0    stevel 
   1457  6639      samf /*
   1458  6639      samf  * Free a vector allocated by split();
   1459  6639      samf  */
   1460  6639      samf static void
   1461  7172      samf freev(char **v)
   1462  7172      samf {
   1463  6639      samf 	int i;
   1464  6639      samf 	for (i = 0; v[i] != NULL; i++) {
   1465  6639      samf 		free(v[i]);
   1466  6639      samf 	}
   1467  6639      samf 	free(v);
   1468  6639      samf }
   1469     0    stevel 
   1470     0    stevel /*
   1471     0    stevel  * Convert paths to full paths if necessary
   1472     0    stevel  *
   1473     0    stevel  */
   1474     0    stevel 
   1475     0    stevel static void
   1476  4466  dk208809 fullpaths(struct man_node **manp_head)
   1477     0    stevel {
   1478  4466  dk208809 	char *cwd = NULL;
   1479     0    stevel 	char *p;
   1480  4466  dk208809 	char cwd_gotten = 0;
   1481  4466  dk208809 	struct man_node *manp = *manp_head;
   1482     0    stevel 	struct man_node *b;
   1483  4466  dk208809 	struct man_node *prev = NULL;
   1484     0    stevel 
   1485     0    stevel 	for (b = manp; b != NULL; b = b->next) {
   1486  4466  dk208809 		if (*(b->path) == '/') {
   1487  4466  dk208809 			prev = b;
   1488     0    stevel 			continue;
   1489     0    stevel 		}
   1490  4466  dk208809 
   1491  4466  dk208809 		/* try to get cwd if haven't already */
   1492  4466  dk208809 		if (!cwd_gotten) {
   1493  4466  dk208809 			cwd = getcwd(NULL, MAXPATHLEN+1);
   1494  4466  dk208809 			cwd_gotten = 1;
   1495  4466  dk208809 		}
   1496  4466  dk208809 
   1497  4466  dk208809 		if (cwd) {
   1498  4466  dk208809 			/* case: relative manpath with cwd: make absolute */
   1499  4466  dk208809 			if ((p = malloc(strlen(b->path)+strlen(cwd)+2)) ==
   1500  4466  dk208809 			    NULL) {
   1501  4466  dk208809 				malloc_error();
   1502  4466  dk208809 			}
   1503  4466  dk208809 			(void) sprintf(p, "%s/%s", cwd, b->path);
   1504  4466  dk208809 			/*
   1505  4466  dk208809 			 * resetting b->path
   1506  4466  dk208809 			 */
   1507  4466  dk208809 			free(b->path);
   1508  4466  dk208809 			b->path = p;
   1509  4466  dk208809 		} else {
   1510  4466  dk208809 			/* case: relative manpath but no cwd: omit path entry */
   1511  4466  dk208809 			if (prev)
   1512  4466  dk208809 				prev->next = b->next;
   1513  4466  dk208809 			else
   1514  4466  dk208809 				*manp_head = b->next;
   1515  4466  dk208809 
   1516  4466  dk208809 			free_manp(b);
   1517  4466  dk208809 		}
   1518     0    stevel 	}
   1519     0    stevel 	/*
   1520     0    stevel 	 * release memory allocated by getcwd()
   1521     0    stevel 	 */
   1522     0    stevel 	free(cwd);
   1523  4466  dk208809 }
   1524  4466  dk208809 
   1525  4466  dk208809 /*
   1526  4466  dk208809  * Free a man_node structure and its contents
   1527  4466  dk208809  */
   1528  4466  dk208809 
   1529  4466  dk208809 static void
   1530  4466  dk208809 free_manp(struct man_node *manp)
   1531  4466  dk208809 {
   1532  4466  dk208809 	char **p;
   1533  4466  dk208809 
   1534  4466  dk208809 	free(manp->path);
   1535  4466  dk208809 	p = manp->secv;
   1536  4466  dk208809 	while ((p != NULL) && (*p != NULL)) {
   1537  4466  dk208809 		free(*p);
   1538  4466  dk208809 		p++;
   1539  4466  dk208809 	}
   1540  4466  dk208809 	free(manp->secv);
   1541  4466  dk208809 	free(manp);
   1542     0    stevel }
   1543     0    stevel 
   1544     0    stevel 
   1545     0    stevel /*
   1546     0    stevel  * Map (in place) to lower case
   1547     0    stevel  */
   1548     0    stevel 
   1549     0    stevel static void
   1550     0    stevel lower(char *s)
   1551     0    stevel {
   1552     0    stevel 	if (s == 0)
   1553     0    stevel 		return;
   1554     0    stevel 	while (*s) {
   1555     0    stevel 		if (isupper(*s))
   1556     0    stevel 			*s = tolower(*s);
   1557     0    stevel 		s++;
   1558     0    stevel 	}
   1559     0    stevel }
   1560     0    stevel 
   1561     0    stevel 
   1562     0    stevel /*
   1563     0    stevel  * compare for sort()
   1564     0    stevel  * sort first by section-spec, then by prefix {sman, man, cat, fmt}
   1565     0    stevel  *	note: prefix is reverse sorted so that "sman" and "man" always
   1566     0    stevel  * 	comes before {cat, fmt}
   1567     0    stevel  */
   1568     0    stevel 
   1569     0    stevel static int
   1570     0    stevel cmp(const void *arg1, const void *arg2)
   1571     0    stevel {
   1572     0    stevel 	int n;
   1573     0    stevel 	char **p1 = (char **)arg1;
   1574     0    stevel 	char **p2 = (char **)arg2;
   1575     0    stevel 
   1576     0    stevel 
   1577     0    stevel 	/* by section; sman always before man dirs */
   1578     0    stevel 	if ((n = strcmp(*p1 + PLEN + (**p1 == 's' ? 1 : 0),
   1579  8107        Pu 	    *p2 + PLEN + (**p2 == 's' ? 1 : 0))))
   1580     0    stevel 		return (n);
   1581     0    stevel 
   1582     0    stevel 	/* by prefix reversed */
   1583     0    stevel 	return (strncmp(*p2, *p1, PLEN));
   1584     0    stevel }
   1585     0    stevel 
   1586     0    stevel 
   1587     0    stevel /*
   1588     0    stevel  * Find a man page ...
   1589     0    stevel  *   Loop through each path specified,
   1590     0    stevel  *   first try the lookup method (whatis database),
   1591     0    stevel  *   and if it doesn't exist, do the hard way.
   1592     0    stevel  */
   1593     0    stevel 
   1594     0    stevel static void
   1595     0    stevel manual(struct man_node *manp, char *name)
   1596     0    stevel {
   1597     0    stevel 	struct man_node *p;
   1598  6639      samf 	struct man_node *local;
   1599     0    stevel 	int ndirs = 0;
   1600     0    stevel 	char *ldir;
   1601     0    stevel 	char *ldirs[2];
   1602  6639      samf 	char *fullname = name;
   1603  6639      samf 	char *slash;
   1604  6639      samf 
   1605  6639      samf 	if ((slash = strrchr(name, '/')) != NULL) {
   1606  6639      samf 		name = slash + 1;
   1607  6639      samf 	}
   1608     0    stevel 
   1609     0    stevel 	/*
   1610     0    stevel 	 *  for each path in MANPATH
   1611     0    stevel 	 */
   1612     0    stevel 	found = 0;
   1613     0    stevel 
   1614     0    stevel 	for (p = manp; p != NULL; p = p->next) {
   1615     0    stevel /*
   1616     0    stevel  * TRANSLATION_NOTE - message for man -d
   1617     0    stevel  * ex. mandir path = /usr/share/man
   1618     0    stevel  */
   1619     0    stevel 		DPRINTF(gettext("\nmandir path = %s\n"), p->path);
   1620     0    stevel 
   1621     0    stevel 		if (*localedir != '\0') {
   1622     0    stevel 			/* addlocale() allocates memory and returns it */
   1623     0    stevel 			ldir = addlocale(p->path);
   1624     0    stevel 			if (defaultmandir)
   1625     0    stevel 				defaultmandir = 0;
   1626     0    stevel /*
   1627     0    stevel  * TRANSLATION_NOTE - message for man -d
   1628     0    stevel  * ex. localedir = ja, ldir = /usr/share/man/ja
   1629     0    stevel  */
   1630     0    stevel 			if (debug)
   1631  7172      samf 				(void) printf(gettext(
   1632  8107        Pu 				    "localedir = %s, ldir = %s\n"),
   1633  8107        Pu 				    localedir, ldir);
   1634     0    stevel 			ndirs = getdirs(ldir, NULL, 0);
   1635     0    stevel 			if (ndirs != 0) {
   1636     0    stevel 				ldirs[0] = ldir;
   1637     0    stevel 				ldirs[1] = NULL;
   1638  6639      samf 				local = build_manpath(ldirs, 0);
   1639     0    stevel 				if (force ||
   1640     0    stevel 				    windex(local->secv, ldir, name) < 0)
   1641     0    stevel 					mandir(local->secv, ldir, name);
   1642  6639      samf 				free_manp(local);
   1643     0    stevel 			}
   1644     0    stevel 			/* release memory allocated by addlocale() */
   1645     0    stevel 			free(ldir);
   1646     0    stevel 		}
   1647     0    stevel 
   1648     0    stevel 		defaultmandir = 1;
   1649     0    stevel 		/*
   1650     0    stevel 		 * locale mandir not valid, man page in locale
   1651     0    stevel 		 * mandir not found, or -a option present
   1652     0    stevel 		 */
   1653     0    stevel 		if (ndirs == 0 || !found || all) {
   1654     0    stevel 			if (force || windex(p->secv, p->path, name) < 0)
   1655     0    stevel 				mandir(p->secv, p->path, name);
   1656     0    stevel 		}
   1657     0    stevel 
   1658     0    stevel 		if (found && !all)
   1659     0    stevel 			break;
   1660     0    stevel 	}
   1661     0    stevel 
   1662     0    stevel 	if (found) {
   1663     0    stevel 		more(pages, nomore);
   1664     0    stevel 	} else {
   1665     0    stevel 		if (sargs) {
   1666     0    stevel 			(void) printf(gettext("No entry for %s in section(s) "
   1667  6639      samf 			    "%s of the manual.\n"), fullname, mansec);
   1668     0    stevel 		} else {
   1669     0    stevel 			(void) printf(gettext(
   1670  6639      samf 			    "No manual entry for %s.\n"), fullname, mansec);
   1671     0    stevel 		}
   1672     0    stevel 
   1673     0    stevel 		if (sman_no_man_no_sroff)
   1674     0    stevel 			(void) printf(gettext("(An SGML manpage was found "
   1675     0    stevel 			    "for '%s' but it cannot be displayed.)\n"),
   1676  6639      samf 			    fullname, mansec);
   1677     0    stevel 	}
   1678     0    stevel 	sman_no_man_no_sroff = 0;
   1679     0    stevel }
   1680     0    stevel 
   1681     0    stevel 
   1682     0    stevel /*
   1683     0    stevel  * For a specified manual directory,
   1684     0    stevel  *	read, store, & sort section subdirs,
   1685     0    stevel  *	for each section specified
   1686     0    stevel  *		find and search matching subdirs
   1687     0    stevel  */
   1688     0    stevel 
   1689     0    stevel static void
   1690     0    stevel mandir(char **secv, char *path, char *name)
   1691     0    stevel {
   1692     0    stevel 	DIR *dp;
   1693     0    stevel 	char **dirv;
   1694     0    stevel 	char **dv, **pdv;
   1695     0    stevel 	int len, dslen, plen = PLEN;
   1696     0    stevel 
   1697     0    stevel 	if ((dp = opendir(path)) == 0) {
   1698     0    stevel /*
   1699     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1700     0    stevel  * opendir(%s) returned 0
   1701     0    stevel  */
   1702     0    stevel 		if (debug)
   1703     0    stevel 			(void) fprintf(stdout, gettext(
   1704  8107        Pu 			    " opendir on %s failed\n"), path);
   1705     0    stevel 		return;
   1706     0    stevel 	}
   1707     0    stevel 
   1708     0    stevel /*
   1709     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1710     0    stevel  * ex. mandir path = /usr/share/man/ja
   1711     0    stevel  */
   1712     0    stevel 	if (debug)
   1713     0    stevel 		(void) printf(gettext("mandir path = %s\n"), path);
   1714     0    stevel 
   1715     0    stevel 	/*
   1716     0    stevel 	 * sordir() allocates memory for dirv and dirv[].
   1717     0    stevel 	 */
   1718     0    stevel 	sortdir(dp, &dirv);
   1719     0    stevel 	/*
   1720     0    stevel 	 * Search in the order specified by MANSECTS
   1721     0    stevel 	 */
   1722     0    stevel 	for (; *secv; secv++) {
   1723     0    stevel /*
   1724     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1725     0    stevel  * ex.  section = 3c
   1726     0    stevel  */
   1727     0    stevel 		DPRINTF(gettext("  section = %s\n"), *secv);
   1728     0    stevel 		len = strlen(*secv);
   1729     0    stevel 		for (dv = dirv; *dv; dv++) {
   1730     0    stevel 			plen = PLEN;
   1731     0    stevel 			if (*dv[0] == 's')
   1732     0    stevel 				plen++;
   1733     0    stevel 			dslen = strlen(*dv+plen);
   1734     0    stevel 			if (dslen > len)
   1735     0    stevel 				len = dslen;
   1736     0    stevel 			if (**secv == '\\') {
   1737     0    stevel 				if (!eq(*secv + 1, *dv+plen))
   1738     0    stevel 					continue;
   1739     0    stevel 			} else if (!match(*secv, *dv+plen, len)) {
   1740     0    stevel 				/* check to see if directory name changed */
   1741     0    stevel 				if (!all &&
   1742     0    stevel 				    (newsection = map_section(*secv, path))
   1743     0    stevel 				    == NULL) {
   1744     0    stevel 					continue;
   1745     0    stevel 				}
   1746     0    stevel 				if (newsection == NULL)
   1747     0    stevel 					newsection = "";
   1748     0    stevel 				if (!match(newsection, *dv+plen, len)) {
   1749     0    stevel 					continue;
   1750     0    stevel 				}
   1751     0    stevel 			}
   1752     0    stevel 
   1753     0    stevel 			if (searchdir(path, *dv, name) == 0)
   1754     0    stevel 				continue;
   1755     0    stevel 
   1756     0    stevel 			if (!all) {
   1757     0    stevel 				/* release memory allocated by sortdir() */
   1758     0    stevel 				pdv = dirv;
   1759     0    stevel 				while (*pdv) {
   1760     0    stevel 					free(*pdv);
   1761     0    stevel 					pdv++;
   1762     0    stevel 				}
   1763     0    stevel 				(void) closedir(dp);
   1764     0    stevel 				/* release memory allocated by sortdir() */
   1765     0    stevel 				free(dirv);
   1766     0    stevel 				return;
   1767     0    stevel 			}
   1768     0    stevel 			/*
   1769     0    stevel 			 * if we found a match in the man dir skip
   1770     0    stevel 			 * the corresponding cat dir if it exists
   1771     0    stevel 			 */
   1772     0    stevel 			if (all && **dv == 'm' && *(dv+1) &&
   1773  8107        Pu 			    eq(*(dv+1)+plen, *dv+plen))
   1774     0    stevel 					dv++;
   1775     0    stevel 		}
   1776     0    stevel 	}
   1777     0    stevel 	/* release memory allocated by sortdir() */
   1778     0    stevel 	pdv = dirv;
   1779     0    stevel 	while (*pdv) {
   1780     0    stevel 		free(*pdv);
   1781     0    stevel 		pdv++;
   1782     0    stevel 	}
   1783     0    stevel 	free(dirv);
   1784     0    stevel 	(void) closedir(dp);
   1785     0    stevel }
   1786     0    stevel 
   1787     0    stevel /*
   1788     0    stevel  * Sort directories.
   1789     0    stevel  */
   1790     0    stevel 
   1791     0    stevel static void
   1792     0    stevel sortdir(DIR *dp, char ***dirv)
   1793     0    stevel {
   1794     0    stevel 	struct dirent *d;
   1795     0    stevel 	char **dv;
   1796     0    stevel 	int	maxentries = MAXDIRS;
   1797     0    stevel 	int	entries = 0;
   1798     0    stevel 
   1799     0    stevel 	*dirv = (char **)malloc(sizeof (char *) * maxentries);
   1800     0    stevel 	dv = *dirv;
   1801     0    stevel 	while ((d = readdir(dp))) {	/* store dirs */
   1802     0    stevel 		if (eq(d->d_name, ".") || eq(d->d_name, ".."))	/* ignore */
   1803     0    stevel 			continue;
   1804     0    stevel 
   1805     0    stevel 		/* check if it matches sman, man, cat format */
   1806     0    stevel 		if (match(d->d_name, SGMLDIR, PLEN+1) ||
   1807     0    stevel 		    match(d->d_name, subdirs[0], PLEN) ||
   1808     0    stevel 		    match(d->d_name, subdirs[1], PLEN)) {
   1809     0    stevel 			*dv = malloc(strlen(d->d_name) + 1);
   1810     0    stevel 			if (*dv == NULL)
   1811     0    stevel 				malloc_error();
   1812     0    stevel 			(void) strcpy(*dv, d->d_name);
   1813     0    stevel 			dv++;
   1814     0    stevel 			entries++;
   1815     0    stevel 			if (entries == maxentries) {
   1816     0    stevel 				maxentries += MAXDIRS;
   1817     0    stevel 				*dirv = (char **)realloc(*dirv,
   1818  8107        Pu 				    sizeof (char *) * maxentries);
   1819     0    stevel 				if (*dirv == NULL)
   1820     0    stevel 					malloc_error();
   1821     0    stevel 				dv = *dirv + entries;
   1822     0    stevel 			}
   1823     0    stevel 		}
   1824     0    stevel 	}
   1825     0    stevel 	*dv = 0;
   1826     0    stevel 
   1827     0    stevel 	qsort((void *)*dirv, dv - *dirv, sizeof (char *), cmp);
   1828     0    stevel 
   1829     0    stevel }
   1830     0    stevel 
   1831     0    stevel 
   1832     0    stevel /*
   1833     0    stevel  * Search a section subdirectory for a
   1834     0    stevel  * given man page, return 1 for success
   1835     0    stevel  */
   1836     0    stevel 
   1837     0    stevel static int
   1838     0    stevel searchdir(char *path, char *dir, char *name)
   1839     0    stevel {
   1840     0    stevel 	DIR *sdp;
   1841     0    stevel 	struct dirent *sd;
   1842     0    stevel 	char sectpath[MAXPATHLEN+1];
   1843     0    stevel 	char file[MAXNAMLEN+1];
   1844     0    stevel 	char dname[MAXPATHLEN+1];
   1845     0    stevel 	char *last;
   1846     0    stevel 	int nlen;
   1847     0    stevel 
   1848     0    stevel /*
   1849     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1850     0    stevel  * ex.   scanning = man3c
   1851     0    stevel  */
   1852     0    stevel 	DPRINTF(gettext("    scanning = %s\n"), dir);
   1853     0    stevel 	(void) sprintf(sectpath, "%s/%s", path, dir);
   1854     0    stevel 	(void) snprintf(file, MAXPATHLEN, "%s.", name);
   1855     0    stevel 
   1856     0    stevel 	if ((sdp = opendir(sectpath)) == 0) {
   1857     0    stevel 		if (errno != ENOTDIR)	/* ignore matching cruft */
   1858     0    stevel 			perror(sectpath);
   1859     0    stevel 		return (0);
   1860     0    stevel 	}
   1861     0    stevel 	while ((sd = readdir(sdp))) {
   1862     0    stevel 		last = strrchr(sd->d_name, '.');
   1863     0    stevel 		nlen = last - sd->d_name;
   1864     0    stevel 		(void) sprintf(dname, "%.*s.", nlen, sd->d_name);
   1865     0    stevel 		if (eq(dname, file) || eq(sd->d_name, name)) {
   1866     0    stevel 			if (no_sroff && *dir == 's') {
   1867     0    stevel 				sman_no_man_no_sroff = 1;
   1868     0    stevel 				return (0);
   1869     0    stevel 			}
   1870     0    stevel 			(void) format(path, dir, name, sd->d_name);
   1871     0    stevel 			(void) closedir(sdp);
   1872     0    stevel 			return (1);
   1873     0    stevel 		}
   1874     0    stevel 	}
   1875     0    stevel 	(void) closedir(sdp);
   1876     0    stevel 	return (0);
   1877     0    stevel }
   1878     0    stevel 
   1879     0    stevel /*
   1880     0    stevel  * Check the hash table of old directory names to see if there is a
   1881     0    stevel  * new directory name.
   1882     0    stevel  * Returns new directory name if a match; after checking to be sure
   1883     0    stevel  * directory exists.
   1884     0    stevel  * Otherwise returns NULL
   1885     0    stevel  */
   1886     0    stevel 
   1887     0    stevel static char *
   1888     0    stevel map_section(char *section, char *path)
   1889     0    stevel {
   1890     0    stevel 	int i;
   1891     0    stevel 	int len;
   1892     0    stevel 	char fullpath[MAXPATHLEN];
   1893     0    stevel 
   1894     0    stevel 	if (list)  /* -l option fall through */
   1895     0    stevel 		return (NULL);
   1896     0    stevel 
   1897     0    stevel 	for (i = 0; i <= ((sizeof (map)/sizeof (map[0]) - 1)); i++) {
   1898     0    stevel 		if (strlen(section) > strlen(map[i].new_name)) {
   1899     0    stevel 			len = strlen(section);
   1900     0    stevel 		} else {
   1901     0    stevel 			len = strlen(map[i].new_name);
   1902     0    stevel 		}
   1903     0    stevel 		if (match(section, map[i].old_name, len)) {
   1904     0    stevel 			(void) sprintf(fullpath,
   1905     0    stevel 			    "%s/sman%s", path, map[i].new_name);
   1906     0    stevel 			if (!access(fullpath, R_OK | X_OK)) {
   1907     0    stevel 				return (map[i].new_name);
   1908     0    stevel 			} else {
   1909     0    stevel 				return (NULL);
   1910     0    stevel 			}
   1911     0    stevel 		}
   1912     0    stevel 	}
   1913     0    stevel 
   1914     0    stevel 	return (NULL);
   1915     0    stevel }
   1916     0    stevel 
   1917     0    stevel 
   1918     0    stevel /*
   1919     0    stevel  * Use windex database for quick lookup of man pages
   1920     0    stevel  * instead of mandir() (brute force search)
   1921     0    stevel  */
   1922     0    stevel 
   1923     0    stevel static int
   1924     0    stevel windex(char **secv, char *path, char *name)
   1925     0    stevel {
   1926     0    stevel 	FILE *fp;
   1927     0    stevel 	struct stat sbuf;
   1928     0    stevel 	struct suffix *sp;
   1929     0    stevel 	struct suffix	psecs[MAXPAGES];
   1930     0    stevel 	char whatfile[MAXPATHLEN+1];
   1931     0    stevel 	char page[MAXPATHLEN+1];
   1932     0    stevel 	char *matches[MAXPAGES];
   1933     0    stevel 	char *file, *dir;
   1934     0    stevel 	char **sv, **vp;
   1935     0    stevel 	int len, dslen, exist, i;
   1936     0    stevel 	int	found_in_windex = 0;
   1937     0    stevel 	char *tmp[] = {0, 0, 0, 0};
   1938     0    stevel 
   1939     0    stevel 
   1940     0    stevel 	(void) sprintf(whatfile, "%s/%s", path, WHATIS);
   1941     0    stevel 	if ((fp = fopen(whatfile, "r")) == NULL) {
   1942     0    stevel 		if (errno == ENOENT)
   1943     0    stevel 			return (-1);
   1944     0    stevel 		return (0);
   1945     0    stevel 	}
   1946     0    stevel 
   1947     0    stevel /*
   1948     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1949     0    stevel  * ex. search in = /usr/share/man/ja/windex file
   1950     0    stevel  */
   1951     0    stevel 	if (debug)
   1952     0    stevel 		(void) fprintf(stdout, gettext(
   1953  8107        Pu 		    " search in = %s file\n"), whatfile);
   1954     0    stevel 
   1955  6639      samf 	if (bfsearch(fp, matches, name, NULL) == 0) {
   1956     0    stevel 		(void) fclose(fp);
   1957     0    stevel 		return (-1); /* force search in mandir */
   1958     0    stevel 	}
   1959     0    stevel 
   1960     0    stevel 	(void) fclose(fp);
   1961     0    stevel 
   1962     0    stevel 	/*
   1963     0    stevel 	 * Save and split sections
   1964     0    stevel 	 * section() allocates memory for sp->ds
   1965     0    stevel 	 */
   1966     0    stevel 	for (sp = psecs, vp = matches; *vp; vp++, sp++)
   1967     0    stevel 		section(sp, *vp);
   1968     0    stevel 
   1969     0    stevel 	sp->ds = 0;
   1970     0    stevel 
   1971     0    stevel 	/*
   1972     0    stevel 	 * Search in the order specified
   1973     0    stevel 	 * by MANSECTS
   1974     0    stevel 	 */
   1975     0    stevel 	for (; *secv; secv++) {
   1976     0    stevel 		len = strlen(*secv);
   1977     0    stevel 
   1978     0    stevel /*
   1979     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   1980     0    stevel  * ex.  search an entry to match printf.3c
   1981     0    stevel  */
   1982     0    stevel 		if (debug)
   1983     0    stevel 			(void) fprintf(stdout, gettext(
   1984     0    stevel 			    "  search an entry to match %s.%s\n"), name, *secv);
   1985     0    stevel 		/*
   1986     0    stevel 		 * For every whatis entry that
   1987     0    stevel 		 * was matched
   1988     0    stevel 		 */
   1989     0    stevel 		for (sp = psecs; sp->ds; sp++) {
   1990     0    stevel 			dslen = strlen(sp->ds);
   1991     0    stevel 			if (dslen > len)
   1992     0    stevel 				len = dslen;
   1993     0    stevel 			if (**secv == '\\') {
   1994     0    stevel 				if (!eq(*secv + 1, sp->ds))
   1995     0    stevel 					continue;
   1996     0    stevel 			} else if (!match(*secv, sp->ds, len)) {
   1997     0    stevel 				/* check to see if directory name changed */
   1998     0    stevel 				if (!all &&
   1999     0    stevel 				    (newsection = map_section(*secv, path))
   2000     0    stevel 				    == NULL) {
   2001     0    stevel 					continue;
   2002     0    stevel 				}
   2003     0    stevel 				if (newsection == NULL)
   2004     0    stevel 					newsection = "";
   2005     0    stevel 				if (!match(newsection, sp->ds, len)) {
   2006     0    stevel 					continue;
   2007     0    stevel 				}
   2008     0    stevel 			}
   2009     0    stevel 			/*
   2010     0    stevel 			 * here to form "sman", "man", "cat"|"fmt" in
   2011     0    stevel 			 * order
   2012     0    stevel 			 */
   2013     0    stevel 			if (!no_sroff) {
   2014     0    stevel 				tmp[0] = SGMLDIR;
   2015     0    stevel 				for (i = 1; i < 4; i++)
   2016     0    stevel 					tmp[i] = subdirs[i-1];
   2017     0    stevel 			} else {
   2018     0    stevel 				for (i = 0; i < 3; i++)
   2019     0    stevel 					tmp[i] = subdirs[i];
   2020     0    stevel 			}
   2021     0    stevel 
   2022     0    stevel 			for (sv = tmp; *sv; sv++) {
   2023     0    stevel 				(void) sprintf(page,
   2024     0    stevel 				    "%s/%s%s/%s%s%s", path, *sv,
   2025     0    stevel 				    sp->ds, name, *sp->fs ? "." : "",
   2026     0    stevel 				    sp->fs);
   2027     0    stevel 				exist = (stat(page, &sbuf) == 0);
   2028     0    stevel 				if (exist)
   2029     0    stevel 					break;
   2030     0    stevel 			}
   2031     0    stevel 			if (!exist) {
   2032     0    stevel 				(void) fprintf(stderr, gettext(
   2033     0    stevel 				    "%s entry incorrect:  %s(%s) not found.\n"),
   2034     0    stevel 				    WHATIS, name, sp->ds);
   2035     0    stevel 				continue;
   2036     0    stevel 			}
   2037     0    stevel 
   2038     0    stevel 			file = strrchr(page, '/'), *file = 0;
   2039     0    stevel 			dir = strrchr(page, '/');
   2040     0    stevel 
   2041     0    stevel 			/*
   2042     0    stevel 			 * By now we have a match
   2043     0    stevel 			 */
   2044     0    stevel 			found_in_windex = 1;
   2045     0    stevel 			(void) format(path, ++dir, name, ++file);
   2046     0    stevel 
   2047     0    stevel 			if (!all)
   2048     0    stevel 				goto finish;
   2049     0    stevel 		}
   2050     0    stevel 	}
   2051     0    stevel finish:
   2052     0    stevel 	/*
   2053     0    stevel 	 * release memory allocated by section()
   2054     0    stevel 	 */
   2055     0    stevel 	sp = psecs;
   2056     0    stevel 	while (sp->ds) {
   2057     0    stevel 		free(sp->ds);
   2058     0    stevel 		sp->ds = NULL;
   2059     0    stevel 		sp++;
   2060     0    stevel 	}
   2061     0    stevel 
   2062     0    stevel 	/*
   2063     0    stevel 	 * If we didn't find a match, return failure as if we didn't find
   2064     0    stevel 	 * the windex at all. Why? Well, if you create a windex, then upgrade
   2065     0    stevel 	 * to a later release that contains new man pages, and forget to
   2066     0    stevel 	 * recreate the windex (since we don't do that automatically), you
   2067     0    stevel 	 * won't see any new man pages since they aren't in the windex.
   2068     0    stevel 	 * Pretending we didn't see a windex at all if there are no matches
   2069     0    stevel 	 * forces a search of the underlying directory. After all, the
   2070     0    stevel 	 * goal of the windex is to enable searches (man -k) and speed things
   2071     0    stevel 	 * up, not to _prevent_ you from seeing new man pages, so this seems
   2072     0    stevel 	 * ok. The only problem is when there are multiple entries (different
   2073     0    stevel 	 * sections), and some are in and some are out. Say you do 'man ls',
   2074     0    stevel 	 * and ls(1) isn't in the windex, but ls(1B) is. In that case, we
   2075     0    stevel 	 * will find a match in ls(1B), and you'll see that man page.
   2076     0    stevel 	 * That doesn't seem bad since if you specify the section the search
   2077     0    stevel 	 * will be restricted too. So in the example above, if you do
   2078     0    stevel 	 * 'man -s 1 ls' you'll get ls(1).
   2079     0    stevel 	 */
   2080     0    stevel 	if (found_in_windex)
   2081     0    stevel 		return (0);
   2082     0    stevel 	else
   2083     0    stevel 		return (-1);
   2084     0    stevel }
   2085     0    stevel 
   2086     0    stevel 
   2087     0    stevel /*
   2088     0    stevel  * Return pointers to the section-spec
   2089     0    stevel  * and file-suffix of a whatis entry
   2090     0    stevel  */
   2091     0    stevel 
   2092     0    stevel static void
   2093     0    stevel section(struct suffix *sp, char *s)
   2094     0    stevel {
   2095     0    stevel 	char *lp, *p;
   2096     0    stevel 
   2097     0    stevel 	lp = strchr(s, '(');
   2098     0    stevel 	p = strchr(s, ')');
   2099     0    stevel 
   2100     0    stevel 	if (++lp == 0 || p == 0 || lp == p) {
   2101     0    stevel 		(void) fprintf(stderr,
   2102     0    stevel 		    gettext("mangled windex entry:\n\t%s\n"), s);
   2103     0    stevel 		return;
   2104     0    stevel 	}
   2105     0    stevel 	*p = 0;
   2106     0    stevel 
   2107     0    stevel 	/*
   2108     0    stevel 	 * copy the string pointed to by lp
   2109     0    stevel 	 */
   2110     0    stevel 	lp = strdup(lp);
   2111     0    stevel 	if (lp == NULL)
   2112     0    stevel 		malloc_error();
   2113     0    stevel 	/*
   2114     0    stevel 	 * release memory in s
   2115     0    stevel 	 * s has been allocated memory in bfsearch()
   2116     0    stevel 	 */
   2117     0    stevel 	free(s);
   2118     0    stevel 
   2119     0    stevel 	lower(lp);
   2120     0    stevel 
   2121     0    stevel 	/*
   2122     0    stevel 	 * split section-specifier if file-name
   2123     0    stevel 	 * suffix differs from section-suffix
   2124     0    stevel 	 */
   2125     0    stevel 	sp->ds = lp;
   2126     0    stevel 	if ((p = strchr(lp, '/'))) {
   2127     0    stevel 		*p++ = 0;
   2128     0    stevel 		sp->fs = p;
   2129     0    stevel 	} else
   2130     0    stevel 		sp->fs = lp;
   2131     0    stevel }
   2132     0    stevel 
   2133     0    stevel 
   2134     0    stevel /*
   2135     0    stevel  * Binary file search to find matching man
   2136     0    stevel  *   pages in whatis database.
   2137     0    stevel  */
   2138     0    stevel 
   2139     0    stevel static int
   2140  6639      samf bfsearch(FILE *fp, char **matchv, char *key, char **secv)
   2141     0    stevel {
   2142     0    stevel 	char entry[BUFSIZ];
   2143     0    stevel 	char **vp;
   2144     0    stevel 	long top, bot, mid;
   2145     0    stevel 	int	c;
   2146     0    stevel 
   2147     0    stevel 	vp = matchv;
   2148     0    stevel 	bot = 0;
   2149     0    stevel 	(void) fseek(fp, 0L, 2);
   2150     0    stevel 	top = ftell(fp);
   2151     0    stevel 	for (;;) {
   2152     0    stevel 		mid = (top+bot)/2;
   2153     0    stevel 		(void) fseek(fp, mid, 0);
   2154     0    stevel 		do {
   2155     0    stevel 			c = getc(fp);
   2156     0    stevel 			mid++;
   2157     0    stevel 		} while (c != EOF && c != '\n');
   2158     0    stevel 		if (fgets(entry, sizeof (entry), fp) == NULL)
   2159     0    stevel 			break;
   2160  6639      samf 		switch (compare(key, entry, secv)) {
   2161     0    stevel 		case -2:
   2162     0    stevel 		case -1:
   2163     0    stevel 		case 0:
   2164     0    stevel 			if (top <= mid)
   2165     0    stevel 				break;
   2166     0    stevel 			top = mid;
   2167     0    stevel 			continue;
   2168     0    stevel 		case 1:
   2169     0    stevel 		case 2:
   2170     0    stevel 			bot = mid;
   2171     0    stevel 			continue;
   2172     0    stevel 		}
   2173     0    stevel 		break;
   2174     0    stevel 	}
   2175     0    stevel 	(void) fseek(fp, bot, 0);
   2176     0    stevel 	while (ftell(fp) < top) {
   2177     0    stevel 		if (fgets(entry, sizeof (entry), fp) == NULL) {
   2178     0    stevel 			*matchv = 0;
   2179     0    stevel 			return (matchv - vp);
   2180     0    stevel 		}
   2181  6639      samf 		switch (compare(key, entry, secv)) {
   2182     0    stevel 		case -2:
   2183     0    stevel 			*matchv = 0;
   2184     0    stevel 			return (matchv - vp);
   2185     0    stevel 		case -1:
   2186     0    stevel 		case 0:
   2187     0    stevel 			*matchv = strdup(entry);
   2188     0    stevel 			if (*matchv == NULL)
   2189     0    stevel 				malloc_error();
   2190     0    stevel 			else
   2191     0    stevel 				matchv++;
   2192     0    stevel 			break;
   2193     0    stevel 		case 1:
   2194     0    stevel 		case 2:
   2195     0    stevel 			continue;
   2196     0    stevel 		}
   2197     0    stevel 		break;
   2198     0    stevel 	}
   2199     0    stevel 	while (fgets(entry, sizeof (entry), fp)) {
   2200  6639      samf 		switch (compare(key, entry, secv)) {
   2201     0    stevel 		case -1:
   2202     0    stevel 		case 0:
   2203     0    stevel 			*matchv = strdup(entry);
   2204     0    stevel 			if (*matchv == NULL)
   2205     0    stevel 				malloc_error();
   2206     0    stevel 			else
   2207     0    stevel 				matchv++;
   2208     0    stevel 			continue;
   2209     0    stevel 		}
   2210     0    stevel 		break;
   2211     0    stevel 	}
   2212     0    stevel 	*matchv = 0;
   2213     0    stevel 	return (matchv - vp);
   2214     0    stevel }
   2215     0    stevel 
   2216     0    stevel static int
   2217  6639      samf compare(char *key, char *entry, char **secv)
   2218     0    stevel {
   2219     0    stevel 	char	*entbuf;
   2220     0    stevel 	char	*s;
   2221     0    stevel 	int	comp, mlen;
   2222     0    stevel 	int	mbcurmax = MB_CUR_MAX;
   2223  6639      samf 	char 	*secp = NULL;
   2224  6639      samf 	int	rv;
   2225  6639      samf 	int	eblen;
   2226     0    stevel 
   2227     0    stevel 	entbuf = strdup(entry);
   2228     0    stevel 	if (entbuf == NULL) {
   2229     0    stevel 		malloc_error();
   2230     0    stevel 	}
   2231  6639      samf 	eblen = strlen(entbuf);
   2232     0    stevel 
   2233     0    stevel 	s = entbuf;
   2234     0    stevel 	while (*s) {
   2235     0    stevel 		if (*s == '\t' || *s == ' ') {
   2236     0    stevel 			*s = '\0';
   2237     0    stevel 			break;
   2238     0    stevel 		}
   2239     0    stevel 		mlen = mblen(s, mbcurmax);
   2240     0    stevel 		if (mlen == -1) {
   2241     0    stevel 			(void) fprintf(stderr, gettext(
   2242  8107        Pu 			    "Invalid character in windex file.\n"));
   2243     0    stevel 			exit(1);
   2244     0    stevel 		}
   2245     0    stevel 		s += mlen;
   2246     0    stevel 	}
   2247  6639      samf 	/*
   2248  6639      samf 	 * Find the section within parantheses
   2249  6639      samf 	 */
   2250  6639      samf 	if (secv != NULL && (s - entbuf) < eblen) {
   2251  6639      samf 		if ((secp = strchr(s + 1, ')')) != NULL) {
   2252  6639      samf 			*secp = '\0';
   2253  6639      samf 			if ((secp = strchr(s + 1, '(')) != NULL) {
   2254  6639      samf 				secp++;
   2255  6639      samf 			}
   2256  6639      samf 		}
   2257  6639      samf 	}
   2258     0    stevel 
   2259     0    stevel 	comp = strcmp(key, entbuf);
   2260  6639      samf 	if (comp == 0) {
   2261  6639      samf 		if (secp == NULL) {
   2262  6639      samf 			rv = 0;
   2263  6639      samf 		} else {
   2264  6639      samf 			while (*secv != NULL) {
   2265  6639      samf 				if ((strcmp(*secv, secp)) == 0) {
   2266  6639      samf 					rv = 0;
   2267  6639      samf 					break;
   2268  6639      samf 				}
   2269  6639      samf 				secv++;
   2270  6639      samf 			}
   2271  6639      samf 		}
   2272  6639      samf 	} else if (comp < 0) {
   2273  6639      samf 		rv = -2;
   2274  6639      samf 	} else {
   2275  6639      samf 		rv = 2;
   2276  6639      samf 	}
   2277     0    stevel 	free(entbuf);
   2278  6639      samf 	return (rv);
   2279     0    stevel }
   2280     0    stevel 
   2281     0    stevel 
   2282     0    stevel /*
   2283     0    stevel  * Format a man page and follow .so references
   2284     0    stevel  * if necessary.
   2285     0    stevel  */
   2286     0    stevel 
   2287     0    stevel static int
   2288     0    stevel format(char *path, char *dir, char *name, char *pg)
   2289     0    stevel {
   2290     0    stevel 	char manpname[MAXPATHLEN+1], catpname[MAXPATHLEN+1];
   2291     0    stevel 	char manpname_sgml[MAXPATHLEN+1], smantmpname[MAXPATHLEN+1];
   2292     0    stevel 	char soed[MAXPATHLEN+1], soref[MAXPATHLEN+1];
   2293     0    stevel 	char manbuf[BUFSIZ], cmdbuf[BUFSIZ], tmpbuf[BUFSIZ];
   2294     0    stevel 	char tmpdir[MAXPATHLEN+1];
   2295     0    stevel 	int socount, updatedcat, regencat;
   2296     0    stevel 	struct stat mansb, catsb, smansb;
   2297     0    stevel 	char *tmpname;
   2298     0    stevel 	int catonly = 0;
   2299     0    stevel 	struct stat statb;
   2300     0    stevel 	int plen = PLEN;
   2301     0    stevel 	FILE *md;
   2302     0    stevel 	int tempfd;
   2303     0    stevel 	ssize_t	count;
   2304     0    stevel 	int	temp, sgml_flag = 0, check_flag = 0;
   2305     0    stevel 	char prntbuf[BUFSIZ + 1];
   2306     0    stevel 	char *ptr;
   2307     0    stevel 	char *new_m;
   2308     0    stevel 	char	*tmpsubdir;
   2309     0    stevel 
   2310     0    stevel 	found++;
   2311     0    stevel 
   2312     0    stevel 	if (*dir != 'm' && *dir != 's')
   2313     0    stevel 		catonly++;
   2314     0    stevel 
   2315     0    stevel 
   2316     0    stevel 	if (*dir == 's') {
   2317     0    stevel 		tmpsubdir = SGMLDIR;
   2318     0    stevel 		++plen;
   2319     0    stevel 		(void) sprintf(manpname_sgml, "%s/man%s/%s",
   2320  8107        Pu 		    path, dir+plen, pg);
   2321     0    stevel 	} else
   2322     0    stevel 		tmpsubdir = MANDIRNAME;
   2323     0    stevel 
   2324     0    stevel 	if (list) {
   2325     0    stevel 		(void) printf(gettext("%s (%s)\t-M %s\n"),
   2326     0    stevel 		    name, dir+plen, path);
   2327     0    stevel 		return (-1);
   2328     0    stevel 	}
   2329     0    stevel 
   2330     0    stevel 	(void) sprintf(manpname, "%s/%s%s/%s", path, tmpsubdir, dir+plen, pg);
   2331     0    stevel 	(void) sprintf(catpname, "%s/%s%s/%s", path, subdirs[1], dir+plen, pg);
   2332     0    stevel 
   2333     0    stevel 	(void) sprintf(smantmpname, "%s/%s%s/%s", path, SGMLDIR, dir+plen, pg);
   2334     0    stevel 
   2335     0    stevel /*
   2336     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2337     0    stevel  * ex.  unformatted = /usr/share/man/ja/man3s/printf.3s
   2338     0    stevel  */
   2339     0    stevel 	DPRINTF(gettext(
   2340  8107        Pu 	    "      unformatted = %s\n"), catonly ? "" : manpname);
   2341     0    stevel /*
   2342     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2343     0    stevel  * ex.  formatted = /usr/share/man/ja/cat3s/printf.3s
   2344     0    stevel  */
   2345     0    stevel 	DPRINTF(gettext(
   2346  8107        Pu 	    "      formatted = %s\n"), catpname);
   2347     0    stevel 
   2348     0    stevel 	/*
   2349     0    stevel 	 * Take care of indirect references to other man pages;
   2350     0    stevel 	 * i.e., resolve files containing only ".so manx/file.x".
   2351     0    stevel 	 * We follow .so chains, replacing title with the .so'ed
   2352     0    stevel 	 * file at each stage, and keeping track of how many times
   2353     0    stevel 	 * we've done so, so that we can avoid looping.
   2354     0    stevel 	 */
   2355     0    stevel 	*soed = 0;
   2356     0    stevel 	socount = 0;
   2357     0    stevel 	for (;;) {
   2358     0    stevel 		FILE *md;
   2359     0    stevel 		char *cp;
   2360     0    stevel 		char *s;
   2361     0    stevel 		char *new_s;
   2362     0    stevel 
   2363     0    stevel 		if (catonly)
   2364     0    stevel 			break;
   2365     0    stevel 		/*
   2366     0    stevel 		 * Grab manpname's first line, stashing it in manbuf.
   2367     0    stevel 		 */
   2368     0    stevel 
   2369     0    stevel 
   2370     0    stevel 		if ((md = fopen(manpname, "r")) == NULL) {
   2371     0    stevel 			if (*soed && errno == ENOENT) {
   2372     0    stevel 				(void) fprintf(stderr,
   2373     0    stevel 				    gettext("Can't find referent of "
   2374  8107        Pu 				    ".so in %s\n"), soed);
   2375     0    stevel 				(void) fflush(stderr);
   2376     0    stevel 				return (-1);
   2377     0    stevel 			}
   2378     0    stevel 			perror(manpname);
   2379     0    stevel 			return (-1);
   2380     0    stevel 		}
   2381     0    stevel 		if (fgets(manbuf, BUFSIZ-1, md) == NULL) {
   2382     0    stevel 			(void) fclose(md);
   2383     0    stevel 			(void) fprintf(stderr, gettext("%s: null file\n"),
   2384     0    stevel 			    manpname);
   2385     0    stevel 			(void) fflush(stderr);
   2386     0    stevel 			return (-1);
   2387     0    stevel 		}
   2388     0    stevel 		(void) fclose(md);
   2389     0    stevel 
   2390     0    stevel 		if (strncmp(manbuf, DOT_SO, sizeof (DOT_SO) - 1))
   2391     0    stevel 			break;
   2392     0    stevel so_again:	if (++socount > SOLIMIT) {
   2393     0    stevel 			(void) fprintf(stderr, gettext(".so chain too long\n"));
   2394     0    stevel 			(void) fflush(stderr);
   2395     0    stevel 			return (-1);
   2396     0    stevel 		}
   2397     0    stevel 		s = manbuf + sizeof (DOT_SO) - 1;
   2398     0    stevel 		if ((check_flag == 1) && ((new_s = strrchr(s, '/')) != NULL)) {
   2399     0    stevel 				new_s++;
   2400     0    stevel 				(void) sprintf(s, "%s%s/%s",
   2401  8107        Pu 				    tmpsubdir, dir+plen, new_s);
   2402     0    stevel 		}
   2403     0    stevel 
   2404     0    stevel 		cp = strrchr(s, '\n');
   2405     0    stevel 		if (cp)
   2406     0    stevel 			*cp = '\0';
   2407     0    stevel 		/*
   2408     0    stevel 		 * Compensate for sloppy typists by stripping
   2409     0    stevel 		 * trailing white space.
   2410     0    stevel 		 */
   2411     0    stevel 		cp = s + strlen(s);
   2412     0    stevel 		while (--cp >= s && (*cp == ' ' || *cp == '\t'))
   2413     0    stevel 			*cp = '\0';
   2414     0    stevel 
   2415     0    stevel 		/*
   2416     0    stevel 		 * Go off and find the next link in the chain.
   2417     0    stevel 		 */
   2418     0    stevel 		(void) strcpy(soed, manpname);
   2419     0    stevel 		(void) strcpy(soref, s);
   2420     0    stevel 		(void) sprintf(manpname, "%s/%s", path, s);
   2421     0    stevel /*
   2422     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2423     0    stevel  * ex.  .so ref = man3c/string.3c
   2424     0    stevel  */
   2425     0    stevel 		DPRINTF(gettext(".so ref = %s\n"), s);
   2426     0    stevel 	}
   2427     0    stevel 
   2428     0    stevel 	/*
   2429     0    stevel 	 * Make symlinks if so'ed and cattin'
   2430     0    stevel 	 */
   2431     0    stevel 	if (socount && catmando) {
   2432     0    stevel 		(void) sprintf(cmdbuf, "cd %s; rm -f %s; ln -s ../%s%s %s",
   2433     0    stevel 		    path, catpname, subdirs[1], soref+plen, catpname);
   2434     0    stevel 		(void) sys(cmdbuf);
   2435     0    stevel 		return (1);
   2436     0    stevel 	}
   2437     0    stevel 
   2438     0    stevel 	/*
   2439     0    stevel 	 * Obtain the cat page that corresponds to the man page.
   2440     0    stevel 	 * If it already exists, is up to date, and if we haven't
   2441     0    stevel 	 * been told not to use it, use it as it stands.
   2442     0    stevel 	 */
   2443     0    stevel 	regencat = updatedcat = 0;
   2444     0    stevel 	if (compargs || (!catonly && stat(manpname, &mansb) >= 0 &&
   2445     0    stevel 	    (stat(catpname, &catsb) < 0 || catsb.st_mtime < mansb.st_mtime)) ||
   2446     0    stevel 	    (access(catpname, R_OK) != 0)) {
   2447     0    stevel 		/*
   2448     0    stevel 		 * Construct a shell command line for formatting manpname.
   2449     0    stevel 		 * The resulting file goes initially into /tmp.  If possible,
   2450     0    stevel 		 * it will later be moved to catpname.
   2451     0    stevel 		 */
   2452     0    stevel 
   2453     0    stevel 		int pipestage = 0;
   2454     0    stevel 		int needcol = 0;
   2455     0    stevel 		char *cbp = cmdbuf;
   2456     0    stevel 
   2457     0    stevel 		regencat = updatedcat = 1;
   2458     0    stevel 
   2459     0    stevel 		if (!catmando && !debug && !check_flag) {
   2460     0    stevel 			(void) fprintf(stderr, gettext(
   2461  8107        Pu 			    "Reformatting page.  Please Wait..."));
   2462     0    stevel 			if (sargs && (newsection != NULL) &&
   2463     0    stevel 			    (*newsection != '\0')) {
   2464     0    stevel 				(void) fprintf(stderr, gettext(
   2465     0    stevel 				    "\nThe directory name has been changed "
   2466     0    stevel 				    "to %s\n"), newsection);
   2467     0    stevel 			}
   2468     0    stevel 			(void) fflush(stderr);
   2469     0    stevel 		}
   2470     0    stevel 
   2471     0    stevel 		/*
   2472     0    stevel 		 * in catman command, if the file exists in sman dir already,
   2473     0    stevel 		 * don't need to convert the file in man dir to cat dir
   2474     0    stevel 		 */
   2475     0    stevel 
   2476     0    stevel 		if (!no_sroff && catmando &&
   2477  8107        Pu 		    match(tmpsubdir, MANDIRNAME, PLEN) &&
   2478  8107        Pu 		    stat(smantmpname, &smansb) >= 0)
   2479     0    stevel 			return (1);
   2480     0    stevel 
   2481     0    stevel 		/*
   2482     0    stevel 		 * cd to path so that relative .so commands will work
   2483     0    stevel 		 * correctly
   2484     0    stevel 		 */
   2485     0    stevel 		(void) sprintf(cbp, "cd %s; ", path);
   2486     0    stevel 		cbp += strlen(cbp);
   2487     0    stevel 
   2488     0    stevel 
   2489     0    stevel 		/*
   2490     0    stevel 		 * check to see whether it is a sgml file
   2491     0    stevel 		 * assume sgml symbol(>!DOCTYPE) can be found in the first
   2492     0    stevel 		 * BUFSIZ bytes
   2493     0    stevel 		 */
   2494     0    stevel 
   2495     0    stevel 		if ((temp = open(manpname, 0)) == -1) {
   2496     0    stevel 				perror(manpname);
   2497     0    stevel 				return (-1);
   2498     0    stevel 		}
   2499     0    stevel 
   2500     0    stevel 		if ((count = read(temp, prntbuf, BUFSIZ)) <= 0) {
   2501     0    stevel 				perror(manpname);
   2502     0    stevel 				return (-1);
   2503     0    stevel 		}
   2504     0    stevel 
   2505     0    stevel 		prntbuf[count] = '\0';	/* null terminate */
   2506     0    stevel 		ptr = prntbuf;
   2507     0    stevel 		if (sgmlcheck((const char *)ptr) == 1) {
   2508     0    stevel 			sgml_flag = 1;
   2509     0    stevel 			if (defaultmandir && *localedir) {
   2510     0    stevel 				(void) sprintf(cbp, "LC_MESSAGES=C %s %s ",
   2511  8107        Pu 				    SROFF_CMD, manpname);
   2512     0    stevel 			} else {
   2513     0    stevel 				(void) sprintf(cbp, "%s %s ",
   2514  8107        Pu 				    SROFF_CMD, manpname);
   2515     0    stevel 			}
   2516     0    stevel 			cbp += strlen(cbp);
   2517     0    stevel 		} else if (*dir == 's') {
   2518     0    stevel 			(void) close(temp);
   2519     0    stevel 			return (-1);
   2520     0    stevel 		}
   2521     0    stevel 		(void) close(temp);
   2522     0    stevel 
   2523     0    stevel 		/*
   2524     0    stevel 		 * Check for special formatting requirements by examining
   2525     0    stevel 		 * manpname's first line preprocessor specifications.
   2526     0    stevel 		 */
   2527     0    stevel 
   2528     0    stevel 		if (strncmp(manbuf, PREPROC_SPEC,
   2529     0    stevel 		    sizeof (PREPROC_SPEC) - 1) == 0) {
   2530     0    stevel 			char *ptp;
   2531     0    stevel 
   2532     0    stevel 			ptp = manbuf + sizeof (PREPROC_SPEC) - 1;
   2533     0    stevel 			while (*ptp && *ptp != '\n') {
   2534     0    stevel 				const struct preprocessor *pp;
   2535     0    stevel 
   2536     0    stevel 				/*
   2537     0    stevel 				 * Check for a preprocessor we know about.
   2538     0    stevel 				 */
   2539     0    stevel 				for (pp = preprocessors; pp->p_tag; pp++) {
   2540     0    stevel 					if (pp->p_tag == *ptp)
   2541     0    stevel 						break;
   2542     0    stevel 				}
   2543     0    stevel 				if (pp->p_tag == 0) {
   2544     0    stevel 					(void) fprintf(stderr,
   2545     0    stevel 					    gettext("unknown preprocessor "
   2546  8107        Pu 					    "specifier %c\n"), *ptp);
   2547     0    stevel 					(void) fflush(stderr);
   2548     0    stevel 					return (-1);
   2549     0    stevel 				}
   2550     0    stevel 
   2551     0    stevel 				/*
   2552     0    stevel 				 * Add it to the pipeline.
   2553     0    stevel 				 */
   2554     0    stevel 				(void) sprintf(cbp, "%s %s |",
   2555  8107        Pu 				    troffit ? pp->p_troff : pp->p_nroff,
   2556  8107        Pu 				    pipestage++ == 0 ? manpname : "-");
   2557     0    stevel 				cbp += strlen(cbp);
   2558     0    stevel 
   2559     0    stevel 				/*
   2560     0    stevel 				 * Special treatment: if tbl is among the
   2561     0    stevel 				 * preprocessors and we'll process with
   2562     0    stevel 				 * nroff, we have to pass things through
   2563     0    stevel 				 * col at the end of the pipeline.
   2564     0    stevel 				 */
   2565     0    stevel 				if (pp->p_tag == 't' && !troffit)
   2566     0    stevel 					needcol++;
   2567     0    stevel 
   2568     0    stevel 				ptp++;
   2569     0    stevel 			}
   2570     0    stevel 		}
   2571     0    stevel 
   2572     0    stevel 		/*
   2573     0    stevel 		 * if catman, use the cat page name
   2574     0    stevel 		 * otherwise, dup template and create another
   2575     0    stevel 		 * (needed for multiple pages)
   2576     0    stevel 		 */
   2577     0    stevel 		if (catmando)
   2578     0    stevel 			tmpname = catpname;
   2579     0    stevel 		else {
   2580     0    stevel 			tmpname = strdup(TEMPLATE);
   2581     0    stevel 			if (tmpname == NULL)
   2582     0    stevel 				malloc_error();
   2583     0    stevel 			(void) close(mkstemp(tmpname));
   2584     0    stevel 		}
   2585     0    stevel 
   2586     0    stevel 		if (! Tflag) {
   2587     0    stevel 			if (*localedir != '\0') {
   2588     0    stevel 				(void) sprintf(macros, "%s/%s", path, MACROF);
   2589     0    stevel /*
   2590     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2591     0    stevel  * ex.  locale macros = /usr/share/man/ja/tmac.an
   2592     0    stevel  */
   2593     0    stevel 				if (debug)
   2594     0    stevel 					(void) printf(gettext(
   2595  8107        Pu 					    "\nlocale macros = %s "),
   2596  8107        Pu 					    macros);
   2597     0    stevel 				if (stat(macros, &statb) < 0)
   2598     0    stevel 					(void) strcpy(macros, TMAC_AN);
   2599     0    stevel /*
   2600     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2601     0    stevel  * ex.  macros = /usr/share/man/ja/tman.an
   2602     0    stevel  */
   2603     0    stevel 				if (debug)
   2604     0    stevel 					(void) printf(gettext(
   2605  8107        Pu 					    "\nmacros = %s\n"),
   2606  8107        Pu 					    macros);
   2607     0    stevel 			}
   2608     0    stevel 		}
   2609     0    stevel 
   2610  8107        Pu 		tmpdir[0] = '\0';
   2611     0    stevel 		if (sgml_flag == 1) {
   2612     0    stevel 			if (check_flag == 0) {
   2613     0    stevel 				strcpy(tmpdir, "/tmp/sman_XXXXXX");
   2614     0    stevel 				if ((tempfd = mkstemp(tmpdir)) == -1) {
   2615     0    stevel 					(void) fprintf(stderr, gettext(
   2616     0    stevel 					    "%s: null file\n"), tmpdir);
   2617     0    stevel 					(void) fflush(stderr);
   2618     0    stevel 					return (-1);
   2619     0    stevel 				}
   2620     0    stevel 
   2621     0    stevel 				if (debug)
   2622     0    stevel 					close(tempfd);
   2623     0    stevel 
   2624     0    stevel 				(void) sprintf(tmpbuf, "%s > %s",
   2625  8107        Pu 				    cmdbuf, tmpdir);
   2626     0    stevel 				if (sys(tmpbuf)) {
   2627     0    stevel /*
   2628     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2629     0    stevel  * Error message if sys(%s) failed
   2630     0    stevel  */
   2631     0    stevel 					(void) fprintf(stderr, gettext(
   2632  8107        Pu 					    "sys(%s) fail!\n"), tmpbuf);
   2633     0    stevel 					(void) fprintf(stderr,
   2634  8107        Pu 					    gettext(" aborted (sorry)\n"));
   2635     0    stevel 					(void) fflush(stderr);
   2636     0    stevel 					/* release memory for tmpname */
   2637     0    stevel 					if (!catmando) {
   2638     0    stevel 						(void) unlink(tmpdir);
   2639     0    stevel 						(void) unlink(tmpname);
   2640     0    stevel 						free(tmpname);
   2641     0    stevel 					}
   2642     0    stevel 					return (-1);
   2643     0    stevel 				} else if (debug == 0) {
   2644     0    stevel 					if ((md = fdopen(tempfd, "r"))
   2645     0    stevel 					    == NULL) {
   2646     0    stevel 						(void) fprintf(stderr, gettext(
   2647     0    stevel 						    "%s: null file\n"), tmpdir);
   2648     0    stevel 						(void) fflush(stderr);
   2649     0    stevel 						close(tempfd);
   2650     0    stevel 						/* release memory for tmpname */
   2651     0    stevel 						if (!catmando)
   2652     0    stevel 							free(tmpname);
   2653     0    stevel 						return (-1);
   2654     0    stevel 					}
   2655     0    stevel 
   2656     0    stevel 					/* if the file is empty, */
   2657     0    stevel 					/* it's a fragment, do nothing */
   2658     0    stevel 					if (fgets(manbuf, BUFSIZ-1, md)
   2659  8107        Pu 					    == NULL) {
   2660     0    stevel 						(void) fclose(md);
   2661     0    stevel 						/* release memory for tmpname */
   2662     0    stevel 						if (!catmando)
   2663     0    stevel 							free(tmpname);
   2664     0    stevel 						return (1);
   2665     0    stevel 					}
   2666     0    stevel 					(void) fclose(md);
   2667     0    stevel 
   2668     0    stevel 					if (strncmp(manbuf, DOT_SO,
   2669  8107        Pu 					    sizeof (DOT_SO) - 1) == 0) {
   2670     0    stevel 						if (!compargs) {
   2671     0    stevel 						check_flag = 1;
   2672     0    stevel 						(void) unlink(tmpdir);
   2673     0    stevel 						(void) unlink(tmpname);
   2674     0    stevel 						/* release memory for tmpname */
   2675     0    stevel 						if (!catmando)
   2676     0    stevel 							free(tmpname);
   2677     0    stevel 						goto so_again;
   2678     0    stevel 						} else {
   2679     0    stevel 							(void) unlink(tmpdir);
   2680     0    stevel 						strcpy(tmpdir,
   2681     0    stevel 						    "/tmp/sman_XXXXXX");
   2682     0    stevel 						tempfd = mkstemp(tmpdir);
   2683     0    stevel 						if ((tempfd == -1) ||
   2684     0    stevel 						    (md = fdopen(tempfd, "w"))
   2685     0    stevel 						    == NULL) {
   2686     0    stevel 							(void) fprintf(stderr,
   2687  8107        Pu 							    gettext(
   2688     0    stevel 							    "%s: null file\n"),
   2689     0    stevel 							    tmpdir);
   2690     0    stevel 							(void) fflush(stderr);
   2691     0    stevel 							if (tempfd != -1)
   2692     0    stevel 								close(tempfd);
   2693     0    stevel 						/* release memory for tmpname */
   2694     0    stevel 							if (!catmando)
   2695     0    stevel 								free(tmpname);
   2696     0    stevel 							return (-1);
   2697     0    stevel 						}
   2698     0    stevel 				if ((new_m = strrchr(manbuf, '/')) != NULL) {
   2699     0    stevel 		(void) fprintf(md, ".so man%s%s\n", dir+plen, new_m);
   2700     0    stevel 							} else {
   2701     0    stevel /*
   2702     0    stevel  * TRANSLATION_NOTE - message for catman -c
   2703     0    stevel  * Error message if unable to get file name
   2704     0    stevel  */
   2705     0    stevel 				(void) fprintf(stderr,
   2706  8107        Pu 				    gettext("file not found\n"));
   2707     0    stevel 				(void) fflush(stderr);
   2708     0    stevel 				return (-1);
   2709     0    stevel 				}
   2710     0    stevel 							(void) fclose(md);
   2711     0    stevel 						}
   2712     0    stevel 					}
   2713     0    stevel 				}
   2714     0    stevel 				if (catmando && compargs)
   2715     0    stevel 					(void) sprintf(cmdbuf, "cat %s > %s",
   2716  8107        Pu 					    tmpdir, manpname_sgml);
   2717     0    stevel 				else
   2718  8107        Pu 	(void) sprintf(cmdbuf, " cat %s | tbl | eqn | %s %s - %s > %s",
   2719  8107        Pu 	    tmpdir, troffit ? troffcmd : "nroff -u0 -Tlp",
   2720  8107        Pu 	    macros, troffit ? "" : " | col -x", tmpname);
   2721     0    stevel 			} else
   2722     0    stevel 				if (catmando && compargs)
   2723     0    stevel 					(void) sprintf(cbp, " > %s",
   2724  8107        Pu 					    manpname_sgml);
   2725     0    stevel 				else
   2726  8107        Pu 	(void) sprintf(cbp, " | tbl | eqn | %s %s - %s > %s",
   2727  8107        Pu 	    troffit ? troffcmd : "nroff -u0 -Tlp",
   2728  8107        Pu 	    macros, troffit ? "" : " | col -x", tmpname);
   2729     0    stevel 
   2730     0    stevel 		} else
   2731  8107        Pu 	(void) sprintf(cbp, "%s %s %s%s > %s",
   2732  8107        Pu 	    troffit ? troffcmd : "nroff -u0 -Tlp",
   2733  8107        Pu 	    macros, pipestage == 0 ? manpname : "-",
   2734  8107        Pu 	    troffit ? "" : " | col -x", tmpname);
   2735     0    stevel 
   2736     0    stevel 		/* Reformat the page. */
   2737     0    stevel 		if (sys(cmdbuf)) {
   2738     0    stevel /*
   2739     0    stevel  * TRANSLATION_NOTE - message for man -d or catman -p
   2740     0    stevel  * Error message if sys(%s) failed
   2741     0    stevel  */
   2742     0    stevel 			(void) fprintf(stderr, gettext(
   2743  8107        Pu 			    "sys(%s) fail!\n"), cmdbuf);
   2744     0    stevel 			(void) fprintf(stderr, gettext(" aborted (sorry)\n"));
   2745     0    stevel 			(void) fflush(stderr);
   2746     0    stevel 			(void) unlink(tmpname);
   2747     0    stevel 			/* release memory for tmpname */
   2748     0    stevel 			if (!catmando)
   2749     0    stevel 				free(tmpname);
   2750     0    stevel 			return (-1);
   2751     0    stevel 		}
   2752     0    stevel 
   2753  8107        Pu 		if (tmpdir[0] != '\0')
   2754  8107        Pu 			(void) unlink(tmpdir);
   2755     0    stevel 
   2756     0    stevel 		if (catmando)
   2757     0    stevel 			return (1);
   2758     0    stevel 
   2759     0    stevel 		/*
   2760     0    stevel 		 * Attempt to move the cat page to its proper home.
   2761     0    stevel 		 */
   2762     0    stevel 		(void) sprintf(cmdbuf,
   2763  8107        Pu 		    "trap '' 1 15; /usr/bin/mv -f %s %s 2> /dev/null",
   2764  8107        Pu 		    tmpname,
   2765  8107        Pu 		    catpname);
   2766     0    stevel 		if (sys(cmdbuf))
   2767     0    stevel 			updatedcat = 0;
   2768     0    stevel 		else if (debug == 0)
   2769     0    stevel 			(void) chmod(catpname, 0644);
   2770     0    stevel 
   2771     0    stevel 		if (debug) {
   2772     0    stevel 			/* release memory for tmpname */
   2773     0    stevel 			if (!catmando)
   2774     0    stevel 				free(tmpname);
   2775     0    stevel 			(void) unlink(tmpname);
   2776     0    stevel 			return (1);
   2777     0    stevel 		}
   2778     0    stevel 
   2779     0    stevel 		(void) fprintf(stderr, gettext(" done\n"));
   2780     0    stevel 		(void) fflush(stderr);
   2781     0    stevel 	}
   2782     0    stevel 
   2783     0    stevel 	/*
   2784     0    stevel 	 * Save file name (dup if necessary)
   2785     0    stevel 	 * to view later
   2786     0    stevel 	 * fix for 1123802 - don't save names if we are invoked as catman
   2787     0    stevel 	 */
   2788     0    stevel 	if (!catmando) {
   2789     0    stevel 		char	**tmpp;
   2790     0    stevel 		int	dup;
   2791     0    stevel 		char	*newpage;
   2792     0    stevel 
   2793     0    stevel 		if (regencat && !updatedcat)
   2794     0    stevel 			newpage = tmpname;
   2795     0    stevel 		else {
   2796     0    stevel 			newpage = strdup(catpname);
   2797     0    stevel 			if (newpage == NULL)
   2798     0    stevel 				malloc_error();
   2799     0    stevel 		}
   2800     0    stevel 		/* make sure we don't add a dup */
   2801     0    stevel 		dup = 0;
   2802     0    stevel 		for (tmpp = pages; tmpp < endp; tmpp++) {
   2803     0    stevel 			if (strcmp(*tmpp, newpage) == 0) {
   2804     0    stevel 				dup = 1;
   2805     0    stevel 				break;
   2806     0    stevel 			}
   2807     0    stevel 		}
   2808     0    stevel 		if (!dup)
   2809     0    stevel 			*endp++ = newpage;
   2810     0    stevel 		if (endp >= &pages[MAXPAGES]) {
   2811     0    stevel 			fprintf(stderr,
   2812     0    stevel 			    gettext("Internal pages array overflow!\n"));
   2813     0    stevel 			exit(1);
   2814     0    stevel 		}
   2815     0    stevel 	}
   2816     0    stevel 
   2817     0    stevel 	return (regencat);
   2818     0    stevel }
   2819     0    stevel 
   2820     0    stevel /*
   2821     0    stevel  * Add <localedir> to the path.
   2822     0    stevel  */
   2823     0    stevel 
   2824     0    stevel static char *
   2825     0    stevel addlocale(char *path)
   2826     0    stevel {
   2827     0    stevel 
   2828     0    stevel 	char *tmp;
   2829     0    stevel 
   2830     0    stevel 	tmp = malloc(strlen(path) + strlen(localedir) + 2);
   2831     0    stevel 	if (tmp == NULL)
   2832     0    stevel 		malloc_error();
   2833     0    stevel 	(void) sprintf(tmp, "%s/%s", path, localedir);
   2834     0    stevel 	return (tmp);
   2835     0    stevel 
   2836     0    stevel }
   2837     0    stevel 
   2838     0    stevel /*
   2839     0    stevel  * From the configuration file "man.cf", get the order of suffices of
   2840     0    stevel  * sub-mandirs to be used in the search path for a given mandir.
   2841     0    stevel  */
   2842     0    stevel 
   2843     0    stevel static char *
   2844     0    stevel check_config(char *path)
   2845     0    stevel {
   2846     0    stevel 	FILE *fp;
   2847     0    stevel 	static char submandir[BUFSIZ];
   2848     0    stevel 	char *sect;
   2849     0    stevel 	char fname[MAXPATHLEN];
   2850     0    stevel 
   2851     0    stevel 	(void) sprintf(fname, "%s/%s", path, CONFIG);
   2852     0    stevel 
   2853     0    stevel 	if ((fp = fopen(fname, "r")) == NULL)
   2854     0    stevel 		return (NULL);
   2855     0    stevel 	else {
   2856     0    stevel 		if (get_manconfig(fp, submandir) == -1) {
   2857     0    stevel 			(void) fclose(fp);
   2858     0    stevel 			return (NULL);
   2859     0    stevel 		}
   2860     0    stevel 
   2861     0    stevel 		(void) fclose(fp);
   2862     0    stevel 
   2863     0    stevel 		sect = strchr(submandir, '=');
   2864     0    stevel 		if (sect != NULL)
   2865     0    stevel 			return (++sect);
   2866     0    stevel 		else
   2867     0    stevel 			return (NULL);
   2868     0    stevel 	}
   2869     0    stevel }
   2870     0    stevel 
   2871     0    stevel /*
   2872     0    stevel  *  This routine is for getting the MANSECTS entry from man.cf.
   2873     0    stevel  *  It sets submandir to the line in man.cf that contains
   2874     0    stevel  *	MANSECTS=sections[,sections]...
   2875     0    stevel  */
   2876     0    stevel 
   2877     0    stevel static int
   2878     0    stevel get_manconfig(FILE *fp, char *submandir)
   2879     0    stevel {
   2880     0    stevel 	char *s, *t, *rc;
   2881     0    stevel 	char buf[BUFSIZ];
   2882     0    stevel 
   2883     0    stevel 	while ((rc = fgets(buf, sizeof (buf), fp)) != NULL) {
   2884     0    stevel 
   2885     0    stevel 		/*
   2886     0    stevel 		 * skip leading blanks
   2887     0    stevel 		 */
   2888     0    stevel 		for (t = buf; *t != '\0'; t++) {
   2889     0    stevel 			if (!isspace(*t))
   2890     0    stevel 				break;
   2891     0    stevel 		}
   2892     0    stevel 		/*
   2893     0    stevel 		 * skip line that starts with '#' or empty line
   2894     0    stevel 		 */
   2895     0    stevel 		if (*t == '#' || *t == '\0')
   2896     0    stevel 			continue;
   2897     0    stevel 
   2898     0    stevel 		if (strstr(buf, "MANSECTS") != NULL)
   2899     0    stevel 			break;
   2900     0    stevel 	}
   2901     0    stevel 
   2902     0    stevel 	/*
   2903     0    stevel 	 * the man.cf file doesn't have a MANSECTS entry
   2904     0    stevel 	 */
   2905     0    stevel 	if (rc == NULL)
   2906     0    stevel 		return (-1);
   2907     0    stevel 
   2908     0    stevel 	s = strchr(buf, '\n');
   2909     0    stevel 	*s = '\0';	/* replace '\n' with '\0' */
   2910     0    stevel 
   2911     0    stevel 	(void) strcpy(submandir, buf);
   2912     0    stevel 	return (0);
   2913     0    stevel }
   2914     0    stevel 
   2915     0    stevel static void
   2916     0    stevel malloc_error(void)
   2917     0    stevel {
   2918     0    stevel 	(void) fprintf(stderr, gettext(
   2919  8107        Pu 	    "Memory allocation failed.\n"));
   2920     0    stevel 	exit(1);
   2921     0    stevel }
   2922     0    stevel 
   2923     0    stevel static int
   2924     0    stevel sgmlcheck(const char *s1)
   2925     0    stevel {
   2926     0    stevel 	const char	*s2 = SGML_SYMBOL;
   2927     0    stevel 	int	len;
   2928     0    stevel 
   2929     0    stevel 	while (*s1) {
   2930     0    stevel 		/*
   2931     0    stevel 		 * Assume the first character of SGML_SYMBOL(*s2) is '<'.
   2932     0    stevel 		 * Therefore, not necessary to do toupper(*s1) here.
   2933     0    stevel 		 */
   2934     0    stevel 		if (*s1 == *s2) {
   2935     0    stevel 			/*
   2936     0    stevel 			 * *s1 is '<'.  Check the following substring matches
   2937     0    stevel 			 * with "!DOCTYPE".
   2938     0    stevel 			 */
   2939     0    stevel 			s1++;
   2940     0    stevel 			if (strncasecmp(s1, s2 + 1, SGML_SYMBOL_LEN - 1)
   2941  8107        Pu 			    == 0) {
   2942     0    stevel 				/*
   2943     0    stevel 				 * SGML_SYMBOL found
   2944     0    stevel 				 */
   2945     0    stevel 				return (1);
   2946     0    stevel 			}
   2947     0    stevel 			continue;
   2948     0    stevel 		} else if (isascii(*s1)) {
   2949     0    stevel 			/*
   2950     0    stevel 			 * *s1 is an ASCII char
   2951     0    stevel 			 * Skip one character
   2952     0    stevel 			 */
   2953     0    stevel 			s1++;
   2954     0    stevel 			continue;
   2955     0    stevel 		} else {
   2956     0    stevel 			/*
   2957     0    stevel 			 * *s1 is a non-ASCII char or
   2958     0    stevel 			 * the first byte of the multibyte char.
   2959     0    stevel 			 * Skip one character
   2960     0    stevel 			 */
   2961     0    stevel 			len = mblen(s1, MB_CUR_MAX);
   2962     0    stevel 			if (len == -1)
   2963     0    stevel 				len = 1;
   2964     0    stevel 			s1 += len;
   2965     0    stevel 			continue;
   2966     0    stevel 		}
   2967     0    stevel 	}
   2968     0    stevel 	/*
   2969     0    stevel 	 * SGML_SYMBOL not found
   2970     0    stevel 	 */
   2971     0    stevel 	return (0);
   2972     0    stevel }
   2973     0    stevel 
   2974     0    stevel /*
   2975  6639      samf  * Initializes the bintoman array with appropriate device and inode info
   2976     0    stevel  */
   2977     0    stevel 
   2978  6639      samf static void
   2979  6639      samf init_bintoman(void)
   2980     0    stevel {
   2981  6639      samf 	int i;
   2982  6639      samf 	struct stat sb;
   2983     0    stevel 
   2984  6639      samf 	for (i = 0; bintoman[i].bindir != NULL; i++) {
   2985  6639      samf 		if (stat(bintoman[i].bindir, &sb) == 0) {
   2986  6639      samf 			bintoman[i].dev = sb.st_dev;
   2987  6639      samf 			bintoman[i].ino = sb.st_ino;
   2988  6639      samf 		} else {
   2989  6639      samf 			bintoman[i].dev = NODEV;
   2990  6639      samf 		}
   2991     0    stevel 	}
   2992     0    stevel }
   2993     0    stevel 
   2994     0    stevel /*
   2995  6639      samf  * If a duplicate is found, return 1
   2996  6639      samf  * If a duplicate is not found, add it to the dupnode list and return 0
   2997  6639      samf  */
   2998  6639      samf static int
   2999  7172      samf dupcheck(struct man_node *mnp, struct dupnode **dnp)
   3000  7172      samf {
   3001  6639      samf 	struct dupnode	*curdnp;
   3002  6639      samf 	struct secnode	*cursnp;
   3003  6639      samf 	struct stat 	sb;
   3004  6639      samf 	int 		i;
   3005  6639      samf 	int		rv = 1;
   3006  6639      samf 	int		dupfound;
   3007  6639      samf 
   3008  6639      samf 	/*
   3009  6639      samf 	 * If the path doesn't exist, treat it as a duplicate
   3010  6639      samf 	 */
   3011  6639      samf 	if (stat(mnp->path, &sb) != 0) {
   3012  7172      samf 		return (1);
   3013  7172      samf 	}
   3014  7172      samf 
   3015  7172      samf 	/*
   3016  7172      samf 	 * If no sections were found in the man dir, treat it as duplicate
   3017  7172      samf 	 */
   3018  7172      samf 	if (mnp->secv == NULL) {
   3019  6639      samf 		return (1);
   3020  6639      samf 	}
   3021  6639      samf 
   3022  6639      samf 	/*
   3023  6639      samf 	 * Find the dupnode structure for the previous time this directory
   3024  6639      samf 	 * was looked at.  Device and inode numbers are compared so that
   3025  6639      samf 	 * directories that are reached via different paths (e.g. /usr/man vs.
   3026  6639      samf 	 * /usr/share/man) are treated as equivalent.
   3027  6639      samf 	 */
   3028  6639      samf 	for (curdnp = *dnp; curdnp != NULL; curdnp = curdnp->next) {
   3029  6639      samf 		if (curdnp->dev == sb.st_dev && curdnp->ino == sb.st_ino) {
   3030  6639      samf 			break;
   3031  6639      samf 		}
   3032  6639      samf 	}
   3033  6639      samf 
   3034  6639      samf 	/*
   3035  6639      samf 	 * First time this directory has been seen.  Add a new node to the
   3036  6639      samf 	 * head of the list.  Since all entries are guaranteed to be unique
   3037  6639      samf 	 * copy all sections to new node.
   3038  6639      samf 	 */
   3039  6639      samf 	if (curdnp == NULL) {
   3040  6639      samf 		if ((curdnp = calloc(1, sizeof (struct dupnode))) == NULL) {
   3041  6639      samf 			malloc_error();
   3042  6639      samf 		}
   3043  6639      samf 		for (i = 0; mnp->secv[i] != NULL; i++) {
   3044  6639      samf 			if ((cursnp = calloc(1, sizeof (struct secnode)))
   3045  6639      samf 			    == NULL) {
   3046  6639      samf 				malloc_error();
   3047  6639      samf 			}
   3048  6639      samf 			cursnp->next = curdnp->secl;
   3049  6639      samf 			curdnp->secl = cursnp;
   3050  6639      samf 			if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) {
   3051  6639      samf 				malloc_error();
   3052  6639      samf 			}
   3053  6639      samf 		}
   3054  6639      samf 		curdnp->dev = sb.st_dev;
   3055  6639      samf 		curdnp->ino = sb.st_ino;
   3056  6639      samf 		curdnp->next = *dnp;
   3057  6639      samf 		*dnp = curdnp;
   3058  6639      samf 		return (0);
   3059  6639      samf 	}
   3060  6639      samf 
   3061  6639      samf 	/*
   3062  6639      samf 	 * Traverse the section vector in the man_node and the section list
   3063  6639      samf 	 * in dupnode cache to eliminate all duplicates from man_node
   3064  6639      samf 	 */
   3065  6639      samf 	for (i = 0; mnp->secv[i] != NULL; i++) {
   3066  6639      samf 		dupfound = 0;
   3067  6639      samf 		for (cursnp = curdnp->secl; cursnp != NULL;
   3068  6639      samf 		    cursnp = cursnp->next) {
   3069  6639      samf 			if (strcmp(mnp->secv[i], cursnp->secp) == 0) {
   3070  6639      samf 				dupfound = 1;
   3071  6639      samf 				break;
   3072  6639      samf 			}
   3073  6639      samf 		}
   3074  6639      samf 		if (dupfound) {
   3075  6639      samf 			mnp->secv[i][0] = '\0';
   3076  6639      samf 			continue;
   3077  6639      samf 		}
   3078  6639      samf 
   3079  6639      samf 
   3080  6639      samf 		/*
   3081  6639      samf 		 * Update curdnp and set return value to indicate that this
   3082  6639      samf 		 * was not all duplicates.
   3083  6639      samf 		 */
   3084  6639      samf 		if ((cursnp = calloc(1, sizeof (struct secnode))) == NULL) {
   3085  6639      samf 			malloc_error();
   3086  6639      samf 		}
   3087  6639      samf 		cursnp->next = curdnp->secl;
   3088  6639      samf 		curdnp->secl = cursnp;
   3089  6639      samf 		if ((cursnp->secp = strdup(mnp->secv[i])) == NULL) {
   3090  6639      samf 			malloc_error();
   3091  6639      samf 		}
   3092  6639      samf 		rv = 0;
   3093  6639      samf 	}
   3094  6639      samf 
   3095  6639      samf 	return (rv);
   3096  6639      samf }
   3097  6639      samf 
   3098  6639      samf /*
   3099  6639      samf  * Given a bin directory, return the corresponding man directory.
   3100  6639      samf  * Return string must be free()d by the caller.
   3101  6639      samf  *
   3102  6639      samf  * NULL will be returned if no matching man directory can be found.
   3103     0    stevel  */
   3104     0    stevel 
   3105  6639      samf static char *
   3106  6639      samf path_to_manpath(char *bindir)
   3107  6639      samf {
   3108  6639      samf 	char	*mand, *p;
   3109  6639      samf 	int	i;
   3110  6639      samf 	struct stat	sb;
   3111  6639      samf 
   3112  6639      samf 	/*
   3113  6639      samf 	 * First look for known translations for specific bin paths
   3114  6639      samf 	 */
   3115  6639      samf 	if (stat(bindir, &sb) != 0) {
   3116  6639      samf 		return (NULL);
   3117  6639      samf 	}
   3118  6639      samf 	for (i = 0; bintoman[i].bindir != NULL; i++) {
   3119  6639      samf 		if (sb.st_dev == bintoman[i].dev &&
   3120  6639      samf 		    sb.st_ino == bintoman[i].ino) {
   3121  6639      samf 			if ((mand = strdup(bintoman[i].mandir)) == NULL) {
   3122  6639      samf 				malloc_error();
   3123  6639      samf 			}
   3124  6639      samf 			if ((p = strchr(mand, ',')) != NULL) {
   3125  6639      samf 				*p = '\0';
   3126  6639      samf 			}
   3127  6639      samf 			if (stat(mand, &sb) != 0) {
   3128  6639      samf 				free(mand);
   3129  6639      samf 				return (NULL);
   3130  6639      samf 			}
   3131  6639      samf 			if (p != NULL) {
   3132  6639      samf 				*p = ',';
   3133  6639      samf 			}
   3134  6639      samf 			return (mand);
   3135  6639      samf 		}
   3136  6639      samf 	}
   3137  6639      samf 
   3138  6639      samf 	/*
   3139  6639      samf 	 * No specific translation found.  Try `dirname $bindir`/man
   3140  6639      samf 	 * and `dirname $bindir`/share/man
   3141  6639      samf 	 */
   3142  6639      samf 	if ((mand = malloc(PATH_MAX)) == NULL) {
   3143  6639      samf 		malloc_error();
   3144  6639      samf 	}
   3145  6639      samf 
   3146  6639      samf 	if (strlcpy(mand, bindir, PATH_MAX) >= PATH_MAX) {
   3147  6639      samf 		free(mand);
   3148  6639      samf 		return (NULL);
   3149  6639      samf 	}
   3150  6639      samf 
   3151  6639      samf 	/*
   3152  6639      samf 	 * Advance to end of buffer, strip trailing /'s then remove last
   3153  6639      samf 	 * directory component.
   3154  6639      samf 	 */
   3155  6639      samf 	for (p = mand; *p != '\0'; p++)
   3156  6639      samf 		;
   3157  6639      samf 	for (; p > mand && *p == '/'; p--)
   3158  6639      samf 		;
   3159  6639      samf 	for (; p > mand && *p != '/'; p--)
   3160  6639      samf 		;
   3161  6639      samf 	if (p == mand && *p == '.') {
   3162  6639      samf 		if (realpath("..", mand) == NULL) {
   3163  6639      samf 			free(mand);
   3164  6639      samf 			return (NULL);
   3165  6639      samf 		}
   3166  7172      samf 		for (; *p != '\0'; p++)
   3167  7172      samf 			;
   3168  6639      samf 	} else {
   3169  6639      samf 		*p = '\0';
   3170  6639      samf 	}
   3171  6639      samf 
   3172  6639      samf 	if (strlcat(mand, "/man", PATH_MAX) >= PATH_MAX) {
   3173  6639      samf 		free(mand);
   3174  6639      samf 		return (NULL);
   3175  6639      samf 	}
   3176  6639      samf 
   3177  7172      samf 	if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) {
   3178  6639      samf 		return (mand);
   3179  6639      samf 	}
   3180  6639      samf 
   3181  6639      samf 	/*
   3182  6639      samf 	 * Strip the /man off and try /share/man
   3183  6639      samf 	 */
   3184  6639      samf 	*p = '\0';
   3185  6639      samf 	if (strlcat(mand, "/share/man", PATH_MAX) >= PATH_MAX) {
   3186  6639      samf 		free(mand);
   3187  6639      samf 		return (NULL);
   3188  6639      samf 	}
   3189  7172      samf 	if ((stat(mand, &sb) == 0) && S_ISDIR(sb.st_mode)) {
   3190  7172      samf 		return (mand);
   3191  6639      samf 	}
   3192  6639      samf 
   3193  7172      samf 	/*
   3194  7172      samf 	 * No man or share/man directory found
   3195  7172      samf 	 */
   3196  7172      samf 	free(mand);
   3197  7172      samf 	return (NULL);
   3198  6639      samf }
   3199  6639      samf 
   3200  6639      samf /*
   3201  6639      samf  * Free a linked list of dupnode structs
   3202  6639      samf  */
   3203     0    stevel void
   3204  6639      samf free_dupnode(struct dupnode *dnp) {
   3205  6639      samf 	struct dupnode *dnp2;
   3206  6639      samf 	struct secnode *snp;
   3207  6639      samf 
   3208  6639      samf 	while (dnp != NULL) {
   3209  6639      samf 		dnp2 = dnp;
   3210  6639      samf 		dnp = dnp->next;
   3211  6639      samf 		while (dnp2->secl != NULL) {
   3212  6639      samf 			snp = dnp2->secl;
   3213  6639      samf 			dnp2->secl = dnp2->secl->next;
   3214  6639      samf 			free(snp->secp);
   3215  6639      samf 			free(snp);
   3216  6639      samf 		}
   3217  6639      samf 		free(dnp2);
   3218  6639      samf 	}
   3219  6639      samf }
   3220  6639      samf 
   3221  6639      samf /*
   3222  6639      samf  * prints manp linked list to stdout.
   3223  6639      samf  *
   3224  6639      samf  * If namep is NULL, output can be used for setting MANPATH.
   3225  6639      samf  *
   3226  6639      samf  * If namep is not NULL output is two columns.  First column is the string
   3227  6639      samf  * pointed to by namep.  Second column is a MANPATH-compatible representation
   3228  6639      samf  * of manp linked list.
   3229  6639      samf  */
   3230  6639      samf void
   3231  6639      samf print_manpath(struct man_node *manp, char *namep)
   3232     0    stevel {
   3233  6639      samf 	char colon[2];
   3234  6639      samf 	char **secp;
   3235     0    stevel 
   3236  6639      samf 	if (namep != NULL) {
   3237  6639      samf 		(void) printf("%s ", namep);
   3238  6639      samf 	}
   3239  6639      samf 
   3240  6639      samf 	colon[0] = '\0';
   3241  6639      samf 	colon[1] = '\0';
   3242  6639      samf 
   3243  6639      samf 	for (; manp != NULL; manp = manp->next) {
   3244  6639      samf 		(void) printf("%s%s", colon, manp->path);
   3245  6639      samf 		colon[0] = ':';
   3246  6639      samf 
   3247  6639      samf 		/*
   3248  6639      samf 		 * If man.cf or a directory scan was used to create section
   3249  6639      samf 		 * list, do not print section list again.  If the output of
   3250  6639      samf 		 * man -p is used to set MANPATH, subsequent runs of man
   3251  6639      samf 		 * will re-read man.cf and/or scan man directories as
   3252  6639      samf 		 * required.
   3253  6639      samf 		 */
   3254  6639      samf 		if (manp->defsrch != 0) {
   3255  6639      samf 			continue;
   3256  6639      samf 		}
   3257  6639      samf 
   3258  6639      samf 		for (secp = manp->secv; *secp != NULL; secp++) {
   3259  6639      samf 			/*
   3260  6639      samf 			 * Section deduplication may have eliminated some
   3261  6639      samf 			 * sections from the vector. Avoid displaying this
   3262  6639      samf 			 * detail which would appear as ",," in output
   3263  6639      samf 			 */
   3264  6639      samf 			if ((*secp)[0] != '\0') {
   3265  6639      samf 				(void) printf(",%s", *secp);
   3266  6639      samf 			}
   3267  6639      samf 		}
   3268  6639      samf 	}
   3269  6639      samf 	(void) printf("\n");
   3270     0    stevel }
   3271