summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile124
-rw-r--r--src/Makefile.in120
-rwxr-xr-xsrc/apropos88
-rw-r--r--src/apropos.sh88
-rw-r--r--src/defs.h26
-rw-r--r--src/different.c72
-rw-r--r--src/different.h3
-rw-r--r--src/glob.c682
-rw-r--r--src/glob.h1
-rw-r--r--src/gripedefs.h87
-rw-r--r--src/gripes.c139
-rw-r--r--src/gripes.h5
-rw-r--r--src/join.c28
-rwxr-xr-xsrc/makemsgbin0 -> 11755 bytes
-rw-r--r--src/makemsg.c175
-rwxr-xr-xsrc/makewhatis460
-rw-r--r--src/makewhatis.in456
-rw-r--r--src/makewhatis.sh456
-rw-r--r--src/man-config.c297
-rw-r--r--src/man-config.h6
-rw-r--r--src/man-getopt.c322
-rw-r--r--src/man-getopt.h6
-rw-r--r--src/man-iconv.c163
-rw-r--r--src/man-iconv.h1
-rw-r--r--src/man.c1366
-rw-r--r--src/man.conf144
-rw-r--r--src/man.conf.in140
-rw-r--r--src/man.h22
-rwxr-xr-xsrc/man2dvi36
-rw-r--r--src/manfile.c337
-rw-r--r--src/manfile.h36
-rw-r--r--src/manpath.c412
-rw-r--r--src/manpath.h5
-rw-r--r--src/msg.c106
-rwxr-xr-xsrc/mwi19
-rw-r--r--src/ndir.h51
-rw-r--r--src/paths.h43
-rw-r--r--src/paths.h.in39
-rw-r--r--src/to_cat.c171
-rw-r--r--src/to_cat.h3
-rw-r--r--src/util.c305
-rw-r--r--src/util.h13
-rw-r--r--src/version.h1
-rwxr-xr-xsrc/whatis88
44 files changed, 7142 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..c68bd77
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,124 @@
+#
+# Generated automatically from Makefile.in by the
+# configure script.
+#
+#
+# Master Makefile for man, apropos, whatis, and makewhatis
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+# Copyright (c) 1994-2001, Andries E. Brouwer
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man 1.0
+# distribution.
+#
+# various changes - aeb, March 1994
+# use of catalogs - aeb, June 1994
+
+CC = gcc -O
+BUILD_CC = gcc -O
+INSTALL = install
+EXEEXT =
+
+pager = /bin/less -is
+
+DEFS = -DSTDC_HEADERS -DTERMIOS_HEADER -DPOSIX -DDO_COMPRESS
+CWARN = -Wall -Wstrict-prototypes -Wmissing-prototypes
+CWARNNP = -Wall
+
+.c.o:
+ $(CC) -c $(CWARN) $(CFLAGS) -I. $(DEFS) $<
+
+# LDFLAGS = -g
+LDFLAGS ?= -s
+
+LIBOBJS =
+
+all: man$(EXEEXT) man.conf apropos whatis makewhatis
+
+MANOBJS = man.o manfile.o manpath.o man-config.o man-getopt.o \
+ man-iconv.o to_cat.o different.o gripes.o glob.o util.o msg.o
+
+man$(EXEEXT): $(MANOBJS) $(LIBOBJS)
+ $(CC) $(LDFLAGS) -o man$(EXEEXT) $(MANOBJS) $(LIBOBJS) $(LIBS)
+
+# CC may be a cross compiler, but BUILD_CC must compile for
+# the present machine.
+makemsg:
+ $(BUILD_CC) -o makemsg makemsg.c
+
+msg.c gripedefs.h: ../msgs/mess.en makemsg
+ ./makemsg ../msgs/mess.en gripedefs.h msg.c
+
+# glob.c does not have prototypes
+glob.o: glob.c ndir.h
+ $(CC) -c $(CWARNNP) $(CFLAGS) -I. $(DEFS) glob.c
+
+man-config.o man-getopt.o man.o manpath.o to_cat.o: defs.h
+different.o man.o: different.h
+man.o manfile.o: glob.h
+different.o gripes.o man-config.o man-getopt.o man.o manfile.o manpath.o util.o: gripes.h gripedefs.h
+different.o man-config.o man-getopt.o man.o manpath.o: man-config.h
+gripes.o man-config.o man-getopt.o man.o manpath.o util.o: man.h
+man-getopt.o man.o manpath.o: man-getopt.h
+man.o manfile.o to_cat.o: manfile.h
+man.o man-iconv.o: man-iconv.h
+man.o manpath.o: manpath.h
+man-config.o: paths.h
+different.o man-config.o man-getopt.o man.o manpath.o util.o: util.h
+man-getopt.o: version.h
+msg.o: msg.c
+gripes.o: ../catopen/catopen.c
+
+man.conf: man.conf.in ../conf_script
+ ../conf_script man.conf
+
+paths.h: paths.h.in ../conf_script
+ ../conf_script paths.h
+
+version.h: ../version Makefile
+ vers=`sed -e s/man-// ../version`; \
+ echo "static char version[] = \"$$vers\";" > version.h
+
+apropos: apropos.sh Makefile
+ rm -f apropos
+ sed -e 's,%apropos_or_whatis%,apropos,' \
+ -e 's,%version%,man-1.6g,' \
+ -e 's,%manpathoption%,--path,' \
+ apropos.sh > apropos
+ chmod +x apropos
+
+whatis: apropos.sh Makefile
+ rm -f whatis
+ sed -e 's,%apropos_or_whatis%,whatis,' \
+ -e 's,%version%,man-1.6g,' \
+ -e 's,%manpathoption%,--path,' \
+ apropos.sh > whatis
+ chmod +x whatis
+
+makewhatis: makewhatis.sh Makefile
+ rm -f makewhatis
+ cp makewhatis.sh makewhatis.in
+ ../conf_script makewhatis
+ chmod +x makewhatis
+
+MANCONFIG=$(DESTDIR)$(PREFIX)/usr/share/misc/man.conf
+
+install: all apropos whatis makewhatis
+ mkdir -p $(DESTDIR)$(PREFIX)/usr/bin
+ $(INSTALL) -c man$(EXEEXT) $(DESTDIR)$(PREFIX)/usr/bin/man
+ $(INSTALL) -c -m 755 apropos $(DESTDIR)$(PREFIX)/usr/bin/apropos
+ $(INSTALL) -c -m 755 whatis $(DESTDIR)$(PREFIX)/usr/bin/whatis
+ $(INSTALL) -c -m 755 man2dvi $(DESTDIR)$(PREFIX)/usr/bin/man2dvi
+ mkdir -p $(DESTDIR)$(PREFIX)/usr/sbin
+ $(INSTALL) -c -m 754 makewhatis $(DESTDIR)$(PREFIX)/usr/sbin/makewhatis
+ mkdir -p $(DESTDIR)$(PREFIX)/usr/share/misc
+ if [ -f $(MANCONFIG) ]; then mv $(MANCONFIG) $(MANCONFIG).orig; fi
+ $(INSTALL) -c -m 644 man.conf $(MANCONFIG)
+
+clean:
+ rm -f *.o *~ core man$(EXEEXT) apropos whatis makewhatis makemsg
+
+spotless: clean
+ rm -f Makefile config.status paths.h version.h man.conf
+ rm -f gripedefs.h msg.c mess.*.cat
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..0b08305
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,120 @@
+#
+# Master Makefile for man, apropos, whatis, and makewhatis
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+# Copyright (c) 1994-2001, Andries E. Brouwer
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man 1.0
+# distribution.
+#
+# various changes - aeb, March 1994
+# use of catalogs - aeb, June 1994
+
+CC = @CC@
+BUILD_CC = @BUILD_CC@
+INSTALL = @INSTALL@
+EXEEXT = @EXEEXT@
+
+pager = @pager@
+
+DEFS = @DEFS@
+CWARN = -Wall -Wstrict-prototypes -Wmissing-prototypes
+CWARNNP = -Wall
+
+.c.o:
+ $(CC) -c $(CWARN) $(CFLAGS) -I. $(DEFS) $<
+
+# LDFLAGS = -g
+LDFLAGS ?= -s
+
+LIBOBJS = @LIBOBJS@
+
+all: man$(EXEEXT) man.conf apropos whatis makewhatis
+
+MANOBJS = man.o manfile.o manpath.o man-config.o man-getopt.o \
+ man-iconv.o to_cat.o different.o gripes.o glob.o util.o msg.o
+
+man$(EXEEXT): $(MANOBJS) $(LIBOBJS)
+ $(CC) $(LDFLAGS) -o man$(EXEEXT) $(MANOBJS) $(LIBOBJS) $(LIBS)
+
+# CC may be a cross compiler, but BUILD_CC must compile for
+# the present machine.
+makemsg:
+ $(BUILD_CC) -o makemsg makemsg.c
+
+msg.c gripedefs.h: ../msgs/mess.en makemsg
+ ./makemsg ../msgs/mess.en gripedefs.h msg.c
+
+# glob.c does not have prototypes
+glob.o: glob.c ndir.h
+ $(CC) -c $(CWARNNP) $(CFLAGS) -I. $(DEFS) glob.c
+
+man-config.o man-getopt.o man.o manpath.o to_cat.o: defs.h
+different.o man.o: different.h
+man.o manfile.o: glob.h
+different.o gripes.o man-config.o man-getopt.o man.o manfile.o manpath.o util.o: gripes.h gripedefs.h
+different.o man-config.o man-getopt.o man.o manpath.o: man-config.h
+gripes.o man-config.o man-getopt.o man.o manpath.o util.o: man.h
+man-getopt.o man.o manpath.o: man-getopt.h
+man.o manfile.o to_cat.o: manfile.h
+man.o man-iconv.o: man-iconv.h
+man.o manpath.o: manpath.h
+man-config.o: paths.h
+different.o man-config.o man-getopt.o man.o manpath.o util.o: util.h
+man-getopt.o: version.h
+msg.o: msg.c
+gripes.o: ../catopen/catopen.c
+
+man.conf: man.conf.in ../conf_script
+ ../conf_script man.conf
+
+paths.h: paths.h.in ../conf_script
+ ../conf_script paths.h
+
+version.h: ../version Makefile
+ vers=`sed -e s/man-// ../version`; \
+ echo "static char version[] = \"$$vers\";" > version.h
+
+apropos: apropos.sh Makefile
+ rm -f apropos
+ sed -e 's,%apropos_or_whatis%,apropos,' \
+ -e 's,%version%,@version@,' \
+ -e 's,%manpathoption%,@manpathoption@,' \
+ apropos.sh > apropos
+ chmod +x apropos
+
+whatis: apropos.sh Makefile
+ rm -f whatis
+ sed -e 's,%apropos_or_whatis%,whatis,' \
+ -e 's,%version%,@version@,' \
+ -e 's,%manpathoption%,@manpathoption@,' \
+ apropos.sh > whatis
+ chmod +x whatis
+
+makewhatis: makewhatis.sh Makefile
+ rm -f makewhatis
+ cp makewhatis.sh makewhatis.in
+ ../conf_script makewhatis
+ chmod +x makewhatis
+
+MANCONFIG=$(DESTDIR)$(PREFIX)@man_config_file@
+
+install: all apropos whatis makewhatis
+ mkdir -p $(DESTDIR)$(PREFIX)@bindir@
+ $(INSTALL) -c @man_install_flags@ man$(EXEEXT) $(DESTDIR)$(PREFIX)@man@
+ $(INSTALL) -c -m 755 apropos $(DESTDIR)$(PREFIX)@apropos@
+ $(INSTALL) -c -m 755 whatis $(DESTDIR)$(PREFIX)@whatis@
+ $(INSTALL) -c -m 755 man2dvi $(DESTDIR)$(PREFIX)@man2dvi@
+ mkdir -p $(DESTDIR)$(PREFIX)@sbindir@
+ $(INSTALL) -c -m 754 makewhatis $(DESTDIR)$(PREFIX)@makewhatis@
+ mkdir -p $(DESTDIR)$(PREFIX)@man_config_dir@
+ if [ -f $(MANCONFIG) ]; then mv $(MANCONFIG) $(MANCONFIG).orig; fi
+ $(INSTALL) -c -m 644 man.conf $(MANCONFIG)
+
+clean:
+ rm -f *.o *~ core man$(EXEEXT) apropos whatis makewhatis makemsg
+
+spotless: clean
+ rm -f Makefile config.status paths.h version.h man.conf
+ rm -f gripedefs.h msg.c mess.*.cat
diff --git a/src/apropos b/src/apropos
new file mode 100755
index 0000000..a85968a
--- /dev/null
+++ b/src/apropos
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# apropos -- search the whatis database for keywords.
+# whatis -- idem, but match only commands (as whole words).
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+# Copyright (c) 1994-1999, Andries E. Brouwer.
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man
+# distribution.
+#
+# apropos/whatis-1.5m aeb 2003-08-01 (from man-1.6g)
+#
+# keep old PATH - 000323 - Bryan Henderson
+# also look in /var/cache/man - 030801 - aeb
+
+program=`basename $0`
+
+# When man pages in your favorite locale look to grep like binary files
+# (and you use GNU grep) you may want to add the 'a' option to *grepopt1.
+aproposgrepopt1='i'
+aproposgrepopt2=''
+whatisgrepopt1='iw'
+whatisgrepopt2='^'
+grepopt1=$aproposgrepopt1
+grepopt2=$aproposgrepopt2
+
+if [ $# = 0 ]
+then
+ echo "usage: $program keyword ..."
+ exit 1
+fi
+
+manpath=`man --path | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "$program: manpath is null"
+ exit 1
+fi
+
+args=
+for arg in $*; do
+ case $arg in
+ --version|-V|-v)
+ echo "$program from man-1.6g"
+ exit 0
+ ;;
+ --help|-h)
+ echo "usage: $program keyword ..."
+ exit 0
+ ;;
+ -*)
+ echo "$program: $arg: unknown option"
+ exit 1
+ ;;
+ *)
+ args="$args $arg"
+ esac
+done
+
+while [ "$1" != "" ]
+do
+ found=0
+ for d in /var/cache/man $manpath /usr/lib
+ do
+ if [ -f $d/whatis ]
+ then
+ if grep -"$grepopt1" "$grepopt2""$1" $d/whatis
+ then
+ found=1
+# Some people are satisfied with a single occurrence
+# But it is better to give all
+# break
+ fi
+ fi
+ done
+
+ if [ $found = 0 ]
+ then
+ echo "$1: nothing appropriate"
+ fi
+
+ shift
+done
+
+exit
diff --git a/src/apropos.sh b/src/apropos.sh
new file mode 100644
index 0000000..f4b88ea
--- /dev/null
+++ b/src/apropos.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# apropos -- search the whatis database for keywords.
+# whatis -- idem, but match only commands (as whole words).
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+# Copyright (c) 1994-1999, Andries E. Brouwer.
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man
+# distribution.
+#
+# apropos/whatis-1.5m aeb 2003-08-01 (from %version%)
+#
+# keep old PATH - 000323 - Bryan Henderson
+# also look in /var/cache/man - 030801 - aeb
+
+program=`basename $0`
+
+# When man pages in your favorite locale look to grep like binary files
+# (and you use GNU grep) you may want to add the 'a' option to *grepopt1.
+aproposgrepopt1='i'
+aproposgrepopt2=''
+whatisgrepopt1='iw'
+whatisgrepopt2='^'
+grepopt1=$%apropos_or_whatis%grepopt1
+grepopt2=$%apropos_or_whatis%grepopt2
+
+if [ $# = 0 ]
+then
+ echo "usage: $program keyword ..."
+ exit 1
+fi
+
+manpath=`man %manpathoption% | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "$program: manpath is null"
+ exit 1
+fi
+
+args=
+for arg in $*; do
+ case $arg in
+ --version|-V|-v)
+ echo "$program from %version%"
+ exit 0
+ ;;
+ --help|-h)
+ echo "usage: $program keyword ..."
+ exit 0
+ ;;
+ -*)
+ echo "$program: $arg: unknown option"
+ exit 1
+ ;;
+ *)
+ args="$args $arg"
+ esac
+done
+
+while [ "$1" != "" ]
+do
+ found=0
+ for d in /var/cache/man $manpath /usr/lib
+ do
+ if [ -f $d/whatis ]
+ then
+ if grep -"$grepopt1" "$grepopt2""$1" $d/whatis
+ then
+ found=1
+# Some people are satisfied with a single occurrence
+# But it is better to give all
+# break
+ fi
+ fi
+ done
+
+ if [ $found = 0 ]
+ then
+ echo "$1: nothing appropriate"
+ fi
+
+ shift
+done
+
+exit
diff --git a/src/defs.h b/src/defs.h
new file mode 100644
index 0000000..f33c05d
--- /dev/null
+++ b/src/defs.h
@@ -0,0 +1,26 @@
+/* defs.h */
+#undef MAXPATHLEN /* make sure struct dirs has a
+ well-defined size (thanks to
+ Pierre.Humblet@eurecom.fr) */
+#include <sys/param.h>
+
+#define MAN 0
+#define CAT 1
+#define SCAT 2
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+struct dir {
+ struct dir *nxt;
+ char *dir;
+};
+
+struct dirs {
+ struct dirs *nxt;
+ char mandir[MAXPATHLEN];
+ char catdir[MAXPATHLEN];
+ char bindir[MAXPATHLEN];
+ int mandatory;
+};
diff --git a/src/different.c b/src/different.c
new file mode 100644
index 0000000..cfce5fb
--- /dev/null
+++ b/src/different.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "different.h"
+#include "gripes.h"
+#include "man-config.h"
+#include "util.h"
+
+static struct filelist {
+ char *pathname;
+ struct filelist *next;
+} cat_list, man_list;
+
+static int
+is_different(const char *file, struct filelist *p) {
+ char *command;
+ const char *cmp = getval("CMP");
+ int ret;
+
+ if (cmp) {
+ while (p->next) {
+ command = my_xsprintf("%s %S %S\n", cmp, file, p->pathname);
+ ret = do_system_command (command, 1);
+ if (ret == 0) {
+ gripe(IDENTICAL, file, p->pathname);
+ return 0;
+ }
+ p = p->next;
+ }
+ p->next = (struct filelist *) my_malloc(sizeof(struct filelist));
+ p->pathname = my_strdup(file);
+ p->next->next = 0;
+ }
+ return 1;
+}
+
+static int
+free_filelist (struct filelist *list){
+struct filelist *current, *next;
+
+ current = list;
+ if (current != list)
+ do {
+ next = current->next;
+ if (current != list)
+ free(current);
+ current = next;
+ } while (current->next != NULL);
+
+ list->next = NULL;
+
+ return 0;
+}
+
+int
+different_cat_file (const char *file) {
+ return is_different (file, &cat_list);
+}
+
+int
+different_man_file (const char *file) {
+ return is_different (file, &man_list);
+}
+
+int
+free_catman_filelists (void){
+
+ free_filelist(&man_list);
+ free_filelist(&cat_list);
+return 0;
+}
diff --git a/src/different.h b/src/different.h
new file mode 100644
index 0000000..e952500
--- /dev/null
+++ b/src/different.h
@@ -0,0 +1,3 @@
+int different_cat_file (const char *file);
+int different_man_file (const char *file);
+int free_catman_filelists (void);
diff --git a/src/glob.c b/src/glob.c
new file mode 100644
index 0000000..71b93d7
--- /dev/null
+++ b/src/glob.c
@@ -0,0 +1,682 @@
+/* File-name wildcard pattern matching for GNU.
+ Copyright (C) 1985, 1988, 1989, 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* To whomever it may concern: I have never seen the code which most
+ Unix programs use to perform this function. I wrote this from scratch
+ based on specifications for the pattern matching. --RMS. */
+
+#ifdef SHELL
+#include "config.h"
+#endif /* SHELL */
+
+#include <sys/types.h>
+
+#if defined (USGr3) && !defined (DIRENT)
+#define DIRENT
+#endif /* USGr3 */
+#if defined (Xenix) && !defined (SYSNDIR)
+#define SYSNDIR
+#endif /* Xenix */
+
+#if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
+#include <dirent.h>
+#define direct dirent
+#define D_NAMLEN(d) strlen((d)->d_name)
+#else /* not POSIX or DIRENT or __GNU_LIBRARY__ */
+#define D_NAMLEN(d) ((d)->d_namlen)
+#ifdef USG
+#if defined (SYSNDIR)
+#include <sys/ndir.h>
+#else /* SYSNDIR */
+#include "ndir.h"
+#endif /* not SYSNDIR */
+#else /* not USG */
+#include <sys/dir.h>
+#endif /* USG */
+#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
+
+#ifdef __QNX__
+#define REAL_DIR_ENTRY(dp) (dp->d_stat.st_ino != 0)
+#elif defined (_POSIX_SOURCE)
+/* Posix does not require that the d_ino field be present, and some
+ systems do not provide it. */
+#define REAL_DIR_ENTRY(dp) 1
+#else
+#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+#endif /* _POSIX_SOURCE */
+
+#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)
+#include <stdlib.h>
+#include <string.h>
+#define STDC_STRINGS
+#else /* STDC_HEADERS or __GNU_LIBRARY__ */
+
+#if defined (USG)
+#include <string.h>
+#ifndef POSIX
+#include <memory.h>
+#endif /* POSIX */
+#define STDC_STRINGS
+#else /* not USG */
+#ifdef NeXT
+#include <string.h>
+#else /* NeXT */
+#include <strings.h>
+#endif /* NeXT */
+/* Declaring bcopy causes errors on systems whose declarations are different.
+ If the declaration is omitted, everything works fine. */
+#endif /* not USG */
+
+extern char *malloc ();
+extern char *realloc ();
+extern void free ();
+
+#ifndef NULL
+#define NULL 0
+#endif
+#endif /* Not STDC_HEADERS or __GNU_LIBRARY__. */
+
+#ifdef STDC_STRINGS
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#define index strchr
+#define rindex strrchr
+#endif /* STDC_STRINGS */
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* Not GCC. */
+#ifdef sparc
+#include <alloca.h>
+#else /* Not sparc. */
+extern char *alloca ();
+#endif /* sparc. */
+#endif /* GCC. */
+#endif
+
+/* Nonzero if '*' and '?' do not match an initial '.' for glob_filename. */
+int noglob_dot_filenames = 1;
+
+static int glob_match_after_star ();
+
+/* Return nonzero if PATTERN has any special globbing chars in it. */
+
+int
+glob_pattern_p (pattern)
+ char *pattern;
+{
+ register char *p = pattern;
+ register char c;
+ int open = 0;
+
+ while ((c = *p++) != '\0')
+ switch (c)
+ {
+ case '?':
+ case '*':
+ return 1;
+
+ case '[': /* Only accept an open brace if there is a close */
+ open++; /* brace to match it. Bracket expressions must be */
+ continue; /* complete, according to Posix.2 */
+ case ']':
+ if (open)
+ return 1;
+ continue;
+
+ case '\\':
+ if (*p++ == '\0')
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/* Match the pattern PATTERN against the string TEXT;
+ return 1 if it matches, 0 otherwise.
+
+ A match means the entire string TEXT is used up in matching.
+
+ In the pattern string, `*' matches any sequence of characters,
+ `?' matches any character, [SET] matches any character in the specified set,
+ [!SET] matches any character not in the specified set.
+
+ A set is composed of characters or ranges; a range looks like
+ character hyphen character (as in 0-9 or A-Z).
+ [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
+ Any other character in the pattern must be matched exactly.
+
+ To suppress the special syntactic significance of any of `[]*?!-\',
+ and match the character exactly, precede it with a `\'.
+
+ If DOT_SPECIAL is nonzero,
+ `*' and `?' do not match `.' at the beginning of TEXT. */
+
+int
+glob_match (pattern, text, dot_special)
+ char *pattern, *text;
+ int dot_special;
+{
+ register char *p = pattern, *t = text;
+ register char c;
+
+ while ((c = *p++) != '\0')
+ switch (c)
+ {
+ case '?':
+ if (*t == '\0' || (dot_special && t == text && *t == '.'))
+ return 0;
+ else
+ ++t;
+ break;
+
+ case '\\':
+ if (*p++ != *t++)
+ return 0;
+ break;
+
+ case '*':
+ if (dot_special && t == text && *t == '.')
+ return 0;
+ return glob_match_after_star (p, t);
+
+ case '[':
+ {
+ register char c1 = *t++;
+ int invert;
+
+ if (c1 == '\0')
+ return 0;
+
+ invert = (*p == '!');
+
+ if (invert)
+ p++;
+
+ c = *p++;
+ while (1)
+ {
+ register char cstart = c, cend = c;
+
+ if (c == '\\')
+ {
+ cstart = *p++;
+ cend = cstart;
+ }
+
+ if (cstart == '\0')
+ return 0; /* Missing ']'. */
+
+ c = *p++;
+
+ if (c == '-')
+ {
+ cend = *p++;
+ if (cend == '\\')
+ cend = *p++;
+ if (cend == '\0')
+ return 0;
+ c = *p++;
+ }
+ if (c1 >= cstart && c1 <= cend)
+ goto match;
+ if (c == ']')
+ break;
+ }
+ if (!invert)
+ return 0;
+ break;
+
+ match:
+ /* Skip the rest of the [...] construct that already matched. */
+ while (c != ']')
+ {
+ if (c == '\0')
+ return 0;
+ c = *p++;
+ if (c == '\0')
+ return 0;
+ if (c == '\\')
+ p++;
+ }
+ if (invert)
+ return 0;
+ break;
+ }
+
+ default:
+ if (c != *t++)
+ return 0;
+ }
+
+ return *t == '\0';
+}
+
+/* Like glob_match, but match PATTERN against any final segment of TEXT. */
+
+static int
+glob_match_after_star (pattern, text)
+ char *pattern, *text;
+{
+ register char *p = pattern, *t = text;
+ register char c, c1;
+
+ while ((c = *p++) == '?' || c == '*')
+ if (c == '?' && *t++ == '\0')
+ return 0;
+
+ if (c == '\0')
+ return 1;
+
+ if (c == '\\')
+ c1 = *p;
+ else
+ c1 = c;
+
+ --p;
+ while (1)
+ {
+ if ((c == '[' || *t == c1) && glob_match (p, t, 0))
+ return 1;
+ if (*t++ == '\0')
+ return 0;
+ }
+}
+
+/* Return a vector of names of files in directory DIR
+ whose names match glob pattern PAT.
+ The names are not in any particular order.
+ Wildcards at the beginning of PAT do not match an initial period
+ if noglob_dot_filenames is nonzero.
+
+ The vector is terminated by an element that is a null pointer.
+
+ To free the space allocated, first free the vector's elements,
+ then free the vector.
+
+ Return NULL if cannot get enough memory to hold the pointer
+ and the names.
+
+ Return -1 if cannot access directory DIR.
+ Look in errno for more information. */
+
+char **
+glob_vector (pat, dir)
+ char *pat;
+ char *dir;
+{
+ struct globval
+ {
+ struct globval *next;
+ char *name;
+ };
+
+ DIR *d;
+ register struct direct *dp;
+ struct globval *lastlink;
+ register struct globval *nextlink;
+ register char *nextname;
+ unsigned int count;
+ int lose;
+ register char **name_vector = 0;
+ register unsigned int i;
+#ifdef ALLOCA_MISSING
+ struct globval *templink;
+#endif
+
+ d = opendir (dir);
+ if (d == NULL)
+ return (char **) -1;
+
+ lastlink = NULL;
+ count = 0;
+ lose = 0;
+
+ /* Scan the directory, finding all names that match.
+ For each name that matches, allocate a struct globval
+ on the stack and store the name in it.
+ Chain those structs together; lastlink is the front of the chain. */
+ while (1)
+ {
+#if defined (SHELL)
+ /* Make globbing interruptible in the bash shell. */
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ {
+ closedir (d);
+ lose = 1;
+ goto lost;
+ }
+#endif /* SHELL */
+
+ dp = readdir (d);
+ if (dp == NULL)
+ break;
+ if (REAL_DIR_ENTRY (dp)
+ && glob_match (pat, dp->d_name, noglob_dot_filenames))
+ {
+#ifdef ALLOCA_MISSING
+ nextlink = (struct globval *) malloc (sizeof (struct globval));
+#else
+ nextlink = (struct globval *) alloca (sizeof (struct globval));
+#endif
+ nextlink->next = lastlink;
+ i = D_NAMLEN (dp) + 1;
+ nextname = (char *) malloc (i);
+ if (nextname == NULL)
+ {
+ lose = 1;
+ break;
+ }
+ lastlink = nextlink;
+ nextlink->name = nextname;
+ bcopy (dp->d_name, nextname, i);
+ count++;
+ }
+ }
+ closedir (d);
+
+ if (!lose)
+ {
+ name_vector = (char **) malloc ((count + 1) * sizeof (char *));
+ lose |= name_vector == NULL;
+ }
+
+ /* Have we run out of memory? */
+#ifdef SHELL
+ lost:
+#endif
+ if (lose)
+ {
+ /* Here free the strings we have got. */
+ while (lastlink)
+ {
+ free (lastlink->name);
+#ifdef ALLOCA_MISSING
+ templink = lastlink->next;
+ free ((char *) lastlink);
+ lastlink = templink;
+#else
+ lastlink = lastlink->next;
+#endif
+ }
+ return NULL;
+ }
+
+ /* Copy the name pointers from the linked list into the vector. */
+ for (i = 0; i < count; ++i)
+ {
+ name_vector[i] = lastlink->name;
+#ifdef ALLOCA_MISSING
+ templink = lastlink->next;
+ free ((char *) lastlink);
+ lastlink = templink;
+#else
+ lastlink = lastlink->next;
+#endif
+ }
+
+ name_vector[count] = NULL;
+ return name_vector;
+}
+
+/* Return a new array, replacing ARRAY, which is the concatenation
+ of each string in ARRAY to DIR.
+ Return NULL if out of memory. */
+
+static char **
+glob_dir_to_array (dir, array)
+ char *dir, **array;
+{
+ register unsigned int i, l;
+ int add_slash = 0;
+ char **result;
+
+ l = strlen (dir);
+ if (l == 0)
+ return array;
+
+ if (dir[l - 1] != '/')
+ add_slash++;
+
+ for (i = 0; array[i] != NULL; i++)
+ ;
+
+ result = (char **) malloc ((i + 1) * sizeof (char *));
+ if (result == NULL)
+ return NULL;
+
+ for (i = 0; array[i] != NULL; i++)
+ {
+ result[i] = (char *) malloc (1 + l + add_slash + strlen (array[i]));
+ if (result[i] == NULL)
+ return NULL;
+ strcpy (result[i], dir);
+ if (add_slash)
+ result[i][l] = '/';
+ strcpy (result[i] + l + add_slash, array[i]);
+ }
+ result[i] = NULL;
+
+ /* Free the input array. */
+ for (i = 0; array[i] != NULL; i++)
+ free (array[i]);
+ free ((char *) array);
+ return result;
+}
+
+/* Do globbing on PATHNAME. Return an array of pathnames that match,
+ marking the end of the array with a null-pointer as an element.
+ If no pathnames match, then the array is empty (first element is null).
+ If there isn't enough memory, then return NULL.
+ If a file system error occurs, return -1; `errno' has the error code.
+
+ Wildcards at the beginning of PAT, or following a slash,
+ do not match an initial period if noglob_dot_filenames is nonzero. */
+
+char **
+glob_filename (const char *pathname)
+{
+ char **result;
+ unsigned int result_size;
+ char *directory_name;
+ const char *filename;
+ unsigned int directory_len;
+
+ result = (char **) malloc (sizeof (char *));
+ result_size = 1;
+ if (result == NULL)
+ return NULL;
+
+ result[0] = NULL;
+
+ /* Find the filename. */
+ filename = rindex (pathname, '/');
+ if (filename == NULL)
+ {
+ filename = pathname;
+ directory_name = "";
+ directory_len = 0;
+ }
+ else
+ {
+ directory_len = (filename - pathname) + 1;
+#ifdef ALLOCA_MISSING
+ directory_name = (char *) malloc (directory_len + 1);
+#else
+ directory_name = (char *) alloca (directory_len + 1);
+#endif
+ bcopy (pathname, directory_name, directory_len);
+ directory_name[directory_len] = '\0';
+ ++filename;
+ }
+
+ /* If directory_name contains globbing characters, then we
+ have to expand the previous levels. Just recurse. */
+ if (glob_pattern_p (directory_name))
+ {
+ char **directories;
+ register unsigned int i;
+
+ if (directory_name[directory_len - 1] == '/')
+ directory_name[directory_len - 1] = '\0';
+
+ directories = glob_filename (directory_name);
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ if (directories == NULL)
+ goto memory_error;
+ else if (directories == (char **) -1)
+ return (char **) -1;
+ else if (*directories == NULL)
+ {
+ free ((char *) directories);
+ return (char **) -1;
+ }
+
+ /* We have successfully globbed the preceding directory name.
+ For each name in DIRECTORIES, call glob_vector on it and
+ FILENAME. Concatenate the results together. */
+ for (i = 0; directories[i] != NULL; i++)
+ {
+ char **temp_results = glob_vector (filename, directories[i]);
+ if (temp_results == NULL)
+ goto memory_error;
+ else if (temp_results == (char **) -1)
+ /* This filename is probably not a directory. Ignore it. */
+ ;
+ else
+ {
+ char **array = glob_dir_to_array (directories[i], temp_results);
+ register unsigned int l;
+
+ l = 0;
+ while (array[l] != NULL)
+ ++l;
+
+ result = (char **) realloc (result,
+ (result_size + l) * sizeof (char *));
+ if (result == NULL)
+ goto memory_error;
+
+ for (l = 0; array[l] != NULL; ++l)
+ result[result_size++ - 1] = array[l];
+ result[result_size - 1] = NULL;
+ free ((char *) array);
+ }
+ }
+ /* Free the directories. */
+ for (i = 0; directories[i] != NULL; i++)
+ free (directories[i]);
+ free ((char *) directories);
+
+ return result;
+ }
+
+ /* If there is only a directory name, return it. */
+ if (*filename == '\0')
+ {
+ result = (char **) realloc ((char *) result, 2 * sizeof (char *));
+ if (result != NULL)
+ {
+ result[0] = (char *) malloc (directory_len + 1);
+ if (result[0] == NULL)
+ {
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ goto memory_error;
+ }
+ bcopy (directory_name, result[0], directory_len + 1);
+ result[1] = NULL;
+ }
+#ifdef ALLOCA_MISSING
+ free ((char *) directory_name);
+#endif
+ return result;
+ }
+ else
+ {
+ /* Otherwise, just return what glob_vector
+ returns appended to the directory name. */
+ char **temp_results = glob_vector (filename,
+ (directory_len == 0
+ ? "." : directory_name));
+
+ if (temp_results == NULL || temp_results == (char **) -1)
+ {
+#ifdef NO_ALLOCA
+ free ((char *) directory_name);
+#endif
+ return temp_results;
+ }
+
+ temp_results = glob_dir_to_array (directory_name, temp_results);
+#ifdef NO_ALLOCA
+ free ((char *) directory_name);
+#endif
+ return temp_results;
+ }
+
+ /* We get to memory error if the program has run out of memory, or
+ if this is the shell, and we have been interrupted. */
+ memory_error:
+ if (result != NULL)
+ {
+ register unsigned int i;
+ for (i = 0; result[i] != NULL; ++i)
+ free (result[i]);
+ free ((char *) result);
+ }
+#if defined (SHELL)
+ {
+ extern int interrupt_state;
+
+ if (interrupt_state)
+ throw_to_top_level ();
+ }
+#endif /* SHELL */
+ return NULL;
+}
+
+#ifdef TEST
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char **value;
+ int i, optind;
+
+ for (optind = 1; optind < argc; optind++)
+ {
+ value = glob_filename (argv[optind]);
+ if (value == NULL)
+ puts ("virtual memory exhausted");
+ else if (value == (char **) -1)
+ perror (argv[optind]);
+ else
+ for (i = 0; value[i] != NULL; i++)
+ puts (value[i]);
+ }
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/glob.h b/src/glob.h
new file mode 100644
index 0000000..fd6e07c
--- /dev/null
+++ b/src/glob.h
@@ -0,0 +1 @@
+char **glob_filename (const char *);
diff --git a/src/gripedefs.h b/src/gripedefs.h
new file mode 100644
index 0000000..57aa898
--- /dev/null
+++ b/src/gripedefs.h
@@ -0,0 +1,87 @@
+#define BAD_CONFIG_FILE 1
+#define CONFIG_OPEN_ERROR 2
+#define PARSE_ERROR_IN_CONFIG 3
+#define INCOMPAT 4
+#define NO_ALTERNATE 5
+#define NO_COMPRESS 6
+#define NO_NAME_FROM_SECTION 7
+#define NO_NAME_NO_SECTION 8
+#define NO_SUCH_ENTRY_IN_SECTION 9
+#define NO_SUCH_ENTRY 10
+#define PAGER_IS 11
+#define SYSTEM_FAILED 12
+#define VERSION 13
+#define OUT_OF_MEMORY 14
+#define ROFF_CMD_FROM_FILE_ERROR 15
+#define MANROFFSEQ_ERROR 16
+#define ROFF_CMD_FROM_COMMANDLINE_ERROR 17
+#define UNRECOGNIZED_LINE 18
+#define GETVAL_ERROR 19
+#define FOUND_MANDIR 20
+#define FOUND_MAP 21
+#define FOUND_CATDIR 22
+#define LINE_TOO_LONG 23
+#define SECTION 24
+#define UNLINKED 25
+#define GLOBBING 26
+#define EXPANSION_FAILED 27
+#define OPEN_ERROR 28
+#define READ_ERROR 29
+#define FOUND_EQN 30
+#define FOUND_GRAP 31
+#define FOUND_PIC 32
+#define FOUND_TBL 33
+#define FOUND_VGRIND 34
+#define FOUND_REFER 35
+#define ROFF_FROM_COMMAND_LINE 36
+#define ROFF_FROM_FILE 37
+#define ROFF_FROM_ENV 38
+#define USING_DEFAULT 39
+#define PLEASE_WAIT 40
+#define CHANGED_MODE 41
+#define CAT_OPEN_ERROR 42
+#define PROPOSED_CATFILE 43
+#define IS_NEWER_RESULT 44
+#define TRYING_SECTION 45
+#define SEARCHING 46
+#define ALREADY_IN_MANPATH 47
+#define CANNOT_STAT 48
+#define IS_NO_DIR 49
+#define ADDING_TO_MANPATH 50
+#define PATH_DIR 51
+#define IS_IN_CONFIG 52
+#define IS_NOT_IN_CONFIG 53
+#define MAN_NEARBY 54
+#define NO_MAN_NEARBY 55
+#define ADDING_MANDIRS 56
+#define CATNAME_IS 57
+#define NO_EXEC 58
+#define USAGE1 59
+#define USAGE2 60
+#define USAGE3 61
+#define USAGE4 62
+#define USAGE5 63
+#define USAGE6 64
+#define USAGE7 65
+#define USAGE8 66
+#define USER_CANNOT_OPEN_CAT 67
+#define USER_CAN_OPEN_CAT 68
+#define CANNOT_FORK 69
+#define WAIT_FAILED 70
+#define GOT_WRONG_PID 71
+#define CHILD_TERMINATED_ABNORMALLY 72
+#define IDENTICAL 73
+#define MAN_FOUND 74
+#define NO_TROFF 75
+#define NO_CAT_FOR_NONSTD_LL 76
+#define BROWSER_IS 77
+#define HTMLPAGER_IS 78
+#define FOUND_FILE 79
+#define CALLTRACE1 80
+#define CALLTRACE2 81
+#define NO_MATCH 82
+#define GLOB_FOR_FILE 83
+#define CALLTRACE3 84
+#define ABOUT_TO_GLOB 85
+
+#define MAXMSG 85
diff --git a/src/gripes.c b/src/gripes.c
new file mode 100644
index 0000000..505f8b8
--- /dev/null
+++ b/src/gripes.c
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "gripes.h"
+#include "man.h" /* for progname */
+
+extern char *msg[];
+
+static char *mantexts = "man"; /* e.g. /usr/lib/locale/%L/man.cat */
+
+#ifdef NONLS
+
+static char *
+getmsg (int n) {
+ char *s;
+
+ if (0 < n && n <= MAXMSG)
+ s = msg[n];
+ else {
+ fprintf (stderr, "man: internal error - cannot find message %d\n", n);
+ exit (1);
+ }
+ return s;
+}
+
+#else /* NONLS */
+
+#include <string.h>
+#include <nl_types.h>
+#include "../catopen/catopen.c"
+
+nl_catd catfd = (nl_catd) -1;
+int cat_is_open = 0;
+
+static void
+catinit (void) {
+ if (!cat_is_open) {
+#ifdef NL_CAT_LOCALE
+ catfd = my_catopen(mantexts,NL_CAT_LOCALE);
+#else
+ catfd = my_catopen(mantexts,0);
+#endif
+ if (catfd == (nl_catd) -1) {
+ /*
+ * Only complain if LANG exists, and LANG != "en"
+ * (or when debugging). Also accept en_ZA etc.
+ * No messages for C locale.
+ */
+ char *s, *lg;
+ s = getenv("NLSPATH");
+ lg = getenv("LANG");
+ if (!lg)
+ lg = getenv("LC_MESSAGES");
+ if (!lg)
+ lg = getenv("LC_ALL");
+ if (lg && strncmp(lg, "en", 2) && strcmp(lg, "C") && strcmp(lg, "POSIX")) {
+ fprintf(stderr,
+ "Cannot open the message catalog \"%s\" for locale \"%s\"\n"
+ "(NLSPATH=\"%s\")\n\n",
+ mantexts, lg, s ? s : "<none>");
+ } else if (debug) {
+ fprintf(stderr,
+"Looked whether there exists a message catalog %s, but there is none\n"
+"(and for English messages none is needed)\n\n",
+ mantexts);
+ }
+ }
+ }
+ cat_is_open = 1;
+}
+
+/*
+ * This routine is unnecessary, but people ask for such things.
+ *
+ * Maybe man is suid or sgid to some user that owns the cat directories.
+ * Maybe NLSPATH can be manipulated by the user - even though
+ * modern glibc avoids using environment variables when the
+ * program is suid or sgid.
+ * So, maybe the string s that we are returning was user invented
+ * and we have to avoid %n and the like.
+ *
+ * As a random hack, only allow %s,%d,%o, and only two %-signs.
+ */
+static int
+is_suspect (char *s) {
+ int ct = 0;
+
+ while (*s) {
+ if (*s++ == '%') {
+ ct++;
+ if (*s != 's' && *s != 'd' && *s != 'o')
+ return 1;
+ }
+ }
+ return (ct > 2);
+}
+
+static char *
+getmsg (int n) {
+ char *s = "";
+
+ catinit ();
+ if (catfd != (nl_catd) -1) {
+ s = catgets(catfd, 1, n, "");
+ if (*s && is_suspect(s))
+ s = "";
+ }
+ if (*s == 0 && 0 < n && n <= MAXMSG)
+ s = msg[n];
+ if (*s == 0) {
+ fprintf(stderr,
+ "man: internal error - cannot find message %d\n", n);
+ exit (1);
+ }
+ return s;
+}
+
+#endif /* NONLS */
+
+void
+gripe (int n, ...) {
+ va_list p;
+
+ va_start(p, n);
+ vfprintf (stderr, getmsg(n), p);
+ va_end(p);
+ fflush (stderr);
+}
+
+void
+fatal (int n, ...) {
+ va_list p;
+ fprintf (stderr, "%s: ", progname);
+ va_start(p, n);
+ vfprintf (stderr, getmsg(n), p);
+ va_end(p);
+ exit (1);
+}
diff --git a/src/gripes.h b/src/gripes.h
new file mode 100644
index 0000000..8699eca
--- /dev/null
+++ b/src/gripes.h
@@ -0,0 +1,5 @@
+#include "gripedefs.h"
+
+void gripe (int n, ...);
+void fatal (int n, ...);
+
diff --git a/src/join.c b/src/join.c
new file mode 100644
index 0000000..1461ace
--- /dev/null
+++ b/src/join.c
@@ -0,0 +1,28 @@
+
+/* note: this routine frees its arguments! */
+char **
+my_join (char **np1, char **np2) {
+ int lth1, lth2;
+ char **p, **q, **np;
+
+ if (np1 == NULL)
+ return np2;
+ if (np2 == NULL)
+ return np1;
+ lth1 = lth2 = 0;
+ for (p = np1; *p; p++)
+ lth1++;
+ for (p = np2; *p; p++)
+ lth2++;
+ p = np = (char **) my_malloc((lth1+lth2+1)*sizeof(*np));
+ q = np1;
+ while(*q)
+ *p++ = *q++;
+ q = np2;
+ while(*q)
+ *p++ = *q++;
+ *p = 0;
+ free(np1);
+ free(np2);
+ return np;
+}
diff --git a/src/makemsg b/src/makemsg
new file mode 100755
index 0000000..7c1893c
--- /dev/null
+++ b/src/makemsg
Binary files differ
diff --git a/src/makemsg.c b/src/makemsg.c
new file mode 100644
index 0000000..34b3846
--- /dev/null
+++ b/src/makemsg.c
@@ -0,0 +1,175 @@
+/* makemsg.c - aeb - 940605 */
+/*
+ * Read a file input with lines
+ * LABEL "text"
+ * and either output two files:
+ * a file msgout.c with content char *msg[] = { "text", ... };
+ * and a file msgout.h with content #define LABEL 1
+ * or output a single file:
+ * a message catalog with lines 1 "text"
+ *
+ * The former two are used during compilation of the main program
+ * and give default (English) messages. The latter output file is
+ * input for gencat, and used in non-English locales.
+ *
+ * Call:
+ * makemsg input msgout.h msgout.c
+ * or
+ * makemsg -c input message_catalog
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef __QNX__
+#include <unix.h>
+#endif
+extern char *index(const char *, int);
+extern char *rindex(const char *, int);
+
+#define BUFSIZE 4096
+
+#define whitespace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
+
+static void
+usage(void){
+ fprintf (stderr, "call is: makemsg input msgout.h msgout.c\n");
+ fprintf (stderr, "or: makemsg -c input catalog\n");
+ exit (1);
+}
+
+int
+main(int argc, char **argv) {
+ FILE *fin, *foh, *foc;
+ char *s, *t;
+ char *infile, *outcfile, *outhfile;
+ char buf[BUFSIZE];
+ int defct = 0;
+ int makecat = 0;
+
+#define getbuf if (fgets (buf, sizeof(buf), fin) == NULL) {\
+ fprintf (stderr, "makemsg: unexpected end of input\n");\
+ fprintf (stderr, "[output file(s) removed]\n");\
+ unlink (outcfile);\
+ if (!makecat) unlink (outhfile);\
+ exit (1);\
+ }
+
+ if (argc != 4)
+ usage ();
+
+ outhfile = 0; foh = 0; /* just to keep gcc happy */
+
+ if (!strcmp(argv[1], "-c")) {
+ makecat = 1;
+ infile = argv[2];
+ outcfile = argv[3];
+ } else {
+ infile = argv[1];
+ outhfile = argv[2];
+ outcfile = argv[3];
+ }
+
+ fin = fopen (infile, "r");
+ if (!fin) {
+ perror (infile);
+ fprintf (stderr, "makemsg: cannot open input file %s\n", infile);
+ usage ();
+ }
+
+ /* help people not to confuse the order of these args */
+ if (!makecat) {
+ s = rindex(outhfile, '.');
+ if (!s || s[1] != 'h') {
+ fprintf (stderr, "defines output file should have name ending in .h\n");
+ usage ();
+ }
+ s = rindex(outcfile, '.');
+ if (!s || s[1] != 'c') {
+ fprintf (stderr, "string output file should have name ending in .c\n");
+ usage ();
+ }
+ }
+
+ if (!makecat) {
+ foh = fopen (outhfile, "w");
+ if (!foh) {
+ perror (argv[1]);
+ fprintf (stderr, "makemsg: cannot open output file %s\n", outhfile);
+ usage ();
+ }
+ }
+ foc = fopen (outcfile, "w");
+ if (!foc) {
+ perror (argv[2]);
+ fprintf (stderr, "makemsg: cannot open output file %s\n", outcfile);
+ usage ();
+ }
+
+ if (makecat)
+ fputs ("$quote \"\n$set 1\n", foc);
+ else
+ fputs ("char *msg[] = {\n \"\",\n", foc);
+
+ while (fgets (buf, sizeof(buf), fin) != NULL) {
+ char ss;
+
+ /* skip leading blanks and blank lines */
+ s = buf;
+ while (whitespace(*s))
+ s++;
+ if (*s == 0)
+ continue;
+
+ /* extract label part */
+ t = s;
+ while (*s && !whitespace(*s))
+ s++;
+ ss = *s;
+ *s = 0;
+ if (makecat) {
+ /* the format here used to be "%d ", but that breaks
+ glibc-2.1.2 gencat */
+ fprintf (foc, "%d ", ++defct); /* gencat cannot handle %2d */
+ } else {
+ fprintf (foh, "#define %s %d\n", t, ++defct);
+ fprintf (foc, "/* %2d */ ", defct);
+ }
+ *s = ss;
+
+ /* skip blanks and newlines until string found */
+ while (whitespace(*s) || *s == 0) {
+ if (*s == 0) {
+ getbuf;
+ s = buf;
+ } else
+ s++;
+ }
+
+ /* output string - it may extend over several lines */
+ while ((t = index(s, '\n')) == NULL || (t > buf && t[-1] == '\\')) {
+ fputs (s, foc);
+ getbuf;
+ s = buf;
+ }
+ *t = 0;
+ fputs (s, foc);
+ if (makecat)
+ fputs ("\n", foc);
+ else
+ fputs (",\n", foc);
+ }
+
+ if (!makecat) {
+ fputs ("};\n", foc);
+ fprintf (foh, "\n#define MAXMSG %d\n", defct);
+ }
+
+ if (!makecat) {
+ fclose (foh);
+ }
+
+ fclose (foc);
+ fclose (fin);
+
+ return 0;
+}
diff --git a/src/makewhatis b/src/makewhatis
new file mode 100755
index 0000000..639d488
--- /dev/null
+++ b/src/makewhatis
@@ -0,0 +1,460 @@
+#!/bin/sh
+# Generated automatically from makewhatis.in by the
+# configure script.
+#
+#!/bin/sh
+# makewhatis: create the whatis database
+# Created: Sun Jun 14 10:49:37 1992
+# Revised: Sat Jan 8 14:12:37 1994 by faith@cs.unc.edu
+# Revised: Sat Mar 23 17:56:18 1996 by micheal@actrix.gen.nz
+# Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu)
+# May be freely distributed and modified as long as copyright is retained.
+#
+# Wed Dec 23 13:27:50 1992: Rik Faith (faith@cs.unc.edu) applied changes
+# based on Mitchum DSouza (mitchum.dsouza@mrc-apu.cam.ac.uk) cat patches.
+# Also, cleaned up code and make it work with NET-2 doc pages.
+#
+# makewhatis-1.4: aeb 940802, 941007, 950417
+# Fixed so that the -c option works correctly for the cat pages
+# on my machine. Fix for -u by Nan Zou (nan@ksu.ksu.edu).
+# Many minor changes.
+# The -s option is undocumented, and may well disappear again.
+#
+# Sat Mar 23 1996: Michael Hamilton (michael@actrix.gen.nz).
+# I changed the script to invoke gawk only once for each directory tree.
+# This speeds things up considerably (from 30 minutes down to 1.5 minutes
+# on my 486DX66).
+# 960401 - aeb: slight adaptation to work correctly with cat pages.
+# 960510 - added fixes by brennan@raven.ca.boeing.com, author of mawk.
+# 971012 - replaced "test -z" - it doesnt work on SunOS 4.1.3_U1.
+# 980710 - be more careful with TMPFILE.
+# 000323 - do not change PATH, better treatment of catpages - Bryan Henderson.
+# 011117 - avoid suspicious filenames.
+# 030310 - find files only; fix LAPACK cruft; no /usr/man default;
+# use /dev/stderr instead of /dev/tty; handle files with strange names;
+# add support for chinese, hungarian, indonesian, japanese, korean,
+# polish, russian (Thierry Vignaud).
+#
+# makewhatis 1.6: Federico Lucifredi
+# 060608 - Corrected traps.
+# 060719 - section choosing behavior to match man's (Mike frysinger).
+#
+# Note for Slackware users: "makewhatis -v -w -c" will work.
+#
+# makewhatis flc 060719 (from man-1.6g)
+
+program=`basename $0`
+
+# In case both /usr/man and /usr/share/man exist, the former is local
+# and should be first.
+# It is a bug to add /var/cache/man to DEFCATPATH.
+dm=
+for d in /usr/man /usr/share/man /usr/X11R6/man /usr/local/man
+do
+ if [ -d $d ]; then
+ if [ x$dm = x ]; then dm=$d; else dm=$dm:$d; fi
+ fi
+done
+DEFMANPATH=$dm
+dc=
+for d in /usr/man/preformat /usr/man /usr/share/man/preformat /usr/share/man
+do
+ if [ -d $d ]; then
+ if [ x$dc = x ]; then dc=$d; else dc=$dc:$d; fi
+ fi
+done
+DEFCATPATH=$dc
+
+# In case /usr is read-only, make /usr/foo/whatis (etc) a symlink to
+# something like /var/cache/man/foo-whatis.
+# Some distributions make a single big /var/cache/man/whatis file,
+# but that leads to problems and bugs.
+
+# AWK=/usr/bin/gawk
+AWK=/usr/bin/awk
+
+# Find a place for our temporary files. If security is not a concern, use
+# TMPFILE=/tmp/whatis$$; TMPFILEDIR=none
+# Of course makewhatis should only have the required permissions
+# (for reading and writing directories like /usr/man).
+# We try here to be careful (and avoid preconstructed symlinks)
+# in case makewhatis is run as root, by creating a subdirectory of /tmp.
+
+TMPFILEDIR=/tmp/whatis.tmp.dir.$$
+rm -rf $TMPFILEDIR
+if ! mkdir -m 0700 $TMPFILEDIR; then
+ echo Could not create $TMPFILEDIR
+ exit 1;
+fi
+TMPFILE=$TMPFILEDIR/w
+
+# make sure TMPFILEDIR is deleted if program is killed or terminates
+# (just delete this line if your shell doesnt know about trap)
+trap "rm -rf $TMPFILEDIR" 0
+trap "rm -rf $TMPFILEDIR; exit 255" 1 2 3 15
+
+# default find arg: no directories, no empty files
+findarg0="-type f -size +0"
+
+topath=manpath
+
+defmanpath=$DEFMANPATH
+defcatpath=
+
+if [ -n "$MANSECT" ]; then
+ sections=$MANSECT
+else
+ sections=`$AWK '($1 == "MANSECT") { print $2 }' /usr/share/misc/man.conf`
+ if [ x"$sections" = x ]; then
+ sections="1:1p:8:2:3:3p:4:5:6:7:9:0p:tcl:n:l:p:o"
+ fi
+fi
+sections=`echo $sections | sed -e 's/:/ /g'`
+
+for name in "$@"
+do
+if [ -n "$setsections" ]; then
+ setsections=
+ sections=$name
+ continue
+fi
+case $name in
+ --version|-V)
+ echo "$program from man-1.6g"
+ exit 0;;
+ -c) topath=catpath
+ defmanpath=
+ defcatpath=$DEFCATPATH
+ continue;;
+ -s) setsections=1
+ continue;;
+ -u) findarg="-ctime 0"
+ update=1
+ continue;;
+ -v) verbose=1
+ continue;;
+ -w) manpath=`man --path`
+ catpath=$manpath
+ continue;;
+ -*) echo "Usage: makewhatis [-s sections] [-u] [-v] [-w] [manpath] [-c [catpath]]"
+ echo " This will build the whatis database for the man pages"
+ echo " found in manpath and the cat pages found in catpath."
+ echo " -s: sections (default: $sections)"
+ echo " -u: update database with new pages"
+ echo " -v: verbose"
+ echo " -w: use manpath obtained from \`man --path\`"
+ echo " [manpath]: man directories (default: $DEFMANPATH)"
+ echo " [catpath]: cat directories (default: the first existing"
+ echo " directory in $DEFCATPATH)"
+ exit;;
+ *) if [ -d $name ]
+ then
+ eval $topath="\$$topath":$name
+ else
+ echo "No such directory $name"
+ exit
+ fi;;
+esac
+done
+
+manpath=`echo ${manpath-$defmanpath} | tr : ' '`
+if [ x"$catpath" = x ]; then
+ for d in `echo $defcatpath | tr : ' '`
+ do
+ if [ -d $d ]; then catpath=$d; break; fi
+ done
+fi
+catpath=`echo ${catpath} | tr : ' '`
+
+# first truncate all the whatis files that will be created new,
+# then only update - we might visit the same directory twice
+if [ x$update = x ]; then
+ for pages in man cat
+ do
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ cp /dev/null $mandir/whatis
+ done
+ done
+fi
+
+for pages in man cat
+do
+ export pages
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ if [ x$verbose != x ]; then
+ echo "about to enter $mandir" > /dev/stderr
+ fi
+
+ # kludge for Slackware's /usr/man/preformat
+ if [ $mandir = /usr/man/preformat ]
+ then
+ mandir1=/usr/man
+ else
+ mandir1=$mandir
+ fi
+
+ # if $mandir is on a readonly partition, and the whatis file
+ # is not a symlink, then let's skip trying to update it
+ if [ ! -L ${mandir1}/whatis ]
+ then
+ if [ -e ${mandir1}/whatis ] && [ ! -w ${mandir1}/whatis ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - whatis file is readonly > /dev/stderr
+ fi
+ continue
+ elif [ ! -e ${mandir1}/whatis ] && [ ! -w ${mandir1} ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - directory is readonly > /dev/stderr
+ fi
+ continue
+ fi
+ fi
+
+ if [ -s ${mandir}/whatis -a $pages = man -a x$update = x ]; then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - we did it already > /dev/stderr
+ fi
+ else
+ here=`pwd`
+ cd $mandir
+ for i in $sections
+ do
+ if [ -d ${pages}$i ]
+ then
+ cd ${pages}$i
+ section=$i
+ curdir=$mandir/${pages}$i
+ export section verbose curdir
+ find $mandir/${pages}$i/. -name '*' $findarg0 $findarg -print | $AWK '
+
+ function readline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ result = (pipe_cmd | getline);
+ if (result < 0) {
+ print "Pipe error: " pipe_cmd " " ERRNO > "/dev/stderr";
+ }
+ } else {
+ result = (getline < filename);
+ if (result < 0) {
+ print "Read file error: " filename " " ERRNO > "/dev/stderr";
+ }
+ }
+ return result;
+ }
+
+ function closeline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ return close(pipe_cmd);
+ } else {
+ return close(filename);
+ }
+ }
+
+ function do_one() {
+ insh = 0; thisjoin = 1; done = 0;
+ entire_line = "";
+
+ if (verbose) {
+ print "adding " filename > "/dev/stderr"
+ }
+
+ use_zcat = match(filename,"\\.Z$") ||
+ match(filename,"\\.z$") || match(filename,"\\.gz$");
+ if (!use_zcat)
+ use_bzcat = match(filename,"\\.bz2");
+ if(!use_bzcat)
+ use_lzcat = match(filename,"\\.lzma");
+ if (use_zcat || use_bzcat || use_lzcat ) {
+ filename_no_gz = substr(filename, 0, RSTART - 1);
+ } else {
+ filename_no_gz = filename;
+ }
+ match(filename_no_gz, "/[^/]+$");
+ progname = substr(filename, RSTART + 1, RLENGTH - 1);
+ if (match(progname, "\\." section "[A-Za-z]+")) {
+ actual_section = substr(progname, RSTART + 1, RLENGTH - 1);
+ } else {
+ actual_section = section;
+ }
+ sub(/\..*/, "", progname);
+ if (use_zcat || use_bzcat || use_lzcat) {
+ if (use_zcat) {
+ pipe_cmd = "zcat \"" filename "\"";
+ } else if (use_bzcat) {
+ pipe_cmd = "bzcat \"" filename "\"";
+ } else {
+ pipe_cmd = "lzcat \"" filename "\"";
+ }
+ # try to avoid suspicious stuff
+ if (filename ~ /[;&|`$(]/) {
+ print "ignored strange file name " filename " in " curdir > "/dev/stderr";
+ return;
+ }
+ }
+
+ while (!done && readline() > 0) {
+ gsub(/.\b/, "");
+ if (($1 ~ /^\.[Ss][Hh]/ &&
+ ($2 ~ /[Nn][Aa][Mm][Ee]/ ||
+ $2 ~ /^JMÉNO/ || $2 ~ /^NAVN/ || $2 ~ /^NUME/ ||
+ $2 ~ /^BEZEICHNUNG/ || $2 ~ /^NOMBRE/ ||
+ $2 ~ /^NIMI/ || $2 ~ /^NOM/ || $2 ~ /^IME/ ||
+ $2 ~ /^N[ÉE]V/ || $2 ~ /^NAMA/ || $2 ~ /^̾Á°/ ||
+ $2 ~ /^̾¾Î/ || $2 ~ /^À̸§/ || $2 ~ /^NAZWA/ ||
+ $2 ~ /^îáú÷áîéå/ || $2 ~ /^Ãû³Æ/ || $2 ~ /^¦WºÙ/ ||
+ $2 ~ /^NOME/ || $2 ~ /^NAAM/ || $2 ~ /^ÈÌÅ/)) ||
+ (pages == "cat" && $1 ~ /^NAME/)) {
+ if (!insh) {
+ insh = 1;
+ } else {
+ done = 1;
+ }
+ } else if (insh) {
+ if ($1 ~ /^\.[Ss][HhYS]/ ||
+ (pages == "cat" &&
+ ($1 ~ /^S[yYeE]/ || $1 ~ /^DESCRIPTION/ ||
+ $1 ~ /^COMMAND/ || $1 ~ /^OVERVIEW/ ||
+ $1 ~ /^STRUCTURES/ || $1 ~ /^INTRODUCTION/ ||
+ $0 ~ /^[^ ]/))) {
+ # end insh for Synopsis, Syntax, but also for
+ # DESCRIPTION (e.g., XFree86.1x),
+ # COMMAND (e.g., xspread.1)
+ # OVERVIEW (e.g., TclCommandWriting.3)
+ # STRUCTURES (e.g., XEvent.3x)
+ # INTRODUCTION (e.g., TclX.n)
+ # and anything at all that begins in Column 1, so
+ # is probably a section header.
+ done = 1;
+ } else {
+ if ($0 ~ progname"-") { # Fix old cat pages
+ sub(progname"-", progname" - ");
+ }
+ if ($0 ~ /[^ \\]-$/) {
+ sub(/-$/, ""); # Handle Hyphenations
+ nextjoin = 1;
+ } else if ($0 ~ /\\c$/) {
+ sub(/\\c$/, ""); # Handle Continuations
+ nextjoin = 1;
+ } else
+ nextjoin = 0;
+
+ sub(/^.[IB] /, ""); # Kill bold and italics
+ sub(/^.BI /, ""); #
+ sub(/^.SM /, ""); # Kill small
+ sub(/^.Nm /, ""); # Kill bold
+ sub(/^.Tn /, ""); # Kill normal
+ sub(/^.Li /, ""); # Kill .Li
+ sub(/^.Dq /, ""); # Kill .Dq
+ sub(/^.Nd */, "- "); # Convert .Nd to dash
+ sub(/\\\".*/, ""); # Trim pending comments
+ sub(/ *$/, ""); # Trim pending spaces
+ sub(/^\.$/, ""); # Kill blank comments
+ sub(/^'"'"'.*/, ""); # Kill comment/troff lines
+ sub(/^.in .*/, ""); # Kill various macros
+ sub(/^.ti .*/, "");
+ sub(/^.ta .*/, "");
+ sub(/^.Vb .*/, "");
+ sub(/^.[PLTH]P$/, ""); # .PP/.LP/.TP/.HP
+ sub(/^.Pp$/, "");
+ sub(/^.[iI]X .*$/, "");
+ sub(/^.nolinks$/, "");
+ sub(/^.B$/, "");
+ sub(/^.nf$/, "");
+
+ if (($1 ~ /^\.../ || $1 == "") &&
+ (entire_line ~ / - / || entire_line ~ / \\- /)) {
+ # Assume that this ends the description of one line
+ # Sometimes there are several descriptions in one page,
+ # as in outb(2).
+ handle_entire_line();
+ entire_line = "";
+ thisjoin = 1;
+ } else {
+ if (thisjoin) {
+ entire_line = entire_line $0;
+ } else {
+ entire_line = entire_line " " $0;
+ }
+ thisjoin = nextjoin;
+ }
+ }
+ }
+ }
+ handle_entire_line();
+ closeline();
+ }
+
+ function handle_entire_line() {
+ x = entire_line; # Keep it short
+
+ gsub(/\015/, "", x); # Kill DOS remains
+ gsub(/ /, " ", x); # Translate tabs to spaces
+ gsub(/ +/, " ", x); # Collapse spaces
+ gsub(/ *, */, ", ", x); # Fix comma spacings
+ sub(/^ /, "", x); # Kill initial spaces
+ sub(/ $/, "", x); # Kill trailing spaces
+ sub(/__+/, "_", x); # Collapse underscores
+
+ gsub(/\\f\(../, "", x); # Kill font changes
+ gsub(/\\f[PRIB0123]/, "", x); # Kill font changes
+ gsub(/\\s[-+0-9]*/, "", x); # Kill size changes
+ gsub(/\\&/, "", x); # Kill \&
+ gsub(/\\\|/, "", x); # Kill \|
+ gsub(/\\\((ru|ul)/, "_", x); # Translate
+ gsub(/\\\((mi|hy|em)/, "-", x); # Translate
+ gsub(/\\\*\(../, "", x); # Kill troff strings
+ gsub(/\\/, "", x); # Kill all backslashes
+ gsub(/"/, "", x); # Kill quotes (from .Nd "foo bar")
+ sub(/<h1 align=center>/, "", x);# Yuk! HTML cruft
+ gsub(/\000.*/, "X", x); # Binary cruft in LAPACK pages
+ gsub(/ +/, " ", x); # Collapse spaces (again)
+ sub(/^ /, "", x); # Kill initial spaces (again)
+ sub(/ $/, "", x); # Kill trailing spaces (again)
+ sub(/\.$/, "", x); # Kill trailing period
+
+ if (!match(x, / - /))
+ return;
+
+ after_dash = substr(x, RSTART);
+ head = substr(x, 1, RSTART-1) ", ";
+ while (match(head, /, /)) {
+ prog = substr(head, 1, RSTART-1);
+ head = substr(head, RSTART+2);
+ if (prog != progname)
+ prog = prog " [" progname "]";
+ printf "%-*s (%s) %s\n", 20, prog, actual_section, after_dash;
+ }
+ }
+
+ { # Main action - process each filename read in.
+ filename = $0;
+ do_one();
+ }
+ ' pages=$pages section=$section verbose=$verbose curdir=$curdir
+ cd ..
+ fi
+ done > $TMPFILE
+
+ cd "$here"
+
+ if [ -f ${mandir1}/whatis ]
+ then
+ cat ${mandir1}/whatis >> $TMPFILE
+ fi
+ tr -s '\n' < $TMPFILE | sort -u > ${mandir1}/whatis
+
+ chmod 644 ${mandir1}/whatis
+ rm $TMPFILE
+ fi
+ done
+done
+
+# remove tempdir
+rm -rf $TMPFILEDIR
+
diff --git a/src/makewhatis.in b/src/makewhatis.in
new file mode 100644
index 0000000..5665feb
--- /dev/null
+++ b/src/makewhatis.in
@@ -0,0 +1,456 @@
+#!/bin/sh
+# makewhatis: create the whatis database
+# Created: Sun Jun 14 10:49:37 1992
+# Revised: Sat Jan 8 14:12:37 1994 by faith@cs.unc.edu
+# Revised: Sat Mar 23 17:56:18 1996 by micheal@actrix.gen.nz
+# Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu)
+# May be freely distributed and modified as long as copyright is retained.
+#
+# Wed Dec 23 13:27:50 1992: Rik Faith (faith@cs.unc.edu) applied changes
+# based on Mitchum DSouza (mitchum.dsouza@mrc-apu.cam.ac.uk) cat patches.
+# Also, cleaned up code and make it work with NET-2 doc pages.
+#
+# makewhatis-1.4: aeb 940802, 941007, 950417
+# Fixed so that the -c option works correctly for the cat pages
+# on my machine. Fix for -u by Nan Zou (nan@ksu.ksu.edu).
+# Many minor changes.
+# The -s option is undocumented, and may well disappear again.
+#
+# Sat Mar 23 1996: Michael Hamilton (michael@actrix.gen.nz).
+# I changed the script to invoke gawk only once for each directory tree.
+# This speeds things up considerably (from 30 minutes down to 1.5 minutes
+# on my 486DX66).
+# 960401 - aeb: slight adaptation to work correctly with cat pages.
+# 960510 - added fixes by brennan@raven.ca.boeing.com, author of mawk.
+# 971012 - replaced "test -z" - it doesnt work on SunOS 4.1.3_U1.
+# 980710 - be more careful with TMPFILE.
+# 000323 - do not change PATH, better treatment of catpages - Bryan Henderson.
+# 011117 - avoid suspicious filenames.
+# 030310 - find files only; fix LAPACK cruft; no /usr/man default;
+# use /dev/stderr instead of /dev/tty; handle files with strange names;
+# add support for chinese, hungarian, indonesian, japanese, korean,
+# polish, russian (Thierry Vignaud).
+#
+# makewhatis 1.6: Federico Lucifredi
+# 060608 - Corrected traps.
+# 060719 - section choosing behavior to match man's (Mike frysinger).
+#
+# Note for Slackware users: "makewhatis -v -w -c" will work.
+#
+# makewhatis flc 060719 (from @version@)
+
+program=`basename $0`
+
+# In case both /usr/man and /usr/share/man exist, the former is local
+# and should be first.
+# It is a bug to add /var/cache/man to DEFCATPATH.
+dm=
+for d in /usr/man /usr/share/man /usr/X11R6/man /usr/local/man
+do
+ if [ -d $d ]; then
+ if [ x$dm = x ]; then dm=$d; else dm=$dm:$d; fi
+ fi
+done
+DEFMANPATH=$dm
+dc=
+for d in /usr/man/preformat /usr/man /usr/share/man/preformat /usr/share/man
+do
+ if [ -d $d ]; then
+ if [ x$dc = x ]; then dc=$d; else dc=$dc:$d; fi
+ fi
+done
+DEFCATPATH=$dc
+
+# In case /usr is read-only, make /usr/foo/whatis (etc) a symlink to
+# something like /var/cache/man/foo-whatis.
+# Some distributions make a single big /var/cache/man/whatis file,
+# but that leads to problems and bugs.
+
+# AWK=/usr/bin/gawk
+AWK=@awk@
+
+# Find a place for our temporary files. If security is not a concern, use
+# TMPFILE=/tmp/whatis$$; TMPFILEDIR=none
+# Of course makewhatis should only have the required permissions
+# (for reading and writing directories like /usr/man).
+# We try here to be careful (and avoid preconstructed symlinks)
+# in case makewhatis is run as root, by creating a subdirectory of /tmp.
+
+TMPFILEDIR=/tmp/whatis.tmp.dir.$$
+rm -rf $TMPFILEDIR
+if ! mkdir -m 0700 $TMPFILEDIR; then
+ echo Could not create $TMPFILEDIR
+ exit 1;
+fi
+TMPFILE=$TMPFILEDIR/w
+
+# make sure TMPFILEDIR is deleted if program is killed or terminates
+# (just delete this line if your shell doesnt know about trap)
+trap "rm -rf $TMPFILEDIR" 0
+trap "rm -rf $TMPFILEDIR; exit 255" 1 2 3 15
+
+# default find arg: no directories, no empty files
+findarg0="-type f -size +0"
+
+topath=manpath
+
+defmanpath=$DEFMANPATH
+defcatpath=
+
+if [ -n "$MANSECT" ]; then
+ sections=$MANSECT
+else
+ sections=`$AWK '($1 == "MANSECT") { print $2 }' @man_config_file@`
+ if [ x"$sections" = x ]; then
+ sections="@sections@"
+ fi
+fi
+sections=`echo $sections | sed -e 's/:/ /g'`
+
+for name in "$@"
+do
+if [ -n "$setsections" ]; then
+ setsections=
+ sections=$name
+ continue
+fi
+case $name in
+ --version|-V)
+ echo "$program from @version@"
+ exit 0;;
+ -c) topath=catpath
+ defmanpath=
+ defcatpath=$DEFCATPATH
+ continue;;
+ -s) setsections=1
+ continue;;
+ -u) findarg="-ctime 0"
+ update=1
+ continue;;
+ -v) verbose=1
+ continue;;
+ -w) manpath=`man --path`
+ catpath=$manpath
+ continue;;
+ -*) echo "Usage: makewhatis [-s sections] [-u] [-v] [-w] [manpath] [-c [catpath]]"
+ echo " This will build the whatis database for the man pages"
+ echo " found in manpath and the cat pages found in catpath."
+ echo " -s: sections (default: $sections)"
+ echo " -u: update database with new pages"
+ echo " -v: verbose"
+ echo " -w: use manpath obtained from \`man --path\`"
+ echo " [manpath]: man directories (default: $DEFMANPATH)"
+ echo " [catpath]: cat directories (default: the first existing"
+ echo " directory in $DEFCATPATH)"
+ exit;;
+ *) if [ -d $name ]
+ then
+ eval $topath="\$$topath":$name
+ else
+ echo "No such directory $name"
+ exit
+ fi;;
+esac
+done
+
+manpath=`echo ${manpath-$defmanpath} | tr : ' '`
+if [ x"$catpath" = x ]; then
+ for d in `echo $defcatpath | tr : ' '`
+ do
+ if [ -d $d ]; then catpath=$d; break; fi
+ done
+fi
+catpath=`echo ${catpath} | tr : ' '`
+
+# first truncate all the whatis files that will be created new,
+# then only update - we might visit the same directory twice
+if [ x$update = x ]; then
+ for pages in man cat
+ do
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ cp /dev/null $mandir/whatis
+ done
+ done
+fi
+
+for pages in man cat
+do
+ export pages
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ if [ x$verbose != x ]; then
+ echo "about to enter $mandir" > /dev/stderr
+ fi
+
+ # kludge for Slackware's /usr/man/preformat
+ if [ $mandir = /usr/man/preformat ]
+ then
+ mandir1=/usr/man
+ else
+ mandir1=$mandir
+ fi
+
+ # if $mandir is on a readonly partition, and the whatis file
+ # is not a symlink, then let's skip trying to update it
+ if [ ! -L ${mandir1}/whatis ]
+ then
+ if [ -e ${mandir1}/whatis ] && [ ! -w ${mandir1}/whatis ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - whatis file is readonly > /dev/stderr
+ fi
+ continue
+ elif [ ! -e ${mandir1}/whatis ] && [ ! -w ${mandir1} ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - directory is readonly > /dev/stderr
+ fi
+ continue
+ fi
+ fi
+
+ if [ -s ${mandir}/whatis -a $pages = man -a x$update = x ]; then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - we did it already > /dev/stderr
+ fi
+ else
+ here=`pwd`
+ cd $mandir
+ for i in $sections
+ do
+ if [ -d ${pages}$i ]
+ then
+ cd ${pages}$i
+ section=$i
+ curdir=$mandir/${pages}$i
+ export section verbose curdir
+ find $mandir/${pages}$i/. -name '*' $findarg0 $findarg -print | $AWK '
+
+ function readline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ result = (pipe_cmd | getline);
+ if (result < 0) {
+ print "Pipe error: " pipe_cmd " " ERRNO > "/dev/stderr";
+ }
+ } else {
+ result = (getline < filename);
+ if (result < 0) {
+ print "Read file error: " filename " " ERRNO > "/dev/stderr";
+ }
+ }
+ return result;
+ }
+
+ function closeline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ return close(pipe_cmd);
+ } else {
+ return close(filename);
+ }
+ }
+
+ function do_one() {
+ insh = 0; thisjoin = 1; done = 0;
+ entire_line = "";
+
+ if (verbose) {
+ print "adding " filename > "/dev/stderr"
+ }
+
+ use_zcat = match(filename,"\\.Z$") ||
+ match(filename,"\\.z$") || match(filename,"\\.gz$");
+ if (!use_zcat)
+ use_bzcat = match(filename,"\\.bz2");
+ if(!use_bzcat)
+ use_lzcat = match(filename,"\\.lzma");
+ if (use_zcat || use_bzcat || use_lzcat ) {
+ filename_no_gz = substr(filename, 0, RSTART - 1);
+ } else {
+ filename_no_gz = filename;
+ }
+ match(filename_no_gz, "/[^/]+$");
+ progname = substr(filename, RSTART + 1, RLENGTH - 1);
+ if (match(progname, "\\." section "[A-Za-z]+")) {
+ actual_section = substr(progname, RSTART + 1, RLENGTH - 1);
+ } else {
+ actual_section = section;
+ }
+ sub(/\..*/, "", progname);
+ if (use_zcat || use_bzcat || use_lzcat) {
+ if (use_zcat) {
+ pipe_cmd = "zcat \"" filename "\"";
+ } else if (use_bzcat) {
+ pipe_cmd = "bzcat \"" filename "\"";
+ } else {
+ pipe_cmd = "lzcat \"" filename "\"";
+ }
+ # try to avoid suspicious stuff
+ if (filename ~ /[;&|`$(]/) {
+ print "ignored strange file name " filename " in " curdir > "/dev/stderr";
+ return;
+ }
+ }
+
+ while (!done && readline() > 0) {
+ gsub(/.\b/, "");
+ if (($1 ~ /^\.[Ss][Hh]/ &&
+ ($2 ~ /[Nn][Aa][Mm][Ee]/ ||
+ $2 ~ /^JMÉNO/ || $2 ~ /^NAVN/ || $2 ~ /^NUME/ ||
+ $2 ~ /^BEZEICHNUNG/ || $2 ~ /^NOMBRE/ ||
+ $2 ~ /^NIMI/ || $2 ~ /^NOM/ || $2 ~ /^IME/ ||
+ $2 ~ /^N[ÉE]V/ || $2 ~ /^NAMA/ || $2 ~ /^̾Á°/ ||
+ $2 ~ /^̾¾Î/ || $2 ~ /^À̸§/ || $2 ~ /^NAZWA/ ||
+ $2 ~ /^îáú÷áîéå/ || $2 ~ /^Ãû³Æ/ || $2 ~ /^¦WºÙ/ ||
+ $2 ~ /^NOME/ || $2 ~ /^NAAM/ || $2 ~ /^ÈÌÅ/)) ||
+ (pages == "cat" && $1 ~ /^NAME/)) {
+ if (!insh) {
+ insh = 1;
+ } else {
+ done = 1;
+ }
+ } else if (insh) {
+ if ($1 ~ /^\.[Ss][HhYS]/ ||
+ (pages == "cat" &&
+ ($1 ~ /^S[yYeE]/ || $1 ~ /^DESCRIPTION/ ||
+ $1 ~ /^COMMAND/ || $1 ~ /^OVERVIEW/ ||
+ $1 ~ /^STRUCTURES/ || $1 ~ /^INTRODUCTION/ ||
+ $0 ~ /^[^ ]/))) {
+ # end insh for Synopsis, Syntax, but also for
+ # DESCRIPTION (e.g., XFree86.1x),
+ # COMMAND (e.g., xspread.1)
+ # OVERVIEW (e.g., TclCommandWriting.3)
+ # STRUCTURES (e.g., XEvent.3x)
+ # INTRODUCTION (e.g., TclX.n)
+ # and anything at all that begins in Column 1, so
+ # is probably a section header.
+ done = 1;
+ } else {
+ if ($0 ~ progname"-") { # Fix old cat pages
+ sub(progname"-", progname" - ");
+ }
+ if ($0 ~ /[^ \\]-$/) {
+ sub(/-$/, ""); # Handle Hyphenations
+ nextjoin = 1;
+ } else if ($0 ~ /\\c$/) {
+ sub(/\\c$/, ""); # Handle Continuations
+ nextjoin = 1;
+ } else
+ nextjoin = 0;
+
+ sub(/^.[IB] /, ""); # Kill bold and italics
+ sub(/^.BI /, ""); #
+ sub(/^.SM /, ""); # Kill small
+ sub(/^.Nm /, ""); # Kill bold
+ sub(/^.Tn /, ""); # Kill normal
+ sub(/^.Li /, ""); # Kill .Li
+ sub(/^.Dq /, ""); # Kill .Dq
+ sub(/^.Nd */, "- "); # Convert .Nd to dash
+ sub(/\\\".*/, ""); # Trim pending comments
+ sub(/ *$/, ""); # Trim pending spaces
+ sub(/^\.$/, ""); # Kill blank comments
+ sub(/^'"'"'.*/, ""); # Kill comment/troff lines
+ sub(/^.in .*/, ""); # Kill various macros
+ sub(/^.ti .*/, "");
+ sub(/^.ta .*/, "");
+ sub(/^.Vb .*/, "");
+ sub(/^.[PLTH]P$/, ""); # .PP/.LP/.TP/.HP
+ sub(/^.Pp$/, "");
+ sub(/^.[iI]X .*$/, "");
+ sub(/^.nolinks$/, "");
+ sub(/^.B$/, "");
+ sub(/^.nf$/, "");
+
+ if (($1 ~ /^\.../ || $1 == "") &&
+ (entire_line ~ / - / || entire_line ~ / \\- /)) {
+ # Assume that this ends the description of one line
+ # Sometimes there are several descriptions in one page,
+ # as in outb(2).
+ handle_entire_line();
+ entire_line = "";
+ thisjoin = 1;
+ } else {
+ if (thisjoin) {
+ entire_line = entire_line $0;
+ } else {
+ entire_line = entire_line " " $0;
+ }
+ thisjoin = nextjoin;
+ }
+ }
+ }
+ }
+ handle_entire_line();
+ closeline();
+ }
+
+ function handle_entire_line() {
+ x = entire_line; # Keep it short
+
+ gsub(/\015/, "", x); # Kill DOS remains
+ gsub(/ /, " ", x); # Translate tabs to spaces
+ gsub(/ +/, " ", x); # Collapse spaces
+ gsub(/ *, */, ", ", x); # Fix comma spacings
+ sub(/^ /, "", x); # Kill initial spaces
+ sub(/ $/, "", x); # Kill trailing spaces
+ sub(/__+/, "_", x); # Collapse underscores
+
+ gsub(/\\f\(../, "", x); # Kill font changes
+ gsub(/\\f[PRIB0123]/, "", x); # Kill font changes
+ gsub(/\\s[-+0-9]*/, "", x); # Kill size changes
+ gsub(/\\&/, "", x); # Kill \&
+ gsub(/\\\|/, "", x); # Kill \|
+ gsub(/\\\((ru|ul)/, "_", x); # Translate
+ gsub(/\\\((mi|hy|em)/, "-", x); # Translate
+ gsub(/\\\*\(../, "", x); # Kill troff strings
+ gsub(/\\/, "", x); # Kill all backslashes
+ gsub(/"/, "", x); # Kill quotes (from .Nd "foo bar")
+ sub(/<h1 align=center>/, "", x);# Yuk! HTML cruft
+ gsub(/\000.*/, "X", x); # Binary cruft in LAPACK pages
+ gsub(/ +/, " ", x); # Collapse spaces (again)
+ sub(/^ /, "", x); # Kill initial spaces (again)
+ sub(/ $/, "", x); # Kill trailing spaces (again)
+ sub(/\.$/, "", x); # Kill trailing period
+
+ if (!match(x, / - /))
+ return;
+
+ after_dash = substr(x, RSTART);
+ head = substr(x, 1, RSTART-1) ", ";
+ while (match(head, /, /)) {
+ prog = substr(head, 1, RSTART-1);
+ head = substr(head, RSTART+2);
+ if (prog != progname)
+ prog = prog " [" progname "]";
+ printf "%-*s (%s) %s\n", 20, prog, actual_section, after_dash;
+ }
+ }
+
+ { # Main action - process each filename read in.
+ filename = $0;
+ do_one();
+ }
+ ' pages=$pages section=$section verbose=$verbose curdir=$curdir
+ cd ..
+ fi
+ done > $TMPFILE
+
+ cd "$here"
+
+ if [ -f ${mandir1}/whatis ]
+ then
+ cat ${mandir1}/whatis >> $TMPFILE
+ fi
+ tr -s '\n' < $TMPFILE | sort -u > ${mandir1}/whatis
+
+ chmod 644 ${mandir1}/whatis
+ rm $TMPFILE
+ fi
+ done
+done
+
+# remove tempdir
+rm -rf $TMPFILEDIR
+
diff --git a/src/makewhatis.sh b/src/makewhatis.sh
new file mode 100644
index 0000000..5665feb
--- /dev/null
+++ b/src/makewhatis.sh
@@ -0,0 +1,456 @@
+#!/bin/sh
+# makewhatis: create the whatis database
+# Created: Sun Jun 14 10:49:37 1992
+# Revised: Sat Jan 8 14:12:37 1994 by faith@cs.unc.edu
+# Revised: Sat Mar 23 17:56:18 1996 by micheal@actrix.gen.nz
+# Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu)
+# May be freely distributed and modified as long as copyright is retained.
+#
+# Wed Dec 23 13:27:50 1992: Rik Faith (faith@cs.unc.edu) applied changes
+# based on Mitchum DSouza (mitchum.dsouza@mrc-apu.cam.ac.uk) cat patches.
+# Also, cleaned up code and make it work with NET-2 doc pages.
+#
+# makewhatis-1.4: aeb 940802, 941007, 950417
+# Fixed so that the -c option works correctly for the cat pages
+# on my machine. Fix for -u by Nan Zou (nan@ksu.ksu.edu).
+# Many minor changes.
+# The -s option is undocumented, and may well disappear again.
+#
+# Sat Mar 23 1996: Michael Hamilton (michael@actrix.gen.nz).
+# I changed the script to invoke gawk only once for each directory tree.
+# This speeds things up considerably (from 30 minutes down to 1.5 minutes
+# on my 486DX66).
+# 960401 - aeb: slight adaptation to work correctly with cat pages.
+# 960510 - added fixes by brennan@raven.ca.boeing.com, author of mawk.
+# 971012 - replaced "test -z" - it doesnt work on SunOS 4.1.3_U1.
+# 980710 - be more careful with TMPFILE.
+# 000323 - do not change PATH, better treatment of catpages - Bryan Henderson.
+# 011117 - avoid suspicious filenames.
+# 030310 - find files only; fix LAPACK cruft; no /usr/man default;
+# use /dev/stderr instead of /dev/tty; handle files with strange names;
+# add support for chinese, hungarian, indonesian, japanese, korean,
+# polish, russian (Thierry Vignaud).
+#
+# makewhatis 1.6: Federico Lucifredi
+# 060608 - Corrected traps.
+# 060719 - section choosing behavior to match man's (Mike frysinger).
+#
+# Note for Slackware users: "makewhatis -v -w -c" will work.
+#
+# makewhatis flc 060719 (from @version@)
+
+program=`basename $0`
+
+# In case both /usr/man and /usr/share/man exist, the former is local
+# and should be first.
+# It is a bug to add /var/cache/man to DEFCATPATH.
+dm=
+for d in /usr/man /usr/share/man /usr/X11R6/man /usr/local/man
+do
+ if [ -d $d ]; then
+ if [ x$dm = x ]; then dm=$d; else dm=$dm:$d; fi
+ fi
+done
+DEFMANPATH=$dm
+dc=
+for d in /usr/man/preformat /usr/man /usr/share/man/preformat /usr/share/man
+do
+ if [ -d $d ]; then
+ if [ x$dc = x ]; then dc=$d; else dc=$dc:$d; fi
+ fi
+done
+DEFCATPATH=$dc
+
+# In case /usr is read-only, make /usr/foo/whatis (etc) a symlink to
+# something like /var/cache/man/foo-whatis.
+# Some distributions make a single big /var/cache/man/whatis file,
+# but that leads to problems and bugs.
+
+# AWK=/usr/bin/gawk
+AWK=@awk@
+
+# Find a place for our temporary files. If security is not a concern, use
+# TMPFILE=/tmp/whatis$$; TMPFILEDIR=none
+# Of course makewhatis should only have the required permissions
+# (for reading and writing directories like /usr/man).
+# We try here to be careful (and avoid preconstructed symlinks)
+# in case makewhatis is run as root, by creating a subdirectory of /tmp.
+
+TMPFILEDIR=/tmp/whatis.tmp.dir.$$
+rm -rf $TMPFILEDIR
+if ! mkdir -m 0700 $TMPFILEDIR; then
+ echo Could not create $TMPFILEDIR
+ exit 1;
+fi
+TMPFILE=$TMPFILEDIR/w
+
+# make sure TMPFILEDIR is deleted if program is killed or terminates
+# (just delete this line if your shell doesnt know about trap)
+trap "rm -rf $TMPFILEDIR" 0
+trap "rm -rf $TMPFILEDIR; exit 255" 1 2 3 15
+
+# default find arg: no directories, no empty files
+findarg0="-type f -size +0"
+
+topath=manpath
+
+defmanpath=$DEFMANPATH
+defcatpath=
+
+if [ -n "$MANSECT" ]; then
+ sections=$MANSECT
+else
+ sections=`$AWK '($1 == "MANSECT") { print $2 }' @man_config_file@`
+ if [ x"$sections" = x ]; then
+ sections="@sections@"
+ fi
+fi
+sections=`echo $sections | sed -e 's/:/ /g'`
+
+for name in "$@"
+do
+if [ -n "$setsections" ]; then
+ setsections=
+ sections=$name
+ continue
+fi
+case $name in
+ --version|-V)
+ echo "$program from @version@"
+ exit 0;;
+ -c) topath=catpath
+ defmanpath=
+ defcatpath=$DEFCATPATH
+ continue;;
+ -s) setsections=1
+ continue;;
+ -u) findarg="-ctime 0"
+ update=1
+ continue;;
+ -v) verbose=1
+ continue;;
+ -w) manpath=`man --path`
+ catpath=$manpath
+ continue;;
+ -*) echo "Usage: makewhatis [-s sections] [-u] [-v] [-w] [manpath] [-c [catpath]]"
+ echo " This will build the whatis database for the man pages"
+ echo " found in manpath and the cat pages found in catpath."
+ echo " -s: sections (default: $sections)"
+ echo " -u: update database with new pages"
+ echo " -v: verbose"
+ echo " -w: use manpath obtained from \`man --path\`"
+ echo " [manpath]: man directories (default: $DEFMANPATH)"
+ echo " [catpath]: cat directories (default: the first existing"
+ echo " directory in $DEFCATPATH)"
+ exit;;
+ *) if [ -d $name ]
+ then
+ eval $topath="\$$topath":$name
+ else
+ echo "No such directory $name"
+ exit
+ fi;;
+esac
+done
+
+manpath=`echo ${manpath-$defmanpath} | tr : ' '`
+if [ x"$catpath" = x ]; then
+ for d in `echo $defcatpath | tr : ' '`
+ do
+ if [ -d $d ]; then catpath=$d; break; fi
+ done
+fi
+catpath=`echo ${catpath} | tr : ' '`
+
+# first truncate all the whatis files that will be created new,
+# then only update - we might visit the same directory twice
+if [ x$update = x ]; then
+ for pages in man cat
+ do
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ cp /dev/null $mandir/whatis
+ done
+ done
+fi
+
+for pages in man cat
+do
+ export pages
+ eval path="\$$pages"path
+ for mandir in $path
+ do
+ if [ x$verbose != x ]; then
+ echo "about to enter $mandir" > /dev/stderr
+ fi
+
+ # kludge for Slackware's /usr/man/preformat
+ if [ $mandir = /usr/man/preformat ]
+ then
+ mandir1=/usr/man
+ else
+ mandir1=$mandir
+ fi
+
+ # if $mandir is on a readonly partition, and the whatis file
+ # is not a symlink, then let's skip trying to update it
+ if [ ! -L ${mandir1}/whatis ]
+ then
+ if [ -e ${mandir1}/whatis ] && [ ! -w ${mandir1}/whatis ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - whatis file is readonly > /dev/stderr
+ fi
+ continue
+ elif [ ! -e ${mandir1}/whatis ] && [ ! -w ${mandir1} ]
+ then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - directory is readonly > /dev/stderr
+ fi
+ continue
+ fi
+ fi
+
+ if [ -s ${mandir}/whatis -a $pages = man -a x$update = x ]; then
+ if [ x$verbose != x ]; then
+ echo skipping $mandir - we did it already > /dev/stderr
+ fi
+ else
+ here=`pwd`
+ cd $mandir
+ for i in $sections
+ do
+ if [ -d ${pages}$i ]
+ then
+ cd ${pages}$i
+ section=$i
+ curdir=$mandir/${pages}$i
+ export section verbose curdir
+ find $mandir/${pages}$i/. -name '*' $findarg0 $findarg -print | $AWK '
+
+ function readline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ result = (pipe_cmd | getline);
+ if (result < 0) {
+ print "Pipe error: " pipe_cmd " " ERRNO > "/dev/stderr";
+ }
+ } else {
+ result = (getline < filename);
+ if (result < 0) {
+ print "Read file error: " filename " " ERRNO > "/dev/stderr";
+ }
+ }
+ return result;
+ }
+
+ function closeline() {
+ if (use_zcat || use_bzcat || use_lzcat) {
+ return close(pipe_cmd);
+ } else {
+ return close(filename);
+ }
+ }
+
+ function do_one() {
+ insh = 0; thisjoin = 1; done = 0;
+ entire_line = "";
+
+ if (verbose) {
+ print "adding " filename > "/dev/stderr"
+ }
+
+ use_zcat = match(filename,"\\.Z$") ||
+ match(filename,"\\.z$") || match(filename,"\\.gz$");
+ if (!use_zcat)
+ use_bzcat = match(filename,"\\.bz2");
+ if(!use_bzcat)
+ use_lzcat = match(filename,"\\.lzma");
+ if (use_zcat || use_bzcat || use_lzcat ) {
+ filename_no_gz = substr(filename, 0, RSTART - 1);
+ } else {
+ filename_no_gz = filename;
+ }
+ match(filename_no_gz, "/[^/]+$");
+ progname = substr(filename, RSTART + 1, RLENGTH - 1);
+ if (match(progname, "\\." section "[A-Za-z]+")) {
+ actual_section = substr(progname, RSTART + 1, RLENGTH - 1);
+ } else {
+ actual_section = section;
+ }
+ sub(/\..*/, "", progname);
+ if (use_zcat || use_bzcat || use_lzcat) {
+ if (use_zcat) {
+ pipe_cmd = "zcat \"" filename "\"";
+ } else if (use_bzcat) {
+ pipe_cmd = "bzcat \"" filename "\"";
+ } else {
+ pipe_cmd = "lzcat \"" filename "\"";
+ }
+ # try to avoid suspicious stuff
+ if (filename ~ /[;&|`$(]/) {
+ print "ignored strange file name " filename " in " curdir > "/dev/stderr";
+ return;
+ }
+ }
+
+ while (!done && readline() > 0) {
+ gsub(/.\b/, "");
+ if (($1 ~ /^\.[Ss][Hh]/ &&
+ ($2 ~ /[Nn][Aa][Mm][Ee]/ ||
+ $2 ~ /^JMÉNO/ || $2 ~ /^NAVN/ || $2 ~ /^NUME/ ||
+ $2 ~ /^BEZEICHNUNG/ || $2 ~ /^NOMBRE/ ||
+ $2 ~ /^NIMI/ || $2 ~ /^NOM/ || $2 ~ /^IME/ ||
+ $2 ~ /^N[ÉE]V/ || $2 ~ /^NAMA/ || $2 ~ /^̾Á°/ ||
+ $2 ~ /^̾¾Î/ || $2 ~ /^À̸§/ || $2 ~ /^NAZWA/ ||
+ $2 ~ /^îáú÷áîéå/ || $2 ~ /^Ãû³Æ/ || $2 ~ /^¦WºÙ/ ||
+ $2 ~ /^NOME/ || $2 ~ /^NAAM/ || $2 ~ /^ÈÌÅ/)) ||
+ (pages == "cat" && $1 ~ /^NAME/)) {
+ if (!insh) {
+ insh = 1;
+ } else {
+ done = 1;
+ }
+ } else if (insh) {
+ if ($1 ~ /^\.[Ss][HhYS]/ ||
+ (pages == "cat" &&
+ ($1 ~ /^S[yYeE]/ || $1 ~ /^DESCRIPTION/ ||
+ $1 ~ /^COMMAND/ || $1 ~ /^OVERVIEW/ ||
+ $1 ~ /^STRUCTURES/ || $1 ~ /^INTRODUCTION/ ||
+ $0 ~ /^[^ ]/))) {
+ # end insh for Synopsis, Syntax, but also for
+ # DESCRIPTION (e.g., XFree86.1x),
+ # COMMAND (e.g., xspread.1)
+ # OVERVIEW (e.g., TclCommandWriting.3)
+ # STRUCTURES (e.g., XEvent.3x)
+ # INTRODUCTION (e.g., TclX.n)
+ # and anything at all that begins in Column 1, so
+ # is probably a section header.
+ done = 1;
+ } else {
+ if ($0 ~ progname"-") { # Fix old cat pages
+ sub(progname"-", progname" - ");
+ }
+ if ($0 ~ /[^ \\]-$/) {
+ sub(/-$/, ""); # Handle Hyphenations
+ nextjoin = 1;
+ } else if ($0 ~ /\\c$/) {
+ sub(/\\c$/, ""); # Handle Continuations
+ nextjoin = 1;
+ } else
+ nextjoin = 0;
+
+ sub(/^.[IB] /, ""); # Kill bold and italics
+ sub(/^.BI /, ""); #
+ sub(/^.SM /, ""); # Kill small
+ sub(/^.Nm /, ""); # Kill bold
+ sub(/^.Tn /, ""); # Kill normal
+ sub(/^.Li /, ""); # Kill .Li
+ sub(/^.Dq /, ""); # Kill .Dq
+ sub(/^.Nd */, "- "); # Convert .Nd to dash
+ sub(/\\\".*/, ""); # Trim pending comments
+ sub(/ *$/, ""); # Trim pending spaces
+ sub(/^\.$/, ""); # Kill blank comments
+ sub(/^'"'"'.*/, ""); # Kill comment/troff lines
+ sub(/^.in .*/, ""); # Kill various macros
+ sub(/^.ti .*/, "");
+ sub(/^.ta .*/, "");
+ sub(/^.Vb .*/, "");
+ sub(/^.[PLTH]P$/, ""); # .PP/.LP/.TP/.HP
+ sub(/^.Pp$/, "");
+ sub(/^.[iI]X .*$/, "");
+ sub(/^.nolinks$/, "");
+ sub(/^.B$/, "");
+ sub(/^.nf$/, "");
+
+ if (($1 ~ /^\.../ || $1 == "") &&
+ (entire_line ~ / - / || entire_line ~ / \\- /)) {
+ # Assume that this ends the description of one line
+ # Sometimes there are several descriptions in one page,
+ # as in outb(2).
+ handle_entire_line();
+ entire_line = "";
+ thisjoin = 1;
+ } else {
+ if (thisjoin) {
+ entire_line = entire_line $0;
+ } else {
+ entire_line = entire_line " " $0;
+ }
+ thisjoin = nextjoin;
+ }
+ }
+ }
+ }
+ handle_entire_line();
+ closeline();
+ }
+
+ function handle_entire_line() {
+ x = entire_line; # Keep it short
+
+ gsub(/\015/, "", x); # Kill DOS remains
+ gsub(/ /, " ", x); # Translate tabs to spaces
+ gsub(/ +/, " ", x); # Collapse spaces
+ gsub(/ *, */, ", ", x); # Fix comma spacings
+ sub(/^ /, "", x); # Kill initial spaces
+ sub(/ $/, "", x); # Kill trailing spaces
+ sub(/__+/, "_", x); # Collapse underscores
+
+ gsub(/\\f\(../, "", x); # Kill font changes
+ gsub(/\\f[PRIB0123]/, "", x); # Kill font changes
+ gsub(/\\s[-+0-9]*/, "", x); # Kill size changes
+ gsub(/\\&/, "", x); # Kill \&
+ gsub(/\\\|/, "", x); # Kill \|
+ gsub(/\\\((ru|ul)/, "_", x); # Translate
+ gsub(/\\\((mi|hy|em)/, "-", x); # Translate
+ gsub(/\\\*\(../, "", x); # Kill troff strings
+ gsub(/\\/, "", x); # Kill all backslashes
+ gsub(/"/, "", x); # Kill quotes (from .Nd "foo bar")
+ sub(/<h1 align=center>/, "", x);# Yuk! HTML cruft
+ gsub(/\000.*/, "X", x); # Binary cruft in LAPACK pages
+ gsub(/ +/, " ", x); # Collapse spaces (again)
+ sub(/^ /, "", x); # Kill initial spaces (again)
+ sub(/ $/, "", x); # Kill trailing spaces (again)
+ sub(/\.$/, "", x); # Kill trailing period
+
+ if (!match(x, / - /))
+ return;
+
+ after_dash = substr(x, RSTART);
+ head = substr(x, 1, RSTART-1) ", ";
+ while (match(head, /, /)) {
+ prog = substr(head, 1, RSTART-1);
+ head = substr(head, RSTART+2);
+ if (prog != progname)
+ prog = prog " [" progname "]";
+ printf "%-*s (%s) %s\n", 20, prog, actual_section, after_dash;
+ }
+ }
+
+ { # Main action - process each filename read in.
+ filename = $0;
+ do_one();
+ }
+ ' pages=$pages section=$section verbose=$verbose curdir=$curdir
+ cd ..
+ fi
+ done > $TMPFILE
+
+ cd "$here"
+
+ if [ -f ${mandir1}/whatis ]
+ then
+ cat ${mandir1}/whatis >> $TMPFILE
+ fi
+ tr -s '\n' < $TMPFILE | sort -u > ${mandir1}/whatis
+
+ chmod 644 ${mandir1}/whatis
+ rm $TMPFILE
+ fi
+ done
+done
+
+# remove tempdir
+rm -rf $TMPFILEDIR
+
diff --git a/src/man-config.c b/src/man-config.c
new file mode 100644
index 0000000..d66cef6
--- /dev/null
+++ b/src/man-config.c
@@ -0,0 +1,297 @@
+/*
+ * man-config.c
+ *
+ * Read the man.conf file
+ *
+ * Input line types:
+ * MANBIN /usr/bin/man
+ * MANPATH /usr/X386/man [/var/catman/X386]
+ * MANPATH_MAP /usr/bin /usr/man
+ * FHS
+ * FSSTND
+ * NOAUTOPATH
+ * NROFF /usr/bin/groff -Tascii -mandoc
+ * BROWSER /usr/bin/lynx
+ * HTMLPAGER /usr/bin/lynx -dump
+ * .gz /usr/bin/gunzip -c
+ * # Comment
+ *
+ * Allow globbing in MANPATH elements.
+ * This is useful e.g. for having MANPATH /opt/ * /man
+ * (avoid comment within comment).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "defs.h"
+#include "glob.h"
+#include "man-config.h"
+#include "man.h"
+#include "paths.h"
+#include "gripes.h"
+#include "util.h"
+
+#define BUFSIZE 4096
+
+extern char *rindex (const char *, int); /* not always in <string.h> */
+
+#define whitespace(x) ((x) == ' ' || (x) == '\t')
+
+/* directories listed in config file */
+struct dirs cfdirlist; /* linked list, 1st entry unused */
+
+static void
+addval (char *buf) {
+ int i, len;
+ char *bp;
+
+ for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++) {
+ len = strlen (paths[i].name);
+ bp = buf + len;
+ if(!strncmp (buf, paths[i].name, len) && (!*bp || whitespace(*bp))) {
+ while(whitespace(*bp))
+ bp++;
+ paths[i].path = my_strdup(bp);
+ return;
+ }
+ }
+ gripe (UNRECOGNIZED_LINE, buf);
+}
+
+const char *
+getval (const char *cmd) {
+ int i;
+
+ for (i = 0; i < sizeof(paths)/sizeof(paths[0]); i++)
+ if (!strcmp (cmd, paths[i].name))
+ return paths[i].path; /* never NULL */
+ gripe (GETVAL_ERROR, cmd);
+ return ""; /* impossible */
+}
+
+static void
+adddir (const char *bp, int mandatory) {
+ int i;
+ struct dirs *dlp;
+
+ while (whitespace(*bp))
+ bp++;
+ if (*bp == 0)
+ gripe (PARSE_ERROR_IN_CONFIG);
+
+ dlp = &cfdirlist;
+ while (dlp->nxt)
+ dlp = dlp->nxt;
+ dlp->nxt = (struct dirs *) my_malloc (sizeof(struct dirs));
+ dlp = dlp->nxt;
+ dlp->mandatory = mandatory;
+ dlp->nxt = 0;
+
+ if (!mandatory) {
+ i = 0;
+ while (*bp && !whitespace(*bp)) {
+ if (i < MAXPATHLEN - 1)
+ dlp->bindir[i++] = *bp;
+ bp++;
+ }
+ dlp->bindir[i] = 0;
+
+ while (whitespace(*bp))
+ bp++;
+ } else {
+ dlp->bindir[0] = 0;
+ }
+
+ i = 0;
+ while (*bp && !whitespace(*bp)) {
+ if (i < MAXPATHLEN - 1)
+ dlp->mandir[i++] = *bp;
+ bp++;
+ }
+ dlp->mandir[i] = 0;
+
+ while (whitespace(*bp))
+ bp++;
+
+ i = 0;
+ while (*bp && !whitespace(*bp)) {
+ if (i < MAXPATHLEN - 1)
+ dlp->catdir[i++] = *bp;
+ bp++;
+ }
+ dlp->catdir[i] = 0;
+
+ if (debug) {
+ if (dlp->mandatory)
+ gripe (FOUND_MANDIR, dlp->mandir);
+ else
+ gripe (FOUND_MAP, dlp->bindir, dlp->mandir);
+ if (dlp->catdir[0])
+ gripe (FOUND_CATDIR, dlp->catdir);
+ }
+}
+
+static void
+addglobdir (const char *bp, int mandatory) {
+ const char *dir;
+
+ while (whitespace(*bp))
+ bp++;
+
+ dir = bp;
+ if (index(dir, '*') || index(dir, '?') || index(dir, '[')) {
+ char **dp = glob_filename (dir);
+
+ if (dp && dp != (char **) -1) {
+ while (*dp)
+ adddir(*dp++, mandatory);
+ return;
+ }
+ }
+ adddir(dir, mandatory);
+}
+
+static struct xp {
+ char *extension; /* non-null, including initial . */
+ char *expander;
+ struct xp *nxt;
+} uncompressors; /* linked list, 1st entry unused */
+
+static void
+addext (char *bp) {
+ char *p, csv;
+ struct xp *xpp;
+
+ xpp = &uncompressors;
+ while (xpp->nxt)
+ xpp = xpp->nxt;
+ xpp->nxt = (struct xp *) my_malloc (sizeof(struct xp));
+ xpp = xpp->nxt;
+ xpp->nxt = 0;
+
+ p = bp;
+ while(*p && !whitespace(*p))
+ p++;
+ csv = *p;
+ *p = 0;
+ xpp->extension = my_strdup(bp);
+
+ *p = csv;
+ while(whitespace(*p))
+ p++;
+ xpp->expander = my_strdup(p);
+}
+
+const char *
+get_expander (const char *file) {
+ struct xp *xp;
+ char *extp = NULL;
+
+ if (dohp) {
+ /* Some HP systems have both man1 and man1.Z */
+ /* For man1.Z/file.1 let extp=".Z" */
+ /* For .1 return NULL */
+ int len = strlen (dohp);
+ char *dirname_end = rindex (file, '/');
+ if (dirname_end && !strncmp (dirname_end-len, dohp, len))
+ extp = dohp;
+ } else
+ extp = rindex (file, '.');
+ if (extp != NULL) {
+ if (uncompressors.nxt) {
+ for (xp = uncompressors.nxt; xp; xp = xp->nxt)
+ if (!strcmp (extp, xp->extension))
+ return (xp->expander);
+ } else if (!strcmp (extp, getval("COMPRESS_EXT"))) {
+ return getval("DECOMPRESS");
+ }
+ }
+ return NULL;
+}
+
+const char *configuration_file = "[no configuration file]";
+
+char *default_config_files[] = {
+ CONFIG_FILE, /* compiled-in default */
+ "/etc/man.conf", "/etc/man.config",
+ "/usr/lib/man.conf", "/usr/lib/man.config",
+ "/usr/share/misc/man.conf", "/usr/share/misc/man.config"
+};
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+void
+read_config_file (const char *cf) {
+ char *bp;
+ char *p;
+ char buf[BUFSIZE];
+ FILE *config = NULL;
+
+ if (cf) {
+ /* User explicitly specified a config file */
+ if ((config = fopen (cf, "r")) == NULL) {
+ perror (cf);
+ gripe (CONFIG_OPEN_ERROR, cf);
+ return;
+ }
+ } else {
+ /* Try some things - unfortunately we cannot lookup
+ the config file to use in the config file :-). */
+ int i;
+
+ for(i=0; i < SIZE(default_config_files); i++) {
+ cf = default_config_files[i];
+ if ((config = fopen (cf, "r")) != NULL)
+ break;
+ }
+
+ if (config == NULL) {
+ gripe (CONFIG_OPEN_ERROR, CONFIG_FILE);
+ return;
+ }
+ }
+
+ if (debug)
+ fprintf(stderr, "Reading config file %s\n", cf);
+ configuration_file = cf;
+
+ while ((bp = fgets (buf, BUFSIZE, config)) != NULL) {
+ while (whitespace(*bp))
+ bp++;
+
+ for (p = bp; *p && *p != '#' && *p != '\n'; p++) ;
+ if (!*p) {
+ gripe (LINE_TOO_LONG);
+ gripe (BAD_CONFIG_FILE, cf);
+ return;
+ }
+ while (p > bp && whitespace(p[-1]))
+ p--;
+ *p = 0;
+
+ if (*bp == 0)
+ continue;
+
+ if (!strncmp ("MANPATH_MAP", bp, 11))
+ adddir (bp+11, 0);
+ else if (!strncmp ("MANPATH", bp, 7))
+ addglobdir (bp+7, 1);
+ else if(!strncmp ("MANDATORY_MANPATH", bp, 17))/* backwards compatible */
+ adddir (bp+17, 1);
+ else if (!strncmp ("FHS", bp, 3))
+ fhs = 1;
+ else if (!strncmp ("FSSTND", bp, 6))
+ fsstnd = 1;
+ else if (!strncmp ("NOAUTOPATH", bp, 10))
+ noautopath = 1;
+ else if (!strncmp ("NOCACHE", bp, 7))
+ nocache = 1;
+ else if (*bp == '.')
+ addext (bp);
+ else
+ addval (bp);
+ }
+}
+
diff --git a/src/man-config.h b/src/man-config.h
new file mode 100644
index 0000000..b364ffd
--- /dev/null
+++ b/src/man-config.h
@@ -0,0 +1,6 @@
+const char *getval (const char *);
+const char *get_expander (const char *);
+void read_config_file (const char *cf);
+
+extern struct dirs cfdirlist;
+extern const char *configuration_file;
diff --git a/src/man-getopt.c b/src/man-getopt.c
new file mode 100644
index 0000000..07aecdb
--- /dev/null
+++ b/src/man-getopt.c
@@ -0,0 +1,322 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "defs.h"
+#include "gripes.h"
+#include "man.h"
+#include "man-config.h"
+#include "man-getopt.h"
+#include "util.h"
+#include "version.h"
+
+int alt_system;
+char *alt_system_name;
+char *opt_manpath;
+int global_apropos = 0;
+
+static void
+print_version (void) {
+ gripe (VERSION, progname, version);
+}
+
+static void
+usage (void) {
+ print_version();
+ gripe (USAGE1, progname);
+
+ gripe (USAGE2); /* only for alt_systems */
+
+ gripe (USAGE3);
+ gripe (USAGE4);
+ gripe (USAGE5); /* maybe only if troff found? */
+ gripe (USAGE6);
+
+ gripe (USAGE7); /* only for alt_systems */
+
+ gripe (USAGE8);
+ exit(1);
+}
+
+static char short_opts[] = "B:C:H:xM:P:S:acdDfFhkKm:p:s:tvVwW?";
+
+#ifndef NOGETOPT
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <getopt.h>
+
+static const struct option long_opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { "path", no_argument, NULL, 'w' },
+ { "preformat", no_argument, NULL, 'F' },
+ { NULL, 0, NULL, 0 }
+};
+#endif
+
+/*
+ * Read options, return count.
+ */
+static int
+get_options_from_argvec(int argc, char **argv, char **config_file,
+ char **manpath) {
+ char *s;
+ int c;
+ int optct = 0;
+
+#ifndef NOGETOPT
+ while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1){
+#else
+ while ((c = getopt (argc, argv, short_opts)) != -1) {
+#endif
+ switch (c) {
+ case 'C':
+ no_privileges ();
+ if (config_file)
+ *config_file = my_strdup (optarg);
+ break;
+ case'F':
+ preformat = 1;
+ break;
+ case 'M':
+ if (manpath)
+ *manpath = my_strdup (optarg);
+ break;
+ case 'P':
+ pager = my_strdup (optarg);
+ break;
+ case 'B':
+ browser = my_strdup (optarg);
+ break;
+ case 'H':
+ htmlpager = my_strdup (optarg);
+ break;
+ case 'S':
+ colon_sep_section_list = my_strdup (optarg);
+ break;
+ case 's':
+ /* undocumented; compatibility with Sun */
+ s = colon_sep_section_list = my_strdup (optarg);
+ while (*s) {
+ if (*s == ',')
+ *s = ':';
+ s++;
+ }
+ break;
+ case 'a':
+ findall++;
+ break;
+ case 'c':
+ nocats++;
+ break;
+ case 'D':
+ debug++;
+ case 'd':
+ debug++;
+ break;
+ case 'f':
+ if (do_troff)
+ fatal (INCOMPAT, "-f", "-t");
+ if (apropos)
+ fatal (INCOMPAT, "-f", "-k");
+ if (print_where)
+ fatal (INCOMPAT, "-f", "-w");
+ whatis++;
+ break;
+ case 'k':
+ if (do_troff)
+ fatal (INCOMPAT, "-k", "-t");
+ if (whatis)
+ fatal (INCOMPAT, "-k", "-f");
+ if (print_where)
+ fatal (INCOMPAT, "-k", "-w");
+ apropos++;
+ break;
+ case 'K':
+ global_apropos++;
+ break;
+ case 'm':
+ alt_system++;
+ alt_system_name = my_strdup (optarg);
+ break;
+ /* or: gripe (NO_ALTERNATE); exit(1); */
+ case 'p':
+ roff_directive = my_strdup (optarg);
+ break;
+ case 't':
+ if (apropos)
+ fatal (INCOMPAT, "-t", "-k");
+ if (whatis)
+ fatal (INCOMPAT, "-t", "-f");
+ if (print_where)
+ fatal (INCOMPAT, "-t", "-w");
+ do_troff++;
+ break;
+ case 'v':
+ case 'V':
+ print_version();
+ exit(0);
+ case 'W':
+ one_per_line++;
+ /* fall through */
+ case 'w':
+ if (apropos)
+ fatal (INCOMPAT, "-w", "-k");
+ if (whatis)
+ fatal (INCOMPAT, "-w", "-f");
+ if (do_troff)
+ fatal (INCOMPAT, "-w", "-t");
+ print_where++;
+ break;
+ case 'h':
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ optct++;
+ }
+
+ return optct;
+}
+
+static void
+get_options_from_string(const char *s) {
+ char *s0, *ss;
+ int argct;
+ char **argvec;
+ int optindsv;
+
+ if (!s || *s == 0)
+ return;
+
+ /* In order to avoid having a list of options in two places,
+ massage the string so that it can be fed to getopt() */
+
+ s0 = my_strdup(s);
+
+ /* count arguments */
+ argct = 0;
+ ss = s0;
+ while (*ss) {
+ while (*ss == ' ')
+ ss++;
+ if (*ss) {
+ argct++;
+ while (*ss && *ss != ' ')
+ ss++;
+ }
+ }
+
+ /* allocate argvec */
+ argvec = (char **) my_malloc((argct+2)*sizeof(char *));
+ argct = 0;
+ argvec[argct++] = "dummy";
+ ss = s0;
+ while (*ss) {
+ while (*ss == ' ')
+ *ss++ = 0;
+ if (*ss) {
+ argvec[argct++] = ss;
+ while (*ss && *ss != ' ')
+ ss++;
+ }
+ }
+ argvec[argct] = 0;
+
+ optindsv = optind;
+ optind = 1;
+ get_options_from_argvec(argct, argvec, NULL, NULL);
+ optind = optindsv;
+}
+
+static void
+mysetenv(const char *name, const char *value) {
+#if defined(__sgi__) || defined(__sun__) || defined(sun)
+ int len = strlen(value)+1+strlen(value)+1;
+ char *str = my_malloc(len);
+ sprintf(str, "%s=%s", name, value);
+ putenv(str);
+#else
+ setenv(name, value, 1);
+#endif
+}
+
+/*
+ * Get options from the command line and user environment.
+ * Also reads the configuration file.
+ */
+
+void
+man_getopt (int argc, char **argv) {
+ char *config_file = NULL;
+ char *manp = NULL;
+ int optct = 0;
+
+ optct = get_options_from_argvec(argc, argv, &config_file, &manp);
+
+ read_config_file (config_file);
+
+ /* If no options were given and MANDEFOPTIONS is set, use that */
+ if (optct == 0) {
+ const char *defopts = getval ("MANDEFOPTIONS");
+ get_options_from_string(defopts);
+ }
+
+ /* In case an explicit -P option was given, put it in the
+ environment for possible use with -k or -K.
+ Ignore errors (out of memory?) */
+
+ if (pager && (global_apropos || apropos || whatis))
+ mysetenv("PAGER", pager);
+
+ if (pager == NULL || *pager == '\0')
+ if (((pager = getenv ("MANPAGER")) == NULL) || (*pager == '\0'))
+ if (((pager = getenv ("PAGER")) == NULL) || (*pager == '\0'))
+ pager = getval ("PAGER");
+
+ if (debug)
+ gripe (PAGER_IS, pager);
+
+ /* Ditto for BROWSER and -B */
+ if (browser && (global_apropos || apropos || whatis))
+ mysetenv("BROWSER", browser);
+
+ if (browser == NULL || *browser == '\0')
+ if ((browser = getenv ("BROWSER")) == NULL)
+ browser = getval ("BROWSER");
+
+ if (debug)
+ gripe (BROWSER_IS, browser);
+
+ /* Ditto for HTMLHTMLPAGER and -H */
+ if (htmlpager && (global_apropos || apropos || whatis))
+ mysetenv("HTMLPAGER", htmlpager);
+
+ if (htmlpager == NULL || *htmlpager == '\0')
+ if ((htmlpager = getenv ("HTMLPAGER")) == NULL)
+ htmlpager = getval ("HTMLPAGER");
+
+ if (debug)
+ gripe (HTMLPAGER_IS, htmlpager);
+
+ if (do_compress && !*getval ("COMPRESS")) {
+ if (debug)
+ gripe (NO_COMPRESS);
+ do_compress = 0;
+ }
+
+ if (do_troff && !*getval ("TROFF")) {
+ gripe (NO_TROFF, configuration_file);
+ exit (1);
+ }
+
+ opt_manpath = manp; /* do not yet expand manpath -
+ maybe it is not needed */
+
+ if (alt_system_name == NULL || *alt_system_name == '\0')
+ if ((alt_system_name = getenv ("SYSTEM")) != NULL)
+ alt_system_name = my_strdup (alt_system_name);
+
+}
diff --git a/src/man-getopt.h b/src/man-getopt.h
new file mode 100644
index 0000000..35ad35b
--- /dev/null
+++ b/src/man-getopt.h
@@ -0,0 +1,6 @@
+extern void man_getopt (int argc, char **argv);
+
+extern int global_apropos;
+extern int alt_system;
+extern char *alt_system_name;
+extern char *opt_manpath;
diff --git a/src/man-iconv.c b/src/man-iconv.c
new file mode 100644
index 0000000..9ce1236
--- /dev/null
+++ b/src/man-iconv.c
@@ -0,0 +1,163 @@
+/*
+ * From andy@pylesos.asp-linux.com.ua Tue Dec 3 14:17:38 2002
+ * (polished, aeb)
+ *
+ * Manpages for a given language have a traditional character set.
+ * E.g., for Russian this is koi8r.
+ * If the user uses a different locale, throw in an invocation of iconv.
+ *
+ * Exports:
+ * const char *get_converter (const char *path);
+ * Conversion is to the users locale. Conversion is from the
+ * manpage charset, found in environment variables, or in
+ * PATH/.charset, where PATH is the directory (below that) containing
+ * the man page.
+ *
+ * TODO: adapt this to man.conf way
+ */
+
+/*
+ * By default iconv is not used - this is the wrong interface.
+ * But if you want it, define USE_ICONV.
+ */
+#undef USE_ICONV
+
+#include <stdio.h> /* NULL */
+
+#if defined __GLIBC__ && __GLIBC__ >= 2 && defined USE_ICONV
+#include <stdlib.h> /* getenv */
+#include <unistd.h> /* access */
+#include <string.h> /* strcmp */
+#include <locale.h> /* setlocale */
+#include <langinfo.h> /* nl_langinfo */
+#include <iconv.h> /* iconv_open */
+#include "man-iconv.h" /* get_converter */
+#include "util.h" /* my_strdup */
+#include "man.h" /* debug */
+
+static char *
+find_iconv(void) {
+ static char *iconv_path = NULL;
+ static int inited = 0;
+
+ if (!inited) {
+ char *file = getenv("MAN_ICONV_PATH");
+ if (!file)
+ file = "/usr/bin/iconv";
+ if (access(file, X_OK) == 0)
+ iconv_path = my_strdup(file);
+ inited = 1;
+ }
+ return iconv_path;
+}
+
+static char *
+iconv_extra_flags(void) {
+ static char *iconv_flags = "-cs";
+ static int inited = 0;
+
+ if (!inited) {
+ char *opt = getenv("MAN_ICONV_OPT");
+ if (opt)
+ iconv_flags = my_strdup(opt);
+ inited = 1;
+ }
+ return iconv_flags;
+}
+
+static char *
+get_locale_charset (void) {
+ char *old_lc_ctype, *charset;
+
+ if ((charset = getenv("MAN_ICONV_OUTPUT_CHARSET")) == NULL) {
+ old_lc_ctype = setlocale(LC_CTYPE, "");
+ charset = nl_langinfo(CODESET);
+ setlocale(LC_CTYPE, old_lc_ctype);
+ }
+ return charset;
+}
+
+static char *
+get_man_charset (const char *path) {
+ char *charset_env, *file, *path2, *p;
+ FILE *f = NULL;
+
+ charset_env = getenv("MAN_ICONV_INPUT_CHARSET");
+ if (charset_env)
+ return charset_env;
+
+ if (!path || !*path)
+ return NULL;
+
+ if (debug)
+ fprintf(stderr, "get_man_charset: path=%s\n", path);
+
+ /* strip trailing "/.." and try that directory first */
+ path2 = my_strdup(path);
+ p = strrchr(path2, '/');
+ if (p && !strcmp(p, "/..")) {
+ *p = 0;
+ file = my_xsprintf("%s/.charset", path2);
+ f = fopen(file, "r");
+ free(file);
+ }
+ free(path2);
+
+ /* if that fails, try path itself */
+ if (f == NULL) {
+ file = my_xsprintf("%s/.charset", path);
+ f = fopen(file, "r");
+ free(file);
+ }
+
+ if (f) {
+ char charset[100], *p;
+
+ fgets(charset, sizeof(charset), f);
+ fclose(f);
+ fprintf(stderr, "read %s\n", charset);
+ p = strchr(charset, '\n');
+ if (p) {
+ *p = 0;
+ return my_strdup(charset);
+ }
+ }
+ return NULL;
+}
+
+static int
+is_conversion_supported (char *from, char *to) {
+ iconv_t cd;
+
+ if (!from || !*from || !to || !*to || !strcmp(from,to))
+ return 0;
+ if ((cd = iconv_open(to, from)) != (iconv_t) -1) {
+ iconv_close(cd);
+ return 1;
+ }
+ return 0;
+}
+
+const char *
+get_converter (const char *path) {
+ char *from, *to, *iconv_path;
+
+ iconv_path = find_iconv();
+ from = get_man_charset(path);
+ to = get_locale_charset();
+ if (debug)
+ fprintf(stderr, "get_converter: iconv_path=%s from=%s to=%s\n",
+ iconv_path, from, to);
+ if (iconv_path && is_conversion_supported(from, to))
+ return my_xsprintf("%s %s -f %s -t %s",
+ iconv_path, iconv_extra_flags(), from, to);
+ return NULL;
+}
+#else
+#include "man-iconv.h"
+
+const char *
+get_converter (const char *path) {
+ return NULL;
+}
+#endif /* __GLIBC__ && __GLIBC__ >= 2 */
diff --git a/src/man-iconv.h b/src/man-iconv.h
new file mode 100644
index 0000000..40c9ad8
--- /dev/null
+++ b/src/man-iconv.h
@@ -0,0 +1 @@
+extern const char *get_converter (const char *path);
diff --git a/src/man.c b/src/man.c
new file mode 100644
index 0000000..62eaee4
--- /dev/null
+++ b/src/man.c
@@ -0,0 +1,1366 @@
+/*
+ * man.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ *
+ * Some manpath, compression and locale related changes - aeb - 940320
+ * Some suid related changes - aeb - 941008
+ * Some more fixes, Pauline Middelink & aeb, Oct 1994
+ * man -K: aeb, Jul 1995
+ * Split off of manfile for man2html, aeb, New Year's Eve 1997
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/stat.h> /* for chmod */
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <locale.h>
+#ifdef TERMIOS_HEADER
+#include <sys/termios.h>
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+extern char *index (const char *, int); /* not always in <string.h> */
+extern char *rindex (const char *, int); /* not always in <string.h> */
+
+#include "defs.h"
+#include "gripes.h"
+#include "man.h"
+#include "manfile.h"
+#include "manpath.h"
+#include "man-config.h"
+#include "man-getopt.h"
+#include "man-iconv.h"
+#include "to_cat.h"
+#include "util.h"
+#include "glob.h"
+#include "different.h"
+#include "man-iconv.h"
+
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+const char *progname;
+const char *pager, *browser, *htmlpager;
+char *colon_sep_section_list;
+char *roff_directive;
+char *dohp = 0;
+int do_irix;
+int do_win32;
+int apropos;
+int whatis;
+int nocats; /* set by -c option: do not use cat page */
+ /* this means that cat pages must not be used,
+ perhaps because the user knows they are
+ old or corrupt or so */
+int can_use_cache; /* output device is a tty, width 80 */
+ /* this means that the result may be written
+ in /var/cache, and may be read from there */
+int findall;
+int print_where;
+int one_per_line;
+int do_troff;
+int preformat;
+int debug;
+int fhs;
+int fsstnd;
+int noautopath;
+int nocache;
+static int is_japanese;
+static char *language;
+static char **section_list;
+
+#ifdef DO_COMPRESS
+int do_compress = 1;
+#else
+int do_compress = 0;
+#endif
+
+#define BUFSIZE 8192
+
+/*
+ * Try to determine the line length to use.
+ * Preferences: 1. MANWIDTH, 2. ioctl, 3. COLUMNS, 4. 80
+ *
+ * joey, 950902
+ */
+
+#include <sys/ioctl.h>
+
+int line_length = 80;
+int ll = 0;
+
+static void
+get_line_length(void){
+ char *cp;
+ int width;
+
+ if (preformat) {
+ line_length = 80;
+ return;
+ }
+ if ((cp = getenv ("MANWIDTH")) != NULL && (width = atoi(cp)) > 0) {
+ line_length = width;
+ return;
+ }
+#ifdef TIOCGWINSZ
+ if (isatty(0) && isatty(1)) { /* Jon Tombs */
+ struct winsize wsz;
+
+ if(ioctl(0, TIOCGWINSZ, &wsz))
+ perror("TIOCGWINSZ failed\n");
+ else if(wsz.ws_col) {
+ line_length = wsz.ws_col;
+ return;
+ }
+ }
+#endif
+ if ((cp = getenv ("COLUMNS")) != NULL && (width = atoi(cp)) > 0)
+ line_length = width;
+ else
+ line_length = 80;
+}
+
+static int
+setll(void) {
+ return
+ (!do_troff && (line_length < 66 || line_length > 80)) ?
+ line_length*9/10 : 0;
+}
+
+/* People prefer no page headings in their man screen output;
+ now ".pl 0" has a bad effect on .SH etc, so we need ".pl N"
+ for some large number N, like 1100i (a hundred pages). */
+#define VERY_LONG_PAGE "1100i"
+
+static char *
+setpl(void) {
+ char *pl;
+ if (do_troff)
+ return NULL;
+ if (preformat)
+ pl = VERY_LONG_PAGE;
+ else
+ if ((pl = getenv("MANPL")) == 0) {
+ if (isatty(0) && isatty(1))
+ pl = VERY_LONG_PAGE;
+ else
+ pl = "11i"; /* old troff default */
+ }
+ return pl;
+}
+
+/*
+ * Check to see if the argument is a valid section number. If the
+ * first character of name is a numeral, or the name matches one of
+ * the sections listed in section_list, we'll assume that it's a section.
+ * The list of sections in config.h simply allows us to specify oddly
+ * named directories like .../man3f. Yuk.
+ */
+static char *
+is_section (char *name) {
+ char **vs;
+
+ /* 3Xt may be a section, but 3DBorder is a man page */
+ if (isdigit (name[0]) && !isdigit (name[1]) && strlen(name) < 5)
+ return my_strdup (name);
+
+ for (vs = section_list; *vs != NULL; vs++)
+ if (strcmp (*vs, name) == 0)
+ return my_strdup (name);
+
+ return NULL;
+}
+
+
+static void
+remove_file (char *file) {
+ int i;
+
+ i = unlink (file);
+
+ if (debug) {
+ if (i)
+ perror(file);
+ else
+ gripe (UNLINKED, file);
+ }
+}
+
+static void
+remove_other_catfiles (const char *catfile) {
+ char *pathname;
+ char *t;
+ char **gf;
+ int offset;
+
+ pathname = my_strdup(catfile);
+ t = rindex(pathname, '.');
+ if (t == NULL || strcmp(t, getval("COMPRESS_EXT")))
+ return;
+ offset = t - pathname;
+ strcpy(t, "*");
+ gf = glob_filename (pathname);
+
+ if (gf != (char **) -1 && gf != NULL) {
+ for ( ; *gf; gf++) {
+ /*
+ * Only remove files with a known extension, like .Z
+ * (otherwise we might kill a lot when called with
+ * catfile = ".gz" ...)
+ */
+ if (strlen (*gf) <= offset) {
+ if (strlen (*gf) == offset) /* uncompressed version */
+ remove_file (*gf);
+ continue;
+ }
+
+ if (!strcmp (*gf + offset, getval("COMPRESS_EXT")))
+ continue;
+
+ if (get_expander (*gf) != NULL)
+ remove_file (*gf);
+ }
+ }
+}
+
+/*
+ * Simply display the preformatted page.
+ */
+static int
+display_cat_file (const char *file) {
+ int found;
+
+ if (preformat)
+ return 1; /* nothing to do - preformat only */
+
+ found = 0;
+
+ if (access (file, R_OK) == 0 && different_cat_file(file)) {
+ char *command = NULL;
+ const char *expander = get_expander (file);
+
+ if (expander != NULL && expander[0] != 0) {
+ if (isatty(1))
+ command = my_xsprintf("%s %S | %s", expander, file, pager);
+ else
+ command = my_xsprintf("%s %S", expander, file);
+ } else {
+ if (isatty(1)) {
+ command = my_xsprintf("%s %S", pager, file);
+ } else {
+ const char *cat = getval("CAT");
+ command = my_xsprintf("%s %S", cat[0] ? cat : "cat", file);
+ }
+ }
+ found = !do_system_command (command, 0);
+ }
+ return found;
+}
+
+/*
+ * Simply display the preformatted page.
+ */
+static int
+display_html_file (const char *file) {
+ int found;
+
+ found = 0;
+
+ if (access (file, R_OK) == 0 && different_cat_file(file)) {
+ char *command = NULL;
+
+ if (isatty(1)) {
+ command = my_xsprintf("%s %S", browser, file);
+ } else {
+ command = my_xsprintf("%s %S", htmlpager, file);
+ }
+ found = !do_system_command (command, 0);
+ }
+ return found;
+
+ return 1;
+}
+
+/*
+ * Try to find the ultimate source file. If the first line of the
+ * current file is not of the form
+ *
+ * .so man3/printf.3s
+ *
+ * the input file name is returned.
+ *
+ * For /cd/usr/src/usr.bin/util-linux-1.5/mount/umount.8.gz
+ * (which contains `.so man8/mount.8')
+ * we return /cd/usr/src/usr.bin/util-linux-1.5/mount/mount.8.gz .
+ *
+ * For /usr/man/man3/TIFFScanlineSize.3t
+ * (which contains `.so TIFFsize.3t')
+ * we return /usr/man/man3/TIFFsize.3t .
+ */
+static const char *
+ultimate_source (const char *name0) {
+ FILE *fp;
+ char *name;
+ const char *expander;
+ int expfl = 0;
+ char *fgr;
+ char *beg;
+ char *end;
+ char *cp;
+ char buf[BUFSIZE];
+ static char ultname[BUFSIZE];
+
+ if (strlen(name0) >= sizeof(ultname))
+ return name0;
+ strcpy(ultname, name0);
+ name = ultname;
+
+again:
+ expander = get_expander (name);
+ if (expander && *expander) {
+ char *command;
+
+ command = my_xsprintf ("%s %S", expander, name);
+ fp = my_popen (command, "r");
+ if (fp == NULL) {
+ perror("popen");
+ gripe (EXPANSION_FAILED, command);
+ return (NULL);
+ }
+ fgr = fgets (buf, sizeof(buf), fp);
+
+ #ifdef __APPLE__
+ /* Man 1.5x randomly freezes under Mac OS X 10.4.7 when the
+ man page is compressed (with either gzip or bzip2), and
+ only with large pages.
+ The freeze occurs at the pclose function, and a ps shows
+ that gunzip is still running.
+
+ The problem is the specification of pclose(): The pclose()
+ function waits for the associated process to terminate
+ and returns the exit status of the command as returned by
+ wait4().
+
+ So, if gunzip is started to look at the start of a file and
+ the file is larger than the buffer used by stdio then the
+ first read does not read everything, and the pclose hangs. */
+
+ /* Reading loop insures lockup cannot occur */
+ char dummy[BUFSIZE];
+ while (fgets (dummy,sizeof(dummy),fp) );
+ #endif // __APPLE__
+
+ pclose (fp);
+ expfl = 1;
+ } else {
+ fp = fopen (name, "r");
+ if (fp == NULL && expfl) {
+ char *extp = rindex (name0, '.');
+ if (extp && *extp && strlen(name)+strlen(extp) < BUFSIZE) {
+ strcat(name, extp);
+ fp = fopen (name, "r");
+ }
+ }
+ /*
+ * Some people have compressed man pages, but uncompressed
+ * .so files - we could glob for all possible extensions,
+ * for now: only try .gz
+ */
+ else if (fp == NULL && get_expander(".gz") &&
+ strlen(name)+strlen(".gz") < BUFSIZE) {
+ strcat(name, ".gz");
+ fp = fopen (name, "r");
+ }
+
+ if (fp == NULL) {
+ perror("fopen");
+ gripe (OPEN_ERROR, name);
+ return (NULL);
+ }
+ fgr = fgets (buf, sizeof(buf), fp);
+ fclose (fp);
+ }
+
+ if (fgr == NULL) {
+ perror("fgets");
+ gripe (READ_ERROR, name);
+ return (NULL);
+ }
+
+ if (strncmp(buf, ".so", 3))
+ return (my_strdup(name));
+
+ beg = buf+3;
+ while (*beg == ' ' || *beg == '\t')
+ beg++;
+
+ end = beg;
+ while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
+ end++; /* note that buf is NUL-terminated */
+ *end = '\0';
+
+ /* If name ends in path/manx/foo.9x then use path, otherwise
+ try same directory. */
+ if ((cp = rindex(name, '/')) == NULL) /* very strange ... */
+ return 0;
+ *cp = 0;
+
+ /* allow "man ./foo.3" where foo.3 contains ".so man2/bar.2" */
+ if ((cp = rindex(name, '/')) != NULL && !strcmp(cp+1, "."))
+ *cp = 0;
+
+ /* In all cases, the new name will be something from name
+ followed by something from beg. */
+ if (strlen(name) + strlen(beg) + 1 >= BUFSIZ)
+ return 0; /* very long names, ignore */
+
+ if (!index(beg, '/')) {
+ /* strange.. try same directory as the .so file */
+ strcat(name, "/");
+ strcat(name, beg);
+ } else if((cp = rindex(name, '/')) != NULL && !strncmp(cp+1, "man", 3)) {
+ strcpy(cp+1, beg);
+ } else if((cp = rindex(beg, '/')) != NULL) {
+ strcat(name, cp);
+ } else {
+ strcat(name, "/");
+ strcat(name, beg);
+ }
+
+ goto again;
+}
+
+static void
+add_directive (const char *d, const char *file, char *buf, int buflen) {
+ if ((d = getval(d)) != 0 && *d) {
+ if (*buf == 0) {
+ if (strlen(d) + strlen(file) + 2 > buflen)
+ return;
+ strcpy (buf, d);
+ strcat (buf, " ");
+ strcat (buf, file);
+ } else {
+ if (strlen(d) + strlen(buf) + 4 > buflen)
+ return;
+ strcat (buf, " | ");
+ strcat (buf, d);
+ }
+ }
+}
+
+static int
+is_lang_page (char *lang, const char *file) {
+ char lang_path[16] = "";
+
+ snprintf(lang_path, sizeof(lang_path), "/%s/", lang);
+ if (strstr(file, lang_path))
+ return 1;
+ if (strlen(lang) > 2) {
+ lang_path[3] = '/';
+ lang_path[4] = 0;
+ if (strstr(file, lang_path))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+parse_roff_directive (char *cp, const char *file, char *buf, int buflen) {
+ char c;
+ int tbl_found = 0;
+ int use_jroff;
+
+ use_jroff = (is_japanese &&
+ (strstr(file, "/jman/") || is_lang_page(language, file)));
+
+ while ((c = *cp++) != '\0') {
+ switch (c) {
+ case 'e':
+ if (debug)
+ gripe (FOUND_EQN);
+ add_directive((do_troff ? "EQN" : use_jroff ? "JNEQN": "NEQN"),
+ file, buf, buflen);
+ break;
+
+ case 'g':
+ if (debug)
+ gripe (FOUND_GRAP);
+ add_directive ("GRAP", file, buf, buflen);
+ break;
+
+ case 'p':
+ if (debug)
+ gripe (FOUND_PIC);
+ add_directive ("PIC", file, buf, buflen);
+ break;
+
+ case 't':
+ if (debug)
+ gripe (FOUND_TBL);
+ tbl_found++;
+ add_directive ("TBL", file, buf, buflen);
+ break;
+
+ case 'v':
+ if (debug)
+ gripe (FOUND_VGRIND);
+ add_directive ("VGRIND", file, buf, buflen);
+ break;
+
+ case 'r':
+ if (debug)
+ gripe (FOUND_REFER);
+ add_directive ("REFER", file, buf, buflen);
+ break;
+
+ case ' ':
+ case '\t':
+ case '\n':
+ goto done;
+
+ default:
+ return -1;
+ }
+ }
+
+done:
+ if (*buf == 0)
+ return 1;
+
+ add_directive (do_troff ? "TROFF" : use_jroff ? "JNROFF" : "NROFF",
+ "", buf, buflen);
+
+ if (tbl_found && !do_troff && *getval("COL"))
+ add_directive ("COL", "", buf, buflen);
+
+ return 0;
+}
+
+static char *
+eos(char *s) {
+ while(*s) s++;
+ return s;
+}
+
+/*
+ * Create command to format FILE, in the directory PATH/manX
+ */
+static char *
+make_roff_command (const char *path, const char *file) {
+ FILE *fp;
+ static char buf [BUFSIZE];
+ char line [BUFSIZE], bufh [BUFSIZE], buft [BUFSIZE];
+ int status, ll;
+ char *cp, *fgr, *pl;
+ char *command = "";
+ const char *expander;
+ const char *converter;
+
+ /* if window size differs much from 80, try to adapt */
+ /* (but write only standard formatted files to the cat directory,
+ see can_use_cache) */
+ ll = setll();
+ pl = setpl();
+ if (ll && debug)
+ gripe (NO_CAT_FOR_NONSTD_LL);
+
+ expander = get_expander (file);
+ converter = get_converter (path);
+
+ /* head */
+ bufh[0] = 0;
+ if (ll || pl) {
+ /* some versions of echo do not accept the -e flag,
+ so we just use two echo calls when needed */
+ strcat(bufh, "(");
+ if (ll) {
+ /*
+ * We should set line length and title line length.
+ * However, a .lt command here fails, only
+ * .ev 1; .lt ...; .ev helps for my version of groff.
+ * The LL assignment is needed by the mandoc macros.
+ */
+ sprintf(eos(bufh), "echo \".ll %d.%di\"; ", ll/10, ll%10);
+ sprintf(eos(bufh), "echo \".nr LL %d.%di\"; ", ll/10, ll%10);
+#if 0
+ sprintf(eos(bufh), "echo \".lt %d.%di\"; ", ll/10, ll%10);
+#endif
+ }
+ if (pl)
+ sprintf(eos(bufh), "echo \".pl %.128s\"; ", pl);
+ }
+
+ /* tail */
+ buft[0] = 0;
+ if (ll || pl) {
+ if (pl && !strcmp(pl, VERY_LONG_PAGE))
+ /* At end of the nroff source, set the page length to
+ the current position plus 10 lines. This plus setpl()
+ gives us a single page that just contains the whole
+ man page. (William Webber, wew@cs.rmit.edu.au) */
+ strcat(buft, "; echo \".\\\\\\\"\"; echo \".pl \\n(nlu+10\"");
+#if 0
+ /* In case this doesnt work for some reason,
+ michaelkjohnson suggests: I've got a simple
+ awk invocation that I throw into the pipeline: */
+
+ awk 'BEGIN {RS="\n\n\n\n*"} /.*/ {print}'
+#endif
+ strcat(buft, ")");
+ }
+
+ if (expander && *expander) {
+ if (converter && *converter)
+ command = my_xsprintf("%s%s '%S' | %s%s",
+ bufh, expander, file, converter, buft);
+ else
+ command = my_xsprintf("%s%s '%S'%s",
+ bufh, expander, file, buft);
+ } else if (ll || pl) {
+ const char *cat = getval("CAT");
+ if (!cat || !*cat)
+ cat = "cat";
+
+ if (converter && *converter)
+ command = my_xsprintf("%s%s '%S' | %s%s",
+ bufh, cat, file, converter, buft);
+ else
+ command = my_xsprintf("%s%s '%S'%s",
+ bufh, cat, file, buft);
+ }
+
+ if (strlen(command) >= sizeof(buf))
+ exit(1);
+ strcpy(buf, command);
+
+ if (roff_directive != NULL) {
+ if (debug)
+ gripe (ROFF_FROM_COMMAND_LINE);
+
+ status = parse_roff_directive (roff_directive, file,
+ buf, sizeof(buf));
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe (ROFF_CMD_FROM_COMMANDLINE_ERROR);
+ }
+
+ if (expander && *expander) {
+ char *cmd = my_xsprintf ("%s %S", expander, file);
+ fp = my_popen (cmd, "r");
+ if (fp == NULL) {
+ perror("popen");
+ gripe (EXPANSION_FAILED, cmd);
+ return (NULL);
+ }
+ fgr = fgets (line, sizeof(line), fp);
+ pclose (fp);
+ } else {
+ fp = fopen (file, "r");
+ if (fp == NULL) {
+ perror("fopen");
+ gripe (OPEN_ERROR, file);
+ return (NULL);
+ }
+ fgr = fgets (line, sizeof(line), fp);
+ fclose (fp);
+ }
+
+ if (fgr == NULL) {
+ perror("fgets");
+ gripe (READ_ERROR, file);
+ return (NULL);
+ }
+
+ cp = &line[0];
+ if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ') {
+ if (debug)
+ gripe (ROFF_FROM_FILE, file);
+
+ status = parse_roff_directive (cp, file, buf, sizeof(buf));
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe (ROFF_CMD_FROM_FILE_ERROR, file);
+ }
+
+ if ((cp = getenv ("MANROFFSEQ")) != NULL) {
+ if (debug)
+ gripe (ROFF_FROM_ENV);
+
+ status = parse_roff_directive (cp, file, buf, sizeof(buf));
+
+ if (status == 0)
+ return buf;
+
+ if (status == -1)
+ gripe (MANROFFSEQ_ERROR);
+ }
+
+ if (debug)
+ gripe (USING_DEFAULT);
+
+ (void) parse_roff_directive ("t", file, buf, sizeof(buf));
+
+ return buf;
+}
+
+/*
+ * Try to format the man page and create a new formatted file. Return
+ * 1 for success and 0 for failure.
+ */
+static int
+make_cat_file (const char *path, const char *man_file, const char *cat_file) {
+ int mode;
+ FILE *fp;
+ char *roff_command;
+ char *command = NULL;
+ struct stat statbuf;
+
+ /* _Before_ first, make sure we will write to a regular file. */
+ if (stat(cat_file, &statbuf) == 0) {
+ if(!S_ISREG(statbuf.st_mode)) {
+ if (debug)
+ gripe (CAT_OPEN_ERROR, cat_file);
+ return 0;
+ }
+ }
+
+ /* First make sure we can write the file; create an empty file. */
+ /* If we are suid it must get mode 0666. */
+ if ((fp = fopen (cat_file, "w")) == NULL) {
+ if (errno == ENOENT) /* directory does not exist */
+ return 0;
+
+ /* If we cannot write the file, maybe we can delete it */
+ if(unlink (cat_file) != 0 || (fp = fopen (cat_file, "w")) == NULL) {
+ if (errno == EROFS) /* possibly a CDROM */
+ return 0;
+ if (debug)
+ gripe (CAT_OPEN_ERROR, cat_file);
+ if (!suid)
+ return 0;
+
+ /* maybe the real user can write it */
+ /* note: just doing "> %s" gives the wrong exit status */
+ command = my_xsprintf("cp /dev/null %S 2>/dev/null", cat_file);
+ if (do_system_command(command, 1)) {
+ if (debug)
+ gripe (USER_CANNOT_OPEN_CAT);
+ return 0;
+ }
+ if (debug)
+ gripe (USER_CAN_OPEN_CAT);
+ }
+ } else {
+ /* we can write it - good */
+ fclose (fp);
+
+ /* but maybe the real user cannot - let's allow everybody */
+ /* the mode is reset below */
+ if (suid) {
+ if (chmod (cat_file, 0666)) {
+ /* probably we are sgid but not owner;
+ just delete the file and create it again */
+ if(unlink(cat_file) != 0) {
+ command = my_xsprintf("rm %S", cat_file);
+ (void) do_system_command (command, 1);
+ }
+ if ((fp = fopen (cat_file, "w")) != NULL)
+ fclose (fp);
+ }
+ }
+ }
+
+ roff_command = make_roff_command (path, man_file);
+ if (roff_command == NULL)
+ return 0;
+ if (do_compress)
+ /* The cd is necessary, because of .so commands,
+ like .so man1/bash.1 in bash_builtins.1.
+ But it changes the meaning of man_file and cat_file,
+ if these are not absolute. */
+
+ command = my_xsprintf("(cd %S && %s | %S > %S)", path,
+ roff_command, getval("COMPRESS"), cat_file);
+ else
+ command = my_xsprintf ("(cd %S && %s > %S)", path,
+ roff_command, cat_file);
+
+ /*
+ * Don't let the user interrupt the system () call and screw up
+ * the formatted man page if we're not done yet.
+ */
+ signal (SIGINT, SIG_IGN);
+
+ gripe (PLEASE_WAIT);
+
+ if (!do_system_command (command, 0)) {
+ /* success */
+ mode = ((ruid != euid) ? 0644 : (rgid != egid) ? 0464 : 0444);
+ if(chmod (cat_file, mode) != 0 && suid) {
+ command = my_xsprintf ("chmod 0%o %S", mode, cat_file);
+ (void) do_system_command (command, 1);
+ }
+ /* be silent about the success of chmod - it is not important */
+ if (debug)
+ gripe (CHANGED_MODE, cat_file, mode);
+ } else {
+ /* something went wrong - remove garbage */
+ if(unlink(cat_file) != 0 && suid) {
+ command = my_xsprintf ("rm %S", cat_file);
+ (void) do_system_command (command, 1);
+ }
+ }
+
+ signal (SIGINT, SIG_DFL);
+
+ return 1;
+}
+
+static int
+display_man_file(const char *path, const char *man_file) {
+ char *roff_command;
+ char *command;
+
+ if (!different_man_file (man_file))
+ return 0;
+ roff_command = make_roff_command (path, man_file);
+ if (roff_command == NULL)
+ return 0;
+ if (do_troff)
+ command = my_xsprintf ("(cd \"%S\" && %s)", path, roff_command);
+ else
+ command = my_xsprintf ("(cd \"%S\" && %s | %s)", path,
+ roff_command, pager);
+
+ return !do_system_command (command, 0);
+}
+
+/*
+ * make and display the cat file - return 0 if something went wrong
+ */
+static int
+make_and_display_cat_file (const char *path, const char *man_file) {
+ const char *cat_file;
+ const char *ext;
+ int status;
+ int standards;
+
+ ext = (do_compress ? getval("COMPRESS_EXT") : 0);
+
+ standards = (fhs ? FHS : 0) | (fsstnd ? FSSTND : 0) | (dohp ? DO_HP : 0);
+
+ if ((cat_file = convert_to_cat(man_file, ext, standards)) == NULL)
+ return 0;
+
+ if (debug)
+ gripe (PROPOSED_CATFILE, cat_file);
+
+ /*
+ * If cat_file exists, check whether it is more recent.
+ * Otherwise, check for other cat files (maybe there are
+ * old .Z files that should be removed).
+ */
+
+ status = ((nocats | preformat) ? -2 : is_newer (man_file, cat_file));
+ if (debug)
+ gripe (IS_NEWER_RESULT, status);
+ if (status == -1 || status == -3) {
+ /* what? man_file does not exist anymore? */
+ gripe (CANNOT_STAT, man_file);
+ return(0);
+ }
+
+ if (status != 0 || access (cat_file, R_OK) != 0) {
+ /*
+ * Cat file is out of date (status = 1) or does not exist or is
+ * empty or is to be rewritten (status = -2) or is unreadable.
+ * Try to format and save it.
+ */
+ if (print_where) {
+ printf ("%s\n", man_file);
+ return 1;
+ }
+
+ if (!make_cat_file (path, man_file, cat_file))
+ return 0;
+
+ /*
+ * If we just created this cat file, unlink any others.
+ */
+ if (status == -2 && do_compress)
+ remove_other_catfiles(cat_file);
+ } else {
+ /*
+ * Formatting not necessary. Cat file is newer than source
+ * file, or source file is not present but cat file is.
+ */
+ if (print_where) {
+ if (one_per_line) {
+ /* addition by marty leisner - leisner@sdsp.mc.xerox.com */
+ printf("%s\n", cat_file);
+ printf("%s\n", man_file);
+ } else
+ printf ("%s (<-- %s)\n", cat_file, man_file);
+ return 1;
+ }
+ }
+ (void) display_cat_file (cat_file);
+ return 1;
+}
+
+/*
+ * Try to format the man page source and save it, then display it. If
+ * that's not possible, try to format the man page source and display
+ * it directly.
+ */
+static int
+format_and_display (const char *man_file) {
+ const char *path;
+
+ if (access (man_file, R_OK) != 0)
+ return 0;
+
+ path = mandir_of(man_file);
+ if (path == NULL)
+ return 0;
+
+ /* first test for contents .so man1/xyzzy.1 */
+ /* (in that case we do not want to make a cat file identical
+ to cat1/xyzzy.1) */
+ man_file = ultimate_source (man_file);
+ if (man_file == NULL)
+ return 0;
+
+ if (do_troff) {
+ char *command;
+ char *roff_command = make_roff_command (path, man_file);
+
+ if (roff_command == NULL)
+ return 0;
+
+ command = my_xsprintf("(cd \"%S\" && %s)", path, roff_command);
+ return !do_system_command (command, 0);
+ }
+
+ if (can_use_cache && make_and_display_cat_file (path, man_file))
+ return 1;
+
+ /* line length was wrong or could not display cat_file */
+ if (print_where) {
+ printf ("%s\n", man_file);
+ return 1;
+ }
+
+ return display_man_file (path, man_file);
+}
+
+/*
+ * Search for manual pages.
+ *
+ * If preformatted manual pages are supported, look for the formatted
+ * file first, then the man page source file. If they both exist and
+ * the man page source file is newer, or only the source file exists,
+ * try to reformat it and write the results in the cat directory. If
+ * it is not possible to write the cat file, simply format and display
+ * the man file.
+ *
+ * If preformatted pages are not supported, or the troff option is
+ * being used, only look for the man page source file.
+ *
+ * Note that globbing is necessary also if the section is given,
+ * since a preformatted man page might be compressed.
+ *
+ */
+static int
+man (const char *name, const char *section) {
+ int found, type, flags;
+ struct manpage *mp;
+
+ found = 0;
+
+ /* allow man ./manpage for formatting explicitly given man pages */
+ if (index(name, '/')) {
+ char fullname[BUFSIZE];
+ char fullpath[BUFSIZE];
+ char *path;
+ char *cp;
+ FILE *fp = fopen(name, "r");
+
+ if (!fp) {
+ perror(name);
+ return 0;
+ }
+ fclose (fp);
+ if (*name != '/' && getcwd(fullname, sizeof(fullname))
+ && strlen(fullname) + strlen(name) + 3 < sizeof(fullname)) {
+ strcat (fullname, "/");
+ strcat (fullname, name);
+ } else if (strlen(name) + 2 < sizeof(fullname)) {
+ strcpy (fullname, name);
+ } else {
+ fprintf(stderr, "%s: name too long\n", name);
+ return 0;
+ }
+
+ strcpy (fullpath, fullname);
+ if ((cp = rindex(fullpath, '/')) != NULL
+ && cp-fullpath+4 < sizeof(fullpath)) {
+ strcpy(cp+1, "..");
+ path = fullpath;
+ } else
+ path = ".";
+
+ name = ultimate_source (fullname);
+ if (!name)
+ return 0;
+
+ if (print_where) {
+ printf("%s\n", name);
+ return 1;
+ }
+ return display_man_file (path, name);
+ }
+
+ fflush (stdout);
+ init_manpath();
+
+ can_use_cache = nocache ? 0 : (preformat || print_where ||
+ (isatty(0) && isatty(1) && !setll()));
+
+ if (do_troff) {
+ const char *t = getval("TROFF");
+ if (!t || !*t)
+ return 0; /* don't know how to format */
+ type = TYPE_MAN;
+ } else {
+ const char *n = getval("NROFF");
+ type = 0;
+ if (can_use_cache)
+ type |= TYPE_CAT;
+ if (n && *n)
+ type |= TYPE_MAN;
+ if (fhs || fsstnd)
+ type |= TYPE_SCAT;
+
+ n = getval("BROWSER");
+ if (n && *n)
+ type |= TYPE_HTML;
+ }
+
+ flags = type;
+ if (!findall)
+ flags |= ONLY_ONE;
+ if (fsstnd)
+ flags |= FSSTND;
+ else if (fhs)
+ flags |= FHS;
+ if (dohp)
+ flags |= DO_HP;
+ if (do_irix)
+ flags |= DO_IRIX;
+ if (do_win32)
+ flags |= DO_WIN32;
+
+ mp = manfile(name, section, flags, section_list, mandirlist,
+ convert_to_cat);
+ found = 0;
+ while (mp) {
+ if (mp->type == TYPE_MAN) {
+ found = format_and_display(mp->filename);
+ } else if (mp->type == TYPE_CAT || mp->type == TYPE_SCAT) {
+ if (print_where) {
+ printf ("%s\n", mp->filename);
+ found = 1;
+ } else
+ found = display_cat_file(mp->filename);
+ } else if (mp->type == TYPE_HTML) {
+ if (print_where) {
+ printf ("%s\n", mp->filename);
+ found = 1;
+ } else
+ found = display_html_file(mp->filename);
+ } else
+ /* internal error */
+ break;
+ if (found && !findall)
+ break;
+ mp = mp->next;
+ }
+ return found;
+}
+
+static char **
+get_section_list (void) {
+ int i;
+ const char *p;
+ char *end;
+ static char *tmp_section_list[100];
+
+ if (colon_sep_section_list == NULL) {
+ if ((p = getenv ("MANSECT")) == NULL)
+ p = getval ("MANSECT");
+ colon_sep_section_list = my_strdup (p);
+ }
+
+ i = 0;
+ for (p = colon_sep_section_list; ; p = end+1) {
+ if ((end = strchr (p, ':')) != NULL)
+ *end = '\0';
+
+ tmp_section_list[i++] = my_strdup (p);
+
+ if (end == NULL || i+1 == SIZE(tmp_section_list))
+ break;
+ }
+
+ tmp_section_list [i] = NULL;
+ return tmp_section_list;
+}
+
+/* return 0 when all was OK */
+static int
+do_global_apropos (char *name, char *section) {
+ char **dp, **gf;
+ char *pathname;
+ char *command;
+ int status, res;
+
+ status = 0;
+ init_manpath();
+ if (mandirlist)
+ for (dp = mandirlist; *dp; dp++) {
+ if (debug)
+ gripe(SEARCHING, *dp);
+ pathname = my_xsprintf("%s/man%s/*", *dp, section ? section : "*");
+ gf = glob_filename (pathname);
+ free(pathname);
+
+ if (gf != (char **) -1 && gf != NULL) {
+ for( ; *gf; gf++) {
+ const char *expander = get_expander (*gf);
+ if (expander)
+ command = my_xsprintf("%s %S | grep '%Q'"
+ "> /dev/null 2> /dev/null",
+ expander, *gf, name);
+ else
+ command = my_xsprintf("grep '%Q' %S"
+ "> /dev/null 2> /dev/null",
+ name, *gf);
+ res = do_system_command (command, 1);
+ status |= res;
+ free (command);
+ if (res == 0) {
+ if (print_where)
+ printf("%s\n", *gf);
+ else {
+ /* should read LOCALE, but libc 4.6.27 doesn't
+ seem to handle LC_RESPONSE yet */
+ int answer, c;
+ char path[BUFSIZE];
+
+ printf("%s? [ynq] ", *gf);
+ fflush(stdout);
+ answer = c = getchar();
+ while (c != '\n' && c != EOF)
+ c = getchar();
+ if(index("QqXx", answer))
+ exit(0);
+ if(index("YyJj", answer)) {
+ char *ri;
+
+ strcpy(path, *gf);
+ ri = rindex(path, '/');
+ if (ri)
+ *ri = 0;
+ format_and_display(*gf);
+ }
+ }
+ }
+ }
+ }
+ }
+ return status;
+}
+
+/* Special code for Japanese (to pick jnroff instead of nroff, etc.) */
+static void
+setlang(void) {
+ char *lang;
+
+ /* We use getenv() instead of setlocale(), because of
+ glibc 2.1.x security policy for SetUID/SetGID binary. */
+ if ((lang = getenv("LANG")) == NULL &&
+ (lang = getenv("LC_ALL")) == NULL &&
+ (lang = getenv("LC_CTYPE")) == NULL)
+ /* nothing */;
+
+ language = lang;
+ is_japanese = (lang && strncmp(lang, "ja", 2) == 0);
+}
+
+/*
+ * Handle the apropos option. Cheat by using another program.
+ */
+static int
+do_apropos (char *name) {
+ char *command;
+
+ command = my_xsprintf("'%s' '%Q'", getval("APROPOS"), name);
+ return do_system_command (command, 0);
+}
+
+/*
+ * Handle the whatis option. Cheat by using another program.
+ */
+static int
+do_whatis (char *name) {
+ char *command;
+
+ command = my_xsprintf("'%s' '%Q'", getval("WHATIS"), name);
+ return do_system_command (command, 0);
+}
+
+int
+main (int argc, char **argv) {
+ int status = 0;
+ char *nextarg;
+ char *tmp;
+ char *section = 0;
+
+#ifdef __CYGWIN__
+ extern int optind;
+#endif
+
+
+#if 0
+ {
+ /* There are no known cases of buffer overflow caused by
+ excessively long environment variables. In case you find one,
+ the simplistic way to fix is to enable this stopgap. */
+ char *s;
+#define CHECK(p,l) s=getenv(p); if(s && strlen(s)>(l)) { fprintf(stderr, "ERROR: Environment variable %s too long!\n", p); exit(1); }
+ CHECK("LANG", 32);
+ CHECK("LANGUAGE", 128);
+ CHECK("LC_MESSAGES", 128);
+ CHECK("MANPAGER", 128);
+ CHECK("MANPL", 128);
+ CHECK("MANROFFSEQ", 128);
+ CHECK("MANSECT", 128);
+ CHECK("MAN_HP_DIREXT", 128);
+ CHECK("PAGER", 128);
+ CHECK("SYSTEM", 64);
+ CHECK("BROWSER", 64);
+ CHECK("HTMLPAGER", 64);
+ /* COLUMNS, LC_ALL, LC_CTYPE, MANPATH, MANWIDTH, MAN_IRIX_CATNAMES,
+ MAN_ICONV_PATH, MAN_ICONV_OPT, MAN_ICONV_INPUT_CHARSET,
+ MAN_ICONV_OUTPUT_CHARSET, NLSPATH, PATH */
+ }
+#endif
+
+
+#ifndef __FreeBSD__
+ /* Slaven Rezif: FreeBSD-2.2-SNAP does not recognize LC_MESSAGES. */
+ setlocale(LC_CTYPE, ""); /* used anywhere? maybe only isdigit()? */
+ setlocale(LC_MESSAGES, "");
+#endif
+
+ /* No doubt we'll need some generic language code here later.
+ For the moment only Japanese support. */
+ setlang();
+
+ /* Handle /usr/man/man1.Z/name.1 nonsense from HP */
+ dohp = getenv("MAN_HP_DIREXT"); /* .Z */
+
+ /* Handle ls.z (instead of ls.1.z) cat page naming from IRIX */
+ if (getenv("MAN_IRIX_CATNAMES"))
+ do_irix = 1;
+
+ /* Handle lack of ':' in NTFS file names */
+#if defined(_WIN32) || defined(__CYGWIN__)
+ do_win32 = 1;
+#endif
+
+ progname = mkprogname (argv[0]);
+
+ get_permissions ();
+ get_line_length();
+
+ /*
+ * read command line options and man.conf
+ */
+ man_getopt (argc, argv);
+
+ /*
+ * manpath or man --path or man -w will only print the manpath
+ */
+ if (!strcmp (progname, "manpath") || (optind == argc && print_where)) {
+ init_manpath();
+ prmanpath();
+ exit(0);
+ }
+
+ if (optind == argc)
+ gripe(NO_NAME_NO_SECTION);
+
+ section_list = get_section_list ();
+
+ while (optind < argc) {
+ nextarg = argv[optind++];
+
+ /* is_section correctly accepts 3Xt as section, but also 9wm,
+ so we should not believe is_section() for the last arg. */
+ tmp = is_section (nextarg);
+ if (tmp && optind < argc) {
+ section = tmp;
+ if (debug)
+ gripe (SECTION, section);
+ continue;
+ }
+
+ if (global_apropos)
+ status = !do_global_apropos (nextarg, section);
+ else if (apropos)
+ status = !do_apropos (nextarg);
+ else if (whatis)
+ status = !do_whatis (nextarg);
+ else {
+ status = man (nextarg, section);
+
+ if (status == 0) {
+ if (section)
+ gripe (NO_SUCH_ENTRY_IN_SECTION, nextarg, section);
+ else
+ gripe (NO_SUCH_ENTRY, nextarg);
+ }
+ }
+
+ /* reset duplicate search -
+ fixes Fedora#542852 "man cut cut throws an error" */
+ free_catman_filelists ();
+ }
+ return status ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/man.conf b/src/man.conf
new file mode 100644
index 0000000..88073e4
--- /dev/null
+++ b/src/man.conf
@@ -0,0 +1,144 @@
+#
+# Generated automatically from man.conf.in by the
+# configure script.
+#
+# man.conf from man-1.6g
+#
+# For more information about this file, see the man pages man(1)
+# and man.conf(5).
+#
+# This file is read by man to configure the default manpath (also used
+# when MANPATH contains an empty substring), to find out where the cat
+# pages corresponding to given man pages should be stored,
+# and to map each PATH element to a manpath element.
+# It may also record the pathname of the man binary. [This is unused.]
+# The format is:
+#
+# MANBIN pathname
+# MANPATH manpath_element [corresponding_catdir]
+# MANPATH_MAP path_element manpath_element
+#
+# If no catdir is given, it is assumed to be equal to the mandir
+# (so that this dir has both man1 etc. and cat1 etc. subdirs).
+# This is the traditional Unix setup.
+# Certain versions of the FSSTND recommend putting formatted versions
+# of /usr/.../man/manx/page.x into /var/catman/.../catx/page.x.
+# The keyword FSSTND will cause this behaviour.
+# Certain versions of the FHS recommend putting formatted versions of
+# /usr/.../share/man/[locale/]manx/page.x into
+# /var/cache/man/.../[locale/]catx/page.x.
+# The keyword FHS will cause this behaviour (and overrides FSSTND).
+# Explicitly given catdirs override.
+#
+# FSSTND
+FHS
+#
+# This file is also read by man in order to find how to call nroff, less, etc.,
+# and to determine the correspondence between extensions and decompressors.
+#
+# MANBIN /usr/local/bin/man
+#
+# Every automatically generated MANPATH includes these fields
+#
+MANPATH /usr/man
+MANPATH /usr/share/man
+MANPATH /usr/local/man
+MANPATH /usr/local/share/man
+MANPATH /usr/X11R6/man
+#
+# Uncomment if you want to include one of these by default
+#
+# MANPATH /opt/*/man
+# MANPATH /usr/lib/*/man
+# MANPATH /usr/share/*/man
+# MANPATH /usr/kerberos/man
+#
+# Set up PATH to MANPATH mapping
+#
+# If people ask for "man foo" and have "/dir/bin/foo" in their PATH
+# and the docs are found in "/dir/man", then no mapping is required.
+#
+# The below mappings are superfluous when the right hand side is
+# in the mandatory manpath already, but will keep man from statting
+# lots of other nearby files and directories.
+#
+MANPATH_MAP /bin /usr/share/man
+MANPATH_MAP /sbin /usr/share/man
+MANPATH_MAP /usr/bin /usr/share/man
+MANPATH_MAP /usr/sbin /usr/share/man
+MANPATH_MAP /usr/local/bin /usr/local/share/man
+MANPATH_MAP /usr/local/sbin /usr/local/share/man
+MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
+MANPATH_MAP /usr/bin/X11 /usr/X11R6/man
+MANPATH_MAP /usr/bin/mh /usr/share/man
+#
+# NOAUTOPATH keeps man from automatically adding directories that look like
+# manual page directories to the path.
+#
+#NOAUTOPATH
+#
+# NOCACHE keeps man from creating cache pages ("cat pages")
+# (generally one enables/disable cat page creation by creating/deleting
+# the directory they would live in - man never does mkdir)
+#
+#NOCACHE
+#
+# Useful paths - note that COL should not be defined when
+# NROFF is defined as "groff -Tascii" or "groff -Tlatin1";
+# not only is it superfluous, but it actually damages the output.
+# For use with utf-8, NROFF should be "nroff -mandoc" without -T option.
+# (Maybe - but today I need -Tlatin1 to prevent double conversion to utf8.)
+#
+# If you have a new troff (version 1.18.1?) and its colored output
+# causes problems, add the -c option to TROFF, NROFF, JNROFF.
+#
+TROFF /usr/bin/groff -Tps -mandoc
+NROFF /usr/bin/nroff -Tlatin1 -mandoc
+JNROFF /usr/bin/groff -Tnippon -mandocj
+EQN /usr/bin/geqn -Tps
+NEQN /usr/bin/geqn -Tlatin1
+JNEQN /usr/bin/geqn -Tnippon
+TBL /usr/bin/gtbl
+# COL /usr/bin/col
+REFER
+PIC /usr/bin/gpic
+VGRIND
+GRAP
+PAGER /bin/less -is
+BROWSER /bin/less -is
+HTMLPAGER /bin/cat
+CAT /bin/cat
+#
+# The command "man -a xyzzy" will show all man pages for xyzzy.
+# When CMP is defined man will try to avoid showing the same
+# text twice. (But compressed pages compare unequal.)
+#
+CMP /usr/bin/cmp -s
+#
+# Compress cat pages
+#
+COMPRESS /usr/bin/xz
+COMPRESS_EXT .xz
+#
+# Default manual sections (and order) to search if -S is not specified
+# and the MANSECT environment variable is not set.
+#
+MANSECT 1:1p:8:2:3:3p:4:5:6:7:9:0p:tcl:n:l:p:o
+#
+# Default options to use when man is invoked without options
+# This is mainly for the benefit of those that think -a should be the default
+# Note that some systems have /usr/man/allman, causing pages to be shown twice.
+#
+#MANDEFOPTIONS -a
+#
+# Decompress with given decompressor when input file has given extension
+# The command given must act as a filter.
+#
+.gz /bin/gunzip -c
+.bz2 /bin/bzip2 -c -d
+.lzma /usr/bin/unlzma -c -d
+.z
+.Z /bin/zcat
+.F
+.Y
+.xz /usr/bin/unxz -c
diff --git a/src/man.conf.in b/src/man.conf.in
new file mode 100644
index 0000000..ce73ffc
--- /dev/null
+++ b/src/man.conf.in
@@ -0,0 +1,140 @@
+# man.conf from @version@
+#
+# For more information about this file, see the man pages man(1)
+# and man.conf(5).
+#
+# This file is read by man to configure the default manpath (also used
+# when MANPATH contains an empty substring), to find out where the cat
+# pages corresponding to given man pages should be stored,
+# and to map each PATH element to a manpath element.
+# It may also record the pathname of the man binary. [This is unused.]
+# The format is:
+#
+# MANBIN pathname
+# MANPATH manpath_element [corresponding_catdir]
+# MANPATH_MAP path_element manpath_element
+#
+# If no catdir is given, it is assumed to be equal to the mandir
+# (so that this dir has both man1 etc. and cat1 etc. subdirs).
+# This is the traditional Unix setup.
+# Certain versions of the FSSTND recommend putting formatted versions
+# of /usr/.../man/manx/page.x into /var/catman/.../catx/page.x.
+# The keyword FSSTND will cause this behaviour.
+# Certain versions of the FHS recommend putting formatted versions of
+# /usr/.../share/man/[locale/]manx/page.x into
+# /var/cache/man/.../[locale/]catx/page.x.
+# The keyword FHS will cause this behaviour (and overrides FSSTND).
+# Explicitly given catdirs override.
+#
+@fsstnd@FSSTND
+@fhs@FHS
+#
+# This file is also read by man in order to find how to call nroff, less, etc.,
+# and to determine the correspondence between extensions and decompressors.
+#
+# MANBIN /usr/local/bin/man
+#
+# Every automatically generated MANPATH includes these fields
+#
+MANPATH /usr/man
+MANPATH /usr/share/man
+MANPATH /usr/local/man
+MANPATH /usr/local/share/man
+MANPATH /usr/X11R6/man
+#
+# Uncomment if you want to include one of these by default
+#
+# MANPATH /opt/*/man
+# MANPATH /usr/lib/*/man
+# MANPATH /usr/share/*/man
+# MANPATH /usr/kerberos/man
+#
+# Set up PATH to MANPATH mapping
+#
+# If people ask for "man foo" and have "/dir/bin/foo" in their PATH
+# and the docs are found in "/dir/man", then no mapping is required.
+#
+# The below mappings are superfluous when the right hand side is
+# in the mandatory manpath already, but will keep man from statting
+# lots of other nearby files and directories.
+#
+MANPATH_MAP /bin /usr/share/man
+MANPATH_MAP /sbin /usr/share/man
+MANPATH_MAP /usr/bin /usr/share/man
+MANPATH_MAP /usr/sbin /usr/share/man
+MANPATH_MAP /usr/local/bin /usr/local/share/man
+MANPATH_MAP /usr/local/sbin /usr/local/share/man
+MANPATH_MAP /usr/X11R6/bin /usr/X11R6/man
+MANPATH_MAP /usr/bin/X11 /usr/X11R6/man
+MANPATH_MAP /usr/bin/mh /usr/share/man
+#
+# NOAUTOPATH keeps man from automatically adding directories that look like
+# manual page directories to the path.
+#
+#NOAUTOPATH
+#
+# NOCACHE keeps man from creating cache pages ("cat pages")
+# (generally one enables/disable cat page creation by creating/deleting
+# the directory they would live in - man never does mkdir)
+#
+#NOCACHE
+#
+# Useful paths - note that COL should not be defined when
+# NROFF is defined as "groff -Tascii" or "groff -Tlatin1";
+# not only is it superfluous, but it actually damages the output.
+# For use with utf-8, NROFF should be "nroff -mandoc" without -T option.
+# (Maybe - but today I need -Tlatin1 to prevent double conversion to utf8.)
+#
+# If you have a new troff (version 1.18.1?) and its colored output
+# causes problems, add the -c option to TROFF, NROFF, JNROFF.
+#
+TROFF @troff@
+NROFF @nroff@
+JNROFF @jnroff@
+EQN @eqn@
+NEQN @neqn@
+JNEQN @jneqn@
+TBL @tbl@
+@nocol@COL @col@
+REFER @refer@
+PIC @pic@
+VGRIND @vgrind@
+GRAP @grap@
+PAGER @pager@
+BROWSER @browser@
+HTMLPAGER @htmlpager@
+CAT @cat@
+#
+# The command "man -a xyzzy" will show all man pages for xyzzy.
+# When CMP is defined man will try to avoid showing the same
+# text twice. (But compressed pages compare unequal.)
+#
+CMP @cmp@
+#
+# Compress cat pages
+#
+COMPRESS @compress@
+COMPRESS_EXT @compress_ext@
+#
+# Default manual sections (and order) to search if -S is not specified
+# and the MANSECT environment variable is not set.
+#
+MANSECT @sections@
+#
+# Default options to use when man is invoked without options
+# This is mainly for the benefit of those that think -a should be the default
+# Note that some systems have /usr/man/allman, causing pages to be shown twice.
+#
+#MANDEFOPTIONS -a
+#
+# Decompress with given decompressor when input file has given extension
+# The command given must act as a filter.
+#
+.gz @gunzip@
+.bz2 @bzip2@
+.lzma @unlzma@
+.z @pcat@
+.Z @zcat@
+.F @fcat@
+.Y @unyabba@
+.xz @unxz@
diff --git a/src/man.h b/src/man.h
new file mode 100644
index 0000000..285aac7
--- /dev/null
+++ b/src/man.h
@@ -0,0 +1,22 @@
+extern int debug;
+extern int do_compress;
+extern int fhs;
+extern int fsstnd;
+extern int noautopath;
+extern int nocache;
+extern int findall;
+extern int nocats;
+extern int preformat;
+extern int do_troff;
+extern int apropos;
+extern int whatis;
+extern int print_where;
+extern int one_per_line;
+extern int do_irix;
+extern char *dohp;
+extern const char *progname;
+extern const char *pager;
+extern const char *browser;
+extern const char *htmlpager;
+extern char *colon_sep_section_list;
+extern char *roff_directive;
diff --git a/src/man2dvi b/src/man2dvi
new file mode 100755
index 0000000..f9cb52e
--- /dev/null
+++ b/src/man2dvi
@@ -0,0 +1,36 @@
+#! /bin/sh
+#
+# Script to format manpages to dvi.
+# Copyright (c) 1997 Tobias Begalke (tb@lst.de)
+#
+# Part of release 1.6g of the man suite.
+#
+
+groff="groff -Tdvi -mandoc"
+
+if [ ! $# = 1 ]; then
+ echo "$0: usage:"
+ echo " $0 [topic] > topic.dvi"
+ exit 1
+fi
+
+location=`man -c -w $1`
+
+if [ "$location" = "" ]; then
+ exit 1
+fi
+
+case `file $location` in
+ *gzip* )
+ zcat $location | $groff
+ ;;
+
+ *bzip2* )
+ bzcat $location | $groff
+ ;;
+
+ *troff* )
+ $groff $location
+ ;;
+esac
+
diff --git a/src/manfile.c b/src/manfile.c
new file mode 100644
index 0000000..0df62ea
--- /dev/null
+++ b/src/manfile.c
@@ -0,0 +1,337 @@
+/*
+ * manfile.c - aeb, 971231
+ *
+ * Used both by man and man2html - be careful with printing!
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "glob.h"
+#include "util.h"
+#include "manfile.h"
+#include "gripes.h"
+#include "man.h" /* for debug */
+
+static int standards;
+static const char *((*to_cat_filename)(const char *man_filename,
+ const char *ext, int flags));
+
+/*
+ * Append the struct or chain A to the chain HEAD.
+ */
+static void
+append(struct manpage **head, struct manpage *a) {
+ struct manpage *p;
+
+ if (a) {
+ if (*head) {
+ p = *head;
+ while(p->next)
+ p = p->next;
+ p->next = a;
+ } else
+ *head = a;
+ }
+}
+
+
+static int
+my_lth(const char *s) {
+ return s ? strlen(s) : 0;
+}
+
+/*
+ * Find the files of the form DIR/manSEC/NAME.EXT etc.
+ * Use "man" for TYPE_MAN, "cat" for TYPE_SCAT, and
+ * apply convert_to_cat() to the man version for TYPE_CAT.
+ *
+ * Some HP systems use /usr/man/man1.Z/name.1, where name.1 is
+ * compressed - yuk. We can handle this by using section 1.Z
+ * instead of 1 and assuming that the man page is compressed
+ * if the directory name ends in .Z.
+ *
+ * Some Sun systems use /usr/share/man/sman1/man.1 and
+ * /usr/share/man/sman1m/mkfs.1m.
+ *
+ * We support HTML filenames of the following form:
+ * /usr/share/man/sman1m/mkfs.1m.html, optionally followed
+ * by a compression suffix.
+ *
+ * Returns an array with pathnames, or 0 if out-of-memory or error.
+ */
+static char **
+glob_for_file_ext_glob (const char *dir, const char *sec,
+ const char *name, const char *ext, char *hpx,
+ int glob, int type) {
+ char *pathname;
+ const char *p;
+ char **names;
+ int len;
+#define MANFORM "%s/%s%s%s/%s.%s"
+#define GLOB "*"
+#define LENGTHOF(s) (sizeof(s)-1)
+/* This must be long enough to hold the format-directory name.
+ * The basic type-directory names are 'cat' and 'man'; this needs to
+ * allocate space for those or any others such as html or sman.
+ */
+#define TYPELEN 8
+
+ len = my_lth(dir) + my_lth(sec) + my_lth(hpx) + my_lth(name) + my_lth(ext)
+ + TYPELEN
+ + LENGTHOF(".html") + LENGTHOF(MANFORM) + LENGTHOF(GLOB);
+
+ if (debug >= 2)
+ gripe(CALLTRACE3, dir, sec, name, ext, hpx, glob, type);
+
+ pathname = (char *) malloc(len);
+ if (!pathname)
+ return 0;
+
+ sprintf (pathname, MANFORM,
+ dir,
+ (type==TYPE_HTML) ? "html" : (type==TYPE_XML) ? "sman" : (type==TYPE_SCAT) ? "cat" : "man",
+ sec, hpx, name, ext);
+ if (type == TYPE_HTML)
+ strcat(pathname, ".html");
+ if (glob)
+ strcat(pathname, GLOB);
+
+ if (type == TYPE_CAT) {
+ p = to_cat_filename(pathname, 0, standards);
+ if (p) {
+ free(pathname);
+ } else {
+ sprintf (pathname, "%s/cat%s%s/%s.%s%s",
+ dir, sec, hpx, name, ext, glob ? GLOB : "");
+ p = pathname;
+ }
+ } else
+ p = pathname;
+
+ if (debug >=2)
+ gripe(ABOUT_TO_GLOB, p);
+ names = glob_filename (p);
+ if (names == (char **) -1) /* file system error; print msg? */
+ names = 0;
+ return names;
+}
+
+static char **
+glob_for_file_ext (const char *dir, const char *sec,
+ const char *name, const char *ext, int type) {
+ char **names, **namesglob;
+ char *hpx = ((standards & DO_HP) ? ".Z" : "");
+
+ namesglob = glob_for_file_ext_glob(dir,sec,name,ext,hpx,1,type);
+ if (!namesglob && *hpx) {
+ hpx = "";
+ namesglob = glob_for_file_ext_glob(dir,sec,name,ext,hpx,1,type);
+ }
+ if (!namesglob)
+ return 0;
+ if (*namesglob) {
+ /* we found something - try to get a more precise match */
+ names = glob_for_file_ext_glob(dir,sec,name,ext,hpx,0,type);
+ if (names && *names)
+ namesglob = names;
+ }
+ return namesglob;
+}
+
+/*
+ * Find the files of the form DIR/manSEC/NAME.SEC etc.
+ */
+static char **
+glob_for_file (const char *dir, const char *sec, const char *name, int type) {
+ char **names;
+
+ if (debug >= 2)
+ gripe(CALLTRACE2, dir, sec, name, type);
+
+ if (standards & DO_IRIX) {
+ /* try first without `sec' extension */
+ /* maybe this should be done only for cat pages? */
+ return glob_for_file_ext (dir, sec, name, "", type);
+ }
+
+ /* try /usr/X11R6/man/man3x/XSetFont.3x */
+ names = glob_for_file_ext (dir, sec, name, sec, type);
+
+ if (!names)
+ return 0; /* out-of-memory or error */
+
+ /* sometimes the extension is only a single digit */
+ if (!*names && isdigit(sec[0]) && sec[1] != 0) {
+ char ext[2];
+ ext[0] = sec[0];
+ ext[1] = 0;
+ names = glob_for_file_ext (dir, sec, name, ext, type);
+ }
+
+ if (!names)
+ return 0; /* out-of-memory or error */
+
+ /* or the extension could be .man */
+ if (!*names)
+ names = glob_for_file_ext (dir, sec, name, "man", type);
+
+ if (debug >= 2) {
+ if (!names[0])
+ gripe(NO_MATCH);
+ else {
+ char **np;
+ for (np = names; *np; np++)
+ gripe(GLOB_FOR_FILE, *np);
+ }
+ }
+
+ return names;
+}
+
+/*
+ * Find a man page of the given NAME under the directory DIR,
+ * in section SEC. Only types (man, cat, scat, html) permitted in FLAGS
+ * are allowed, and priorities are in this order.
+ */
+static struct manpage *
+manfile_from_sec_and_dir(const char *dir,
+ const char *sec, const char *name, int flags) {
+ struct manpage *res = 0;
+ struct manpage *p;
+ char **names, **np;
+ int i, type;
+ int types[] = {TYPE_HTML, TYPE_MAN, TYPE_CAT, TYPE_SCAT};
+
+ if (debug >= 2)
+ gripe(CALLTRACE1, dir, sec, name, flags);
+
+ for (i=0; i<(sizeof(types)/sizeof(types[0])); i++) {
+ type = types[i];
+
+ /* If convert_to_cat() is trivial, TYPE_CAT and TYPE_SCAT
+ are the same thing. */
+ if ((type == TYPE_CAT) && (flags & TYPE_SCAT) && !standards)
+ continue;
+
+ if (flags & type) {
+ names = glob_for_file (dir, sec, name, type);
+ if (names) {
+ for (np = names; *np; np++) {
+#if 1
+ /* Keep looking if we encounter a file
+ we can't access */
+ if (access(*np, R_OK))
+ continue;
+
+ if (debug >= 2)
+ gripe(FOUND_FILE, *np);
+ /* disadvantage: no error message when permissions
+ are wrong, the page just silently becomes
+ invisible */
+#endif
+ p = (struct manpage *) malloc(sizeof(*p));
+ if (!p)
+ break; /* %% perhaps print msg, free names */
+ p->filename = *np;
+ p->type = type;
+ p->next = 0;
+ append(&res, p);
+ if (res && (flags & ONLY_ONE_PERSEC))
+ break;
+ }
+ free(names);
+ }
+ }
+
+ if (res)
+ return res;
+ }
+
+ return res;
+}
+
+/*
+ * Find a man page of the given NAME, searching in the specified SECTION.
+ * Searching is done in all directories of MANPATH.
+ */
+static struct manpage *
+manfile_from_section(const char *name, const char *section,
+ int flags, char **manpath) {
+ char **mp;
+ struct manpage *res = 0;
+
+ for (mp = manpath; *mp; mp++) {
+ append(&res, manfile_from_sec_and_dir(*mp, section, name, flags));
+ if (res && (flags & ONLY_ONE_PERSEC))
+ break;
+ }
+#if 0
+ /* Someone wants section 1p - better not to give 1 */
+ if (res == NULL && isdigit(section[0]) && section[1]) {
+ char sec[2];
+
+ sec[0] = section[0];
+ sec[1] = 0;
+ for (mp = manpath; *mp; mp++) {
+ append(&res, manfile_from_sec_and_dir(*mp, sec, name, flags));
+ if (res && (flags & ONLY_ONE_PERSEC))
+ break;
+ }
+ }
+#endif
+ return res;
+}
+
+/*
+ * Find a man page of the given NAME, searching in the specified
+ * SECTION, or, if that is 0, in all sections in SECTIONLIST.
+ * Searching is done in all directories of MANPATH.
+ * If FLAGS contains the ONLY_ONE bits, only the first matching
+ * page is returned; otherwise all matching pages are found.
+ * Only types (man, cat, scat) permitted in FLAGS are allowed.
+ */
+struct manpage *
+manfile(const char *name, const char *section, int flags,
+ char **sectionlist, char **manpath,
+ const char *((*tocat)(const char *man_filename, const char *ext,
+ int flags))) {
+ char **sl;
+ struct manpage *res;
+
+ standards = (flags & (FHS | FSSTND | DO_HP | DO_IRIX));
+ to_cat_filename = tocat;
+
+ if (name && (flags & DO_WIN32)) { /* Convert : sequences to a ? */
+ char *n = my_malloc(strlen(name) + 1);
+ const char *p = name;
+ char *q = n;
+
+ while (*p) {
+ if (*p == ':') {
+ *q++ = '?';
+ while (*p == ':')
+ p++;
+ } else
+ *q++ = *p++;
+ }
+ *q = 0;
+ name = n;
+ }
+
+ if (!name || !manpath) /* error msg? */
+ res = 0;
+ else if (section)
+ res = manfile_from_section(name, section, flags, manpath);
+ else if (sectionlist) {
+ res = 0;
+ for (sl = sectionlist; *sl; sl++) {
+ append(&res, manfile_from_section(name, *sl, flags, manpath));
+ if (res && (flags & ONLY_ONE))
+ break;
+ }
+ }
+ return res;
+}
diff --git a/src/manfile.h b/src/manfile.h
new file mode 100644
index 0000000..cae3add
--- /dev/null
+++ b/src/manfile.h
@@ -0,0 +1,36 @@
+struct manpage {
+ struct manpage *next;
+ char *filename;
+ int type;
+};
+
+#define TYPE_MAN 0x0001
+#define TYPE_CAT 0x0002
+#define TYPE_SCAT 0x0004
+#define TYPE_HTML 0x0008
+#define TYPE_XML 0x0010 /* not presently used */
+
+#define ONLY_ONE_PERSEC 0x0020 /* do not return more pages from one section */
+#define ONLY_ONE 0x0040 /* return only a single page */
+
+/* various standards have various ideas about where the cat pages
+ ought to live */
+#define FSSTND 0x0080
+#define FHS 0x0100
+
+/* HP has a peculiar way to indicate that pages are compressed */
+#define DO_HP 0x0200 /* compressed file in man1.Z/ls.1 */
+
+/* IRIX has a peculiar cat page naming */
+#define DO_IRIX 0x0400 /* cat page ls.z, not ls.1.z */
+
+/* Sun uses both man and sman, where sman contains XML */
+#define DO_SUN 0x0800 /* unused today */
+
+/* NTFS cannot handle : in filenames */
+#define DO_WIN32 0x1000 /* turn :: into ? */
+
+extern struct manpage *
+manfile(const char *name, const char *section, int flags,
+ char **sectionlist, char **manpath,
+ const char *(*tocat)(const char *, const char *, int));
diff --git a/src/manpath.c b/src/manpath.c
new file mode 100644
index 0000000..90d520e
--- /dev/null
+++ b/src/manpath.c
@@ -0,0 +1,412 @@
+/*
+ * manpath.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ *
+ * Changed PATH->manpath algorithm
+ * Added: an empty string in MANPATH denotes the system path
+ * Added: use LANG to search in /usr/man/<locale>
+ * Lots of other minor things, including spoiling the indentation.
+ * aeb - 940315
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* not always in <string.h> */
+extern char *index(const char *, int);
+extern char *rindex(const char *, int);
+
+#include "defs.h"
+#include "gripes.h"
+#include "man.h" /* for debug */
+#include "man-config.h" /* for cfdirlist */
+#include "man-getopt.h" /* for alt_system, opt_manpath */
+#include "manpath.h"
+#include "util.h" /* my_malloc, my_strdup */
+
+char **mandirlist;
+static int mandirlistlth = 0;
+static int mandirlistmax = 0;
+
+/*
+ * Input: a string, with : as separator
+ * For each entry in the string, call fn.
+ */
+static void
+split (char *string, void (*fn)(char *, int), int perrs) {
+ char *p, *q, *r;
+
+ if (string) {
+ p = my_strdup(string);
+ for (q = p; ; ) {
+ if ((r = index(q, ':'))==(char*)0)
+ r=index(q,'\01');
+ if (r) {
+ *r = 0;
+ fn (q, perrs);
+ q = r+1;
+ } else {
+ fn (q, perrs);
+ break;
+ }
+ }
+ free (p);
+ }
+}
+
+static void
+split2 (char *s, char *string, void (*fn)(char *, char *, int), int perrs) {
+ char *p, *q, *r;
+
+ if (string) {
+ p = my_strdup(string);
+ for (q = p; ; ) {
+ r = index(q, ':');
+ if (r) {
+ *r = 0;
+ fn (s, q, perrs);
+ q = r+1;
+ } else {
+ fn (s, q, perrs);
+ break;
+ }
+ }
+ free (p);
+ }
+}
+
+/*
+ * Is path a directory?
+ * -1: error, 0: no, 1: yes.
+ */
+static int
+is_directory (char *path) {
+ struct stat sb;
+
+ if (stat (path, &sb) != 0)
+ return -1;
+
+ return ((sb.st_mode & S_IFDIR) == S_IFDIR);
+}
+
+/*
+ * Check to see if the current directory has man or MAN
+ * or ../man or ../man1 or ../man8 subdirectories.
+ */
+static char *
+find_man_subdir (char *p) {
+ int len;
+ char *t, *sp;
+
+ len = strlen (p);
+
+ t = my_malloc ((unsigned) len + 20);
+
+ memcpy (t, p, len);
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ strcpy (t + len, "/MAN");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ /* find parent directory */
+ t[len] = 0;
+ if ((sp = rindex (t, '/')) != NULL) {
+ *sp = 0;
+ len = sp - t;
+ } else {
+ strcpy (t + len, "/..");
+ len += 3;
+ }
+
+ /* look for the situation with packagedir/bin and packagedir/man */
+ strcpy (t + len, "/man");
+
+ if (is_directory (t) == 1)
+ return t;
+
+ /* look for the situation with pkg/bin and pkg/man1 or pkg/man8 */
+ /* (looking for all man[1-9] would probably be a waste of stats) */
+ strcpy (t + len, "/man1");
+
+ if (is_directory (t) == 1) {
+ t[len] = 0;
+ return t;
+ }
+
+ strcpy (t + len, "/man8");
+
+ if (is_directory (t) == 1) {
+ t[len] = 0;
+ return t;
+ }
+
+ free (t);
+ return NULL;
+}
+
+/*
+ * Add a directory to the manpath list if it isn't already there.
+ */
+static void
+add_to_list (char *dir, char *lang, int perrs) {
+ int status;
+ char cwd[BUFSIZ];
+ char **dp;
+
+ if (!lang)
+ lang = "";
+
+ /* only add absolute paths */
+ if (*dir != '/') {
+ if (!getcwd(cwd, sizeof(cwd)))
+ return; /* cwd not readable, or pathname very long */
+ if (cwd[0] != '/')
+ return; /* strange.. */
+ if (strlen(dir) + strlen(lang) + strlen(cwd) + 3 > sizeof(cwd))
+ return;
+ if (!strncmp (dir, "./", 2))
+ dir += 2;
+ while (!strncmp (dir, "../", 3)) {
+ char *p = rindex (cwd, '/');
+ if (p > cwd)
+ *p = 0;
+ else
+ cwd[1] = 0;
+ dir += 3;
+ }
+ strcat (cwd, "/");
+ strcat (cwd, dir);
+ if (*lang) {
+ strcat (cwd, "/");
+ strcat (cwd, lang);
+ }
+ dir = cwd;
+ } else if (*lang) {
+ if (strlen(dir) + strlen(lang) + 2 > sizeof(cwd))
+ return;
+ strcpy (cwd, dir);
+ strcat (cwd, "/");
+ strcat (cwd, lang);
+ dir = cwd;
+ }
+
+ if (mandirlist) {
+ for (dp = mandirlist; *dp; dp++) {
+ if (!strcmp (*dp, dir))
+ return;
+ }
+ }
+
+ /*
+ * Avoid trickery: no /../ in path.
+ */
+ if (strstr(dir, "/../"))
+ return;
+
+ /*
+ * Not found -- add it.
+ */
+ status = is_directory(dir);
+
+ if (status < 0 && perrs) {
+ gripe (CANNOT_STAT, dir);
+ } else if (status == 0 && perrs) {
+ gripe (IS_NO_DIR, dir);
+ } else if (status == 1) {
+ if (debug)
+ gripe (ADDING_TO_MANPATH, dir);
+
+ if (!mandirlist || mandirlistlth+1 >= mandirlistmax) {
+ int i, ct = mandirlistmax + 100;
+ char **p = (char **) my_malloc(ct * sizeof(char *));
+
+ if (mandirlist) {
+ for (i=0; i<mandirlistlth; i++)
+ p[i] = mandirlist[i];
+ free(mandirlist);
+ }
+ mandirlistmax = ct;
+ mandirlist = p;
+ }
+ mandirlist[mandirlistlth++] = my_strdup (dir);
+ mandirlist[mandirlistlth] = 0;
+ }
+}
+
+static void
+add_to_mandirlist_x (char *dir, char *lang, int perrs) {
+ add_to_list(dir, lang, perrs);
+ if (lang && strlen(lang) > 5 && lang[5] == '.') {
+ char lang2[6]; /* e.g. zh_CN from zh_CN.GB2312 */
+
+ strncpy(lang2,lang,5);
+ lang2[5] = 0;
+ add_to_list(dir, lang2, perrs);
+ }
+ if (lang && strlen(lang) > 2) {
+ char lang2[3];
+
+ strncpy(lang2,lang,2);
+ lang2[2] = 0;
+ add_to_list(dir, lang2, perrs);
+ }
+}
+
+static void
+add_to_mandirlist (char *dir, int perrs) {
+ char *lang;
+
+ if (alt_system) {
+ add_to_list(dir, alt_system_name, perrs);
+ } else {
+ /* We cannot use "lang = setlocale(LC_MESSAGES, NULL)" or so:
+ the return value of setlocale is an opaque string. */
+ /* POSIX prescribes the order: LC_ALL, LC_MESSAGES, LANG */
+ if((lang = getenv("LC_ALL")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LC_MESSAGES")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LANG")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ if((lang = getenv("LANGUAGE")) != NULL)
+ split2(dir, lang, add_to_mandirlist_x, perrs);
+ add_to_mandirlist_x(dir, 0, perrs);
+ }
+}
+
+/*
+ * For each directory in the user's path, see if it is one of the
+ * directories listed in the man.conf file. If so, and it is
+ * not already in the manpath, add it. If the directory is not listed
+ * in the man.conf file, see if there is a subdirectory `man' or
+ * `MAN'. If so, and it is not already in the manpath, add it.
+ *
+ * Example: user has <dir>/bin in his path and the directory
+ * <dir>/bin/man exists -- the directory <dir>/bin/man will be added
+ * to the manpath.
+ * Try also <dir>/man ?and <dir>?, and, if LANG is set, <dir>/$LANG/man.
+ * aeb - 940320
+ */
+static void
+get_manpath_from_pathdir (char *dir, int perrs) {
+ char *t;
+ struct dirs *dlp;
+
+ if (debug)
+ gripe (PATH_DIR, dir);
+
+ /*
+ * The directory we're working on is in the config file.
+ * If we haven't added it to the list yet, do.
+ */
+ if (*dir) {
+ for (dlp = cfdirlist.nxt; dlp; dlp = dlp->nxt) {
+ if (!strcmp (dir, dlp->bindir)) {
+ if (debug)
+ gripe (IS_IN_CONFIG);
+
+ add_to_mandirlist (dlp->mandir, perrs);
+ return;
+ }
+ }
+ }
+
+ if (!noautopath) {
+ /*
+ * The directory we're working on isn't in the config file.
+ * See if it has man or MAN subdirectories. If so, and this
+ * subdirectory hasn't been added to the list, do. (Try also
+ * a few other places nearby.)
+ */
+ if (debug)
+ gripe (IS_NOT_IN_CONFIG);
+
+ t = find_man_subdir (dir);
+ if (t != NULL) {
+ if (debug)
+ gripe (MAN_NEARBY);
+
+ add_to_mandirlist (t, perrs);
+ free (t);
+ } else {
+ if (debug)
+ gripe (NO_MAN_NEARBY);
+ }
+ }
+}
+
+static void
+add_default_manpath (int perrs) {
+ struct dirs *dlp;
+
+ if (debug)
+ gripe (ADDING_MANDIRS);
+
+ for (dlp = cfdirlist.nxt; dlp; dlp = dlp->nxt)
+ if (dlp->mandatory)
+ add_to_mandirlist (dlp->mandir, perrs);
+}
+
+static void
+to_mandirlist(char *s, int perrs) {
+ char *path;
+
+ if (*s) {
+ add_to_mandirlist (s, perrs);
+ } else {
+ /* empty substring: insert default path */
+ if((path = getenv ("PATH")) != NULL)
+ split (path, get_manpath_from_pathdir, perrs);
+ add_default_manpath (perrs);
+ }
+}
+
+void
+init_manpath () {
+ static int done = 0;
+
+ if (!done) {
+ char *manp;
+
+ if ((manp = opt_manpath) == NULL &&
+ (manp = getenv ("manpath")) == NULL &&
+ (manp = getenv ("MANPATH")) == NULL)
+ manp = ""; /* default path */
+ split (manp, to_mandirlist, 0);
+ done = 1;
+ }
+}
+
+void
+prmanpath () {
+ char **dp, **dp0;
+
+ if (mandirlist) {
+ for (dp0 = dp = mandirlist; *dp; dp++) {
+ if (dp != dp0)
+ printf(":");
+ printf("%s", *dp);
+ }
+ }
+ printf("\n");
+}
diff --git a/src/manpath.h b/src/manpath.h
new file mode 100644
index 0000000..5232938
--- /dev/null
+++ b/src/manpath.h
@@ -0,0 +1,5 @@
+/* functions and variables exported by manpath.c */
+void prmanpath (void);
+void init_manpath (void);
+
+extern char ** mandirlist;
diff --git a/src/msg.c b/src/msg.c
new file mode 100644
index 0000000..874e22f
--- /dev/null
+++ b/src/msg.c
@@ -0,0 +1,106 @@
+char *msg[] = {
+ "",
+/* 1 */ "unable to make sense of the file %s\n",
+/* 2 */ "Warning: cannot open configuration file %s\n",
+/* 3 */ "Error parsing config file\n",
+/* 4 */ "incompatible options %s and %s\n",
+/* 5 */ "Sorry - no support for alternate systems compiled in\n",
+/* 6 */ "Man was compiled with automatic cat page compression,\n\
+but the configuration file does not define COMPRESS.\n",
+/* 7 */ "What manual page do you want from section %s?\n",
+/* 8 */ "What manual page do you want?\n",
+/* 9 */ "No entry for %s in section %s of the manual\n",
+/* 10 */ "No manual entry for %s\n",
+/* 11 */ "\nusing %s as pager\n",
+/* 12 */ "Error executing formatting or display command.\n\
+System command %s exited with status %d.\n",
+/* 13 */ "%s, version %s\n\n",
+/* 14 */ "Out of memory - can't malloc %d bytes\n",
+/* 15 */ "Error parsing *roff command from file %s\n",
+/* 16 */ "Error parsing MANROFFSEQ. Using system defaults.\n",
+/* 17 */ "Error parsing *roff command from command line.\n",
+/* 18 */ "Unrecognized line in config file (ignored)\n%s\n",
+/* 19 */ "man-config.c: internal error: string %s not found\n",
+/* 20 */ "found man directory %s\n",
+/* 21 */ "found manpath map %s --> %s\n",
+/* 22 */ "corresponding catdir is %s\n",
+/* 23 */ "Line too long in config file\n",
+/* 24 */ "\nsection: %s\n",
+/* 25 */ "unlinked %s\n",
+/* 26 */ "globbing %s\n",
+/* 27 */ "Attempt [%s] to expand man page failed\n",
+/* 28 */ "Cannot open man page %s\n",
+/* 29 */ "Error reading man page %s\n",
+/* 30 */ "found eqn(1) directive\n",
+/* 31 */ "found grap(1) directive\n",
+/* 32 */ "found pic(1) directive\n",
+/* 33 */ "found tbl(1) directive\n",
+/* 34 */ "found vgrind(1) directive\n",
+/* 35 */ "found refer(1) directive\n",
+/* 36 */ "parsing directive from command line\n",
+/* 37 */ "parsing directive from file %s\n",
+/* 38 */ "parsing directive from environment\n",
+/* 39 */ "using default preprocessor sequence\n",
+/* 40 */ "Formatting page, please wait...\n",
+/* 41 */ "changed mode of %s to %o\n",
+/* 42 */ "Couldn't open %s for writing.\n",
+/* 43 */ "will try to write %s if needed\n",
+/* 44 */ "status from is_newer() = %d\n",
+/* 45 */ "trying section %s\n",
+/* 46 */ "\nsearching in %s\n",
+/* 47 */ "but %s is already in the manpath\n",
+/* 48 */ "Warning: cannot stat file %s!\n",
+/* 49 */ "Warning: %s isn't a directory!\n",
+/* 50 */ "adding %s to manpath\n",
+/* 51 */ "\npath directory %s ",
+/* 52 */ "is in the config file\n",
+/* 53 */ "is not in the config file\n",
+/* 54 */ "but there is a man directory nearby\n",
+/* 55 */ "and we found no man directory nearby\n",
+/* 56 */ "\nadding mandatory man directories\n\n",
+/* 57 */ "cat_name in convert_to_cat () is: %s\n",
+/* 58 */ "\nnot executing command:\n %s\n",
+/* 59 */ "usage: %s [-adfhktwW] [section] [-M path] [-P pager] [-S list]\n\t",
+/* 60 */ "[-m system] ",
+/* 61 */ "[-p string] name ...\n\n",
+/* 62 */ " a : find all matching entries\n\
+ c : do not use cat file\n\
+ d : print gobs of debugging information\n\
+ D : as for -d, but also display the pages\n\
+ f : same as whatis(1)\n\
+ h : print this help message\n\
+ k : same as apropos(1)\n\
+ K : search for a string in all pages\n",
+/* 63 */ " t : use troff to format pages for printing\n",
+/* 64 */ "\
+ w : print location of man page(s) that would be displayed\n\
+ (if no name given: print directories that would be searched)\n\
+ W : as for -w, but display filenames only\n\n\
+ C file : use `file' as configuration file\n\
+ M path : set search path for manual pages to `path'\n\
+ P pager : use program `pager' to display pages\n\
+ S list : colon separated section list\n",
+/* 65 */ " m system : search for alternate system's man pages\n",
+/* 66 */ " p string : string tells which preprocessors to run\n\
+ e - [n]eqn(1) p - pic(1) t - tbl(1)\n\
+ g - grap(1) r - refer(1) v - vgrind(1)\n",
+/* 67 */ "and the real user cannot open the cat file either\n",
+/* 68 */ "but the real user can open the cat file\n",
+/* 69 */ "failed to fork off the command _%s_\n",
+/* 70 */ "error while waiting for child _%s_\n",
+/* 71 */ "very strange ..., got wrong pid while waiting for my child\n",
+/* 72 */ "fatal error: the command _%s_ terminated abnormally\n",
+/* 73 */ "Man page %s is identical to %s\n",
+/* 74 */ "Found the man page(s):\n",
+/* 75 */ "error: no TROFF command specified in %s\n",
+/* 76 */ "no cat page stored because of nonstandard line length\n",
+/* 77 */ "\nusing %s as browser\n",
+/* 78 */ "\nusing %s to dump HTML pages as text\n",
+/* 79 */ "manfile_from_sec_and_dir() found %s\n",
+/* 80 */ "manfile_from_sec_and_dir(dir=%s, sec=%s, name=%s, flags=0x%0x)\n",
+/* 81 */ "glob_for_file(dir=%s, sec=%s, name=%s, type=0x%0x, ...)\n",
+/* 82 */ "glob_for_file found no matches.\n",
+/* 83 */ "glob_for_file returns %s.\n",
+/* 84 */ "glob_for_file_ext_glob(dir=%s, sec=%s, name=%s, ext=%s, hpx=%s, glob=%d, type=0x%0x);\n",
+/* 85 */ "glob_for_file_ext_glob will expand %s\n",
+};
diff --git a/src/mwi b/src/mwi
new file mode 100755
index 0000000..3b52feb
--- /dev/null
+++ b/src/mwi
@@ -0,0 +1,19 @@
+#!/bin/sh
+# test which words in all caps end a NAME section in a (compressed) cat page
+#
+# Found so far:
+#
+# SYNOPSIS
+# SYNOPOSIS
+# SYSTEM V SYNOPSIS
+# SYNTAX
+# DESCRIPTION
+# COMMAND
+# OVERVIEW
+# STRUCTURES
+# INTRODUCTION
+#
+ for i in *
+ do
+ zcat $i | col -bx | sed '1,/^NAME/d; /^[A-Z][A-Z]/q' | tail -1
+ done
diff --git a/src/ndir.h b/src/ndir.h
new file mode 100644
index 0000000..438d5c2
--- /dev/null
+++ b/src/ndir.h
@@ -0,0 +1,51 @@
+/*
+ <dir.h> -- definitions for 4.2BSD-compatible directory access
+
+ last edit: 09-Jul-1983 D A Gwyn
+*/
+
+#ifdef VMS
+#ifndef FAB$C_BID
+#include <fab.h>
+#endif
+#ifndef NAM$C_BID
+#include <nam.h>
+#endif
+#ifndef RMS$_SUC
+#include <rmsdef.h>
+#endif
+#include "dir.h"
+#endif /* VMS */
+
+#define DIRBLKSIZ 512 /* size of directory block */
+#ifdef VMS
+#define MAXNAMLEN (DIR$S_NAME + 7) /* 80 plus room for version #. */
+#define MAXFULLSPEC NAM$C_MAXRSS /* Maximum full spec */
+#else
+#define MAXNAMLEN 15 /* maximum filename length */
+#endif /* VMS */
+ /* NOTE: MAXNAMLEN must be one less than a multiple of 4 */
+
+struct direct /* data from readdir() */
+ {
+ long d_ino; /* inode number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned short d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN+1]; /* name of file */
+ };
+
+typedef struct
+ {
+ int dd_fd; /* file descriptor */
+ int dd_loc; /* offset in block */
+ int dd_size; /* amount of valid data */
+ char dd_buf[DIRBLKSIZ]; /* directory block */
+ } DIR; /* stream data from opendir() */
+
+extern DIR *opendir();
+extern struct direct *readdir();
+extern long telldir();
+extern void seekdir();
+extern void closedir();
+
+#define rewinddir( dirp ) seekdir( dirp, 0L )
diff --git a/src/paths.h b/src/paths.h
new file mode 100644
index 0000000..723731d
--- /dev/null
+++ b/src/paths.h
@@ -0,0 +1,43 @@
+/*
+ * Generated automatically from paths.h.in by the
+ * configure script.
+ */
+/* paths.h - included in man-config.c */
+/*
+ * Define the absolute path to the configuration file and programs used.
+ * (If no configuration file is found then the preset values are used.)
+ */
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "/usr/share/misc/man.conf"
+#endif
+
+static struct paths {
+ char *name;
+ char *path; /* path plus command options - never NULL */
+} paths[] = {
+ { "MANBIN", "" }, /* value unused */
+ { "APROPOS", "/usr/bin/apropos" },
+ { "WHATIS", "/usr/bin/whatis" },
+ { "TROFF", "/usr/bin/groff -Tps -mandoc" },
+ { "NROFF", "/usr/bin/nroff -Tlatin1 -mandoc" },
+ { "JNROFF", "/usr/bin/groff -Tnippon -mandocj" },
+ { "EQN", "/usr/bin/geqn -Tps" },
+ { "NEQN", "/usr/bin/geqn -Tlatin1" },
+ { "JNEQN", "/usr/bin/geqn -Tnippon" },
+ { "TBL", "/usr/bin/gtbl" },
+ { "COL", "" },
+ { "REFER", "" },
+ { "PIC", "/usr/bin/gpic" },
+ { "VGRIND", "" },
+ { "GRAP", "" },
+ { "PAGER", "/bin/less -is" },
+ { "BROWSER","/bin/less -is" },
+ { "HTMLPAGER", "/bin/cat" },
+ { "CMP", "/usr/bin/cmp -s" },
+ { "CAT", "/bin/cat" },
+ { "COMPRESS", "/usr/bin/xz" },
+ { "COMPRESS_EXT", ".xz" }, /* not a path, just a string variable */
+ { "DECOMPRESS", "/usr/bin/unxz -c" },
+ { "MANSECT", "1:1p:8:2:3:3p:4:5:6:7:9:0p:tcl:n:l:p:o"}, /* idem */
+ { "MANDEFOPTIONS", ""} /* idem */
+};
diff --git a/src/paths.h.in b/src/paths.h.in
new file mode 100644
index 0000000..ee9ec75
--- /dev/null
+++ b/src/paths.h.in
@@ -0,0 +1,39 @@
+/* paths.h - included in man-config.c */
+/*
+ * Define the absolute path to the configuration file and programs used.
+ * (If no configuration file is found then the preset values are used.)
+ */
+#ifndef CONFIG_FILE
+#define CONFIG_FILE "@man_config_file@"
+#endif
+
+static struct paths {
+ char *name;
+ char *path; /* path plus command options - never NULL */
+} paths[] = {
+ { "MANBIN", "" }, /* value unused */
+ { "APROPOS", "@apropos@" },
+ { "WHATIS", "@whatis@" },
+ { "TROFF", "@troff@" },
+ { "NROFF", "@nroff@" },
+ { "JNROFF", "@jnroff@" },
+ { "EQN", "@eqn@" },
+ { "NEQN", "@neqn@" },
+ { "JNEQN", "@jneqn@" },
+ { "TBL", "@tbl@" },
+ { "COL", "@pcol@" },
+ { "REFER", "@refer@" },
+ { "PIC", "@pic@" },
+ { "VGRIND", "@vgrind@" },
+ { "GRAP", "@grap@" },
+ { "PAGER", "@pager@" },
+ { "BROWSER","@browser@" },
+ { "HTMLPAGER", "@htmlpager@" },
+ { "CMP", "@cmp@" },
+ { "CAT", "@cat@" },
+ { "COMPRESS", "@compress@" },
+ { "COMPRESS_EXT", "@compress_ext@" }, /* not a path, just a string variable */
+ { "DECOMPRESS", "@decompress@" },
+ { "MANSECT", "@sections@"}, /* idem */
+ { "MANDEFOPTIONS", ""} /* idem */
+};
diff --git a/src/to_cat.c b/src/to_cat.c
new file mode 100644
index 0000000..c6aeb5f
--- /dev/null
+++ b/src/to_cat.c
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char *rindex (const char *, int); /* not always in <string.h> */
+
+#include "defs.h"
+#include "manfile.h"
+#include "man-config.h"
+#include "to_cat.h"
+#include "util.h"
+
+/*
+ * Given PATH/man1/name.1, return a pointer to the '/' following PATH.
+ */
+static char *
+mantail_of(char *name) {
+ char *s0, *s1, *s;
+
+ s0 = s1 = 0;
+ for (s = name; *s; s++) {
+ if (*s == '/') {
+ s0 = s1;
+ s1 = s;
+ }
+ }
+ return s0;
+}
+
+/*
+ * Given PATH/man1/name.1, return PATH, newly allocated.
+ * The argument must be writable, not a constant string.
+ */
+const char *
+mandir_of(const char *name) {
+ char *p, *q;
+
+ q = my_strdup(name);
+ p = mantail_of(q);
+ if (p) {
+ *p = 0;
+ return q;
+ }
+ free(q);
+ return NULL;
+}
+
+/*
+ * Change a name of the form PATH/man1/name.1[.Z]
+ * into PATH/cat1/name.1.EXT
+ * or (FSSTND) change /usr/PA/man/PB/man1/name.1
+ * into /var/catman/PA/PB/cat1/name.1.EXT
+ * or (FHS) change /usr/PATH/share/man/LOC/man1/name.1
+ * into /var/cache/man/PATH/LOC/cat1/name.1.EXT
+ * (here the /LOC part is absent or a single [locale] dir).
+ *
+ * Returns 0 on failure.
+ */
+
+const char *
+convert_to_cat (const char *name0, const char *ext, int standards) {
+ char *name, *freename, *cat_name = 0;
+ char *t0, *t2, *t3, *t4;
+ struct dirs *dlp;
+ int len;
+
+ freename = name = my_strdup (name0);
+
+ t0 = rindex (name, '.');
+ if (t0 && get_expander(t0)) /* remove compressee extension */
+ *t0 = 0;
+
+ t2 = mantail_of (name);
+ if (t2 == NULL)
+ return 0;
+ *t2 = 0; /* remove man1/name.1 part */
+
+ if (strncmp(t2+1, "man", 3) != 0)
+ return 0;
+ t2[1] = 'c';
+ t2[3] = 't';
+
+ len = (ext ? strlen(ext) : 0);
+
+ /* Explicitly given cat file? */
+ for (dlp = cfdirlist.nxt; dlp; dlp = dlp->nxt) {
+ if (!strcmp (name, dlp->mandir)) {
+ if (!dlp->catdir[0])
+ break;
+ *t2 = '/';
+ len += strlen (dlp->catdir) + strlen (t2) + 1;
+ cat_name = (char *) my_malloc (len);
+ strcpy (cat_name, dlp->catdir);
+ strcat (cat_name, t2);
+ goto gotit;
+ }
+ }
+
+ if (standards & FHS) {
+ if (*name != '/')
+ return 0;
+
+ /* possibly strip locale part */
+ t3 = t2;
+ if ((t4 = rindex(name,'/')) != NULL && strcmp(t4, "/man")) {
+ *t3 = '/';
+ t3 = t4;
+ *t3 = 0;
+ }
+
+ if(t3 - name >= 4 && !strcmp(t3 - 4, "/man")) {
+ /* fhs is applicable; strip leading /usr and trailing share */
+ if(!strncmp(name, "/usr/", 5))
+ name += 4;
+ t4 = t3 - 4;
+ *t4 = 0;
+ if(t4 - name >= 6 && !strcmp(t4 - 6, "/share"))
+ t4[-6] = 0;
+ *t3 = '/';
+
+ len += strlen("/var/cache/man") + strlen(name) + strlen(t3) + 1;
+ cat_name = (char *) my_malloc (len);
+ strcpy (cat_name, "/var/cache/man");
+ strcat (cat_name, name);
+ strcat (cat_name, t3);
+ goto gotit;
+ }
+
+ return 0;
+ }
+
+ if ((standards & FSSTND) && !strncmp(name, "/usr/", 5)) {
+ /* search, starting at the end, for a part `man' to delete */
+ t3 = t2;
+ while ((t4 = rindex(name, '/')) != NULL && strcmp(t4, "/man")) {
+ *t3 = '/';
+ t3 = t4;
+ *t3 = 0;
+ }
+ *t3 = '/';
+ if (t4) {
+ *t4 = 0;
+ len += strlen("/var/catman") + strlen (name+4) + strlen (t3) + 1;
+ cat_name = (char *) my_malloc (len);
+ strcpy (cat_name, "/var/catman");
+ strcat (cat_name, name+4);
+ strcat (cat_name, t3);
+ goto gotit;
+ }
+ } else
+ *t2 = '/';
+
+ if (ext) { /* allocate room for extension */
+ len += strlen(name) + 1;
+ cat_name = (char *) my_malloc (len);
+ strcpy (cat_name, name);
+ } else
+ cat_name = name;
+
+gotit:
+
+ if ((standards & DO_HP) && get_expander(cat_name)) {
+ /* nothing - we have cat1.Z/file.1 */
+ } else if (ext)
+ strcat (cat_name, ext);
+
+ if (name != cat_name)
+ free (freename);
+
+ return cat_name;
+}
diff --git a/src/to_cat.h b/src/to_cat.h
new file mode 100644
index 0000000..c9cc7e9
--- /dev/null
+++ b/src/to_cat.h
@@ -0,0 +1,3 @@
+extern const char *mandir_of (const char *name);
+extern const char *convert_to_cat (const char *name, const char *ext,
+ int standards);
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..d074451
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,305 @@
+/*
+ * util.c
+ *
+ * Copyright (c) 1990, 1991, John W. Eaton.
+ *
+ * You may distribute under the terms of the GNU General Public
+ * License as specified in the file COPYING that comes with the man
+ * distribution.
+ *
+ * John W. Eaton
+ * jwe@che.utexas.edu
+ * Department of Chemical Engineering
+ * The University of Texas at Austin
+ * Austin, Texas 78712
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "gripes.h"
+#include "man.h" /* for debug */
+
+/*
+ * Extract last element of a name like /foo/bar/baz.
+ */
+const char *
+mkprogname (const char *s) {
+ const char *t;
+
+ t = strrchr (s, '/');
+ if (t == (char *)NULL)
+ t = s;
+ else
+ t++;
+
+ return my_strdup (t);
+}
+
+/*
+ * Is file a nonempty and newer than file b?
+ *
+ * case:
+ *
+ * a newer than b returns 1
+ * a older than b returns 0
+ * stat on a fails or a empty returns -1
+ * stat on b fails or b empty returns -2
+ * both fail or empty returns -3
+ */
+int
+is_newer (const char *fa, const char *fb) {
+ struct stat fa_sb;
+ struct stat fb_sb;
+ register int fa_stat;
+ register int fb_stat;
+ register int status = 0;
+
+ fa_stat = stat (fa, &fa_sb);
+ if (fa_stat != 0 || fa_sb.st_size == 0)
+ status = 1;
+
+ fb_stat = stat (fb, &fb_sb);
+ if (fb_stat != 0 || fb_sb.st_size == 0)
+ status |= 2;
+
+ if (status != 0)
+ return -status;
+
+ return (fa_sb.st_mtime > fb_sb.st_mtime);
+}
+
+int ruid, rgid, euid, egid, suid;
+
+void
+get_permissions (void) {
+ ruid = getuid();
+ euid = geteuid();
+ rgid = getgid();
+ egid = getegid();
+ suid = (ruid != euid || rgid != egid);
+}
+
+void
+no_privileges (void) {
+ if (suid) {
+#if !defined (__CYGWIN__) && !defined (__BEOS__)
+ setreuid(ruid, ruid);
+ setregid(rgid, rgid);
+#endif
+ suid = 0;
+ }
+}
+
+/*
+ * What to do upon an interrupt? Experience shows that
+ * if we exit immediately, sh notices that its child has
+ * died and will try to fiddle with the tty.
+ * Simultaneously, also less will fiddle with the tty,
+ * resetting the mode before exiting.
+ * This leads to undesirable races. So, we catch SIGINT here
+ * and exit after the child has exited.
+ */
+static int interrupted = 0;
+static void catch_int(int a) {
+ interrupted = 1;
+}
+
+static int
+system1 (const char *command) {
+ void (*prev_handler)(int) = signal (SIGINT,catch_int);
+ int ret = system(command);
+
+ /* child terminated with signal? */
+ if (WIFSIGNALED(ret) &&
+ (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))
+ exit(1);
+
+ /* or we caught an interrupt? */
+ if (interrupted)
+ exit(1);
+
+ signal(SIGINT,prev_handler);
+ return ret;
+}
+
+static int
+my_system (const char *command) {
+ int pid, pid2, status, stat;
+
+ if (!suid)
+ return system1 (command);
+
+#ifdef _POSIX_SAVED_IDS
+
+ /* we need not fork */
+ setuid(ruid);
+ setgid(rgid);
+ status = system1(command);
+ setuid(euid);
+ setgid(egid);
+ return (WIFEXITED(status) ? WEXITSTATUS(status) : 127);
+#endif
+
+ fflush(stdout); fflush(stderr);
+ pid = fork();
+ if (pid == -1) {
+ perror(progname);
+ fatal (CANNOT_FORK, command);
+ }
+ if (pid == 0) {
+ setuid(ruid);
+ setgid(rgid);
+ status = system1 (command);
+ exit(WIFEXITED(status) ? WEXITSTATUS(status) : 127);
+ }
+ pid2 = wait (&stat);
+ if (pid2 == -1) {
+ perror(progname);
+ fatal (WAIT_FAILED, command); /* interrupted? */
+ }
+ if (pid2 != pid)
+ fatal (GOT_WRONG_PID);
+ if (WIFEXITED(stat) && WEXITSTATUS(stat) != 127)
+ return WEXITSTATUS(stat);
+ fatal (CHILD_TERMINATED_ABNORMALLY, command);
+ return -1; /* not reached */
+}
+
+FILE *
+my_popen(const char *command, const char *type) {
+ FILE *r;
+
+ if (!suid)
+ return popen(command, type);
+
+#ifdef _POSIX_SAVED_IDS
+ setuid(ruid);
+ setgid(rgid);
+ r = popen(command, type);
+ setuid(euid);
+ setgid(egid);
+ return r;
+#endif
+
+ no_privileges();
+ return popen(command, type);
+}
+
+#define NOT_SAFE "/unsafe/"
+
+/*
+ * Attempt a system () call.
+ */
+int
+do_system_command (const char *command, int silent) {
+ int status = 0;
+
+ /*
+ * If we're debugging, don't really execute the command
+ */
+ if ((debug & 1) || !strncmp(command, NOT_SAFE, strlen(NOT_SAFE)))
+ fatal (NO_EXEC, command);
+ else
+ status = my_system (command);
+
+ if (status && !silent)
+ gripe (SYSTEM_FAILED, command, status);
+
+ return status;
+}
+
+char *
+my_malloc (int n) {
+ char *s = malloc(n);
+ if (!s)
+ fatal (OUT_OF_MEMORY, n);
+ return s;
+}
+
+char *
+my_strdup (const char *s) {
+ char *t = my_malloc(strlen(s) + 1);
+ strcpy(t, s);
+ return t;
+}
+
+/*
+ * Call: my_xsprintf(format,s1,s2,...) where format only contains %s/%S/%Q
+ * (or %d or %o) and all %s/%S/%Q parameters are strings.
+ * Result: allocates a new string containing the sprintf result.
+ * The %S parameters are checked for being shell safe.
+ * The %Q parameters are checked for being shell safe inside single quotes.
+ */
+
+static int
+is_shell_safe(const char *ss, int quoted) {
+ char *bad = " ;'\\\"<>|&";
+ char *p;
+
+ if (quoted)
+ bad++; /* allow a space inside quotes */
+ for (p = bad; *p; p++)
+ if (strchr(ss, *p))
+ return 0;
+ return 1;
+}
+
+static void
+nothing(int x) {}
+
+char *
+my_xsprintf (char *format, ...) {
+ va_list p;
+ char *s, *ss, *fm;
+ int len;
+
+ len = strlen(format) + 1;
+ fm = my_strdup(format);
+
+ va_start(p, format);
+ for (s = fm; *s; s++) {
+ if (*s == '%') {
+ switch (s[1]) {
+ case 'Q':
+ case 'S': /* check and turn into 's' */
+ ss = va_arg(p, char *);
+ if (!is_shell_safe(ss, (s[1] == 'Q')))
+ return NOT_SAFE;
+ len += strlen(ss);
+ s[1] = 's';
+ break;
+ case 's':
+ len += strlen(va_arg(p, char *));
+ break;
+ case 'd':
+ case 'o':
+ case 'c':
+ len += 20;
+ nothing(va_arg(p, int)); /* advance */
+ break;
+ default:
+ fprintf(stderr,
+ "my_xsprintf called with %s\n",
+ format);
+ exit(1);
+ }
+ }
+ }
+ va_end(p);
+
+ s = my_malloc(len);
+ va_start(p, format);
+ vsprintf(s, fm, p);
+ va_end(p);
+
+ return s;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..c317bd9
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,13 @@
+/* functions and variables exported from util.c */
+
+void get_permissions (void);
+void no_privileges (void);
+char *my_malloc (int n);
+char *my_strdup (const char *s);
+const char *mkprogname (const char *s);
+int is_newer (const char *fa, const char *fb);
+int do_system_command (const char *cmd, int silent);
+FILE *my_popen(const char *cmd, const char *type);
+char *my_xsprintf(char *f,...);
+
+extern int ruid, rgid, euid, egid, suid;
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..b575ffd
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1 @@
+static char version[] = "1.6g";
diff --git a/src/whatis b/src/whatis
new file mode 100755
index 0000000..22da854
--- /dev/null
+++ b/src/whatis
@@ -0,0 +1,88 @@
+#!/bin/sh
+#
+# apropos -- search the whatis database for keywords.
+# whatis -- idem, but match only commands (as whole words).
+#
+# Copyright (c) 1990, 1991, John W. Eaton.
+# Copyright (c) 1994-1999, Andries E. Brouwer.
+#
+# You may distribute under the terms of the GNU General Public
+# License as specified in the README file that comes with the man
+# distribution.
+#
+# apropos/whatis-1.5m aeb 2003-08-01 (from man-1.6g)
+#
+# keep old PATH - 000323 - Bryan Henderson
+# also look in /var/cache/man - 030801 - aeb
+
+program=`basename $0`
+
+# When man pages in your favorite locale look to grep like binary files
+# (and you use GNU grep) you may want to add the 'a' option to *grepopt1.
+aproposgrepopt1='i'
+aproposgrepopt2=''
+whatisgrepopt1='iw'
+whatisgrepopt2='^'
+grepopt1=$whatisgrepopt1
+grepopt2=$whatisgrepopt2
+
+if [ $# = 0 ]
+then
+ echo "usage: $program keyword ..."
+ exit 1
+fi
+
+manpath=`man --path | tr : '\040'`
+
+if [ "$manpath" = "" ]
+then
+ echo "$program: manpath is null"
+ exit 1
+fi
+
+args=
+for arg in $*; do
+ case $arg in
+ --version|-V|-v)
+ echo "$program from man-1.6g"
+ exit 0
+ ;;
+ --help|-h)
+ echo "usage: $program keyword ..."
+ exit 0
+ ;;
+ -*)
+ echo "$program: $arg: unknown option"
+ exit 1
+ ;;
+ *)
+ args="$args $arg"
+ esac
+done
+
+while [ "$1" != "" ]
+do
+ found=0
+ for d in /var/cache/man $manpath /usr/lib
+ do
+ if [ -f $d/whatis ]
+ then
+ if grep -"$grepopt1" "$grepopt2""$1" $d/whatis
+ then
+ found=1
+# Some people are satisfied with a single occurrence
+# But it is better to give all
+# break
+ fi
+ fi
+ done
+
+ if [ $found = 0 ]
+ then
+ echo "$1: nothing appropriate"
+ fi
+
+ shift
+done
+
+exit