diff options
Diffstat (limited to '')
67 files changed, 28611 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ecc397f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,198 @@ +## Process this file with automake to produce Makefile.in +## +## Copyright (C) 1994, 1995 Graeme Wilford. +## Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +## 2011, 2012 Colin Watson. +## +## This file is part of man-db. +## +## man-db 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 2 of the License, or +## (at your option) any later version. +## +## man-db 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 man-db; if not, write to the Free Software Foundation, +## Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +pkglibexecdir = $(libexecdir)/@PACKAGE@ + +SUBDIRS = . tests + +bin_PROGRAMS = \ + catman \ + lexgrog \ + man \ + mandb \ + manpath \ + whatis +sbin_PROGRAMS = accessdb +pkglibexec_PROGRAMS = globbing manconv zsoelim +noinst_DATA = man_db.conf + +EXTRA_DIST = lexgrog.c zsoelim.c + +AM_CPPFLAGS = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libdb \ + -DCONFIG_FILE=\"$(config_file)\" \ + -DAPROPOS=\"$(bindir)/$(TRANS_APROPOS)\" \ + -DAPROPOS_NAME=\"$(TRANS_APROPOS)\" \ + -DMAN=\"$(bindir)/$(TRANS_MAN)\" \ + -DMANCONV=\"$(pkglibexecdir)/$(TRANS_MANCONV)\" \ + -DMANDB=\"$(bindir)/$(TRANS_MANDB)\" \ + -DWHATIS=\"$(bindir)/$(TRANS_WHATIS)\" \ + -DZSOELIM=\"$(pkglibexecdir)/$(TRANS_ZSOELIM)\" +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + $(libpipeline_CFLAGS) + +LIBMAN = $(top_builddir)/lib/libman.la $(top_builddir)/gl/lib/libgnu.la \ + @LTLIBINTL@ +LIBMANDB = $(top_builddir)/libdb/libmandb.la $(LIBMAN) $(DBLIBS) + +accessdb_LDADD = $(LIBMANDB) +catman_LDADD = $(LIBMANDB) $(libpipeline_LIBS) +globbing_LDADD = $(LIBMAN) +lexgrog_LDADD = $(LIBMAN) $(libpipeline_LIBS) $(LTLIBICONV) +man_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +manconv_LDADD = $(LIBMAN) $(libpipeline_LIBS) $(LTLIBICONV) +mandb_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +manpath_LDADD = $(LIBMAN) +whatis_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +zsoelim_LDADD = $(LIBMAN) $(libpipeline_LIBS) + +accessdb_SOURCES = \ + accessdb.c +catman_SOURCES = \ + catman.c \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h +globbing_SOURCES = \ + globbing.c \ + globbing.h \ + globbing_test.c +lexgrog_SOURCES = \ + compression.c \ + descriptions.c \ + descriptions.h \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + lexgrog.l \ + lexgrog_test.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + ult_src.c \ + ult_src.h +man_SOURCES = \ + compression.c \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + man.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + manp.c \ + manp.h \ + ult_src.c \ + ult_src.h \ + zsoelim.h \ + zsoelim.l +manconv_SOURCES = \ + manconv.c \ + manconv.h \ + manconv_main.c +mandb_SOURCES = \ + check_mandirs.c \ + check_mandirs.h \ + compression.c \ + descriptions.c \ + descriptions.h \ + descriptions_store.c \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + lexgrog.l \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + mandb.c \ + manp.c \ + manp.h \ + straycats.c \ + ult_src.c \ + ult_src.h +manpath_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + manpath.c +whatis_SOURCES = \ + globbing.c \ + globbing.h \ + manconv.c \ + manconv.h \ + manp.c \ + manp.h \ + whatis.c +zsoelim_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + zsoelim.h \ + zsoelim.l \ + zsoelim_main.c + +CLEANFILES = apropos man_db.conf + +apropos$(EXEEXT): whatis$(EXEEXT) + rm -f $@ + $(LN_S) whatis$(EXEEXT) $@ + +all-am: apropos$(EXEEXT) + +install-exec-hook: + if [ "$(man_owner)" ] && [ "$(man_mode)" = 6755 ]; then \ + chown $(man_owner):$(man_owner) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB); \ + fi + chmod $(man_mode) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB) + cd $(DESTDIR)$(bindir) && rm -f $(TRANS_APROPOS)$(EXEEXT) && \ + $(LN_S) $(TRANS_WHATIS)$(EXEEXT) $(TRANS_APROPOS)$(EXEEXT) + +install-data-hook: + @if test -f $(DESTDIR)$(config_file); then \ + echo "$(DESTDIR)$(config_file) already exists; overwrite manually if necessary"; \ + else \ + test -z "$(config_file_dirname)" || $(MKDIR_P) "$(DESTDIR)$(config_file_dirname)"; \ + echo " $(INSTALL_DATA) man_db.conf $(DESTDIR)$(config_file)"; \ + $(INSTALL_DATA) man_db.conf $(DESTDIR)$(config_file); \ + fi + +uninstall-hook: + rm -f $(DESTDIR)$(bindir)/$(TRANS_APROPOS)$(EXEEXT) + @echo "Please remove $(DESTDIR)$(config_file) manually if necessary" diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..c2f4385 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,2337 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = catman$(EXEEXT) lexgrog$(EXEEXT) man$(EXEEXT) \ + mandb$(EXEEXT) manpath$(EXEEXT) whatis$(EXEEXT) +sbin_PROGRAMS = accessdb$(EXEEXT) +pkglibexec_PROGRAMS = globbing$(EXEEXT) manconv$(EXEEXT) \ + zsoelim$(EXEEXT) +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/man-arg-automatic-create.m4 \ + $(top_srcdir)/m4/man-arg-automatic-update.m4 \ + $(top_srcdir)/m4/man-arg-cache-owner.m4 \ + $(top_srcdir)/m4/man-arg-cats.m4 \ + $(top_srcdir)/m4/man-arg-config-file.m4 \ + $(top_srcdir)/m4/man-arg-db.m4 \ + $(top_srcdir)/m4/man-arg-device.m4 \ + $(top_srcdir)/m4/man-arg-mandirs.m4 \ + $(top_srcdir)/m4/man-arg-override-dir.m4 \ + $(top_srcdir)/m4/man-arg-sections.m4 \ + $(top_srcdir)/m4/man-arg-setuid.m4 \ + $(top_srcdir)/m4/man-arg-systemdsystemunitdir.m4 \ + $(top_srcdir)/m4/man-arg-systemdtmpfilesdir.m4 \ + $(top_srcdir)/m4/man-arg-undoc.m4 $(top_srcdir)/m4/man-bdb.m4 \ + $(top_srcdir)/m4/man-check-progs.m4 \ + $(top_srcdir)/m4/man-compress-lib.m4 \ + $(top_srcdir)/m4/man-gnu-nroff.m4 \ + $(top_srcdir)/m4/man-heirloom-nroff.m4 \ + $(top_srcdir)/m4/man-libseccomp.m4 \ + $(top_srcdir)/m4/man-linguas.m4 $(top_srcdir)/m4/man-po4a.m4 \ + $(top_srcdir)/m4/man-tar-sort-name.m4 \ + $(top_srcdir)/m4/man-trans-subst.m4 \ + $(top_srcdir)/gl/m4/00gnulib.m4 \ + $(top_srcdir)/gl/m4/__inline.m4 \ + $(top_srcdir)/gl/m4/absolute-header.m4 \ + $(top_srcdir)/gl/m4/alloca.m4 $(top_srcdir)/gl/m4/argp.m4 \ + $(top_srcdir)/gl/m4/asm-underscore.m4 \ + $(top_srcdir)/gl/m4/btowc.m4 \ + $(top_srcdir)/gl/m4/builtin-expect.m4 \ + $(top_srcdir)/gl/m4/canonicalize.m4 \ + $(top_srcdir)/gl/m4/chdir-long.m4 \ + $(top_srcdir)/gl/m4/clock_time.m4 $(top_srcdir)/gl/m4/close.m4 \ + $(top_srcdir)/gl/m4/closedir.m4 $(top_srcdir)/gl/m4/codeset.m4 \ + $(top_srcdir)/gl/m4/d-ino.m4 $(top_srcdir)/gl/m4/d-type.m4 \ + $(top_srcdir)/gl/m4/dirent_h.m4 $(top_srcdir)/gl/m4/dirfd.m4 \ + $(top_srcdir)/gl/m4/dirname.m4 \ + $(top_srcdir)/gl/m4/double-slash-root.m4 \ + $(top_srcdir)/gl/m4/dup.m4 $(top_srcdir)/gl/m4/dup2.m4 \ + $(top_srcdir)/gl/m4/eealloc.m4 $(top_srcdir)/gl/m4/environ.m4 \ + $(top_srcdir)/gl/m4/errno_h.m4 $(top_srcdir)/gl/m4/error.m4 \ + $(top_srcdir)/gl/m4/exponentd.m4 \ + $(top_srcdir)/gl/m4/extensions.m4 \ + $(top_srcdir)/gl/m4/extern-inline.m4 \ + $(top_srcdir)/gl/m4/fchdir.m4 $(top_srcdir)/gl/m4/fcntl-o.m4 \ + $(top_srcdir)/gl/m4/fcntl.m4 $(top_srcdir)/gl/m4/fcntl_h.m4 \ + $(top_srcdir)/gl/m4/fdopendir.m4 \ + $(top_srcdir)/gl/m4/filenamecat.m4 \ + $(top_srcdir)/gl/m4/flexmember.m4 \ + $(top_srcdir)/gl/m4/float_h.m4 $(top_srcdir)/gl/m4/flock.m4 \ + $(top_srcdir)/gl/m4/fnmatch.m4 \ + $(top_srcdir)/gl/m4/fnmatch_h.m4 $(top_srcdir)/gl/m4/fstat.m4 \ + $(top_srcdir)/gl/m4/fstatat.m4 $(top_srcdir)/gl/m4/futimens.m4 \ + $(top_srcdir)/gl/m4/getcwd-abort-bug.m4 \ + $(top_srcdir)/gl/m4/getcwd-path-max.m4 \ + $(top_srcdir)/gl/m4/getcwd.m4 $(top_srcdir)/gl/m4/getdelim.m4 \ + $(top_srcdir)/gl/m4/getdtablesize.m4 \ + $(top_srcdir)/gl/m4/getline.m4 $(top_srcdir)/gl/m4/getlogin.m4 \ + $(top_srcdir)/gl/m4/getlogin_r.m4 \ + $(top_srcdir)/gl/m4/getopt.m4 \ + $(top_srcdir)/gl/m4/getpagesize.m4 \ + $(top_srcdir)/gl/m4/getprogname.m4 \ + $(top_srcdir)/gl/m4/gettext.m4 $(top_srcdir)/gl/m4/gettime.m4 \ + $(top_srcdir)/gl/m4/gettimeofday.m4 \ + $(top_srcdir)/gl/m4/glibc21.m4 $(top_srcdir)/gl/m4/glob.m4 \ + $(top_srcdir)/gl/m4/glob_h.m4 \ + $(top_srcdir)/gl/m4/gnulib-common.m4 \ + $(top_srcdir)/gl/m4/gnulib-comp.m4 \ + $(top_srcdir)/gl/m4/host-cpu-c-abi.m4 \ + $(top_srcdir)/gl/m4/iconv.m4 $(top_srcdir)/gl/m4/idpriv.m4 \ + $(top_srcdir)/gl/m4/include_next.m4 \ + $(top_srcdir)/gl/m4/intlmacosx.m4 \ + $(top_srcdir)/gl/m4/intmax_t.m4 \ + $(top_srcdir)/gl/m4/inttypes_h.m4 $(top_srcdir)/gl/m4/ioctl.m4 \ + $(top_srcdir)/gl/m4/langinfo_h.m4 \ + $(top_srcdir)/gl/m4/largefile.m4 \ + $(top_srcdir)/gl/m4/lib-ignore.m4 \ + $(top_srcdir)/gl/m4/lib-ld.m4 $(top_srcdir)/gl/m4/lib-link.m4 \ + $(top_srcdir)/gl/m4/lib-prefix.m4 \ + $(top_srcdir)/gl/m4/libtool.m4 $(top_srcdir)/gl/m4/limits-h.m4 \ + $(top_srcdir)/gl/m4/localcharset.m4 \ + $(top_srcdir)/gl/m4/locale-fr.m4 \ + $(top_srcdir)/gl/m4/locale-ja.m4 \ + $(top_srcdir)/gl/m4/locale-zh.m4 \ + $(top_srcdir)/gl/m4/locale_h.m4 \ + $(top_srcdir)/gl/m4/localeconv.m4 \ + $(top_srcdir)/gl/m4/localtime-buffer.m4 \ + $(top_srcdir)/gl/m4/lock.m4 $(top_srcdir)/gl/m4/longlong.m4 \ + $(top_srcdir)/gl/m4/lstat.m4 $(top_srcdir)/gl/m4/ltoptions.m4 \ + $(top_srcdir)/gl/m4/ltsugar.m4 \ + $(top_srcdir)/gl/m4/ltversion.m4 \ + $(top_srcdir)/gl/m4/lt~obsolete.m4 \ + $(top_srcdir)/gl/m4/malloc.m4 $(top_srcdir)/gl/m4/malloca.m4 \ + $(top_srcdir)/gl/m4/mbrtowc.m4 $(top_srcdir)/gl/m4/mbsinit.m4 \ + $(top_srcdir)/gl/m4/mbsrtowcs.m4 \ + $(top_srcdir)/gl/m4/mbstate_t.m4 $(top_srcdir)/gl/m4/mbtowc.m4 \ + $(top_srcdir)/gl/m4/memchr.m4 $(top_srcdir)/gl/m4/memmem.m4 \ + $(top_srcdir)/gl/m4/mempcpy.m4 $(top_srcdir)/gl/m4/memrchr.m4 \ + $(top_srcdir)/gl/m4/minmax.m4 $(top_srcdir)/gl/m4/mkdir.m4 \ + $(top_srcdir)/gl/m4/mkdtemp.m4 $(top_srcdir)/gl/m4/mkstemp.m4 \ + $(top_srcdir)/gl/m4/mmap-anon.m4 $(top_srcdir)/gl/m4/mode_t.m4 \ + $(top_srcdir)/gl/m4/msvc-inval.m4 \ + $(top_srcdir)/gl/m4/msvc-nothrow.m4 \ + $(top_srcdir)/gl/m4/multiarch.m4 \ + $(top_srcdir)/gl/m4/nanosleep.m4 \ + $(top_srcdir)/gl/m4/nl_langinfo.m4 $(top_srcdir)/gl/m4/nls.m4 \ + $(top_srcdir)/gl/m4/nocrash.m4 \ + $(top_srcdir)/gl/m4/nonblocking.m4 \ + $(top_srcdir)/gl/m4/off_t.m4 \ + $(top_srcdir)/gl/m4/open-cloexec.m4 \ + $(top_srcdir)/gl/m4/open.m4 $(top_srcdir)/gl/m4/openat.m4 \ + $(top_srcdir)/gl/m4/opendir.m4 $(top_srcdir)/gl/m4/pathmax.m4 \ + $(top_srcdir)/gl/m4/po.m4 $(top_srcdir)/gl/m4/printf.m4 \ + $(top_srcdir)/gl/m4/progtest.m4 \ + $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \ + $(top_srcdir)/gl/m4/raise.m4 $(top_srcdir)/gl/m4/rawmemchr.m4 \ + $(top_srcdir)/gl/m4/readdir.m4 $(top_srcdir)/gl/m4/readlink.m4 \ + $(top_srcdir)/gl/m4/realloc.m4 $(top_srcdir)/gl/m4/regex.m4 \ + $(top_srcdir)/gl/m4/rename.m4 $(top_srcdir)/gl/m4/rewinddir.m4 \ + $(top_srcdir)/gl/m4/rmdir.m4 $(top_srcdir)/gl/m4/same.m4 \ + $(top_srcdir)/gl/m4/save-cwd.m4 $(top_srcdir)/gl/m4/select.m4 \ + $(top_srcdir)/gl/m4/setenv.m4 $(top_srcdir)/gl/m4/sigaction.m4 \ + $(top_srcdir)/gl/m4/signal_h.m4 \ + $(top_srcdir)/gl/m4/signalblocking.m4 \ + $(top_srcdir)/gl/m4/size_max.m4 $(top_srcdir)/gl/m4/sleep.m4 \ + $(top_srcdir)/gl/m4/socketlib.m4 \ + $(top_srcdir)/gl/m4/sockets.m4 $(top_srcdir)/gl/m4/socklen.m4 \ + $(top_srcdir)/gl/m4/ssize_t.m4 \ + $(top_srcdir)/gl/m4/stat-time.m4 $(top_srcdir)/gl/m4/stat.m4 \ + $(top_srcdir)/gl/m4/std-gnu11.m4 \ + $(top_srcdir)/gl/m4/stdalign.m4 $(top_srcdir)/gl/m4/stdarg.m4 \ + $(top_srcdir)/gl/m4/stdbool.m4 $(top_srcdir)/gl/m4/stddef_h.m4 \ + $(top_srcdir)/gl/m4/stdint.m4 $(top_srcdir)/gl/m4/stdint_h.m4 \ + $(top_srcdir)/gl/m4/stdio_h.m4 $(top_srcdir)/gl/m4/stdlib_h.m4 \ + $(top_srcdir)/gl/m4/strcase.m4 \ + $(top_srcdir)/gl/m4/strcasestr.m4 \ + $(top_srcdir)/gl/m4/strchrnul.m4 $(top_srcdir)/gl/m4/strdup.m4 \ + $(top_srcdir)/gl/m4/strerror.m4 \ + $(top_srcdir)/gl/m4/string_h.m4 \ + $(top_srcdir)/gl/m4/strings_h.m4 \ + $(top_srcdir)/gl/m4/strndup.m4 $(top_srcdir)/gl/m4/strnlen.m4 \ + $(top_srcdir)/gl/m4/strsep.m4 \ + $(top_srcdir)/gl/m4/sys_file_h.m4 \ + $(top_srcdir)/gl/m4/sys_ioctl_h.m4 \ + $(top_srcdir)/gl/m4/sys_select_h.m4 \ + $(top_srcdir)/gl/m4/sys_socket_h.m4 \ + $(top_srcdir)/gl/m4/sys_stat_h.m4 \ + $(top_srcdir)/gl/m4/sys_time_h.m4 \ + $(top_srcdir)/gl/m4/sys_types_h.m4 \ + $(top_srcdir)/gl/m4/sys_uio_h.m4 \ + $(top_srcdir)/gl/m4/sysexits.m4 \ + $(top_srcdir)/gl/m4/tempname.m4 \ + $(top_srcdir)/gl/m4/threadlib.m4 $(top_srcdir)/gl/m4/time_h.m4 \ + $(top_srcdir)/gl/m4/timespec.m4 \ + $(top_srcdir)/gl/m4/unistd-safer.m4 \ + $(top_srcdir)/gl/m4/unistd_h.m4 $(top_srcdir)/gl/m4/utime.m4 \ + $(top_srcdir)/gl/m4/utime_h.m4 $(top_srcdir)/gl/m4/utimens.m4 \ + $(top_srcdir)/gl/m4/utimes.m4 \ + $(top_srcdir)/gl/m4/vasnprintf.m4 \ + $(top_srcdir)/gl/m4/vasprintf.m4 \ + $(top_srcdir)/gl/m4/vsnprintf.m4 \ + $(top_srcdir)/gl/m4/warn-on-use.m4 \ + $(top_srcdir)/gl/m4/warnings.m4 $(top_srcdir)/gl/m4/wchar_h.m4 \ + $(top_srcdir)/gl/m4/wchar_t.m4 $(top_srcdir)/gl/m4/wcrtomb.m4 \ + $(top_srcdir)/gl/m4/wctype_h.m4 $(top_srcdir)/gl/m4/wint_t.m4 \ + $(top_srcdir)/gl/m4/xalloc.m4 $(top_srcdir)/gl/m4/xgetcwd.m4 \ + $(top_srcdir)/gl/m4/xsize.m4 $(top_srcdir)/gl/m4/xstrndup.m4 \ + $(top_srcdir)/gl/m4/xvasprintf.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = man_db.conf +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" \ + "$(DESTDIR)$(sbindir)" +PROGRAMS = $(bin_PROGRAMS) $(pkglibexec_PROGRAMS) $(sbin_PROGRAMS) +am_accessdb_OBJECTS = accessdb.$(OBJEXT) +accessdb_OBJECTS = $(am_accessdb_OBJECTS) +am__DEPENDENCIES_1 = $(top_builddir)/lib/libman.la \ + $(top_builddir)/gl/lib/libgnu.la +am__DEPENDENCIES_2 = +am__DEPENDENCIES_3 = $(top_builddir)/libdb/libmandb.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +accessdb_DEPENDENCIES = $(am__DEPENDENCIES_3) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +am_catman_OBJECTS = catman.$(OBJEXT) globbing.$(OBJEXT) manp.$(OBJEXT) +catman_OBJECTS = $(am_catman_OBJECTS) +catman_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) +am_globbing_OBJECTS = globbing.$(OBJEXT) globbing_test.$(OBJEXT) +globbing_OBJECTS = $(am_globbing_OBJECTS) +globbing_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_lexgrog_OBJECTS = compression.$(OBJEXT) descriptions.$(OBJEXT) \ + filenames.$(OBJEXT) globbing.$(OBJEXT) lexgrog.$(OBJEXT) \ + lexgrog_test.$(OBJEXT) manconv.$(OBJEXT) \ + manconv_client.$(OBJEXT) ult_src.$(OBJEXT) +lexgrog_OBJECTS = $(am_lexgrog_OBJECTS) +lexgrog_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_man_OBJECTS = compression.$(OBJEXT) filenames.$(OBJEXT) \ + globbing.$(OBJEXT) man.$(OBJEXT) manconv.$(OBJEXT) \ + manconv_client.$(OBJEXT) manp.$(OBJEXT) ult_src.$(OBJEXT) \ + zsoelim.$(OBJEXT) +man_OBJECTS = $(am_man_OBJECTS) +man_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_manconv_OBJECTS = manconv.$(OBJEXT) manconv_main.$(OBJEXT) +manconv_OBJECTS = $(am_manconv_OBJECTS) +manconv_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_mandb_OBJECTS = check_mandirs.$(OBJEXT) compression.$(OBJEXT) \ + descriptions.$(OBJEXT) descriptions_store.$(OBJEXT) \ + filenames.$(OBJEXT) globbing.$(OBJEXT) lexgrog.$(OBJEXT) \ + manconv.$(OBJEXT) manconv_client.$(OBJEXT) mandb.$(OBJEXT) \ + manp.$(OBJEXT) straycats.$(OBJEXT) ult_src.$(OBJEXT) +mandb_OBJECTS = $(am_mandb_OBJECTS) +mandb_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_manpath_OBJECTS = globbing.$(OBJEXT) manp.$(OBJEXT) \ + manpath.$(OBJEXT) +manpath_OBJECTS = $(am_manpath_OBJECTS) +manpath_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_whatis_OBJECTS = globbing.$(OBJEXT) manconv.$(OBJEXT) \ + manp.$(OBJEXT) whatis.$(OBJEXT) +whatis_OBJECTS = $(am_whatis_OBJECTS) +whatis_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_zsoelim_OBJECTS = globbing.$(OBJEXT) manp.$(OBJEXT) \ + zsoelim.$(OBJEXT) zsoelim_main.$(OBJEXT) +zsoelim_OBJECTS = $(am_zsoelim_OBJECTS) +zsoelim_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/accessdb.Po ./$(DEPDIR)/catman.Po \ + ./$(DEPDIR)/check_mandirs.Po ./$(DEPDIR)/compression.Po \ + ./$(DEPDIR)/descriptions.Po ./$(DEPDIR)/descriptions_store.Po \ + ./$(DEPDIR)/filenames.Po ./$(DEPDIR)/globbing.Po \ + ./$(DEPDIR)/globbing_test.Po ./$(DEPDIR)/lexgrog.Po \ + ./$(DEPDIR)/lexgrog_test.Po ./$(DEPDIR)/man.Po \ + ./$(DEPDIR)/manconv.Po ./$(DEPDIR)/manconv_client.Po \ + ./$(DEPDIR)/manconv_main.Po ./$(DEPDIR)/mandb.Po \ + ./$(DEPDIR)/manp.Po ./$(DEPDIR)/manpath.Po \ + ./$(DEPDIR)/straycats.Po ./$(DEPDIR)/ult_src.Po \ + ./$(DEPDIR)/whatis.Po ./$(DEPDIR)/zsoelim.Po \ + ./$(DEPDIR)/zsoelim_main.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || +LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) +LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) +AM_V_LEX = $(am__v_LEX_@AM_V@) +am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) +am__v_LEX_0 = @echo " LEX " $@; +am__v_LEX_1 = +YLWRAP = $(top_srcdir)/build-aux/ylwrap +SOURCES = $(accessdb_SOURCES) $(catman_SOURCES) $(globbing_SOURCES) \ + $(lexgrog_SOURCES) $(man_SOURCES) $(manconv_SOURCES) \ + $(mandb_SOURCES) $(manpath_SOURCES) $(whatis_SOURCES) \ + $(zsoelim_SOURCES) +DIST_SOURCES = $(accessdb_SOURCES) $(catman_SOURCES) \ + $(globbing_SOURCES) $(lexgrog_SOURCES) $(man_SOURCES) \ + $(manconv_SOURCES) $(mandb_SOURCES) $(manpath_SOURCES) \ + $(whatis_SOURCES) $(zsoelim_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DATA = $(noinst_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/man_db.conf.in \ + $(top_srcdir)/build-aux/depcomp $(top_srcdir)/build-aux/ylwrap \ + lexgrog.c zsoelim.c +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkglibexecdir = $(libexecdir)/@PACKAGE@ +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALLOCA_H = @ALLOCA_H@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +ASM_SYMBOL_PREFIX = @ASM_SYMBOL_PREFIX@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@ +BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@ +BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@ +BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@ +BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBLIBS = @DBLIBS@ +DBTYPE = @DBTYPE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ +EMULTIHOP_VALUE = @EMULTIHOP_VALUE@ +ENOLINK_HIDDEN = @ENOLINK_HIDDEN@ +ENOLINK_VALUE = @ENOLINK_VALUE@ +EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ +EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ +ERRNO_H = @ERRNO_H@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLOAT_H = @FLOAT_H@ +FNMATCH_H = @FNMATCH_H@ +GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC21 = @GLIBC21@ +GLOB_H = @GLOB_H@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ACCEPT = @GNULIB_ACCEPT@ +GNULIB_ACCEPT4 = @GNULIB_ACCEPT4@ +GNULIB_ALPHASORT = @GNULIB_ALPHASORT@ +GNULIB_ATOLL = @GNULIB_ATOLL@ +GNULIB_BIND = @GNULIB_BIND@ +GNULIB_BTOWC = @GNULIB_BTOWC@ +GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ +GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CHDIR = @GNULIB_CHDIR@ +GNULIB_CHOWN = @GNULIB_CHOWN@ +GNULIB_CLOSE = @GNULIB_CLOSE@ +GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@ +GNULIB_CONNECT = @GNULIB_CONNECT@ +GNULIB_CTIME = @GNULIB_CTIME@ +GNULIB_DIRFD = @GNULIB_DIRFD@ +GNULIB_DPRINTF = @GNULIB_DPRINTF@ +GNULIB_DUP = @GNULIB_DUP@ +GNULIB_DUP2 = @GNULIB_DUP2@ +GNULIB_DUP3 = @GNULIB_DUP3@ +GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ +GNULIB_ENVIRON = @GNULIB_ENVIRON@ +GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_EXPLICIT_BZERO = @GNULIB_EXPLICIT_BZERO@ +GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ +GNULIB_FCHDIR = @GNULIB_FCHDIR@ +GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ +GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ +GNULIB_FCLOSE = @GNULIB_FCLOSE@ +GNULIB_FCNTL = @GNULIB_FCNTL@ +GNULIB_FDATASYNC = @GNULIB_FDATASYNC@ +GNULIB_FDOPEN = @GNULIB_FDOPEN@ +GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@ +GNULIB_FFLUSH = @GNULIB_FFLUSH@ +GNULIB_FFS = @GNULIB_FFS@ +GNULIB_FFSL = @GNULIB_FFSL@ +GNULIB_FFSLL = @GNULIB_FFSLL@ +GNULIB_FGETC = @GNULIB_FGETC@ +GNULIB_FGETS = @GNULIB_FGETS@ +GNULIB_FLOCK = @GNULIB_FLOCK@ +GNULIB_FNMATCH = @GNULIB_FNMATCH@ +GNULIB_FOPEN = @GNULIB_FOPEN@ +GNULIB_FPRINTF = @GNULIB_FPRINTF@ +GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ +GNULIB_FPURGE = @GNULIB_FPURGE@ +GNULIB_FPUTC = @GNULIB_FPUTC@ +GNULIB_FPUTS = @GNULIB_FPUTS@ +GNULIB_FREAD = @GNULIB_FREAD@ +GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FSCANF = @GNULIB_FSCANF@ +GNULIB_FSEEK = @GNULIB_FSEEK@ +GNULIB_FSEEKO = @GNULIB_FSEEKO@ +GNULIB_FSTAT = @GNULIB_FSTAT@ +GNULIB_FSTATAT = @GNULIB_FSTATAT@ +GNULIB_FSYNC = @GNULIB_FSYNC@ +GNULIB_FTELL = @GNULIB_FTELL@ +GNULIB_FTELLO = @GNULIB_FTELLO@ +GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ +GNULIB_FUTIMENS = @GNULIB_FUTIMENS@ +GNULIB_FWRITE = @GNULIB_FWRITE@ +GNULIB_GETC = @GNULIB_GETC@ +GNULIB_GETCHAR = @GNULIB_GETCHAR@ +GNULIB_GETCWD = @GNULIB_GETCWD@ +GNULIB_GETDELIM = @GNULIB_GETDELIM@ +GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@ +GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@ +GNULIB_GETGROUPS = @GNULIB_GETGROUPS@ +GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@ +GNULIB_GETLINE = @GNULIB_GETLINE@ +GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@ +GNULIB_GETLOGIN = @GNULIB_GETLOGIN@ +GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@ +GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@ +GNULIB_GETPASS = @GNULIB_GETPASS@ +GNULIB_GETPEERNAME = @GNULIB_GETPEERNAME@ +GNULIB_GETSOCKNAME = @GNULIB_GETSOCKNAME@ +GNULIB_GETSOCKOPT = @GNULIB_GETSOCKOPT@ +GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ +GNULIB_GLOB = @GNULIB_GLOB@ +GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ +GNULIB_GRANTPT = @GNULIB_GRANTPT@ +GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ +GNULIB_IOCTL = @GNULIB_IOCTL@ +GNULIB_ISATTY = @GNULIB_ISATTY@ +GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ +GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ +GNULIB_LCHMOD = @GNULIB_LCHMOD@ +GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LINK = @GNULIB_LINK@ +GNULIB_LINKAT = @GNULIB_LINKAT@ +GNULIB_LISTEN = @GNULIB_LISTEN@ +GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ +GNULIB_LOCALENAME = @GNULIB_LOCALENAME@ +GNULIB_LOCALTIME = @GNULIB_LOCALTIME@ +GNULIB_LSEEK = @GNULIB_LSEEK@ +GNULIB_LSTAT = @GNULIB_LSTAT@ +GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ +GNULIB_MBRLEN = @GNULIB_MBRLEN@ +GNULIB_MBRTOWC = @GNULIB_MBRTOWC@ +GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@ +GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@ +GNULIB_MBSCHR = @GNULIB_MBSCHR@ +GNULIB_MBSCSPN = @GNULIB_MBSCSPN@ +GNULIB_MBSINIT = @GNULIB_MBSINIT@ +GNULIB_MBSLEN = @GNULIB_MBSLEN@ +GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@ +GNULIB_MBSNLEN = @GNULIB_MBSNLEN@ +GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@ +GNULIB_MBSPBRK = @GNULIB_MBSPBRK@ +GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@ +GNULIB_MBSRCHR = @GNULIB_MBSRCHR@ +GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@ +GNULIB_MBSSEP = @GNULIB_MBSSEP@ +GNULIB_MBSSPN = @GNULIB_MBSSPN@ +GNULIB_MBSSTR = @GNULIB_MBSSTR@ +GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@ +GNULIB_MBTOWC = @GNULIB_MBTOWC@ +GNULIB_MEMCHR = @GNULIB_MEMCHR@ +GNULIB_MEMMEM = @GNULIB_MEMMEM@ +GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ +GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ +GNULIB_MKDIRAT = @GNULIB_MKDIRAT@ +GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ +GNULIB_MKFIFO = @GNULIB_MKFIFO@ +GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@ +GNULIB_MKNOD = @GNULIB_MKNOD@ +GNULIB_MKNODAT = @GNULIB_MKNODAT@ +GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ +GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ +GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ +GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ +GNULIB_MKTIME = @GNULIB_MKTIME@ +GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ +GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ +GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ +GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ +GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ +GNULIB_OPEN = @GNULIB_OPEN@ +GNULIB_OPENAT = @GNULIB_OPENAT@ +GNULIB_OPENDIR = @GNULIB_OPENDIR@ +GNULIB_OVERRIDES_STRUCT_STAT = @GNULIB_OVERRIDES_STRUCT_STAT@ +GNULIB_OVERRIDES_WINT_T = @GNULIB_OVERRIDES_WINT_T@ +GNULIB_PCLOSE = @GNULIB_PCLOSE@ +GNULIB_PERROR = @GNULIB_PERROR@ +GNULIB_PIPE = @GNULIB_PIPE@ +GNULIB_PIPE2 = @GNULIB_PIPE2@ +GNULIB_POPEN = @GNULIB_POPEN@ +GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@ +GNULIB_PREAD = @GNULIB_PREAD@ +GNULIB_PRINTF = @GNULIB_PRINTF@ +GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ +GNULIB_PSELECT = @GNULIB_PSELECT@ +GNULIB_PTHREAD_SIGMASK = @GNULIB_PTHREAD_SIGMASK@ +GNULIB_PTSNAME = @GNULIB_PTSNAME@ +GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@ +GNULIB_PUTC = @GNULIB_PUTC@ +GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ +GNULIB_PUTENV = @GNULIB_PUTENV@ +GNULIB_PUTS = @GNULIB_PUTS@ +GNULIB_PWRITE = @GNULIB_PWRITE@ +GNULIB_QSORT_R = @GNULIB_QSORT_R@ +GNULIB_RAISE = @GNULIB_RAISE@ +GNULIB_RANDOM = @GNULIB_RANDOM@ +GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ +GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ +GNULIB_READ = @GNULIB_READ@ +GNULIB_READDIR = @GNULIB_READDIR@ +GNULIB_READLINK = @GNULIB_READLINK@ +GNULIB_READLINKAT = @GNULIB_READLINKAT@ +GNULIB_REALLOCARRAY = @GNULIB_REALLOCARRAY@ +GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ +GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_RECV = @GNULIB_RECV@ +GNULIB_RECVFROM = @GNULIB_RECVFROM@ +GNULIB_REMOVE = @GNULIB_REMOVE@ +GNULIB_RENAME = @GNULIB_RENAME@ +GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ +GNULIB_REWINDDIR = @GNULIB_REWINDDIR@ +GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_RPMATCH = @GNULIB_RPMATCH@ +GNULIB_SCANDIR = @GNULIB_SCANDIR@ +GNULIB_SCANF = @GNULIB_SCANF@ +GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@ +GNULIB_SELECT = @GNULIB_SELECT@ +GNULIB_SEND = @GNULIB_SEND@ +GNULIB_SENDTO = @GNULIB_SENDTO@ +GNULIB_SETENV = @GNULIB_SETENV@ +GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ +GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ +GNULIB_SETSOCKOPT = @GNULIB_SETSOCKOPT@ +GNULIB_SHUTDOWN = @GNULIB_SHUTDOWN@ +GNULIB_SIGACTION = @GNULIB_SIGACTION@ +GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@ +GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@ +GNULIB_SLEEP = @GNULIB_SLEEP@ +GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ +GNULIB_SOCKET = @GNULIB_SOCKET@ +GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_STAT = @GNULIB_STAT@ +GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ +GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ +GNULIB_STPCPY = @GNULIB_STPCPY@ +GNULIB_STPNCPY = @GNULIB_STPNCPY@ +GNULIB_STRCASESTR = @GNULIB_STRCASESTR@ +GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@ +GNULIB_STRDUP = @GNULIB_STRDUP@ +GNULIB_STRERROR = @GNULIB_STRERROR@ +GNULIB_STRERROR_R = @GNULIB_STRERROR_R@ +GNULIB_STRFTIME = @GNULIB_STRFTIME@ +GNULIB_STRNCAT = @GNULIB_STRNCAT@ +GNULIB_STRNDUP = @GNULIB_STRNDUP@ +GNULIB_STRNLEN = @GNULIB_STRNLEN@ +GNULIB_STRPBRK = @GNULIB_STRPBRK@ +GNULIB_STRPTIME = @GNULIB_STRPTIME@ +GNULIB_STRSEP = @GNULIB_STRSEP@ +GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@ +GNULIB_STRSTR = @GNULIB_STRSTR@ +GNULIB_STRTOD = @GNULIB_STRTOD@ +GNULIB_STRTOK_R = @GNULIB_STRTOK_R@ +GNULIB_STRTOLL = @GNULIB_STRTOLL@ +GNULIB_STRTOULL = @GNULIB_STRTOULL@ +GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ +GNULIB_SYMLINK = @GNULIB_SYMLINK@ +GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ +GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ +GNULIB_TIMEGM = @GNULIB_TIMEGM@ +GNULIB_TIME_R = @GNULIB_TIME_R@ +GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ +GNULIB_TMPFILE = @GNULIB_TMPFILE@ +GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ +GNULIB_TRUNCATE = @GNULIB_TRUNCATE@ +GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ +GNULIB_TZSET = @GNULIB_TZSET@ +GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ +GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ +GNULIB_UNLINK = @GNULIB_UNLINK@ +GNULIB_UNLINKAT = @GNULIB_UNLINKAT@ +GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@ +GNULIB_UNSETENV = @GNULIB_UNSETENV@ +GNULIB_USLEEP = @GNULIB_USLEEP@ +GNULIB_UTIME = @GNULIB_UTIME@ +GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@ +GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ +GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ +GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ +GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ +GNULIB_VFSCANF = @GNULIB_VFSCANF@ +GNULIB_VPRINTF = @GNULIB_VPRINTF@ +GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ +GNULIB_VSCANF = @GNULIB_VSCANF@ +GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ +GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ +GNULIB_WCPCPY = @GNULIB_WCPCPY@ +GNULIB_WCPNCPY = @GNULIB_WCPNCPY@ +GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ +GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@ +GNULIB_WCSCAT = @GNULIB_WCSCAT@ +GNULIB_WCSCHR = @GNULIB_WCSCHR@ +GNULIB_WCSCMP = @GNULIB_WCSCMP@ +GNULIB_WCSCOLL = @GNULIB_WCSCOLL@ +GNULIB_WCSCPY = @GNULIB_WCSCPY@ +GNULIB_WCSCSPN = @GNULIB_WCSCSPN@ +GNULIB_WCSDUP = @GNULIB_WCSDUP@ +GNULIB_WCSFTIME = @GNULIB_WCSFTIME@ +GNULIB_WCSLEN = @GNULIB_WCSLEN@ +GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@ +GNULIB_WCSNCAT = @GNULIB_WCSNCAT@ +GNULIB_WCSNCMP = @GNULIB_WCSNCMP@ +GNULIB_WCSNCPY = @GNULIB_WCSNCPY@ +GNULIB_WCSNLEN = @GNULIB_WCSNLEN@ +GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ +GNULIB_WCSPBRK = @GNULIB_WCSPBRK@ +GNULIB_WCSRCHR = @GNULIB_WCSRCHR@ +GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ +GNULIB_WCSSPN = @GNULIB_WCSSPN@ +GNULIB_WCSSTR = @GNULIB_WCSSTR@ +GNULIB_WCSTOK = @GNULIB_WCSTOK@ +GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@ +GNULIB_WCSXFRM = @GNULIB_WCSXFRM@ +GNULIB_WCTOB = @GNULIB_WCTOB@ +GNULIB_WCTOMB = @GNULIB_WCTOMB@ +GNULIB_WCTRANS = @GNULIB_WCTRANS@ +GNULIB_WCTYPE = @GNULIB_WCTYPE@ +GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ +GNULIB_WMEMCHR = @GNULIB_WMEMCHR@ +GNULIB_WMEMCMP = @GNULIB_WMEMCMP@ +GNULIB_WMEMCPY = @GNULIB_WMEMCPY@ +GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@ +GNULIB_WMEMSET = @GNULIB_WMEMSET@ +GNULIB_WRITE = @GNULIB_WRITE@ +GNULIB__EXIT = @GNULIB__EXIT@ +GREP = @GREP@ +HAVE_ACCEPT4 = @HAVE_ACCEPT4@ +HAVE_ALPHASORT = @HAVE_ALPHASORT@ +HAVE_ATOLL = @HAVE_ATOLL@ +HAVE_BTOWC = @HAVE_BTOWC@ +HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@ +HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CHOWN = @HAVE_CHOWN@ +HAVE_CLOSEDIR = @HAVE_CLOSEDIR@ +HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ +HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ +HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@ +HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ +HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ +HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ +HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@ +HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ +HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ +HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@ +HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ +HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ +HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@ +HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ +HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ +HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ +HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ +HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ +HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@ +HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ +HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ +HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@ +HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ +HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@ +HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@ +HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ +HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ +HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DIRENT_H = @HAVE_DIRENT_H@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP2 = @HAVE_DUP2@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@ +HAVE_FACCESSAT = @HAVE_FACCESSAT@ +HAVE_FCHDIR = @HAVE_FCHDIR@ +HAVE_FCHMODAT = @HAVE_FCHMODAT@ +HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ +HAVE_FCNTL = @HAVE_FCNTL@ +HAVE_FDATASYNC = @HAVE_FDATASYNC@ +HAVE_FDOPENDIR = @HAVE_FDOPENDIR@ +HAVE_FEATURES_H = @HAVE_FEATURES_H@ +HAVE_FFS = @HAVE_FFS@ +HAVE_FFSL = @HAVE_FFSL@ +HAVE_FFSLL = @HAVE_FFSLL@ +HAVE_FLOCK = @HAVE_FLOCK@ +HAVE_FNMATCH = @HAVE_FNMATCH@ +HAVE_FNMATCH_H = @HAVE_FNMATCH_H@ +HAVE_FREELOCALE = @HAVE_FREELOCALE@ +HAVE_FSEEKO = @HAVE_FSEEKO@ +HAVE_FSTATAT = @HAVE_FSTATAT@ +HAVE_FSYNC = @HAVE_FSYNC@ +HAVE_FTELLO = @HAVE_FTELLO@ +HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ +HAVE_FUTIMENS = @HAVE_FUTIMENS@ +HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@ +HAVE_GETGROUPS = @HAVE_GETGROUPS@ +HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@ +HAVE_GETLOGIN = @HAVE_GETLOGIN@ +HAVE_GETOPT_H = @HAVE_GETOPT_H@ +HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@ +HAVE_GETPASS = @HAVE_GETPASS@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ +HAVE_GLOB = @HAVE_GLOB@ +HAVE_GLOB_H = @HAVE_GLOB_H@ +HAVE_GLOB_PATTERN_P = @HAVE_GLOB_PATTERN_P@ +HAVE_GRANTPT = @HAVE_GRANTPT@ +HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISWBLANK = @HAVE_ISWBLANK@ +HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ +HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@ +HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@ +HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@ +HAVE_LANGINFO_H = @HAVE_LANGINFO_H@ +HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ +HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ +HAVE_LCHMOD = @HAVE_LCHMOD@ +HAVE_LCHOWN = @HAVE_LCHOWN@ +HAVE_LINK = @HAVE_LINK@ +HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ +HAVE_LSTAT = @HAVE_LSTAT@ +HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ +HAVE_MBRLEN = @HAVE_MBRLEN@ +HAVE_MBRTOWC = @HAVE_MBRTOWC@ +HAVE_MBSINIT = @HAVE_MBSINIT@ +HAVE_MBSLEN = @HAVE_MBSLEN@ +HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@ +HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@ +HAVE_MEMCHR = @HAVE_MEMCHR@ +HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MKDIRAT = @HAVE_MKDIRAT@ +HAVE_MKDTEMP = @HAVE_MKDTEMP@ +HAVE_MKFIFO = @HAVE_MKFIFO@ +HAVE_MKFIFOAT = @HAVE_MKFIFOAT@ +HAVE_MKNOD = @HAVE_MKNOD@ +HAVE_MKNODAT = @HAVE_MKNODAT@ +HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ +HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ +HAVE_MKSTEMP = @HAVE_MKSTEMP@ +HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ +HAVE_NANOSLEEP = @HAVE_NANOSLEEP@ +HAVE_NEWLOCALE = @HAVE_NEWLOCALE@ +HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ +HAVE_OPENAT = @HAVE_OPENAT@ +HAVE_OPENDIR = @HAVE_OPENDIR@ +HAVE_OS_H = @HAVE_OS_H@ +HAVE_PCLOSE = @HAVE_PCLOSE@ +HAVE_PIPE = @HAVE_PIPE@ +HAVE_PIPE2 = @HAVE_PIPE2@ +HAVE_POPEN = @HAVE_POPEN@ +HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@ +HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@ +HAVE_PREAD = @HAVE_PREAD@ +HAVE_PSELECT = @HAVE_PSELECT@ +HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@ +HAVE_PTSNAME = @HAVE_PTSNAME@ +HAVE_PTSNAME_R = @HAVE_PTSNAME_R@ +HAVE_PWRITE = @HAVE_PWRITE@ +HAVE_QSORT_R = @HAVE_QSORT_R@ +HAVE_RAISE = @HAVE_RAISE@ +HAVE_RANDOM = @HAVE_RANDOM@ +HAVE_RANDOM_H = @HAVE_RANDOM_H@ +HAVE_RANDOM_R = @HAVE_RANDOM_R@ +HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ +HAVE_READDIR = @HAVE_READDIR@ +HAVE_READLINK = @HAVE_READLINK@ +HAVE_READLINKAT = @HAVE_READLINKAT@ +HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@ +HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_RENAMEAT = @HAVE_RENAMEAT@ +HAVE_REWINDDIR = @HAVE_REWINDDIR@ +HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@ +HAVE_SCANDIR = @HAVE_SCANDIR@ +HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@ +HAVE_SETENV = @HAVE_SETENV@ +HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@ +HAVE_SIGACTION = @HAVE_SIGACTION@ +HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@ +HAVE_SIGINFO_T = @HAVE_SIGINFO_T@ +HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ +HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ +HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ +HAVE_SIGSET_T = @HAVE_SIGSET_T@ +HAVE_SLEEP = @HAVE_SLEEP@ +HAVE_STDINT_H = @HAVE_STDINT_H@ +HAVE_STPCPY = @HAVE_STPCPY@ +HAVE_STPNCPY = @HAVE_STPNCPY@ +HAVE_STRCASECMP = @HAVE_STRCASECMP@ +HAVE_STRCASESTR = @HAVE_STRCASESTR@ +HAVE_STRCHRNUL = @HAVE_STRCHRNUL@ +HAVE_STRINGS_H = @HAVE_STRINGS_H@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOULL = @HAVE_STRTOULL@ +HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@ +HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@ +HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@ +HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@ +HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@ +HAVE_STRVERSCMP = @HAVE_STRVERSCMP@ +HAVE_SYMLINK = @HAVE_SYMLINK@ +HAVE_SYMLINKAT = @HAVE_SYMLINKAT@ +HAVE_SYSEXITS_H = @HAVE_SYSEXITS_H@ +HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@ +HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@ +HAVE_SYS_FILE_H = @HAVE_SYS_FILE_H@ +HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@ +HAVE_SYS_IOCTL_H = @HAVE_SYS_IOCTL_H@ +HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@ +HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ +HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@ +HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ +HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ +HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ +HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@ +HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ +HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ +HAVE_TZSET = @HAVE_TZSET@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@ +HAVE_USLEEP = @HAVE_USLEEP@ +HAVE_UTIME = @HAVE_UTIME@ +HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ +HAVE_UTIME_H = @HAVE_UTIME_H@ +HAVE_VASPRINTF = @HAVE_VASPRINTF@ +HAVE_VDPRINTF = @HAVE_VDPRINTF@ +HAVE_WCHAR_H = @HAVE_WCHAR_H@ +HAVE_WCHAR_T = @HAVE_WCHAR_T@ +HAVE_WCPCPY = @HAVE_WCPCPY@ +HAVE_WCPNCPY = @HAVE_WCPNCPY@ +HAVE_WCRTOMB = @HAVE_WCRTOMB@ +HAVE_WCSCASECMP = @HAVE_WCSCASECMP@ +HAVE_WCSCAT = @HAVE_WCSCAT@ +HAVE_WCSCHR = @HAVE_WCSCHR@ +HAVE_WCSCMP = @HAVE_WCSCMP@ +HAVE_WCSCOLL = @HAVE_WCSCOLL@ +HAVE_WCSCPY = @HAVE_WCSCPY@ +HAVE_WCSCSPN = @HAVE_WCSCSPN@ +HAVE_WCSDUP = @HAVE_WCSDUP@ +HAVE_WCSFTIME = @HAVE_WCSFTIME@ +HAVE_WCSLEN = @HAVE_WCSLEN@ +HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@ +HAVE_WCSNCAT = @HAVE_WCSNCAT@ +HAVE_WCSNCMP = @HAVE_WCSNCMP@ +HAVE_WCSNCPY = @HAVE_WCSNCPY@ +HAVE_WCSNLEN = @HAVE_WCSNLEN@ +HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ +HAVE_WCSPBRK = @HAVE_WCSPBRK@ +HAVE_WCSRCHR = @HAVE_WCSRCHR@ +HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ +HAVE_WCSSPN = @HAVE_WCSSPN@ +HAVE_WCSSTR = @HAVE_WCSSTR@ +HAVE_WCSTOK = @HAVE_WCSTOK@ +HAVE_WCSWIDTH = @HAVE_WCSWIDTH@ +HAVE_WCSXFRM = @HAVE_WCSXFRM@ +HAVE_WCTRANS_T = @HAVE_WCTRANS_T@ +HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ +HAVE_WCTYPE_T = @HAVE_WCTYPE_T@ +HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ +HAVE_WINT_T = @HAVE_WINT_T@ +HAVE_WMEMCHR = @HAVE_WMEMCHR@ +HAVE_WMEMCMP = @HAVE_WMEMCMP@ +HAVE_WMEMCPY = @HAVE_WMEMCPY@ +HAVE_WMEMMOVE = @HAVE_WMEMMOVE@ +HAVE_WMEMSET = @HAVE_WMEMSET@ +HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ +HAVE_XLOCALE_H = @HAVE_XLOCALE_H@ +HAVE__BOOL = @HAVE__BOOL@ +HAVE__EXIT = @HAVE__EXIT@ +IGNORE_UNUSED_LIBRARIES_CFLAGS = @IGNORE_UNUSED_LIBRARIES_CFLAGS@ +INCLUDE_NEXT = @INCLUDE_NEXT@ +INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCOMPRESS = @LIBCOMPRESS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_GETLOGIN = @LIB_GETLOGIN@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_SELECT = @LIB_SELECT@ +LIMITS_H = @LIMITS_H@ +LINGUAS = @LINGUAS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALE_FR = @LOCALE_FR@ +LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ +LOCALE_JA = @LOCALE_JA@ +LOCALE_ZH_CN = @LOCALE_ZH_CN@ +LTALLOCA = @LTALLOCA@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANDIR_LAYOUT = @MANDIR_LAYOUT@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_SUBDIRS = @MAN_SUBDIRS@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@ +NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ +NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ +NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@ +NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H = @NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H@ +NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ +NEXT_AS_FIRST_DIRECTIVE_GLOB_H = @NEXT_AS_FIRST_DIRECTIVE_GLOB_H@ +NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ +NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ +NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ +NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ +NEXT_AS_FIRST_DIRECTIVE_STDARG_H = @NEXT_AS_FIRST_DIRECTIVE_STDARG_H@ +NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ +NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ +NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ +NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@ +NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@ +NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@ +NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H = @NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@ +NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ +NEXT_AS_FIRST_DIRECTIVE_UTIME_H = @NEXT_AS_FIRST_DIRECTIVE_UTIME_H@ +NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ +NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ +NEXT_DIRENT_H = @NEXT_DIRENT_H@ +NEXT_ERRNO_H = @NEXT_ERRNO_H@ +NEXT_FCNTL_H = @NEXT_FCNTL_H@ +NEXT_FLOAT_H = @NEXT_FLOAT_H@ +NEXT_FNMATCH_H = @NEXT_FNMATCH_H@ +NEXT_GETOPT_H = @NEXT_GETOPT_H@ +NEXT_GLOB_H = @NEXT_GLOB_H@ +NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ +NEXT_LIMITS_H = @NEXT_LIMITS_H@ +NEXT_LOCALE_H = @NEXT_LOCALE_H@ +NEXT_SIGNAL_H = @NEXT_SIGNAL_H@ +NEXT_STDARG_H = @NEXT_STDARG_H@ +NEXT_STDDEF_H = @NEXT_STDDEF_H@ +NEXT_STDINT_H = @NEXT_STDINT_H@ +NEXT_STDIO_H = @NEXT_STDIO_H@ +NEXT_STDLIB_H = @NEXT_STDLIB_H@ +NEXT_STRINGS_H = @NEXT_STRINGS_H@ +NEXT_STRING_H = @NEXT_STRING_H@ +NEXT_SYSEXITS_H = @NEXT_SYSEXITS_H@ +NEXT_SYS_FILE_H = @NEXT_SYS_FILE_H@ +NEXT_SYS_IOCTL_H = @NEXT_SYS_IOCTL_H@ +NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@ +NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@ +NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@ +NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@ +NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@ +NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@ +NEXT_TIME_H = @NEXT_TIME_H@ +NEXT_UNISTD_H = @NEXT_UNISTD_H@ +NEXT_UTIME_H = @NEXT_UTIME_H@ +NEXT_WCHAR_H = @NEXT_WCHAR_H@ +NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PO4A = @PO4A@ +POSUB = @POSUB@ +PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ +PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC = @REPLACE_CALLOC@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ +REPLACE_CTIME = @REPLACE_CTIME@ +REPLACE_DIRFD = @REPLACE_DIRFD@ +REPLACE_DPRINTF = @REPLACE_DPRINTF@ +REPLACE_DUP = @REPLACE_DUP@ +REPLACE_DUP2 = @REPLACE_DUP2@ +REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ +REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ +REPLACE_FCLOSE = @REPLACE_FCLOSE@ +REPLACE_FCNTL = @REPLACE_FCNTL@ +REPLACE_FDOPEN = @REPLACE_FDOPEN@ +REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ +REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FNMATCH = @REPLACE_FNMATCH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREELOCALE = @REPLACE_FREELOCALE@ +REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FSEEK = @REPLACE_FSEEK@ +REPLACE_FSEEKO = @REPLACE_FSEEKO@ +REPLACE_FSTAT = @REPLACE_FSTAT@ +REPLACE_FSTATAT = @REPLACE_FSTATAT@ +REPLACE_FTELL = @REPLACE_FTELL@ +REPLACE_FTELLO = @REPLACE_FTELLO@ +REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@ +REPLACE_FUTIMENS = @REPLACE_FUTIMENS@ +REPLACE_GETCWD = @REPLACE_GETCWD@ +REPLACE_GETDELIM = @REPLACE_GETDELIM@ +REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@ +REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@ +REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ +REPLACE_GETLINE = @REPLACE_GETLINE@ +REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ +REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ +REPLACE_GETPASS = @REPLACE_GETPASS@ +REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ +REPLACE_GLOB = @REPLACE_GLOB@ +REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@ +REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_IOCTL = @REPLACE_IOCTL@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_ITOLD = @REPLACE_ITOLD@ +REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LINK = @REPLACE_LINK@ +REPLACE_LINKAT = @REPLACE_LINKAT@ +REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ +REPLACE_LOCALTIME = @REPLACE_LOCALTIME@ +REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ +REPLACE_LSEEK = @REPLACE_LSEEK@ +REPLACE_LSTAT = @REPLACE_LSTAT@ +REPLACE_MALLOC = @REPLACE_MALLOC@ +REPLACE_MBRLEN = @REPLACE_MBRLEN@ +REPLACE_MBRTOWC = @REPLACE_MBRTOWC@ +REPLACE_MBSINIT = @REPLACE_MBSINIT@ +REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@ +REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@ +REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@ +REPLACE_MBTOWC = @REPLACE_MBTOWC@ +REPLACE_MEMCHR = @REPLACE_MEMCHR@ +REPLACE_MEMMEM = @REPLACE_MEMMEM@ +REPLACE_MKDIR = @REPLACE_MKDIR@ +REPLACE_MKFIFO = @REPLACE_MKFIFO@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ +REPLACE_MKTIME = @REPLACE_MKTIME@ +REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ +REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@ +REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ +REPLACE_NULL = @REPLACE_NULL@ +REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ +REPLACE_OPEN = @REPLACE_OPEN@ +REPLACE_OPENAT = @REPLACE_OPENAT@ +REPLACE_OPENDIR = @REPLACE_OPENDIR@ +REPLACE_PERROR = @REPLACE_PERROR@ +REPLACE_POPEN = @REPLACE_POPEN@ +REPLACE_PREAD = @REPLACE_PREAD@ +REPLACE_PRINTF = @REPLACE_PRINTF@ +REPLACE_PSELECT = @REPLACE_PSELECT@ +REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@ +REPLACE_PTSNAME = @REPLACE_PTSNAME@ +REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@ +REPLACE_PUTENV = @REPLACE_PUTENV@ +REPLACE_PWRITE = @REPLACE_PWRITE@ +REPLACE_QSORT_R = @REPLACE_QSORT_R@ +REPLACE_RAISE = @REPLACE_RAISE@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_READLINKAT = @REPLACE_READLINKAT@ +REPLACE_REALLOC = @REPLACE_REALLOC@ +REPLACE_REALPATH = @REPLACE_REALPATH@ +REPLACE_REMOVE = @REPLACE_REMOVE@ +REPLACE_RENAME = @REPLACE_RENAME@ +REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ +REPLACE_RMDIR = @REPLACE_RMDIR@ +REPLACE_SELECT = @REPLACE_SELECT@ +REPLACE_SETENV = @REPLACE_SETENV@ +REPLACE_SETLOCALE = @REPLACE_SETLOCALE@ +REPLACE_SLEEP = @REPLACE_SLEEP@ +REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ +REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_STAT = @REPLACE_STAT@ +REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ +REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ +REPLACE_STPNCPY = @REPLACE_STPNCPY@ +REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ +REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@ +REPLACE_STRDUP = @REPLACE_STRDUP@ +REPLACE_STRERROR = @REPLACE_STRERROR@ +REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ +REPLACE_STRFTIME = @REPLACE_STRFTIME@ +REPLACE_STRNCAT = @REPLACE_STRNCAT@ +REPLACE_STRNDUP = @REPLACE_STRNDUP@ +REPLACE_STRNLEN = @REPLACE_STRNLEN@ +REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ +REPLACE_STRSTR = @REPLACE_STRSTR@ +REPLACE_STRTOD = @REPLACE_STRTOD@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@ +REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@ +REPLACE_SYMLINK = @REPLACE_SYMLINK@ +REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@ +REPLACE_TIMEGM = @REPLACE_TIMEGM@ +REPLACE_TMPFILE = @REPLACE_TMPFILE@ +REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ +REPLACE_TRUNCATE = @REPLACE_TRUNCATE@ +REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ +REPLACE_TZSET = @REPLACE_TZSET@ +REPLACE_UNLINK = @REPLACE_UNLINK@ +REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ +REPLACE_UNSETENV = @REPLACE_UNSETENV@ +REPLACE_USLEEP = @REPLACE_USLEEP@ +REPLACE_UTIME = @REPLACE_UTIME@ +REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@ +REPLACE_VASPRINTF = @REPLACE_VASPRINTF@ +REPLACE_VDPRINTF = @REPLACE_VDPRINTF@ +REPLACE_VFPRINTF = @REPLACE_VFPRINTF@ +REPLACE_VPRINTF = @REPLACE_VPRINTF@ +REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@ +REPLACE_VSPRINTF = @REPLACE_VSPRINTF@ +REPLACE_WCRTOMB = @REPLACE_WCRTOMB@ +REPLACE_WCSFTIME = @REPLACE_WCSFTIME@ +REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ +REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@ +REPLACE_WCTOB = @REPLACE_WCTOB@ +REPLACE_WCTOMB = @REPLACE_WCTOMB@ +REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ +REPLACE_WRITE = @REPLACE_WRITE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ +SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDALIGN_H = @STDALIGN_H@ +STDARG_H = @STDARG_H@ +STDBOOL_H = @STDBOOL_H@ +STDDEF_H = @STDDEF_H@ +STDINT_H = @STDINT_H@ +STRIP = @STRIP@ +SYSEXITS_H = @SYSEXITS_H@ +SYS_IOCTL_H_HAVE_WINSOCK2_H = @SYS_IOCTL_H_HAVE_WINSOCK2_H@ +SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ +TBL_X_FORMAT = @TBL_X_FORMAT@ +TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ +TRANS_APROPOS = @TRANS_APROPOS@ +TRANS_APROPOS_UPPER = @TRANS_APROPOS_UPPER@ +TRANS_CATMAN = @TRANS_CATMAN@ +TRANS_CATMAN_UPPER = @TRANS_CATMAN_UPPER@ +TRANS_LEXGROG = @TRANS_LEXGROG@ +TRANS_LEXGROG_UPPER = @TRANS_LEXGROG_UPPER@ +TRANS_MAN = @TRANS_MAN@ +TRANS_MANCONV = @TRANS_MANCONV@ +TRANS_MANCONV_UPPER = @TRANS_MANCONV_UPPER@ +TRANS_MANDB = @TRANS_MANDB@ +TRANS_MANDB_UPPER = @TRANS_MANDB_UPPER@ +TRANS_MANPATH = @TRANS_MANPATH@ +TRANS_MANPATH_UPPER = @TRANS_MANPATH_UPPER@ +TRANS_MAN_UPPER = @TRANS_MAN_UPPER@ +TRANS_WHATIS = @TRANS_WHATIS@ +TRANS_WHATIS_UPPER = @TRANS_WHATIS_UPPER@ +TRANS_ZSOELIM = @TRANS_ZSOELIM@ +TRANS_ZSOELIM_UPPER = @TRANS_ZSOELIM_UPPER@ +TROFF = @TROFF@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ +UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ +UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +USE_NLS = @USE_NLS@ +UTIME_H = @UTIME_H@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ +WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@ +WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@ +WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@ +WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@ +WINT_T_SUFFIX = @WINT_T_SUFFIX@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +browser = @browser@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +bunzip2 = @bunzip2@ +bzip2 = @bzip2@ +cache_top_owner = @cache_top_owner@ +cat = @cat@ +col = @col@ +compress = @compress@ +compress_ext = @compress_ext@ +compressor = @compressor@ +config_file = @config_file@ +config_file_basename = @config_file_basename@ +config_file_dirname = @config_file_dirname@ +datadir = @datadir@ +datarootdir = @datarootdir@ +date = @date@ +docdir = @docdir@ +dvidir = @dvidir@ +eqn = @eqn@ +exec_prefix = @exec_prefix@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grap = @grap@ +grep = @grep@ +gunzip = @gunzip@ +gzip = @gzip@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libpipeline_CFLAGS = @libpipeline_CFLAGS@ +libpipeline_LIBS = @libpipeline_LIBS@ +libseccomp_CFLAGS = @libseccomp_CFLAGS@ +libseccomp_LIBS = @libseccomp_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lzip = @lzip@ +lzma = @lzma@ +man_mode = @man_mode@ +man_owner = @man_owner@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +neqn = @neqn@ +nroff = @nroff@ +oldincludedir = @oldincludedir@ +override_dir = @override_dir@ +pager = @pager@ +pdfdir = @pdfdir@ +pic = @pic@ +preconv = @preconv@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +refer = @refer@ +roff_version = @roff_version@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sections = @sections@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +systemdtmpfilesdir = @systemdtmpfilesdir@ +target_alias = @target_alias@ +tbl = @tbl@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +tr = @tr@ +troff = @troff@ +uncompress = @uncompress@ +unlzip = @unlzip@ +unlzma = @unlzma@ +unxz = @unxz@ +vgrind = @vgrind@ +xz = @xz@ +SUBDIRS = . tests +noinst_DATA = man_db.conf +EXTRA_DIST = lexgrog.c zsoelim.c +AM_CPPFLAGS = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/libdb \ + -DCONFIG_FILE=\"$(config_file)\" \ + -DAPROPOS=\"$(bindir)/$(TRANS_APROPOS)\" \ + -DAPROPOS_NAME=\"$(TRANS_APROPOS)\" \ + -DMAN=\"$(bindir)/$(TRANS_MAN)\" \ + -DMANCONV=\"$(pkglibexecdir)/$(TRANS_MANCONV)\" \ + -DMANDB=\"$(bindir)/$(TRANS_MANDB)\" \ + -DWHATIS=\"$(bindir)/$(TRANS_WHATIS)\" \ + -DZSOELIM=\"$(pkglibexecdir)/$(TRANS_ZSOELIM)\" + +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + $(libpipeline_CFLAGS) + +LIBMAN = $(top_builddir)/lib/libman.la $(top_builddir)/gl/lib/libgnu.la \ + @LTLIBINTL@ + +LIBMANDB = $(top_builddir)/libdb/libmandb.la $(LIBMAN) $(DBLIBS) +accessdb_LDADD = $(LIBMANDB) +catman_LDADD = $(LIBMANDB) $(libpipeline_LIBS) +globbing_LDADD = $(LIBMAN) +lexgrog_LDADD = $(LIBMAN) $(libpipeline_LIBS) $(LTLIBICONV) +man_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +manconv_LDADD = $(LIBMAN) $(libpipeline_LIBS) $(LTLIBICONV) +mandb_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +manpath_LDADD = $(LIBMAN) +whatis_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +zsoelim_LDADD = $(LIBMAN) $(libpipeline_LIBS) +accessdb_SOURCES = \ + accessdb.c + +catman_SOURCES = \ + catman.c \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h + +globbing_SOURCES = \ + globbing.c \ + globbing.h \ + globbing_test.c + +lexgrog_SOURCES = \ + compression.c \ + descriptions.c \ + descriptions.h \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + lexgrog.l \ + lexgrog_test.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + ult_src.c \ + ult_src.h + +man_SOURCES = \ + compression.c \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + man.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + manp.c \ + manp.h \ + ult_src.c \ + ult_src.h \ + zsoelim.h \ + zsoelim.l + +manconv_SOURCES = \ + manconv.c \ + manconv.h \ + manconv_main.c + +mandb_SOURCES = \ + check_mandirs.c \ + check_mandirs.h \ + compression.c \ + descriptions.c \ + descriptions.h \ + descriptions_store.c \ + filenames.c \ + filenames.h \ + globbing.c \ + globbing.h \ + lexgrog.l \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + mandb.c \ + manp.c \ + manp.h \ + straycats.c \ + ult_src.c \ + ult_src.h + +manpath_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + manpath.c + +whatis_SOURCES = \ + globbing.c \ + globbing.h \ + manconv.c \ + manconv.h \ + manp.c \ + manp.h \ + whatis.c + +zsoelim_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + zsoelim.h \ + zsoelim.l \ + zsoelim_main.c + +CLEANFILES = apropos man_db.conf +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .l .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +man_db.conf: $(top_builddir)/config.status $(srcdir)/man_db.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +accessdb$(EXEEXT): $(accessdb_OBJECTS) $(accessdb_DEPENDENCIES) $(EXTRA_accessdb_DEPENDENCIES) + @rm -f accessdb$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(accessdb_OBJECTS) $(accessdb_LDADD) $(LIBS) + +catman$(EXEEXT): $(catman_OBJECTS) $(catman_DEPENDENCIES) $(EXTRA_catman_DEPENDENCIES) + @rm -f catman$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(catman_OBJECTS) $(catman_LDADD) $(LIBS) + +globbing$(EXEEXT): $(globbing_OBJECTS) $(globbing_DEPENDENCIES) $(EXTRA_globbing_DEPENDENCIES) + @rm -f globbing$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(globbing_OBJECTS) $(globbing_LDADD) $(LIBS) + +lexgrog$(EXEEXT): $(lexgrog_OBJECTS) $(lexgrog_DEPENDENCIES) $(EXTRA_lexgrog_DEPENDENCIES) + @rm -f lexgrog$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(lexgrog_OBJECTS) $(lexgrog_LDADD) $(LIBS) + +man$(EXEEXT): $(man_OBJECTS) $(man_DEPENDENCIES) $(EXTRA_man_DEPENDENCIES) + @rm -f man$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(man_OBJECTS) $(man_LDADD) $(LIBS) + +manconv$(EXEEXT): $(manconv_OBJECTS) $(manconv_DEPENDENCIES) $(EXTRA_manconv_DEPENDENCIES) + @rm -f manconv$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(manconv_OBJECTS) $(manconv_LDADD) $(LIBS) + +mandb$(EXEEXT): $(mandb_OBJECTS) $(mandb_DEPENDENCIES) $(EXTRA_mandb_DEPENDENCIES) + @rm -f mandb$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(mandb_OBJECTS) $(mandb_LDADD) $(LIBS) + +manpath$(EXEEXT): $(manpath_OBJECTS) $(manpath_DEPENDENCIES) $(EXTRA_manpath_DEPENDENCIES) + @rm -f manpath$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(manpath_OBJECTS) $(manpath_LDADD) $(LIBS) + +whatis$(EXEEXT): $(whatis_OBJECTS) $(whatis_DEPENDENCIES) $(EXTRA_whatis_DEPENDENCIES) + @rm -f whatis$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(whatis_OBJECTS) $(whatis_LDADD) $(LIBS) + +zsoelim$(EXEEXT): $(zsoelim_OBJECTS) $(zsoelim_DEPENDENCIES) $(EXTRA_zsoelim_DEPENDENCIES) + @rm -f zsoelim$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(zsoelim_OBJECTS) $(zsoelim_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/accessdb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/catman.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_mandirs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compression.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptions.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptions_store.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filenames.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globbing.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globbing_test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexgrog.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexgrog_test.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/man.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manconv.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manconv_client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manconv_main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mandb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manpath.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/straycats.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ult_src.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whatis.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zsoelim.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zsoelim_main.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +.l.c: + $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f lexgrog.c + -rm -f zsoelim.c +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-pkglibexecPROGRAMS clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/accessdb.Po + -rm -f ./$(DEPDIR)/catman.Po + -rm -f ./$(DEPDIR)/check_mandirs.Po + -rm -f ./$(DEPDIR)/compression.Po + -rm -f ./$(DEPDIR)/descriptions.Po + -rm -f ./$(DEPDIR)/descriptions_store.Po + -rm -f ./$(DEPDIR)/filenames.Po + -rm -f ./$(DEPDIR)/globbing.Po + -rm -f ./$(DEPDIR)/globbing_test.Po + -rm -f ./$(DEPDIR)/lexgrog.Po + -rm -f ./$(DEPDIR)/lexgrog_test.Po + -rm -f ./$(DEPDIR)/man.Po + -rm -f ./$(DEPDIR)/manconv.Po + -rm -f ./$(DEPDIR)/manconv_client.Po + -rm -f ./$(DEPDIR)/manconv_main.Po + -rm -f ./$(DEPDIR)/mandb.Po + -rm -f ./$(DEPDIR)/manp.Po + -rm -f ./$(DEPDIR)/manpath.Po + -rm -f ./$(DEPDIR)/straycats.Po + -rm -f ./$(DEPDIR)/ult_src.Po + -rm -f ./$(DEPDIR)/whatis.Po + -rm -f ./$(DEPDIR)/zsoelim.Po + -rm -f ./$(DEPDIR)/zsoelim_main.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-pkglibexecPROGRAMS \ + install-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/accessdb.Po + -rm -f ./$(DEPDIR)/catman.Po + -rm -f ./$(DEPDIR)/check_mandirs.Po + -rm -f ./$(DEPDIR)/compression.Po + -rm -f ./$(DEPDIR)/descriptions.Po + -rm -f ./$(DEPDIR)/descriptions_store.Po + -rm -f ./$(DEPDIR)/filenames.Po + -rm -f ./$(DEPDIR)/globbing.Po + -rm -f ./$(DEPDIR)/globbing_test.Po + -rm -f ./$(DEPDIR)/lexgrog.Po + -rm -f ./$(DEPDIR)/lexgrog_test.Po + -rm -f ./$(DEPDIR)/man.Po + -rm -f ./$(DEPDIR)/manconv.Po + -rm -f ./$(DEPDIR)/manconv_client.Po + -rm -f ./$(DEPDIR)/manconv_main.Po + -rm -f ./$(DEPDIR)/mandb.Po + -rm -f ./$(DEPDIR)/manp.Po + -rm -f ./$(DEPDIR)/manpath.Po + -rm -f ./$(DEPDIR)/straycats.Po + -rm -f ./$(DEPDIR)/ult_src.Po + -rm -f ./$(DEPDIR)/whatis.Po + -rm -f ./$(DEPDIR)/zsoelim.Po + -rm -f ./$(DEPDIR)/zsoelim_main.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-pkglibexecPROGRAMS \ + uninstall-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +.MAKE: $(am__recursive_targets) install-am install-data-am \ + install-exec-am install-strip uninstall-am + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-pkglibexecPROGRAMS \ + clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-data-hook install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibexecPROGRAMS \ + install-ps install-ps-am install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-hook \ + uninstall-pkglibexecPROGRAMS uninstall-sbinPROGRAMS + +.PRECIOUS: Makefile + + +apropos$(EXEEXT): whatis$(EXEEXT) + rm -f $@ + $(LN_S) whatis$(EXEEXT) $@ + +all-am: apropos$(EXEEXT) + +install-exec-hook: + if [ "$(man_owner)" ] && [ "$(man_mode)" = 6755 ]; then \ + chown $(man_owner):$(man_owner) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB); \ + fi + chmod $(man_mode) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB) + cd $(DESTDIR)$(bindir) && rm -f $(TRANS_APROPOS)$(EXEEXT) && \ + $(LN_S) $(TRANS_WHATIS)$(EXEEXT) $(TRANS_APROPOS)$(EXEEXT) + +install-data-hook: + @if test -f $(DESTDIR)$(config_file); then \ + echo "$(DESTDIR)$(config_file) already exists; overwrite manually if necessary"; \ + else \ + test -z "$(config_file_dirname)" || $(MKDIR_P) "$(DESTDIR)$(config_file_dirname)"; \ + echo " $(INSTALL_DATA) man_db.conf $(DESTDIR)$(config_file)"; \ + $(INSTALL_DATA) man_db.conf $(DESTDIR)$(config_file); \ + fi + +uninstall-hook: + rm -f $(DESTDIR)$(bindir)/$(TRANS_APROPOS)$(EXEEXT) + @echo "Please remove $(DESTDIR)$(config_file) manually if necessary" + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/accessdb.c b/src/accessdb.c new file mode 100644 index 0000000..21f18cb --- /dev/null +++ b/src/accessdb.c @@ -0,0 +1,166 @@ +/* + * accessdb.c: show every key/content pair in the database. + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Tue Apr 26 12:56:44 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "argp.h" +#include "progname.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "error.h" +#include "sandbox.h" + +#include "mydbm.h" + +const char *cat_root; +man_sandbox *sandbox; /* unused, but needed by libman */ + +/* for db_storage.c */ +char *database; + +const char *argp_program_version = "accessdb " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("[MAN DATABASE]"); +static const char doc[] = "\v" N_("The man database defaults to %s%s."); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP & + ~ARGP_HELP_PRE_DOC); + break; + case ARGP_KEY_ARG: + if (database) + argp_usage (state); + database = arg; + return 0; + case ARGP_KEY_NO_ARGS: + database = mkdbname (cat_root); + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, + void *input ATTRIBUTE_UNUSED) +{ + switch (key) { + case ARGP_KEY_HELP_PRE_DOC: + /* We have no pre-options help text, but the input + * text may contain header junk due to gettext (""). + */ + return NULL; + case ARGP_KEY_HELP_POST_DOC: + return xasprintf (text, cat_root, MAN_DB); + default: + return (char *) text; + } +} + +static struct argp argp = { options, parse_opt, args_doc, doc, 0, + help_filter }; + +int main (int argc, char *argv[]) +{ + MYDBM_FILE dbf; + datum key; + int ret = OK; + + set_program_name (argv[0]); + + init_debug (); + init_locale (); + + if (is_directory (FHS_CAT_ROOT) == 1) + cat_root = FHS_CAT_ROOT; + else if (is_directory (CAT_ROOT) == 1) + cat_root = CAT_ROOT; + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + dbf = MYDBM_RDOPEN (database); + if (dbf && dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + } + if (!dbf) + error (FATAL, errno, _("can't open %s for reading"), database); + + key = MYDBM_FIRSTKEY (dbf); + + while (MYDBM_DPTR (key) != NULL) { + datum content, nextkey; + char *t, *nicekey; + + content = MYDBM_FETCH (dbf, key); + if (!MYDBM_DPTR (content)) { + debug ("key %s has no content!\n", MYDBM_DPTR (key)); + ret = FATAL; + goto next; + } + nicekey = xstrdup (MYDBM_DPTR (key)); + while ( (t = strchr (nicekey, '\t')) ) + *t = '~'; + while ( (t = strchr (MYDBM_DPTR (content), '\t')) ) + *t = ' '; + printf ("%s -> \"%s\"\n", nicekey, MYDBM_DPTR (content)); + free (nicekey); + MYDBM_FREE_DPTR (content); +next: + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + MYDBM_CLOSE (dbf); + exit (ret); +} diff --git a/src/catman.c b/src/catman.c new file mode 100644 index 0000000..489b33c --- /dev/null +++ b/src/catman.c @@ -0,0 +1,434 @@ +/* + * catman.c: create and/or update cat files + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2010, 2011 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Thu Dec 8 00:03:12 GMT 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +/* MAX_ARGS must be >= 7, 5 for options, 1 for page and 1 for NULL */ +#define MAX_ARGS 1024 + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <assert.h> +#include <sys/types.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> + +#ifndef NAME_MAX +# if defined(_POSIX_VERSION) && defined(_POSIX_NAME_MAX) +# define NAME_MAX _POSIX_NAME_MAX +# else /* !_POSIX_VERSION */ +# ifdef MAXNAMLEN +# define NAME_MAX MAXNAMLEN +# else /* !MAXNAMLEN */ +# define NAME_MAX 255 /* default to max */ +# endif /* MAXNAMLEN */ +# endif /* _POSIX_VERSION */ +#endif /* !NAME_MAX */ + +#ifndef ARG_MAX +# if defined(_POSIX_VERSION) && defined(_POSIX_ARG_MAX) +# define ARG_MAX _POSIX_ARG_MAX +# else /* !_POSIX_VERSION */ +# define ARG_MAX 4096 /* default to min */ +# endif /* _POSIX_VERSION */ +#endif /* !ARG_MAX */ + +#include "argp.h" +#include "progname.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "error.h" +#include "pipeline.h" +#include "sandbox.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "manp.h" + +/* globals */ +int quiet = 1; +MYDBM_FILE dbf_close_post_fork; +char *manp; +extern char *user_config_file; +char *database; +man_sandbox *sandbox; /* unused, but needed by libman */ + +static const char **sections; + +const char *argp_program_version = "catman " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("[SECTION...]"); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "manpath", 'M', N_("PATH"), 0, N_("set search path for manual pages to PATH") }, + { "config-file", 'C', N_("FILE"), 0, N_("use this user configuration file") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + char *mansect; + + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'M': + manp = arg; + return 0; + case 'C': + user_config_file = arg; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_ARGS: + sections = xmalloc ((state->argc - state->next + 1) * + sizeof *sections); + memcpy (sections, state->argv + state->next, + (state->argc - state->next) * + sizeof *sections); + sections[state->argc - state->next] = NULL; + return 0; + case ARGP_KEY_NO_ARGS: + mansect = getenv ("MANSECT"); + if (mansect && *mansect) { + /* MANSECT contains sections */ + const char *sec; + int i = 0; + + mansect = xstrdup (mansect); + sections = NULL; + for (sec = strtok (mansect, ":"); sec; + sec = strtok (NULL, ":")) { + sections = xnrealloc + (sections, i + 2, + sizeof *sections); + sections[i++] = sec; + } + if (sections) + sections[i] = NULL; + free (mansect); + } else { + /* use default sections */ + static const char *std_sections[] = + STD_SECTIONS; + sections = std_sections; + } + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +static char *locale; + +static char *manpathlist[MAXDIRS]; + +static void post_fork (void) +{ + pop_all_cleanups (); + if (dbf_close_post_fork) + MYDBM_CLOSE (dbf_close_post_fork); +} + +/* Execute man with the appropriate catman args. Always frees cmd. */ +static void catman (pipecmd *cmd) +{ + pipeline *p; + int status; + + if (debug_level) { + /* just show the command, but don't execute it */ + fputs ("man command = ", stderr); + pipecmd_dump (cmd, stderr); + putc ('\n', stderr); + pipecmd_free (cmd); + return; + } + + p = pipeline_new_commands (cmd, (void *) 0); + status = pipeline_run (p); + if (status) + error (CHILD_FAIL, 0, + _("man command failed with exit status %d"), status); +} + +/* Add key to this command, stripping off tab-and-following if necessary. + * Return length of argument. + */ +static size_t add_arg (pipecmd *cmd, datum key) +{ + char *tab; + size_t len; + + tab = strrchr (MYDBM_DPTR (key), '\t'); + if (tab == MYDBM_DPTR (key)) + tab = NULL; + + if (tab) + *tab = '\0'; + pipecmd_arg (cmd, MYDBM_DPTR (key)); + len = strlen (MYDBM_DPTR (key)); + debug ("key: '%s' (%zu), len: %zd\n", + MYDBM_DPTR (key), (size_t) MYDBM_DSIZE (key), len); + if (tab) + *tab = '\t'; + + return len; +} + +/* find all pages that are in the supplied manpath and section and that are + ultimate source files. */ +static int parse_for_sec (const char *manpath, const char *section) +{ + MYDBM_FILE dbf; + pipecmd *basecmd, *cmd; + datum key; + size_t arg_size, initial_bit; + int message = 1, first_arg; + + dbf = MYDBM_RDOPEN (database); + if (!dbf) { + error (0, errno, _("cannot read database %s"), database); + return 1; + } + if (dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + return 1; + } + dbf_close_post_fork = dbf; + + basecmd = pipecmd_new (MAN); + pipecmd_clearenv (basecmd); + + /* As we supply a NULL environment to save precious execve() space, + we must also supply a locale if necessary */ + if (locale) { + pipecmd_args (basecmd, "-L", locale, (void *) 0); + initial_bit = sizeof "-L" + strlen (locale) + 1; + } else + initial_bit = 0; + + pipecmd_args (basecmd, "-caM", manpath, (void *) 0); /* manpath */ + pipecmd_args (basecmd, "-S", section, (void *) 0); /* section */ + + initial_bit += sizeof MAN + sizeof "-caM" + + strlen (manpath) + strlen (section) + 2; + + cmd = pipecmd_dup (basecmd); + first_arg = pipecmd_get_nargs (cmd); + + arg_size = initial_bit; + key = MYDBM_FIRSTKEY (dbf); + + while (MYDBM_DPTR (key) != NULL) { + datum nextkey; + + /* ignore db identifier keys */ + if (*MYDBM_DPTR (key) != '$') { + datum content; + + content = MYDBM_FETCH (dbf, key); + + if (!MYDBM_DPTR (content)) + error (FATAL, 0, + _( "NULL content for key: %s"), + MYDBM_DPTR (key)); + + /* ignore overflow entries */ + if (*MYDBM_DPTR (content) != '\t') { + struct mandata entry; + + split_content (MYDBM_DPTR (content), &entry); + + /* Accept if the entry is an ultimate manual + page and the section matches the one we're + currently dealing with */ + if (entry.id == ULT_MAN && + strcmp (entry.sec, section) == 0) { + if (message) { + printf (_("\nUpdating cat files for section %s of man hierarchy %s\n"), + section, manpath); + message = 0; + } + + arg_size += add_arg (cmd, key) + 1; + + debug ("arg space free: %zd bytes\n", + ARG_MAX - arg_size); + + /* Check to see if we have enough room + to add another max sized filename + and that we haven't run out of array + space too */ + if (arg_size >= ARG_MAX - NAME_MAX || + pipecmd_get_nargs (cmd) == + MAX_ARGS) { + catman (cmd); + + cmd = pipecmd_dup (basecmd); + arg_size = initial_bit; + } + } + + /* == MYDBM_DPTR (content), freed below */ + entry.addr = NULL; + free_mandata_elements (&entry); + } + + /* we don't need the content ever again */ + assert (MYDBM_DPTR (content)); /* just to be sure */ + MYDBM_FREE_DPTR (content); + } + + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + dbf_close_post_fork = NULL; + MYDBM_CLOSE (dbf); + if (pipecmd_get_nargs (cmd) > first_arg) + catman (cmd); + else + pipecmd_free (cmd); + + pipecmd_free (basecmd); + + return 0; +} + +static int check_access (const char *directory) +{ + if (!CAN_ACCESS (directory, W_OK)) { + error (0, errno, _("cannot write within %s"), directory); + return 1; + } + + return 0; +} + +int main (int argc, char *argv[]) +{ + char *sys_manp; + char **mp; + const char **sp; + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (post_fork); + + init_locale (); + locale = setlocale (LC_MESSAGES, NULL); + if (locale) + locale = xstrdup (locale); + else + locale = xstrdup ("C"); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + for (sp = sections; *sp; sp++) + debug ("sections: %s\n", *sp); + + /* Deal with the MANPATH */ + + /* This is required for get_catpath(), regardless */ + sys_manp = get_manpath (NULL); + + /* pick up the system manpath or use the supplied one */ + if (!manp) { + manp = get_mandb_manpath (); + if (!manp) + manp = sys_manp; + } + + debug ("manpath=%s\n", manp); + + /* get the manpath as an array of pointers */ + create_pathlist (manp, manpathlist); + + for (mp = manpathlist; *mp; mp++) { + char *catpath; + size_t len; + + catpath = get_catpath (*mp, SYSTEM_CAT | USER_CAT); + + if (catpath) { + if (is_directory (catpath) != 1) { + free (catpath); + continue; + } + database = mkdbname (catpath); + } else { + if (is_directory (*mp) != 1) + continue; + database = mkdbname (*mp); + catpath = xstrdup (*mp); + } + + len = strlen (catpath); + + for (sp = sections; *sp; sp++) { + *(catpath + len) = '\0'; + catpath = appendstr (catpath, "/cat", *sp, (void *) 0); + if (is_directory (catpath) != 1) + continue; + if (check_access (catpath)) + continue; + if (parse_for_sec (*mp, *sp)) { + error (0, 0, _("unable to update %s"), *mp); + break; + } + } + + free (catpath); + } + + free_pathlist (manpathlist); + free (locale); + exit (OK); +} diff --git a/src/check_mandirs.c b/src/check_mandirs.c new file mode 100644 index 0000000..c8c33dc --- /dev/null +++ b/src/check_mandirs.c @@ -0,0 +1,1071 @@ +/* + * check_mandirs.c: used to auto-update the database caches + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2007, 2008, 2009, 2010, 2011 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Mon May 2 17:36:33 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * CJW: Many changes to whatis parsing. Added database purging. + * See ChangeLog for details. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <errno.h> +#include <ctype.h> +#include <dirent.h> +#include <unistd.h> + +#include "dirname.h" +#include "stat-time.h" +#include "timespec.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "hashtable.h" +#include "orderfiles.h" +#include "security.h" +#include "xchown.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "descriptions.h" +#include "filenames.h" +#include "globbing.h" +#include "manp.h" +#include "ult_src.h" +#include "check_mandirs.h" + +int opt_test; /* don't update db */ +int pages; +int force_rescan = 0; + +static struct hashtable *whatis_hash = NULL; + +struct whatis_hashent { + char *whatis; + struct ult_trace trace; +}; + +static void whatis_hashtable_free (void *defn) +{ + struct whatis_hashent *hashent = defn; + + free (hashent->whatis); + free_ult_trace (&hashent->trace); + free (hashent); +} + +static void gripe_multi_extensions (const char *path, const char *sec, + const char *name, const char *ext) +{ + if (quiet < 2) + error (0, 0, + _("warning: %s/man%s/%s.%s*: competing extensions"), + path, sec, name, ext); +} + +static void gripe_rwopen_failed (void) +{ + if (errno == EACCES || errno == EROFS) + debug ("database %s is read-only\n", database); + else if (errno == EAGAIN || errno == EWOULDBLOCK) + debug ("database %s is locked by another process\n", database); + else { +#ifdef MAN_DB_UPDATES + if (!quiet) +#endif /* MAN_DB_UPDATES */ + error (0, errno, _("can't update index cache %s"), + database); + } +} + +/* Take absolute filename and path (for ult_src) and do sanity checks on + * file. Also check that file is non-zero in length and is not already in + * the db. If not, find its ult_src() and see if we have the whatis cached, + * otherwise cache it in case we trace another manpage back to it. Next, + * store it in the db along with any references found in the whatis. + */ +void test_manfile (MYDBM_FILE dbf, const char *file, const char *path) +{ + char *manpage_base; + const char *ult; + struct lexgrog lg; + char *manpage; + struct mandata info, *exists; + struct stat buf; + size_t len; + struct ult_trace ult_trace; + struct whatis_hashent *whatis; + + memset (&lg, 0, sizeof (struct lexgrog)); + memset (&info, 0, sizeof (struct mandata)); + memset (&ult_trace, 0, sizeof (struct ult_trace)); + + manpage = filename_info (file, &info, NULL); + if (!manpage) + return; + manpage_base = manpage + strlen (manpage) + 1; + + len = strlen (manpage) + 1; /* skip over directory name */ + len += strlen (manpage + len) + 1; /* skip over base name */ + len += strlen (manpage + len); /* skip over section ext */ + + /* to get mtime info */ + (void) lstat (file, &buf); + info.mtime = get_stat_mtime (&buf); + + /* check that our file actually contains some data */ + if (buf.st_size == 0) { + /* man-db pre 2.3 place holder ? */ + free (manpage); + return; + } + + /* See if we already have it, before going any further. This will + * save both an ult_src() and a find_name(), amongst other wastes of + * time. + */ + exists = dblookup_exact (dbf, manpage_base, info.ext, 1); + + /* Ensure we really have the actual page. Gzip keeps the mtime the + * same when it compresses, so we have to compare compression + * extensions as well. + */ + if (exists) { + if (strcmp (exists->comp, info.comp ? info.comp : "-") == 0) { + if (timespec_cmp (exists->mtime, info.mtime) == 0 && + exists->id < WHATIS_MAN) { + free_mandata_struct (exists); + free (manpage); + return; + } + } else { + char *abs_filename; + + /* see if the cached file actually exists. It's + evident at this point that we have multiple + comp extensions */ + abs_filename = make_filename (path, NULL, + exists, "man"); + if (!abs_filename) { + if (!opt_test) + dbdelete (dbf, manpage_base, exists); + } else { + gripe_multi_extensions (path, exists->sec, + manpage_base, + exists->ext); + free (abs_filename); + free_mandata_struct (exists); + free (manpage); + return; + } + } + free_mandata_struct (exists); + } + + /* Check if it happens to be a symlink/hardlink to something already + * in our cache. This just does some extra checks to avoid scanning + * links quite so many times. + */ + { + /* Avoid too much noise in debug output */ + int save_debug = debug_level; + debug_level = 0; + ult = ult_src (file, path, &buf, SOFT_LINK | HARD_LINK, NULL); + debug_level = save_debug; + } + + if (!ult) { + /* already warned about this, don't do so again */ + debug ("test_manfile(): bad link %s\n", file); + free (manpage); + return; + } + + if (!whatis_hash) + whatis_hash = hashtable_create (&whatis_hashtable_free); + + whatis = hashtable_lookup (whatis_hash, ult, strlen (ult)); + if (!whatis) { + if (!STRNEQ (ult, file, len)) + debug ("\ntest_manfile(): link not in cache:\n" + " source = %s\n" + " target = %s\n", file, ult); + /* Trace the file to its ultimate source, otherwise we'll be + * looking for whatis info in files containing only '.so + * manx/foo.x', which will give us an unobtainable whatis + * for the entry. */ + ult = ult_src (file, path, &buf, + SO_LINK | SOFT_LINK | HARD_LINK, &ult_trace); + } + + if (!ult) { + if (quiet < 2) + error (0, 0, + _("warning: %s: bad symlink or ROFF `.so' request"), + file); + free (manpage); + return; + } + + pages++; /* pages seen so far */ + + if (strncmp (ult, file, len) == 0) + info.id = ULT_MAN; /* ultimate source file */ + else + info.id = SO_MAN; /* .so, sym or hard linked file */ + + /* Ok, here goes: Use a hash tree to store the ult_srcs with + * their whatis. Anytime after, check the hash tree, if it's there, + * use it. This saves us a find_name() which is a real hog. + * + * Use the full path in ult as the hash key so we don't have to + * clear the hash between calls. + */ + + if (whatis) + lg.whatis = whatis->whatis ? xstrdup (whatis->whatis) : NULL; + else { + /* Cache miss; go and get the whatis info in its raw state. */ + char *file_base = base_name (file); + + lg.type = MANPAGE; + drop_effective_privs (); + find_name (ult, file_base, &lg, NULL); + free (file_base); + regain_effective_privs (); + + whatis = XMALLOC (struct whatis_hashent); + whatis->whatis = lg.whatis ? xstrdup (lg.whatis) : NULL; + /* We filled out ult_trace above. */ + memcpy (&whatis->trace, &ult_trace, sizeof (ult_trace)); + hashtable_install (whatis_hash, ult, strlen (ult), whatis); + } + + debug ("\"%s\"\n", lg.whatis); + + /* split up the raw whatis data and store references */ + info.pointer = NULL; /* direct page, so far */ + info.filter = lg.filters; + if (lg.whatis) { + struct page_description *descs = + parse_descriptions (manpage_base, lg.whatis); + if (descs) { + if (!opt_test) + store_descriptions (dbf, descs, &info, + path, manpage_base, + &whatis->trace); + free_descriptions (descs); + } + } else if (quiet < 2) { + (void) stat (ult, &buf); + if (buf.st_size == 0) + error (0, 0, _("warning: %s: ignoring empty file"), + ult); + else + error (0, 0, + _("warning: %s: whatis parse for %s(%s) failed"), + ult, manpage_base, info.ext); + } + + free (manpage); + free (lg.whatis); +} + +static void add_dir_entries (MYDBM_FILE dbf, const char *path, char *infile) +{ + char *manpage; + int len; + struct dirent *newdir; + DIR *dir; + char **names; + size_t names_len, names_max, i; + + manpage = xasprintf ("%s/%s/", path, infile); + len = strlen (manpage); + + /* + * All filename entries in this dir should either be valid manpages + * or . files (such as current, parent dir). + */ + + dir = opendir (infile); + if (!dir) { + error (0, errno, _("can't search directory %s"), manpage); + free (manpage); + return; + } + + names_len = 0; + names_max = 1024; + names = XNMALLOC (names_max, char *); + + /* strlen(newdir->d_name) could be replaced by newdir->d_reclen */ + + while ((newdir = readdir (dir)) != NULL) { + if (*newdir->d_name == '.' && + strlen (newdir->d_name) < (size_t) 3) + continue; + if (names_len >= names_max) { + names_max *= 2; + names = xnrealloc (names, names_max, sizeof (char *)); + } + names[names_len++] = xstrdup (newdir->d_name); + } + closedir (dir); + + order_files (infile, names, names_len); + + for (i = 0; i < names_len; ++i) { + manpage = appendstr (manpage, names[i], (void *) 0); + test_manfile (dbf, manpage, path); + *(manpage + len) = '\0'; + free (names[i]); + } + + free (names); + free (manpage); +} + +#ifdef MAN_OWNER +extern uid_t uid; /* current effective user id */ +extern gid_t gid; /* current effective group id */ + +/* Fix a path's ownership if possible and necessary. */ +void chown_if_possible (const char *path) +{ + struct stat st; + struct passwd *man_owner = get_man_owner (); + + if (lstat (path, &st) != 0) + return; + + if ((uid == 0 || + (uid == man_owner->pw_uid && st.st_uid == man_owner->pw_uid && + gid == man_owner->pw_gid)) && + (st.st_uid != man_owner->pw_uid || + st.st_gid != man_owner->pw_gid)) { + debug ("fixing ownership of %s\n", path); +#ifdef HAVE_LCHOWN + xlchown (path, man_owner->pw_uid, man_owner->pw_gid); +#else + xchown (path, man_owner->pw_uid, man_owner->pw_gid); +#endif + } +} +#else /* !MAN_OWNER */ +void chown_if_possible (const char *path ATTRIBUTE_UNUSED) +{ +} +#endif /* MAN_OWNER */ + +/* create the catman hierarchy if it doesn't exist */ +static void mkcatdirs (const char *mandir, const char *catdir) +{ + char *manname, *catname; + + if (catdir) { + int oldmask = umask (022); + /* first the base catdir */ + if (is_directory (catdir) != 1) { + regain_effective_privs (); + if (mkdir (catdir, 0755) < 0) { + if (!quiet) + error (0, 0, + _("warning: cannot create catdir %s"), + catdir); + debug ("warning: cannot create catdir %s\n", + catdir); + } else + debug ("created base catdir %s\n", catdir); + chown_if_possible (catdir); + drop_effective_privs (); + } + /* then the hierarchy */ + catname = xasprintf ("%s/cat1", catdir); + manname = xasprintf ("%s/man1", mandir); + if (is_directory (catdir) == 1) { + int j; + regain_effective_privs (); + debug ("creating catdir hierarchy %s ", catdir); + for (j = 1; j <= 9; j++) { + catname[strlen (catname) - 1] = '0' + j; + manname[strlen (manname) - 1] = '0' + j; + if ((is_directory (manname) == 1) + && (is_directory (catname) != 1)) { + if (mkdir (catname, 0755) < 0) { + if (!quiet) + error (0, 0, _("warning: cannot create catdir %s"), catname); + debug ("warning: cannot create catdir %s\n", catname); + } else + debug (" cat%d", j); + chown_if_possible (catname); + } + } + debug ("\n"); + drop_effective_privs (); + } + free (catname); + free (manname); + umask (oldmask); + } +} + +/* We used to install cat directories with the setgid bit set, but this + * wasn't very useful and introduces the ability to escalate privileges to + * that group: + * https://www.halfdog.net/Security/2015/SetgidDirectoryPrivilegeEscalation/ + */ +static void fix_permissions (const char *dir) +{ + struct stat st; + + if (stat (dir, &st) == 0) { + if ((st.st_mode & S_ISGID) != 0) { + int status; + + debug ("removing setgid bit from %s\n", dir); + status = chmod (dir, st.st_mode & ~S_ISGID); + if (status) + error (0, errno, _("can't chmod %s"), dir); + } + + chown_if_possible (dir); + } +} + +static void fix_permissions_tree (const char *catdir) +{ + if (is_directory (catdir) == 1) { + char *catname; + int i; + + fix_permissions (catdir); + catname = xasprintf ("%s/cat1", catdir); + for (i = 1; i <= 9; ++i) { + catname[strlen (catname) - 1] = '0' + i; + fix_permissions (catname); + } + free (catname); + } +} + +/* + * accepts the raw man dir tree eg. "/usr/man" and the time stored in the db + * any dirs of the tree that have been modified (ie added to) will then be + * scanned for new files, which are then added to the db. + */ +static int testmandirs (const char *path, const char *catpath, + struct timespec last, int create) +{ + DIR *dir; + struct dirent *mandir; + int amount = 0; + int created = 0; + + debug ("Testing %s for new files\n", path); + + if (catpath) + fix_permissions_tree (catpath); + + dir = opendir (path); + if (!dir) { + error (0, errno, _("can't search directory %s"), path); + return 0; + } + + if (chdir (path) != 0) { + error (0, errno, _("can't change to directory %s"), path); + closedir (dir); + return 0; + } + + while( (mandir = readdir (dir)) ) { + struct stat stbuf; + struct timespec mtime; + MYDBM_FILE dbf; + + if (strncmp (mandir->d_name, "man", 3) != 0) + continue; + + debug ("Examining %s\n", mandir->d_name); + + if (stat (mandir->d_name, &stbuf) != 0) /* stat failed */ + continue; + if (!S_ISDIR(stbuf.st_mode)) /* not a directory */ + continue; + mtime = get_stat_mtime (&stbuf); + if (last.tv_sec && timespec_cmp (mtime, last) <= 0) { + /* scanned already */ + debug ("%s modified %ld.%09ld, " + "db modified %ld.%09ld\n", + mandir->d_name, + (long) mtime.tv_sec, (long) mtime.tv_nsec, + (long) last.tv_sec, (long) last.tv_nsec); + continue; + } + + debug ("\tsubdirectory %s has been 'modified'\n", + mandir->d_name); + + if (create && !created) { + /* We seem to have something to do, so create the + * database now. + */ + mkcatdirs (path, catpath); + + /* Open the db in CTRW mode to store the $ver$ ID */ + + dbf = MYDBM_CTRWOPEN (database); + if (dbf == NULL) { + if (errno == EACCES || errno == EROFS) { + debug ("database %s is read-only\n", + database); + closedir (dir); + return 0; + } else { + error (0, errno, + _("can't create index cache %s"), + database); + closedir (dir); + return -errno; + } + } + + dbver_wr (dbf); + + created = 1; + } else + dbf = MYDBM_RWOPEN(database); + + if (!dbf) { + gripe_rwopen_failed (); + closedir (dir); + return 0; + } + + if (!quiet) { + int tty = isatty (STDERR_FILENO); + + if (tty) + fprintf (stderr, "\r"); + fprintf (stderr, + _("Updating index cache for path " + "`%s/%s'. Wait..."), path, mandir->d_name); + if (!tty) + fprintf (stderr, "\n"); + } + add_dir_entries (dbf, path, mandir->d_name); + MYDBM_CLOSE (dbf); + amount++; + } + closedir (dir); + + return amount; +} + +/* update the modification timestamp of `database' */ +static void update_db_time (void) +{ + MYDBM_FILE dbf; + struct timespec now; + + /* Open the db in RW to update its mtime */ + /* we know that this should succeed because we just updated the db! */ + dbf = MYDBM_RWOPEN (database); + if (dbf == NULL) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + /* Another mandb process is probably running. With + * any luck it will update the mtime ... + */ + debug ("database %s is locked by another process\n", + database); + else { +#ifdef MAN_DB_UPDATES + if (!quiet) +#endif /* MAN_DB_UPDATES */ + error (0, errno, + _("can't update index cache %s"), + database); + } + return; + } + now.tv_sec = 0; + now.tv_nsec = UTIME_NOW; + MYDBM_SET_TIME (dbf, now); + + MYDBM_CLOSE (dbf); +} + +/* routine to prepare/create the db prior to calling testmandirs() */ +int create_db (const char *manpath, const char *catpath) +{ + struct timespec time_zero; + int amount; + + debug ("create_db(%s): %s\n", manpath, database); + + time_zero.tv_sec = 0; + time_zero.tv_nsec = 0; + amount = testmandirs (manpath, catpath, time_zero, 1); + + if (amount) { + update_db_time (); + if (!quiet) + fputs (_("done.\n"), stderr); + } + + return amount; +} + +/* Make sure an existing database is essentially sane. */ +static int sanity_check_db (MYDBM_FILE dbf) +{ + datum key; + + if (dbver_rd (dbf)) + return 0; + + key = MYDBM_FIRSTKEY (dbf); + while (MYDBM_DPTR (key) != NULL) { + datum content, nextkey; + + content = MYDBM_FETCH (dbf, key); + if (!MYDBM_DPTR (content)) { + debug ("warning: %s has a key with no content (%s); " + "rebuilding\n", database, MYDBM_DPTR (key)); + MYDBM_FREE_DPTR (key); + return 0; + } + MYDBM_FREE_DPTR (content); + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + return 1; +} + +/* routine to update the db, ensure that it is consistent with the + filesystem */ +int update_db (const char *manpath, const char *catpath) +{ + MYDBM_FILE dbf; + struct timespec mtime; + int new; + + dbf = MYDBM_RDOPEN (database); + if (dbf && !sanity_check_db (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + } + if (!dbf) { + debug ("failed to open %s O_RDONLY\n", database); + return EOF; + } + mtime = MYDBM_GET_TIME (dbf); + MYDBM_CLOSE (dbf); + + debug ("update_db(): %ld.%09ld\n", + (long) mtime.tv_sec, (long) mtime.tv_nsec); + new = testmandirs (manpath, catpath, mtime, 0); + + if (new) { + update_db_time (); + if (!quiet) + fputs (_("done.\n"), stderr); + } + + return new; +} + +/* Purge any entries pointing to name. This currently assumes that pointers + * are always shallow, which may not be a good assumption yet; it should be + * close, though. + */ +void purge_pointers (MYDBM_FILE dbf, const char *name) +{ + datum key = MYDBM_FIRSTKEY (dbf); + + debug ("Purging pointers to vanished page \"%s\"\n", name); + + while (MYDBM_DPTR (key) != NULL) { + datum content, nextkey; + struct mandata entry; + char *nicekey, *tab; + + /* Ignore db identifier keys. */ + if (*MYDBM_DPTR (key) == '$') + goto pointers_next; + + content = MYDBM_FETCH (dbf, key); + if (!MYDBM_DPTR (content)) + return; + + /* Get just the name. */ + nicekey = xstrdup (MYDBM_DPTR (key)); + tab = strchr (nicekey, '\t'); + if (tab) + *tab = '\0'; + + if (*MYDBM_DPTR (content) == '\t') + goto pointers_contentnext; + + split_content (MYDBM_DPTR (content), &entry); + if (entry.id != SO_MAN && entry.id != WHATIS_MAN) + goto pointers_contentnext; + + if (STREQ (entry.pointer, name)) { + if (!opt_test) + dbdelete (dbf, nicekey, &entry); + else + debug ("%s(%s): pointer vanished, " + "would delete\n", nicekey, entry.ext); + } + +pointers_contentnext: + free (nicekey); + MYDBM_FREE_DPTR (content); +pointers_next: + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } +} + +/* Count the number of exact extension matches returned from look_for_file() + * (which may return inexact extension matches in some cases). It may turn + * out that this is better handled in look_for_file() itself. + */ +static int count_glob_matches (const char *name, const char *ext, + char **source, struct timespec db_mtime) +{ + char **walk; + int count = 0; + + for (walk = source; walk && *walk; ++walk) { + struct mandata info; + struct stat statbuf; + char *buf; + + memset (&info, 0, sizeof (struct mandata)); + + if (stat (*walk, &statbuf) == -1) { + debug ("count_glob_matches: excluding %s " + "because stat failed\n", *walk); + continue; + } + if (db_mtime.tv_sec != (time_t) -1 && + timespec_cmp (get_stat_mtime (&statbuf), db_mtime) <= 0) { + debug ("count_glob_matches: excluding %s, " + "no newer than database\n", *walk); + continue; + } + + buf = filename_info (*walk, &info, name); + if (buf) { + if (STREQ (ext, info.ext)) + ++count; + free (info.name); + free (buf); + } + } + + return count; +} + +/* Decide whether to purge a reference to a "normal" (ULT_MAN or SO_MAN) + * page. + */ +static int purge_normal (MYDBM_FILE dbf, const char *name, + struct mandata *info, char **found) +{ + struct timespec t; + + /* TODO: On some systems, the cat page extension differs from the + * man page extension, so this may be too strict. + */ + t.tv_sec = -1; + t.tv_nsec = -1; + if (count_glob_matches (name, info->ext, found, t)) + return 0; + + if (!opt_test) + dbdelete (dbf, name, info); + else + debug ("%s(%s): missing page, would delete\n", + name, info->ext); + + return 1; +} + +/* Decide whether to purge a reference to a WHATIS_MAN or WHATIS_CAT page. */ +static int purge_whatis (MYDBM_FILE dbf, const char *path, int cat, + const char *name, struct mandata *info, char **found, + struct timespec db_mtime) +{ + /* TODO: On some systems, the cat page extension differs from the + * man page extension, so this may be too strict. + */ + if (count_glob_matches (name, info->ext, found, db_mtime)) { + /* If the page exists and didn't beforehand, then presumably + * we're about to rescan, which will replace the WHATIS_MAN + * entry with something better. However, there have been + * bugs that created false WHATIS_MAN entries, so force the + * rescan just to be sure; since in the absence of a bug we + * would rescan anyway, this isn't a problem. + */ + if (!force_rescan) + debug ("%s(%s): whatis replaced by real page; " + "forcing a rescan just in case\n", + name, info->ext); + force_rescan = 1; + return 0; + } else if (STREQ (info->pointer, "-")) { + /* This is broken; a WHATIS_MAN should never have an empty + * pointer field. This might have happened due to the first + * name in a page being different from what the file name + * says; that's fixed now, so delete and force a rescan. + */ + if (!opt_test) + dbdelete (dbf, name, info); + else + debug ("%s(%s): whatis with empty pointer, " + "would delete\n", name, info->ext); + + if (!force_rescan) + debug ("%s(%s): whatis had empty pointer; " + "forcing a rescan just in case\n", + name, info->ext); + force_rescan = 1; + return 1; + } else { + /* Does the real page still exist? */ + char **real_found; + int save_debug = debug_level; + struct timespec t; + + debug_level = 0; + real_found = look_for_file (path, info->ext, + info->pointer, cat, LFF_MATCHCASE); + debug_level = save_debug; + + t.tv_sec = -1; + t.tv_nsec = -1; + if (count_glob_matches (info->pointer, info->ext, real_found, + t)) + return 0; + + if (!opt_test) + dbdelete (dbf, name, info); + else + debug ("%s(%s): whatis target was deleted, " + "would delete\n", name, info->ext); + return 1; + } +} + +/* Check that multi keys are correctly constructed. */ +static int check_multi_key (const char *name, const char *content) +{ + const char *walk, *next; + + if (!*content) + return 0; + + for (walk = content; walk && *walk; walk = next) { + /* The name in the multi key should only differ from the + * name of the key itself in its case, if at all. + */ + int valid = 1; + ++walk; /* skip over initial tab */ + next = strchr (walk, '\t'); + if (next) { + if (strncasecmp (name, walk, next - walk)) + valid = 0; + } else { + if (strcasecmp (name, walk)) + valid = 0; + } + if (!valid) { + debug ("%s: broken multi key \"%s\", " + "forcing a rescan\n", name, content); + force_rescan = 1; + return 1; + } + + /* If the name was valid, skip over the extension and + * continue the scan. + */ + walk = next; + next = walk ? strchr (walk + 1, '\t') : NULL; + } + + return 0; +} + +/* Go through the database and purge references to man pages that no longer + * exist. + */ +int purge_missing (const char *manpath, const char *catpath, + int will_run_mandb) +{ +#ifdef NDBM + char *dirfile; +#endif + struct stat st; + int db_exists; + MYDBM_FILE dbf; + datum key; + int count = 0; + struct timespec db_mtime; + +#ifdef NDBM + dirfile = xasprintf ("%s.dir", database); + db_exists = stat (dirfile, &st) == 0; + free (dirfile); +#else + db_exists = stat (database, &st) == 0; +#endif + if (!db_exists) + /* nothing to purge */ + return 0; + + if (!quiet) + printf (_("Purging old database entries in %s...\n"), manpath); + + dbf = MYDBM_RWOPEN (database); + if (!dbf) { + gripe_rwopen_failed (); + return 0; + } + if (!sanity_check_db (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + return 0; + } + db_mtime = MYDBM_GET_TIME (dbf); + + key = MYDBM_FIRSTKEY (dbf); + + while (MYDBM_DPTR (key) != NULL) { + datum content, nextkey; + struct mandata entry; + char *nicekey, *tab; + int save_debug; + char **found; + + /* Ignore db identifier keys. */ + if (*MYDBM_DPTR (key) == '$') { + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + continue; + } + + content = MYDBM_FETCH (dbf, key); + if (!MYDBM_DPTR (content)) { + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + continue; + } + + /* Get just the name. */ + nicekey = xstrdup (MYDBM_DPTR (key)); + tab = strchr (nicekey, '\t'); + if (tab) + *tab = '\0'; + + /* Deal with multi keys. */ + if (*MYDBM_DPTR (content) == '\t') { + if (check_multi_key (nicekey, MYDBM_DPTR (content))) + MYDBM_DELETE (dbf, key); + free (nicekey); + MYDBM_FREE_DPTR (content); + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + continue; + } + + split_content (MYDBM_DPTR (content), &entry); + + save_debug = debug_level; + debug_level = 0; /* look_for_file() is quite noisy */ + if (entry.id <= WHATIS_MAN) + found = look_for_file (manpath, entry.ext, + entry.name ? entry.name + : nicekey, + 0, LFF_MATCHCASE); + else + found = look_for_file (catpath, entry.ext, + entry.name ? entry.name + : nicekey, + 1, LFF_MATCHCASE); + debug_level = save_debug; + + /* Now actually decide whether to purge, depending on the + * type of entry. + */ + if (entry.id == ULT_MAN || entry.id == SO_MAN || + entry.id == STRAY_CAT) + count += purge_normal (dbf, nicekey, &entry, found); + else if (entry.id == WHATIS_MAN) + count += purge_whatis (dbf, manpath, 0, nicekey, + &entry, found, db_mtime); + else /* entry.id == WHATIS_CAT */ + count += purge_whatis (dbf, catpath, 1, nicekey, + &entry, found, db_mtime); + + free (nicekey); + + free_mandata_elements (&entry); + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + MYDBM_REORG (dbf); + if (will_run_mandb) + /* Reset mtime to avoid confusing mandb into not running. + * TODO: It would be better to avoid this by only opening + * the database once between here and mandb. + */ + MYDBM_SET_TIME (dbf, db_mtime); + MYDBM_CLOSE (dbf); + return count; +} diff --git a/src/check_mandirs.h b/src/check_mandirs.h new file mode 100644 index 0000000..c6565ac --- /dev/null +++ b/src/check_mandirs.h @@ -0,0 +1,32 @@ +/* + * check_mandirs.h: Interface to updating database caches + * + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "db_storage.h" + +/* check_mandirs.c */ +extern void test_manfile (MYDBM_FILE dbf, const char *file, const char *path); +extern void chown_if_possible (const char *path); +extern int create_db (const char *manpath, const char *catpath); +extern int update_db (const char *manpath, const char *catpath); +extern void purge_pointers (MYDBM_FILE dbf, const char *name); +extern int purge_missing (const char *manpath, const char *catpath, + int will_run_mandb); diff --git a/src/compression.c b/src/compression.c new file mode 100644 index 0000000..7063567 --- /dev/null +++ b/src/compression.c @@ -0,0 +1,123 @@ +/* + * compression.c: code to find decompressor / compression extension + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Sat Aug 20 15:01:02 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" +#ifdef COMP_SRC /* must come after manconfig.h */ + +#include "error.h" +#include "pipeline.h" + +/* Take filename as arg, return structure containing decompressor + and extension, or NULL if no comp extension found. + If want_stem, set comp->stem to the filename without extension, which + the caller should free. + + eg. + filename = /usr/man/man1/foo.1.gz + + comp->prog = "/usr/bin/gzip -dc"; + comp->ext = "gz"; + comp->stem = "/usr/man/man1/foo.1"; + */ +struct compression *comp_info (const char *filename, int want_stem) +{ + const char *ext; + static struct compression hpux_comp = {GUNZIP " -S \"\"", "", NULL}; + + ext = strrchr (filename, '.'); + + if (ext) { + struct compression *comp; + for (comp = comp_list; comp->ext; comp++) { + if (strcmp (comp->ext, ext + 1) == 0) { + if (want_stem) + comp->stem = xstrndup (filename, + ext - filename); + else + comp->stem = NULL; + return comp; + } + } + } + + ext = strstr (filename, ".Z/"); + if (ext) { + if (want_stem) + hpux_comp.stem = xstrndup (filename, ext - filename); + else + hpux_comp.stem = NULL; + return &hpux_comp; + } + + return NULL; +} + +/* take filename w/o comp ext. as arg, return comp->stem as a relative + compressed file or NULL if none found */ +struct compression *comp_file (const char *filename) +{ + size_t len; + char *compfile; + struct compression *comp; + + compfile = xasprintf ("%s.", filename); + len = strlen (compfile); + + for (comp = comp_list; comp->ext; comp++) { + struct stat buf; + + compfile = appendstr (compfile, comp->ext, (void *) 0); + + if (stat (compfile, &buf) == 0) { + comp->stem = compfile; + return comp; + } + + *(compfile + len) = '\0'; + } + free (compfile); + return NULL; +} + +#endif /* COMP_SRC */ diff --git a/src/descriptions.c b/src/descriptions.c new file mode 100644 index 0000000..009a50b --- /dev/null +++ b/src/descriptions.c @@ -0,0 +1,161 @@ +/* + * descriptions.c: manipulate man page descriptions + * + * Copyright (C) 2002, 2003, 2006, 2007, 2008, 2009, 2010, 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> + +#include "manconfig.h" +#include "descriptions.h" + +/* Parse the description in a whatis line returned by find_name() into a + * sequence of names and whatis descriptions. + */ +struct page_description *parse_descriptions (const char *base, + const char *whatis) +{ + const char *sep, *nextsep; + struct page_description *desc = NULL, *head = NULL; + int seen_base = 0; + + if (!whatis) + return NULL; + + sep = whatis; + + while (sep) { + char *record; + size_t length; + const char *dash; + char *names; + const char *token; + + /* Use a while loop so that we skip over things like the + * result of double line breaks. + */ + while (*sep == 0x11 || *sep == ' ') + ++sep; + nextsep = strchr (sep, 0x11); + + /* Get this record as a null-terminated string. */ + if (nextsep) + length = (size_t) (nextsep - sep); + else + length = strlen (sep); + if (length == 0) + break; + + record = xstrndup (sep, length); + debug ("record = '%s'\n", record); + + /* Split the record into name and whatis description. */ + dash = strstr (record, " - "); + if (dash) + names = xstrndup (record, dash - record); + else if (!desc) + /* Some pages have a NAME section with just the page + * name and no whatis. We might as well include + * this. + */ + names = xstrdup (record); + else + /* Once at least one record has been seen, further + * cases where there is no whatis usually amount to + * garbage following the useful records, and can + * cause problems due to false WHATIS_MAN entries in + * the database. On the whole it seems best to + * ignore these. + */ + goto next; + + for (token = strtok (names, ","); token; + token = strtok (NULL, ",")) { + char *name = trim_spaces (token); + + /* Skip name tokens containing whitespace. They are + * almost never useful as manual page names. + */ + if (strpbrk (name, " \t") != NULL) { + free (name); + continue; + } + + /* Allocate new description node. */ + if (head) { + desc->next = xmalloc (sizeof *desc); + desc = desc->next; + } else { + desc = xmalloc (sizeof *desc); + head = desc; + } + desc->name = name; /* steal memory */ + desc->whatis = dash ? trim_spaces (dash + 3) : NULL; + desc->next = NULL; + + if (base && STREQ (base, desc->name)) + seen_base = 1; + } + + free (names); +next: + free (record); + + sep = nextsep; + } + + /* If it isn't there already, add the base name onto the returned + * list. + */ + if (base && !seen_base) { + if (head) { + desc->next = xmalloc (sizeof *desc); + desc = desc->next; + desc->whatis = + head->whatis ? xstrdup (head->whatis) : NULL; + } else { + desc = xmalloc (sizeof *desc); + head = desc; + desc->whatis = NULL; + } + desc->name = xstrdup (base); + desc->next = NULL; + } + + return head; +} + +/* Free a description list and all its contents. */ +void free_descriptions (struct page_description *head) +{ + struct page_description *desc = head, *prev; + + while (desc) { + free (desc->name); + free (desc->whatis); + prev = desc; + desc = desc->next; + free (prev); + } +} diff --git a/src/descriptions.h b/src/descriptions.h new file mode 100644 index 0000000..a0161be --- /dev/null +++ b/src/descriptions.h @@ -0,0 +1,40 @@ +/* + * descriptions.h: Interface to manipulating man page descriptions + * + * Copyright (C) 2002, 2007, 2008, 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "db_storage.h" + +struct page_description { + char *name; + char *whatis; + struct page_description *next; +}; + +struct ult_trace; + +extern struct page_description *parse_descriptions (const char *base, + const char *whatis); +extern void store_descriptions (MYDBM_FILE dbf, + const struct page_description *head, + struct mandata *info, + const char *path, const char *base, + struct ult_trace *trace); +extern void free_descriptions (struct page_description *head); diff --git a/src/descriptions_store.c b/src/descriptions_store.c new file mode 100644 index 0000000..c473aee --- /dev/null +++ b/src/descriptions_store.c @@ -0,0 +1,148 @@ +/* + * descriptions_store.c: store man page descriptions in database + * + * Copyright (C) 2002, 2003, 2006, 2007, 2008, 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" + +#include "db_storage.h" + +#include "filenames.h" +#include "ult_src.h" +#include "descriptions.h" + +static void gripe_bad_store (const char *name, const char *ext) +{ + if (quiet < 2) + error (0, 0, _("warning: failed to store entry for %s(%s)"), + name, ext); +} + +/* Is PATH a prefix of DIR, such that DIR is in the manual hierarchy PATH? + * This requires that the part of DIR following PATH start with "/man". + */ +static int is_prefix (const char *path, const char *dir) +{ + return (STRNEQ (dir, path, strlen (path)) && + STRNEQ (dir + strlen (path), "/man", 4)); +} + +/* Take a list of descriptions returned by parse_descriptions() and store + * it into the database. + */ +void store_descriptions (MYDBM_FILE dbf, const struct page_description *head, + struct mandata *info, + const char *path, const char *base, + struct ult_trace *trace) +{ + const struct page_description *desc; + char save_id = info->id; + size_t i; + + if (trace) { + for (i = 0; i < trace->len; ++i) + debug ("trace->names[%zu] = '%s'\n", + i, trace->names[i]); + } + + for (desc = head; desc; desc = desc->next) { + /* Either it's the real thing or merely a reference. Get the + * id and pointer right in either case. + */ + int found_real_page = 0; + int found_external = 0; + + if (STREQ (base, desc->name)) { + info->id = save_id; + info->pointer = NULL; + info->whatis = desc->whatis; + found_real_page = 1; + } else if (trace) { + for (i = 0; i < trace->len; ++i) { + struct mandata trace_info; + char *buf; + + buf = filename_info (trace->names[i], + &trace_info, ""); + if (trace_info.name && + STREQ (trace_info.name, desc->name)) { + if (path && !is_prefix (path, buf)) { + /* Link outside this manual + * hierarchy; skip this + * description. + */ + found_external = 1; + free (trace_info.name); + free (buf); + break; + } + if (i == trace->len - 1 && + save_id == SO_MAN) + info->id = ULT_MAN; + else + info->id = save_id; + info->pointer = NULL; + info->whatis = desc->whatis; + found_real_page = 1; + } + + free (trace_info.name); + free (buf); + } + } + + if (found_external) { + debug ("skipping '%s'; link outside manual " + "hierarchy\n", desc->name); + continue; + } + + if (!found_real_page) { + if (save_id < STRAY_CAT) + info->id = WHATIS_MAN; + else + info->id = WHATIS_CAT; + info->pointer = xstrdup (base); + /* Don't waste space storing the whatis in the db + * more than once. + */ + info->whatis = NULL; + } + + debug ("name = '%s', id = %c\n", desc->name, info->id); + if (dbstore (dbf, info, desc->name) > 0) { + gripe_bad_store (base, info->ext); + break; + } + } +} diff --git a/src/filenames.c b/src/filenames.c new file mode 100644 index 0000000..69cdeda --- /dev/null +++ b/src/filenames.c @@ -0,0 +1,158 @@ +/* + * filenames.c: compose and dissect man page file names + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" + +#include "db_storage.h" + +#include "filenames.h" + +static void gripe_bogus_manpage (const char *manpage) +{ + if (quiet < 2) + error (0, 0, _("warning: %s: ignoring bogus filename"), + manpage); +} + +char *make_filename (const char *path, const char *name, + struct mandata *in, const char *type) +{ + static char *file; + + if (!name) + name = in->name; /* comes from dblookup(), so non-NULL */ + + file = xasprintf ("%s/%s%s/%s.%s", path, type, in->sec, name, in->ext); + + if (in->comp && *in->comp != '-') /* Is there an extension? */ + file = appendstr (file, ".", in->comp, (void *) 0); + + debug ("Checking physical location: %s\n", file); + if (!CAN_ACCESS (file, R_OK)) { + free (file); + return NULL; + } + + return file; +} + +/* Fill in a mandata structure with information about a file name. + * file is the name to examine. info points to the structure to be filled + * in. req_name is the page name that was requested. + * + * Returns either a pointer to the buffer which the fields in info point + * into, to be freed by the caller, or NULL on error. The buffer will + * contain either three or four null-terminated strings: the directory name, + * the base of the file name in that directory, the section extension, and + * optionally the compression extension (if COMP_SRC is defined). + * + * Only the fields name, ext, sec, and comp are filled in by this function. + * name is only set if it differs from req_name; otherwise it remains at + * NULL. + */ +char *filename_info (const char *file, struct mandata *info, + const char *req_name) +{ + char *manpage = xstrdup (file); + char *slash = strrchr (manpage, '/'); + char *base_name; + + memset (info, 0, sizeof (struct mandata)); + +#ifdef COMP_SRC + struct compression *comp; +#endif + + if (slash) { + *slash = '\0'; /* strip '/base_name' */ + base_name = slash + 1; + } else + base_name = manpage; + + /* Bogus files either have (i) no period, ie no extension, (ii) + a compression extension, but no sectional extension, (iii) + a missmatch between the section they are under and the + sectional part of their extension. */ + +#ifdef COMP_SRC + comp = comp_info (base_name, 1); + if (comp) { + info->comp = comp->ext; + *(base_name + strlen (comp->stem)) = '\0'; + free (comp->stem); + } else + info->comp = NULL; +#else /* !COMP_SRC */ + info->comp = NULL; +#endif /* COMP_SRC */ + + { + char *ext = strrchr (base_name, '.'); + if (!ext) { + /* no section extension */ + gripe_bogus_manpage (file); + free (manpage); + return NULL; + } + *ext++ = '\0'; /* set section ext */ + info->ext = ext; + if (!*info->ext) { + /* zero-length section extension */ + gripe_bogus_manpage (file); + free (manpage); + return NULL; + } + } + + info->sec = strrchr (manpage, '/') + 4; /* set section name */ + + if (strlen (info->sec) >= 1 && strlen (info->ext) >= 1 && + info->sec[0] != info->ext[0]) { + /* mismatch in section */ + gripe_bogus_manpage (file); + free (manpage); + return NULL; + } + + if (req_name && !STREQ (base_name, req_name)) + info->name = xstrdup (base_name); + else + info->name = NULL; + + return manpage; +} diff --git a/src/filenames.h b/src/filenames.h new file mode 100644 index 0000000..d7fd8a1 --- /dev/null +++ b/src/filenames.h @@ -0,0 +1,28 @@ +/* + * filenames.h: Interface to composing and dissecting man page file names + * + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "db_storage.h" + +extern char *make_filename (const char *path, const char *name, + struct mandata *in, const char *type); +extern char *filename_info (const char *file, struct mandata *info, + const char *req_name); diff --git a/src/globbing.c b/src/globbing.c new file mode 100644 index 0000000..2fc8e24 --- /dev/null +++ b/src/globbing.c @@ -0,0 +1,453 @@ +/* + * globbing.c: interface to the POSIX glob routines + * + * Copyright (C) 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Mon Mar 13 20:27:36 GMT 1995 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <glob.h> +#include <sys/types.h> +#include <dirent.h> + +#include "fnmatch.h" +#include "regex.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "error.h" +#include "hashtable.h" +#include "cleanup.h" +#include "xregcomp.h" + +#include "globbing.h" + +const char *extension; +static const char *mandir_layout = MANDIR_LAYOUT; + +static char *make_pattern (const char *name, const char *sec, int opts) +{ + char *pattern; + + if (opts & LFF_REGEX) { + if (extension) { + char *esc_ext = escape_shell (extension); + pattern = xasprintf ("%s\\..*%s.*", name, esc_ext); + free (esc_ext); + } else { + char *esc_sec = escape_shell (sec); + pattern = xasprintf ("%s\\.%s.*", name, esc_sec); + free (esc_sec); + } + } else { + if (extension) + pattern = xasprintf ("%s.*%s*", name, extension); + else + pattern = xasprintf ("%s.%s*", name, sec); + } + + return pattern; +} + +#define LAYOUT_GNU 1 +#define LAYOUT_HPUX 2 +#define LAYOUT_IRIX 4 +#define LAYOUT_SOLARIS 8 +#define LAYOUT_BSD 16 + +static int parse_layout (const char *layout) +{ + if (!*layout) + return LAYOUT_GNU | LAYOUT_HPUX | LAYOUT_IRIX | + LAYOUT_SOLARIS | LAYOUT_BSD; + else { + int flags = 0; + + char *upper_layout = xstrdup (layout); + char *layoutp; + for (layoutp = upper_layout; *layoutp; layoutp++) + *layoutp = CTYPE (toupper, *layoutp); + + if (strstr (upper_layout, "GNU")) + flags |= LAYOUT_GNU; + if (strstr (upper_layout, "HPUX")) + flags |= LAYOUT_HPUX; + if (strstr (upper_layout, "IRIX")) + flags |= LAYOUT_IRIX; + if (strstr (upper_layout, "SOLARIS")) + flags |= LAYOUT_SOLARIS; + if (strstr (upper_layout, "BSD")) + flags |= LAYOUT_BSD; + + free (upper_layout); + return flags; + } +} + +struct dirent_hashent { + char **names; + size_t names_len, names_max; +}; + +static void dirent_hashtable_free (void *defn) +{ + struct dirent_hashent *hashent = defn; + size_t i; + + for (i = 0; i < hashent->names_len; ++i) + free (hashent->names[i]); + free (hashent->names); + free (hashent); +} + +static struct hashtable *dirent_hash = NULL; + +static int cache_compare (const void *a, const void *b) +{ + const char *left = *(const char **) a; + const char *right = *(const char **) b; + return strcasecmp (left, right); +} + +static struct dirent_hashent *update_directory_cache (const char *path) +{ + struct dirent_hashent *cache; + DIR *dir; + struct dirent *entry; + + if (!dirent_hash) { + dirent_hash = hashtable_create (&dirent_hashtable_free); + push_cleanup ((cleanup_fun) hashtable_free, dirent_hash, 0); + } + cache = hashtable_lookup (dirent_hash, path, strlen (path)); + + /* Check whether we've got this one already. */ + if (cache) { + debug ("update_directory_cache %s: hit\n", path); + return cache; + } + + debug ("update_directory_cache %s: miss\n", path); + + dir = opendir (path); + if (!dir) { + debug_error ("can't open directory %s", path); + return NULL; + } + + cache = XMALLOC (struct dirent_hashent); + cache->names_len = 0; + cache->names_max = 1024; + cache->names = XNMALLOC (cache->names_max, char *); + + /* Dump all the entries into cache->names, resizing if necessary. */ + for (entry = readdir (dir); entry; entry = readdir (dir)) { + if (cache->names_len >= cache->names_max) { + cache->names_max *= 2; + cache->names = + xnrealloc (cache->names, cache->names_max, + sizeof (char *)); + } + cache->names[cache->names_len++] = xstrdup (entry->d_name); + } + + qsort (cache->names, cache->names_len, sizeof *cache->names, + &cache_compare); + + hashtable_install (dirent_hash, path, strlen (path), cache); + closedir (dir); + + return cache; +} + +struct pattern_bsearch { + char *pattern; + size_t len; +}; + +static int pattern_compare (const void *a, const void *b) +{ + const struct pattern_bsearch *key = a; + const char *memb = *(const char **) b; + return strncasecmp (key->pattern, memb, key->len); +} + +static void clear_glob (glob_t *pglob) +{ + /* look_for_file declares this static, so it's zero-initialised. + * globfree() can deal with checking it before freeing. + */ + globfree (pglob); + + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + pglob->gl_offs = 0; +} + +static void match_in_directory (const char *path, const char *pattern, int opts, + glob_t *pglob, size_t *allocated) +{ + struct dirent_hashent *cache; + size_t my_allocated = 0; + int flags; + regex_t preg; + struct pattern_bsearch pattern_start = { NULL, -1 }; + char **bsearched; + size_t i; + + if (!allocated) + allocated = &my_allocated; + if (!*allocated) + clear_glob (pglob); + + cache = update_directory_cache (path); + if (!cache) { + debug ("directory cache update failed\n"); + return; + } + + debug ("globbing pattern in %s: %s\n", path, pattern); + + if (!*allocated) { + *allocated = 4; + pglob->gl_pathv = XNMALLOC (*allocated, char *); + pglob->gl_pathv[0] = NULL; + } + + if (opts & LFF_REGEX) + flags = REG_EXTENDED | REG_NOSUB | + ((opts & LFF_MATCHCASE) ? 0 : REG_ICASE); + else + flags = (opts & LFF_MATCHCASE) ? 0 : FNM_CASEFOLD; + + if (opts & LFF_REGEX) { + xregcomp (&preg, pattern, flags); + bsearched = cache->names; + } else { + pattern_start.pattern = xstrndup (pattern, + strcspn (pattern, "?*{}\\")); + pattern_start.len = strlen (pattern_start.pattern); + bsearched = bsearch (&pattern_start, cache->names, + cache->names_len, sizeof *cache->names, + &pattern_compare); + if (!bsearched) { + free (pattern_start.pattern); + return; + } + while (bsearched > cache->names && + !strncasecmp (pattern_start.pattern, *(bsearched - 1), + pattern_start.len)) + --bsearched; + } + + for (i = bsearched - cache->names; i < cache->names_len; ++i) { + if (opts & LFF_REGEX) { + if (regexec (&preg, cache->names[i], 0, NULL, 0) != 0) + continue; + } else { + if (strncasecmp (pattern_start.pattern, + cache->names[i], pattern_start.len)) + break; + + if (fnmatch (pattern, cache->names[i], flags) != 0) + continue; + } + + debug ("matched: %s/%s\n", path, cache->names[i]); + + if (pglob->gl_pathc >= *allocated) { + *allocated *= 2; + pglob->gl_pathv = xnrealloc ( + pglob->gl_pathv, *allocated, sizeof (char *)); + } + pglob->gl_pathv[pglob->gl_pathc++] = + xasprintf ("%s/%s", path, cache->names[i]); + } + + if (opts & LFF_REGEX) + regfree (&preg); + else + free (pattern_start.pattern); + + if (pglob->gl_pathc >= *allocated) { + *allocated *= 2; + pglob->gl_pathv = xnrealloc (pglob->gl_pathv, + *allocated, sizeof (char *)); + } + pglob->gl_pathv[pglob->gl_pathc] = NULL; + + return; +} + +char **look_for_file (const char *hier, const char *sec, + const char *unesc_name, int cat, int opts) +{ + char *pattern, *path = NULL; + static glob_t gbuf; + static int cleanup_installed = 0; + static int layout = -1; + char *name; + + if (!cleanup_installed) { + /* appease valgrind */ + push_cleanup ((cleanup_fun) globfree, &gbuf, 0); + cleanup_installed = 1; + } + + clear_glob (&gbuf); + + /* This routine only does a minimum amount of matching. It does not + find cat files in the alternate cat directory. */ + + if (layout == -1) { + layout = parse_layout (mandir_layout); + debug ("Layout is %s (%d)\n", mandir_layout, layout); + } + + if (opts & (LFF_REGEX | LFF_WILDCARD)) + name = xstrdup (unesc_name); + else + name = escape_shell (unesc_name); + + /* allow lookups like "3x foo" to match "../man3/foo.3x" */ + + if (layout & LAYOUT_GNU) { + glob_t dirs; + size_t i; + size_t allocated = 0; + + memset (&dirs, 0, sizeof (dirs)); + pattern = xasprintf ("%s\t*", cat ? "cat" : "man"); + *strrchr (pattern, '\t') = *sec; + match_in_directory (hier, pattern, LFF_MATCHCASE, &dirs, NULL); + free (pattern); + + pattern = make_pattern (name, sec, opts); + for (i = 0; i < dirs.gl_pathc; ++i) { + if (path) + *path = '\0'; + match_in_directory (dirs.gl_pathv[i], pattern, opts, + &gbuf, &allocated); + } + free (pattern); + globfree (&dirs); + } + + /* Try HPUX style compressed man pages */ + if ((layout & LAYOUT_HPUX) && gbuf.gl_pathc == 0) { + if (path) + *path = '\0'; + path = appendstr (path, hier, cat ? "/cat" : "/man", + sec, ".Z", (void *) 0); + pattern = make_pattern (name, sec, opts); + + match_in_directory (path, pattern, opts, &gbuf, NULL); + free (pattern); + } + + /* Try man pages without the section extension --- IRIX man pages */ + if ((layout & LAYOUT_IRIX) && gbuf.gl_pathc == 0) { + if (path) + *path = '\0'; + path = appendstr (path, hier, cat ? "/cat" : "/man", sec, + (void *) 0); + if (opts & LFF_REGEX) + pattern = xasprintf ("%s\\..*", name); + else + pattern = xasprintf ("%s.*", name); + + match_in_directory (path, pattern, opts, &gbuf, NULL); + free (pattern); + } + + /* Try Solaris style man page directories */ + if ((layout & LAYOUT_SOLARIS) && gbuf.gl_pathc == 0) { + if (path) + *path = '\0'; + /* TODO: This needs to be man/sec*, not just man/sec. */ + path = appendstr (path, hier, cat ? "/cat" : "/man", sec, + (void *) 0); + pattern = make_pattern (name, sec, opts); + + match_in_directory (path, pattern, opts, &gbuf, NULL); + free (pattern); + } + + /* BSD cat pages take the extension .0 */ + if ((layout & LAYOUT_BSD) && gbuf.gl_pathc == 0) { + if (path) + *path = '\0'; + if (cat) { + path = appendstr (path, hier, "/cat", sec, (void *) 0); + if (opts & LFF_REGEX) + pattern = xasprintf ("%s\\.0.*", name); + else + pattern = xasprintf ("%s.0*", name); + } else { + path = appendstr (path, hier, "/man", sec, (void *) 0); + pattern = make_pattern (name, sec, opts); + } + match_in_directory (path, pattern, opts, &gbuf, NULL); + free (pattern); + } + + free (name); + free (path); + + if (gbuf.gl_pathc == 0) + return NULL; + else + return gbuf.gl_pathv; +} + +char **expand_path (const char *path) +{ + int res = 0; + char **result = NULL; + glob_t globbuf; + size_t i; + + res = glob (path, GLOB_NOCHECK, NULL, &globbuf); + /* if glob failed, return the given path */ + if (res != 0) { + result = XNMALLOC (2, char *); + result[0] = xstrdup (path); + result[1] = NULL; + return result; + } + + result = XNMALLOC (globbuf.gl_pathc + 1, char *); + for (i = 0; i < globbuf.gl_pathc; i++) { + result[i] = xstrdup (globbuf.gl_pathv[i]); + } + result[globbuf.gl_pathc] = NULL; + + globfree (&globbuf); + + return result; +} diff --git a/src/globbing.h b/src/globbing.h new file mode 100644 index 0000000..1c81141 --- /dev/null +++ b/src/globbing.h @@ -0,0 +1,34 @@ +/* + * globbing.h: Headers for glob routines + * + * Copyright (C) 2001, 2002, 2007, 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +enum look_for_file_opts { + LFF_MATCHCASE = 1, + LFF_REGEX = 2, + LFF_WILDCARD = 4 +}; + +/* globbing.c */ +extern char **look_for_file (const char *hier, const char *sec, + const char *unesc_name, int cat, int opts); + +/* Expand path with wildcards into list of all existing directories. */ +extern char **expand_path (const char *path); diff --git a/src/globbing_test.c b/src/globbing_test.c new file mode 100644 index 0000000..eb4070a --- /dev/null +++ b/src/globbing_test.c @@ -0,0 +1,130 @@ +/* + * globbing_test.c: test program for file-finding functions + * + * Copyright (C) 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <stdlib.h> + +#include "argp.h" +#include "progname.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "error.h" +#include "globbing.h" +#include "sandbox.h" + +man_sandbox *sandbox; /* unused, but needed by libman */ + +extern const char *extension; +static int match_case = 0; +static int regex_opt = 0; +static int wildcard = 0; +static char **remaining_args; + +const char *argp_program_version = "globbing " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("PATH SECTION NAME"); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "extension", 'e', N_("EXTENSION"), 0, N_("limit search to extension type EXTENSION") }, + { "ignore-case", 'i', 0, 0, N_("look for pages case-insensitively (default)") }, + { "match-case", 'I', 0, 0, N_("look for pages case-sensitively") }, + { "regex", 'r', 0, 0, N_("interpret page name as a regex") }, + { "wildcard", 'w', 0, 0, N_("the page name contains wildcards") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'e': + extension = arg; + return 0; + case 'i': + match_case = 0; + return 0; + case 'I': + match_case = 1; + return 0; + case 'r': + regex_opt = 1; + return 0; + case 'w': + wildcard = 1; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_ARGS: + if (state->argc - state->next != 3) + argp_usage (state); + remaining_args = state->argv + state->next; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +int main (int argc, char **argv) +{ + int i; + + set_program_name (argv[0]); + + init_debug (); + init_locale (); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + for (i = 0; i <= 1; i++) { + char **files; + + files = look_for_file (remaining_args[0], remaining_args[1], + remaining_args[2], i, + (match_case ? LFF_MATCHCASE : 0) | + (regex_opt ? LFF_REGEX : 0) | + (wildcard ? LFF_WILDCARD : 0)); + if (files) + while (*files) + printf ("%s\n", *files++); + } + return 0; +} diff --git a/src/lexgrog.c b/src/lexgrog.c new file mode 100644 index 0000000..7915d7d --- /dev/null +++ b/src/lexgrog.c @@ -0,0 +1,5201 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#line 6 "lexgrog.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 139 +#define YY_END_OF_BUFFER 140 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[1410] = + { 0, + 0, 0, 0, 0, 65, 65, 65, 65, 0, 0, + 0, 0, 0, 0, 0, 0, 117, 117, 0, 0, + 0, 0, 0, 0, 124, 124, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 140, 139, 29, 29, + 29, 138, 65, 65, 138, 138, 138, 136, 138, 134, + 81, 65, 65, 138, 81, 104, 104, 104, 99, 104, + 106, 106, 105, 111, 111, 111, 110, 116, 116, 116, + 116, 116, 117, 119, 119, 118, 121, 121, 120, 123, + 123, 122, 124, 124, 138, 135, 138, 138, 138, 7, + 10, 7, 7, 6, 6, 6, 4, 18, 18, 18, + + 19, 19, 0, 28, 0, 27, 27, 29, 65, 0, + 136, 0, 0, 137, 65, 65, 137, 133, 137, 137, + 133, 81, 65, 0, 0, 136, 0, 134, 68, 65, + 74, 0, 61, 0, 0, 63, 64, 0, 0, 60, + 62, 60, 0, 0, 0, 0, 0, 0, 65, 0, + 65, 65, 137, 133, 81, 65, 0, 63, 104, 0, + 0, 99, 92, 93, 94, 95, 96, 97, 98, 106, + 105, 111, 0, 0, 0, 110, 110, 116, 0, 0, + 0, 117, 119, 118, 121, 120, 123, 122, 124, 135, + 0, 0, 124, 124, 137, 137, 137, 137, 124, 135, + + 54, 0, 124, 39, 7, 0, 9, 0, 10, 7, + 6, 0, 3, 4, 3, 4, 3, 18, 0, 0, + 0, 18, 19, 28, 0, 0, 0, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 56, 0, 65, + 0, 0, 36, 36, 36, 36, 36, 36, 36, 36, + 0, 50, 0, 0, 0, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 56, 49, 0, 57, 74, 70, 0, 0, + 0, 0, 0, 0, 0, 0, 73, 73, 73, 0, + 0, 0, 67, 0, 75, 76, 0, 77, 0, 0, + + 79, 0, 0, 65, 0, 0, 36, 36, 36, 36, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 91, 100, 101, 102, 103, 99, 92, 93, 94, 95, + 96, 97, 98, 0, 0, 0, 0, 0, 0, 59, + 0, 124, 38, 38, 124, 38, 38, 38, 38, 37, + 54, 7, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 5, 3, 3, 4, 4, 4, 3, 0, + 0, 0, 0, 0, 16, 0, 21, 27, 27, 27, + 27, 20, 27, 27, 27, 56, 0, 0, 0, 36, + + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 51, 41, 0, + 0, 0, 0, 0, 126, 58, 0, 128, 47, 127, + 0, 0, 30, 0, 0, 0, 125, 34, 53, 0, + 35, 33, 52, 32, 49, 82, 71, 61, 55, 62, + 66, 0, 0, 0, 0, 0, 0, 0, 0, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + + 83, 0, 85, 90, 86, 87, 88, 89, 63, 91, + 100, 101, 102, 103, 0, 0, 0, 114, 112, 0, + 38, 38, 38, 38, 37, 38, 38, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 5, 3, 3, 4, 4, 4, 0, 3, + 3, 12, 14, 13, 15, 11, 17, 21, 25, 26, + 20, 22, 24, 23, 55, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 30, 36, 36, 36, 36, 34, 36, + + 36, 35, 33, 36, 32, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 40, 130, 129, 45, 126, 58, 46, 47, 127, 132, + 131, 30, 42, 44, 31, 125, 34, 34, 53, 43, + 35, 33, 52, 32, 82, 55, 72, 0, 69, 78, + 80, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 83, 84, 85, 90, 86, 87, 88, 89, + 0, 108, 0, 114, 115, 112, 113, 38, 38, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 3, 25, 26, 22, + 24, 23, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 30, 36, + 36, 31, 36, 34, 34, 36, 36, 35, 33, 36, + 32, 36, 36, 36, 36, 36, 36, 36, 36, 36, + + 36, 36, 130, 129, 45, 132, 131, 44, 43, 80, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, + 107, 108, 109, 115, 113, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 107, 109, + 7, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, + + 4, 1, 4, 1, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 36, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 4, 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 1, 4, 4, 4, 4, 4, 4, 1, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 7, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 7, 3, 3, + 4, 4, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 0, 0, 1, 0, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 6, 7, 8, 9, 6, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 1, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 27, 1, 1, 1, + 1, 1, 1, 1, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 6, 57, 58, 59, 60, 61, 62, + + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 6, 85, 6, 86, 1, 1, 87, 1, + 1, 88, 89, 1, 1, 1, 90, 91, 1, 1, + 92, 1, 1, 93, 94, 95, 1, 1, 96, 1, + 97, 98, 1, 1, 1, 99, 100, 101, 1, 1, + 102, 1, 1, 103, 1, 104, 105, 106, 107, 108, + 1, 1, 109, 1, 110, 111, 112, 1, 1, 113, + 1, 1, 1, 1, 114, 1, 115, 1, 116, 117, + 1, 1, 1, 1, 118, 119, 1, 1, 1, 1, + + 1, 1, 1, 120, 1, 1, 1, 121, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 122, 123, 1, + 124, 1, 1, 1, 125, 126, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[127] = + { 0, + 1, 2, 3, 4, 2, 1, 5, 1, 1, 1, + 6, 7, 1, 1, 1, 1, 1, 1, 8, 9, + 9, 9, 9, 8, 8, 8, 8, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 1, 1, 1, 1, 1, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[1593] = + { 0, + 0, 0, 0, 2, 6, 0, 131, 135, 138, 139, + 219, 0, 345, 0, 137, 468, 5110, 5109, 546, 0, + 672, 0, 798, 0, 142, 151, 146, 159, 161, 162, + 0, 0, 166, 171, 5107, 5106, 5109, 7208, 7208, 191, + 5105, 7208, 471, 478, 923, 5052, 5051, 176, 5088, 0, + 976, 934, 941, 5101, 186, 7208, 5100, 5081, 187, 477, + 7208, 5089, 0, 7208, 5087, 152, 199, 7208, 5085, 5020, + 5023, 5026, 0, 7208, 5081, 0, 7208, 5080, 0, 7208, + 5079, 0, 946, 952, 5077, 489, 213, 5073, 5020, 0, + 506, 5046, 5043, 7208, 5044, 4991, 964, 0, 501, 5038, + + 7208, 5037, 518, 513, 5036, 0, 1030, 525, 1009, 1065, + 530, 5021, 930, 7208, 1081, 1085, 1106, 4982, 4981, 5018, + 1160, 920, 1113, 5025, 4946, 532, 537, 0, 7208, 936, + 0, 1121, 7208, 1093, 919, 927, 7208, 956, 0, 4952, + 7208, 7208, 5017, 0, 5016, 5020, 1160, 964, 1133, 987, + 1019, 1231, 5023, 1197, 1143, 1248, 1198, 7208, 7208, 4945, + 982, 1171, 995, 1015, 1027, 1042, 1076, 1090, 1099, 7208, + 0, 7208, 4954, 4960, 4959, 1117, 1124, 7208, 4943, 4948, + 4953, 0, 7208, 0, 7208, 0, 7208, 0, 1239, 1214, + 1268, 5013, 1149, 1276, 5014, 1230, 5011, 4958, 1286, 1293, + + 1297, 5011, 1263, 7208, 0, 1302, 1321, 5010, 1306, 5007, + 7208, 5004, 5003, 5002, 5001, 1307, 5000, 0, 1096, 5003, + 1302, 1109, 7208, 7208, 4993, 1317, 4991, 0, 1310, 1325, + 4921, 448, 1331, 4919, 1074, 4912, 1328, 1165, 1221, 1396, + 1413, 1417, 4986, 1421, 1450, 973, 996, 154, 1504, 1579, + 1314, 7208, 4985, 1367, 4944, 1430, 4943, 129, 1169, 1349, + 1431, 4912, 1150, 0, 4906, 4918, 447, 1183, 4889, 1444, + 7208, 4940, 1335, 0, 4938, 1346, 0, 7208, 0, 4891, + 407, 4886, 4861, 4876, 4863, 4871, 7208, 0, 0, 1391, + 0, 0, 7208, 0, 7208, 7208, 0, 7208, 0, 1580, + + 7208, 1426, 0, 1460, 482, 4937, 1384, 4936, 1664, 1739, + 4858, 1480, 4860, 4852, 1009, 4851, 4850, 469, 4848, 4863, + 1402, 1404, 1431, 1443, 1456, 1482, 1484, 1486, 1490, 1496, + 1497, 1498, 1515, 4855, 4850, 4847, 4863, 4852, 4851, 1526, + 1532, 1539, 0, 1556, 1575, 4920, 1563, 4917, 4864, 7208, + 1620, 0, 1824, 4917, 1833, 1846, 4916, 901, 4878, 1150, + 1166, 1662, 4889, 4798, 4869, 4803, 4796, 85, 1012, 4804, + 4811, 4905, 0, 4893, 4889, 4888, 4886, 1668, 4885, 4847, + 4868, 4840, 4863, 4836, 7208, 4833, 0, 1521, 1558, 1565, + 1567, 1607, 1608, 1612, 1614, 1626, 1061, 4795, 4808, 4871, + + 1684, 1759, 1237, 1767, 1828, 1372, 1280, 1674, 1678, 4868, + 1852, 1349, 1876, 1407, 1205, 1841, 1863, 1922, 1272, 1705, + 2003, 957, 1364, 1426, 1724, 1510, 1935, 4867, 1735, 0, + 1908, 4864, 4863, 1914, 4853, 1715, 4861, 1772, 1015, 4860, + 4859, 2045, 2071, 2144, 1467, 2000, 1899, 7208, 1910, 1631, + 1642, 1728, 1750, 1777, 1790, 1791, 1802, 1837, 1854, 1918, + 1934, 1935, 1958, 1959, 1973, 1981, 1987, 1993, 0, 1989, + 1995, 2002, 0, 2006, 0, 2056, 7208, 7208, 2057, 7208, + 7208, 0, 0, 4850, 4803, 0, 0, 4851, 4846, 4852, + 2226, 1136, 2196, 1477, 1466, 1770, 1572, 1632, 2171, 4851, + + 2067, 4771, 2123, 2124, 2155, 2156, 2157, 2161, 7208, 2162, + 2163, 2233, 2238, 2244, 4786, 4791, 4786, 2246, 2250, 4785, + 0, 2251, 2255, 4841, 0, 2259, 0, 0, 2279, 4842, + 2288, 1458, 4812, 2222, 1644, 2283, 1642, 1683, 1720, 2290, + 2251, 4794, 4751, 1083, 1215, 4719, 4718, 4746, 4721, 4747, + 4722, 4829, 0, 4826, 4824, 4822, 4818, 2413, 2538, 4814, + 4809, 7208, 7208, 7208, 7208, 7208, 7208, 0, 0, 0, + 2260, 0, 0, 0, 2261, 2236, 0, 1665, 2284, 2293, + 2342, 2354, 2363, 2370, 2374, 2378, 2382, 2386, 2390, 2419, + 2423, 2427, 2431, 2435, 2441, 2456, 2460, 2464, 2468, 0, + + 2472, 2476, 2480, 0, 2484, 0, 4811, 0, 4743, 1385, + 4741, 4713, 4725, 4711, 4691, 4757, 0, 2488, 1220, 4756, + 2662, 4755, 4754, 2688, 4753, 1778, 2481, 4752, 2507, 1521, + 7208, 0, 0, 0, 2269, 2274, 2292, 2308, 2332, 0, + 0, 2346, 2392, 0, 2401, 2443, 2450, 2490, 0, 0, + 2492, 2509, 0, 2511, 2515, 2517, 7208, 4698, 7208, 7208, + 0, 2521, 1803, 2525, 2544, 2548, 2552, 2556, 2560, 1695, + 4670, 4684, 2564, 2566, 2568, 2575, 2581, 2582, 2586, 2587, + 4691, 2592, 4679, 2593, 2594, 2598, 2599, 2604, 2608, 0, + 1800, 2612, 1836, 4734, 1800, 1882, 2129, 2590, 2130, 2346, + + 2194, 2621, 2234, 2771, 2268, 4715, 4699, 4698, 4626, 4644, + 4602, 4607, 4612, 2664, 4581, 4575, 4572, 4688, 0, 0, + 0, 0, 2833, 2772, 2301, 4652, 2370, 2466, 2757, 4661, + 4570, 1839, 4640, 4573, 4566, 872, 1848, 4572, 4579, 2812, + 2489, 4630, 2485, 2558, 2854, 4641, 4550, 1952, 4620, 4554, + 4547, 1529, 1970, 4536, 4543, 0, 0, 0, 0, 0, + 0, 0, 1999, 1509, 1617, 0, 2625, 4636, 0, 0, + 0, 2630, 2634, 2638, 2642, 2649, 0, 0, 2665, 2669, + 0, 2673, 2677, 2681, 2740, 0, 0, 2775, 2779, 0, + 2789, 4635, 4633, 2793, 4632, 4631, 0, 1535, 2970, 2996, + + 1827, 1915, 0, 0, 0, 0, 0, 0, 0, 0, + 2802, 2820, 2840, 2855, 2861, 2882, 2899, 2903, 4629, 2683, + 2781, 2809, 2816, 2824, 2842, 0, 2583, 2907, 2849, 4627, + 2587, 4590, 4551, 2614, 2601, 2920, 2624, 4568, 4502, 4481, + 4469, 4468, 2709, 2179, 2766, 4465, 4464, 4473, 4568, 0, + 0, 3079, 3056, 2747, 4524, 2757, 2814, 3062, 4535, 4444, + 2387, 4514, 4448, 4441, 1634, 2821, 4426, 4431, 2797, 4498, + 2871, 2827, 2911, 2840, 2876, 2878, 3078, 2855, 4480, 4437, + 3194, 3144, 1324, 2805, 4405, 4374, 4402, 4377, 4403, 4374, + 2866, 4454, 2933, 2895, 3220, 2891, 2903, 2904, 3221, 2876, + + 4436, 4392, 4469, 3168, 1583, 2845, 4356, 4351, 4376, 4324, + 4350, 4325, 0, 2974, 2982, 0, 0, 0, 0, 0, + 0, 0, 3086, 4430, 4429, 4428, 3107, 3136, 2988, 2992, + 0, 2925, 3048, 3069, 3070, 3056, 4393, 3140, 1886, 2883, + 4318, 3008, 4326, 4311, 4308, 4315, 4308, 4326, 4399, 0, + 0, 3304, 3235, 3085, 4362, 3084, 3115, 3257, 4368, 4277, + 2467, 4348, 4281, 4273, 1796, 3057, 4270, 4273, 3100, 4340, + 3231, 3131, 3324, 3170, 3180, 3181, 3325, 3208, 4321, 4277, + 3419, 3395, 1909, 3033, 4245, 4243, 4243, 4218, 4243, 4214, + 3221, 3312, 3215, 4314, 2279, 3215, 3225, 3307, 3225, 3231, + + 3253, 3321, 3295, 3471, 3279, 4297, 4281, 3507, 3446, 3366, + 3455, 4278, 4206, 4222, 4206, 4209, 4214, 3257, 4170, 4165, + 4165, 3305, 3430, 3297, 4277, 2548, 3330, 3342, 3449, 3356, + 3438, 3352, 3509, 3371, 3577, 3441, 4260, 4243, 0, 3556, + 3593, 3598, 4242, 4166, 4179, 4162, 4166, 4170, 3320, 4140, + 4134, 4132, 0, 3205, 0, 3462, 4207, 3396, 3502, 4119, + 4114, 4116, 3584, 3626, 3644, 4098, 3652, 4209, 4206, 4201, + 3723, 3700, 3563, 170, 3492, 3570, 3636, 2343, 2530, 3594, + 499, 2320, 2163, 3336, 3080, 1020, 2783, 3520, 1487, 3635, + 3629, 3728, 3603, 3554, 3644, 3744, 3598, 2553, 1939, 2849, + + 3838, 3093, 3322, 1689, 2298, 1667, 2296, 1779, 2120, 3659, + 3513, 3667, 2934, 3517, 3689, 3662, 3741, 3673, 3725, 3699, + 3687, 3555, 3845, 3704, 3100, 2394, 4193, 3844, 3810, 3881, + 2383, 2465, 2858, 958, 1915, 1891, 3769, 2450, 2508, 2371, + 3637, 3784, 3800, 3737, 3743, 2795, 3147, 3706, 3751, 3865, + 3834, 3311, 3918, 3206, 2682, 2355, 3202, 3133, 3576, 3686, + 3785, 3847, 1547, 3419, 3583, 3802, 3896, 3253, 2830, 3798, + 4182, 4137, 3848, 3833, 3927, 3850, 4154, 4173, 4097, 4108, + 4079, 4048, 4037, 4035, 3356, 3237, 3424, 4031, 4028, 4018, + 4113, 7208, 3842, 4068, 3564, 4004, 3940, 3952, 3956, 3969, + + 3973, 3981, 3985, 3989, 3993, 4006, 4001, 4078, 0, 0, + 7208, 3976, 3658, 3865, 3793, 4069, 4013, 3864, 3870, 3855, + 4044, 4027, 4053, 4013, 3101, 3792, 3932, 3810, 3932, 3911, + 3909, 3900, 3872, 3891, 0, 0, 3871, 3926, 3830, 3826, + 3825, 4022, 4053, 4057, 3831, 3907, 3896, 0, 4062, 4051, + 4077, 3845, 4066, 4069, 0, 4078, 4106, 4121, 3758, 3747, + 3745, 4122, 4128, 4132, 3716, 4136, 3908, 3794, 3725, 3716, + 3698, 3973, 4128, 3706, 3715, 3710, 4132, 3968, 3639, 4155, + 4161, 4162, 4168, 4177, 4200, 4204, 4213, 4217, 4223, 4224, + 4231, 4232, 3627, 4066, 3670, 3591, 4240, 3589, 4099, 4278, + + 3674, 3621, 3529, 3500, 3487, 4251, 4308, 4360, 4259, 4414, + 4386, 4268, 4468, 4520, 3508, 3498, 3423, 4124, 4529, 4244, + 0, 4245, 3489, 3416, 3316, 3310, 4574, 4269, 4626, 4278, + 4680, 4314, 4635, 4369, 4734, 4423, 4786, 4469, 3273, 3236, + 4147, 4377, 3304, 3215, 4477, 3200, 4545, 4740, 4792, 4549, + 4796, 4813, 4562, 4817, 4821, 3179, 3167, 3118, 3101, 4882, + 4926, 4978, 5022, 5074, 5118, 3065, 3031, 3009, 2974, 5170, + 4531, 5198, 4586, 5197, 4689, 5225, 4693, 5277, 4697, 5305, + 4825, 2958, 2957, 2832, 2777, 4575, 4651, 4655, 2696, 2623, + 2560, 2527, 2486, 2469, 2427, 2355, 2339, 2267, 2188, 1889, + + 1850, 1758, 1487, 1444, 1382, 1351, 1208, 1162, 7208, 5358, + 5369, 5380, 5391, 5402, 5413, 5424, 5435, 5446, 5457, 5468, + 5472, 5483, 5494, 5505, 5516, 5527, 5538, 5549, 5560, 5571, + 5582, 5593, 5604, 5608, 5619, 5630, 5641, 5652, 5657, 5658, + 5663, 5674, 5685, 5696, 5707, 5718, 5729, 5740, 5751, 5762, + 5773, 5784, 5795, 5806, 1111, 5817, 5828, 5839, 5850, 5861, + 5872, 5883, 5894, 1062, 5896, 5907, 5918, 5929, 5940, 5951, + 5962, 5973, 5984, 5995, 6006, 6017, 6028, 6039, 6050, 6061, + 6072, 6083, 6094, 6105, 6116, 1033, 6118, 6129, 6140, 6151, + 6162, 6173, 6184, 6195, 6206, 6217, 6228, 6239, 6250, 6261, + + 6272, 6283, 6294, 6305, 6316, 6327, 6338, 6349, 6360, 6371, + 6382, 6393, 6404, 6415, 6426, 6437, 6448, 6459, 6470, 6481, + 6492, 6503, 6514, 6525, 6536, 6547, 6558, 6569, 6580, 6591, + 6602, 6613, 6624, 6635, 6646, 6657, 6668, 6679, 6690, 6701, + 6712, 6723, 6734, 6745, 6756, 6767, 6778, 6789, 6800, 6811, + 6822, 6833, 6844, 6855, 6866, 6877, 6888, 6899, 6910, 6921, + 6932, 6937, 6947, 6958, 6969, 6980, 6991, 7002, 7013, 7024, + 7035, 7046, 7057, 7068, 967, 7079, 7090, 7101, 7112, 7123, + 7134, 7141, 7151, 7156, 7160, 508, 502, 7170, 7181, 7192, + 7197, 195 + + } ; + +static const flex_int16_t yy_def[1593] = + { 0, + 1410, 1410, 1411, 1411, 1409, 5, 5, 5, 1412, 1412, + 1409, 11, 1409, 13, 1413, 1413, 1414, 1414, 1409, 19, + 1409, 21, 1409, 23, 1415, 1415, 1416, 1416, 1417, 1417, + 1410, 1410, 1418, 1418, 1419, 1419, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1420, 1409, 1409, 1409, 1409, 1409, 1421, + 1409, 1409, 1420, 1409, 51, 1409, 1409, 1409, 1422, 1409, + 1409, 1409, 1423, 1409, 1409, 1409, 1424, 1409, 1409, 1409, + 1409, 1409, 1425, 1409, 1409, 1426, 1409, 1409, 1427, 1409, + 1409, 1428, 1409, 1420, 1409, 1409, 1409, 1409, 1409, 1429, + 1409, 1429, 1429, 1409, 1409, 1409, 1430, 1431, 1409, 1431, + + 1409, 1409, 1409, 1409, 1409, 1432, 1432, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1433, 1409, 1409, 1409, 1409, + 1409, 51, 1420, 1409, 1409, 1409, 1409, 1434, 1409, 1409, + 1435, 1409, 1409, 1436, 1437, 1409, 1409, 1409, 1438, 1409, + 1409, 1409, 1439, 1440, 1441, 1409, 1409, 1409, 1409, 1409, + 1409, 1433, 1409, 121, 51, 1420, 1436, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1442, 1409, 1409, 1409, 1409, 1443, 1409, 1409, 1409, 1409, + 1409, 1444, 1409, 1445, 1409, 1446, 1409, 1447, 1409, 1409, + 1409, 1409, 1409, 1448, 1409, 1409, 1409, 1409, 1420, 1409, + + 1409, 1409, 1409, 1409, 1449, 1409, 1409, 1409, 1409, 1449, + 1409, 1409, 1450, 1451, 1450, 1451, 1450, 1452, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1453, 1453, 1453, + 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1409, 1409, 1409, + 1454, 1409, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1455, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1456, 1409, 1457, 1409, 1409, 1458, 1409, 1459, 1459, + 1459, 1459, 1459, 1459, 1459, 1459, 1409, 1460, 1461, 1409, + 1462, 1463, 1409, 1464, 1409, 1409, 1465, 1409, 1466, 1409, + + 1409, 1409, 1467, 1409, 1454, 1409, 1454, 1454, 1454, 1454, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1459, 1459, 1459, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1468, 1468, 1469, 1468, 1468, 1468, 1468, 1409, + 1409, 1470, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1470, 1471, 1472, 1472, 1473, 1473, 1473, 1474, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1475, 1476, 1476, 1476, + 1476, 1476, 1476, 1476, 1476, 1409, 1409, 1409, 1409, 1454, + + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1477, + 1454, 1454, 1454, 1478, 1479, 1454, 1454, 1454, 1454, 1454, + 1454, 421, 421, 421, 1454, 1454, 1454, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1480, 1409, + 1409, 1409, 1481, 1409, 1482, 1409, 1409, 1409, 1409, 1409, + 1409, 1483, 1484, 1485, 1409, 1486, 1487, 1488, 1489, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1490, 1454, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1491, 1491, 1491, 1491, 1491, 1491, 1491, 1492, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1492, 1493, 1494, 1494, 1495, 1495, 1495, 1409, 1496, + 1496, 1409, 1409, 1409, 1409, 1409, 1409, 1497, 1498, 1499, + 1500, 1501, 1502, 1503, 1409, 1454, 1504, 1454, 1454, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1505, + + 1454, 1454, 1454, 1506, 1454, 1507, 1454, 1508, 1508, 1508, + 1508, 1508, 1508, 1508, 1508, 1454, 1509, 1454, 1510, 1454, + 1454, 1454, 1454, 621, 1454, 1511, 1454, 1454, 1454, 1512, + 1409, 1513, 1514, 1515, 1409, 1409, 1409, 1409, 1409, 1516, + 1517, 1409, 1409, 1518, 1409, 1409, 1409, 1409, 1519, 1520, + 1409, 1409, 1521, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1522, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1523, + 1523, 1523, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1524, 1524, 1525, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1525, 1526, 1527, + 1528, 1529, 1528, 1529, 1528, 1528, 1528, 1528, 1528, 1528, + 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1530, 1531, 1532, 1533, 1534, + 1535, 1536, 1454, 1454, 1454, 1537, 1454, 1454, 1538, 1539, + 1540, 1454, 1454, 1454, 1454, 1454, 1541, 1542, 1454, 1454, + 1543, 1454, 1454, 1454, 1454, 1544, 1545, 1454, 1454, 1546, + 1454, 1454, 1454, 1454, 1454, 1454, 1547, 1548, 1454, 799, + + 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1409, + 1409, 1409, 1409, 1409, 1409, 1559, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1559, 1560, + 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, + 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, + 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, + 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, 1561, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1562, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1563, 1454, 1454, 1564, 1565, 1566, 1567, 1568, + 1569, 1570, 1454, 1454, 1454, 1454, 1571, 1454, 1409, 1409, + 1572, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1572, 1573, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, + 1574, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1575, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1576, 1571, 1577, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1578, 1579, 1580, 1409, 1409, 1577, 1581, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1582, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1575, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1582, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1153, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1583, 1409, 1409, 1409, 1409, 1409, 1579, 1578, 1578, 1578, + + 1579, 1579, 1579, 1580, 1580, 1580, 1409, 1409, 1581, 1581, + 1409, 1409, 1409, 1409, 1409, 1584, 1409, 1409, 1409, 1409, + 1409, 1409, 1585, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1583, 1583, 1409, 1409, 1409, 1409, + 1409, 1578, 1579, 1580, 1409, 1409, 1409, 1586, 1409, 1409, + 1409, 1409, 1409, 1409, 1587, 1409, 1409, 1409, 1409, 1409, + 1409, 1588, 1589, 1590, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1584, 1409, 1409, 1409, 1585, 1409, 1409, 1589, + 1588, 1588, 1588, 1588, 1589, 1589, 1589, 1589, 1590, 1590, + 1590, 1590, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1591, 1409, 1409, 1409, 1409, 1588, 1588, 1588, 1589, 1589, + 1589, 1590, 1590, 1590, 1409, 1409, 1409, 1409, 1409, 1409, + 1592, 1409, 1409, 1409, 1409, 1409, 1588, 1588, 1588, 1588, + 1589, 1589, 1589, 1589, 1590, 1590, 1590, 1590, 1409, 1409, + 1409, 1591, 1409, 1409, 1409, 1409, 1307, 1588, 1588, 1310, + 1589, 1589, 1313, 1590, 1590, 1409, 1409, 1409, 1409, 1588, + 1307, 1589, 1310, 1590, 1313, 1409, 1409, 1409, 1409, 1588, + 1588, 1327, 1588, 1589, 1589, 1331, 1589, 1590, 1590, 1335, + 1590, 1409, 1409, 1409, 1409, 1361, 1363, 1365, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 0, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409 + + } ; + +static const flex_int16_t yy_nxt[7335] = + { 0, + 1409, 1409, 40, 41, 40, 41, 42, 43, 44, 45, + 43, 42, 42, 42, 42, 42, 46, 47, 42, 42, + 42, 48, 49, 46, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 42, + 51, 42, 42, 42, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 52, 53, 54, 52, 52, 53, 54, 52, + 69, 57, 57, 83, 84, 85, 83, 42, 91, 92, + 93, 42, 83, 84, 85, 83, 1409, 86, 87, 58, + 58, 91, 92, 93, 95, 95, 86, 87, 99, 100, + 408, 96, 96, 99, 100, 70, 1211, 126, 97, 97, + 126, 71, 546, 72, 547, 55, 59, 59, 162, 55, + 456, 162, 103, 104, 105, 103, 88, 157, 89, 457, + + 177, 106, 158, 177, 1342, 88, 70, 89, 107, 892, + 173, 174, 71, 175, 72, 201, 202, 60, 60, 61, + 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 61, 61, 61, 61, 61, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 64, 64, 64, 65, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 66, 64, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 64, 64, + + 64, 64, 64, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 69, 109, 110, 110, 109, 388, 479, 479, 115, + 116, 117, 115, 388, 305, 490, 111, 112, 118, 119, + 200, 200, 200, 200, 120, 121, 163, 164, 165, 166, + + 167, 168, 169, 219, 220, 1211, 70, 206, 207, 208, + 206, 1277, 71, 469, 72, 226, 227, 1273, 221, 103, + 224, 225, 103, 106, 470, 113, 103, 104, 105, 103, + 107, 126, 122, 126, 126, 106, 126, 70, 276, 509, + 509, 276, 107, 71, 905, 72, 74, 74, 74, 75, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 74, + + 74, 74, 74, 74, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 77, 77, 77, 78, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 77, 77, 77, 77, 77, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 80, 80, + + 80, 81, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 80, 80, 80, 80, 80, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 110, 123, 110, 110, 276, 271, + 288, 276, 532, 272, 130, 149, 273, 130, 149, 112, + 130, 239, 151, 152, 153, 151, 238, 189, 130, 111, + 189, 118, 119, 193, 194, 195, 193, 290, 154, 1409, + 290, 190, 191, 532, 1211, 302, 291, 214, 302, 885, + 215, 886, 289, 1409, 303, 1409, 1178, 112, 129, 129, + 130, 129, 131, 131, 132, 129, 133, 134, 150, 135, + 150, 130, 136, 137, 130, 155, 327, 196, 1409, 327, + + 192, 322, 323, 324, 325, 130, 197, 130, 198, 216, + 109, 110, 110, 109, 138, 130, 328, 1409, 217, 328, + 304, 305, 306, 304, 111, 112, 1211, 406, 329, 139, + 140, 329, 598, 141, 129, 138, 129, 129, 142, 143, + 216, 138, 295, 330, 144, 138, 330, 145, 146, 129, + 407, 129, 147, 130, 129, 138, 148, 138, 229, 129, + 129, 130, 1182, 113, 130, 230, 110, 110, 110, 110, + 231, 486, 130, 150, 232, 233, 234, 331, 235, 457, + 331, 112, 240, 241, 242, 240, 244, 116, 245, 244, + 506, 332, 620, 236, 332, 246, 247, 112, 219, 220, + + 333, 248, 249, 333, 548, 549, 237, 110, 116, 110, + 110, 219, 220, 221, 115, 116, 117, 115, 177, 112, + 466, 177, 112, 118, 119, 177, 221, 911, 177, 120, + 121, 575, 575, 394, 149, 113, 394, 149, 1409, 250, + 278, 278, 278, 278, 278, 278, 278, 278, 111, 708, + 342, 280, 271, 342, 157, 281, 272, 282, 283, 158, + 112, 251, 252, 284, 251, 191, 396, 122, 285, 396, + 458, 286, 326, 458, 300, 326, 300, 253, 301, 301, + 301, 301, 301, 301, 301, 301, 301, 150, 254, 534, + 322, 323, 324, 325, 255, 256, 1409, 535, 257, 459, + + 258, 709, 259, 192, 260, 261, 262, 1409, 263, 465, + 264, 460, 465, 662, 124, 200, 200, 200, 200, 265, + 534, 266, 484, 267, 311, 312, 268, 313, 535, 314, + 400, 269, 307, 152, 308, 307, 270, 315, 316, 1409, + 189, 246, 247, 189, 317, 471, 471, 472, 309, 151, + 152, 153, 151, 408, 190, 191, 280, 1258, 118, 119, + 318, 350, 282, 319, 203, 154, 587, 203, 320, 340, + 340, 340, 340, 285, 1409, 588, 286, 344, 345, 346, + 344, 350, 1409, 397, 341, 310, 398, 193, 194, 195, + 193, 399, 350, 192, 200, 200, 200, 200, 351, 351, + + 351, 351, 155, 206, 353, 354, 206, 206, 207, 208, + 206, 387, 350, 377, 387, 251, 252, 192, 251, 226, + 227, 347, 355, 356, 357, 355, 387, 106, 1408, 387, + 348, 196, 349, 380, 107, 381, 396, 710, 711, 396, + 197, 378, 198, 595, 382, 388, 383, 276, 384, 358, + 276, 1409, 378, 389, 388, 385, 359, 360, 378, 388, + 361, 362, 392, 363, 578, 392, 1409, 364, 449, 389, + 388, 449, 378, 392, 1409, 390, 392, 450, 577, 392, + 461, 386, 392, 378, 450, 429, 1409, 365, 429, 378, + 1012, 582, 290, 392, 462, 290, 392, 240, 241, 242, + + 240, 291, 450, 510, 392, 511, 510, 392, 511, 1409, + 392, 450, 112, 392, 401, 241, 402, 401, 110, 241, + 110, 110, 404, 110, 401, 404, 599, 302, 1409, 403, + 302, 449, 512, 112, 449, 512, 303, 403, 491, 366, + 367, 368, 1013, 369, 513, 370, 371, 513, 1407, 586, + 113, 401, 116, 401, 401, 794, 794, 514, 452, 450, + 514, 304, 305, 306, 304, 463, 403, 403, 1409, 1409, + 450, 112, 453, 626, 452, 405, 463, 1059, 463, 1409, + 454, 449, 463, 326, 449, 327, 326, 328, 327, 463, + 328, 329, 600, 1211, 329, 463, 463, 330, 331, 332, + + 330, 331, 332, 601, 403, 409, 252, 463, 409, 463, + 691, 1409, 1409, 463, 150, 450, 333, 474, 1023, 333, + 463, 410, 387, 489, 450, 387, 463, 340, 340, 340, + 340, 400, 411, 340, 340, 340, 340, 484, 412, 413, + 342, 691, 414, 342, 415, 925, 416, 666, 417, 418, + 419, 665, 420, 1211, 421, 191, 502, 522, 406, 387, + 522, 503, 387, 422, 1406, 423, 569, 424, 570, 569, + 425, 570, 523, 604, 1409, 426, 344, 345, 346, 344, + 427, 129, 428, 429, 428, 430, 430, 431, 432, 433, + 434, 914, 435, 192, 525, 436, 437, 429, 301, 301, + + 301, 301, 301, 301, 301, 301, 301, 1405, 571, 572, + 524, 571, 572, 573, 525, 574, 573, 438, 574, 1409, + 347, 351, 351, 351, 351, 525, 907, 396, 908, 348, + 396, 349, 449, 439, 1409, 449, 440, 428, 438, 428, + 428, 441, 442, 632, 438, 525, 632, 443, 438, 1043, + 444, 445, 428, 668, 428, 446, 429, 428, 438, 447, + 438, 1232, 428, 428, 429, 409, 252, 1409, 409, 558, + 559, 558, 558, 1211, 557, 579, 1409, 767, 579, 409, + 252, 410, 409, 914, 696, 401, 110, 401, 401, 536, + 702, 492, 493, 537, 494, 1211, 495, 538, 412, 413, + + 403, 1044, 414, 539, 496, 497, 416, 1409, 417, 418, + 419, 498, 420, 669, 421, 696, 579, 1409, 406, 579, + 540, 702, 703, 422, 537, 423, 1409, 424, 538, 449, + 425, 985, 449, 986, 539, 426, 429, 1409, 403, 429, + 427, 129, 428, 429, 428, 430, 430, 431, 432, 433, + 499, 633, 435, 703, 633, 500, 437, 429, 1049, 704, + 401, 241, 401, 401, 596, 819, 819, 596, 404, 110, + 401, 404, 1409, 618, 1409, 403, 618, 438, 634, 541, + 488, 634, 619, 403, 400, 1211, 602, 602, 603, 491, + 704, 635, 636, 439, 635, 636, 440, 428, 438, 428, + + 428, 441, 442, 637, 438, 1409, 637, 443, 438, 1047, + 444, 445, 428, 403, 428, 446, 429, 428, 438, 447, + 438, 405, 428, 428, 429, 355, 529, 530, 355, 488, + 1409, 827, 429, 926, 355, 529, 530, 355, 458, 576, + 588, 458, 589, 1409, 408, 589, 429, 531, 356, 357, + 531, 667, 358, 580, 1409, 638, 580, 1404, 638, 359, + 360, 358, 827, 361, 362, 1409, 363, 1051, 359, 360, + 364, 590, 361, 362, 358, 363, 831, 580, 1409, 364, + 580, 359, 360, 591, 812, 361, 362, 581, 363, 693, + 365, 581, 364, 1104, 592, 1105, 581, 1211, 581, 365, + + 629, 1409, 881, 629, 583, 429, 693, 831, 593, 630, + 1409, 449, 365, 429, 449, 882, 631, 489, 584, 639, + 583, 1211, 639, 702, 1409, 927, 585, 607, 607, 607, + 607, 607, 607, 607, 607, 640, 641, 1409, 640, 641, + 887, 888, 366, 367, 368, 1211, 369, 1403, 370, 371, + 581, 366, 367, 368, 702, 369, 594, 370, 371, 642, + 643, 581, 642, 643, 366, 367, 368, 594, 369, 594, + 370, 371, 609, 594, 644, 1131, 610, 644, 611, 612, + 594, 1058, 645, 1184, 613, 645, 594, 594, 646, 614, + 650, 646, 615, 650, 647, 1059, 651, 647, 594, 651, + + 594, 1409, 1409, 652, 594, 1409, 652, 654, 605, 1402, + 654, 594, 648, 1183, 627, 903, 627, 594, 628, 628, + 628, 628, 628, 628, 628, 628, 628, 1132, 904, 1038, + 597, 597, 597, 597, 597, 597, 597, 597, 597, 597, + 597, 597, 597, 597, 597, 597, 597, 597, 597, 597, + 597, 597, 597, 597, 597, 597, 621, 655, 656, 648, + 655, 656, 909, 910, 622, 622, 622, 622, 673, 914, + 914, 673, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, 623, 623, + + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 675, 676, 1211, 675, 676, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 624, 677, 678, 679, 677, + 678, 679, 680, 510, 511, 680, 510, 511, 702, 1211, + 702, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 580, 1409, 702, + + 580, 702, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 1409, 609, + 429, 581, 1052, 670, 512, 611, 671, 512, 1409, 513, + 581, 672, 513, 834, 429, 514, 614, 684, 514, 615, + 684, 686, 522, 693, 686, 522, 688, 340, 688, 688, + 526, 571, 656, 526, 571, 656, 685, 523, 839, 702, + 635, 689, 663, 635, 834, 636, 694, 664, 636, 906, + 531, 529, 530, 531, 693, 579, 1409, 943, 579, 531, + 529, 530, 531, 637, 580, 1409, 637, 580, 763, 768, + + 702, 764, 1211, 429, 1211, 524, 765, 358, 1401, 638, + 697, 429, 638, 524, 359, 360, 358, 697, 361, 362, + 837, 363, 698, 359, 360, 364, 1211, 361, 362, 698, + 363, 699, 869, 639, 364, 700, 639, 705, 699, 695, + 537, 697, 701, 580, 1409, 365, 580, 642, 697, 1211, + 642, 837, 705, 698, 365, 769, 1409, 537, 769, 1400, + 698, 1211, 699, 869, 580, 1409, 701, 580, 1112, 699, + 901, 770, 1409, 701, 770, 771, 1409, 1211, 771, 772, + 1409, 833, 772, 773, 1409, 1112, 773, 774, 1409, 1211, + 774, 589, 1409, 643, 589, 834, 643, 366, 367, 368, + + 1211, 369, 645, 370, 371, 645, 366, 367, 368, 871, + 369, 1050, 370, 371, 723, 559, 723, 723, 1048, 724, + 775, 1409, 1033, 775, 776, 1409, 834, 776, 777, 1409, + 749, 777, 778, 1409, 1033, 778, 779, 1409, 1399, 779, + 871, 725, 780, 1409, 646, 780, 1224, 646, 726, 727, + 981, 647, 728, 729, 647, 730, 1211, 781, 1409, 731, + 781, 782, 1409, 982, 782, 783, 1409, 732, 783, 784, + 1409, 1211, 784, 787, 1409, 1398, 787, 788, 1409, 733, + 788, 789, 1409, 1409, 789, 791, 1409, 785, 791, 618, + 1409, 647, 618, 651, 647, 1190, 651, 872, 619, 628, + + 628, 628, 628, 628, 628, 628, 628, 628, 629, 1409, + 652, 629, 654, 652, 1211, 654, 655, 630, 656, 655, + 891, 656, 811, 1409, 893, 811, 813, 1409, 872, 813, + 1100, 734, 735, 736, 785, 737, 1211, 738, 739, 559, + 559, 559, 559, 1101, 740, 814, 1409, 1397, 814, 815, + 1409, 891, 815, 816, 1409, 893, 816, 817, 1409, 1211, + 817, 818, 1409, 1396, 818, 673, 741, 820, 673, 675, + 820, 1188, 675, 742, 743, 1043, 676, 744, 745, 676, + 746, 1258, 677, 678, 747, 677, 678, 679, 680, 894, + 679, 680, 748, 822, 684, 824, 822, 684, 824, 686, + + 825, 1037, 686, 825, 749, 688, 340, 688, 688, 688, + 340, 688, 688, 828, 829, 830, 828, 702, 932, 1395, + 894, 702, 828, 829, 830, 828, 915, 1409, 702, 915, + 702, 772, 1409, 1189, 772, 773, 1409, 1024, 773, 774, + 1409, 702, 774, 775, 1409, 935, 775, 902, 702, 932, + 776, 1409, 702, 776, 1024, 936, 750, 751, 752, 702, + 753, 702, 754, 755, 1409, 843, 779, 1409, 843, 779, + 780, 1409, 702, 780, 782, 1409, 935, 782, 783, 1409, + 1394, 783, 784, 1409, 820, 784, 936, 820, 1211, 799, + 799, 799, 799, 799, 799, 799, 799, 799, 799, 799, + + 799, 799, 799, 799, 799, 799, 799, 799, 799, 799, + 799, 799, 799, 799, 799, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 784, 1409, 1393, 784, 1223, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 828, 829, 830, 828, 788, 1409, 969, 788, + 789, 1409, 929, 789, 873, 929, 844, 845, 874, 1211, + 791, 1409, 875, 791, 923, 1409, 971, 923, 876, 835, + + 725, 1211, 836, 811, 1409, 1218, 811, 726, 727, 969, + 822, 728, 729, 822, 730, 877, 1392, 930, 731, 874, + 930, 928, 1409, 875, 928, 824, 732, 971, 824, 876, + 835, 941, 942, 836, 852, 559, 852, 852, 733, 853, + 741, 813, 1409, 825, 813, 972, 825, 742, 743, 991, + 933, 744, 745, 933, 746, 1211, 814, 1409, 747, 814, + 1039, 854, 815, 1409, 1211, 815, 748, 996, 855, 856, + 944, 945, 857, 858, 878, 859, 972, 1391, 749, 860, + 991, 895, 912, 816, 1409, 896, 816, 861, 1002, 897, + 734, 735, 736, 1216, 737, 898, 738, 739, 996, 862, + + 817, 1409, 993, 817, 818, 1409, 1217, 818, 828, 829, + 830, 828, 899, 987, 988, 1003, 896, 1004, 1022, 1002, + 897, 828, 829, 830, 828, 994, 898, 1014, 1015, 1390, + 750, 751, 752, 993, 753, 1027, 754, 755, 997, 1033, + 1211, 1005, 1034, 1035, 974, 1171, 1003, 1181, 1004, 1022, + 998, 863, 864, 865, 1056, 866, 1005, 867, 868, 999, + 702, 974, 1036, 1000, 1024, 896, 1027, 1045, 1046, 997, + 1033, 900, 1409, 1034, 1035, 923, 1409, 1036, 923, 1060, + 1061, 998, 896, 915, 1409, 1056, 915, 1025, 995, 929, + 999, 702, 929, 930, 1001, 1024, 930, 622, 622, 622, + + 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 933, + 1026, 1389, 933, 1059, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, + 952, 559, 952, 952, 954, 953, 1211, 923, 1409, 973, + 923, 955, 956, 974, 1385, 957, 958, 975, 959, 1211, + + 693, 702, 960, 976, 702, 997, 1211, 954, 400, 810, + 961, 400, 1062, 945, 955, 956, 1088, 998, 957, 958, + 977, 959, 962, 1090, 974, 960, 999, 1177, 975, 1384, + 1001, 693, 702, 961, 976, 702, 997, 928, 1409, 1211, + 928, 828, 829, 830, 828, 962, 1091, 1088, 998, 1106, + 1107, 1383, 1110, 1211, 1090, 1133, 1134, 999, 1010, 1043, + 1010, 1001, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011, + 1011, 1115, 909, 910, 963, 964, 965, 1091, 966, 978, + 967, 968, 1041, 1110, 1041, 1382, 1042, 1042, 1042, 1042, + 1042, 1042, 1042, 1042, 1042, 1023, 1257, 963, 964, 965, + + 1369, 966, 1115, 967, 968, 1008, 400, 810, 1211, 400, + 1258, 1044, 1211, 1009, 1009, 1009, 1009, 1368, 1121, 1122, + 1123, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 1009, 1009, 1009, 1009, 1028, 1028, 1121, + 1122, 1123, 1141, 1225, 1215, 1145, 1121, 1215, 1160, 1029, + 1029, 1160, 1112, 1073, 1121, 1121, 1147, 1367, 1030, 1030, + 1074, 1075, 1031, 1032, 1076, 1077, 1366, 1078, 1028, 1028, + 1148, 1079, 1222, 1141, 1092, 1113, 1145, 1121, 1093, 1080, + 1029, 1029, 1094, 1112, 1124, 1121, 1121, 1093, 1095, 1030, + + 1030, 1081, 1148, 1032, 1032, 1071, 559, 1071, 1071, 1124, + 1072, 1148, 1224, 1142, 1093, 1096, 1142, 1211, 1143, 1093, + 1359, 1185, 1142, 1094, 1185, 1142, 1181, 1143, 1211, 1095, + 1121, 1151, 1073, 1148, 1121, 1358, 1166, 1170, 1121, 1074, + 1075, 1221, 1211, 1076, 1077, 1229, 1078, 1121, 1114, 1033, + 1079, 1116, 1116, 1082, 1083, 1084, 1357, 1085, 1080, 1086, + 1087, 1121, 1151, 1117, 1117, 1121, 1144, 1166, 1170, 1121, + 1081, 1033, 1118, 1118, 1097, 1144, 1119, 1120, 1121, 1161, + 1162, 1033, 1116, 1116, 1130, 1130, 1130, 1130, 1130, 1130, + 1130, 1130, 1130, 1356, 1117, 1117, 1033, 828, 829, 830, + + 828, 1173, 1033, 1118, 1118, 1346, 1033, 1120, 1120, 1129, + 1345, 1129, 1033, 1130, 1130, 1130, 1130, 1130, 1130, 1130, + 1130, 1130, 1082, 1083, 1084, 1211, 1085, 1033, 1086, 1087, + 1127, 1167, 1173, 907, 1167, 908, 1168, 1033, 1128, 1128, + 1128, 1128, 1186, 1187, 1045, 1046, 1128, 1128, 1128, 1128, + 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, + 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128, + 1128, 1128, 1142, 1172, 1073, 1142, 1033, 1143, 1227, 1228, + 1033, 1074, 1075, 1073, 1169, 1076, 1077, 1173, 1078, 1033, + 1074, 1075, 1079, 1176, 1076, 1077, 1193, 1078, 1211, 1149, + + 1154, 1079, 1150, 828, 829, 830, 828, 1033, 1344, 1155, + 1167, 1033, 1081, 1167, 1167, 1168, 1343, 1167, 1173, 1213, + 1033, 1081, 1340, 1211, 1176, 1144, 1211, 1193, 1230, 1231, + 1149, 893, 1233, 1150, 1153, 1153, 1153, 1153, 1153, 1153, + 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, + 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153, + 1211, 1211, 893, 1169, 1082, 1083, 1084, 1169, 1085, 1211, + 1086, 1087, 1022, 1082, 1083, 1084, 1211, 1085, 1167, 1086, + 1087, 1167, 1211, 1168, 741, 1199, 829, 1200, 1199, 1211, + 1033, 742, 743, 1034, 891, 744, 745, 1339, 746, 1264, + + 1211, 894, 747, 1022, 1211, 1174, 1024, 1326, 1175, 1211, + 1179, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1042, + 1325, 1033, 749, 1024, 1034, 891, 741, 1202, 829, 1203, + 1202, 1169, 894, 742, 743, 1211, 1174, 744, 745, 1175, + 746, 1211, 1211, 1211, 747, 1205, 829, 1206, 1205, 1324, + 1211, 1033, 1180, 828, 829, 830, 828, 903, 1239, 1215, + 1323, 1240, 1215, 895, 749, 1211, 1024, 896, 1211, 1027, + 904, 897, 1214, 1211, 750, 751, 752, 898, 753, 1211, + 754, 755, 1033, 1035, 1036, 1321, 1234, 896, 1167, 1025, + 1166, 1167, 1211, 1213, 899, 1211, 1226, 1024, 896, 1036, + + 1027, 1033, 897, 1214, 896, 1211, 1211, 1170, 898, 1317, + 1211, 1316, 1211, 1033, 1035, 702, 750, 751, 752, 1315, + 753, 1166, 754, 755, 559, 559, 559, 559, 741, 1212, + 1033, 1211, 1033, 1033, 1211, 742, 743, 1305, 1170, 744, + 745, 1169, 746, 1211, 1033, 1302, 747, 1211, 1173, 1211, + 1211, 741, 1026, 900, 748, 1028, 1176, 1211, 742, 743, + 1172, 1033, 744, 745, 1033, 746, 749, 1029, 1033, 747, + 1185, 1028, 1033, 1185, 1173, 1211, 1030, 748, 1301, 1173, + 1031, 1033, 1300, 1029, 1033, 1167, 1028, 1176, 1167, 749, + 1213, 1211, 1030, 1298, 1215, 1219, 1032, 1215, 1029, 1033, + + 1216, 1215, 1028, 1033, 1215, 1173, 1211, 1030, 1227, 1228, + 1297, 1032, 1033, 1217, 1029, 1033, 1211, 1296, 750, 751, + 752, 1295, 753, 1030, 754, 755, 1219, 1032, 1042, 1042, + 1042, 1042, 1042, 1042, 1042, 1042, 1042, 1214, 1293, 1033, + 1211, 750, 751, 752, 1211, 753, 1167, 754, 755, 1167, + 1211, 1213, 1041, 1211, 1041, 1280, 1042, 1042, 1042, 1042, + 1042, 1042, 1042, 1042, 1042, 1220, 1167, 1279, 1214, 1167, + 1033, 1213, 741, 1174, 1181, 1033, 1175, 1219, 1278, 742, + 743, 1220, 1237, 744, 745, 1276, 746, 1211, 1259, 1260, + 747, 1186, 1187, 1229, 1247, 1024, 1220, 1167, 1179, 1169, + + 1167, 1033, 1168, 1033, 1174, 1033, 1033, 1175, 1219, 741, + 749, 1246, 1220, 1237, 1261, 1231, 742, 743, 1267, 1169, + 744, 745, 1065, 746, 1211, 1247, 1024, 747, 1167, 1409, + 1272, 1167, 1033, 1168, 1033, 1180, 1033, 1409, 1409, 1409, + 1409, 1202, 829, 1203, 1202, 1271, 1270, 749, 1294, 1267, + 1269, 1230, 1231, 1242, 829, 1200, 1242, 1242, 829, 1200, + 1242, 1272, 750, 751, 752, 1268, 753, 1033, 754, 755, + 1242, 829, 1200, 1242, 1243, 829, 1203, 1243, 1266, 1294, + 1266, 1169, 1243, 829, 1203, 1243, 1243, 829, 1203, 1243, + 1244, 829, 1206, 1244, 1244, 829, 1206, 1244, 1033, 750, + + 751, 752, 1265, 753, 741, 754, 755, 1244, 829, 1206, + 1244, 742, 743, 1299, 1167, 744, 745, 1167, 746, 1168, + 1264, 1263, 747, 1242, 829, 1200, 1242, 1250, 1262, 1250, + 748, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1229, 1253, 749, 1253, 1299, 1254, 1254, 1254, 1254, 1254, + 1254, 1254, 1254, 1254, 1243, 829, 1203, 1243, 1244, 829, + 1206, 1244, 1303, 1167, 1255, 1304, 1167, 1169, 1168, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1167, 1252, + 1248, 1167, 1246, 1168, 1254, 1254, 1254, 1254, 1254, 1254, + 1254, 1254, 1254, 1245, 750, 751, 752, 741, 753, 702, + + 754, 755, 1241, 1238, 742, 743, 741, 1167, 744, 745, + 1167, 746, 1168, 742, 743, 747, 1274, 744, 745, 1236, + 746, 1234, 1167, 1282, 747, 1167, 1282, 1168, 1283, 1286, + 702, 1275, 1286, 1290, 1287, 749, 1290, 1167, 1291, 1409, + 1167, 1233, 1168, 1409, 749, 1232, 1318, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1226, 1286, 1225, 1224, 1286, + 1169, 1287, 1306, 1306, 1341, 1306, 1306, 1283, 1283, 1306, + 1224, 1223, 1306, 1222, 1283, 1169, 1284, 1318, 1306, 1409, + 1033, 1306, 1288, 1283, 1221, 1023, 1292, 750, 751, 752, + 1169, 753, 1218, 754, 755, 1341, 750, 751, 752, 1211, + + 753, 1309, 754, 755, 1309, 1309, 1287, 1211, 1309, 1288, + 1287, 1033, 1210, 1208, 1309, 1284, 1284, 1309, 1309, 1287, + 1207, 1309, 1284, 1287, 1312, 1312, 1197, 1312, 1312, 1291, + 1291, 1284, 1312, 1312, 1196, 1312, 1312, 1291, 1291, 1195, + 1307, 828, 829, 830, 828, 1167, 1167, 1194, 1167, 1167, + 1168, 1168, 1306, 1308, 1288, 1306, 1190, 1283, 1288, 1189, + 1309, 1188, 1184, 1309, 1183, 1287, 1182, 1288, 1181, 1312, + 1306, 1288, 1312, 1306, 1291, 1283, 1043, 1292, 1292, 1306, + 1310, 1033, 1306, 1033, 1283, 1292, 1292, 1177, 1171, 1165, + 1164, 1163, 1319, 1311, 1319, 1313, 1320, 1320, 1320, 1320, + + 1320, 1320, 1320, 1320, 1320, 1284, 1159, 1158, 1314, 1306, + 1157, 1156, 1306, 1288, 1283, 1309, 1131, 1121, 1309, 1327, + 1287, 1121, 1292, 1348, 1152, 1146, 1140, 1328, 1328, 1328, + 1328, 1139, 1349, 1138, 1137, 1328, 1328, 1328, 1328, 1328, + 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, + 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, 1328, + 1328, 1306, 1284, 1136, 1306, 1135, 1283, 1126, 1351, 1125, + 1309, 1111, 1109, 1309, 1329, 1287, 1329, 1108, 1330, 1330, + 1330, 1330, 1330, 1330, 1330, 1330, 1330, 1309, 1409, 1103, + 1309, 1081, 1287, 1102, 1099, 1098, 1409, 1409, 1409, 1409, + + 1333, 1089, 1333, 1068, 1334, 1334, 1334, 1334, 1334, 1334, + 1334, 1334, 1334, 1067, 1284, 1309, 1067, 1066, 1309, 1065, + 1287, 1064, 1063, 1352, 1312, 1331, 943, 1312, 1057, 1291, + 1409, 1409, 1409, 1332, 1332, 1332, 1332, 1052, 1051, 1050, + 1288, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, + 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1049, 1288, 1312, + 1312, 1048, 1312, 1312, 1291, 1291, 1047, 1354, 1167, 1335, + 1039, 1167, 1038, 1168, 1037, 1023, 1021, 1336, 1336, 1336, + 1336, 1020, 1019, 1018, 1017, 1336, 1336, 1336, 1336, 1336, + + 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, 1336, + 1336, 1312, 1292, 1355, 1312, 1016, 1291, 1007, 1006, 992, + 990, 1169, 1306, 989, 1337, 1306, 1337, 1283, 1338, 1338, + 1338, 1338, 1338, 1338, 1338, 1338, 1338, 1320, 1320, 1320, + 1320, 1320, 1320, 1320, 1320, 1320, 1281, 984, 962, 983, + 1285, 980, 979, 970, 1281, 1281, 1281, 1281, 1285, 1285, + 1285, 1285, 949, 1289, 1292, 1306, 948, 947, 1306, 946, + 1283, 1289, 1289, 1289, 1289, 1349, 1281, 1306, 940, 939, + 1306, 938, 1283, 938, 1281, 1281, 1281, 1281, 937, 692, + + 934, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, + 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1347, + 1347, 1347, 1347, 1347, 1347, 1347, 1347, 1306, 1284, 829, + 1306, 1409, 1283, 1409, 1409, 1409, 1309, 1409, 1409, 1309, + 1348, 1287, 912, 911, 1330, 1330, 1330, 1330, 1330, 1330, + 1330, 1330, 1330, 1334, 1334, 1334, 1334, 1334, 1334, 1334, + 1334, 1334, 1285, 906, 749, 905, 1289, 902, 901, 892, + 1285, 1285, 1285, 1285, 1289, 1289, 1289, 1289, 890, 889, + 1284, 1309, 884, 862, 1309, 883, 1287, 880, 879, 1288, + 1309, 870, 849, 1309, 1309, 1287, 848, 1309, 1312, 1287, + + 847, 1312, 846, 1291, 842, 841, 840, 1350, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1350, 1350, 1350, 839, 1288, 1312, 708, 702, 1312, 702, + 1291, 1306, 838, 1352, 1306, 832, 1283, 1351, 823, 821, + 819, 1355, 819, 657, 1409, 1409, 1409, 1409, 1409, 1409, + 796, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, + 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1353, + 1353, 1353, 1353, 1353, 1353, 1353, 1353, 1312, 1292, 796, + 1312, 794, 1291, 1306, 1284, 794, 1306, 1309, 1283, 795, + + 1309, 793, 1287, 1307, 1338, 1338, 1338, 1338, 1338, 1338, + 1338, 1338, 1338, 1409, 1309, 757, 1360, 1309, 1312, 1287, + 757, 1312, 1312, 1291, 722, 1312, 1312, 1291, 722, 1312, + 720, 1291, 720, 718, 717, 716, 715, 714, 713, 712, + 1292, 707, 706, 692, 529, 526, 1284, 687, 683, 682, + 1288, 681, 674, 1409, 305, 1361, 661, 660, 477, 1310, + 659, 1409, 1409, 1409, 617, 1409, 1409, 1288, 1308, 1409, + 448, 1292, 1362, 1409, 575, 1292, 1363, 575, 567, 1354, + 1313, 566, 565, 1306, 1365, 564, 1306, 563, 1283, 1311, + 562, 561, 557, 1364, 557, 555, 1370, 1314, 1370, 555, + + 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1371, 552, + 551, 550, 545, 365, 544, 543, 542, 533, 356, 353, + 527, 526, 345, 520, 519, 518, 517, 516, 515, 509, + 509, 508, 507, 505, 504, 501, 1284, 1372, 152, 305, + 481, 481, 479, 479, 480, 1373, 1373, 1373, 1373, 478, + 476, 288, 473, 1373, 1373, 1373, 1373, 1373, 1373, 1373, + 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, + 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1373, 1309, + 468, 467, 1309, 464, 1287, 455, 451, 448, 1409, 395, + 393, 391, 1374, 226, 1374, 224, 1375, 1375, 1375, 1375, + + 1375, 1375, 1375, 1375, 1375, 219, 379, 375, 377, 375, + 373, 372, 207, 201, 204, 203, 194, 203, 339, 338, + 337, 336, 335, 334, 321, 152, 299, 297, 294, 293, + 275, 274, 1288, 1376, 238, 125, 124, 238, 104, 223, + 222, 1377, 1377, 1377, 1377, 212, 211, 210, 209, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, 1377, + 1377, 1377, 1377, 1377, 1377, 1312, 204, 203, 1312, 199, + 1291, 187, 185, 183, 181, 180, 179, 178, 1378, 172, + 1378, 170, 1379, 1379, 1379, 1379, 1379, 1379, 1379, 1379, + + 1379, 160, 159, 156, 127, 125, 124, 108, 1409, 102, + 102, 38, 38, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1292, 1380, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1381, 1381, 1381, + 1381, 1409, 1409, 1409, 1409, 1381, 1381, 1381, 1381, 1381, + 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, + 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, 1381, + 1381, 1306, 1409, 1409, 1306, 1409, 1283, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1371, 1371, + 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1409, 1309, 1409, + + 1409, 1309, 1409, 1287, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1375, 1375, 1375, 1375, 1375, + 1375, 1375, 1375, 1375, 1284, 1386, 1386, 1386, 1386, 1386, + 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, + 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, 1386, + 1386, 1288, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, + 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, + 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1387, 1312, 1409, + 1409, 1312, 1409, 1291, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1379, 1379, 1379, 1379, 1379, + + 1379, 1379, 1379, 1379, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1292, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, + 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, + 1388, 1388, 1388, 1388, 1388, 1388, 1388, 1388, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 68, 68, 68, 68, 68, 68, 68, 68, 68, + + 68, 68, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 128, + 128, 128, 128, 161, 161, 1409, 161, 161, 161, 161, + 161, 161, 161, 161, 171, 1409, 1409, 1409, 171, 171, + + 171, 171, 171, 171, 171, 176, 176, 1409, 1409, 176, + 176, 176, 176, 176, 176, 176, 182, 182, 1409, 182, + 182, 182, 182, 182, 182, 182, 182, 184, 1409, 1409, + 1409, 184, 184, 184, 184, 184, 184, 184, 186, 1409, + 1409, 1409, 186, 186, 186, 186, 186, 186, 186, 188, + 1409, 1409, 1409, 188, 188, 188, 188, 188, 188, 188, + 205, 205, 1409, 205, 205, 205, 205, 205, 205, 205, + 205, 213, 213, 1409, 213, 213, 213, 213, 213, 213, + 213, 213, 218, 218, 1409, 218, 218, 218, 218, 218, + 218, 218, 218, 228, 228, 1409, 228, 228, 228, 228, + + 228, 228, 228, 228, 243, 243, 243, 243, 243, 243, + 243, 243, 243, 243, 243, 128, 128, 128, 128, 277, + 277, 1409, 277, 277, 277, 277, 277, 277, 277, 277, + 279, 279, 1409, 279, 279, 279, 279, 279, 279, 279, + 279, 287, 287, 1409, 287, 287, 287, 287, 287, 287, + 287, 287, 292, 292, 1409, 292, 292, 292, 292, 292, + 292, 292, 292, 295, 1409, 295, 295, 296, 296, 298, + 1409, 1409, 298, 298, 171, 1409, 1409, 1409, 171, 171, + 171, 171, 171, 171, 171, 176, 176, 1409, 1409, 176, + 176, 176, 176, 176, 176, 176, 182, 182, 1409, 182, + + 182, 182, 182, 182, 182, 182, 182, 184, 1409, 1409, + 1409, 184, 184, 184, 184, 184, 184, 184, 186, 1409, + 1409, 1409, 186, 186, 186, 186, 186, 186, 186, 188, + 1409, 1409, 1409, 188, 188, 188, 188, 188, 188, 188, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 352, 352, 1409, 352, 352, 352, 352, 352, 352, + 352, 352, 374, 374, 1409, 374, 374, 374, 374, 374, + 374, 374, 374, 376, 376, 1409, 376, 376, 376, 376, + 376, 376, 376, 376, 218, 218, 1409, 218, 218, 218, + 218, 218, 218, 218, 218, 228, 228, 1409, 228, 228, + + 228, 228, 228, 228, 228, 228, 400, 400, 400, 400, + 400, 400, 400, 400, 400, 400, 400, 287, 287, 1409, + 287, 287, 287, 287, 287, 287, 287, 287, 475, 475, + 1409, 475, 475, 475, 475, 475, 475, 475, 475, 277, + 277, 1409, 277, 277, 277, 277, 277, 277, 277, 277, + 477, 477, 1409, 477, 477, 477, 477, 477, 477, 477, + 477, 482, 482, 1409, 482, 482, 482, 482, 482, 482, + 482, 482, 483, 483, 1409, 483, 483, 483, 483, 483, + 483, 483, 483, 484, 484, 484, 484, 484, 1409, 484, + 484, 484, 484, 484, 485, 485, 1409, 485, 485, 485, + + 485, 485, 485, 485, 485, 487, 487, 488, 488, 488, + 488, 1409, 488, 488, 488, 488, 488, 488, 489, 489, + 489, 489, 489, 1409, 489, 489, 489, 489, 489, 521, + 521, 1409, 521, 521, 521, 521, 521, 521, 521, 521, + 343, 343, 343, 343, 343, 343, 343, 343, 343, 343, + 343, 528, 528, 1409, 528, 528, 528, 528, 528, 528, + 528, 528, 553, 553, 1409, 553, 553, 553, 553, 553, + 553, 553, 553, 554, 554, 1409, 554, 554, 554, 554, + 554, 554, 554, 554, 556, 556, 1409, 556, 556, 556, + 556, 556, 556, 556, 556, 560, 560, 1409, 560, 560, + + 560, 560, 560, 560, 560, 560, 568, 568, 1409, 568, + 568, 568, 568, 568, 568, 568, 568, 228, 228, 1409, + 228, 228, 228, 228, 228, 228, 228, 228, 606, 606, + 1409, 606, 606, 606, 606, 606, 606, 606, 606, 608, + 608, 1409, 608, 608, 608, 608, 608, 608, 608, 608, + 616, 616, 1409, 616, 616, 616, 616, 616, 616, 616, + 616, 649, 649, 1409, 649, 649, 649, 649, 649, 649, + 649, 649, 653, 653, 1409, 653, 653, 653, 653, 653, + 653, 653, 653, 475, 475, 1409, 475, 475, 475, 475, + 475, 475, 475, 475, 657, 657, 1409, 657, 657, 657, + + 657, 657, 657, 657, 657, 658, 658, 1409, 658, 658, + 658, 658, 658, 658, 658, 658, 484, 484, 484, 484, + 484, 484, 484, 484, 484, 484, 484, 298, 298, 488, + 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, + 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, + 489, 608, 608, 1409, 608, 608, 608, 608, 608, 608, + 608, 608, 521, 521, 1409, 521, 521, 521, 521, 521, + 521, 521, 521, 690, 690, 1409, 690, 690, 690, 690, + 690, 690, 690, 690, 553, 553, 1409, 553, 553, 553, + 553, 553, 553, 553, 553, 719, 719, 1409, 719, 719, + + 719, 719, 719, 719, 719, 719, 721, 721, 1409, 721, + 721, 721, 721, 721, 721, 721, 721, 756, 756, 1409, + 756, 756, 756, 756, 756, 756, 756, 756, 568, 568, + 1409, 568, 568, 568, 568, 568, 568, 568, 568, 758, + 758, 1409, 758, 758, 758, 758, 758, 758, 758, 758, + 759, 759, 1409, 759, 759, 759, 759, 759, 759, 759, + 759, 228, 228, 1409, 228, 228, 228, 228, 228, 228, + 228, 228, 760, 760, 1409, 760, 760, 760, 760, 760, + 760, 760, 760, 761, 761, 1409, 761, 761, 761, 761, + 761, 761, 761, 761, 762, 762, 1409, 762, 762, 762, + + 762, 762, 762, 762, 762, 766, 766, 1409, 766, 766, + 766, 766, 766, 766, 766, 766, 786, 786, 1409, 786, + 786, 786, 786, 786, 786, 786, 786, 790, 790, 1409, + 790, 790, 790, 790, 790, 790, 790, 790, 606, 606, + 1409, 606, 606, 606, 606, 606, 606, 606, 606, 792, + 792, 1409, 792, 792, 792, 792, 792, 792, 792, 792, + 797, 797, 1409, 797, 797, 797, 797, 797, 797, 797, + 797, 798, 798, 798, 798, 798, 798, 798, 798, 798, + 798, 798, 801, 801, 801, 801, 801, 801, 801, 801, + 801, 801, 801, 802, 802, 802, 802, 802, 802, 802, + + 802, 802, 802, 802, 803, 803, 1409, 803, 803, 803, + 803, 803, 803, 803, 803, 804, 804, 1409, 804, 804, + 804, 804, 804, 804, 804, 804, 805, 805, 1409, 805, + 805, 805, 805, 805, 805, 805, 805, 806, 806, 1409, + 806, 806, 806, 806, 806, 806, 806, 806, 807, 807, + 1409, 807, 807, 807, 807, 807, 807, 807, 807, 808, + 808, 1409, 808, 808, 808, 808, 808, 808, 808, 808, + 649, 649, 1409, 649, 649, 649, 649, 649, 649, 649, + 649, 809, 809, 1409, 809, 809, 809, 809, 809, 809, + 809, 809, 653, 653, 1409, 653, 653, 653, 653, 653, + + 653, 653, 653, 810, 1409, 810, 810, 810, 810, 810, + 810, 810, 810, 810, 792, 792, 1409, 792, 792, 792, + 792, 792, 792, 792, 792, 521, 521, 521, 521, 521, + 521, 521, 521, 521, 521, 521, 826, 826, 1409, 826, + 826, 826, 826, 826, 826, 826, 826, 850, 850, 1409, + 850, 850, 850, 850, 850, 850, 850, 850, 719, 719, + 1409, 719, 719, 719, 719, 719, 719, 719, 719, 851, + 851, 1409, 851, 851, 851, 851, 851, 851, 851, 851, + 721, 721, 1409, 721, 721, 721, 721, 721, 721, 721, + 721, 913, 913, 1409, 913, 913, 913, 913, 913, 913, + + 913, 913, 756, 756, 1409, 756, 756, 756, 756, 756, + 756, 756, 756, 758, 758, 1409, 758, 758, 758, 758, + 758, 758, 758, 758, 759, 759, 1409, 759, 759, 759, + 759, 759, 759, 759, 759, 760, 760, 1409, 760, 760, + 760, 760, 760, 760, 760, 760, 761, 761, 1409, 761, + 761, 761, 761, 761, 761, 761, 761, 762, 762, 1409, + 762, 762, 762, 762, 762, 762, 762, 762, 766, 766, + 1409, 766, 766, 766, 766, 766, 766, 766, 766, 916, + 916, 1409, 916, 916, 916, 916, 916, 916, 916, 916, + 917, 917, 1409, 917, 917, 917, 917, 917, 917, 917, + + 917, 918, 918, 1409, 918, 918, 918, 918, 918, 918, + 918, 918, 919, 919, 1409, 919, 919, 919, 919, 919, + 919, 919, 919, 920, 920, 1409, 920, 920, 920, 920, + 920, 920, 920, 920, 921, 921, 1409, 921, 921, 921, + 921, 921, 921, 921, 921, 786, 786, 1409, 786, 786, + 786, 786, 786, 786, 786, 786, 922, 922, 1409, 922, + 922, 922, 922, 922, 922, 922, 922, 790, 790, 1409, + 790, 790, 790, 790, 790, 790, 790, 790, 924, 924, + 1409, 924, 924, 924, 924, 924, 924, 924, 924, 798, + 798, 798, 798, 798, 798, 798, 798, 798, 798, 798, + + 801, 801, 801, 801, 801, 801, 801, 801, 801, 801, + 801, 802, 802, 802, 802, 802, 802, 802, 802, 802, + 802, 802, 803, 803, 1409, 803, 803, 803, 803, 803, + 803, 803, 803, 804, 804, 1409, 804, 804, 804, 804, + 804, 804, 804, 804, 805, 805, 1409, 805, 805, 805, + 805, 805, 805, 805, 805, 806, 806, 1409, 806, 806, + 806, 806, 806, 806, 806, 806, 807, 807, 1409, 807, + 807, 807, 807, 807, 807, 807, 807, 808, 808, 1409, + 808, 808, 808, 808, 808, 808, 808, 808, 809, 809, + 1409, 809, 809, 809, 809, 809, 809, 809, 809, 810, + + 1409, 810, 810, 810, 810, 810, 810, 810, 810, 810, + 931, 931, 1409, 931, 931, 931, 931, 931, 931, 931, + 931, 950, 950, 1409, 950, 950, 950, 950, 950, 950, + 950, 950, 951, 951, 1409, 951, 951, 951, 951, 951, + 951, 951, 951, 1040, 1409, 1040, 1040, 1053, 1053, 1409, + 1053, 1053, 1053, 1053, 1053, 1053, 1053, 1053, 916, 916, + 1409, 916, 916, 916, 916, 916, 916, 916, 916, 917, + 917, 1409, 917, 917, 917, 917, 917, 917, 917, 917, + 918, 918, 1409, 918, 918, 918, 918, 918, 918, 918, + 918, 919, 919, 1409, 919, 919, 919, 919, 919, 919, + + 919, 919, 920, 920, 1409, 920, 920, 920, 920, 920, + 920, 920, 920, 921, 921, 1409, 921, 921, 921, 921, + 921, 921, 921, 921, 922, 922, 1409, 922, 922, 922, + 922, 922, 922, 922, 922, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1055, 1055, 1409, 1055, + 1055, 1055, 1055, 1055, 1055, 1055, 1055, 1069, 1069, 1409, + 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1069, 1070, 1070, + 1409, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1070, 1191, + 1191, 1409, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, + 1192, 1192, 1409, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + + 1192, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, 1198, + 1198, 1198, 1201, 1201, 1201, 1201, 1201, 1201, 1201, 1201, + 1201, 1201, 1201, 1204, 1204, 1204, 1204, 1204, 1204, 1204, + 1204, 1204, 1204, 1204, 1209, 1209, 1409, 1209, 1209, 1209, + 1209, 1209, 1209, 1209, 1209, 1040, 1409, 1040, 1409, 1040, + 1040, 1235, 1235, 1409, 1235, 1235, 1235, 1235, 1235, 1235, + 1235, 1235, 1249, 1409, 1249, 1249, 1256, 1409, 1256, 1256, + 1281, 1281, 1409, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + 1281, 1285, 1285, 1409, 1285, 1285, 1285, 1285, 1285, 1285, + 1285, 1285, 1289, 1289, 1409, 1289, 1289, 1289, 1289, 1289, + + 1289, 1289, 1289, 1322, 1409, 1322, 1322, 37, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409 + } ; + +static const flex_int16_t yy_chk[7335] = + { 0, + 0, 0, 3, 3, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, + 15, 9, 10, 25, 25, 25, 25, 7, 27, 27, + 27, 8, 26, 26, 26, 26, 248, 25, 25, 9, + 10, 28, 28, 28, 29, 30, 26, 26, 33, 33, + 248, 29, 30, 34, 34, 15, 1074, 48, 29, 30, + 48, 15, 368, 15, 368, 7, 9, 10, 59, 8, + 258, 59, 40, 40, 40, 40, 25, 55, 25, 258, + + 67, 40, 55, 67, 1592, 26, 15, 26, 40, 1074, + 66, 66, 15, 66, 15, 87, 87, 9, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 16, 43, 43, 43, 43, 232, 281, 281, 44, + 44, 44, 44, 232, 305, 305, 43, 43, 44, 44, + 86, 86, 86, 86, 44, 44, 60, 60, 60, 60, + + 60, 60, 60, 99, 99, 1081, 16, 91, 91, 91, + 91, 1587, 16, 267, 16, 104, 104, 1586, 99, 103, + 103, 103, 103, 104, 267, 43, 108, 108, 108, 108, + 104, 111, 44, 126, 111, 108, 126, 16, 127, 318, + 318, 127, 108, 16, 1081, 16, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 23, 23, + + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 45, 45, 45, 45, 136, 122, + 135, 136, 358, 122, 113, 52, 122, 130, 52, 45, + 130, 113, 53, 53, 53, 53, 113, 83, 113, 52, + 83, 53, 53, 84, 84, 84, 84, 138, 53, 422, + 138, 83, 83, 358, 1134, 148, 138, 97, 148, 736, + 97, 736, 135, 122, 148, 246, 1575, 45, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 52, 51, + 130, 150, 51, 51, 51, 53, 163, 84, 247, 163, + + 83, 161, 161, 161, 161, 150, 84, 113, 84, 97, + 109, 109, 109, 109, 51, 113, 164, 439, 97, 164, + 151, 151, 151, 151, 109, 109, 1086, 246, 165, 51, + 51, 165, 422, 51, 51, 51, 51, 51, 51, 51, + 97, 51, 1486, 166, 51, 51, 166, 51, 51, 51, + 247, 51, 51, 51, 51, 51, 51, 51, 107, 51, + 51, 51, 1134, 109, 150, 107, 110, 110, 110, 110, + 107, 1464, 150, 151, 107, 107, 107, 167, 107, 315, + 167, 110, 115, 115, 115, 115, 116, 116, 116, 116, + 315, 168, 439, 107, 168, 116, 116, 115, 219, 219, + + 169, 116, 116, 169, 369, 369, 107, 117, 117, 117, + 117, 222, 222, 219, 123, 123, 123, 123, 176, 110, + 1455, 176, 117, 123, 123, 177, 222, 1086, 177, 123, + 123, 397, 397, 235, 149, 115, 235, 149, 492, 116, + 132, 132, 132, 132, 132, 132, 132, 132, 149, 544, + 193, 134, 155, 193, 155, 134, 155, 134, 134, 155, + 117, 121, 121, 134, 121, 193, 238, 123, 134, 238, + 259, 134, 162, 259, 147, 162, 147, 121, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 149, 121, 360, + 162, 162, 162, 162, 121, 121, 155, 361, 121, 259, + + 121, 544, 121, 193, 121, 121, 121, 415, 121, 263, + 121, 259, 263, 492, 121, 190, 190, 190, 190, 121, + 360, 121, 619, 121, 154, 154, 121, 154, 361, 154, + 619, 121, 152, 152, 152, 152, 121, 154, 154, 403, + 189, 152, 152, 189, 154, 268, 268, 268, 152, 156, + 156, 156, 156, 403, 189, 189, 157, 1408, 156, 156, + 157, 196, 157, 157, 203, 156, 415, 203, 157, 191, + 191, 191, 191, 157, 419, 415, 157, 194, 194, 194, + 194, 196, 407, 239, 191, 152, 239, 199, 199, 199, + 199, 239, 196, 189, 200, 200, 200, 200, 201, 201, + + 201, 201, 156, 206, 206, 206, 206, 209, 209, 209, + 209, 229, 196, 216, 229, 251, 251, 203, 251, 226, + 226, 194, 207, 207, 207, 207, 230, 226, 1407, 230, + 194, 199, 194, 221, 226, 221, 273, 545, 545, 273, + 199, 216, 199, 419, 221, 229, 221, 276, 221, 207, + 276, 412, 216, 230, 229, 221, 207, 207, 216, 233, + 207, 207, 237, 207, 407, 233, 423, 207, 254, 230, + 233, 254, 216, 237, 406, 230, 233, 260, 406, 237, + 260, 221, 233, 216, 260, 307, 307, 207, 307, 216, + 883, 412, 290, 237, 260, 290, 233, 240, 240, 240, + + 240, 290, 254, 321, 237, 322, 321, 233, 322, 414, + 237, 254, 240, 233, 241, 241, 241, 241, 242, 242, + 242, 242, 244, 244, 244, 244, 423, 302, 424, 241, + 302, 256, 323, 242, 256, 323, 302, 244, 307, 207, + 207, 207, 883, 207, 324, 207, 207, 324, 1406, 414, + 240, 245, 245, 245, 245, 610, 610, 325, 256, 261, + 325, 304, 304, 304, 304, 261, 245, 241, 495, 445, + 261, 242, 256, 445, 256, 244, 261, 1405, 270, 494, + 256, 312, 261, 326, 312, 327, 326, 328, 327, 270, + 328, 329, 424, 1089, 329, 270, 261, 330, 331, 332, + + 330, 331, 332, 424, 245, 249, 249, 261, 249, 270, + 532, 764, 426, 261, 304, 312, 333, 270, 1089, 333, + 270, 249, 388, 630, 312, 388, 270, 340, 340, 340, + 340, 630, 249, 341, 341, 341, 341, 798, 249, 249, + 342, 532, 249, 342, 249, 798, 249, 495, 249, 249, + 249, 494, 249, 1163, 249, 342, 312, 344, 249, 389, + 344, 312, 389, 249, 1404, 249, 390, 249, 391, 390, + 249, 391, 344, 426, 497, 249, 345, 345, 345, 345, + 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 764, 250, 342, 347, 250, 250, 250, 300, 300, + + 300, 300, 300, 300, 300, 300, 300, 1403, 392, 393, + 344, 392, 393, 394, 347, 395, 394, 250, 395, 765, + 345, 351, 351, 351, 351, 347, 752, 396, 752, 345, + 396, 345, 450, 250, 498, 450, 250, 250, 250, 250, + 250, 250, 250, 451, 250, 347, 451, 250, 250, 905, + 250, 250, 250, 497, 250, 250, 250, 250, 250, 250, + 250, 1163, 250, 250, 250, 309, 309, 578, 309, 378, + 378, 378, 378, 1106, 378, 408, 408, 578, 408, 409, + 409, 309, 409, 765, 535, 401, 401, 401, 401, 362, + 537, 309, 309, 362, 309, 1104, 309, 362, 309, 309, + + 401, 905, 309, 362, 309, 309, 309, 420, 309, 309, + 309, 309, 309, 498, 309, 535, 436, 436, 309, 436, + 362, 537, 538, 309, 362, 309, 425, 309, 362, 452, + 309, 865, 452, 865, 362, 309, 429, 429, 401, 429, + 309, 310, 310, 310, 310, 310, 310, 310, 310, 310, + 310, 453, 310, 538, 453, 310, 310, 310, 1106, 539, + 402, 402, 402, 402, 420, 670, 670, 420, 404, 404, + 404, 404, 496, 438, 438, 402, 438, 310, 454, 362, + 626, 454, 438, 404, 626, 1108, 425, 425, 425, 429, + 539, 455, 456, 310, 455, 456, 310, 310, 310, 310, + + 310, 310, 310, 457, 310, 663, 457, 310, 310, 1104, + 310, 310, 310, 402, 310, 310, 310, 310, 310, 310, + 310, 404, 310, 310, 310, 353, 353, 353, 353, 801, + 405, 691, 405, 801, 355, 355, 355, 355, 458, 405, + 496, 458, 416, 416, 405, 416, 405, 356, 356, 356, + 356, 496, 353, 411, 411, 459, 411, 1402, 459, 353, + 353, 355, 691, 353, 353, 417, 353, 1108, 355, 355, + 353, 416, 355, 355, 356, 355, 693, 413, 413, 355, + 413, 356, 356, 416, 663, 356, 356, 411, 356, 695, + 353, 417, 356, 965, 417, 965, 411, 1136, 417, 355, + + 447, 447, 732, 447, 413, 405, 695, 693, 417, 447, + 431, 449, 356, 405, 449, 732, 449, 802, 413, 460, + 413, 1135, 460, 696, 418, 802, 413, 431, 431, 431, + 431, 431, 431, 431, 431, 461, 462, 427, 461, 462, + 737, 737, 353, 353, 353, 1099, 353, 1401, 353, 353, + 418, 355, 355, 355, 696, 355, 418, 355, 355, 463, + 464, 418, 463, 464, 356, 356, 356, 418, 356, 427, + 356, 356, 434, 418, 465, 983, 434, 465, 434, 434, + 427, 939, 466, 1136, 434, 466, 427, 418, 467, 434, + 470, 467, 434, 470, 468, 939, 471, 468, 418, 471, + + 427, 763, 446, 472, 418, 421, 472, 474, 427, 1400, + 474, 427, 468, 1135, 446, 748, 446, 427, 446, 446, + 446, 446, 446, 446, 446, 446, 446, 983, 748, 1099, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, + 421, 421, 421, 421, 421, 421, 442, 476, 479, 468, + 476, 479, 753, 753, 442, 442, 442, 442, 501, 763, + 763, 501, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 443, 443, + + 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, + 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, + 443, 443, 443, 443, 503, 504, 1109, 503, 504, 443, + 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, + 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, + 443, 443, 443, 443, 443, 444, 505, 506, 507, 505, + 506, 507, 508, 510, 511, 508, 510, 511, 697, 1083, + 699, 444, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 444, 444, 493, 493, 697, + + 493, 699, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 444, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 444, 444, 444, 491, 499, + 491, 493, 1109, 499, 512, 499, 499, 512, 576, 513, + 493, 499, 513, 701, 491, 514, 499, 518, 514, 499, + 518, 519, 522, 534, 519, 522, 523, 523, 523, 523, + 526, 571, 575, 526, 571, 575, 518, 522, 844, 703, + 635, 523, 493, 635, 701, 636, 534, 493, 636, 1083, + 529, 529, 529, 529, 534, 579, 579, 844, 579, 531, + 531, 531, 531, 637, 580, 580, 637, 580, 576, 580, + + 703, 576, 1107, 491, 1105, 522, 576, 529, 1399, 638, + 536, 491, 638, 526, 529, 529, 531, 540, 529, 529, + 705, 529, 536, 531, 531, 529, 1082, 531, 531, 540, + 531, 536, 725, 639, 531, 536, 639, 541, 540, 534, + 541, 536, 540, 581, 581, 529, 581, 642, 540, 1078, + 642, 705, 541, 536, 531, 582, 582, 541, 582, 1398, + 540, 1156, 536, 725, 583, 583, 536, 583, 995, 540, + 1078, 584, 584, 540, 584, 585, 585, 1140, 585, 586, + 586, 700, 586, 587, 587, 995, 587, 588, 588, 1131, + 588, 589, 589, 643, 589, 700, 643, 529, 529, 529, + + 1126, 529, 645, 529, 529, 645, 531, 531, 531, 727, + 531, 1107, 531, 531, 558, 558, 558, 558, 1105, 558, + 590, 590, 1131, 590, 591, 591, 700, 591, 592, 592, + 1082, 592, 593, 593, 1126, 593, 594, 594, 1397, 594, + 727, 558, 595, 595, 646, 595, 1156, 646, 558, 558, + 861, 647, 558, 558, 647, 558, 1138, 596, 596, 558, + 596, 597, 597, 861, 597, 598, 598, 558, 598, 599, + 599, 1132, 599, 601, 601, 1396, 601, 602, 602, 558, + 602, 603, 603, 627, 603, 605, 605, 599, 605, 618, + 618, 648, 618, 651, 648, 1140, 651, 728, 618, 627, + + 627, 627, 627, 627, 627, 627, 627, 627, 629, 629, + 652, 629, 654, 652, 1139, 654, 655, 629, 656, 655, + 741, 656, 662, 662, 743, 662, 664, 664, 728, 664, + 961, 558, 558, 558, 599, 558, 1079, 558, 558, 559, + 559, 559, 559, 961, 559, 665, 665, 1395, 665, 666, + 666, 741, 666, 667, 667, 743, 667, 668, 668, 1098, + 668, 669, 669, 1394, 669, 673, 559, 674, 673, 675, + 674, 1138, 675, 559, 559, 1132, 676, 559, 559, 676, + 559, 1393, 677, 678, 559, 677, 678, 679, 680, 744, + 679, 680, 559, 682, 684, 685, 682, 684, 685, 686, + + 687, 1098, 686, 687, 559, 688, 688, 688, 688, 689, + 689, 689, 689, 692, 692, 692, 692, 698, 827, 1392, + 744, 698, 702, 702, 702, 702, 767, 767, 831, 767, + 698, 772, 772, 1139, 772, 773, 773, 1026, 773, 774, + 774, 834, 774, 775, 775, 835, 775, 1079, 698, 827, + 776, 776, 698, 776, 1026, 837, 559, 559, 559, 831, + 559, 698, 559, 559, 621, 714, 779, 779, 714, 779, + 780, 780, 834, 780, 782, 782, 835, 782, 783, 783, + 1391, 783, 784, 784, 820, 784, 837, 820, 1155, 621, + 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, + + 621, 621, 621, 621, 621, 621, 621, 621, 621, 621, + 621, 621, 621, 621, 621, 624, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, + 624, 785, 785, 1390, 785, 1155, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, + 624, 624, 704, 704, 704, 704, 788, 788, 854, 788, + 789, 789, 821, 789, 729, 821, 714, 714, 729, 1087, + 791, 791, 729, 791, 794, 794, 856, 794, 729, 704, + + 724, 1146, 704, 811, 811, 1146, 811, 724, 724, 854, + 822, 724, 724, 822, 724, 729, 1389, 823, 724, 729, + 823, 812, 812, 729, 812, 824, 724, 856, 824, 729, + 704, 843, 843, 704, 723, 723, 723, 723, 724, 723, + 740, 813, 813, 825, 813, 857, 825, 740, 740, 869, + 829, 740, 740, 829, 740, 1100, 814, 814, 740, 814, + 1100, 723, 815, 815, 1133, 815, 740, 872, 723, 723, + 845, 845, 723, 723, 729, 723, 857, 1385, 740, 723, + 869, 745, 1087, 816, 816, 745, 816, 723, 874, 745, + 724, 724, 724, 1169, 724, 745, 724, 724, 872, 723, + + 817, 817, 871, 817, 818, 818, 1169, 818, 828, 828, + 828, 828, 745, 866, 866, 875, 745, 876, 891, 874, + 745, 836, 836, 836, 836, 871, 745, 884, 884, 1384, + 740, 740, 740, 871, 740, 894, 740, 740, 873, 896, + 1113, 878, 897, 898, 878, 1113, 875, 1133, 876, 891, + 873, 723, 723, 723, 932, 723, 878, 723, 723, 873, + 836, 878, 900, 873, 893, 900, 894, 906, 906, 873, + 896, 745, 799, 897, 898, 914, 914, 900, 914, 940, + 940, 873, 900, 915, 915, 932, 915, 893, 871, 929, + 873, 836, 929, 930, 873, 893, 930, 799, 799, 799, + + 799, 799, 799, 799, 799, 799, 799, 799, 799, 799, + 799, 799, 799, 799, 799, 799, 799, 799, 799, 799, + 799, 799, 799, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 933, + 893, 1383, 933, 1382, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 852, 852, 852, 852, 853, 852, 1085, 923, 923, 858, + 923, 853, 853, 858, 1369, 853, 853, 858, 853, 1102, + + 934, 935, 853, 858, 936, 877, 1125, 852, 927, 927, + 853, 927, 942, 942, 852, 852, 954, 877, 852, 852, + 858, 852, 853, 956, 858, 852, 877, 1125, 858, 1368, + 877, 934, 935, 852, 858, 936, 877, 928, 928, 1158, + 928, 938, 938, 938, 938, 852, 957, 954, 877, 966, + 966, 1367, 969, 1147, 956, 984, 984, 877, 882, 1102, + 882, 877, 882, 882, 882, 882, 882, 882, 882, 882, + 882, 972, 1085, 1085, 853, 853, 853, 957, 853, 858, + 853, 853, 904, 969, 904, 1366, 904, 904, 904, 904, + 904, 904, 904, 904, 904, 1147, 1225, 852, 852, 852, + + 1359, 852, 972, 852, 852, 881, 1054, 1054, 1157, 1054, + 1225, 1102, 1154, 881, 881, 881, 881, 1358, 974, 975, + 976, 881, 881, 881, 881, 881, 881, 881, 881, 881, + 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, + 881, 881, 881, 881, 881, 881, 881, 895, 899, 974, + 975, 976, 991, 1158, 1168, 993, 996, 1168, 1018, 895, + 899, 1018, 971, 953, 997, 999, 1000, 1357, 895, 899, + 953, 953, 895, 899, 953, 953, 1356, 953, 895, 899, + 1000, 953, 1154, 991, 958, 971, 993, 996, 958, 953, + 895, 899, 958, 971, 978, 997, 999, 978, 958, 895, + + 899, 953, 1001, 895, 899, 952, 952, 952, 952, 978, + 952, 1000, 1157, 992, 978, 958, 992, 1152, 992, 958, + 1346, 1049, 1002, 958, 1049, 1002, 1186, 1002, 1103, 958, + 1003, 1005, 952, 1001, 998, 1344, 1022, 1024, 998, 952, + 952, 1152, 1084, 952, 952, 1186, 952, 998, 971, 1343, + 952, 973, 977, 953, 953, 953, 1340, 953, 952, 953, + 953, 1003, 1005, 973, 977, 998, 992, 1022, 1024, 998, + 952, 1027, 973, 977, 958, 1002, 973, 977, 998, 1018, + 1018, 1028, 973, 977, 1010, 1010, 1010, 1010, 1010, 1010, + 1010, 1010, 1010, 1339, 973, 977, 1030, 1058, 1058, 1058, + + 1058, 1032, 1027, 973, 977, 1326, 1034, 973, 977, 982, + 1325, 982, 1028, 982, 982, 982, 982, 982, 982, 982, + 982, 982, 952, 952, 952, 1164, 952, 1030, 952, 952, + 981, 1023, 1032, 1084, 1023, 1084, 1023, 1034, 981, 981, + 981, 981, 1049, 1049, 1103, 1103, 981, 981, 981, 981, + 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, + 981, 981, 981, 981, 981, 981, 981, 981, 981, 981, + 981, 981, 1004, 1031, 1009, 1004, 1029, 1004, 1185, 1185, + 1029, 1009, 1009, 1011, 1023, 1009, 1009, 1031, 1009, 1029, + 1011, 1011, 1009, 1036, 1011, 1011, 1056, 1011, 1075, 1004, + + 1009, 1011, 1004, 1059, 1059, 1059, 1059, 1029, 1324, 1011, + 1033, 1029, 1009, 1033, 1111, 1033, 1323, 1111, 1031, 1111, + 1029, 1011, 1317, 1114, 1036, 1004, 1088, 1056, 1187, 1187, + 1004, 1075, 1164, 1004, 1008, 1008, 1008, 1008, 1008, 1008, + 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1094, 1122, 1075, 1033, 1009, 1009, 1009, 1111, 1009, 1073, + 1009, 1009, 1088, 1011, 1011, 1011, 1076, 1011, 1035, 1011, + 1011, 1035, 1159, 1035, 1040, 1063, 1063, 1063, 1063, 1165, + 1122, 1040, 1040, 1094, 1073, 1040, 1040, 1316, 1040, 1315, + + 1080, 1076, 1040, 1088, 1097, 1035, 1114, 1305, 1035, 1093, + 1040, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, 1041, + 1304, 1122, 1040, 1114, 1094, 1073, 1042, 1064, 1064, 1064, + 1064, 1035, 1076, 1042, 1042, 1091, 1035, 1042, 1042, 1035, + 1042, 1090, 1077, 1141, 1042, 1065, 1065, 1065, 1065, 1303, + 1095, 1093, 1042, 1067, 1067, 1067, 1067, 1080, 1195, 1213, + 1302, 1195, 1213, 1077, 1042, 1110, 1090, 1077, 1116, 1091, + 1080, 1077, 1141, 1112, 1040, 1040, 1040, 1077, 1040, 1118, + 1040, 1040, 1093, 1095, 1097, 1301, 1165, 1097, 1121, 1090, + 1110, 1121, 1160, 1121, 1077, 1115, 1159, 1090, 1077, 1097, + + 1091, 1116, 1077, 1141, 1097, 1120, 1072, 1112, 1077, 1298, + 1124, 1296, 1148, 1118, 1095, 1295, 1042, 1042, 1042, 1293, + 1042, 1110, 1042, 1042, 1071, 1071, 1071, 1071, 1072, 1071, + 1115, 1119, 1116, 1148, 1092, 1072, 1072, 1279, 1112, 1072, + 1072, 1121, 1072, 1144, 1118, 1276, 1072, 1117, 1120, 1145, + 1096, 1071, 1090, 1077, 1072, 1092, 1124, 1149, 1071, 1071, + 1119, 1115, 1071, 1071, 1148, 1071, 1072, 1092, 1117, 1071, + 1137, 1096, 1117, 1137, 1119, 1137, 1092, 1071, 1275, 1120, + 1092, 1117, 1274, 1096, 1145, 1142, 1092, 1124, 1142, 1071, + 1142, 1161, 1096, 1271, 1215, 1149, 1096, 1215, 1092, 1117, + + 1144, 1143, 1096, 1117, 1143, 1119, 1143, 1092, 1160, 1160, + 1270, 1092, 1117, 1144, 1096, 1145, 1129, 1269, 1072, 1072, + 1072, 1268, 1072, 1096, 1072, 1072, 1149, 1096, 1129, 1129, + 1129, 1129, 1129, 1129, 1129, 1129, 1129, 1166, 1265, 1170, + 1151, 1071, 1071, 1071, 1101, 1071, 1123, 1071, 1071, 1123, + 1128, 1123, 1101, 1162, 1101, 1261, 1101, 1101, 1101, 1101, + 1101, 1101, 1101, 1101, 1101, 1151, 1150, 1260, 1166, 1150, + 1170, 1150, 1128, 1123, 1161, 1173, 1123, 1174, 1259, 1128, + 1128, 1176, 1193, 1128, 1128, 1252, 1128, 1130, 1226, 1226, + 1128, 1137, 1137, 1161, 1214, 1218, 1151, 1167, 1128, 1123, + + 1167, 1219, 1167, 1220, 1123, 1150, 1173, 1123, 1174, 1130, + 1128, 1246, 1176, 1193, 1228, 1228, 1130, 1130, 1237, 1150, + 1130, 1130, 1245, 1130, 1153, 1214, 1218, 1130, 1175, 1153, + 1247, 1175, 1219, 1175, 1220, 1130, 1150, 1153, 1153, 1153, + 1153, 1197, 1197, 1197, 1197, 1241, 1240, 1130, 1267, 1237, + 1239, 1162, 1162, 1198, 1198, 1198, 1198, 1199, 1199, 1199, + 1199, 1247, 1128, 1128, 1128, 1238, 1128, 1175, 1128, 1128, + 1200, 1200, 1200, 1200, 1201, 1201, 1201, 1201, 1234, 1267, + 1233, 1175, 1202, 1202, 1202, 1202, 1203, 1203, 1203, 1203, + 1204, 1204, 1204, 1204, 1205, 1205, 1205, 1205, 1175, 1130, + + 1130, 1130, 1232, 1130, 1212, 1130, 1130, 1206, 1206, 1206, + 1206, 1212, 1212, 1272, 1224, 1212, 1212, 1224, 1212, 1224, + 1231, 1230, 1212, 1242, 1242, 1242, 1242, 1217, 1229, 1217, + 1212, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, 1217, + 1227, 1222, 1212, 1222, 1272, 1222, 1222, 1222, 1222, 1222, + 1222, 1222, 1222, 1222, 1243, 1243, 1243, 1243, 1244, 1244, + 1244, 1244, 1278, 1249, 1223, 1278, 1249, 1224, 1249, 1250, + 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1251, 1221, + 1216, 1251, 1208, 1251, 1253, 1253, 1253, 1253, 1253, 1253, + 1253, 1253, 1253, 1207, 1212, 1212, 1212, 1254, 1212, 1294, + + 1212, 1212, 1196, 1194, 1254, 1254, 1256, 1257, 1254, 1254, + 1257, 1254, 1257, 1256, 1256, 1254, 1249, 1256, 1256, 1191, + 1256, 1190, 1258, 1262, 1256, 1258, 1262, 1258, 1262, 1263, + 1294, 1251, 1263, 1264, 1263, 1254, 1264, 1266, 1264, 1273, + 1266, 1189, 1266, 1277, 1256, 1188, 1299, 1273, 1273, 1273, + 1273, 1277, 1277, 1277, 1277, 1184, 1280, 1183, 1182, 1280, + 1257, 1280, 1281, 1282, 1318, 1281, 1282, 1281, 1282, 1283, + 1181, 1180, 1283, 1179, 1283, 1258, 1262, 1299, 1284, 1178, + 1341, 1284, 1263, 1284, 1177, 1172, 1264, 1254, 1254, 1254, + 1266, 1254, 1171, 1254, 1254, 1318, 1256, 1256, 1256, 1127, + + 1256, 1285, 1256, 1256, 1285, 1286, 1285, 1070, 1286, 1280, + 1286, 1341, 1069, 1068, 1287, 1281, 1282, 1287, 1288, 1287, + 1066, 1288, 1283, 1288, 1289, 1290, 1062, 1289, 1290, 1289, + 1290, 1284, 1291, 1292, 1061, 1291, 1292, 1291, 1292, 1060, + 1284, 1297, 1297, 1297, 1297, 1320, 1322, 1057, 1320, 1322, + 1320, 1322, 1306, 1284, 1285, 1306, 1052, 1306, 1286, 1051, + 1309, 1050, 1048, 1309, 1047, 1309, 1046, 1287, 1045, 1312, + 1328, 1288, 1312, 1328, 1312, 1328, 1044, 1289, 1290, 1330, + 1288, 1043, 1330, 1038, 1330, 1291, 1292, 1037, 1025, 1021, + 1020, 1019, 1300, 1288, 1300, 1292, 1300, 1300, 1300, 1300, + + 1300, 1300, 1300, 1300, 1300, 1306, 1017, 1016, 1292, 1307, + 1015, 1014, 1307, 1309, 1307, 1332, 1013, 1012, 1332, 1307, + 1332, 1007, 1312, 1328, 1006, 994, 990, 1307, 1307, 1307, + 1307, 989, 1330, 988, 987, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, 1307, + 1307, 1308, 1307, 986, 1308, 985, 1308, 980, 1332, 979, + 1334, 970, 968, 1334, 1308, 1334, 1308, 967, 1308, 1308, + 1308, 1308, 1308, 1308, 1308, 1308, 1308, 1311, 1342, 964, + 1311, 963, 1311, 962, 960, 959, 1342, 1342, 1342, 1342, + + 1311, 955, 1311, 949, 1311, 1311, 1311, 1311, 1311, 1311, + 1311, 1311, 1311, 948, 1308, 1310, 947, 946, 1310, 945, + 1310, 944, 943, 1334, 1336, 1310, 941, 1336, 937, 1336, + 926, 925, 924, 1310, 1310, 1310, 1310, 912, 911, 910, + 1311, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, + 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, 1310, + 1310, 1310, 1310, 1310, 1310, 1310, 1310, 909, 1310, 1313, + 1338, 908, 1313, 1338, 1313, 1338, 907, 1336, 1345, 1313, + 903, 1345, 902, 1345, 901, 892, 890, 1313, 1313, 1313, + 1313, 889, 888, 887, 886, 1313, 1313, 1313, 1313, 1313, + + 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, + 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, + 1313, 1314, 1313, 1338, 1314, 885, 1314, 880, 879, 870, + 868, 1345, 1371, 867, 1314, 1371, 1314, 1371, 1314, 1314, + 1314, 1314, 1314, 1314, 1314, 1314, 1314, 1319, 1319, 1319, + 1319, 1319, 1319, 1319, 1319, 1319, 1347, 864, 863, 862, + 1350, 860, 859, 855, 1347, 1347, 1347, 1347, 1350, 1350, + 1350, 1350, 849, 1353, 1314, 1327, 848, 847, 1327, 846, + 1327, 1353, 1353, 1353, 1353, 1371, 1386, 1373, 842, 841, + 1373, 840, 1373, 839, 1386, 1386, 1386, 1386, 838, 833, + + 832, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1327, + 1327, 1327, 1327, 1327, 1327, 1327, 1327, 1329, 1327, 830, + 1329, 819, 1329, 796, 795, 793, 1333, 792, 768, 1333, + 1373, 1333, 755, 754, 1329, 1329, 1329, 1329, 1329, 1329, + 1329, 1329, 1329, 1333, 1333, 1333, 1333, 1333, 1333, 1333, + 1333, 1333, 1387, 751, 750, 749, 1388, 747, 746, 742, + 1387, 1387, 1387, 1387, 1388, 1388, 1388, 1388, 739, 738, + 1329, 1331, 735, 734, 1331, 733, 1331, 731, 730, 1333, + 1375, 726, 718, 1375, 1377, 1375, 717, 1377, 1379, 1377, + + 716, 1379, 715, 1379, 713, 712, 711, 1331, 1331, 1331, + 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, + 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, 1331, + 1331, 1331, 1331, 710, 1331, 1335, 709, 708, 1335, 707, + 1335, 1348, 706, 1375, 1348, 694, 1348, 1377, 683, 681, + 672, 1379, 671, 658, 628, 625, 623, 622, 620, 616, + 615, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, + 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1335, + 1335, 1335, 1335, 1335, 1335, 1335, 1335, 1337, 1335, 614, + 1337, 613, 1337, 1349, 1348, 612, 1349, 1351, 1349, 611, + + 1351, 609, 1351, 1348, 1337, 1337, 1337, 1337, 1337, 1337, + 1337, 1337, 1337, 607, 1352, 561, 1348, 1352, 1354, 1352, + 560, 1354, 1355, 1354, 557, 1355, 1381, 1355, 556, 1381, + 555, 1381, 554, 552, 551, 550, 549, 548, 547, 546, + 1337, 543, 542, 533, 530, 524, 1349, 520, 517, 516, + 1351, 515, 502, 500, 490, 1349, 489, 488, 485, 1351, + 484, 441, 440, 437, 435, 433, 432, 1352, 1349, 428, + 410, 1354, 1351, 400, 399, 1355, 1352, 398, 386, 1381, + 1354, 384, 383, 1360, 1355, 382, 1360, 381, 1360, 1352, + 380, 379, 377, 1354, 376, 375, 1360, 1355, 1360, 374, + + 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 1360, 372, + 371, 370, 367, 366, 365, 364, 363, 359, 357, 354, + 349, 348, 346, 339, 338, 337, 336, 335, 334, 320, + 319, 317, 316, 314, 313, 311, 1360, 1361, 308, 306, + 286, 285, 284, 283, 282, 1361, 1361, 1361, 1361, 280, + 275, 272, 269, 1361, 1361, 1361, 1361, 1361, 1361, 1361, + 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, + 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1362, + 266, 265, 1362, 262, 1362, 257, 255, 253, 243, 236, + 234, 231, 1362, 227, 1362, 225, 1362, 1362, 1362, 1362, + + 1362, 1362, 1362, 1362, 1362, 220, 217, 215, 214, 213, + 212, 210, 208, 202, 198, 197, 195, 192, 181, 180, + 179, 175, 174, 173, 160, 153, 146, 145, 143, 140, + 125, 124, 1362, 1363, 120, 119, 118, 112, 105, 102, + 100, 1363, 1363, 1363, 1363, 96, 95, 93, 92, 1363, + 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, + 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, 1363, + 1363, 1363, 1363, 1363, 1363, 1364, 89, 88, 1364, 85, + 1364, 81, 78, 75, 72, 71, 70, 69, 1364, 65, + 1364, 62, 1364, 1364, 1364, 1364, 1364, 1364, 1364, 1364, + + 1364, 58, 57, 54, 49, 47, 46, 41, 37, 36, + 35, 18, 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1364, 1365, + 0, 0, 0, 0, 0, 0, 0, 1365, 1365, 1365, + 1365, 0, 0, 0, 0, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, 1365, + 1365, 1370, 0, 0, 1370, 0, 1370, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1370, 1370, + 1370, 1370, 1370, 1370, 1370, 1370, 1370, 0, 1374, 0, + + 0, 1374, 0, 1374, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1374, 1374, 1374, 1374, 1374, + 1374, 1374, 1374, 1374, 1370, 1372, 1372, 1372, 1372, 1372, + 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, + 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, 1372, + 1372, 1374, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, + 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, + 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1376, 1378, 0, + 0, 1378, 0, 1378, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1378, 1378, 1378, 1378, 1378, + + 1378, 1378, 1378, 1378, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1378, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, + 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, + 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1380, 1410, 1410, + 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1410, 1411, + 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, 1411, + 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412, + 1412, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, 1413, + + 1413, 1413, 1414, 1414, 1414, 1414, 1414, 1414, 1414, 1414, + 1414, 1414, 1414, 1415, 1415, 1415, 1415, 1415, 1415, 1415, + 1415, 1415, 1415, 1415, 1416, 1416, 1416, 1416, 1416, 1416, + 1416, 1416, 1416, 1416, 1416, 1417, 1417, 1417, 1417, 1417, + 1417, 1417, 1417, 1417, 1417, 1417, 1418, 1418, 1418, 1418, + 1418, 1418, 1418, 1418, 1418, 1418, 1418, 1419, 1419, 1419, + 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1419, 1420, 1420, + 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1420, 1421, + 1421, 1421, 1421, 1422, 1422, 0, 1422, 1422, 1422, 1422, + 1422, 1422, 1422, 1422, 1423, 0, 0, 0, 1423, 1423, + + 1423, 1423, 1423, 1423, 1423, 1424, 1424, 0, 0, 1424, + 1424, 1424, 1424, 1424, 1424, 1424, 1425, 1425, 0, 1425, + 1425, 1425, 1425, 1425, 1425, 1425, 1425, 1426, 0, 0, + 0, 1426, 1426, 1426, 1426, 1426, 1426, 1426, 1427, 0, + 0, 0, 1427, 1427, 1427, 1427, 1427, 1427, 1427, 1428, + 0, 0, 0, 1428, 1428, 1428, 1428, 1428, 1428, 1428, + 1429, 1429, 0, 1429, 1429, 1429, 1429, 1429, 1429, 1429, + 1429, 1430, 1430, 0, 1430, 1430, 1430, 1430, 1430, 1430, + 1430, 1430, 1431, 1431, 0, 1431, 1431, 1431, 1431, 1431, + 1431, 1431, 1431, 1432, 1432, 0, 1432, 1432, 1432, 1432, + + 1432, 1432, 1432, 1432, 1433, 1433, 1433, 1433, 1433, 1433, + 1433, 1433, 1433, 1433, 1433, 1434, 1434, 1434, 1434, 1435, + 1435, 0, 1435, 1435, 1435, 1435, 1435, 1435, 1435, 1435, + 1436, 1436, 0, 1436, 1436, 1436, 1436, 1436, 1436, 1436, + 1436, 1437, 1437, 0, 1437, 1437, 1437, 1437, 1437, 1437, + 1437, 1437, 1438, 1438, 0, 1438, 1438, 1438, 1438, 1438, + 1438, 1438, 1438, 1439, 0, 1439, 1439, 1440, 1440, 1441, + 0, 0, 1441, 1441, 1442, 0, 0, 0, 1442, 1442, + 1442, 1442, 1442, 1442, 1442, 1443, 1443, 0, 0, 1443, + 1443, 1443, 1443, 1443, 1443, 1443, 1444, 1444, 0, 1444, + + 1444, 1444, 1444, 1444, 1444, 1444, 1444, 1445, 0, 0, + 0, 1445, 1445, 1445, 1445, 1445, 1445, 1445, 1446, 0, + 0, 0, 1446, 1446, 1446, 1446, 1446, 1446, 1446, 1447, + 0, 0, 0, 1447, 1447, 1447, 1447, 1447, 1447, 1447, + 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, 1448, + 1448, 1449, 1449, 0, 1449, 1449, 1449, 1449, 1449, 1449, + 1449, 1449, 1450, 1450, 0, 1450, 1450, 1450, 1450, 1450, + 1450, 1450, 1450, 1451, 1451, 0, 1451, 1451, 1451, 1451, + 1451, 1451, 1451, 1451, 1452, 1452, 0, 1452, 1452, 1452, + 1452, 1452, 1452, 1452, 1452, 1453, 1453, 0, 1453, 1453, + + 1453, 1453, 1453, 1453, 1453, 1453, 1454, 1454, 1454, 1454, + 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1456, 1456, 0, + 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1456, 1457, 1457, + 0, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1458, + 1458, 0, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1459, 1459, 0, 1459, 1459, 1459, 1459, 1459, 1459, 1459, + 1459, 1460, 1460, 0, 1460, 1460, 1460, 1460, 1460, 1460, + 1460, 1460, 1461, 1461, 0, 1461, 1461, 1461, 1461, 1461, + 1461, 1461, 1461, 1462, 1462, 1462, 1462, 1462, 0, 1462, + 1462, 1462, 1462, 1462, 1463, 1463, 0, 1463, 1463, 1463, + + 1463, 1463, 1463, 1463, 1463, 1465, 1465, 1466, 1466, 1466, + 1466, 0, 1466, 1466, 1466, 1466, 1466, 1466, 1467, 1467, + 1467, 1467, 1467, 0, 1467, 1467, 1467, 1467, 1467, 1468, + 1468, 0, 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468, + 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, + 1469, 1470, 1470, 0, 1470, 1470, 1470, 1470, 1470, 1470, + 1470, 1470, 1471, 1471, 0, 1471, 1471, 1471, 1471, 1471, + 1471, 1471, 1471, 1472, 1472, 0, 1472, 1472, 1472, 1472, + 1472, 1472, 1472, 1472, 1473, 1473, 0, 1473, 1473, 1473, + 1473, 1473, 1473, 1473, 1473, 1474, 1474, 0, 1474, 1474, + + 1474, 1474, 1474, 1474, 1474, 1474, 1475, 1475, 0, 1475, + 1475, 1475, 1475, 1475, 1475, 1475, 1475, 1476, 1476, 0, + 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1476, 1477, 1477, + 0, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1477, 1478, + 1478, 0, 1478, 1478, 1478, 1478, 1478, 1478, 1478, 1478, + 1479, 1479, 0, 1479, 1479, 1479, 1479, 1479, 1479, 1479, + 1479, 1480, 1480, 0, 1480, 1480, 1480, 1480, 1480, 1480, + 1480, 1480, 1481, 1481, 0, 1481, 1481, 1481, 1481, 1481, + 1481, 1481, 1481, 1482, 1482, 0, 1482, 1482, 1482, 1482, + 1482, 1482, 1482, 1482, 1483, 1483, 0, 1483, 1483, 1483, + + 1483, 1483, 1483, 1483, 1483, 1484, 1484, 0, 1484, 1484, + 1484, 1484, 1484, 1484, 1484, 1484, 1485, 1485, 1485, 1485, + 1485, 1485, 1485, 1485, 1485, 1485, 1485, 1487, 1487, 1488, + 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, 1488, + 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, 1489, + 1489, 1490, 1490, 0, 1490, 1490, 1490, 1490, 1490, 1490, + 1490, 1490, 1491, 1491, 0, 1491, 1491, 1491, 1491, 1491, + 1491, 1491, 1491, 1492, 1492, 0, 1492, 1492, 1492, 1492, + 1492, 1492, 1492, 1492, 1493, 1493, 0, 1493, 1493, 1493, + 1493, 1493, 1493, 1493, 1493, 1494, 1494, 0, 1494, 1494, + + 1494, 1494, 1494, 1494, 1494, 1494, 1495, 1495, 0, 1495, + 1495, 1495, 1495, 1495, 1495, 1495, 1495, 1496, 1496, 0, + 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1496, 1497, 1497, + 0, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1497, 1498, + 1498, 0, 1498, 1498, 1498, 1498, 1498, 1498, 1498, 1498, + 1499, 1499, 0, 1499, 1499, 1499, 1499, 1499, 1499, 1499, + 1499, 1500, 1500, 0, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1501, 1501, 0, 1501, 1501, 1501, 1501, 1501, + 1501, 1501, 1501, 1502, 1502, 0, 1502, 1502, 1502, 1502, + 1502, 1502, 1502, 1502, 1503, 1503, 0, 1503, 1503, 1503, + + 1503, 1503, 1503, 1503, 1503, 1504, 1504, 0, 1504, 1504, + 1504, 1504, 1504, 1504, 1504, 1504, 1505, 1505, 0, 1505, + 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1506, 1506, 0, + 1506, 1506, 1506, 1506, 1506, 1506, 1506, 1506, 1507, 1507, + 0, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1508, + 1508, 0, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, + 1509, 1509, 0, 1509, 1509, 1509, 1509, 1509, 1509, 1509, + 1509, 1510, 1510, 1510, 1510, 1510, 1510, 1510, 1510, 1510, + 1510, 1510, 1511, 1511, 1511, 1511, 1511, 1511, 1511, 1511, + 1511, 1511, 1511, 1512, 1512, 1512, 1512, 1512, 1512, 1512, + + 1512, 1512, 1512, 1512, 1513, 1513, 0, 1513, 1513, 1513, + 1513, 1513, 1513, 1513, 1513, 1514, 1514, 0, 1514, 1514, + 1514, 1514, 1514, 1514, 1514, 1514, 1515, 1515, 0, 1515, + 1515, 1515, 1515, 1515, 1515, 1515, 1515, 1516, 1516, 0, + 1516, 1516, 1516, 1516, 1516, 1516, 1516, 1516, 1517, 1517, + 0, 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1518, + 1518, 0, 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, + 1519, 1519, 0, 1519, 1519, 1519, 1519, 1519, 1519, 1519, + 1519, 1520, 1520, 0, 1520, 1520, 1520, 1520, 1520, 1520, + 1520, 1520, 1521, 1521, 0, 1521, 1521, 1521, 1521, 1521, + + 1521, 1521, 1521, 1522, 0, 1522, 1522, 1522, 1522, 1522, + 1522, 1522, 1522, 1522, 1523, 1523, 0, 1523, 1523, 1523, + 1523, 1523, 1523, 1523, 1523, 1524, 1524, 1524, 1524, 1524, + 1524, 1524, 1524, 1524, 1524, 1524, 1525, 1525, 0, 1525, + 1525, 1525, 1525, 1525, 1525, 1525, 1525, 1526, 1526, 0, + 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1526, 1527, 1527, + 0, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1527, 1528, + 1528, 0, 1528, 1528, 1528, 1528, 1528, 1528, 1528, 1528, + 1529, 1529, 0, 1529, 1529, 1529, 1529, 1529, 1529, 1529, + 1529, 1530, 1530, 0, 1530, 1530, 1530, 1530, 1530, 1530, + + 1530, 1530, 1531, 1531, 0, 1531, 1531, 1531, 1531, 1531, + 1531, 1531, 1531, 1532, 1532, 0, 1532, 1532, 1532, 1532, + 1532, 1532, 1532, 1532, 1533, 1533, 0, 1533, 1533, 1533, + 1533, 1533, 1533, 1533, 1533, 1534, 1534, 0, 1534, 1534, + 1534, 1534, 1534, 1534, 1534, 1534, 1535, 1535, 0, 1535, + 1535, 1535, 1535, 1535, 1535, 1535, 1535, 1536, 1536, 0, + 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1537, 1537, + 0, 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1537, 1538, + 1538, 0, 1538, 1538, 1538, 1538, 1538, 1538, 1538, 1538, + 1539, 1539, 0, 1539, 1539, 1539, 1539, 1539, 1539, 1539, + + 1539, 1540, 1540, 0, 1540, 1540, 1540, 1540, 1540, 1540, + 1540, 1540, 1541, 1541, 0, 1541, 1541, 1541, 1541, 1541, + 1541, 1541, 1541, 1542, 1542, 0, 1542, 1542, 1542, 1542, + 1542, 1542, 1542, 1542, 1543, 1543, 0, 1543, 1543, 1543, + 1543, 1543, 1543, 1543, 1543, 1544, 1544, 0, 1544, 1544, + 1544, 1544, 1544, 1544, 1544, 1544, 1545, 1545, 0, 1545, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1546, 1546, 0, + 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1547, 1547, + 0, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1548, + 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, + + 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, + 1549, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, + 1550, 1550, 1551, 1551, 0, 1551, 1551, 1551, 1551, 1551, + 1551, 1551, 1551, 1552, 1552, 0, 1552, 1552, 1552, 1552, + 1552, 1552, 1552, 1552, 1553, 1553, 0, 1553, 1553, 1553, + 1553, 1553, 1553, 1553, 1553, 1554, 1554, 0, 1554, 1554, + 1554, 1554, 1554, 1554, 1554, 1554, 1555, 1555, 0, 1555, + 1555, 1555, 1555, 1555, 1555, 1555, 1555, 1556, 1556, 0, + 1556, 1556, 1556, 1556, 1556, 1556, 1556, 1556, 1557, 1557, + 0, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1558, + + 0, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, + 1559, 1559, 0, 1559, 1559, 1559, 1559, 1559, 1559, 1559, + 1559, 1560, 1560, 0, 1560, 1560, 1560, 1560, 1560, 1560, + 1560, 1560, 1561, 1561, 0, 1561, 1561, 1561, 1561, 1561, + 1561, 1561, 1561, 1562, 0, 1562, 1562, 1563, 1563, 0, + 1563, 1563, 1563, 1563, 1563, 1563, 1563, 1563, 1564, 1564, + 0, 1564, 1564, 1564, 1564, 1564, 1564, 1564, 1564, 1565, + 1565, 0, 1565, 1565, 1565, 1565, 1565, 1565, 1565, 1565, + 1566, 1566, 0, 1566, 1566, 1566, 1566, 1566, 1566, 1566, + 1566, 1567, 1567, 0, 1567, 1567, 1567, 1567, 1567, 1567, + + 1567, 1567, 1568, 1568, 0, 1568, 1568, 1568, 1568, 1568, + 1568, 1568, 1568, 1569, 1569, 0, 1569, 1569, 1569, 1569, + 1569, 1569, 1569, 1569, 1570, 1570, 0, 1570, 1570, 1570, + 1570, 1570, 1570, 1570, 1570, 1571, 1571, 1571, 1571, 1571, + 1571, 1571, 1571, 1571, 1571, 1571, 1572, 1572, 0, 1572, + 1572, 1572, 1572, 1572, 1572, 1572, 1572, 1573, 1573, 0, + 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1573, 1574, 1574, + 0, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1574, 1576, + 1576, 0, 1576, 1576, 1576, 1576, 1576, 1576, 1576, 1576, + 1577, 1577, 0, 1577, 1577, 1577, 1577, 1577, 1577, 1577, + + 1577, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, 1578, + 1578, 1578, 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579, + 1579, 1579, 1579, 1580, 1580, 1580, 1580, 1580, 1580, 1580, + 1580, 1580, 1580, 1580, 1581, 1581, 0, 1581, 1581, 1581, + 1581, 1581, 1581, 1581, 1581, 1582, 0, 1582, 0, 1582, + 1582, 1583, 1583, 0, 1583, 1583, 1583, 1583, 1583, 1583, + 1583, 1583, 1584, 0, 1584, 1584, 1585, 0, 1585, 1585, + 1588, 1588, 0, 1588, 1588, 1588, 1588, 1588, 1588, 1588, + 1588, 1589, 1589, 0, 1589, 1589, 1589, 1589, 1589, 1589, + 1589, 1589, 1590, 1590, 0, 1590, 1590, 1590, 1590, 1590, + + 1590, 1590, 1590, 1591, 0, 1591, 1591, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409, + 1409, 1409, 1409, 1409 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "lexgrog.l" + +#line 8 "lexgrog.l" + +/* + * lexgrog.l: extract 'whatis' info from nroff man / formatted cat pages. + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + * 2011, 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Wed Oct 12 18:46:11 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * CJW: Detect grap and vgrind. Understand fill requests. Other improvements + * in the syntax accepted. + */ + +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "decompress.h" +#include "security.h" +#include "encodings.h" +#include "sandbox.h" + +#include "manconv_client.h" + +#define YY_READ_BUF_SIZE 1024 +#define MAX_NAME 8192 + +#define ARRAY_SIZE(array) (sizeof (array) / sizeof ((array)[0])) + +extern man_sandbox *sandbox; + +struct macro { + const char *name; + const char *value; +}; + +static const struct macro glyphs[] = { + /* It is vital to keep these in strcmp order (sort -t\" -k2)! They + * will be searched using bsearch. + * Data from groff_char(7), although I have omitted some that are + * particularly unlikely to be used in NAME sections. + */ + { "'A", "Á" }, + { "'C", "Ć" }, + { "'E", "É" }, + { "'I", "Í" }, + { "'O", "Ó" }, + { "'U", "Ú" }, + { "'Y", "Ý" }, + { "'a", "á" }, + { "'c", "ć" }, + { "'e", "é" }, + { "'i", "í" }, + { "'o", "ó" }, + { "'u", "ú" }, + { "'y", "ý" }, + { ",C", "Ç" }, + { ",c", "ç" }, + { "-D", "Ð" }, + { ".i", "ı" }, + { "/L", "Ł" }, + { "/O", "Ø" }, + { "/l", "ł" }, + { "/o", "ø" }, + { ":A", "Ä" }, + { ":E", "Ë" }, + { ":I", "Ï" }, + { ":O", "Ö" }, + { ":U", "Ü" }, + { ":Y", "Ÿ" }, + { ":a", "ä" }, + { ":e", "ë" }, + { ":i", "ï" }, + { ":o", "ö" }, + { ":u", "ü" }, + { ":y", "ÿ" }, + { "AE", "Æ" }, + { "Bq", "„" }, + { "Fc", "»" }, + { "Fi", "ffi" }, + { "Fl", "ffl" }, + { "Fo", "«" }, + { "IJ", "IJ" }, + { "OE", "Œ" }, + { "Sd", "ð" }, + { "TP", "Þ" }, + { "Tp", "þ" }, + { "^A", "Â" }, + { "^E", "Ê" }, + { "^I", "Î" }, + { "^O", "Ô" }, + { "^U", "Û" }, + { "^a", "â" }, + { "^e", "ê" }, + { "^i", "î" }, + { "^o", "ô" }, + { "^u", "û" }, + { "`A", "À" }, + { "`E", "È" }, + { "`I", "Ì" }, + { "`O", "Ò" }, + { "`U", "Ù" }, + { "`a", "à" }, + { "`e", "è" }, + { "`i", "ì" }, + { "`o", "ò" }, + { "`u", "ù" }, + { "a\"", "˝" }, + { "a-", "¯" }, + { "a.", "˙" }, + { "a^", "^" }, + { "aa", "´" }, + { "ab", "˘" }, + { "ac", "¸" }, + { "ad", "¨" }, + { "ae", "æ" }, + { "ah", "ˇ" }, + { "ao", "˚" }, + { "aq", "'" }, + { "a~", "~" }, + { "bq", "‚" }, + { "cq", "’" }, + { "dq", "\"" }, + { "em", "—" }, + { "en", "–" }, + { "fc", "›" }, + { "ff", "ff" }, + { "fi", "fi" }, + { "fl", "fl" }, + { "fo", "‹" }, + { "ga", "`" }, + { "ha", "^" }, + { "ho", "˛" }, + { "hy", "‐" }, + { "ij", "ij" }, + { "lq", "“" }, + { "oA", "Å" }, + { "oa", "å" }, + { "oe", "œ" }, + { "oq", "‘" }, + { "r!", "¡" }, + { "r?", "¿" }, + { "rq", "”" }, + { "ss", "ß" }, + { "ti", "~" }, + { "vS", "Š" }, + { "vZ", "Ž" }, + { "vs", "š" }, + { "vz", "ž" }, + { "~A", "Ã" }, + { "~N", "Ñ" }, + { "~O", "Õ" }, + { "~a", "ã" }, + { "~n", "ñ" }, + { "~o", "õ" } +}; + +static const struct macro perldocs[] = { + /* It is vital to keep these in strcmp order (sort -t\" -k2)! They + * will be searched using bsearch. + * Data from Pod/Man.pm. + */ + { "--", "-" }, + { "Aq", "'" }, + { "C'", "'" }, + { "C+", "C++" }, + { "C`", "`" }, + { "L\"", "\"" }, + { "PI", "π" }, + { "R\"", "\"" } +}; + +static void add_str_to_whatis (const char *string, size_t length); +static void add_char_to_whatis (unsigned char c); +static void add_separator_to_whatis (void); +static void add_wordn_to_whatis (const char *string, size_t length); +static void add_word_to_whatis (const char *string); +static void add_glyph_to_whatis (const char *string, size_t length); +static void add_perldoc_to_whatis (const char *string, size_t length); +static void mdoc_text (const char *string); +static void newline_found (void); + +static char newname[MAX_NAME]; +static char *p_name; +static const char *fname; +static char filters[MAX_FILTERS]; + +static int fill_mode; +static int waiting_for_quote; + +static pipeline *decomp; + +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = pipeline_read (decomp, &size); \ + if (block && size != 0) { \ + memcpy (buf, block, size); \ + buf[size] = '\0'; \ + result = size; \ + } else \ + result = YY_NULL; \ +} +#define YY_NO_INPUT +#line 2807 "lexgrog.c" + +#line 283 "lexgrog.l" + /* Please add to this list if you know how. */ + /* Note that, since flex only supports UTF-8 by accident, character classes + * including non-ASCII characters must be written out as (a|b|c|d) rather + * than [abcd]. + */ + /* NOME also works for gl, pt */ + /* eptgrv : eqn, pic, tbl, grap, refer, vgrind */ +#line 2817 "lexgrog.c" + +#define INITIAL 0 +#define MAN_PRENAME 1 +#define MAN_NAME 2 +#define MAN_DESC 3 +#define MAN_DESC_AT 4 +#define MAN_DESC_BSX 5 +#define MAN_DESC_BX 6 +#define MAN_DESC_BX_RELEASE 7 +#define MAN_DESC_DQ 8 +#define MAN_DESC_FX 9 +#define MAN_DESC_NX 10 +#define MAN_DESC_OX 11 +#define CAT_NAME 12 +#define CAT_FILE 13 +#define MAN_FILE 14 +#define CAT_REST 15 +#define MAN_REST 16 +#define FORCE_EXIT 17 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 327 "lexgrog.l" + + + /* begin NAME section processing */ +#line 3053 "lexgrog.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1410 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 1409 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 330 "lexgrog.l" +BEGIN (MAN_PRENAME); + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 331 "lexgrog.l" +BEGIN (CAT_NAME); + YY_BREAK +/* general text matching */ + +case 3: +#line 336 "lexgrog.l" +case 4: +#line 337 "lexgrog.l" +case 5: +#line 338 "lexgrog.l" +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 338 "lexgrog.l" + + YY_BREAK + + +case 7: +#line 343 "lexgrog.l" +case 8: +#line 344 "lexgrog.l" +case 9: +/* rule 9 can match eol */ +#line 345 "lexgrog.l" +case 10: +/* rule 10 can match eol */ +YY_RULE_SETUP +#line 345 "lexgrog.l" + + YY_BREAK + + +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 349 "lexgrog.l" +filters[TBL_FILTER] = 't'; + YY_BREAK +case 12: +/* rule 12 can match eol */ +YY_RULE_SETUP +#line 350 "lexgrog.l" +filters[EQN_FILTER] = 'e'; + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 351 "lexgrog.l" +filters[PIC_FILTER] = 'p'; + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 352 "lexgrog.l" +filters[GRAP_FILTER] = 'g'; + YY_BREAK +case 15: +/* rule 15 can match eol */ +#line 354 "lexgrog.l" +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 354 "lexgrog.l" +filters[REF_FILTER] = 'r'; + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 355 "lexgrog.l" +filters[VGRIND_FILTER] = 'v'; + YY_BREAK + +case YY_STATE_EOF(MAN_REST): +#line 357 "lexgrog.l" +{ /* exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} + YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +#line 361 "lexgrog.l" + + YY_BREAK +/* rules to end NAME section processing */ +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 364 "lexgrog.l" +{ /* forced exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} + YY_BREAK +case 20: +/* rule 20 can match eol */ +#line 370 "lexgrog.l" +YY_RULE_SETUP +case YY_STATE_EOF(MAN_PRENAME): +#line 370 "lexgrog.l" +{ /* no NAME at all */ + *p_name = '\0'; + BEGIN (MAN_REST); +} + YY_BREAK +/* need to match whole string so that we beat the following roff catch-all, + so use yyless to push back the name */ + +case 21: +/* rule 21 can match eol */ +#line 379 "lexgrog.l" +case 22: +/* rule 22 can match eol */ +#line 380 "lexgrog.l" +case 23: +/* rule 23 can match eol */ +#line 381 "lexgrog.l" +case 24: +/* rule 24 can match eol */ +#line 382 "lexgrog.l" +case 25: +/* rule 25 can match eol */ +#line 383 "lexgrog.l" +case 26: +/* rule 26 can match eol */ +YY_RULE_SETUP +#line 383 "lexgrog.l" +{ + yyless (0); + BEGIN (MAN_NAME); + } + YY_BREAK + +/* Skip over initial roff requests in NAME section. The use of yyless here + is evil. */ +case 27: +/* rule 27 can match eol */ +YY_RULE_SETUP +#line 391 "lexgrog.l" + + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +#line 393 "lexgrog.l" +yyless (1); + YY_BREAK +case 29: +/* rule 29 can match eol */ +YY_RULE_SETUP +#line 395 "lexgrog.l" +{ + yyless (0); + BEGIN (MAN_NAME); +} + YY_BREAK + +case 30: +/* rule 30 can match eol */ +#line 402 "lexgrog.l" +case 31: +/* rule 31 can match eol */ +#line 403 "lexgrog.l" +case 32: +/* rule 32 can match eol */ +#line 404 "lexgrog.l" +case 33: +/* rule 33 can match eol */ +#line 405 "lexgrog.l" +case 34: +/* rule 34 can match eol */ +#line 406 "lexgrog.l" +case 35: +/* rule 35 can match eol */ +#line 407 "lexgrog.l" +case 36: +/* rule 36 can match eol */ +#line 408 "lexgrog.l" +YY_RULE_SETUP +case YY_STATE_EOF(MAN_NAME): +YY_RULE_SETUP +case YY_STATE_EOF(MAN_DESC): +#line 408 "lexgrog.l" +{ /* terminate the string */ + *p_name = '\0'; + BEGIN (MAN_REST); + } + YY_BREAK + + +case 37: +/* rule 37 can match eol */ +#line 416 "lexgrog.l" +case 38: +/* rule 38 can match eol */ +#line 417 "lexgrog.l" +case 39: +/* rule 39 can match eol */ +YY_RULE_SETUP +#line 417 "lexgrog.l" +{ /* terminate the string */ + *p_name = '\0'; + BEGIN (CAT_REST); + yyterminate (); + } + YY_BREAK + +/* ROFF request removal */ + +/* some include quoting; dealing with this is unpleasant */ +case 40: +/* rule 40 can match eol */ +YY_RULE_SETUP +#line 427 "lexgrog.l" +{ + newline_found (); + waiting_for_quote = 1; + } + YY_BREAK +case 41: +/* rule 41 can match eol */ +#line 433 "lexgrog.l" +case 42: +/* rule 42 can match eol */ +#line 434 "lexgrog.l" +case 43: +/* rule 43 can match eol */ +#line 435 "lexgrog.l" +case 44: +/* rule 44 can match eol */ +#line 436 "lexgrog.l" +case 45: +/* rule 45 can match eol */ +#line 437 "lexgrog.l" +case 46: +/* rule 46 can match eol */ +#line 438 "lexgrog.l" +case 47: +/* rule 47 can match eol */ +#line 439 "lexgrog.l" +case 48: +/* rule 48 can match eol */ +#line 440 "lexgrog.l" +case 49: +/* rule 49 can match eol */ +YY_RULE_SETUP +#line 440 "lexgrog.l" +{ /* per line comments */ + newline_found (); + } + YY_BREAK + +/* No-op requests */ + +case 50: +/* rule 50 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 447 "lexgrog.l" +newline_found (); + YY_BREAK +case 51: +/* rule 51 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ +YY_LINENO_REWIND_TO(yy_cp - 1); +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 448 "lexgrog.l" +newline_found (); + YY_BREAK + +/* Toggle fill mode */ + +case 52: +/* rule 52 can match eol */ +YY_RULE_SETUP +#line 453 "lexgrog.l" +fill_mode = 0; + YY_BREAK +case 53: +/* rule 53 can match eol */ +YY_RULE_SETUP +#line 454 "lexgrog.l" +fill_mode = 1; + YY_BREAK + +case 54: +/* rule 54 can match eol */ +YY_RULE_SETUP +#line 457 "lexgrog.l" +/* strip continuations */ + YY_BREAK +/* convert to DASH */ + +case 55: +/* rule 55 can match eol */ +#line 462 "lexgrog.l" +case 56: +/* rule 56 can match eol */ +#line 463 "lexgrog.l" +case 57: +/* rule 57 can match eol */ +#line 464 "lexgrog.l" +case 58: +/* rule 58 can match eol */ +YY_RULE_SETUP +#line 464 "lexgrog.l" +{ + add_separator_to_whatis (); + BEGIN (MAN_DESC); + } + YY_BREAK + +case 59: +/* rule 59 can match eol */ +YY_RULE_SETUP +#line 469 "lexgrog.l" +add_separator_to_whatis (); + YY_BREAK +/* escape sequences and special characters */ + +case 60: +/* rule 60 can match eol */ +YY_RULE_SETUP +#line 473 "lexgrog.l" +add_char_to_whatis ('\\'); + YY_BREAK +case 61: +/* rule 61 can match eol */ +YY_RULE_SETUP +#line 474 "lexgrog.l" +add_char_to_whatis ('\''); + YY_BREAK +case 62: +/* rule 62 can match eol */ +YY_RULE_SETUP +#line 475 "lexgrog.l" +add_char_to_whatis ('`'); + YY_BREAK +case 63: +/* rule 63 can match eol */ +YY_RULE_SETUP +#line 476 "lexgrog.l" +add_char_to_whatis ('-'); + YY_BREAK +case 64: +/* rule 64 can match eol */ +YY_RULE_SETUP +#line 477 "lexgrog.l" +add_char_to_whatis ('.'); + YY_BREAK +case 65: +/* rule 65 can match eol */ +YY_RULE_SETUP +#line 478 "lexgrog.l" +add_char_to_whatis (' '); + YY_BREAK +case 66: +/* rule 66 can match eol */ +YY_RULE_SETUP +#line 479 "lexgrog.l" +add_char_to_whatis ('_'); + YY_BREAK +case 67: +/* rule 67 can match eol */ +YY_RULE_SETUP +#line 480 "lexgrog.l" +add_char_to_whatis ('\t'); + YY_BREAK +case 68: +/* rule 68 can match eol */ +YY_RULE_SETUP +#line 482 "lexgrog.l" +/* various useless control chars */ + YY_BREAK +case 69: +/* rule 69 can match eol */ +YY_RULE_SETUP +#line 483 "lexgrog.l" +/* various inline functions */ + YY_BREAK +case 70: +/* rule 70 can match eol */ +YY_RULE_SETUP +#line 485 "lexgrog.l" +/* interpolate arg */ + YY_BREAK +/* roff named glyphs */ +case 71: +/* rule 71 can match eol */ +YY_RULE_SETUP +#line 488 "lexgrog.l" +add_glyph_to_whatis (yytext + 2, 2); + YY_BREAK +/* perldoc strings */ +case 72: +/* rule 72 can match eol */ +YY_RULE_SETUP +#line 490 "lexgrog.l" +add_perldoc_to_whatis (yytext + 3, 2); + YY_BREAK +case 73: +/* rule 73 can match eol */ +YY_RULE_SETUP +#line 491 "lexgrog.l" +add_perldoc_to_whatis (yytext + 2, 1); + YY_BREAK +case 74: +/* rule 74 can match eol */ +YY_RULE_SETUP +#line 493 "lexgrog.l" +/* comment */ + YY_BREAK +case 75: +/* rule 75 can match eol */ +YY_RULE_SETUP +#line 495 "lexgrog.l" +/* font changes */ + YY_BREAK +case 76: +/* rule 76 can match eol */ +YY_RULE_SETUP +#line 496 "lexgrog.l" +/* mark input place in register */ + YY_BREAK +case 77: +/* rule 77 can match eol */ +YY_RULE_SETUP +#line 498 "lexgrog.l" +/* interpolate number register */ + YY_BREAK +case 78: +/* rule 78 can match eol */ +YY_RULE_SETUP +#line 499 "lexgrog.l" +/* overstrike chars */ + YY_BREAK +case 79: +/* rule 79 can match eol */ +YY_RULE_SETUP +#line 501 "lexgrog.l" +/* size changes */ + YY_BREAK +case 80: +/* rule 80 can match eol */ +YY_RULE_SETUP +#line 502 "lexgrog.l" +/* width of string */ + YY_BREAK +case 81: +/* rule 81 can match eol */ +YY_RULE_SETUP +#line 504 "lexgrog.l" +/* catch all */ + YY_BREAK +case 82: +/* rule 82 can match eol */ +YY_RULE_SETUP +#line 506 "lexgrog.l" +/* function() in hpux */ + YY_BREAK + +/* some people rather ambitiously use non-trivial mdoc macros in NAME + sections; cope with those that have been seen in the wild, and a few + more */ + +case 83: +/* rule 83 can match eol */ +YY_RULE_SETUP +#line 513 "lexgrog.l" +BEGIN (MAN_DESC_AT); + YY_BREAK +case 84: +/* rule 84 can match eol */ +YY_RULE_SETUP +#line 514 "lexgrog.l" +BEGIN (MAN_DESC_BSX); + YY_BREAK +case 85: +/* rule 85 can match eol */ +YY_RULE_SETUP +#line 515 "lexgrog.l" +BEGIN (MAN_DESC_BX); + YY_BREAK +case 86: +/* rule 86 can match eol */ +YY_RULE_SETUP +#line 516 "lexgrog.l" +BEGIN (MAN_DESC_FX); + YY_BREAK +case 87: +/* rule 87 can match eol */ +YY_RULE_SETUP +#line 517 "lexgrog.l" +BEGIN (MAN_DESC_NX); + YY_BREAK +case 88: +/* rule 88 can match eol */ +YY_RULE_SETUP +#line 518 "lexgrog.l" +BEGIN (MAN_DESC_OX); + YY_BREAK +case 89: +/* rule 89 can match eol */ +YY_RULE_SETUP +#line 519 "lexgrog.l" +add_word_to_whatis ("UNIX"); + YY_BREAK +case 90: +/* rule 90 can match eol */ +YY_RULE_SETUP +#line 521 "lexgrog.l" +{ + add_word_to_whatis ("\""); + BEGIN (MAN_DESC_DQ); + } + YY_BREAK + + +case 91: +YY_RULE_SETUP +#line 528 "lexgrog.l" +mdoc_text ("Version 32V AT&T UNIX"); + YY_BREAK +case 92: +YY_RULE_SETUP +#line 529 "lexgrog.l" +mdoc_text ("Version 1 AT&T UNIX"); + YY_BREAK +case 93: +YY_RULE_SETUP +#line 530 "lexgrog.l" +mdoc_text ("Version 2 AT&T UNIX"); + YY_BREAK +case 94: +YY_RULE_SETUP +#line 531 "lexgrog.l" +mdoc_text ("Version 3 AT&T UNIX"); + YY_BREAK +case 95: +YY_RULE_SETUP +#line 532 "lexgrog.l" +mdoc_text ("Version 4 AT&T UNIX"); + YY_BREAK +case 96: +YY_RULE_SETUP +#line 533 "lexgrog.l" +mdoc_text ("Version 5 AT&T UNIX"); + YY_BREAK +case 97: +YY_RULE_SETUP +#line 534 "lexgrog.l" +mdoc_text ("Version 6 AT&T UNIX"); + YY_BREAK +case 98: +YY_RULE_SETUP +#line 535 "lexgrog.l" +mdoc_text ("Version 7 AT&T UNIX"); + YY_BREAK +case 99: +YY_RULE_SETUP +#line 536 "lexgrog.l" +mdoc_text ("AT&T System V UNIX"); + YY_BREAK +case 100: +YY_RULE_SETUP +#line 537 "lexgrog.l" +mdoc_text ("AT&T System V.1 UNIX"); + YY_BREAK +case 101: +YY_RULE_SETUP +#line 538 "lexgrog.l" +mdoc_text ("AT&T System V.2 UNIX"); + YY_BREAK +case 102: +YY_RULE_SETUP +#line 539 "lexgrog.l" +mdoc_text ("AT&T System V.3 UNIX"); + YY_BREAK +case 103: +YY_RULE_SETUP +#line 540 "lexgrog.l" +mdoc_text ("AT&T System V.4 UNIX"); + YY_BREAK +case 104: +/* rule 104 can match eol */ +YY_RULE_SETUP +#line 541 "lexgrog.l" +{ + yyless (0); + mdoc_text ("AT&T UNIX"); + } + YY_BREAK + + +case 105: +YY_RULE_SETUP +#line 548 "lexgrog.l" +{ + add_word_to_whatis ("BSD/OS"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 106: +/* rule 106 can match eol */ +YY_RULE_SETUP +#line 553 "lexgrog.l" +{ + yyless (0); + mdoc_text ("BSD/OS"); + } + YY_BREAK + + +case 107: +YY_RULE_SETUP +#line 560 "lexgrog.l" +mdoc_text ("BSD (currently in alpha test)"); + YY_BREAK +case 108: +YY_RULE_SETUP +#line 561 "lexgrog.l" +mdoc_text ("BSD (currently in beta test)"); + YY_BREAK +case 109: +YY_RULE_SETUP +#line 562 "lexgrog.l" +mdoc_text ("BSD (currently under development"); + YY_BREAK +case 110: +YY_RULE_SETUP +#line 563 "lexgrog.l" +{ + add_wordn_to_whatis (yytext, yyleng); + add_str_to_whatis ("BSD", 3); + BEGIN (MAN_DESC_BX_RELEASE); + } + YY_BREAK +case 111: +/* rule 111 can match eol */ +YY_RULE_SETUP +#line 568 "lexgrog.l" +{ + yyless (0); + mdoc_text ("BSD"); + } + YY_BREAK + + +case 112: +YY_RULE_SETUP +#line 575 "lexgrog.l" +{ + add_str_to_whatis ("-Reno", 5); + BEGIN (MAN_DESC); + } + YY_BREAK +case 113: +YY_RULE_SETUP +#line 579 "lexgrog.l" +{ + add_str_to_whatis ("-Tahoe", 6); + BEGIN (MAN_DESC); + } + YY_BREAK +case 114: +YY_RULE_SETUP +#line 583 "lexgrog.l" +{ + add_str_to_whatis ("-Lite", 5); + BEGIN (MAN_DESC); + } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 587 "lexgrog.l" +{ + add_str_to_whatis ("-Lite2", 6); + BEGIN (MAN_DESC); + } + YY_BREAK +case 116: +/* rule 116 can match eol */ +YY_RULE_SETUP +#line 591 "lexgrog.l" +{ + yyless (0); + BEGIN (MAN_DESC); + } + YY_BREAK + +case 117: +YY_RULE_SETUP +#line 597 "lexgrog.l" +{ + add_str_to_whatis (yytext, yyleng); + add_char_to_whatis ('"'); + BEGIN (MAN_DESC); +} + YY_BREAK + +case 118: +YY_RULE_SETUP +#line 604 "lexgrog.l" +{ + add_word_to_whatis ("FreeBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 119: +/* rule 119 can match eol */ +YY_RULE_SETUP +#line 609 "lexgrog.l" +{ + yyless (0); + mdoc_text ("FreeBSD"); + } + YY_BREAK + + +case 120: +YY_RULE_SETUP +#line 616 "lexgrog.l" +{ + add_word_to_whatis ("NetBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 121: +/* rule 121 can match eol */ +YY_RULE_SETUP +#line 621 "lexgrog.l" +{ + yyless (0); + mdoc_text ("NetBSD"); + } + YY_BREAK + + +case 122: +YY_RULE_SETUP +#line 628 "lexgrog.l" +{ + add_word_to_whatis ("OpenBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 123: +/* rule 123 can match eol */ +YY_RULE_SETUP +#line 633 "lexgrog.l" +{ + yyless (0); + mdoc_text ("OpenBSD"); + } + YY_BREAK + +/* collapse spaces, escaped spaces, tabs, newlines to a single space */ +case 124: +/* rule 124 can match eol */ +YY_RULE_SETUP +#line 640 "lexgrog.l" +add_char_to_whatis (' '); + YY_BREAK +/* a ROFF break request, a paragraph request, or an indentation change + usually means we have multiple whatis definitions, provide a separator + for later processing */ + +case 125: +/* rule 125 can match eol */ +#line 647 "lexgrog.l" +case 126: +/* rule 126 can match eol */ +#line 648 "lexgrog.l" +case 127: +/* rule 127 can match eol */ +#line 649 "lexgrog.l" +case 128: +/* rule 128 can match eol */ +#line 650 "lexgrog.l" +case 129: +/* rule 129 can match eol */ +#line 651 "lexgrog.l" +case 130: +/* rule 130 can match eol */ +#line 652 "lexgrog.l" +case 131: +/* rule 131 can match eol */ +#line 653 "lexgrog.l" +case 132: +/* rule 132 can match eol */ +YY_RULE_SETUP +#line 653 "lexgrog.l" +{ + add_char_to_whatis ((char) 0x11); + BEGIN (MAN_NAME); + } + YY_BREAK + +/* any other roff request we don't recognise terminates definitions */ +case 133: +/* rule 133 can match eol */ +YY_RULE_SETUP +#line 660 "lexgrog.l" +{ + *p_name = '\0'; + BEGIN (MAN_REST); +} + YY_BREAK +/* pass words as a chunk. speed optimization */ +case 134: +YY_RULE_SETUP +#line 666 "lexgrog.l" +add_str_to_whatis (yytext, yyleng); + YY_BREAK +/* normalise the comma (,) separators */ +case 135: +/* rule 135 can match eol */ +#line 670 "lexgrog.l" +case 136: +/* rule 136 can match eol */ +YY_RULE_SETUP +#line 670 "lexgrog.l" +add_str_to_whatis (", ", 2); + YY_BREAK +case 137: +/* rule 137 can match eol */ +YY_RULE_SETUP +#line 672 "lexgrog.l" +{ + newline_found (); + add_char_to_whatis (yytext[yyleng - 1]); +} + YY_BREAK +case 138: +YY_RULE_SETUP +#line 677 "lexgrog.l" +add_char_to_whatis (*yytext); + YY_BREAK +/* default EOF rule */ +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(MAN_DESC_AT): +case YY_STATE_EOF(MAN_DESC_BSX): +case YY_STATE_EOF(MAN_DESC_BX): +case YY_STATE_EOF(MAN_DESC_BX_RELEASE): +case YY_STATE_EOF(MAN_DESC_DQ): +case YY_STATE_EOF(MAN_DESC_FX): +case YY_STATE_EOF(MAN_DESC_NX): +case YY_STATE_EOF(MAN_DESC_OX): +case YY_STATE_EOF(CAT_NAME): +case YY_STATE_EOF(CAT_FILE): +case YY_STATE_EOF(MAN_FILE): +case YY_STATE_EOF(CAT_REST): +case YY_STATE_EOF(FORCE_EXIT): +#line 680 "lexgrog.l" +return 1; + YY_BREAK +case 139: +YY_RULE_SETUP +#line 682 "lexgrog.l" +ECHO; + YY_BREAK +#line 3988 "lexgrog.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1410 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 1410 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 1409); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 682 "lexgrog.l" + + +/* print warning and force scanner to terminate */ +static void too_big (void) +{ + /* Even though MAX_NAME is a macro expanding to a constant, we + * translate it using ngettext anyway because that will make it + * easier to change the macro later. + */ + error (0, 0, + ngettext ("warning: whatis for %s exceeds %d byte, " + "truncating.", + "warning: whatis for %s exceeds %d bytes, " + "truncating.", MAX_NAME), + fname, MAX_NAME); + + BEGIN (FORCE_EXIT); +} + +/* append a string to newname if enough room */ +static void add_str_to_whatis (const char *string, size_t length) +{ + if (p_name - newname + length >= MAX_NAME) + too_big (); + else { + (void) strncpy (p_name, string, length); + p_name += length; + } +} + +/* append a char to newname if enough room */ +static void add_char_to_whatis (unsigned char c) +{ + if (p_name - newname + 1 >= MAX_NAME) + too_big (); + else if (waiting_for_quote && c == '"') + waiting_for_quote = 0; + else + *p_name++ = c; +} + +/* append the " - " separator to newname, trimming the first space if one's + * already there + */ +static void add_separator_to_whatis (void) +{ + if (p_name != newname && *(p_name - 1) != ' ') + add_char_to_whatis (' '); + add_str_to_whatis ("- ", 2); +} + +/* append a word to newname if enough room, ensuring only necessary + surrounding space */ +static void add_wordn_to_whatis (const char *string, size_t length) +{ + if (p_name != newname && *(p_name - 1) != ' ') + add_char_to_whatis (' '); + while (length && string[length - 1] == ' ') + --length; + if (length) + add_str_to_whatis (string, length); +} + +static void add_word_to_whatis (const char *string) +{ + add_wordn_to_whatis (string, strlen (string)); +} + +struct compare_macro_key { + const char *string; + size_t length; +}; + +static int compare_macro (const void *left, const void *right) +{ + const struct compare_macro_key *key = left; + const struct macro *value = right; + int cmp; + + cmp = strncmp (key->string, value->name, key->length); + if (cmp) + return cmp; + /* equal up to key->length, so value->name must be at least size + * key->length + 1 + */ + else if (value->name[key->length]) + return -1; + else + return 0; +} + +static void add_macro_to_whatis (const struct macro *macros, size_t n_macros, + const char *string, size_t length) +{ + struct compare_macro_key key; + const struct macro *macro; + + key.string = string; + key.length = length; + macro = bsearch (&key, macros, n_macros, sizeof (struct macro), + compare_macro); + if (macro) + add_str_to_whatis (macro->value, strlen (macro->value)); +} + +static void add_glyph_to_whatis (const char *string, size_t length) +{ + add_macro_to_whatis (glyphs, ARRAY_SIZE (glyphs), string, length); +} + +static void add_perldoc_to_whatis (const char *string, size_t length) +{ + add_macro_to_whatis (perldocs, ARRAY_SIZE (perldocs), string, length); +} + +static void mdoc_text (const char *string) +{ + add_word_to_whatis (string); + BEGIN (MAN_DESC); +} + +static void newline_found (void) +{ + /* If we are mid p_name and the last added char was not a space, + * best add one. + */ + if (p_name != newname && *(p_name - 1) != ' ') { + if (fill_mode) + add_char_to_whatis (' '); + else { + add_char_to_whatis ((char) 0x11); + BEGIN (MAN_NAME); + } + } + waiting_for_quote = 0; +} + +int find_name (const char *file, const char *filename, lexgrog *p_lg, + const char *encoding) +{ + int ret; + pipeline *p; + char *page_encoding = NULL; + + if (strcmp (file, "-") == 0) { + p = decompress_fdopen (dup (STDIN_FILENO)); + } else { + struct stat st; + char *lang; + + if (stat (file, &st)) { + error (0, errno, "%s", file); + return 0; + } + + if (S_ISDIR (st.st_mode)) { + error (0, EISDIR, "%s", file); + return 0; + } + + drop_effective_privs (); + p = decompress_open (file); + if (!p) { + error (0, errno, _("can't open %s"), file); + regain_effective_privs (); + return 0; + } + regain_effective_privs (); + + if (!encoding) { + lang = lang_dir (file); + page_encoding = get_page_encoding (lang); + free (lang); + } + } + if (!page_encoding && encoding) + page_encoding = xstrdup (encoding); + if (page_encoding) + add_manconv (p, page_encoding, "UTF-8"); + free (page_encoding); + if (p_lg->type && *COL) { + pipecmd *col_cmd; + col_cmd = pipecmd_new_args (COL, "-b", "-p", "-x", (void *) 0); + pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (p, col_cmd); + } + pipeline_start (p); + + ret = find_name_decompressed (p, filename, p_lg); + pipeline_free (p); + return ret; +} + +int find_name_decompressed (pipeline *p, const char *filename, lexgrog *p_lg) +{ + int ret; + + decomp = p; + + fname = filename; + *(p_name = newname) = '\0'; + memset (filters, '_', sizeof (filters)); + + fill_mode = 1; + waiting_for_quote = 0; + + if (p_lg->type) + BEGIN (CAT_FILE); + else + BEGIN (MAN_FILE); + + drop_effective_privs (); + + yyrestart (NULL); + ret = yylex (); + + regain_effective_privs (); + + pipeline_wait (decomp); + + if (ret) + return 0; + else { + char f_tmp[MAX_FILTERS]; + int j, k; + + /* wipe out any leading or trailing spaces */ + if (*newname) { + for (p_name = strchr (newname, '\0'); + *(p_name - 1) == ' '; + p_name--); + if (*p_name == ' ') + *p_name = '\0'; + } + for (p_name = newname; *p_name == ' '; p_name++); + p_lg->whatis = xstrdup (p_name); + memset (f_tmp, '\0', MAX_FILTERS); + f_tmp[0] = '-'; + for (j = k = 0; j < MAX_FILTERS; j++) + if (filters[j] != '_') + f_tmp[k++] = filters[j]; + p_lg->filters = xstrdup (f_tmp); + return p_name[0]; + } +} + diff --git a/src/lexgrog.l b/src/lexgrog.l new file mode 100644 index 0000000..b3b4ef6 --- /dev/null +++ b/src/lexgrog.l @@ -0,0 +1,926 @@ +%top{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ +} + +%{ + +/* + * lexgrog.l: extract 'whatis' info from nroff man / formatted cat pages. + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + * 2011, 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Wed Oct 12 18:46:11 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * CJW: Detect grap and vgrind. Understand fill requests. Other improvements + * in the syntax accepted. + */ + +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "decompress.h" +#include "security.h" +#include "encodings.h" +#include "sandbox.h" + +#include "manconv_client.h" + +#define YY_READ_BUF_SIZE 1024 +#define MAX_NAME 8192 + +#define ARRAY_SIZE(array) (sizeof (array) / sizeof ((array)[0])) + +extern man_sandbox *sandbox; + +struct macro { + const char *name; + const char *value; +}; + +static const struct macro glyphs[] = { + /* It is vital to keep these in strcmp order (sort -t\" -k2)! They + * will be searched using bsearch. + * Data from groff_char(7), although I have omitted some that are + * particularly unlikely to be used in NAME sections. + */ + { "'A", "Á" }, + { "'C", "Ć" }, + { "'E", "É" }, + { "'I", "Í" }, + { "'O", "Ó" }, + { "'U", "Ú" }, + { "'Y", "Ý" }, + { "'a", "á" }, + { "'c", "ć" }, + { "'e", "é" }, + { "'i", "í" }, + { "'o", "ó" }, + { "'u", "ú" }, + { "'y", "ý" }, + { ",C", "Ç" }, + { ",c", "ç" }, + { "-D", "Ð" }, + { ".i", "ı" }, + { "/L", "Ł" }, + { "/O", "Ø" }, + { "/l", "ł" }, + { "/o", "ø" }, + { ":A", "Ä" }, + { ":E", "Ë" }, + { ":I", "Ï" }, + { ":O", "Ö" }, + { ":U", "Ü" }, + { ":Y", "Ÿ" }, + { ":a", "ä" }, + { ":e", "ë" }, + { ":i", "ï" }, + { ":o", "ö" }, + { ":u", "ü" }, + { ":y", "ÿ" }, + { "AE", "Æ" }, + { "Bq", "„" }, + { "Fc", "»" }, + { "Fi", "ffi" }, + { "Fl", "ffl" }, + { "Fo", "«" }, + { "IJ", "IJ" }, + { "OE", "Œ" }, + { "Sd", "ð" }, + { "TP", "Þ" }, + { "Tp", "þ" }, + { "^A", "Â" }, + { "^E", "Ê" }, + { "^I", "Î" }, + { "^O", "Ô" }, + { "^U", "Û" }, + { "^a", "â" }, + { "^e", "ê" }, + { "^i", "î" }, + { "^o", "ô" }, + { "^u", "û" }, + { "`A", "À" }, + { "`E", "È" }, + { "`I", "Ì" }, + { "`O", "Ò" }, + { "`U", "Ù" }, + { "`a", "à" }, + { "`e", "è" }, + { "`i", "ì" }, + { "`o", "ò" }, + { "`u", "ù" }, + { "a\"", "˝" }, + { "a-", "¯" }, + { "a.", "˙" }, + { "a^", "^" }, + { "aa", "´" }, + { "ab", "˘" }, + { "ac", "¸" }, + { "ad", "¨" }, + { "ae", "æ" }, + { "ah", "ˇ" }, + { "ao", "˚" }, + { "aq", "'" }, + { "a~", "~" }, + { "bq", "‚" }, + { "cq", "’" }, + { "dq", "\"" }, + { "em", "—" }, + { "en", "–" }, + { "fc", "›" }, + { "ff", "ff" }, + { "fi", "fi" }, + { "fl", "fl" }, + { "fo", "‹" }, + { "ga", "`" }, + { "ha", "^" }, + { "ho", "˛" }, + { "hy", "‐" }, + { "ij", "ij" }, + { "lq", "“" }, + { "oA", "Å" }, + { "oa", "å" }, + { "oe", "œ" }, + { "oq", "‘" }, + { "r!", "¡" }, + { "r?", "¿" }, + { "rq", "”" }, + { "ss", "ß" }, + { "ti", "~" }, + { "vS", "Š" }, + { "vZ", "Ž" }, + { "vs", "š" }, + { "vz", "ž" }, + { "~A", "Ã" }, + { "~N", "Ñ" }, + { "~O", "Õ" }, + { "~a", "ã" }, + { "~n", "ñ" }, + { "~o", "õ" } +}; + +static const struct macro perldocs[] = { + /* It is vital to keep these in strcmp order (sort -t\" -k2)! They + * will be searched using bsearch. + * Data from Pod/Man.pm. + */ + { "--", "-" }, + { "Aq", "'" }, + { "C'", "'" }, + { "C+", "C++" }, + { "C`", "`" }, + { "L\"", "\"" }, + { "PI", "π" }, + { "R\"", "\"" } +}; + +static void add_str_to_whatis (const char *string, size_t length); +static void add_char_to_whatis (unsigned char c); +static void add_separator_to_whatis (void); +static void add_wordn_to_whatis (const char *string, size_t length); +static void add_word_to_whatis (const char *string); +static void add_glyph_to_whatis (const char *string, size_t length); +static void add_perldoc_to_whatis (const char *string, size_t length); +static void mdoc_text (const char *string); +static void newline_found (void); + +static char newname[MAX_NAME]; +static char *p_name; +static const char *fname; +static char filters[MAX_FILTERS]; + +static int fill_mode; +static int waiting_for_quote; + +static pipeline *decomp; + +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = pipeline_read (decomp, &size); \ + if (block && size != 0) { \ + memcpy (buf, block, size); \ + buf[size] = '\0'; \ + result = size; \ + } else \ + result = YY_NULL; \ +} +#define YY_NO_INPUT +%} + +%option ecs meta-ecs +%option 8bit batch caseful never-interactive +%option nostdinit +%option warn +%option noyywrap nounput + +%x MAN_PRENAME +%x MAN_NAME +%x MAN_DESC +%x MAN_DESC_AT +%x MAN_DESC_BSX +%x MAN_DESC_BX +%x MAN_DESC_BX_RELEASE +%x MAN_DESC_DQ +%x MAN_DESC_FX +%x MAN_DESC_NX +%x MAN_DESC_OX +%x CAT_NAME +%x CAT_FILE +%x MAN_FILE +%x CAT_REST +%x MAN_REST +%x FORCE_EXIT + +digit [[:digit:]] +upper [[:upper:]] +alpha [[:alpha:]] +blank [[:blank:]] +blank_eol [[:blank:]\r\n] +word [[:alnum:]][^[:blank:]\r\n]* +eol \r?\n +bol {eol}+ +next {eol}* +empty {eol}{blank}* +indent {eol}{blank}+ +dbl_quote \" +font_change \\f([[:upper:]1-4]|\({upper}{2}) +size_change \\s[+-]?{digit} +style_change ({font_change}{size_change}?|{size_change}{font_change}?) +typeface \.(B[IR]?|I[BR]?|R[BI]|S[BM]) +sec_request \.[Ss][HhYySs] +comment ['.]\\{dbl_quote} + + /* Please add to this list if you know how. */ + /* Note that, since flex only supports UTF-8 by accident, character classes + * including non-ASCII characters must be written out as (a|b|c|d) rather + * than [abcd]. + */ +bg_name ИМЕ +cs_name (J[Mm](É|é|\\\('[Ee]|E|e)[Nn][Oo]|N(Á|á)[Zz][Ee][Vv]) +da_name N[Aa][Vv][Nn] +de_name B[Ee][Zz][Ee][Ii][Cc][Hh][Nn][Uu][Nn][Gg] +en_name N[Aa][Mm][Ee] +es_name N[Oo][Mm][Bb][Rr][Ee] +fi_name N[Ii][Mm][Ii] +fr_name N[Oo][Mm] +hu_name N(É|é|E|e)[Vv] +id_name N[Aa][Mm][Aa] + /* NOME also works for gl, pt */ +it_name N[Oo][Mm][Ee] +ja_name (名|̾)(前|称) +ko_name (이름|명칭) +latin_name N[Oo][Mm][Ee][Nn] +lt_name PAVADINIMAS +nl_name N[Aa][Aa][Mm] +pl_name N[Aa][Zz][Ww][Aa] +ru_name (ИМЯ|НАЗВАНИЕ|НАИМЕНОВАНИЕ) +sk_name M[Ee][Nn][Oo] +sr_name (ИМЕ|НАЗИВ) +srlatin_name (IME|NAZIV) +sv_name N[Aa][Mm][Nn] +tr_name (İ|i)S(İ|i)M +vi_name TÊN +zh_CN_name 名{blank}?(称|字){blank}?.* +zh_TW_name (名{blank}?(稱|字)|命令名){blank}?.* +name ({bg_name}|{cs_name}|{da_name}|{de_name}|{en_name}|{es_name}|{fi_name}|{fr_name}|{hu_name}|{id_name}|{it_name}|{ja_name}|{ko_name}|{latin_name}|{lt_name}|{nl_name}|{pl_name}|{ru_name}|{sk_name}|{sr_name}|{srlatin_name}|{sv_name}|{tr_name}|{vi_name}|{zh_CN_name}|{zh_TW_name}) +name_sec {dbl_quote}?{style_change}?{name}{style_change}?({blank}*{dbl_quote})? + + /* eptgrv : eqn, pic, tbl, grap, refer, vgrind */ +tbl_request \.TS +eqn_request \.EQ +pic_request \.PS +grap_request \.G1 +ref1_request \.R1 +ref2_request \.\[ +vgrind_request \.vS + +%% + + /* begin NAME section processing */ +<MAN_FILE>{sec_request}{blank_eol}+{name_sec}{blank}* BEGIN (MAN_PRENAME); +<CAT_FILE>{empty}{2,}{name}{blank}*{indent} BEGIN (CAT_NAME); + + /* general text matching */ +<MAN_FILE>{ + \.[^Ss\r\n].* | + \..{0,3}{dbl_quote}?.{0,4}{dbl_quote}? | + {comment}.* | + .|{eol} +} + +<CAT_FILE>{ + .{1,9} | + [ ]* | + {eol}{2,} | + .|{eol} +} + +<MAN_REST>{ + {bol}{tbl_request} filters[TBL_FILTER] = 't'; + {bol}{eqn_request} filters[EQN_FILTER] = 'e'; + {bol}{pic_request} filters[PIC_FILTER] = 'p'; + {bol}{grap_request} filters[GRAP_FILTER] = 'g'; + {bol}{ref1_request} | + {bol}{ref2_request} filters[REF_FILTER] = 'r'; + {bol}{vgrind_request} filters[VGRIND_FILTER] = 'v'; +} +<MAN_REST><<EOF>> { /* exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} +<MAN_REST>.+|{eol} + + /* rules to end NAME section processing */ +<FORCE_EXIT>.|{eol} { /* forced exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} + +<MAN_PRENAME>{bol}{sec_request}{blank}* | +<MAN_PRENAME><<EOF>> { /* no NAME at all */ + *p_name = '\0'; + BEGIN (MAN_REST); +} + + /* need to match whole string so that we beat the following roff catch-all, + so use yyless to push back the name */ +<MAN_PRENAME>{ + {bol}{typeface}{blank}.* | + {bol}\.Tn{blank}.* | + {bol}\.ft{blank}.* | + {bol}\.V[be]{blank}.* | + {bol}\.IX{blank}.* | + {bol}\.Nm{blank}.* { + yyless (0); + BEGIN (MAN_NAME); + } +} + + /* Skip over initial roff requests in NAME section. The use of yyless here + is evil. */ +<MAN_PRENAME>{bol}['.].* + +<MAN_PRENAME>{empty}{eol} yyless (1); + +<MAN_PRENAME>.|{eol} { + yyless (0); + BEGIN (MAN_NAME); +} + +<MAN_NAME,MAN_DESC>{ + {bol}{sec_request}{blank}* | /* Another section */ + {bol}\.X{upper}{blank}+ | /* special - hpux */ + {bol}\.sp{blank}* | /* vertical spacing */ + {bol}\.ig{blank}* | /* block comment */ + {bol}\.de[1i]?{blank}* | /* macro definition */ + {bol}\.i[ef]{blank}* | /* conditional */ + {empty}{bol}.+ | + <<EOF>> { /* terminate the string */ + *p_name = '\0'; + BEGIN (MAN_REST); + } +} + +<CAT_NAME>{ + {bol}S[yYeE] | + {eol}{2,}.+ | + {next}__ { /* terminate the string */ + *p_name = '\0'; + BEGIN (CAT_REST); + yyterminate (); + } +} + + /* ROFF request removal */ +<MAN_NAME,MAN_DESC>{ + /* some include quoting; dealing with this is unpleasant */ + {bol}{typeface}{blank}+\" { + newline_found (); + waiting_for_quote = 1; + } + + {bol}{typeface}{blank}+ | /* type face commands */ + {bol}\.Tn{blank}+ | /* mdoc trade name */ + {bol}\.ft{blank}.* | /* font change */ + {bol}\.V[be]{blank}.* | /* pod2man, verbatim mode */ + {bol}\.IX{blank}.* | /* .IX line */ + {bol}\.Nm{blank}+ | /* mdoc name */ + {bol}\.PD{blank}* | /* paragraph spacing */ + {bol}\\& | /* non-breaking space */ + {next}{comment}.* { /* per line comments */ + newline_found (); + } +} + + /* No-op requests */ +<MAN_NAME,MAN_DESC>{ + {bol}\.{blank}*$ newline_found (); + {bol}\.\.$ newline_found (); +} + + /* Toggle fill mode */ +<MAN_NAME,MAN_DESC>{ + {bol}\.nf.* fill_mode = 0; + {bol}\.fi.* fill_mode = 1; +} + +<CAT_NAME>-{eol}{blank_eol}* /* strip continuations */ + + /* convert to DASH */ +<MAN_NAME>{ + {next}{blank}*\\\((mi|hy|em|en){blank}* | + {next}{blank_eol}+[-\\]-{blank}* | + {next}{blank_eol}*[-\\]-{blank}+ | + {bol}\.Nd{blank}* { + add_separator_to_whatis (); + BEGIN (MAN_DESC); + } +} +<CAT_NAME>{next}{blank}+-{1,2}{blank_eol}+ add_separator_to_whatis (); + + /* escape sequences and special characters */ +<MAN_NAME,MAN_DESC>{ + {next}\\[\\e] add_char_to_whatis ('\\'); + {next}\\('|\(aa) add_char_to_whatis ('\''); + {next}\\(`|\(ga) add_char_to_whatis ('`'); + {next}\\(-|\((mi|hy|em|en)) add_char_to_whatis ('-'); + {next}\\\. add_char_to_whatis ('.'); + {next}((\\[ 0t~])|[ ]|\t)* add_char_to_whatis (' '); + {next}\\\((ru|ul) add_char_to_whatis ('_'); + {next}\\\\t add_char_to_whatis ('\t'); + + {next}\\[|^&!%acdpruz{}\r\n] /* various useless control chars */ + {next}\\[bhlLvx]{blank}*'[^']+' /* various inline functions */ + + {next}\\\$[1-9] /* interpolate arg */ + + /* roff named glyphs */ + {next}\\\(..|\\\[..\] add_glyph_to_whatis (yytext + 2, 2); + /* perldoc strings */ + {next}\\\*\(..|\\\*\[..\] add_perldoc_to_whatis (yytext + 3, 2); + {next}\\\*. add_perldoc_to_whatis (yytext + 2, 1); + + {next}\\["#].* /* comment */ + + {next}{font_change} /* font changes */ + {next}\\k{alpha} /* mark input place in register */ + + {next}\\n(\({alpha})?{alpha} /* interpolate number register */ + {next}\\o\"[^"]+\" /* overstrike chars */ + + {next}{size_change} /* size changes */ + {next}\\w{blank}*'[^']+'[^ \t]* /* width of string */ + + {next}\\ /* catch all */ + + {next}\(\\\|\){blank}* /* function() in hpux */ +} + + /* some people rather ambitiously use non-trivial mdoc macros in NAME + sections; cope with those that have been seen in the wild, and a few + more */ +<MAN_DESC>{ + {bol}\.At{blank}* BEGIN (MAN_DESC_AT); + {bol}\.Bsx{blank}* BEGIN (MAN_DESC_BSX); + {bol}\.Bx{blank}* BEGIN (MAN_DESC_BX); + {bol}\.Fx{blank}* BEGIN (MAN_DESC_FX); + {bol}\.Nx{blank}* BEGIN (MAN_DESC_NX); + {bol}\.Ox{blank}* BEGIN (MAN_DESC_OX); + {bol}\.Ux{blank}* add_word_to_whatis ("UNIX"); + + {bol}\.Dq{blank}* { + add_word_to_whatis ("\""); + BEGIN (MAN_DESC_DQ); + } +} + +<MAN_DESC_AT>{ + 32v{blank}* mdoc_text ("Version 32V AT&T UNIX"); + v1{blank}* mdoc_text ("Version 1 AT&T UNIX"); + v2{blank}* mdoc_text ("Version 2 AT&T UNIX"); + v3{blank}* mdoc_text ("Version 3 AT&T UNIX"); + v4{blank}* mdoc_text ("Version 4 AT&T UNIX"); + v5{blank}* mdoc_text ("Version 5 AT&T UNIX"); + v6{blank}* mdoc_text ("Version 6 AT&T UNIX"); + v7{blank}* mdoc_text ("Version 7 AT&T UNIX"); + V{blank}* mdoc_text ("AT&T System V UNIX"); + V.1{blank}* mdoc_text ("AT&T System V.1 UNIX"); + V.2{blank}* mdoc_text ("AT&T System V.2 UNIX"); + V.3{blank}* mdoc_text ("AT&T System V.3 UNIX"); + V.4{blank}* mdoc_text ("AT&T System V.4 UNIX"); + .|{eol} { + yyless (0); + mdoc_text ("AT&T UNIX"); + } +} + +<MAN_DESC_BSX>{ + {word} { + add_word_to_whatis ("BSD/OS"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + .|{eol} { + yyless (0); + mdoc_text ("BSD/OS"); + } +} + +<MAN_DESC_BX>{ + -alpha{blank}* mdoc_text ("BSD (currently in alpha test)"); + -beta{blank}* mdoc_text ("BSD (currently in beta test)"); + -devel{blank}* mdoc_text ("BSD (currently under development"); + {word}{blank}* { + add_wordn_to_whatis (yytext, yyleng); + add_str_to_whatis ("BSD", 3); + BEGIN (MAN_DESC_BX_RELEASE); + } + .|{eol} { + yyless (0); + mdoc_text ("BSD"); + } +} + +<MAN_DESC_BX_RELEASE>{ + [Rr]eno{blank}* { + add_str_to_whatis ("-Reno", 5); + BEGIN (MAN_DESC); + } + [Tt]ahoe{blank}* { + add_str_to_whatis ("-Tahoe", 6); + BEGIN (MAN_DESC); + } + [Ll]ite{blank}* { + add_str_to_whatis ("-Lite", 5); + BEGIN (MAN_DESC); + } + [Ll]ite2{blank}* { + add_str_to_whatis ("-Lite2", 6); + BEGIN (MAN_DESC); + } + .|{eol} { + yyless (0); + BEGIN (MAN_DESC); + } +} + +<MAN_DESC_DQ>.* { + add_str_to_whatis (yytext, yyleng); + add_char_to_whatis ('"'); + BEGIN (MAN_DESC); +} + +<MAN_DESC_FX>{ + {word} { + add_word_to_whatis ("FreeBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + .|{eol} { + yyless (0); + mdoc_text ("FreeBSD"); + } +} + +<MAN_DESC_NX>{ + {word} { + add_word_to_whatis ("NetBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + .|{eol} { + yyless (0); + mdoc_text ("NetBSD"); + } +} + +<MAN_DESC_OX>{ + {word} { + add_word_to_whatis ("OpenBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + .|{eol} { + yyless (0); + mdoc_text ("OpenBSD"); + } +} + + /* collapse spaces, escaped spaces, tabs, newlines to a single space */ +<CAT_NAME>{next}((\\[ ])|{blank})* add_char_to_whatis (' '); + + /* a ROFF break request, a paragraph request, or an indentation change + usually means we have multiple whatis definitions, provide a separator + for later processing */ +<MAN_NAME,MAN_DESC>{ + {bol}\.br{blank}* | + {bol}\.LP{blank}* | + {bol}\.PP{blank}* | + {bol}\.P{blank}* | + {bol}\.IP{blank}.* | + {bol}\.HP{blank}.* | + {bol}\.RS{blank}.* | + {bol}\.RE{blank}.* { + add_char_to_whatis ((char) 0x11); + BEGIN (MAN_NAME); + } +} + + /* any other roff request we don't recognise terminates definitions */ +<MAN_NAME,MAN_DESC>{bol}['.] { + *p_name = '\0'; + BEGIN (MAN_REST); +} + + /* pass words as a chunk. speed optimization */ +<MAN_NAME,MAN_DESC>[[:alnum:]]* add_str_to_whatis (yytext, yyleng); + + /* normalise the comma (,) separators */ +<CAT_NAME>{blank}*,[ \t\r\n]* | +<MAN_NAME,MAN_DESC>{blank}*,{blank}* add_str_to_whatis (", ", 2); + +<CAT_NAME,MAN_NAME,MAN_DESC>{bol}. { + newline_found (); + add_char_to_whatis (yytext[yyleng - 1]); +} + +<CAT_NAME,MAN_NAME,MAN_DESC>. add_char_to_whatis (*yytext); + + /* default EOF rule */ +<<EOF>> return 1; + +%% + +/* print warning and force scanner to terminate */ +static void too_big (void) +{ + /* Even though MAX_NAME is a macro expanding to a constant, we + * translate it using ngettext anyway because that will make it + * easier to change the macro later. + */ + error (0, 0, + ngettext ("warning: whatis for %s exceeds %d byte, " + "truncating.", + "warning: whatis for %s exceeds %d bytes, " + "truncating.", MAX_NAME), + fname, MAX_NAME); + + BEGIN (FORCE_EXIT); +} + +/* append a string to newname if enough room */ +static void add_str_to_whatis (const char *string, size_t length) +{ + if (p_name - newname + length >= MAX_NAME) + too_big (); + else { + (void) strncpy (p_name, string, length); + p_name += length; + } +} + +/* append a char to newname if enough room */ +static void add_char_to_whatis (unsigned char c) +{ + if (p_name - newname + 1 >= MAX_NAME) + too_big (); + else if (waiting_for_quote && c == '"') + waiting_for_quote = 0; + else + *p_name++ = c; +} + +/* append the " - " separator to newname, trimming the first space if one's + * already there + */ +static void add_separator_to_whatis (void) +{ + if (p_name != newname && *(p_name - 1) != ' ') + add_char_to_whatis (' '); + add_str_to_whatis ("- ", 2); +} + +/* append a word to newname if enough room, ensuring only necessary + surrounding space */ +static void add_wordn_to_whatis (const char *string, size_t length) +{ + if (p_name != newname && *(p_name - 1) != ' ') + add_char_to_whatis (' '); + while (length && string[length - 1] == ' ') + --length; + if (length) + add_str_to_whatis (string, length); +} + +static void add_word_to_whatis (const char *string) +{ + add_wordn_to_whatis (string, strlen (string)); +} + +struct compare_macro_key { + const char *string; + size_t length; +}; + +static int compare_macro (const void *left, const void *right) +{ + const struct compare_macro_key *key = left; + const struct macro *value = right; + int cmp; + + cmp = strncmp (key->string, value->name, key->length); + if (cmp) + return cmp; + /* equal up to key->length, so value->name must be at least size + * key->length + 1 + */ + else if (value->name[key->length]) + return -1; + else + return 0; +} + +static void add_macro_to_whatis (const struct macro *macros, size_t n_macros, + const char *string, size_t length) +{ + struct compare_macro_key key; + const struct macro *macro; + + key.string = string; + key.length = length; + macro = bsearch (&key, macros, n_macros, sizeof (struct macro), + compare_macro); + if (macro) + add_str_to_whatis (macro->value, strlen (macro->value)); +} + +static void add_glyph_to_whatis (const char *string, size_t length) +{ + add_macro_to_whatis (glyphs, ARRAY_SIZE (glyphs), string, length); +} + +static void add_perldoc_to_whatis (const char *string, size_t length) +{ + add_macro_to_whatis (perldocs, ARRAY_SIZE (perldocs), string, length); +} + +static void mdoc_text (const char *string) +{ + add_word_to_whatis (string); + BEGIN (MAN_DESC); +} + +static void newline_found (void) +{ + /* If we are mid p_name and the last added char was not a space, + * best add one. + */ + if (p_name != newname && *(p_name - 1) != ' ') { + if (fill_mode) + add_char_to_whatis (' '); + else { + add_char_to_whatis ((char) 0x11); + BEGIN (MAN_NAME); + } + } + waiting_for_quote = 0; +} + +int find_name (const char *file, const char *filename, lexgrog *p_lg, + const char *encoding) +{ + int ret; + pipeline *p; + char *page_encoding = NULL; + + if (strcmp (file, "-") == 0) { + p = decompress_fdopen (dup (STDIN_FILENO)); + } else { + struct stat st; + char *lang; + + if (stat (file, &st)) { + error (0, errno, "%s", file); + return 0; + } + + if (S_ISDIR (st.st_mode)) { + error (0, EISDIR, "%s", file); + return 0; + } + + drop_effective_privs (); + p = decompress_open (file); + if (!p) { + error (0, errno, _("can't open %s"), file); + regain_effective_privs (); + return 0; + } + regain_effective_privs (); + + if (!encoding) { + lang = lang_dir (file); + page_encoding = get_page_encoding (lang); + free (lang); + } + } + if (!page_encoding && encoding) + page_encoding = xstrdup (encoding); + if (page_encoding) + add_manconv (p, page_encoding, "UTF-8"); + free (page_encoding); + if (p_lg->type && *COL) { + pipecmd *col_cmd; + col_cmd = pipecmd_new_args (COL, "-b", "-p", "-x", (void *) 0); + pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (p, col_cmd); + } + pipeline_start (p); + + ret = find_name_decompressed (p, filename, p_lg); + pipeline_free (p); + return ret; +} + +int find_name_decompressed (pipeline *p, const char *filename, lexgrog *p_lg) +{ + int ret; + + decomp = p; + + fname = filename; + *(p_name = newname) = '\0'; + memset (filters, '_', sizeof (filters)); + + fill_mode = 1; + waiting_for_quote = 0; + + if (p_lg->type) + BEGIN (CAT_FILE); + else + BEGIN (MAN_FILE); + + drop_effective_privs (); + + yyrestart (NULL); + ret = yylex (); + + regain_effective_privs (); + + pipeline_wait (decomp); + + if (ret) + return 0; + else { + char f_tmp[MAX_FILTERS]; + int j, k; + + /* wipe out any leading or trailing spaces */ + if (*newname) { + for (p_name = strchr (newname, '\0'); + *(p_name - 1) == ' '; + p_name--); + if (*p_name == ' ') + *p_name = '\0'; + } + for (p_name = newname; *p_name == ' '; p_name++); + p_lg->whatis = xstrdup (p_name); + memset (f_tmp, '\0', MAX_FILTERS); + f_tmp[0] = '-'; + for (j = k = 0; j < MAX_FILTERS; j++) + if (filters[j] != '_') + f_tmp[k++] = filters[j]; + p_lg->filters = xstrdup (f_tmp); + return p_name[0]; + } +} diff --git a/src/lexgrog_test.c b/src/lexgrog_test.c new file mode 100644 index 0000000..c310aa0 --- /dev/null +++ b/src/lexgrog_test.c @@ -0,0 +1,238 @@ +/* + * lexgrog_test.c: test whatis extraction from man/cat pages + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + * 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> + +#include "argp.h" +#include "progname.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "error.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" + +#include "descriptions.h" +#include "ult_src.h" + +int quiet = 1; +man_sandbox *sandbox; + +static int parse_man = 0, parse_cat = 0, show_whatis = 0, show_filters = 0; +static const char *encoding = NULL; +static char **files; +static int num_files; + +const char *argp_program_version = "lexgrog " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("FILE..."); +static const char doc[] = "\v" N_("The defaults are --man and --whatis."); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "man", 'm', 0, 0, N_("parse as man page"), 1 }, + { "cat", 'c', 0, 0, N_("parse as cat page") }, + { "whatis", 'w', 0, 0, N_("show whatis information"), 2 }, + { "filters", 'f', 0, 0, N_("show guessed series of preprocessing filters") }, + { "encoding", 'E', N_("ENCODING"), 0, N_("use selected output encoding"), 3 }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'm': + parse_man = 1; + return 0; + case 'c': + parse_cat = 1; + return 0; + case 'w': + show_whatis = 1; + return 0; + case 'f': + show_filters = 1; + return 0; + case 'E': + encoding = arg; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP & + ~ARGP_HELP_PRE_DOC); + break; + case ARGP_KEY_ARGS: + files = state->argv + state->next; + num_files = state->argc - state->next; + return 0; + case ARGP_KEY_NO_ARGS: + argp_usage (state); + break; + case ARGP_KEY_SUCCESS: + if (parse_man && parse_cat) + /* This slightly odd construction allows us + * to reuse a translation. + */ + argp_error (state, + _("%s: incompatible options"), + "-m -c"); + /* defaults: --man, --whatis */ + if (!parse_man && !parse_cat) + parse_man = 1; + if (!show_whatis && !show_filters) + show_whatis = 1; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, + void *input ATTRIBUTE_UNUSED) +{ + switch (key) { + case ARGP_KEY_HELP_PRE_DOC: + /* We have no pre-options help text, but the input + * text may contain header junk due to gettext (""). + */ + return NULL; + default: + return (char *) text; + } +} + +static struct argp argp = { options, parse_opt, args_doc, doc, 0, + help_filter }; + +int main (int argc, char **argv) +{ + int type = 0; + int i; + int some_failed = 0; + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + /* We aren't setuid, but this allows generic code in lexgrog.l to + * use drop_effective_privs/regain_effective_privs. + */ + init_security (); + + if (parse_man) + type = 0; + else + type = 1; + + for (i = 0; i < num_files; ++i) { + lexgrog lg; + const char *file; + int found = 0; + + lg.type = type; + + if (STREQ (files[i], "-")) + file = files[i]; + else { + char *path, *pathend; + struct stat statbuf; + + path = xstrdup (files[i]); + pathend = strrchr (path, '/'); + if (pathend) { + *pathend = '\0'; + pathend = strrchr (path, '/'); + if (pathend && STRNEQ (pathend + 1, "man", 3)) + *pathend = '\0'; + else { + free (path); + path = NULL; + } + } else { + free (path); + path = NULL; + } + + file = ult_src (files[i], path ? path : ".", + &statbuf, SO_LINK, NULL); + free (path); + } + + if (file && find_name (file, "-", &lg, encoding)) { + struct page_description *descs = + parse_descriptions (NULL, lg.whatis); + const struct page_description *desc; + for (desc = descs; desc; desc = desc->next) { + if (!desc->name || !desc->whatis) + continue; + found = 1; + printf ("%s", files[i]); + if (show_filters) + printf (" (%s)", lg.filters); + if (show_whatis) + printf (": \"%s - %s\"", + desc->name, desc->whatis); + printf ("\n"); + } + free_descriptions (descs); + free (lg.filters); + free (lg.whatis); + } + + if (!found) { + printf ("%s: parse failed\n", files[i]); + some_failed = 1; + } + } + + if (some_failed) + return FATAL; + else + return OK; +} diff --git a/src/man.c b/src/man.c new file mode 100644 index 0000000..a144596 --- /dev/null +++ b/src/man.c @@ -0,0 +1,4397 @@ +/* + * man.c: The manual pager + * + * Copyright (C) 1990, 1991 John W. Eaton. + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + * 2011, 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * John W. Eaton + * jwe@che.utexas.edu + * Department of Chemical Engineering + * The University of Texas at Austin + * Austin, Texas 78712 + * + * Mostly written/re-written by Wilf, some routines by Markus Armbruster. + * + * CJW: Various robustness, security, and internationalization fixes. + * Improved HTML support (originally written by Fabrizio Polacco). + * Rewrite of page location routines for improved maintainability and + * accuracy. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <errno.h> +#include <termios.h> +#include <unistd.h> + +#ifndef R_OK +# define R_OK 4 +# define X_OK 1 +#endif /* !R_OK */ + +#include <limits.h> + +#if HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#include <ctype.h> +#include <signal.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "argp.h" +#include "dirname.h" +#include "minmax.h" +#include "progname.h" +#include "regex.h" +#include "stat-time.h" +#include "utimens.h" +#include "xvasprintf.h" +#include "xgetcwd.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "error.h" +#include "cleanup.h" +#include "hashtable.h" +#include "pipeline.h" +#include "pathsearch.h" +#include "linelength.h" +#include "decompress.h" +#include "xregcomp.h" +#include "security.h" +#include "encodings.h" +#include "orderfiles.h" +#include "sandbox.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "filenames.h" +#include "globbing.h" +#include "ult_src.h" +#include "manp.h" +#include "zsoelim.h" +#include "manconv_client.h" + +#ifdef MAN_OWNER +extern uid_t ruid; +extern uid_t euid; +#endif /* MAN_OWNER */ + +/* the default preprocessor sequence */ +#ifndef DEFAULT_MANROFFSEQ +# define DEFAULT_MANROFFSEQ "" +#endif + +/* placeholder for the manual page name in the less prompt string */ +#define MAN_PN "$MAN_PN" + +/* Some systems lack these */ +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +char *lang; + +/* external formatter programs, one for use without -t, and one with -t */ +#define NFMT_PROG "mandb_nfmt" +#define TFMT_PROG "mandb_tfmt" +#undef ALT_EXT_FORMAT /* allow external formatters located in cat hierarchy */ + +static int global_manpath = -1; /* global or user manual page hierarchy? */ +static int skip; /* page exists but has been skipped */ + +#if defined _AIX || defined __sgi +char **global_argv; +#endif + +struct candidate { + const char *req_name; + char from_db; + char cat; + const char *path; + char *ult; + struct mandata *source; + int add_index; /* for sort stabilisation */ + struct candidate *next; +}; + +#define CANDIDATE_FILESYSTEM 0 +#define CANDIDATE_DATABASE 1 + +static void gripe_system (pipeline *p, int status) +{ + error (CHILD_FAIL, 0, _("command exited with status %d: %s"), + status, pipeline_tostring (p)); +} + +enum opts { + OPT_WARNINGS = 256, + OPT_REGEX, + OPT_WILDCARD, + OPT_NAMES, + OPT_NO_HYPHENATION, + OPT_NO_JUSTIFICATION, + OPT_NO_SUBPAGES, + OPT_MAX +}; + +struct string_llist; +struct string_llist { + const char *name; + struct string_llist *next; +}; + + +static char *manpathlist[MAXDIRS]; + +/* globals */ +int quiet = 1; +char *database = NULL; +extern const char *extension; /* for globbing.c */ +extern char *user_config_file; /* defined in manp.c */ +extern int disable_cache; +extern int min_cat_width, max_cat_width, cat_width; +man_sandbox *sandbox; + +/* locals */ +static const char *alt_system_name; +static const char **section_list; +static const char *section; +static char *colon_sep_section_list; +static const char *preprocessors; +static const char *pager; +static const char *locale; +static char *internal_locale, *multiple_locale; +static const char *prompt_string; +static char *less; +static const char *std_sections[] = STD_SECTIONS; +static char *manp; +static const char *external; +static struct hashtable *db_hash = NULL; + +static int troff; +static const char *roff_device = NULL; +static const char *want_encoding = NULL; +#ifdef NROFF_WARNINGS +static const char default_roff_warnings[] = "mac"; +static struct string_llist *roff_warnings = NULL; +#endif /* NROFF_WARNINGS */ +static int global_apropos; +static int print_where, print_where_cat; +static int catman; +static int local_man_file; +static int findall; +static int update; +static int match_case; +static int regex_opt; +static int wildcard; +static int names_only; +static int ult_flags = SO_LINK | SOFT_LINK | HARD_LINK; +static const char *recode = NULL; +static int no_hyphenation; +static int no_justification; +static int subpages = 1; + +static int ascii; /* insert tr in the output pipe */ +static int save_cat; /* security breach? Can we save the cat? */ + +static int first_arg; + +static int found_a_stray; /* found a straycat */ + +#ifdef MAN_CATS +static char *tmp_cat_file; /* for open_cat_stream(), close_cat_stream() */ +static int created_tmp_cat; /* dto. */ +#endif +static int tmp_cat_fd; +static struct timespec man_modtime; /* modtime of man page, for + * commit_tmp_cat() */ + +# ifdef TROFF_IS_GROFF +static int ditroff; +static const char *gxditview; +static int htmlout; +static const char *html_pager; +# endif /* TROFF_IS_GROFF */ + +const char *argp_program_version = "man " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("[SECTION] PAGE..."); + +# ifdef NROFF_WARNINGS +# define ONLY_NROFF_WARNINGS 0 +# else +# define ONLY_NROFF_WARNINGS OPTION_HIDDEN +# endif + +# ifdef TROFF_IS_GROFF +# define ONLY_TROFF_IS_GROFF 0 +# else +# define ONLY_TROFF_IS_GROFF OPTION_HIDDEN +# endif + +/* Please keep these options in the same order as in parse_opt below. */ +static struct argp_option options[] = { + { "config-file", 'C', N_("FILE"), 0, N_("use this user configuration file") }, + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "default", 'D', 0, 0, N_("reset all options to their default values") }, + { "warnings", OPT_WARNINGS, N_("WARNINGS"), ONLY_NROFF_WARNINGS | OPTION_ARG_OPTIONAL, + N_("enable warnings from groff") }, + + { 0, 0, 0, 0, N_("Main modes of operation:"), 10 }, + { "whatis", 'f', 0, 0, N_("equivalent to whatis") }, + { "apropos", 'k', 0, 0, N_("equivalent to apropos") }, + { "global-apropos", 'K', 0, 0, N_("search for text in all pages") }, + { "where", 'w', 0, 0, N_("print physical location of man page(s)") }, + { "path", 0, 0, OPTION_ALIAS }, + { "location", 0, 0, OPTION_ALIAS }, + { "where-cat", 'W', 0, 0, N_("print physical location of cat file(s)") }, + { "location-cat", 0, 0, OPTION_ALIAS }, + { "local-file", 'l', 0, 0, N_("interpret PAGE argument(s) as local filename(s)") }, + { "catman", 'c', 0, 0, N_("used by catman to reformat out of date cat pages"), 11 }, + { "recode", 'R', N_("ENCODING"), 0, N_("output source page encoded in ENCODING") }, + + { 0, 0, 0, 0, N_("Finding manual pages:"), 20 }, + { "locale", 'L', N_("LOCALE"), 0, N_("define the locale for this particular man search") }, + { "systems", 'm', N_("SYSTEM"), 0, N_("use manual pages from other systems") }, + { "manpath", 'M', N_("PATH"), 0, N_("set search path for manual pages to PATH") }, + { "sections", 'S', N_("LIST"), 0, N_("use colon separated section list"), 21 }, + { 0, 's', 0, OPTION_ALIAS }, + { "extension", 'e', N_("EXTENSION"), + 0, N_("limit search to extension type EXTENSION"), 22 }, + { "ignore-case", 'i', 0, 0, N_("look for pages case-insensitively (default)"), 23 }, + { "match-case", 'I', 0, 0, N_("look for pages case-sensitively") }, + { "regex", OPT_REGEX, 0, 0, N_("show all pages matching regex"), 24 }, + { "wildcard", OPT_WILDCARD, 0, 0, N_("show all pages matching wildcard") }, + { "names-only", OPT_NAMES, 0, 0, N_("make --regex and --wildcard match page names only, not " + "descriptions"), 25 }, + { "all", 'a', 0, 0, N_("find all matching manual pages"), 26 }, + { "update", 'u', 0, 0, N_("force a cache consistency check") }, + { "no-subpages", + OPT_NO_SUBPAGES, 0, 0, N_("don't try subpages, e.g. 'man foo bar' => 'man foo-bar'"), 27 }, + + { 0, 0, 0, 0, N_("Controlling formatted output:"), 30 }, + { "pager", 'P', N_("PAGER"), 0, N_("use program PAGER to display output") }, + { "prompt", 'r', N_("STRING"), 0, N_("provide the `less' pager with a prompt") }, + { "ascii", '7', 0, 0, N_("display ASCII translation of certain latin1 chars"), 31 }, + { "encoding", 'E', N_("ENCODING"), 0, N_("use selected output encoding") }, + { "no-hyphenation", + OPT_NO_HYPHENATION, 0, 0, N_("turn off hyphenation") }, + { "nh", 0, 0, OPTION_ALIAS }, + { "no-justification", + OPT_NO_JUSTIFICATION, 0, 0, N_("turn off justification") }, + { "nj", 0, 0, OPTION_ALIAS }, + { "preprocessor", 'p', N_("STRING"), 0, N_("STRING indicates which preprocessors to run:\n" + "e - [n]eqn, p - pic, t - tbl,\n" + "g - grap, r - refer, v - vgrind") }, +#ifdef HAS_TROFF + { "troff", 't', 0, 0, N_("use %s to format pages"), 32 }, + { "troff-device", 'T', N_("DEVICE"), OPTION_ARG_OPTIONAL, + N_("use %s with selected device") }, + { "html", 'H', N_("BROWSER"), ONLY_TROFF_IS_GROFF | OPTION_ARG_OPTIONAL, + N_("use %s or BROWSER to display HTML output"), 33 }, + { "gxditview", 'X', N_("RESOLUTION"), + ONLY_TROFF_IS_GROFF | OPTION_ARG_OPTIONAL, + N_("use groff and display through gxditview (X11):\n" + "-X = -TX75, -X100 = -TX100, -X100-12 = -TX100-12") }, + { "ditroff", 'Z', 0, ONLY_TROFF_IS_GROFF, N_("use groff and force it to produce ditroff") }, +#endif /* HAS_TROFF */ + + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static void init_html_pager (void) +{ + html_pager = getenv ("BROWSER"); + if (!html_pager) + html_pager = WEB_BROWSER; +} + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + static int apropos, whatis; /* retain values between calls */ + + /* Please keep these keys in the same order as in options above. */ + switch (key) { + case 'C': + user_config_file = arg; + return 0; + case 'd': + debug_level = 1; + return 0; + case 'D': + /* discard all preset options */ + local_man_file = findall = update = catman = + debug_level = troff = global_apropos = + print_where = print_where_cat = + ascii = match_case = + regex_opt = wildcard = names_only = + no_hyphenation = no_justification = 0; +#ifdef TROFF_IS_GROFF + ditroff = 0; + gxditview = NULL; + htmlout = 0; + init_html_pager (); +#endif + roff_device = want_encoding = extension = pager = + locale = alt_system_name = external = + preprocessors = NULL; + colon_sep_section_list = manp = NULL; + return 0; + + case OPT_WARNINGS: +#ifdef NROFF_WARNINGS + { + char *s = xstrdup + (arg ? arg : default_roff_warnings); + const char *warning; + + for (warning = strtok (s, ","); warning; + warning = strtok (NULL, ",")) { + struct string_llist *new; + new = xmalloc (sizeof *new); + new->name = xstrdup (warning); + new->next = roff_warnings; + roff_warnings = new; + } + + free (s); + } +#endif /* NROFF_WARNINGS */ + return 0; + + case 'f': + external = WHATIS; + whatis = 1; + return 0; + case 'k': + external = APROPOS; + apropos = 1; + return 0; + case 'K': + global_apropos = 1; + return 0; + case 'w': + print_where = 1; + return 0; + case 'W': + print_where_cat = 1; + return 0; + case 'l': + local_man_file = 1; + return 0; + case 'c': + catman = 1; + return 0; + case 'R': + recode = arg; + ult_flags &= ~SO_LINK; + return 0; + + case 'L': + locale = arg; + return 0; + case 'm': + alt_system_name = arg; + return 0; + case 'M': + manp = arg; + return 0; + case 'S': + case 's': + if (*arg) + colon_sep_section_list = arg; + return 0; + case 'e': + extension = arg; + return 0; + case 'i': + match_case = 0; + return 0; + case 'I': + match_case = 1; + return 0; + case OPT_REGEX: + regex_opt = 1; + findall = 1; + return 0; + case OPT_WILDCARD: + wildcard = 1; + findall = 1; + return 0; + case OPT_NAMES: + names_only = 1; + return 0; + case 'a': + findall = 1; + return 0; + case 'u': + update = 1; + return 0; + case OPT_NO_SUBPAGES: + subpages = 0; + return 0; + + case 'P': + pager = arg; + return 0; + case 'r': + prompt_string = arg; + return 0; + case '7': + ascii = 1; + return 0; + case 'E': + want_encoding = arg; + if (is_roff_device (want_encoding)) + roff_device = want_encoding; + return 0; + case OPT_NO_HYPHENATION: + no_hyphenation = 1; + return 0; + case OPT_NO_JUSTIFICATION: + no_justification = 1; + return 0; + case 'p': + preprocessors = arg; + return 0; +#ifdef HAS_TROFF + case 't': + troff = 1; + return 0; + case 'T': + /* Traditional nroff knows -T; troff does not (gets + * ignored). All incarnations of groff know it. Why + * does -T imply -t? + */ + roff_device = (arg ? arg : "ps"); + troff = 1; + return 0; + case 'H': +# ifdef TROFF_IS_GROFF + if (arg) + html_pager = arg; + htmlout = 1; + troff = 1; + roff_device = "html"; +# endif /* TROFF_IS_GROFF */ + return 0; + case 'X': +# ifdef TROFF_IS_GROFF + troff = 1; + gxditview = (arg ? arg : "75"); +# endif /* TROFF_IS_GROFF */ + return 0; + case 'Z': +# ifdef TROFF_IS_GROFF + ditroff = 1; + troff = 1; +# endif /* TROFF_IS_GROFF */ + return 0; +#endif /* HAS_TROFF */ + + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_SUCCESS: + /* check for incompatible options */ + if (troff + whatis + apropos + catman + + (print_where || print_where_cat) > 1) { + char *badopts = xasprintf + ("%s%s%s%s%s%s", + troff ? "-[tTZH] " : "", + whatis ? "-f " : "", + apropos ? "-k " : "", + catman ? "-c " : "", + print_where ? "-w " : "", + print_where_cat ? "-W " : ""); + argp_error (state, + _("%s: incompatible options"), + badopts); + } + if (regex_opt + wildcard > 1) { + char *badopts = xasprintf + ("%s%s", + regex_opt ? "--regex " : "", + wildcard ? "--wildcard " : ""); + argp_error (state, + _("%s: incompatible options"), + badopts); + } + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, + void *input ATTRIBUTE_UNUSED) +{ +#ifdef HAS_TROFF +# ifdef TROFF_IS_GROFF + static const char formatter[] = "groff"; + const char *browser; +# else + static const char formatter[] = "troff"; +# endif /* TROFF_IS_GROFF */ +#endif /* HAS_TROFF */ + + switch (key) { +#ifdef HAS_TROFF + case 't': + case 'T': + return xasprintf (text, formatter); +# ifdef TROFF_IS_GROFF + case 'H': + browser = html_pager; + assert (browser); + if (STRNEQ (browser, "exec ", 5)) + browser += 5; + return xasprintf (text, browser); +# endif /* TROFF_IS_GROFF */ +#endif /* HAS_TROFF */ + default: + return (char *) text; + } +} + +static struct argp argp = { options, parse_opt, args_doc, 0, 0, help_filter }; + +/* + * changed these messages from stdout to stderr, + * (Fabrizio Polacco) Fri, 14 Feb 1997 01:30:07 +0200 + */ +static void gripe_no_name (const char *sect) +{ + if (sect) { + fprintf (stderr, _("No manual entry for %s\n"), sect); + fprintf (stderr, + _("(Alternatively, what manual page do you want from " + "section %s?)\n"), + sect); + } else + fputs (_("What manual page do you want?\n"), stderr); + + exit (FAIL); +} + +/* In case we're set-id, double-check that our standard file descriptors are + * open in a standard way. See: + * + * http://austingroupbugs.net/view.php?id=173 + */ +static void check_standard_fds (void) +{ + int flags, mode; + + /* We can't even write an error message in this case, so check it + * first. + */ + flags = fcntl (2, F_GETFL); + if (flags < 0) + exit (FATAL); + mode = flags & O_ACCMODE; + if (mode != O_WRONLY && mode != O_RDWR) + exit (FATAL); + + flags = fcntl (0, F_GETFL); + if (flags < 0) { + fprintf (stderr, "stdin not open!\n"); + exit (FATAL); + } + mode = flags & O_ACCMODE; + if (mode != O_RDONLY && mode != O_RDWR) { + fprintf (stderr, "stdin not open for reading!\n"); + exit (FATAL); + } + + flags = fcntl (1, F_GETFL); + if (flags < 0) { + fprintf (stderr, "stdout not open!\n"); + exit (FATAL); + } + mode = flags & O_ACCMODE; + if (mode != O_WRONLY && mode != O_RDWR) { + fprintf (stderr, "stdout not open for writing!\n"); + exit (FATAL); + } +} + +static struct termios tms; +static int tms_set = 0; +static pid_t tms_pid = 0; + +static void set_term (void) +{ + if (tms_set && getpid () == tms_pid) + tcsetattr (STDIN_FILENO, TCSANOW, &tms); +} + +static void get_term (void) +{ + if (isatty (STDOUT_FILENO)) { + debug ("is a tty\n"); + tcgetattr (STDIN_FILENO, &tms); + if (!tms_set++) { + /* Work around pipecmd_exec calling exit(3) rather + * than _exit(2), which means our atexit-registered + * functions are called at the end of each child + * process created using pipecmd_new_function and + * friends. It would probably be good to fix this + * in libpipeline at some point, but it would + * require care to avoid breaking compatibility. + */ + tms_pid = getpid (); + atexit (set_term); + } + } +} + +#if defined(TROFF_IS_GROFF) || defined(HEIRLOOM_NROFF) +static int get_roff_line_length (void) +{ + int line_length = cat_width ? cat_width : get_line_length (); + + /* groff >= 1.18 defaults to 78. */ + if ((!troff || ditroff) && line_length != 80) { + int length = line_length * 39 / 40; + if (length > line_length - 2) + return line_length - 2; + else + return length; + } else + return 0; +} + +#ifdef HEIRLOOM_NROFF +static void heirloom_line_length (void *data) +{ + printf (".ll %sn\n", (const char *) data); + /* TODO: This fails to do anything useful. Why? */ + printf (".lt %sn\n", (const char *) data); + printf (".lf 1\n"); +} +#endif /* HEIRLOOM_NROFF */ + +static pipecmd *add_roff_line_length (pipecmd *cmd, int *save_cat_p) +{ + int length; + pipecmd *ret = NULL; + + if (!catman) { + int line_length = get_line_length (); + debug ("Terminal width %d\n", line_length); + if (line_length >= min_cat_width && + line_length <= max_cat_width) + debug ("Terminal width %d within cat page range " + "[%d, %d]\n", + line_length, min_cat_width, max_cat_width); + else { + debug ("Terminal width %d not within cat page range " + "[%d, %d]\n", + line_length, min_cat_width, max_cat_width); + *save_cat_p = 0; + } + } + + length = get_roff_line_length (); + if (length) { +#ifdef HEIRLOOM_NROFF + char *name; + char *lldata; + pipecmd *llcmd; +#endif /* HEIRLOOM_NROFF */ + + debug ("Using %d-character lines\n", length); +#if defined(TROFF_IS_GROFF) + pipecmd_argf (cmd, "-rLL=%dn", length); + pipecmd_argf (cmd, "-rLT=%dn", length); +#elif defined(HEIRLOOM_NROFF) + name = xasprintf ("echo .ll %dn && echo .lt %dn", + length, length); + lldata = xasprintf ("%d", length); + llcmd = pipecmd_new_function (name, heirloom_line_length, free, + lldata); + ret = pipecmd_new_sequence ("line-length", llcmd, + pipecmd_new_passthrough (), NULL); + free (name); +#endif /* HEIRLOOM_NROFF */ + } + + return ret; +} +#endif /* TROFF_IS_GROFF || HEIRLOOM_NROFF */ + +static void gripe_no_man (const char *name, const char *sec) +{ + /* On AIX and IRIX, fall back to the vendor supplied browser. */ +#if defined _AIX || defined __sgi + if (!troff) { + pipecmd *vendor_man; + int i; + + vendor_man = pipecmd_new ("/usr/bin/man"); + for (i = 1; i < argc; ++i) + pipecmd_arg (vendor_man, global_argv[i]); + pipecmd_unsetenv (vendor_man, "MANPATH"); + pipecmd_exec (vendor_man); + } +#endif + + if (sec) + fprintf (stderr, _("No manual entry for %s in section %s\n"), + name, sec); + else + fprintf (stderr, _("No manual entry for %s\n"), name); + +#ifdef UNDOC_COMMAND + if (getenv ("MAN_TEST_DISABLE_UNDOCUMENTED") == NULL && + pathsearch_executable (name)) + fprintf (stderr, + _("See '%s' for help when manual pages are not " + "available.\n"), UNDOC_COMMAND); +#endif +} + +/* fire up the appropriate external program */ +static void do_extern (int argc, char *argv[]) +{ + pipeline *p; + pipecmd *cmd; + + cmd = pipecmd_new (external); + /* Please keep these in the same order as they are in whatis.c. */ + if (debug_level) + pipecmd_arg (cmd, "-d"); + if (local_man_file) /* actually apropos/whatis --long */ + pipecmd_arg (cmd, "-l"); + if (colon_sep_section_list) + pipecmd_args (cmd, "-s", colon_sep_section_list, (void *) 0); + if (alt_system_name) + pipecmd_args (cmd, "-m", alt_system_name, (void *) 0); + if (manp) + pipecmd_args (cmd, "-M", manp, (void *) 0); + if (locale) + pipecmd_args (cmd, "-L", locale, (void *) 0); + if (user_config_file) + pipecmd_args (cmd, "-C", user_config_file, (void *) 0); + while (first_arg < argc) + pipecmd_arg (cmd, argv[first_arg++]); + p = pipeline_new_commands (cmd, (void *) 0); + + /* privs are already dropped */ + exit (pipeline_run (p)); +} + +/* lookup $MANOPT and if available, put in *argv[] format for argp */ +static char **manopt_to_env (int *argc) +{ + char *manopt, *manopt_copy, *opt_start, **argv; + + manopt = getenv ("MANOPT"); + if (manopt == NULL || *manopt == '\0') + return NULL; + + opt_start = manopt = manopt_copy = xstrdup (manopt); + + /* allocate space for the program name */ + *argc = 0; + argv = XNMALLOC (*argc + 3, char *); + argv[(*argc)++] = base_name (program_name); + + /* for each [ \t]+ delimited string, allocate an array space and fill + it in. An escaped space is treated specially */ + while (*manopt) { + switch (*manopt) { + case ' ': + case '\t': + if (manopt != opt_start) { + *manopt = '\0'; + argv = xnrealloc (argv, *argc + 3, + sizeof (char *)); + argv[(*argc)++] = xstrdup (opt_start); + } + while (CTYPE (isspace, *(manopt + 1))) + *++manopt = '\0'; + opt_start = manopt + 1; + break; + case '\\': + if (*(manopt + 1) == ' ') + manopt++; + break; + default: + break; + } + manopt++; + } + + if (*opt_start) + argv[(*argc)++] = xstrdup (opt_start); + argv[*argc] = NULL; + + free (manopt_copy); + return argv; +} + +/* Return char array with 'less' special chars escaped. Uses static storage. */ +static const char *escape_less (const char *string) +{ + static char *escaped_string; + char *ptr; + + /* 2*strlen will always be long enough to hold the escaped string */ + ptr = escaped_string = xrealloc (escaped_string, + 2 * strlen (string) + 1); + + while (*string) { + if (*string == '?' || + *string == ':' || + *string == '.' || + *string == '%' || + *string == '\\') + *ptr++ = '\\'; + + *ptr++ = *string++; + } + + *ptr = *string; + return escaped_string; +} + +#if defined(MAN_DB_CREATES) || defined(MAN_DB_UPDATES) +/* Run mandb to ensure databases are up to date. Only used with -u. + * Returns the exit status of mandb. + * + * If filename is non-NULL, uses mandb's -f option to update a single file. + */ +static int run_mandb (int create, const char *manpath, const char *filename) +{ + pipeline *mandb_pl = pipeline_new (); + pipecmd *mandb_cmd = pipecmd_new ("mandb"); + + if (debug_level) + pipecmd_arg (mandb_cmd, "-d"); + else + pipecmd_arg (mandb_cmd, "-q"); + + if (user_config_file) + pipecmd_args (mandb_cmd, "-C", user_config_file, (void *) 0); + + if (filename) + pipecmd_args (mandb_cmd, "-f", filename, (void *) 0); + else if (create) { + pipecmd_arg (mandb_cmd, "-c"); + pipecmd_setenv (mandb_cmd, "MAN_MUST_CREATE", "1"); + } else + pipecmd_arg (mandb_cmd, "-p"); + + if (manpath) + pipecmd_arg (mandb_cmd, manpath); + + pipeline_command (mandb_pl, mandb_cmd); + + if (debug_level) { + debug ("running mandb: "); + pipeline_dump (mandb_pl, stderr); + } + + return pipeline_run (mandb_pl); +} +#endif /* MAN_DB_CREATES || MAN_DB_UPDATES */ + + +static char *locale_manpath (const char *manpath) +{ + char *all_locales; + char *new_manpath; + + if (multiple_locale && *multiple_locale) { + if (internal_locale && *internal_locale) + all_locales = xasprintf ("%s:%s", multiple_locale, + internal_locale); + else + all_locales = xstrdup (multiple_locale); + } else { + if (internal_locale && *internal_locale) + all_locales = xstrdup (internal_locale); + else + all_locales = NULL; + } + + new_manpath = add_nls_manpaths (manpath, all_locales); + free (all_locales); + + return new_manpath; +} + +/* + * Check to see if the argument is a valid section number. + * If 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 const char *is_section (const char *name) +{ + const char **vs; + + for (vs = section_list; *vs; vs++) { + if (STREQ (*vs, name)) + return name; + /* allow e.g. 3perl but disallow 8139too and libfoo */ + if (strlen (*vs) == 1 && CTYPE (isdigit, **vs) && + strlen (name) > 1 && !CTYPE (isdigit, name[1]) && + STRNEQ (*vs, name, 1)) + return name; + } + return NULL; +} + +/* Snarf pre-processors from file, return string or NULL on failure */ +static char *get_preprocessors_from_file (pipeline *decomp, int prefixes) +{ +#ifdef PP_COOKIE + const size_t block = 4096; + int i; + char *line = NULL; + size_t previous_len = 0; + + if (!decomp) + return NULL; + + /* Prefixes are inserted into the stream by man itself, and we must + * skip over them to find any preprocessors line that exists. Each + * one ends with an .lf macro. + */ + for (i = 0; ; ++i) { + size_t len = block * (i + 1); + const char *buffer, *scan, *end; + int j; + + scan = buffer = pipeline_peek (decomp, &len); + if (!buffer || len == 0) + return NULL; + + for (j = 0; j < prefixes; ++j) { + scan = memmem (scan, len - (scan - buffer), + "\n.lf ", strlen ("\n.lf ")); + if (!scan) + break; + ++scan; + scan = memchr (scan, '\n', len - (scan - buffer)); + if (!scan) + break; + ++scan; + } + if (!scan) + continue; + + end = memchr (scan, '\n', len - (scan - buffer)); + if (!end && len == previous_len) + /* end of file, no newline found */ + end = buffer + len - 1; + if (end) { + line = xstrndup (scan, end - scan + 1); + break; + } + previous_len = len; + } + if (!line) + return NULL; + + if (!strncmp (line, PP_COOKIE, 4)) { + const char *newline = strchr (line, '\n'); + if (newline) + return xstrndup (line + 4, newline - (line + 4)); + else + return xstrdup (line + 4); + } +#endif + return NULL; +} + + +/* Determine pre-processors, set save_cat and return string */ +static char *get_preprocessors (pipeline *decomp, const char *dbfilters, + int prefixes) +{ + char *pp_string; + const char *pp_source; + const char *env; + + /* try in order: database, command line, file, environment, default */ + /* command line overrides the database, but database empty overrides default */ + if (dbfilters && (dbfilters[0] != '-') && !preprocessors) { + pp_string = xstrdup (dbfilters); + pp_source = "database"; + save_cat = 1; + } else if (preprocessors) { + pp_string = xstrdup (preprocessors); + pp_source = "command line"; + save_cat = 0; + } else if ((pp_string = get_preprocessors_from_file (decomp, + prefixes))) { + pp_source = "file"; + save_cat = 1; + } else if ((env = getenv ("MANROFFSEQ"))) { + pp_string = xstrdup (env); + pp_source = "environment"; + save_cat = 0; + } else if (!dbfilters) { + pp_string = xstrdup (DEFAULT_MANROFFSEQ); + pp_source = "default"; + save_cat = 1; + } else { + pp_string = xstrdup (""); + pp_source = "no filters"; + save_cat = 1; + } + + debug ("pre-processors `%s' from %s\n", pp_string, pp_source); + return pp_string; +} + +static const char *my_locale_charset (void) +{ + if (want_encoding && !is_roff_device (want_encoding)) + return want_encoding; + else + return get_locale_charset (); +} + +static void add_col (pipeline *p, const char *locale_charset, ...) +{ + pipecmd *cmd; + va_list argv; + char *col_locale = NULL; + + cmd = pipecmd_new (COL); + va_start (argv, locale_charset); + pipecmd_argv (cmd, argv); + va_end (argv); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, sandbox); + + if (locale_charset) + col_locale = find_charset_locale (locale_charset); + if (col_locale) { + pipecmd_setenv (cmd, "LC_CTYPE", col_locale); + free (col_locale); + } + + pipeline_command (p, cmd); +} + +/* Return pipeline to format file to stdout. */ +static pipeline *make_roff_command (const char *dir, const char *file, + pipeline *decomp, const char *pp_string, + char **result_encoding) +{ + const char *roff_opt; + char *fmt_prog = NULL; + pipeline *p = pipeline_new (); + pipecmd *cmd; + char *page_encoding = NULL; + const char *output_encoding = NULL; + const char *locale_charset = NULL; + + *result_encoding = xstrdup ("UTF-8"); /* optimistic default */ + + roff_opt = getenv ("MANROFFOPT"); + if (!roff_opt) + roff_opt = ""; + + if (dir && !recode) { +#ifdef ALT_EXT_FORMAT + char *catpath = get_catpath + (dir, global_manpath ? SYSTEM_CAT : USER_CAT); + + /* If we have an alternate catpath, look for an external + * formatter there. + */ + if (catpath) { + fmt_prog = appendstr (catpath, "/", + troff ? TFMT_PROG : NFMT_PROG, + (void *) 0); + if (!CAN_ACCESS (fmt_prog, X_OK)) { + free (fmt_prog); + fmt_prog = NULL; + } + } +#endif /* ALT_EXT_FORMAT */ + + /* If the page is in a proper manual page hierarchy (as + * opposed to being read using --local-file or similar), + * look for an external formatter there. + */ + if (!fmt_prog) { + fmt_prog = appendstr (NULL, dir, "/", + troff ? TFMT_PROG : NFMT_PROG, + (void *) 0); + if (!CAN_ACCESS (fmt_prog, X_OK)) { + free (fmt_prog); + fmt_prog = NULL; + } + } + } + + if (fmt_prog) + debug ("External formatter %s\n", fmt_prog); + + if (!fmt_prog) { + /* we don't have an external formatter script */ + const char *source_encoding, *roff_encoding; + const char *groff_preconv; + + if (!recode) { + struct zsoelim_stdin_data *zsoelim_data; + + zsoelim_data = zsoelim_stdin_data_new (dir, + manpathlist); + cmd = pipecmd_new_function (ZSOELIM, &zsoelim_stdin, + zsoelim_stdin_data_free, + zsoelim_data); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (p, cmd); + } + + page_encoding = check_preprocessor_encoding (decomp); + if (!page_encoding) + page_encoding = get_page_encoding (lang); + if (page_encoding && !STREQ (page_encoding, "UTF-8")) + source_encoding = page_encoding; + else + source_encoding = get_source_encoding (lang); + debug ("page_encoding = %s\n", page_encoding); + debug ("source_encoding = %s\n", source_encoding); + + /* Load the roff_device value dependent on the language dir + * in the path. + */ + if (!troff) { +#define STRC(s, otherwise) ((s) ? (s) : (otherwise)) + + locale_charset = my_locale_charset (); + debug ("locale_charset = %s\n", + STRC (locale_charset, "NULL")); + + /* Pick the default device for this locale if there + * wasn't one selected explicitly. + */ + if (!roff_device) { + roff_device = + get_default_device (locale_charset, + source_encoding); +#ifdef HEIRLOOM_NROFF + /* In Heirloom, if LC_CTYPE is a UTF-8 + * locale, then -Tlocale will be equivalent + * to -Tutf8 except that it will do a + * slightly better job of rendering some + * special characters. + */ + if (STREQ (roff_device, "utf8")) { + const char *real_locale_charset = + get_locale_charset (); + if (real_locale_charset && + STREQ (real_locale_charset, + "UTF-8")) + roff_device = "locale"; + } +#endif /* HEIRLOOM_NROFF */ + debug ("roff_device (locale) = %s\n", + STRC (roff_device, "NULL")); + } + } + + roff_encoding = get_roff_encoding (roff_device, + source_encoding); + debug ("roff_encoding = %s\n", roff_encoding); + + /* We may need to recode: + * from page_encoding to roff_encoding on input; + * from output_encoding to locale_charset on output + * (if not troff). + * If we have preconv, then use it to recode the + * input to a safe escaped form. + * The --recode option overrides everything else. + */ + groff_preconv = get_groff_preconv (); + if (recode) + add_manconv (p, page_encoding, recode); + else if (groff_preconv) { + pipecmd *preconv_cmd; + add_manconv (p, page_encoding, "UTF-8"); + preconv_cmd = pipecmd_new_args + (groff_preconv, "-e", "UTF-8", (void *) 0); + pipecmd_pre_exec (preconv_cmd, sandbox_load, + sandbox_free, sandbox); + pipeline_command (p, preconv_cmd); + } else if (roff_encoding) + add_manconv (p, page_encoding, roff_encoding); + else + add_manconv (p, page_encoding, page_encoding); + + if (!troff && !recode) { + output_encoding = get_output_encoding (roff_device); + if (!output_encoding) + output_encoding = source_encoding; + debug ("output_encoding = %s\n", output_encoding); + free (*result_encoding); + *result_encoding = xstrdup (output_encoding); + + if (!getenv ("LESSCHARSET")) { + const char *less_charset = + get_less_charset (locale_charset); + debug ("less_charset = %s\n", less_charset); + setenv ("LESSCHARSET", less_charset, 1); + } + + if (!getenv ("JLESSCHARSET")) { + const char *jless_charset = + get_jless_charset (locale_charset); + if (jless_charset) { + debug ("jless_charset = %s\n", + jless_charset); + setenv ("JLESSCHARSET", + jless_charset, 1); + } + } + } + } + + if (recode) + ; + else if (!fmt_prog) { +#ifndef GNU_NROFF + int using_tbl = 0; +#endif /* GNU_NROFF */ + + do { +#ifdef NROFF_WARNINGS + struct string_llist *cur; +#endif /* NROFF_WARNINGS */ + int wants_dev = 0; /* filter wants a dev argument */ + int wants_post = 0; /* postprocessor arguments */ + + cmd = NULL; + /* set cmd according to *pp_string, on + errors leave cmd as NULL */ + switch (*pp_string) { + case 'e': + if (troff) + cmd = pipecmd_new_argstr + (get_def ("eqn", EQN)); + else + cmd = pipecmd_new_argstr + (get_def ("neqn", NEQN)); + wants_dev = 1; + break; + case 'g': + cmd = pipecmd_new_argstr + (get_def ("grap", GRAP)); + break; + case 'p': + cmd = pipecmd_new_argstr + (get_def ("pic", PIC)); + break; + case 't': + cmd = pipecmd_new_argstr + (get_def ("tbl", TBL)); +#ifndef GNU_NROFF + using_tbl = 1; +#endif /* GNU_NROFF */ + break; + case 'v': + cmd = pipecmd_new_argstr + (get_def ("vgrind", VGRIND)); + break; + case 'r': + cmd = pipecmd_new_argstr + (get_def ("refer", REFER)); + break; + case ' ': + case '-': + case 0: + /* done with preprocessors, now add roff */ + if (troff) { + cmd = pipecmd_new_argstr + (get_def ("troff", TROFF)); + save_cat = 0; + } else + cmd = pipecmd_new_argstr + (get_def ("nroff", NROFF)); + +#ifdef TROFF_IS_GROFF + if (troff && ditroff) + pipecmd_arg (cmd, "-Z"); +#endif /* TROFF_IS_GROFF */ + +#if defined(TROFF_IS_GROFF) || defined(HEIRLOOM_NROFF) + { + pipecmd *seq = add_roff_line_length + (cmd, &save_cat); + if (seq) + pipeline_command (p, seq); + } +#endif /* TROFF_IS_GROFF || HEIRLOOM_NROFF */ + +#ifdef NROFF_WARNINGS + for (cur = roff_warnings; cur; + cur = cur->next) + pipecmd_argf (cmd, "-w%s", cur->name); +#endif /* NROFF_WARNINGS */ + +#ifdef HEIRLOOM_NROFF + if (running_setuid ()) + pipecmd_unsetenv (cmd, "TROFFMACS"); +#endif /* HEIRLOOM_NROFF */ + + pipecmd_argstr (cmd, roff_opt); + + wants_dev = 1; + wants_post = 1; + break; + } + + if (!cmd) { + assert (*pp_string); /* didn't fail on roff */ + error (0, 0, + _("ignoring unknown preprocessor `%c'"), + *pp_string); + continue; + } + + if (wants_dev) { + if (roff_device) + pipecmd_argf (cmd, + "-T%s", roff_device); +#ifdef TROFF_IS_GROFF + else if (gxditview) + pipecmd_argf (cmd, "-TX%s", gxditview); +#endif /* TROFF_IS_GROFF */ + } + + if (wants_post) { +#ifdef TROFF_IS_GROFF + if (gxditview) + pipecmd_arg (cmd, "-X"); +#endif /* TROFF_IS_GROFF */ + + if (roff_device && STREQ (roff_device, "ps")) + /* Tell grops to guess the page + * size. + */ + pipecmd_arg (cmd, "-P-g"); + } + + pipecmd_pre_exec (cmd, sandbox_load_permissive, + sandbox_free, sandbox); + pipeline_command (p, cmd); + + if (*pp_string == ' ' || *pp_string == '-') + break; + } while (*pp_string++); + + if (!troff && *COL) { + const char *man_keep_formatting = + getenv ("MAN_KEEP_FORMATTING"); + if ((!man_keep_formatting || !*man_keep_formatting) && + !isatty (STDOUT_FILENO)) + /* we'll run col later, but prepare for it */ + setenv ("GROFF_NO_SGR", "1", 1); +#ifndef GNU_NROFF + /* tbl needs col */ + else if (using_tbl && !troff && *COL) + add_col (p, locale_charset, (void *) 0); +#endif /* GNU_NROFF */ + } + } else { + /* use external formatter script, it takes arguments + input file, preprocessor string, and (optional) + output device */ + cmd = pipecmd_new_args (fmt_prog, file, pp_string, (void *) 0); + if (roff_device) + pipecmd_arg (cmd, roff_device); + pipeline_command (p, cmd); + } + + free (fmt_prog); + free (page_encoding); + return p; +} + +#ifdef TROFF_IS_GROFF +/* Return pipeline to run a browser on a given file, observing + * http://www.tuxedo.org/~esr/BROWSER/. + * + * (Actually, I really implement + * https://www.dwheeler.com/browse/secure_browser.html, but it's + * backward-compatible.) + * + * TODO: Is there any way to use the pipeline library better here? + */ +static pipeline *make_browser (const char *pattern, const char *file) +{ + pipeline *p; + pipecmd *cmd; + char *browser = xmalloc (1); + int found_percent_s = 0; + char *percent; + char *esc_file; + + *browser = '\0'; + + percent = strchr (pattern, '%'); + while (percent) { + size_t len = strlen (browser); + browser = xrealloc (browser, len + 1 + (percent - pattern)); + strncat (browser, pattern, percent - pattern); + switch (*(percent + 1)) { + case '\0': + case '%': + browser = appendstr (browser, "%", (void *) 0); + break; + case 'c': + browser = appendstr (browser, ":", (void *) 0); + break; + case 's': + esc_file = escape_shell (file); + browser = appendstr (browser, esc_file, + (void *) 0); + free (esc_file); + found_percent_s = 1; + break; + default: + len = strlen (browser); /* cannot be NULL */ + browser = xrealloc (browser, len + 3); + strncat (browser, percent, 2); + break; + } + if (*(percent + 1)) + pattern = percent + 2; + else + pattern = percent + 1; + percent = strchr (pattern, '%'); + } + browser = appendstr (browser, pattern, (void *) 0); + if (!found_percent_s) { + esc_file = escape_shell (file); + browser = appendstr (browser, " ", esc_file, (void *) 0); + free (esc_file); + } + + cmd = pipecmd_new_args ("/bin/sh", "-c", browser, (void *) 0); + pipecmd_pre_exec (cmd, drop_privs, NULL, NULL); + p = pipeline_new_commands (cmd, (void *) 0); + pipeline_ignore_signals (p, 1); + free (browser); + + return p; +} +#endif /* TROFF_IS_GROFF */ + +static void setenv_less (pipecmd *cmd, const char *title) +{ + const char *esc_title; + char *less_opts, *man_pn; + + esc_title = escape_less (title); + less_opts = xasprintf (LESS_OPTS, prompt_string, prompt_string); + less_opts = appendstr (less_opts, less, (void *) 0); + man_pn = strstr (less_opts, MAN_PN); + while (man_pn) { + char *subst_opts = + xmalloc (strlen (less_opts) - strlen (MAN_PN) + + strlen (esc_title) + 1); + strncpy (subst_opts, less_opts, man_pn - less_opts); + subst_opts[man_pn - less_opts] = '\0'; + strcat (subst_opts, esc_title); + strcat (subst_opts, man_pn + strlen (MAN_PN)); + free (less_opts); + less_opts = subst_opts; + man_pn = strstr (less_opts, MAN_PN); + } + + debug ("Setting LESS to %s\n", less_opts); + pipecmd_setenv (cmd, "LESS", less_opts); + + debug ("Setting MAN_PN to %s\n", esc_title); + pipecmd_setenv (cmd, "MAN_PN", esc_title); + + free (less_opts); +} + +static void add_output_iconv (pipeline *p, + const char *source, const char *target) +{ + debug ("add_output_iconv: source %s, target %s\n", source, target); + if (source && target && !STREQ (source, target)) { + char *target_translit = xasprintf ("%s//TRANSLIT", target); + pipecmd *iconv_cmd; + iconv_cmd = pipecmd_new_args + ("iconv", "-c", "-f", source, "-t", target_translit, + (void *) 0); + pipecmd_pre_exec (iconv_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (p, iconv_cmd); + free (target_translit); + } +} + +/* Pipeline command to squeeze multiple blank lines into one. + * + */ +static void squeeze_blank_lines (void *data ATTRIBUTE_UNUSED) +{ + char *line = NULL; + size_t len = 0; + + while (getline (&line, &len, stdin) != -1) { + int in_blank_line = 1; + int got_blank_line = 0; + + while (in_blank_line) { + char *p; + for (p = line; *p; ++p) { + if (!CTYPE (isspace, *p)) { + in_blank_line = 0; + break; + } + } + + if (in_blank_line) { + got_blank_line = 1; + free (line); + line = NULL; + len = 0; + if (getline (&line, &len, stdin) == -1) + break; + } + } + + if (got_blank_line && putchar ('\n') < 0) + break; + + if (!in_blank_line && fputs (line, stdout) < 0) + break; + + free (line); + line = NULL; + len = 0; + } + + free (line); + return; +} + +/* Return pipeline to display file provided on stdin. + * + * TODO: htmlout case is pretty weird now. I'd like the intelligence to be + * somewhere other than format_display. + */ +static pipeline *make_display_command (const char *encoding, const char *title) +{ + pipeline *p = pipeline_new (); + const char *locale_charset = NULL; + pipecmd *pager_cmd = NULL; + + locale_charset = my_locale_charset (); + + if (!troff && (!want_encoding || !is_roff_device (want_encoding))) + add_output_iconv (p, encoding, locale_charset); + + if (!troff && *COL) { + /* get rid of special characters if not writing to a + * terminal + */ + const char *man_keep_formatting = + getenv ("MAN_KEEP_FORMATTING"); + if ((!man_keep_formatting || !*man_keep_formatting) && + !isatty (STDOUT_FILENO)) + add_col (p, locale_charset, "-b", "-p", "-x", + (void *) 0); + } + + /* emulate pager -s, the sed code is just for information */ + { + pipecmd *cmd; + const char *name = "sed -e '/^[[:space:]]*$/{ N; /^[[:space:]]*\\n[[:space:]]*$/D; }'"; + cmd = pipecmd_new_function (name, &squeeze_blank_lines, NULL, NULL); + pipeline_command (p, cmd); + } + + if (isatty (STDOUT_FILENO)) { + if (ascii) { + pipecmd *tr_cmd; + tr_cmd = pipecmd_new_argstr + (get_def_user ("tr", TR TR_SET1 TR_SET2)); + pipecmd_pre_exec (tr_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (p, tr_cmd); + pager_cmd = pipecmd_new_argstr (pager); + } else +#ifdef TROFF_IS_GROFF + if (!htmlout) + /* format_display deals with html_pager */ +#endif + pager_cmd = pipecmd_new_argstr (pager); + } + + if (pager_cmd) { + setenv_less (pager_cmd, title); + pipeline_command (p, pager_cmd); + } + pipeline_ignore_signals (p, 1); + + if (!pipeline_get_ncommands (p)) + /* Always return at least a dummy pipeline. */ + pipeline_command (p, pipecmd_new_passthrough ()); + return p; +} + + +/* return a (malloced) temporary name in cat_file's directory */ +static char *tmp_cat_filename (const char *cat_file) +{ + char *name; + + if (debug_level) { + name = xstrdup ("/dev/null"); + tmp_cat_fd = open (name, O_WRONLY); + } else { + char *slash; + name = xstrdup (cat_file); + slash = strrchr (name, '/'); + if (slash) + *(slash + 1) = '\0'; + else + *name = '\0'; + name = appendstr (name, "catXXXXXX", (void *) 0); + tmp_cat_fd = mkstemp (name); + } + + if (tmp_cat_fd == -1) { + free (name); + return NULL; + } else + return name; +} + + +/* If delete unlink tmp_cat, else commit tmp_cat to cat_file. + Return non-zero on error. + */ +static int commit_tmp_cat (const char *cat_file, const char *tmp_cat, + int delete) +{ + int status = 0; + +#ifdef MAN_OWNER + if (!delete && global_manpath && euid == 0) { + if (debug_level) { + debug ("fixing temporary cat's ownership\n"); + status = 0; + } else { + struct passwd *man_owner = get_man_owner (); + status = chown (tmp_cat, man_owner->pw_uid, + man_owner->pw_gid); + if (status) + error (0, errno, _("can't chown %s"), tmp_cat); + } + } +#endif /* MAN_OWNER */ + + if (!delete && !status) { + if (debug_level) { + debug ("fixing temporary cat's mode\n"); + status = 0; + } else { + status = chmod (tmp_cat, CATMODE); + if (status) + error (0, errno, _("can't chmod %s"), tmp_cat); + } + } + + if (!delete && !status) { + if (debug_level) { + debug ("renaming temporary cat to %s\n", cat_file); + status = 0; + } else { + status = rename (tmp_cat, cat_file); + if (status) + error (0, errno, _("can't rename %s to %s"), + tmp_cat, cat_file); + } + } + + if (!delete && !status) { + if (debug_level) { + debug ("setting modtime on cat file %s\n", cat_file); + status = 0; + } else { + struct timespec times[2]; + + times[0].tv_sec = 0; + times[0].tv_nsec = UTIME_NOW; + times[1] = man_modtime; + status = utimens (cat_file, times); + if (status) + error (0, errno, _("can't set times on %s"), + cat_file); + } + } + + if (delete || status) { + if (debug_level) + debug ("unlinking temporary cat\n"); + else if (unlink (tmp_cat)) + error (0, errno, _("can't unlink %s"), tmp_cat); + } + + return status; +} + +/* TODO: This should all be refactored after work on the decompression + * library is complete. + */ +static void discard_stderr (pipeline *p) +{ + int i; + + for (i = 0; i < pipeline_get_ncommands (p); ++i) + pipecmd_discard_err (pipeline_get_command (p, i), 1); +} + +static void maybe_discard_stderr (pipeline *p) +{ + const char *man_keep_stderr = getenv ("MAN_KEEP_STDERR"); + if ((!man_keep_stderr || !*man_keep_stderr) && isatty (STDOUT_FILENO)) + discard_stderr (p); +} + +static void chdir_commands (pipeline *p, const char *dir) +{ + int i; + + for (i = 0; i < pipeline_get_ncommands (p); ++i) + pipecmd_chdir (pipeline_get_command (p, i), dir); +} + +static void cleanup_unlink (void *arg) +{ + const char *path = arg; + + if (unlink (path)) + error (0, errno, _("can't unlink %s"), path); +} + +#ifdef MAN_CATS + +/* Return pipeline to write formatted manual page to for saving as cat file. */ +static pipeline *open_cat_stream (const char *cat_file, const char *encoding) +{ + pipeline *cat_p; +# ifdef COMP_CAT + pipecmd *comp_cmd; +# endif + + created_tmp_cat = 0; + + debug ("creating temporary cat for %s\n", cat_file); + + tmp_cat_file = tmp_cat_filename (cat_file); + if (tmp_cat_file) + created_tmp_cat = 1; + else { + if (!debug_level && (errno == EACCES || errno == EROFS)) { + /* No permission to write to the cat file. Oh well, + * return NULL and let the caller sort it out. + */ + debug ("can't write to temporary cat for %s\n", + cat_file); + return NULL; + } else + error (FATAL, errno, + _("can't create temporary cat for %s"), + cat_file); + } + + if (!debug_level) + push_cleanup (cleanup_unlink, tmp_cat_file, 1); + + cat_p = pipeline_new (); + add_output_iconv (cat_p, encoding, "UTF-8"); +# ifdef COMP_CAT + /* fork the compressor */ + comp_cmd = pipecmd_new_argstr (get_def ("compressor", COMPRESSOR)); + pipecmd_nice (comp_cmd, 10); + pipecmd_pre_exec (comp_cmd, sandbox_load, sandbox_free, sandbox); + pipeline_command (cat_p, comp_cmd); +# endif + /* pipeline_start will close tmp_cat_fd */ + pipeline_want_out (cat_p, tmp_cat_fd); + + return cat_p; +} + +/* Close the cat page stream, return non-zero on error. + If delete don't update the cat file. + */ +static int close_cat_stream (pipeline *cat_p, const char *cat_file, + int delete) +{ + int status; + + status = pipeline_wait (cat_p); + debug ("cat-saver exited with status %d\n", status); + + pipeline_free (cat_p); + + if (created_tmp_cat) { + status |= commit_tmp_cat (cat_file, tmp_cat_file, + delete || status); + if (!debug_level) + pop_cleanup (cleanup_unlink, tmp_cat_file); + } + free (tmp_cat_file); + return status; +} + +/* + * format a manual page with format_cmd, display it with disp_cmd, and + * save it to cat_file + */ +static int format_display_and_save (pipeline *decomp, + pipeline *format_cmd, + pipeline *disp_cmd, + const char *cat_file, const char *encoding) +{ + pipeline *sav_p = open_cat_stream (cat_file, encoding); + int instat; + + if (global_manpath) + drop_effective_privs (); + + maybe_discard_stderr (format_cmd); + + pipeline_connect (decomp, format_cmd, (void *) 0); + if (sav_p) { + pipeline_connect (format_cmd, disp_cmd, sav_p, (void *) 0); + pipeline_pump (decomp, format_cmd, disp_cmd, sav_p, + (void *) 0); + } else { + pipeline_connect (format_cmd, disp_cmd, (void *) 0); + pipeline_pump (decomp, format_cmd, disp_cmd, (void *) 0); + } + + if (global_manpath) + regain_effective_privs (); + + pipeline_wait (decomp); + instat = pipeline_wait (format_cmd); + if (sav_p) + close_cat_stream (sav_p, cat_file, instat); + pipeline_wait (disp_cmd); + return instat; +} +#endif /* MAN_CATS */ + +/* Format a manual page with format_cmd and display it with disp_cmd. + * Handle temporary file creation if necessary. + * TODO: merge with format_display_and_save + */ +static void format_display (pipeline *decomp, + pipeline *format_cmd, pipeline *disp_cmd, + const char *man_file) +{ + int format_status = 0, disp_status = 0; +#ifdef TROFF_IS_GROFF + char *htmldir = NULL, *htmlfile = NULL; +#endif /* TROFF_IS_GROFF */ + + if (format_cmd) + maybe_discard_stderr (format_cmd); + + drop_effective_privs (); + +#ifdef TROFF_IS_GROFF + if (format_cmd && htmlout) { + char *man_base, *man_ext; + int htmlfd; + + htmldir = create_tempdir ("hman"); + if (!htmldir) + error (FATAL, errno, + _("can't create temporary directory")); + chdir_commands (format_cmd, htmldir); + chdir_commands (disp_cmd, htmldir); + man_base = base_name (man_file); + man_ext = strchr (man_base, '.'); + if (man_ext) + *man_ext = '\0'; + htmlfile = xasprintf ("%s/%s.html", htmldir, man_base); + free (man_base); + htmlfd = open (htmlfile, O_CREAT | O_EXCL | O_WRONLY, 0644); + if (htmlfd == -1) + error (FATAL, errno, _("can't open temporary file %s"), + htmlfile); + pipeline_want_out (format_cmd, htmlfd); + pipeline_connect (decomp, format_cmd, (void *) 0); + pipeline_pump (decomp, format_cmd, (void *) 0); + pipeline_wait (decomp); + format_status = pipeline_wait (format_cmd); + } else +#endif /* TROFF_IS_GROFF */ + if (format_cmd) { + pipeline_connect (decomp, format_cmd, (void *) 0); + pipeline_connect (format_cmd, disp_cmd, (void *) 0); + pipeline_pump (decomp, format_cmd, disp_cmd, (void *) 0); + pipeline_wait (decomp); + format_status = pipeline_wait (format_cmd); + disp_status = pipeline_wait (disp_cmd); + } else { + pipeline_connect (decomp, disp_cmd, (void *) 0); + pipeline_pump (decomp, disp_cmd, (void *) 0); + pipeline_wait (decomp); + disp_status = pipeline_wait (disp_cmd); + } + +#ifdef TROFF_IS_GROFF + if (format_cmd && htmlout) { + char *browser_list, *candidate; + + if (format_status) { + if (remove_directory (htmldir, 0) == -1) + error (0, errno, + _("can't remove directory %s"), + htmldir); + free (htmlfile); + free (htmldir); + gripe_system (format_cmd, format_status); + } + + browser_list = xstrdup (html_pager); + for (candidate = strtok (browser_list, ":"); candidate; + candidate = strtok (NULL, ":")) { + pipeline *browser; + debug ("Trying browser: %s\n", candidate); + browser = make_browser (candidate, htmlfile); + disp_status = pipeline_run (browser); + if (!disp_status) + break; + } + if (!candidate) { + if (html_pager && *html_pager) + error (CHILD_FAIL, 0, + "couldn't execute any browser from %s", + html_pager); + else + error (CHILD_FAIL, 0, + "no browser configured, so cannot show " + "HTML output"); + } + free (browser_list); + if (remove_directory (htmldir, 0) == -1) + error (0, errno, _("can't remove directory %s"), + htmldir); + free (htmlfile); + free (htmldir); + } else +#endif /* TROFF_IS_GROFF */ + { + if (format_status && format_status != (SIGPIPE + 0x80) * 256) + gripe_system (format_cmd, format_status); + if (disp_status && disp_status != (SIGPIPE + 0x80) * 256) + gripe_system (disp_cmd, disp_status); + } + + regain_effective_privs (); +} + +/* "Display" a page in catman mode, which amounts to saving it. */ +/* TODO: merge with format_display_and_save? */ +static void display_catman (const char *cat_file, pipeline *decomp, + pipeline *format_cmd, const char *encoding) +{ + char *tmpcat = tmp_cat_filename (cat_file); +#ifdef COMP_CAT + pipecmd *comp_cmd; +#endif /* COMP_CAT */ + int status; + + add_output_iconv (format_cmd, encoding, "UTF-8"); + +#ifdef COMP_CAT + comp_cmd = pipecmd_new_argstr (get_def ("compressor", COMPRESSOR)); + pipecmd_pre_exec (comp_cmd, sandbox_load, sandbox_free, sandbox); + pipeline_command (format_cmd, comp_cmd); +#endif /* COMP_CAT */ + + maybe_discard_stderr (format_cmd); + pipeline_want_out (format_cmd, tmp_cat_fd); + + push_cleanup (cleanup_unlink, tmpcat, 1); + + /* save the cat as real user + * (1) required for user man hierarchy + * (2) else depending on ruid's privs is ok, effectively disables + * catman for non-root. + */ + drop_effective_privs (); + pipeline_connect (decomp, format_cmd, (void *) 0); + pipeline_pump (decomp, format_cmd, (void *) 0); + pipeline_wait (decomp); + status = pipeline_wait (format_cmd); + regain_effective_privs (); + if (status) + gripe_system (format_cmd, status); + + close (tmp_cat_fd); + commit_tmp_cat (cat_file, tmpcat, status); + pop_cleanup (cleanup_unlink, tmpcat); + free (tmpcat); +} + +static void disable_hyphenation (void *data ATTRIBUTE_UNUSED) +{ + fputs (".nh\n" + ".de hy\n" + "..\n" + ".lf 1\n", stdout); +} + +static void disable_justification (void *data ATTRIBUTE_UNUSED) +{ + fputs (".na\n" + ".de ad\n" + "..\n" + ".lf 1\n", stdout); +} + +#ifdef TROFF_IS_GROFF +static void locale_macros (void *data) +{ + const char *macro_lang = data; + const char *hyphen_lang = STREQ (lang, "en") ? "us" : macro_lang; + + debug ("Macro language %s; hyphenation language %s\n", + macro_lang, hyphen_lang); + + printf ( + /* If we're using groff >= 1.20.2 (for the 'file' warning + * category): + */ + ".if \\n[.g] \\{\\\n" + ". ds Ystring \\n[.Y]\n" + ". while (\\B'\\*[Ystring]' = 0) .chop Ystring\n" + ". if ((\\n[.x] > 1) :" + " ((\\n[.x] == 1) & (\\n[.y] > 20)) :" + " ((\\n[.x] == 1) & (\\n[.y] == 20) & (\\*[Ystring] >= 2))) " + "\\{\\\n" + /* disable warnings of category 'file' */ + ". warn (\\n[.warn] -" + " (\\n[.warn] / 1048576 %% 2 * 1048576))\n" + /* and load the appropriate per-locale macros */ + ". mso %s.tmac\n" + ". \\}\n" + ". rm Ystring\n" + ".\\}\n" + /* set the hyphenation language anyway, to make sure groff + * only hyphenates languages it knows about + */ + ".hla %s\n" + ".lf 1\n", macro_lang, hyphen_lang); +} +#endif /* TROFF_IS_GROFF */ + +/* allow user to skip a page or quit after viewing desired page + return 1 to skip + return 0 to view + */ +static int do_prompt (const char *name) +{ + int ch; + FILE *tty = NULL; + + skip = 0; + if (!isatty (STDOUT_FILENO) || !isatty (STDIN_FILENO)) + return 0; /* noninteractive */ + tty = fopen ("/dev/tty", "r+"); + if (!tty) + return 0; + + fprintf (tty, _( + "--Man-- next: %s " + "[ view (return) | skip (Ctrl-D) | quit (Ctrl-C) ]\n"), + name); + fflush (tty); + + do { + ch = getc (tty); + switch (ch) { + case '\n': + fclose (tty); + return 0; + case EOF: + skip = 1; + fclose (tty); + return 1; + default: + break; + } + } while (1); + + fclose (tty); + return 0; +} + +/* + * optionally chdir to dir, if necessary update cat_file from man_file + * and display it. if man_file is NULL cat_file is a stray cat. If + * !save_cat or cat_file is NULL we must not save the formatted cat. + * If man_file is "" this is a special case -- we expect the man page + * on standard input. + */ +static int display (const char *dir, const char *man_file, + const char *cat_file, const char *title, + const char *dbfilters) +{ + int found; + static int prompt; + int prefixes = 0; + pipeline *format_cmd; /* command to format man_file to stdout */ + char *formatted_encoding = NULL; + int display_to_stdout; + pipeline *decomp = NULL; + int decomp_errno = 0; + + /* define format_cmd */ + if (man_file) { + pipecmd *seq = pipecmd_new_sequence ("decompressor", + (void *) 0); + + if (*man_file) + decomp = decompress_open (man_file); + else + decomp = decompress_fdopen (dup (STDIN_FILENO)); + + if (!recode && no_hyphenation) { + pipecmd *hcmd = pipecmd_new_function ( + "echo .nh && echo .de hy && echo ..", + disable_hyphenation, NULL, NULL); + pipecmd_sequence_command (seq, hcmd); + ++prefixes; + } + + if (!recode && no_justification) { + pipecmd *jcmd = pipecmd_new_function ( + "echo .na && echo .de ad && echo ..", + disable_justification, NULL, NULL); + pipecmd_sequence_command (seq, jcmd); + ++prefixes; + } + +#ifdef TROFF_IS_GROFF + /* This only works with preconv, since the per-locale macros + * may change the assumed input encoding. + */ + if (!recode && *man_file && get_groff_preconv ()) { + char *page_lang = lang_dir (man_file); + + if (page_lang && *page_lang && + !STREQ (page_lang, "C")) { + struct locale_bits bits; + char *name; + pipecmd *lcmd; + + unpack_locale_bits (page_lang, &bits); + name = xasprintf ("echo .mso %s.tmac", + bits.language); + lcmd = pipecmd_new_function ( + name, locale_macros, free, + xstrdup (bits.language)); + pipecmd_sequence_command (seq, lcmd); + ++prefixes; + free (name); + free_locale_bits (&bits); + } + free (page_lang); + } +#endif /* TROFF_IS_GROFF */ + + if (prefixes) { + assert (pipeline_get_ncommands (decomp) <= 1); + if (pipeline_get_ncommands (decomp)) { + pipecmd_sequence_command + (seq, + pipeline_get_command (decomp, 0)); + pipeline_set_command (decomp, 0, seq); + } else { + pipecmd_sequence_command + (seq, pipecmd_new_passthrough ()); + pipeline_command (decomp, seq); + } + } else + pipecmd_free (seq); + } + + if (decomp) { + char *pp_string; + + pipeline_start (decomp); + pp_string = get_preprocessors (decomp, dbfilters, prefixes); + format_cmd = make_roff_command (dir, man_file, decomp, + pp_string, + &formatted_encoding); + if (dir) + chdir_commands (format_cmd, dir); + debug ("formatted_encoding = %s\n", formatted_encoding); + free (pp_string); + } else { + format_cmd = NULL; + decomp_errno = errno; + } + + /* Get modification time, for commit_tmp_cat(). */ + if (man_file && *man_file) { + struct stat stb; + if (stat (man_file, &stb)) { + man_modtime.tv_sec = 0; + man_modtime.tv_nsec = 0; + } else + man_modtime = get_stat_mtime (&stb); + } + + display_to_stdout = troff; +#ifdef TROFF_IS_GROFF + if (htmlout) + display_to_stdout = 0; +#endif + if (recode) + display_to_stdout = 1; + + if (display_to_stdout) { + /* If we're reading stdin via '-l -', man_file is "". See + * below. + */ + assert (man_file); + if (!decomp) { + assert (!format_cmd); /* no need to free it */ + error (0, decomp_errno, _("can't open %s"), man_file); + return 0; + } + if (*man_file == '\0') + found = 1; + else + found = CAN_ACCESS (man_file, R_OK); + if (found) { + int status; + if (prompt && do_prompt (title)) { + pipeline_free (format_cmd); + pipeline_free (decomp); + free (formatted_encoding); + return 0; + } + drop_effective_privs (); + pipeline_connect (decomp, format_cmd, (void *) 0); + pipeline_pump (decomp, format_cmd, (void *) 0); + pipeline_wait (decomp); + status = pipeline_wait (format_cmd); + regain_effective_privs (); + if (status != 0) + gripe_system (format_cmd, status); + } + } else { + int format = 1; + int status; + + /* The caller should already have checked for any + * FSSTND-style (same hierarchy) cat page that may be + * present, and we don't expect to have to update the cat + * page in that case. If by some chance we do have to update + * it, then there's no harm trying; open_cat_stream() will + * refuse gracefully if the file isn't writeable. + */ + + /* In theory we might be able to get away with saving cats + * for want_encoding, but it does change the roff device so + * perhaps that's best avoided. + */ + if (want_encoding +#ifdef TROFF_IS_GROFF + || htmlout +#endif + || local_man_file + || recode + || disable_cache) + save_cat = 0; + + if (!man_file) { + /* Stray cat. */ + assert (cat_file); + format = 0; + } else if (!cat_file) { + assert (man_file); + save_cat = 0; + format = 1; + } else if (format && save_cat) { + char *cat_dir; + char *tmp; + + status = is_changed (man_file, cat_file); + format = (status == -2) || ((status & 1) == 1); + + /* don't save if we haven't a cat directory */ + cat_dir = xstrdup (cat_file); + tmp = strrchr (cat_dir, '/'); + if (tmp) + *tmp = 0; + save_cat = is_directory (cat_dir) == 1; + if (!save_cat) + debug ("cat dir %s does not exist\n", cat_dir); + free (cat_dir); + } + + if (format && (!format_cmd || !decomp)) { + assert (man_file); + /* format_cmd is NULL iff decomp is NULL; no need to + * free either of them. + */ + assert (!format_cmd); + assert (!decomp); + error (0, decomp_errno, _("can't open %s"), man_file); + return 0; + } + + /* if we're trying to read stdin via '-l -' then man_file + * will be "" which access() obviously barfs on, but all is + * well because the format_cmd will have been created to + * expect input via stdin. So we special-case this to avoid + * the bogus access() check. + */ + if (format == 1 && *man_file == '\0') + found = 1; + else + found = CAN_ACCESS + (format ? man_file : cat_file, R_OK); + + debug ("format: %d, save_cat: %d, found: %d\n", + format, save_cat, found); + + if (!found) { + pipeline_free (format_cmd); + pipeline_free (decomp); + return found; + } + + if (print_where || print_where_cat) { + int printed = 0; + if (print_where && man_file) { + printf ("%s", man_file); + printed = 1; + } + if (print_where_cat && cat_file && !format) { + if (printed) + putchar (' '); + printf ("%s", cat_file); + printed = 1; + } + if (printed) + putchar ('\n'); + } else if (catman) { + if (format) { + if (!save_cat) + error (0, 0, + _("\ncannot write to " + "%s in catman mode"), + cat_file); + else + display_catman (cat_file, decomp, + format_cmd, + formatted_encoding); + } + } else if (format) { + /* no cat or out of date */ + pipeline *disp_cmd; + + if (prompt && do_prompt (title)) { + pipeline_free (format_cmd); + pipeline_free (decomp); + free (formatted_encoding); + if (local_man_file) + return 1; + else + return 0; + } + + disp_cmd = make_display_command (formatted_encoding, + title); + +#ifdef MAN_CATS + if (save_cat) { + /* save cat */ + assert (disp_cmd); /* not htmlout for now */ + format_display_and_save (decomp, + format_cmd, + disp_cmd, + cat_file, + formatted_encoding); + } else +#endif /* MAN_CATS */ + /* don't save cat */ + format_display (decomp, format_cmd, disp_cmd, + man_file); + + pipeline_free (disp_cmd); + + } else { + /* display preformatted cat */ + pipeline *disp_cmd; + pipeline *decomp_cat; + + if (prompt && do_prompt (title)) { + pipeline_free (format_cmd); + pipeline_free (decomp); + return 0; + } + + decomp_cat = decompress_open (cat_file); + if (!decomp_cat) { + error (0, errno, _("can't open %s"), cat_file); + pipeline_free (format_cmd); + pipeline_free (decomp); + return 0; + } + disp_cmd = make_display_command ("UTF-8", title); + format_display (decomp_cat, NULL, disp_cmd, man_file); + pipeline_free (disp_cmd); + pipeline_free (decomp_cat); + } + } + + free (formatted_encoding); + + pipeline_free (format_cmd); + pipeline_free (decomp); + + if (!prompt) + prompt = found; + + return found; +} + +static void gripe_converting_name (const char *name) ATTRIBUTE_NORETURN; +static void gripe_converting_name (const char *name) +{ + error (FATAL, 0, _("Can't convert %s to cat name"), name); + abort (); /* error should have exited; help compilers prove noreturn */ +} + +/* Convert the trailing part of 'name' to be a cat page path by altering its + * extension appropriately. If fsstnd is set, also try converting the + * containing directory name from "man1" to "cat1" etc., returning NULL if + * that doesn't work. + * + * fsstnd should only be set if name is the original path of a man page + * found in a man hierarchy, not something like a symlink target or a file + * named with 'man -l'. Otherwise, a symlink to "/home/manuel/foo.1.gz" + * would be converted to "/home/catuel/foo.1.gz", which would be bad. + */ +static char *convert_name (const char *name, int fsstnd) +{ + char *to_name, *t1 = NULL; + char *t2 = NULL; +#ifdef COMP_SRC + struct compression *comp; +#endif /* COMP_SRC */ + char *namestem; + +#ifdef COMP_SRC + comp = comp_info (name, 1); + if (comp) + namestem = comp->stem; + else +#endif /* COMP_SRC */ + namestem = xstrdup (name); + +#ifdef COMP_CAT + /* TODO: BSD layout requires .0. */ + to_name = xasprintf ("%s.%s", namestem, COMPRESS_EXT); +#else /* !COMP_CAT */ + to_name = xstrdup (namestem); +#endif /* COMP_CAT */ + free (namestem); + + if (fsstnd) { + t1 = strrchr (to_name, '/'); + if (!t1) + gripe_converting_name (name); + *t1 = '\0'; + + t2 = strrchr (to_name, '/'); + if (!t2) + gripe_converting_name (name); + ++t2; + *t1 = '/'; + + if (STRNEQ (t2, "man", 3)) { + /* If the second-last component starts with "man", + * replace "man" with "cat". + */ + *t2 = 'c'; + *(t2 + 2) = 't'; + } else { + free (to_name); + debug ("couldn't convert %s to FSSTND cat file\n", + name); + return NULL; + } + } + + debug ("converted %s to %s\n", name, to_name); + + return to_name; +} + +static char *find_cat_file (const char *path, const char *original, + const char *man_file) +{ + size_t path_len = strlen (path); + char *cat_file, *cat_path; + int status; + + /* Try the FSSTND way first, namely a cat page in the same hierarchy + * as the original path to the man page. We don't create these + * unless no alternate cat hierarchy is available, but will use them + * if they happen to exist already and have the same timestamp as + * the corresponding man page. (In practice I'm betting that this + * means we'll hardly ever use them at all except for user + * hierarchies; but compatibility, eh?) + */ + cat_file = convert_name (original, 1); + if (cat_file) { + status = is_changed (original, cat_file); + if (status != -2 && (!(status & 1)) == 1) { + debug ("found valid FSSTND cat file %s\n", cat_file); + return cat_file; + } + free (cat_file); + } + + /* Otherwise, find the cat page we actually want to use or create, + * taking any alternate cat hierarchy into account. If the original + * path and man_file differ (i.e. original was a symlink or .so + * link), try the link target and then the source. + */ + if (!STREQ (man_file, original)) { + global_manpath = is_global_mandir (man_file); + cat_path = get_catpath + (man_file, global_manpath ? SYSTEM_CAT : USER_CAT); + + if (cat_path) { + cat_file = convert_name (cat_path, 0); + free (cat_path); + } else if (STRNEQ (man_file, path, path_len) && + man_file[path_len] == '/') + cat_file = convert_name (man_file, 1); + else + cat_file = NULL; + + if (cat_file) { + char *cat_dir = xstrdup (cat_file); + char *tmp = strrchr (cat_dir, '/'); + if (tmp) + *tmp = 0; + if (is_directory (cat_dir)) { + debug ("will try cat file %s\n", cat_file); + free (cat_dir); + return cat_file; + } else + debug ("cat dir %s does not exist\n", cat_dir); + free (cat_dir); + } else + debug ("no cat path for %s\n", man_file); + } + + global_manpath = is_global_mandir (original); + cat_path = get_catpath + (original, global_manpath ? SYSTEM_CAT : USER_CAT); + + if (cat_path) { + cat_file = convert_name (cat_path, 0); + free (cat_path); + } else + cat_file = convert_name (original, 1); + + if (cat_file) + debug ("will try cat file %s\n", cat_file); + else + debug ("no cat path for %s\n", original); + + return cat_file; +} + +static int get_ult_flags (char from_db, char id) +{ + if (!from_db) + return ult_flags; + else if (id == ULT_MAN) + /* Checking .so links is expensive, as we have to open the + * file. Therefore, if the database lists it as ULT_MAN, + * that's good enough for us and we won't recheck that. This + * does mean that if a page changes from ULT_MAN to SO_MAN + * then you might get duplicates until mandb is next run, + * but that isn't a big deal. + */ + return ult_flags & ~SO_LINK; + else + return ult_flags; +} + +/* Is this candidate substantially a duplicate of a previous one? + * Returns non-zero if so, otherwise zero. + */ +static int duplicate_candidates (struct candidate *left, + struct candidate *right) +{ + const char *slash1, *slash2; + struct locale_bits bits1, bits2; + int ret; + + if (left->ult && right->ult && STREQ (left->ult, right->ult)) + return 1; /* same ultimate source file */ + + if (!STREQ (left->source->name, right->source->name) || + !STREQ (left->source->sec, right->source->sec) || + !STREQ (left->source->ext, right->source->ext)) + return 0; /* different name/section/extension */ + + if (STREQ (left->path, right->path)) + return 1; /* same path */ + + /* Figure out if we've had a sufficiently similar candidate for this + * language already. + */ + slash1 = strrchr (left->path, '/'); + slash2 = strrchr (right->path, '/'); + if (!slash1 || !slash2 || + !STRNEQ (left->path, right->path, + MAX (slash1 - left->path, slash2 - right->path))) + return 0; /* different path base */ + + unpack_locale_bits (++slash1, &bits1); + unpack_locale_bits (++slash2, &bits2); + + if (!STREQ (bits1.language, bits2.language) || + !STREQ (bits1.territory, bits2.territory) || + !STREQ (bits1.modifier, bits2.modifier)) + ret = 0; /* different language/territory/modifier */ + else + /* Everything seems to be the same; we can find nothing to + * choose between them. + */ + ret = 1; + + free_locale_bits (&bits1); + free_locale_bits (&bits2); + return ret; +} + +static int compare_candidates (const struct candidate *left, + const struct candidate *right) +{ + const struct mandata *lsource = left->source, *rsource = right->source; + int sec_left = 0, sec_right = 0; + int cmp; + const char *slash1, *slash2; + + /* If one candidate matches the requested name exactly, sort it + * first. This makes --ignore-case behave more sensibly. + */ + /* name is never NULL here, see add_candidate() */ + if (STREQ (lsource->name, left->req_name)) { + if (!STREQ (rsource->name, right->req_name)) + return -1; + } else { + if (STREQ (rsource->name, right->req_name)) + return 1; + } + + /* Compare pure sections first, then ids, then extensions. + * Rationale: whatis refs get the same section and extension as + * their source, but may be supplanted by a real page with a + * slightly different extension, possibly in another hierarchy (!); + * see Debian bug #204249 for the gory details. + * + * Any extension spelt out in full in section_list effectively + * becomes a pure section; this allows extensions to be selectively + * moved out of order with respect to their parent sections. + */ + if (strcmp (lsource->ext, rsource->ext)) { + const char **sp; + + /* If the user asked for an explicit section, sort exact + * matches first. + */ + if (section) { + if (STREQ (lsource->ext, section)) { + if (!STREQ (rsource->ext, section)) + return -1; + } else { + if (STREQ (rsource->ext, section)) + return 1; + } + } + + /* Find out whether lsource->ext is ahead of rsource->ext in + * section_list. + */ + for (sp = section_list; *sp; ++sp) { + if (!*(*sp + 1)) { + /* No extension */ + if (!sec_left && **sp == *(lsource->ext)) + sec_left = sp - section_list + 1; + if (!sec_right && **sp == *(rsource->ext)) + sec_right = sp - section_list + 1; + } else if (STREQ (*sp, lsource->ext)) { + sec_left = sp - section_list + 1; + } else if (STREQ (*sp, rsource->ext)) { + sec_right = sp - section_list + 1; + } + /* Keep looking for a more specific match */ + } + if (sec_left != sec_right) + return sec_left - sec_right; + + cmp = strcmp (lsource->sec, rsource->sec); + if (cmp) + return cmp; + } + + /* ULT_MAN comes first, etc. Consider SO_MAN equivalent to ULT_MAN. */ + cmp = compare_ids (lsource->id, rsource->id, 1); + if (cmp) + return cmp; + + /* The order in section_list has already been compared above. For + * everything not mentioned explicitly there, we just compare + * lexically. + */ + cmp = strcmp (lsource->ext, rsource->ext); + if (cmp) + return cmp; + + /* Try comparing based on language. We used to prefer to display a + * page in the user's preferred language than a page from a better + * section, but that attracted objections, so now we prefer to get + * the section right. See Debian bug #519547. + */ + slash1 = strrchr (left->path, '/'); + slash2 = strrchr (right->path, '/'); + if (slash1 && slash2) { + char *locale_copy, *p; + struct locale_bits bits1, bits2, lbits; + const char *codeset1, *codeset2; + + unpack_locale_bits (++slash1, &bits1); + unpack_locale_bits (++slash2, &bits2); + + /* We need the current locale as well. */ + locale_copy = xstrdup (internal_locale); + p = strchr (locale_copy, ':'); + if (p) + *p = '\0'; + unpack_locale_bits (locale_copy, &lbits); + free (locale_copy); + +#define COMPARE_LOCALE_ELEMENTS(elt) do { \ + /* For different elements, prefer one that matches the locale if + * possible. + */ \ + if (*lbits.elt) { \ + if (STREQ (lbits.elt, bits1.elt)) { \ + if (!STREQ (lbits.elt, bits2.elt)) { \ + cmp = -1; \ + goto out; \ + } \ + } else { \ + if (STREQ (lbits.elt, bits2.elt)) { \ + cmp = 1; \ + goto out; \ + } \ + } \ + } \ + cmp = strcmp (bits1.territory, bits2.territory); \ + if (cmp) \ + /* No help from locale; might as well sort lexically. */ \ + goto out; \ +} while (0) + + COMPARE_LOCALE_ELEMENTS (language); + COMPARE_LOCALE_ELEMENTS (territory); + COMPARE_LOCALE_ELEMENTS (modifier); + +#undef COMPARE_LOCALE_ELEMENTS + + /* Prefer UTF-8 if available. Otherwise, consider them + * equal. + */ + codeset1 = get_canonical_charset_name (bits1.codeset); + codeset2 = get_canonical_charset_name (bits2.codeset); + if (STREQ (codeset1, "UTF-8")) { + if (!STREQ (codeset2, "UTF-8")) { + cmp = -1; + goto out; + } + } else { + if (STREQ (codeset2, "UTF-8")) { + cmp = 1; + goto out; + } + } + +out: + free_locale_bits (&lbits); + free_locale_bits (&bits1); + free_locale_bits (&bits2); + if (cmp) + return cmp; + } + + /* Explicitly stabilise the sort as a last resort, so that manpath + * ordering (e.g. language-specific hierarchies) works. + */ + if (left->add_index < right->add_index) + return -1; + else if (left->add_index > right->add_index) + return 1; + else + return 0; + + return 0; +} + +static int compare_candidates_qsort (const void *l, const void *r) +{ + const struct candidate *left = *(const struct candidate **)l; + const struct candidate *right = *(const struct candidate **)r; + + return compare_candidates (left, right); +} + +static void free_candidate (struct candidate *candidate) +{ + if (candidate) + free (candidate->ult); + free (candidate); +} + +/* Add an entry to the list of candidates. */ +static int add_candidate (struct candidate **head, char from_db, char cat, + const char *req_name, const char *path, + const char *ult, struct mandata *source) +{ + struct candidate *search, *prev, *insert, *candp; + static int add_index = 0; + + if (!ult) { + const char *name; + char *filename; + + if (*source->pointer != '-') + name = source->pointer; + else if (source->name) + name = source->name; + else + name = req_name; + + filename = make_filename (path, name, source, cat ? "cat" : "man"); + if (!filename) + return 0; + ult = ult_src (filename, path, NULL, + get_ult_flags (from_db, source->id), NULL); + free (filename); + } + + debug ("candidate: %d %d %s %s %s %c %s %s %s\n", + from_db, cat, req_name, path, ult, + source->id, source->name ? source->name : "-", + source->sec, source->ext); + + if (!source->name) + source->name = xstrdup (req_name); + + candp = XMALLOC (struct candidate); + candp->req_name = req_name; + candp->from_db = from_db; + candp->cat = cat; + candp->path = path; + candp->ult = ult ? xstrdup (ult) : NULL; + candp->source = source; + candp->add_index = add_index++; + candp->next = NULL; + + /* insert will be NULL (insert at start) or a pointer to the element + * after which this element should be inserted. + */ + insert = NULL; + search = *head; + prev = NULL; + /* This search produces quadratic-time behaviour, although in + * practice it doesn't seem to be too bad at the moment since the + * run-time is dominated by calls to ult_src. In future it might be + * worth optimising this; the reason I haven't done this yet is that + * it involves quite a bit of tedious bookkeeping. A practical + * approach would be to keep two hashes, one that's just a set to + * keep track of whether candp->ult has been seen already, and one + * that keeps a list of candidates for each candp->name that could + * then be quickly checked by brute force. + */ + while (search) { + int dupcand = duplicate_candidates (candp, search); + + debug ("search: %d %d %s %s %s %c %s %s %s " + "(dup: %d)\n", + search->from_db, search->cat, search->req_name, + search->path, search->ult, search->source->id, + search->source->name ? search->source->name : "-", + search->source->sec, search->source->ext, dupcand); + + /* Check for duplicates. */ + if (dupcand) { + int cmp = compare_candidates (candp, search); + + if (cmp >= 0) { + debug ("other duplicate is at least as " + "good\n"); + free_candidate (candp); + return 0; + } else { + debug ("this duplicate is better; removing " + "old one\n"); + if (prev) { + prev->next = search->next; + free_candidate (search); + search = prev->next; + } else { + *head = search->next; + free_candidate (search); + search = *head; + } + continue; + } + } + + prev = search; + if (search->next) + search = search->next; + else + break; + } + /* Insert the new candidate at the end of the list (having had to go + * through them all looking for duplicates anyway); we'll sort it + * into place later. + */ + insert = prev; + + candp->next = insert ? insert->next : *head; + if (insert) + insert->next = candp; + else + *head = candp; + + return 1; +} + +/* Sort the entire list of candidates. */ +static void sort_candidates (struct candidate **candidates) +{ + struct candidate *cand, **allcands; + size_t count = 0, i; + + for (cand = *candidates; cand; cand = cand->next) + ++count; + + if (count == 0) + return; + + allcands = XNMALLOC (count, struct candidate *); + i = 0; + for (cand = *candidates; cand; cand = cand->next) { + assert (i < count); + allcands[i++] = cand; + } + assert (i == count); + + qsort (allcands, count, sizeof *allcands, compare_candidates_qsort); + + *candidates = cand = allcands[0]; + for (i = 1; i < count; ++i) { + cand->next = allcands[i]; + cand = cand->next; + } + cand->next = NULL; + + free (allcands); +} + +/* + * See if the preformatted man page or the source exists in the given + * section. + */ +static int try_section (const char *path, const char *sec, const char *name, + struct candidate **cand_head) +{ + int found = 0; + char **names = NULL, **np; + size_t names_len = 0; + char cat = 0; + int lff_opts = (match_case ? LFF_MATCHCASE : 0) | + (regex_opt ? LFF_REGEX : 0) | + (wildcard ? LFF_WILDCARD : 0); + + debug ("trying section %s with globbing\n", sec); + +#ifndef NROFF_MISSING /* #ifdef NROFF */ + /* + * Look for man page source files. + */ + + names = look_for_file (path, sec, name, 0, lff_opts); + if (!names) + /* + * No files match. + * See if there's a preformatted page around that + * we can display. + */ +#endif /* NROFF_MISSING */ + { + if (catman) + return 1; + + if (!troff && !want_encoding && !recode) { + names = look_for_file (path, sec, name, 1, lff_opts); + cat = 1; + } + } + + for (np = names; np && *np; np++) + ++names_len; + order_files (path, names, names_len); + + for (np = names; np && *np; np++) { + struct mandata *info = infoalloc (); + char *info_buffer = filename_info (*np, info, name); + const char *ult; + int f; + + if (!info_buffer) { + free_mandata_struct (info); + continue; + } + info->addr = info_buffer; + + /* What kind of page is this? Since it's a real file, it + * must be either ULT_MAN or SO_MAN. ult_src() can tell us + * which. + */ + ult = ult_src (*np, path, NULL, ult_flags, NULL); + if (!ult) { + /* already warned */ + debug ("try_section(): bad link %s\n", *np); + free (info_buffer); + info->addr = NULL; + free_mandata_struct (info); + continue; + } + if (STREQ (ult, *np)) + info->id = ULT_MAN; + else + info->id = SO_MAN; + + f = add_candidate (cand_head, CANDIDATE_FILESYSTEM, + cat, name, path, ult, info); + found += f; + /* Free info and info_buffer if they weren't added to the + * candidates. + */ + if (f == 0) { + free (info_buffer); + info->addr = NULL; + free_mandata_struct (info); + } + /* Don't free info and info_buffer here. */ + } + + return found; +} + +static int display_filesystem (struct candidate *candp) +{ + char *filename = make_filename (candp->path, NULL, candp->source, + candp->cat ? "cat" : "man"); + char *title; + int found = 0; + + if (!filename) + return 0; + /* source->name is never NULL thanks to add_candidate() */ + title = xasprintf ("%s(%s)", candp->source->name, candp->source->ext); + + if (candp->cat) { + if (troff || want_encoding || recode) + goto out; + found = display (candp->path, NULL, filename, title, NULL); + } else { + const char *man_file; + char *cat_file; + + man_file = ult_src (filename, candp->path, NULL, ult_flags, + NULL); + if (man_file == NULL) + goto out; + + debug ("found ultimate source file %s\n", man_file); + lang = lang_dir (man_file); + + cat_file = find_cat_file (candp->path, filename, man_file); + found = display (candp->path, man_file, cat_file, title, NULL); + free (cat_file); + free (lang); + lang = NULL; + } + +out: + free (title); + free (filename); + return found; +} + +#ifdef MAN_DB_UPDATES +/* wrapper to dbdelete which deals with opening/closing the db */ +static void dbdelete_wrapper (const char *page, struct mandata *info) +{ + if (!catman) { + MYDBM_FILE dbf; + + dbf = MYDBM_RWOPEN (database); + if (dbf) { + if (dbdelete (dbf, page, info) == 1) + debug ("%s(%s) not in db!\n", page, info->ext); + MYDBM_CLOSE (dbf); + } + } +} +#endif /* MAN_DB_UPDATES */ + +/* This started out life as try_section, but a lot of that routine is + redundant wrt the db cache. */ +static int display_database (struct candidate *candp) +{ + int found = 0; + char *file; + const char *name; + char *title; + struct mandata *in = candp->source; + + debug ("trying a db located file.\n"); + dbprintf (in); + + /* if the pointer holds some data, this is a reference to the + real page, use that instead. */ + if (*in->pointer != '-') + name = in->pointer; + else if (in->name) + name = in->name; + else + name = candp->req_name; + + if (in->id == WHATIS_MAN || in->id == WHATIS_CAT) + debug (_("%s: relying on whatis refs is deprecated\n"), name); + + title = xasprintf ("%s(%s)", + in->name ? in->name : candp->req_name, in->ext); + +#ifndef NROFF_MISSING /* #ifdef NROFF */ + /* + * Look for man page source files. + */ + + if (in->id < STRAY_CAT) { /* There should be a src page */ + file = make_filename (candp->path, name, in, "man"); + if (file) { + const char *man_file; + char *cat_file; + + man_file = ult_src (file, candp->path, NULL, + get_ult_flags (1, in->id), NULL); + if (man_file == NULL) { + free (title); + return found; /* zero */ + } + + debug ("found ultimate source file %s\n", man_file); + lang = lang_dir (man_file); + + cat_file = find_cat_file (candp->path, file, man_file); + found += display (candp->path, man_file, cat_file, + title, in->filter); + free (cat_file); + free (lang); + lang = NULL; + free (file); + } /* else {drop through to the bottom and return 0 anyway} */ + } else + +#endif /* NROFF_MISSING */ + + if (in->id <= WHATIS_CAT) { + /* The db says we have a stray cat or whatis ref */ + + if (catman) { + free (title); + return ++found; + } + + /* show this page but force an update later to make sure + we haven't just added the new page */ + found_a_stray = 1; + + /* If explicitly asked for troff or a different encoding, + * don't show a stray cat. + */ + if (troff || want_encoding || recode) { + free (title); + return found; + } + + file = make_filename (candp->path, name, in, "cat"); + if (!file) { + char *catpath; + catpath = get_catpath (candp->path, + global_manpath ? SYSTEM_CAT + : USER_CAT); + + if (catpath && strcmp (catpath, candp->path) != 0) { + file = make_filename (catpath, name, + in, "cat"); + free (catpath); + if (!file) { + /* don't delete here, + return==0 will do that */ + free (title); + return found; /* zero */ + } + } else { + free (catpath); + free (title); + return found; /* zero */ + } + } + + found += display (candp->path, NULL, file, title, in->filter); + free (file); + } + free (title); + return found; +} + +/* test for existence, if fail: call dbdelete_wrapper, else return amount */ +static int display_database_check (struct candidate *candp) +{ + int exists = display_database (candp); + +#ifdef MAN_DB_UPDATES + if (!exists && !skip) { + debug ("dbdelete_wrapper (%s, %p)\n", + candp->req_name, candp->source); + dbdelete_wrapper (candp->req_name, candp->source); + } +#endif /* MAN_DB_UPDATES */ + + return exists; +} + +static void db_hashtable_free (void *defn) +{ + free_mandata_struct (defn); +} + +#ifdef MAN_DB_UPDATES +static int maybe_update_file (const char *manpath, const char *name, + struct mandata *info) +{ + const char *real_name; + char *file; + struct stat buf; + struct timespec file_mtime; + int status; + + if (!update) + return 0; + + /* If the pointer holds some data, then we need to look at that + * name in the filesystem instead. + */ + if (!STRNEQ (info->pointer, "-", 1)) + real_name = info->pointer; + else if (info->name) + real_name = info->name; + else + real_name = name; + + file = make_filename (manpath, real_name, info, "man"); + if (!file) + return 0; + if (lstat (file, &buf) != 0) + return 0; + file_mtime = get_stat_mtime (&buf); + if (timespec_cmp (file_mtime, info->mtime) == 0) + return 0; + + debug ("%s needs to be recached: %ld.%09ld %ld.%09ld\n", + file, + (long) info->mtime.tv_sec, (long) info->mtime.tv_nsec, + (long) file_mtime.tv_sec, (long) file_mtime.tv_nsec); + status = run_mandb (0, manpath, file); + if (status) + error (0, 0, _("mandb command failed with exit status %d"), + status); + free (file); + + return 1; +} +#endif /* MAN_DB_UPDATES */ + +/* Special return values from try_db(). */ + +#define TRY_DATABASE_OPEN_FAILED -1 + +#ifdef MAN_DB_CREATES +#define TRY_DATABASE_CREATED -2 +#endif /* MAN_DB_CREATES */ + +#ifdef MAN_DB_UPDATES +#define TRY_DATABASE_UPDATED -3 +#endif /* MAN_DB_UPDATES */ + +/* Look for a page in the database. If db not accessible, return -1, + otherwise return number of pages found. */ +static int try_db (const char *manpath, const char *sec, const char *name, + struct candidate **cand_head) +{ + struct mandata *loc, *data; + char *catpath; + int found = 0; +#ifdef MAN_DB_UPDATES + int found_stale = 0; +#endif /* MAN_DB_UPDATES */ + + /* find out where our db for this manpath should be */ + + catpath = get_catpath (manpath, global_manpath ? SYSTEM_CAT : USER_CAT); + free (database); + if (catpath) { + database = mkdbname (catpath); + free (catpath); + } else + database = mkdbname (manpath); + + if (!db_hash) + db_hash = hashtable_create (&db_hashtable_free); + + /* Have we looked here already? */ + data = hashtable_lookup (db_hash, manpath, strlen (manpath)); + + if (!data) { + MYDBM_FILE dbf; + + dbf = MYDBM_RDOPEN (database); + if (dbf && dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + } + if (dbf) { + debug ("Succeeded in opening %s O_RDONLY\n", database); + + /* if section is set, only return those that match, + otherwise NULL retrieves all available */ + if (regex_opt || wildcard) + data = dblookup_pattern + (dbf, name, section, match_case, + regex_opt, !names_only); + else + data = dblookup_all (dbf, name, section, + match_case); + hashtable_install (db_hash, manpath, strlen (manpath), + data); + MYDBM_CLOSE (dbf); + dbf = NULL; +#ifdef MAN_DB_CREATES + } else if (!global_manpath) { + /* create one */ + debug ("Failed to open %s O_RDONLY\n", database); + if (run_mandb (1, manpath, NULL)) { + data = infoalloc (); + data->next = NULL; + data->addr = NULL; + hashtable_install (db_hash, + manpath, strlen (manpath), + data); + return TRY_DATABASE_OPEN_FAILED; + } + return TRY_DATABASE_CREATED; +#endif /* MAN_DB_CREATES */ + } else { + debug ("Failed to open %s O_RDONLY\n", database); + data = infoalloc (); + data->next = (struct mandata *) NULL; + data->addr = NULL; + hashtable_install (db_hash, manpath, strlen (manpath), + data); + return TRY_DATABASE_OPEN_FAILED; + } + } + + /* if we already know that there is nothing here, get on with it */ + if (!data) + return 0; + + /* We already tried (and failed) to open this db before */ + if (!data->addr) + return TRY_DATABASE_OPEN_FAILED; + +#ifdef MAN_DB_UPDATES + /* Check that all the entries found are up to date. If not, the + * caller should try again. + */ + for (loc = data; loc; loc = loc->next) + if (STREQ (sec, loc->sec) && + (!extension || STREQ (extension, loc->ext) + || STREQ (extension, loc->ext + strlen (sec)))) + if (maybe_update_file (manpath, name, loc)) + found_stale = 1; + + if (found_stale) { + hashtable_remove (db_hash, manpath, strlen (manpath)); + return TRY_DATABASE_UPDATED; + } +#endif /* MAN_DB_UPDATES */ + + /* cycle through the mandata structures (there's usually only + 1 or 2) and see what we have w.r.t. the current section */ + for (loc = data; loc; loc = loc->next) + if (STREQ (sec, loc->sec) && + (!extension || STREQ (extension, loc->ext) + || STREQ (extension, loc->ext + strlen (sec)))) + found += add_candidate (cand_head, CANDIDATE_DATABASE, + 0, name, manpath, NULL, loc); + + return found; +} + +/* Try to locate the page under the specified manpath, in the desired section, + * with the supplied name. Glob if necessary. Initially search the filesystem; + * if that fails, try finding it via a db cache access. */ +static int locate_page (const char *manpath, const char *sec, const char *name, + struct candidate **candidates) +{ + int found, db_ok; + + /* sort out whether we want to treat this hierarchy as + global or user. Differences: + + global: if setuid, use privs; don't create db. + user : if setuid, drop privs; allow db creation. */ + + global_manpath = is_global_mandir (manpath); + if (!global_manpath) + drop_effective_privs (); + + debug ("searching in %s, section %s\n", manpath, sec); + + found = try_section (manpath, sec, name, candidates); + + if ((!found || findall) && !global_apropos) { + db_ok = try_db (manpath, sec, name, candidates); + +#ifdef MAN_DB_CREATES + if (db_ok == TRY_DATABASE_CREATED) + /* we created a db in the last call */ + db_ok = try_db (manpath, sec, name, candidates); +#endif /* MAN_DB_CREATES */ + +#ifdef MAN_DB_UPDATES + if (db_ok == TRY_DATABASE_UPDATED) + /* We found some outdated entries and rebuilt the + * database in the last call. If this keeps + * happening, though, give up and punt to the + * filesystem. + */ + db_ok = try_db (manpath, sec, name, candidates); +#endif /* MAN_DB_UPDATES */ + + if (db_ok > 0) /* we found/opened a db and found something */ + found += db_ok; + } + + if (!global_manpath) + regain_effective_privs (); + + return found; +} + +static int display_pages (struct candidate *candidates) +{ + struct candidate *candp; + int found = 0; + + for (candp = candidates; candp; candp = candp->next) { + global_manpath = is_global_mandir (candp->path); + if (!global_manpath) + drop_effective_privs (); + + switch (candp->from_db) { + case CANDIDATE_FILESYSTEM: + found += display_filesystem (candp); + break; + case CANDIDATE_DATABASE: + found += display_database_check (candp); + break; + default: + error (0, 0, + _("internal error: candidate type %d " + "out of range"), candp->from_db); + } + + if (!global_manpath) + regain_effective_privs (); + + if (found && !findall) + return found; + } + + return found; +} + +/* + * Search for text in all manual pages. + * + * This is not a real full-text search, but a brute-force on-demand search. + * The idea, name, and approach originate in the 'man' package, added (I + * believe) by Andries Brouwer, although the implementation is new for + * man-db and much faster due to running in-process. + * + * Conceptually, this really belongs in whatis.c, as part of apropos. + * However, the implementation in 'man' offers pages for immediate display + * on request rather than simply listing them, which is currently awkward to + * do in apropos. If we ever add support to apropos/whatis for either + * calling back to man or displaying pages directly, we should revisit this. + */ +static int grep (const char *file, const char *string, const regex_t *search) +{ + struct stat st; + pipeline *decomp; + const char *line; + int ret = 0; + + /* pipeline_start makes file open failures unconditionally fatal. + * Here, we'd rather just ignore any such files. + */ + if (stat (file, &st) < 0) + return 0; + + decomp = decompress_open (file); + if (!decomp) + return 0; + pipeline_start (decomp); + while ((line = pipeline_readline (decomp)) != NULL) { + if (regex_opt) { + if (regexec (search, line, + 0, (regmatch_t *) 0, 0) == 0) { + ret = 1; + break; + } + } else { + if (match_case ? + strstr (line, string) : + strcasestr (line, string)) { + ret = 1; + break; + } + } + } + + pipeline_free (decomp); + return ret; +} + +static int do_global_apropos_section (const char *path, const char *sec, + const char *name) +{ + int found = 0; + char **names, **np; + size_t names_len = 0; + regex_t search; + + global_manpath = is_global_mandir (path); + if (!global_manpath) + drop_effective_privs (); + + debug ("searching in %s, section %s\n", path, sec); + + names = look_for_file (path, sec, "*", 0, LFF_WILDCARD); + if (regex_opt) + xregcomp (&search, name, + REG_EXTENDED | REG_NOSUB | + (match_case ? 0 : REG_ICASE)); + else + memset (&search, 0, sizeof search); + + for (np = names; np && *np; ++np) + ++names_len; + order_files (path, names, names_len); + + for (np = names; np && *np; ++np) { + struct mandata *info; + char *info_buffer; + char *title = NULL; + const char *man_file; + char *cat_file = NULL; + + if (!grep (*np, name, &search)) + continue; + + info = infoalloc (); + info_buffer = filename_info (*np, info, NULL); + if (!info_buffer) + goto next; + info->addr = info_buffer; + + title = xasprintf ("%s(%s)", strchr (info_buffer, '\0') + 1, + info->ext); + man_file = ult_src (*np, path, NULL, ult_flags, NULL); + if (!man_file) + goto next; + lang = lang_dir (man_file); + cat_file = find_cat_file (path, *np, man_file); + if (display (path, man_file, cat_file, title, NULL)) + found = 1; + free (lang); + lang = NULL; + +next: + free (cat_file); + free (title); + free_mandata_struct (info); + } + + if (regex_opt) + regfree (&search); + + if (!global_manpath) + regain_effective_privs (); + + return found; +} + +static int do_global_apropos (const char *name, int *found) +{ + const char **my_section_list; + const char **sp; + char **mp; + + if (section) { + my_section_list = XNMALLOC (2, const char *); + my_section_list[0] = section; + my_section_list[1] = NULL; + } else + my_section_list = section_list; + + for (sp = my_section_list; *sp; sp++) + for (mp = manpathlist; *mp; mp++) + *found += do_global_apropos_section (*mp, *sp, name); + + if (section) + free (my_section_list); + + return *found ? OK : NOT_FOUND; +} + +/* Each of local_man_loop and man sometimes calls the other. */ +static int man (const char *name, int *found); + +/* man issued with `-l' option */ +static int local_man_loop (const char *argv) +{ + int exit_status = OK; + int local_mf = local_man_file; + + drop_effective_privs (); + local_man_file = 1; + if (strcmp (argv, "-") == 0) + display (NULL, "", NULL, "(stdin)", NULL); + else { + struct stat st; + + /* Check that the file exists and isn't e.g. a directory */ + if (stat (argv, &st)) { + error (0, errno, "%s", argv); + return NOT_FOUND; + } + + if (S_ISDIR (st.st_mode)) { + error (0, EISDIR, "%s", argv); + return NOT_FOUND; + } + + if (S_ISCHR (st.st_mode) || S_ISBLK (st.st_mode)) { + /* EINVAL is about the best I can do. */ + error (0, EINVAL, "%s", argv); + return NOT_FOUND; + } + + if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { + /* Perhaps an executable. If its directory is on + * $PATH, then we want to look up the corresponding + * manual page in the appropriate hierarchy rather + * than displaying the executable. + */ + char *argv_dir = dir_name (argv); + int found = 0; + + if (directory_on_path (argv_dir)) { + char *argv_base = base_name (argv); + char *new_manp, *nm; + char **old_manpathlist, **mp; + + debug ("recalculating manpath for executable " + "in %s\n", argv_dir); + + new_manp = get_manpath_from_path (argv_dir, 0); + if (!new_manp || !*new_manp) { + debug ("no useful manpath for " + "executable\n"); + goto executable_out; + } + nm = locale_manpath (new_manp); + free (new_manp); + new_manp = nm; + + old_manpathlist = XNMALLOC (MAXDIRS, char *); + memcpy (old_manpathlist, manpathlist, + MAXDIRS * sizeof (*manpathlist)); + create_pathlist (new_manp, manpathlist); + + man (argv_base, &found); + + for (mp = manpathlist; *mp; ++mp) + free (*mp); + memcpy (manpathlist, old_manpathlist, + MAXDIRS * sizeof (*manpathlist)); + free (old_manpathlist); +executable_out: + free (new_manp); + free (argv_base); + } + free (argv_dir); + + if (found) + return OK; + } + + if (exit_status == OK) { + char *argv_base = base_name (argv); + char *argv_abs; + if (argv[0] == '/') + argv_abs = xstrdup (argv); + else { + argv_abs = xgetcwd (); + if (argv_abs) + argv_abs = appendstr (argv_abs, "/", + argv, + (void *) 0); + else + argv_abs = xstrdup (argv); + } + lang = lang_dir (argv_abs); + free (argv_abs); + if (!display (NULL, argv, NULL, argv_base, NULL)) { + if (local_mf) + error (0, errno, "%s", argv); + exit_status = NOT_FOUND; + } + free (lang); + lang = NULL; + free (argv_base); + } + } + local_man_file = local_mf; + regain_effective_privs (); + return exit_status; +} + +/* + * Splits a "name[.section]" into { "name", "section" }. + * Section would be NULL if not present. + * The caller is responsible for freeing *ret_name and *ret_section. + * */ +static void split_page_name (const char *page_name, + char **ret_name, + char **ret_section) +{ + char *dot; + + dot = strrchr (page_name, '.'); + + if (dot && is_section (dot + 1)) { + *ret_name = xstrndup (page_name, dot - page_name); + *ret_section = xstrdup (dot + 1); + } else { + *ret_name = xstrdup (page_name); + *ret_section = NULL; + } +} + +static void locate_page_in_manpath (const char *page_section, + const char *page_name, + struct candidate **candidates, + int *found) +{ + char **mp; + + for (mp = manpathlist; *mp; mp++) + *found += locate_page (*mp, page_section, page_name, candidates); +} + +/* + * 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. + * + */ +static int man (const char *name, int *found) +{ + char *page_name, *page_section; + struct candidate *candidates = NULL, *cand, *candnext; + + *found = 0; + fflush (stdout); + + if (strchr (name, '/')) { + int status = local_man_loop (name); + if (status == OK) + *found = 1; + return status; + } + + if (section) + locate_page_in_manpath (section, name, &candidates, found); + else { + const char **sp; + + for (sp = section_list; *sp; sp++) { + locate_page_in_manpath (*sp, name, &candidates, found); + } + } + + split_page_name (name, &page_name, &page_section); + + if (!*found && page_section) + locate_page_in_manpath (page_section, page_name, &candidates, + found); + + free (page_name); + free (page_section); + + sort_candidates (&candidates); + + if (*found) + *found = display_pages (candidates); + + for (cand = candidates; cand; cand = candnext) { + candnext = cand->next; + free_candidate (cand); + } + + return *found ? OK : NOT_FOUND; +} + + +static const char **get_section_list (void) +{ + int i = 0; + const char **config_sections; + const char **sections = NULL; + const char *sec; + + /* Section list from configuration file, or STD_SECTIONS if it's + * empty. + */ + config_sections = get_sections (); + if (!*config_sections) { + free (config_sections); + config_sections = std_sections; + } + + if (colon_sep_section_list == NULL) + colon_sep_section_list = getenv ("MANSECT"); + if (colon_sep_section_list == NULL || *colon_sep_section_list == '\0') + return config_sections; + + /* Although this is documented as colon-separated, at least Solaris + * man's -s option takes a comma-separated list, so we accept that + * too for compatibility. + */ + for (sec = strtok (colon_sep_section_list, ":,"); sec; + sec = strtok (NULL, ":,")) { + sections = xnrealloc (sections, i + 2, sizeof *sections); + sections[i++] = sec; + } + + if (i > 0) { + sections[i] = NULL; + return sections; + } else { + free (sections); + return config_sections; + } +} + +/* + * Returns the first token of a libpipeline/sh-style command. See SUSv4TC2: + * 2.2 Shell Command Language: Quoting. + * + * Free the returned value. + * + * Examples: + * sh_lang_first_word ("echo 3") returns "echo" + * sh_lang_first_word ("'e ho' 3") returns "e ho" + * sh_lang_first_word ("e\\cho 3") returns "echo" + * sh_lang_first_word ("e\\\ncho 3") returns "echo" + * sh_lang_first_word ("\"echo t\" 3") returns "echo t" + * sh_lang_first_word ("\"ech\\o t\" 3") returns "ech\\o t" + * sh_lang_first_word ("\"ech\\\\o t\" 3") returns "ech\\o t" + * sh_lang_first_word ("\"ech\\\no t\" 3") returns "echo t" + * sh_lang_first_word ("\"ech\\$ t\" 3") returns "ech$ t" + * sh_lang_first_word ("\"ech\\` t\" 3") returns "ech` t" + * sh_lang_first_word ("e\"ch\"o 3") returns "echo" + * sh_lang_first_word ("e'ch'o 3") returns "echo" + */ +static char *sh_lang_first_word (const char *cmd) +{ + int i, o = 0; + char *ret = xmalloc (strlen (cmd) + 1); + + for (i = 0; cmd[i] != '\0'; i++) { + if (cmd[i] == '\\') { + /* Escape Character (Backslash) */ + i++; + if (cmd[i] == '\0') + break; + if (cmd[i] != '\n') + ret[o++] = cmd[i]; + } else if (cmd[i] == '\'') { + /* Single-Quotes */ + i++; + while (cmd[i] != '\0' && cmd[i] != '\'') + ret[o++] = cmd[i++]; + } else if (cmd[i] == '"') { + /* Double-Quotes */ + i++; + while (cmd[i] != '\0' && cmd[i] != '"') { + if (cmd[i] == '\\') { + if (cmd[i + 1] == '$' || + cmd[i + 1] == '`' || + cmd[i + 1] == '"' || + cmd[i + 1] == '\\') + ret[o++] = cmd[++i]; + else if (cmd[i + 1] == '\n') + i++; + else + ret[o++] = cmd[i]; + } else + ret[o++] = cmd[i]; + + i++; + } + } else if (cmd[i] == '\t' || cmd[i] == ' ' || cmd[i] == '\n' || + cmd[i] == '#') + break; + else + ret[o++] = cmd[i]; + } + + ret[o] = '\0'; + + return ret; +} + +int main (int argc, char *argv[]) +{ + int argc_env, exit_status = OK; + char **argv_env; + const char *tmp; + + set_program_name (argv[0]); + + check_standard_fds (); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + + umask (022); + init_locale (); + + internal_locale = setlocale (LC_MESSAGES, NULL); + /* Use LANGUAGE only when LC_MESSAGES locale category is + * neither "C" nor "POSIX". */ + if (internal_locale && strcmp (internal_locale, "C") && + strcmp (internal_locale, "POSIX")) + multiple_locale = getenv ("LANGUAGE"); + internal_locale = xstrdup (internal_locale ? internal_locale : "C"); + +/* export argv, it might be needed when invoking the vendor supplied browser */ +#if defined _AIX || defined __sgi + global_argv = argv; +#endif + +#ifdef TROFF_IS_GROFF + /* used in --help, so initialise early */ + if (!html_pager) + init_html_pager (); +#endif /* TROFF_IS_GROFF */ + + /* First of all, find out if $MANOPT is set. If so, put it in + *argv[] format for argp to play with. */ + argv_env = manopt_to_env (&argc_env); + if (argv_env) + if (argp_parse (&argp, argc_env, argv_env, ARGP_NO_ARGS, 0, 0)) + exit (FAIL); + + /* parse the actual program args */ + if (argp_parse (&argp, argc, argv, ARGP_NO_ARGS, &first_arg, 0)) + exit (FAIL); + + /* record who we are and drop effective privs for later use */ + init_security (); + + read_config_file (local_man_file || user_config_file); + + /* if the user wants whatis or apropos, give it to them... */ + if (external) + do_extern (argc, argv); + + get_term (); /* stores terminal settings */ +#ifdef MAN_OWNER + debug ("real user = %d; effective user = %d\n", ruid, euid); +#endif /* MAN_OWNER */ + + /* close this locale and reinitialise if a new locale was + issued as an argument or in $MANOPT */ + if (locale) { + free (internal_locale); + internal_locale = setlocale (LC_ALL, locale); + if (internal_locale) + internal_locale = xstrdup (internal_locale); + else + internal_locale = xstrdup (locale); + + debug ("main(): locale = %s, internal_locale = %s\n", + locale, internal_locale); + if (internal_locale) { + setenv ("LANGUAGE", internal_locale, 1); + locale_changed (); + multiple_locale = NULL; + } + } + +#ifdef TROFF_IS_GROFF + if (htmlout) + pager = html_pager; +#endif /* TROFF_IS_GROFF */ + + if (pager == NULL) + pager = getenv ("MANPAGER"); + if (pager == NULL) + pager = getenv ("PAGER"); + if (pager == NULL) + pager = get_def_user ("pager", NULL); + if (pager == NULL) { + char *pager_program = sh_lang_first_word (PAGER); + if (pathsearch_executable (pager_program)) + pager = PAGER; + else + pager = ""; + free (pager_program); + } + if (*pager == '\0') + pager = get_def_user ("cat", CAT); + + if (prompt_string == NULL) + prompt_string = getenv ("MANLESS"); + + if (prompt_string == NULL) +#ifdef LESS_PROMPT + prompt_string = LESS_PROMPT; +#else + prompt_string = _( + " Manual page " MAN_PN + " ?ltline %lt?L/%L.:byte %bB?s/%s..?e (END):" + "?pB %pB\\%.. " + "(press h for help or q to quit)"); +#endif + + /* Restore and save $LESS in $MAN_ORIG_LESS so that recursive uses + * of man work as expected. + */ + less = getenv ("MAN_ORIG_LESS"); + if (less == NULL) + less = getenv ("LESS"); + setenv ("MAN_ORIG_LESS", less ? less : "", 1); + + debug ("\nusing %s as pager\n", pager); + + if (first_arg == argc) { + if (print_where) { + manp = get_manpath (""); + printf ("%s\n", manp); + exit (OK); + } else { + free (internal_locale); + gripe_no_name (NULL); + } + } + + section_list = get_section_list (); + + if (manp == NULL) { + char *mp = get_manpath (alt_system_name); + manp = locale_manpath (mp); + free (mp); + } else + free (get_manpath (NULL)); + + debug ("manpath search path (with duplicates) = %s\n", manp); + + create_pathlist (manp, manpathlist); + + /* man issued with `-l' option */ + if (local_man_file) { + while (first_arg < argc) { + exit_status = local_man_loop (argv[first_arg]); + ++first_arg; + } + free (internal_locale); + exit (exit_status); + } + + /* finished manpath processing, regain privs */ + regain_effective_privs (); + +#ifdef MAN_DB_UPDATES + /* If `-u', do it now. */ + if (update) { + int status = run_mandb (0, NULL, NULL); + if (status) + error (0, 0, + _("mandb command failed with exit status %d"), + status); + } +#endif /* MAN_DB_UPDATES */ + + while (first_arg < argc) { + int status = OK; + int found = 0; + static int maybe_section = 0; + const char *nextarg = argv[first_arg++]; + + /* + * See if this argument is a valid section name. If not, + * is_section returns NULL. + */ + if (!catman) { + tmp = is_section (nextarg); + if (tmp) { + section = tmp; + debug ("\nsection: %s\n", section); + maybe_section = 1; + } + } + + if (maybe_section) { + if (first_arg < argc) + /* e.g. 'man 3perl Shell' */ + nextarg = argv[first_arg++]; + else + /* e.g. 'man 9wm' */ + section = NULL; + /* ... but leave maybe_section set so we can + * tell later that this happened. + */ + } + + /* this is where we actually start looking for the man page */ + skip = 0; + if (global_apropos) + status = do_global_apropos (nextarg, &found); + else { + int found_subpage = 0; + if (subpages && first_arg < argc) { + char *subname = xasprintf ( + "%s-%s", nextarg, argv[first_arg]); + status = man (subname, &found); + free (subname); + if (status == OK) { + found_subpage = 1; + ++first_arg; + } + } + if (!found_subpage && subpages && first_arg < argc) { + char *subname = xasprintf ( + "%s_%s", nextarg, argv[first_arg]); + status = man (subname, &found); + free (subname); + if (status == OK) { + found_subpage = 1; + ++first_arg; + } + } + if (!found_subpage) + status = man (nextarg, &found); + } + + /* clean out the cache of database lookups for each man page */ + hashtable_free (db_hash); + db_hash = NULL; + + if (section && maybe_section) { + if (status != OK && !catman) { + /* Maybe the section wasn't a section after + * all? e.g. 'man 9wm fvwm'. + */ + int found_subpage = 0; + debug ("\nRetrying section %s as name\n", + section); + tmp = section; + section = NULL; + if (subpages) { + char *subname = xasprintf ( + "%s-%s", tmp, nextarg); + status = man (subname, &found); + free (subname); + if (status == OK) { + found_subpage = 1; + ++first_arg; + } + } + if (!found_subpage) + status = man (tmp, &found); + hashtable_free (db_hash); + db_hash = NULL; + /* ... but don't gripe about it if it doesn't + * work! + */ + if (status == OK) { + /* It was a name after all, so arrange + * to try the next page again with a + * null section. + */ + nextarg = tmp; + --first_arg; + } else + /* No go, it really was a section. */ + section = tmp; + } + } + + if (status != OK && !catman) { + if (!skip) { + exit_status = status; + if (exit_status == NOT_FOUND) { + if (!section && maybe_section && + CTYPE (isdigit, nextarg[0])) + gripe_no_name (nextarg); + else + gripe_no_man (nextarg, section); + } + } + } else { + debug ("\nFound %d man pages\n", found); + if (catman) { + printf ("%s", nextarg); + if (section) + printf ("(%s)", section); + if (first_arg != argc) + fputs (", ", stdout); + else + fputs (".\n", stdout); + } + } + + maybe_section = 0; + + chkr_garbage_detector (); + } + hashtable_free (db_hash); + db_hash = NULL; + + drop_effective_privs (); + + free (database); + free_pathlist (manpathlist); + free (internal_locale); + exit (exit_status); +} diff --git a/src/man_db.conf.in b/src/man_db.conf.in new file mode 100644 index 0000000..bc8bb7e --- /dev/null +++ b/src/man_db.conf.in @@ -0,0 +1,131 @@ +# @config_file_basename@ +# +# This file is used by the man-db package to configure the man and cat paths. +# It is also used to provide a manpath for those without one by examining +# their PATH environment variable. For details see the manpath(5) man page. +# +# Lines beginning with `#' are comments and are ignored. Any combination of +# tabs or spaces may be used as `whitespace' separators. +# +# There are three mappings allowed in this file: +# -------------------------------------------------------- +# MANDATORY_MANPATH manpath_element +# MANPATH_MAP path_element manpath_element +# MANDB_MAP global_manpath [relative_catpath] +#--------------------------------------------------------- +# every automatically generated MANPATH includes these fields +# +#MANDATORY_MANPATH /usr/src/pvm3/man +# +MANDATORY_MANPATH /usr/man +MANDATORY_MANPATH /usr/share/man +MANDATORY_MANPATH /usr/local/share/man +#--------------------------------------------------------- +# set up PATH to MANPATH mapping +# ie. what man tree holds man pages for what binary directory. +# +# *PATH* -> *MANPATH* +# +MANPATH_MAP /bin /usr/share/man +MANPATH_MAP /usr/bin /usr/share/man +MANPATH_MAP /sbin /usr/share/man +MANPATH_MAP /usr/sbin /usr/share/man +MANPATH_MAP /usr/local/bin /usr/local/man +MANPATH_MAP /usr/local/bin /usr/local/share/man +MANPATH_MAP /usr/local/sbin /usr/local/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/games /usr/share/man +MANPATH_MAP /opt/bin /opt/man +MANPATH_MAP /opt/sbin /opt/man +#--------------------------------------------------------- +# For a manpath element to be treated as a system manpath (as most of those +# above should normally be), it must be mentioned below. Each line may have +# an optional extra string indicating the catpath associated with the +# manpath. If no catpath string is used, the catpath will default to the +# given manpath. +# +# You *must* provide all system manpaths, including manpaths for alternate +# operating systems, locale specific manpaths, and combinations of both, if +# they exist, otherwise the permissions of the user running man/mandb will +# be used to manipulate the manual pages. Also, mandb will not initialise +# the database cache for any manpaths not mentioned below unless explicitly +# requested to do so. +# +# In a per-user configuration file, this directive only controls the +# location of catpaths and the creation of database caches; it has no effect +# on privileges. +# +# Any manpaths that are subdirectories of other manpaths must be mentioned +# *before* the containing manpath. E.g. /usr/man/preformat must be listed +# before /usr/man. +# +# *MANPATH* -> *CATPATH* +# +MANDB_MAP /usr/man /var/cache/man/fsstnd +MANDB_MAP /usr/share/man /var/cache/man +MANDB_MAP /usr/local/man /var/cache/man/oldlocal +MANDB_MAP /usr/local/share/man /var/cache/man/local +MANDB_MAP /usr/X11R6/man /var/cache/man/X11R6 +MANDB_MAP /opt/man /var/cache/man/opt +# +#--------------------------------------------------------- +# Program definitions. These are commented out by default as the value +# of the definition is already the default. To change: uncomment a +# definition and modify it. +# +#DEFINE pager @pager@ +#DEFINE cat @cat@ +#DEFINE tr @tr@ '\255\267\264\327' '\055\157\047\170' +#DEFINE grep @grep@ +#DEFINE troff @troff@ +#DEFINE nroff @nroff@ +#DEFINE eqn @eqn@ +#DEFINE neqn @neqn@ +#DEFINE tbl @tbl@ +#DEFINE col @col@ +#DEFINE vgrind @vgrind@ +#DEFINE refer @refer@ +#DEFINE grap @grap@ +#DEFINE pic @pic@ +# +#DEFINE compressor @compressor@ +#--------------------------------------------------------- +# Misc definitions: same as program definitions above. +# +#DEFINE whatis_grep_flags -i +#DEFINE apropos_grep_flags -iEw +#DEFINE apropos_regex_grep_flags -iE +#--------------------------------------------------------- +# Section names. Manual sections will be searched in the order listed here; +# the default is 1, n, l, 8, 3, 0, 2, 5, 4, 9, 6, 7. Multiple SECTION +# directives may be given for clarity, and will be concatenated together in +# the expected way. +# If a particular extension is not in this list (say, 1mh), it will be +# displayed with the rest of the section it belongs to. The effect of this +# is that you only need to explicitly list extensions if you want to force a +# particular order. Sections with extensions should usually be adjacent to +# their main section (e.g. "1 1mh 8 ..."). +# +SECTION @sections@ +# +#--------------------------------------------------------- +# Range of terminal widths permitted when displaying cat pages. If the +# terminal falls outside this range, cat pages will not be created (if +# missing) or displayed. +# +#MINCATWIDTH 80 +#MAXCATWIDTH 80 +# +# If CATWIDTH is set to a non-zero number, cat pages will always be +# formatted for a terminal of the given width, regardless of the width of +# the terminal actually being used. This should generally be within the +# range set by MINCATWIDTH and MAXCATWIDTH. +# +#CATWIDTH 0 +# +#--------------------------------------------------------- +# Flags. +# NOCACHE keeps man from creating cat pages. +#NOCACHE diff --git a/src/manconv.c b/src/manconv.c new file mode 100644 index 0000000..9759a28 --- /dev/null +++ b/src/manconv.c @@ -0,0 +1,352 @@ +/* + * manconv.c: convert manual page from one encoding to another + * + * Copyright (C) 2007, 2008, 2009, 2010, 2012 Colin Watson. + * Based loosely on parts of glibc's iconv_prog.c, which is: + * Copyright (C) 1998-2004, 2005, 2006, 2007 Free Software Foundation, Inc. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This program arose during a discussion with Adam Borowski. See: + * https://lists.debian.org/debian-mentors/2007/09/msg00245.html + * It behaves like iconv, but allows multiple source encodings and + * attempts to guess the first one that works. An Emacs-style + * "-*- coding:" declaration overrides this. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <unistd.h> + +#ifdef HAVE_ICONV +# include <iconv.h> +#endif /* HAVE_ICONV */ + +#include "argp.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "encodings.h" + +#include "manconv.h" + +#ifdef HAVE_ICONV + +/* When converting text containing an invalid multibyte sequence to + * UTF-8//IGNORE, GNU libc's iconv returns EILSEQ but sets *inbuf to the end + * of the input buffer. I'm not sure whether this is a bug or not (it seems + * to contradict the documentation), but work around it anyway by recoding + * to UTF-8 so that we can accurately position the error. + */ +static off_t locate_error (const char *try_from_code, + const char *input, size_t input_size, + char *utf8, size_t utf8_size) +{ + iconv_t cd_utf8_strict; + char *inptr = (char *) input, *utf8ptr = utf8; + size_t inleft = input_size, utf8left = utf8_size; + size_t n; + off_t ret; + + cd_utf8_strict = iconv_open ("UTF-8", try_from_code); + if (cd_utf8_strict == (iconv_t) -1) { + error (0, errno, "iconv_open (\"UTF-8\", \"%s\")", + try_from_code); + return 0; + } + + n = iconv (cd_utf8_strict, (ICONV_CONST char **) &inptr, &inleft, + &utf8ptr, &utf8left); + if (n == (size_t) -1) + ret = inptr - input; + else + ret = 0; + + iconv_close (cd_utf8_strict); + + return ret; +} + +static int try_iconv (pipeline *p, const char *try_from_code, const char *to, + int last) +{ + char *try_to_code = xstrdup (to); + static const size_t buf_size = 65536; + size_t input_size = buf_size; + off_t input_pos = 0; + const char *input; + static char *utf8 = NULL, *output = NULL; + size_t utf8left = 0; + iconv_t cd_utf8, cd = NULL; + int to_utf8 = STREQ (try_to_code, "UTF-8") || + STRNEQ (try_to_code, "UTF-8//", 7); + const char *utf8_target = last ? "UTF-8//IGNORE" : "UTF-8"; + int ignore_errors = (strstr (try_to_code, "//IGNORE") != NULL);; + int ret = 0; + + debug ("trying encoding %s -> %s\n", try_from_code, try_to_code); + + cd_utf8 = iconv_open (utf8_target, try_from_code); + if (cd_utf8 == (iconv_t) -1) { + error (0, errno, "iconv_open (\"%s\", \"%s\")", + utf8_target, try_from_code); + free (try_to_code); + return -1; + } + + if (!to_utf8) { + cd = iconv_open (try_to_code, "UTF-8"); + if (cd == (iconv_t) -1) { + error (0, errno, "iconv_open (\"%s\", \"UTF-8\")", + try_to_code); + free (try_to_code); + return -1; + } + } + + input = pipeline_peek (p, &input_size); + if (input_size < buf_size) { + /* End of file, error, or just a short read? Repeat until we + * have either a full buffer or EOF/error. + */ + while (input_size < buf_size) { + size_t old_input_size = input_size; + input_size = buf_size; + input = pipeline_peek (p, &input_size); + if (input_size == old_input_size) + break; + } + } + + if (!utf8) + utf8 = xmalloc (buf_size); + if (!output) + output = xmalloc (buf_size); + + while (input_size || utf8left) { + int handle_iconv_errors = 0; + char *inptr = (char *) input, *utf8ptr = utf8; + char *outptr = output; + size_t inleft = input_size, outleft; + size_t n, n2 = -1; + + if (!utf8left) { + /* First, convert the text to UTF-8. By assumption, + * all validly-encoded text can be converted to + * UTF-8 assuming that we picked the correct + * encoding. Any errors at this stage are due to + * selecting an incorrect encoding, or due to + * misencoded source text. + */ + utf8left = buf_size; + n = iconv (cd_utf8, (ICONV_CONST char **) &inptr, + &inleft, &utf8ptr, &utf8left); + utf8left = buf_size - utf8left; + + /* If we need to try the next encoding, do that + * before writing anything. + */ + if (!last && n == (size_t) -1 && + (errno == EILSEQ || + (errno == EINVAL && input_size < buf_size))) { + ret = -1; + break; + } else if (n == (size_t) -1) + handle_iconv_errors = errno; + } + + /* If the target encoding is UTF-8 (the common case), then + * we can just write out what we've got. Otherwise, we need + * to convert to the target encoding. Any errors at this + * stage are due to characters that are not representable in + * the target encoding. + */ + if (handle_iconv_errors) + /* Fall back to error handling below. If we have + * anything to write out, we'll do it next time + * round the loop. + */ + ; + else if (to_utf8) { + memcpy (output, utf8, utf8left); + outptr += utf8left; + outleft = utf8left; + utf8left = 0; + } else if (utf8left) { + outptr = output; + outleft = buf_size; + utf8ptr = utf8; + n2 = iconv ( + cd, (ICONV_CONST char **) &utf8ptr, &utf8left, + &outptr, &outleft); + outleft = buf_size - outleft; + if (n2 == (size_t) -1) + handle_iconv_errors = errno; + + if (n2 == (size_t) -1 && + errno == EILSEQ && ignore_errors) + errno = 0; + } else + /* We appear to have converted some input text, but + * not actually ended up with any UTF-8 text. This + * is odd. However, we can at least continue round + * the loop, skip the input text we converted, and + * then we should get a different result next time. + */ + outptr = output; + + if (outptr != output) { + /* We have something to write out. */ + int errno_save = errno; + size_t w; + w = fwrite (output, 1, outleft, stdout); + if (w < (size_t) outleft || ferror (stdout)) + error (FATAL, 0, _("can't write to " + "standard output")); + errno = errno_save; + } + + if (!to_utf8 && n2 != (size_t) -1) { + /* All the UTF-8 text we have so far was processed. + * For state-dependent character sets we have to + * flush the state now. + */ + outptr = output; + outleft = buf_size; + iconv (cd, NULL, NULL, &outptr, &outleft); + outleft = buf_size - outleft; + + if (outptr != output) { + /* We have something to write out. */ + int errno_save = errno; + size_t w; + w = fwrite (output, 1, outleft, stdout); + if (w < (size_t) outleft || ferror (stdout)) + error (FATAL, 0, _("can't write to " + "standard output")); + errno = errno_save; + } + } else if (handle_iconv_errors) { + intmax_t error_pos; + + if (handle_iconv_errors == EILSEQ && !ignore_errors) { + if (!quiet) { + error_pos = input_pos + locate_error ( + try_from_code, + input, input_size, + utf8, buf_size); + error (0, handle_iconv_errors, + "byte %jd: iconv", error_pos); + } + exit (FATAL); + } else if (handle_iconv_errors == EINVAL && + input_size < buf_size) { + if (!quiet) { + error_pos = input_pos + locate_error ( + try_from_code, + input, input_size, + utf8, buf_size); + error (FATAL, 0, "byte %jd: %s", + error_pos, + _("iconv: incomplete character " + "at end of buffer")); + } + exit (FATAL); + } + } + + if (inptr != input) { + pipeline_peek_skip (p, input_size - inleft); + input_pos += input_size - inleft; + } + + /* Unless we have some UTF-8 text left (which will only + * happen if the output encoding is more verbose than UTF-8, + * so is unlikely for legacy encodings), we need to fetch + * more input text now. + */ + if (!utf8left) { + input_size = buf_size; + input = pipeline_peek (p, &input_size); + while (input_size < buf_size) { + size_t old_input_size = input_size; + input_size = buf_size; + input = pipeline_peek (p, &input_size); + if (input_size == old_input_size) + break; + } + } + } + + if (!to_utf8) + iconv_close (cd); + iconv_close (cd_utf8); + free (try_to_code); + + return ret; +} + +void manconv (pipeline *p, char * const *from, const char *to) +{ + char *pp_encoding; + char * const *try_from_code; + + pp_encoding = check_preprocessor_encoding (p); + if (pp_encoding) { + try_iconv (p, pp_encoding, to, 1); + free (pp_encoding); + } else { + for (try_from_code = from; *try_from_code; ++try_from_code) + if (try_iconv (p, *try_from_code, to, + !*(try_from_code + 1)) == 0) + break; + } +} + +#else /* !HAVE_ICONV */ + +/* If we don't have iconv, there isn't much we can do; just pass everything + * through unchanged. + */ +void manconv (pipeline *p, char * const *from ATTRIBUTE_UNUSED, + const char *to ATTRIBUTE_UNUSED) +{ + for (;;) { + size_t len = 4096; + const char *buffer = pipeline_read (p, &len); + if (len == 0) + break; + if (fwrite (buffer, 1, len, stdout) < len || ferror (stdout)) + error (FATAL, 0, _("can't write to standard output")); + } +} + +#endif /* HAVE_ICONV */ diff --git a/src/manconv.h b/src/manconv.h new file mode 100644 index 0000000..f252102 --- /dev/null +++ b/src/manconv.h @@ -0,0 +1,23 @@ +/* + * manconv.h: interface to converting manual page from one encoding to another + * + * Copyright (C) 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +void manconv (struct pipeline *p, char * const *from, const char *to); diff --git a/src/manconv_client.c b/src/manconv_client.c new file mode 100644 index 0000000..c150e01 --- /dev/null +++ b/src/manconv_client.c @@ -0,0 +1,147 @@ +/* + * manconv_client.c: use manconv in a pipeline + * + * Copyright (C) 2007, 2008, 2010 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "idpriv.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "pipeline.h" +#include "decompress.h" +#include "sandbox.h" +#include "security.h" + +#include "manconv.h" +#include "manconv_client.h" + +extern man_sandbox *sandbox; + +struct manconv_codes { + char **from; + char *to; +}; + +static void manconv_stdin (void *data) +{ + struct manconv_codes *codes = data; + pipeline *p; + + p = decompress_fdopen (dup (STDIN_FILENO)); + pipeline_start (p); + manconv (p, codes->from, codes->to); + pipeline_wait (p); + pipeline_free (p); +} + +static void manconv_pre_exec (void *data) +{ + /* We must drop privileges before loading the sandbox, since our + * seccomp filter doesn't allow setresuid and friends. + */ + drop_privs (NULL); + sandbox_load (data); +} + +static void free_manconv_codes (void *data) +{ + struct manconv_codes *codes = data; + char **try_from; + + for (try_from = codes->from; *try_from; ++try_from) + free (*try_from); + free (codes->from); + free (codes->to); + free (codes); +} + +void add_manconv (pipeline *p, const char *source, const char *target) +{ + struct manconv_codes *codes; + char *name; + pipecmd *cmd; + + if (STREQ (source, "UTF-8") && STREQ (target, "UTF-8")) + return; + + codes = xmalloc (sizeof *codes); + /* informational only; no shell quoting concerns */ + name = xasprintf ("%s -f ", MANCONV); + if (STREQ (source, "UTF-8")) { + codes->from = XNMALLOC (2, char *); + codes->from[0] = xstrdup (source); + codes->from[1] = NULL; + name = appendstr (name, source, (void *) 0); + } else { + codes->from = XNMALLOC (3, char *); + codes->from[0] = xstrdup ("UTF-8"); + codes->from[1] = xstrdup (source); + codes->from[2] = NULL; + name = appendstr (name, "UTF-8:", source, (void *) 0); + } + codes->to = xasprintf ("%s//IGNORE", target); + /* informational only; no shell quoting concerns */ + name = appendstr (name, " -t ", codes->to, (void *) 0); + if (quiet >= 2) + name = appendstr (name, " -q", (void *) 0); + + /* iconv_open may not work correctly in setuid processes; in GNU + * libc, gconv modules may be linked against other gconv modules and + * rely on RPATH $ORIGIN to load those modules from the correct + * path, but $ORIGIN is disabled in setuid processes. It is + * impossible to reset libc's idea of setuidness without creating a + * whole new process image. Therefore, if the calling process is + * setuid, we must drop privileges and execute manconv. + */ + if (running_setuid ()) { + char **from_code; + char *sources = NULL; + + cmd = pipecmd_new_args (MANCONV, "-f", (void *) 0); + for (from_code = codes->from; *from_code; ++from_code) { + sources = appendstr (sources, *from_code, (void *) 0); + if (*(from_code + 1)) + sources = appendstr (sources, ":", (void *) 0); + } + pipecmd_arg (cmd, sources); + free (sources); + pipecmd_args (cmd, "-t", codes->to, (void *) 0); + if (quiet >= 2) + pipecmd_arg (cmd, "-q"); + pipecmd_pre_exec (cmd, manconv_pre_exec, sandbox_free, + sandbox); + free_manconv_codes (codes); + } else { + cmd = pipecmd_new_function (name, &manconv_stdin, + &free_manconv_codes, codes); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, sandbox); + } + free (name); + pipeline_command (p, cmd); +} diff --git a/src/manconv_client.h b/src/manconv_client.h new file mode 100644 index 0000000..5380eef --- /dev/null +++ b/src/manconv_client.h @@ -0,0 +1,23 @@ +/* + * manconv_client.h: interface to using manconv in a pipeline + * + * Copyright (C) 2007 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +void add_manconv (struct pipeline *p, const char *source, const char *target); diff --git a/src/manconv_main.c b/src/manconv_main.c new file mode 100644 index 0000000..75c08ab --- /dev/null +++ b/src/manconv_main.c @@ -0,0 +1,182 @@ +/* + * manconv_main.c: convert manual page from one encoding to another + * + * Copyright (C) 2007, 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "argp.h" +#include "progname.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "error.h" +#include "pipeline.h" +#include "decompress.h" +#include "sandbox.h" + +#include "manconv.h" + +int quiet = 0; +man_sandbox *sandbox; + +static const char *from_codes; +static char *to_code; +static char **from_code; +static const char *filename; + +static char **split_codes (const char *codestr) +{ + char *codestrtok = xstrdup (codestr); + char *codestrtok_ptr = codestrtok; + char *tok; + size_t codearray_cur = 0, codearray_alloc = 0; + char **codearray = NULL; + + for (tok = strsep (&codestrtok_ptr, ":"); tok; + tok = strsep (&codestrtok_ptr, ":")) { + if (!*tok) + continue; /* ignore empty fields */ + if (codearray_cur >= codearray_alloc) + codearray = x2nrealloc + (codearray, + &codearray_alloc, sizeof *codearray); + codearray[codearray_cur++] = xstrdup (tok); + } + + if (codearray_cur >= codearray_alloc) + codearray = x2nrealloc (codearray, + &codearray_alloc, sizeof *codearray); + codearray[codearray_cur] = NULL; + + free (codestrtok); + + return codearray; +} + +const char *argp_program_version = "manconv " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("-f CODE[:...] -t CODE [FILENAME]"); + +static struct argp_option options[] = { + { "from-code", 'f', N_("CODE[:...]"), + 0, N_("possible encodings of original text") }, + { "to-code", 't', N_("CODE"), 0, N_("encoding for output") }, + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "quiet", 'q', 0, 0, N_("produce fewer warnings") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'f': + from_codes = arg; + return 0; + case 't': + to_code = xstrdup (arg); + if (!strstr (to_code, "//")) + to_code = appendstr (to_code, "//TRANSLIT", + (void *) 0); + return 0; + case 'd': + debug_level = 1; + return 0; + case 'q': + quiet = 1; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_ARG: + if (filename) + argp_usage (state); + filename = arg; + return 0; + case ARGP_KEY_SUCCESS: + if (!from_codes) + argp_error (state, + _("must specify an input " + "encoding")); + if (!to_code) + argp_error (state, + _("must specify an output " + "encoding")); + from_code = split_codes (from_codes); + if (!from_code || !*from_code) + argp_error (state, + _("must specify an input " + "encoding")); + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +int main (int argc, char *argv[]) +{ + pipeline *p; + char **try_from_code; + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + if (filename) { + p = decompress_open (filename); + if (!p) + error (FAIL, 0, _("can't open %s"), filename); + } else + p = decompress_fdopen (dup (STDIN_FILENO)); + pipeline_start (p); + + manconv (p, from_code, to_code); + + for (try_from_code = from_code; *try_from_code; ++try_from_code) + free (*try_from_code); + free (to_code); + free (from_code); + + pipeline_wait (p); + + return 0; +} diff --git a/src/mandb.c b/src/mandb.c new file mode 100644 index 0000000..90325d9 --- /dev/null +++ b/src/mandb.c @@ -0,0 +1,954 @@ +/* + * mandb.c: used to create and initialise global man database. + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, + * 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Tue Apr 26 12:56:44 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * CJW: Security fixes. Make --test work. Purge old database entries. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> /* for chmod() */ +#include <dirent.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> + +#ifdef MAN_OWNER +# include <pwd.h> +#endif /* MAN_OWNER */ + +#include "argp.h" +#include "dirname.h" +#include "progname.h" +#include "stat-time.h" +#include "timespec.h" +#include "utimens.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "error.h" +#include "cleanup.h" +#include "hashtable.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" + +#include "mydbm.h" + +#include "check_mandirs.h" +#include "filenames.h" +#include "manp.h" + +int quiet = 1; +extern int opt_test; /* don't update db */ +char *manp; +char *database = NULL; +extern char *extension; /* for globbing.c */ +extern int force_rescan; /* for check_mandirs.c */ +static char *single_filename = NULL; +extern char *user_config_file; /* for manp.c */ +#ifdef MAN_OWNER +struct passwd *man_owner; +#endif +man_sandbox *sandbox; + +static int purged = 0; +static int strays = 0; + +static int check_for_strays = 1; +static int purge = 1; +static int user; +static int create; +static const char *arg_manp; + +struct tried_catdirs_entry { + char *manpath; + int seen; +}; + +const char *argp_program_version = "mandb " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("[MANPATH]"); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "quiet", 'q', 0, 0, N_("work quietly, except for 'bogus' warning") }, + { "no-straycats", 's', 0, 0, N_("don't look for or add stray cats to the dbs") }, + { "no-purge", 'p', 0, 0, N_("don't purge obsolete entries from the dbs") }, + { "user-db", 'u', 0, 0, N_("produce user databases only") }, + { "create", 'c', 0, 0, N_("create dbs from scratch, rather than updating") }, + { "test", 't', 0, 0, N_("check manual pages for correctness") }, + { "filename", 'f', N_("FILENAME"), 0, N_("update just the entry for this filename") }, + { "config-file", 'C', N_("FILE"), 0, N_("use this user configuration file") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + static int quiet_temp = 0; + + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'q': + ++quiet_temp; + return 0; + case 's': + check_for_strays = 0; + return 0; + case 'p': + purge = 0; + return 0; + case 'u': + user = 1; + return 0; + case 'c': + create = 1; + purge = 0; + return 0; + case 't': + opt_test = 1; + return 0; + case 'f': + single_filename = arg; + create = 0; + purge = 0; + check_for_strays = 0; + return 0; + case 'C': + user_config_file = arg; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_ARG: + if (arg_manp) + argp_usage (state); + arg_manp = arg; + return 0; + case ARGP_KEY_SUCCESS: + if (opt_test && !debug_level) + quiet = 1; + else if (quiet_temp == 1) + quiet = 2; + else + quiet = quiet_temp; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +struct dbpaths { +#ifdef NDBM +# ifdef BERKELEY_DB + char *dbfile; + char *tmpdbfile; +# else /* !BERKELEY_DB NDBM */ + char *dirfile; + char *pagfile; + char *tmpdirfile; + char *tmppagfile; +# endif /* BERKELEY_DB */ +#else /* !NDBM */ + char *xfile; + char *xtmpfile; +#endif /* NDBM */ +}; + +#ifdef MAN_OWNER +extern uid_t ruid; +extern uid_t euid; +#endif /* MAN_OWNER */ + +static char *manpathlist[MAXDIRS]; + +extern int pages; + +/* remove() with error checking */ +static void check_remove (const char *path) +{ + if (remove (path) == -1 && errno != ENOENT) + error (0, errno, _("can't remove %s"), path); +} + +/* rename() with error checking */ +static void check_rename (const char *from, const char *to) +{ + if (rename (from, to) == -1 && errno != ENOENT) { + error (0, errno, _("can't rename %s to %s"), from, to); + check_remove (from); + } +} + +/* chmod() with error checking */ +static void check_chmod (const char *path, mode_t mode) +{ + if (chmod (path, mode) == -1) { + error (0, errno, _("can't chmod %s"), path); + check_remove (path); + } +} + +/* CPhipps 2000/02/24 - Copy a file. */ +static int xcopy (const char *from, const char *to) +{ + FILE *ifp, *ofp; + struct stat st; + struct timespec times[2]; + static const size_t buf_size = 32 * 1024; + char *buf; + int ret = 0; + + ifp = fopen (from, "r"); + if (!ifp) { + ret = -errno; + if (errno == ENOENT) + return 0; + error (0, errno, "fopen %s", from); + return ret; + } + + if (fstat (fileno (ifp), &st) >= 0) { + times[0] = get_stat_atime (&st); + times[1] = get_stat_mtime (&st); + } else { + times[0].tv_sec = 0; + times[0].tv_nsec = UTIME_OMIT; + times[1].tv_sec = 0; + times[1].tv_nsec = UTIME_OMIT; + } + + ofp = fopen (to, "w"); + if (!ofp) { + ret = -errno; + error (0, errno, "fopen %s", to); + fclose (ifp); + return ret; + } + + buf = xmalloc (buf_size); + while (!feof (ifp) && !ferror (ifp)) { + size_t in = fread (buf, 1, buf_size, ifp); + if (in > 0) { + if (fwrite (buf, 1, in, ofp) == 0 && ferror (ofp)) { + ret = -errno; + error (0, errno, _("can't write to %s"), to); + break; + } + } else if (ferror (ifp)) { + ret = -errno; + error (0, errno, _("can't read from %s"), from); + break; + } + } + free (buf); + + fclose (ifp); + fclose (ofp); + + if (ret < 0) + check_remove (to); + else { + check_chmod (to, DBMODE); + utimens (to, times); + } + + return ret; +} + +/* rename and chmod the database */ +static void finish_up (struct dbpaths *dbpaths) +{ +#ifdef NDBM +# ifdef BERKELEY_DB + check_rename (dbpaths->tmpdbfile, dbpaths->dbfile); + check_chmod (dbpaths->dbfile, DBMODE); + free (dbpaths->tmpdbfile); + dbpaths->tmpdbfile = NULL; +# else /* not BERKELEY_DB */ + check_rename (dbpaths->tmpdirfile, dbpaths->dirfile); + check_chmod (dbpaths->dirfile, DBMODE); + check_rename (dbpaths->tmppagfile, dbpaths->pagfile); + check_chmod (dbpaths->pagfile, DBMODE); + free (dbpaths->tmpdirfile); + free (dbpaths->tmppagfile); + dbpaths->tmpdirfile = dbpaths->tmppagfile = NULL; +# endif /* BERKELEY_DB */ +#else /* not NDBM */ + check_rename (dbpaths->xtmpfile, dbpaths->xfile); + check_chmod (dbpaths->xfile, DBMODE); + free (dbpaths->xtmpfile); + dbpaths->xtmpfile = NULL; +#endif /* NDBM */ +} + +#ifdef MAN_OWNER +/* change the owner of global man databases */ +static void do_chown (struct dbpaths *dbpaths) +{ +# ifdef NDBM +# ifdef BERKELEY_DB + chown_if_possible (dbpaths->dbfile); +# else /* not BERKELEY_DB */ + chown_if_possible (dbpaths->dirfile); + chown_if_possible (dbpaths->pagfile); +# endif /* BERKELEY_DB */ +# else /* not NDBM */ + chown_if_possible (dbpaths->xfile); +# endif /* NDBM */ +} +#endif /* MAN_OWNER */ + +/* Update a single file in an existing database. */ +static int update_one_file (const char *manpath, const char *filename) +{ + MYDBM_FILE dbf; + + dbf = MYDBM_RWOPEN (database); + if (dbf) { + struct mandata info; + char *manpage; + + memset (&info, 0, sizeof (struct mandata)); + manpage = filename_info (filename, &info, ""); + if (info.name) { + dbdelete (dbf, info.name, &info); + purge_pointers (dbf, info.name); + free (info.name); + } + free (manpage); + + test_manfile (dbf, filename, manpath); + } + MYDBM_CLOSE (dbf); + + return 1; +} + +/* dont actually create any dbs, just do an update */ +static int update_db_wrapper (const char *manpath, const char *catpath) +{ + int amount; + + if (single_filename) + return update_one_file (manpath, single_filename); + + amount = update_db (manpath, catpath); + if (amount != EOF) + return amount; + + return create_db (manpath, catpath); +} + +/* remove incomplete databases */ +static void cleanup_sigsafe (void *arg) +{ + struct dbpaths *dbpaths = arg; + +#ifdef NDBM +# ifdef BERKELEY_DB + if (dbpaths->tmpdbfile) + unlink (dbpaths->tmpdbfile); +# else /* !BERKELEY_DB NDBM */ + if (dbpaths->tmpdirfile) + unlink (dbpaths->tmpdirfile); + if (dbpaths->tmppagfile) + unlink (dbpaths->tmppagfile); +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + if (dbpaths->xtmpfile) + unlink (dbpaths->xtmpfile); +#endif /* NDBM */ +} + +/* free database names */ +static void cleanup (void *arg) +{ + struct dbpaths *dbpaths = arg; + +#ifdef NDBM +# ifdef BERKELEY_DB + free (dbpaths->dbfile); + free (dbpaths->tmpdbfile); + dbpaths->dbfile = dbpaths->tmpdbfile = NULL; +# else /* !BERKELEY_DB NDBM */ + free (dbpaths->dirfile); + free (dbpaths->pagfile); + free (dbpaths->tmpdirfile); + free (dbpaths->tmppagfile); + dbpaths->dirfile = dbpaths->pagfile = NULL; + dbpaths->tmpdirfile = dbpaths->tmppagfile = NULL; +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + free (dbpaths->xfile); + free (dbpaths->xtmpfile); + dbpaths->xfile = dbpaths->xtmpfile = NULL; +#endif /* NDBM */ + free (dbpaths); +} + +#define CACHEDIR_TAG \ + "Signature: 8a477f597d28d172789f06886806bc55\n" \ + "# This file is a cache directory tag created by man-db.\n" \ + "# For information about cache directory tags, see:\n" \ + "#\thttp://www.brynosaurus.com/cachedir/\n" + +/* sort out the database names */ +static int mandb (struct dbpaths *dbpaths, + const char *catpath, const char *manpath, int global_manpath) +{ + int ret, amount; + char *dbname; + int should_create; + + dbname = mkdbname (catpath); + database = xasprintf ("%s/%d", catpath, getpid ()); + + if (!quiet) + printf (_("Processing manual pages under %s...\n"), manpath); + + if (!STREQ (catpath, manpath)) { + char *cachedir_tag; + int fd; + int cachedir_tag_exists = 0; + + cachedir_tag = xasprintf ("%s/CACHEDIR.TAG", catpath); + fd = open (cachedir_tag, O_RDONLY); + if (fd < 0) { + FILE *cachedir_tag_file; + + if (errno != ENOENT) + check_remove (cachedir_tag); + cachedir_tag_file = fopen (cachedir_tag, "w"); + if (cachedir_tag_file) { + cachedir_tag_exists = 1; + fputs (CACHEDIR_TAG, cachedir_tag_file); + fclose (cachedir_tag_file); + } + } else { + cachedir_tag_exists = 1; + close (fd); + } + if (cachedir_tag_exists) { + if (global_manpath) + chown_if_possible (cachedir_tag); + check_chmod (cachedir_tag, DBMODE); + } + free (cachedir_tag); + } + + should_create = (create || force_rescan || opt_test); + +#ifdef NDBM +# ifdef BERKELEY_DB + dbpaths->dbfile = xasprintf ("%s.db", dbname); + free (dbname); + dbpaths->tmpdbfile = xasprintf ("%s.db", database); + if (!should_create) { + if (xcopy (dbpaths->dbfile, dbpaths->tmpdbfile) < 0) + should_create = 1; + } + if (should_create) { + check_remove (dbpaths->tmpdbfile); + ret = create_db (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } else { + ret = update_db_wrapper (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } +# else /* !BERKELEY_DB NDBM */ + dbpaths->dirfile = xasprintf ("%s.dir", dbname); + dbpaths->pagfile = xasprintf ("%s.pag", dbname); + free (dbname); + dbpaths->tmpdirfile = xasprintf ("%s.dir", database); + dbpaths->tmppagfile = xasprintf ("%s.pag", database); + if (!should_create) { + if (xcopy (dbpaths->dirfile, dbpaths->tmpdirfile) < 0 || + xcopy (dbpaths->pagfile, dbpaths->tmppagfile) < 0) + should_create = 1; + } + if (should_create) { + check_remove (dbpaths->tmpdirfile); + check_remove (dbpaths->tmppagfile); + ret = create_db (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } else { + ret = update_db_wrapper (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + dbpaths->xfile = dbname; /* steal memory */ + dbpaths->xtmpfile = xstrdup (database); + if (!should_create) { + if (xcopy (dbpaths->xfile, dbpaths->xtmpfile) < 0) + should_create = 1; + } + if (should_create) { + check_remove (dbpaths->xtmpfile); + ret = create_db (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } else { + ret = update_db_wrapper (manpath, catpath); + if (ret < 0) + return ret; + amount = ret; + } +#endif /* NDBM */ + + return amount; +} + +static int process_manpath (const char *manpath, int global_manpath, + struct hashtable *tried_catdirs) +{ + char *catpath; + struct tried_catdirs_entry *tried; + struct stat st; + int run_mandb = 0; + struct dbpaths *dbpaths = NULL; + int amount = 0; + + if (global_manpath) { /* system db */ + catpath = get_catpath (manpath, SYSTEM_CAT); + assert (catpath); + } else { /* user db */ + catpath = get_catpath (manpath, USER_CAT); + if (!catpath) + catpath = xstrdup (manpath); + } + tried = XMALLOC (struct tried_catdirs_entry); + tried->manpath = xstrdup (manpath); + tried->seen = 0; + hashtable_install (tried_catdirs, catpath, strlen (catpath), tried); + + if (stat (manpath, &st) < 0 || !S_ISDIR (st.st_mode)) + goto out; + tried->seen = 1; + + if (single_filename) { + /* The file might be in a per-locale subdirectory that we + * aren't processing right now. + */ + char *manpath_prefix = xasprintf ("%s/man", manpath); + if (STRNEQ (manpath_prefix, single_filename, + strlen (manpath_prefix))) + run_mandb = 1; + free (manpath_prefix); + } else + run_mandb = 1; + + force_rescan = 0; + if (purge) { + database = mkdbname (catpath); + purged += purge_missing (manpath, catpath, run_mandb); + free (database); + database = NULL; + } + + dbpaths = XZALLOC (struct dbpaths); + push_cleanup (cleanup, dbpaths, 0); + push_cleanup (cleanup_sigsafe, dbpaths, 1); + if (run_mandb) { + int ret = mandb (dbpaths, catpath, manpath, global_manpath); + if (ret < 0) { + amount = ret; + goto out; + } + amount += ret; + } + + if (!opt_test && amount) + finish_up (dbpaths); +#ifdef MAN_OWNER + if (global_manpath) + do_chown (dbpaths); +#endif /* MAN_OWNER */ + +out: + if (dbpaths) { + cleanup_sigsafe (dbpaths); + pop_cleanup (cleanup_sigsafe, dbpaths); + cleanup (dbpaths); + pop_cleanup (cleanup, dbpaths); + } + + free (database); + database = NULL; + + if (check_for_strays && amount > 0) { + database = mkdbname (catpath); + strays += straycats (manpath); + free (database); + database = NULL; + } + + free (catpath); + + return amount; +} + +static int is_lang_dir (const char *base) +{ + return strlen (base) >= 2 && + base[0] >= 'a' && base[0] <= 'z' && + base[1] >= 'a' && base[1] <= 'z' && + (!base[2] || base[2] < 'a' || base[2] > 'z'); +} + +static void tried_catdirs_free (void *defn) +{ + struct tried_catdirs_entry *tried = defn; + + free (tried->manpath); + free (tried); +} + +static void purge_catdir (const struct hashtable *tried_catdirs, + const char *path) +{ + struct stat st; + + if (stat (path, &st) == 0 && S_ISDIR (st.st_mode) && + !hashtable_lookup (tried_catdirs, path, strlen (path))) { + if (!quiet) + printf (_("Removing obsolete cat directory %s...\n"), + path); + remove_directory (path, 1); + } +} + +static void purge_catsubdirs (const char *manpath, const char *catpath) +{ + DIR *dir; + struct dirent *ent; + struct stat st; + + dir = opendir (catpath); + if (!dir) + return; + while ((ent = readdir (dir)) != NULL) { + char *mandir, *catdir; + + if (!STRNEQ (ent->d_name, "cat", 3)) + continue; + + mandir = xasprintf ("%s/man%s", manpath, ent->d_name + 3); + catdir = xasprintf ("%s/%s", catpath, ent->d_name); + + if (stat (mandir, &st) != 0 && errno == ENOENT) { + if (!quiet) + printf (_("Removing obsolete cat directory " + "%s...\n"), catdir); + remove_directory (catdir, 1); + } + + free (catdir); + free (mandir); + } + closedir (dir); +} + +/* Remove catdirs whose corresponding mandirs no longer exist. For safety, + * in case people set catdirs to silly locations, we only do this for the + * cat* and NLS subdirectories of catdirs, but not for the top-level catdir + * itself (which might contain other data, or which might be difficult for + * mandb to recreate with the proper permissions). + * + * We need to be careful here to avoid removing catdirs just because we + * happened not to inspect the corresponding mandir this time round. If a + * mandir was inspected and turned out not to exist, then its catdir is + * clearly fair game for removal of NLS subdirectories. These must match + * the usual NLS pattern (two lower-case letters followed by nothing or a + * non-letter). + */ +static void purge_catdirs (const struct hashtable *tried_catdirs) +{ + struct hashtable_iter *iter = NULL; + const struct nlist *elt; + + while ((elt = hashtable_iterate (tried_catdirs, &iter)) != NULL) { + const char *path = elt->name; + struct tried_catdirs_entry *tried = elt->defn; + char *base; + DIR *dir; + struct dirent *subdirent; + + base = base_name (path); + if (is_lang_dir (base)) { + /* expect to check this as a subdirectory later */ + free (base); + continue; + } + free (base); + + purge_catsubdirs (tried->manpath, path); + + dir = opendir (path); + if (!dir) + continue; + while ((subdirent = readdir (dir)) != NULL) { + char *subdirpath; + + if (STREQ (subdirent->d_name, ".") || + STREQ (subdirent->d_name, "..")) + continue; + if (STRNEQ (subdirent->d_name, "cat", 3)) + continue; + if (!is_lang_dir (subdirent->d_name)) + continue; + + subdirpath = xasprintf ("%s/%s", path, + subdirent->d_name); + + tried = hashtable_lookup (tried_catdirs, subdirpath, + strlen (subdirpath)); + if (tried && tried->seen) { + debug ("Seen mandir for %s; not deleting\n", + subdirpath); + /* However, we may still need to purge cat* + * subdirectories. + */ + purge_catsubdirs (tried->manpath, subdirpath); + } else + purge_catdir (tried_catdirs, subdirpath); + + free (subdirpath); + } + closedir (dir); + } +} + +int main (int argc, char *argv[]) +{ + char *sys_manp; + int amount = 0; + char **mp; + struct hashtable *tried_catdirs; +#ifdef SIGPIPE + struct sigaction sa; +#endif /* SIGPIPE */ + +#ifdef __profile__ + char *cwd; +#endif /* __profile__ */ + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + +#ifdef SIGPIPE + /* Reset SIGPIPE to its default disposition. Too many broken pieces + * of software (Python << 3.2, gnome-session, etc.) spawn child + * processes with SIGPIPE ignored, and this produces noise in cron + * mail. + */ + memset (&sa, 0, sizeof sa); + sa.sa_handler = SIG_DFL; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGPIPE, &sa, NULL); +#endif /* SIGPIPE */ + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + +#ifdef __profile__ + cwd = xgetcwd (); + if (!cwd) { + cwd = xmalloc (1); + cwd[0] = '\0'; + } +#endif /* __profile__ */ + + /* record who we are and drop effective privs for later use */ + init_security (); + +#ifdef MAN_OWNER + man_owner = get_man_owner (); + if (!user && euid != 0 && euid != man_owner->pw_uid) + user = 1; +#endif /* MAN_OWNER */ + + read_config_file (user); + + /* This is required for get_catpath(), regardless */ + manp = get_manpath (NULL); /* also calls read_config_file() */ + + /* pick up the system manpath or use the supplied one */ + if (arg_manp) { + free (manp); + manp = xstrdup (arg_manp); + } else if (!user) { + sys_manp = get_mandb_manpath (); + if (sys_manp) { + free (manp); + manp = sys_manp; + } else + error (0, 0, + _("warning: no MANDB_MAP directives in %s, " + "using your manpath"), + CONFIG_FILE); + } + + debug ("manpath=%s\n", manp); + + /* get the manpath as an array of pointers */ + create_pathlist (manp, manpathlist); + + /* finished manpath processing, regain privs */ + regain_effective_privs (); + + tried_catdirs = hashtable_create (tried_catdirs_free); + + for (mp = manpathlist; *mp; mp++) { + int global_manpath = is_global_mandir (*mp); + int ret; + DIR *dir; + struct dirent *subdirent; + + if (global_manpath) { /* system db */ + if (user) + continue; + } else { /* user db */ + drop_effective_privs (); + } + + ret = process_manpath (*mp, global_manpath, tried_catdirs); + if (ret < 0) + exit (FATAL); + amount += ret; + + dir = opendir (*mp); + if (!dir) { + error (0, errno, _("can't search directory %s"), *mp); + goto next_manpath; + } + + while ((subdirent = readdir (dir)) != NULL) { + char *subdirpath; + + /* Look for per-locale subdirectories. */ + if (STREQ (subdirent->d_name, ".") || + STREQ (subdirent->d_name, "..")) + continue; + if (STRNEQ (subdirent->d_name, "man", 3)) + continue; + + subdirpath = xasprintf ("%s/%s", *mp, + subdirent->d_name); + ret = process_manpath (subdirpath, global_manpath, + tried_catdirs); + if (ret < 0) + exit (FATAL); + amount += ret; + free (subdirpath); + } + + closedir (dir); + +next_manpath: + if (!global_manpath) + regain_effective_privs (); + + chkr_garbage_detector (); + } + + purge_catdirs (tried_catdirs); + hashtable_free (tried_catdirs); + + if (!quiet) { + printf (ngettext ("%d man subdirectory contained newer " + "manual pages.\n", + "%d man subdirectories contained newer " + "manual pages.\n", amount), + amount); + printf (ngettext ("%d manual page was added.\n", + "%d manual pages were added.\n", pages), + pages); + if (check_for_strays) + printf (ngettext ("%d stray cat was added.\n", + "%d stray cats were added.\n", + strays), + strays); + if (purge) + printf (ngettext ("%d old database entry was " + "purged.\n", + "%d old database entries were " + "purged.\n", purged), + purged); + } + +#ifdef __profile__ + /* For profiling */ + if (cwd[0]) + chdir (cwd); +#endif /* __profile__ */ + + free_pathlist (manpathlist); + free (manp); + if (create && !amount) { + const char *must_create; + if (!quiet) + fprintf (stderr, _("No databases created.")); + must_create = getenv ("MAN_MUST_CREATE"); + if (must_create && STREQ (must_create, "1")) + exit (FAIL); + } + exit (OK); +} diff --git a/src/manp.c b/src/manp.c new file mode 100644 index 0000000..5111be7 --- /dev/null +++ b/src/manp.c @@ -0,0 +1,1410 @@ +/* + * manp.c: Manpath calculations + * + * Copyright (C) 1990, 1991 John W. Eaton. + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, + * 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * John W. Eaton + * jwe@che.utexas.edu + * Department of Chemical Engineering + * The University of Texas at Austin + * Austin, Texas 78712 + * + * unpack_locale_bits is derived from _nl_explode_name in libintl: + * Copyright (C) 1995-1998, 2000-2001, 2003, 2005 Free Software Foundation, + * Inc. + * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. + * This was originally LGPL v2 or later, but I (Colin Watson) hereby + * exercise my option under section 3 of LGPL v2 to distribute it under the + * GPL v2 or later as above. + * + * Wed May 4 15:44:47 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk): changes + * to get_dirlist() and manpath(). + * + * This whole code segment is unfriendly and could do with a complete + * overhaul. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <assert.h> +#include <errno.h> +#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "canonicalize.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "cleanup.h" +#include "security.h" + +#include "manp.h" +#include "globbing.h" + +struct list { + char *key; + char *cont; + int flag; + struct list *next; +}; + +static struct list *namestore, *tailstore; + +#define SECTION_USER -6 +#define SECTION -5 +#define DEFINE_USER -4 +#define DEFINE -3 +#define MANDB_MAP_USER -2 +#define MANDB_MAP -1 +#define MANPATH_MAP 0 +#define MANDATORY 1 + +/* DIRLIST list[MAXDIRS]; */ +static char *tmplist[MAXDIRS]; + +char *user_config_file = NULL; +int disable_cache; +int min_cat_width = 80, max_cat_width = 80, cat_width = 0; + +static char *has_mandir (const char *p); +static char *fsstnd (const char *path); +static char *def_path (int flag); +static void add_dir_to_list (char **lp, const char *dir); +static char **add_dir_to_path_list (char **mphead, char **mp, const char *p); + + +static void add_to_list (const char *key, const char *cont, int flag) +{ + struct list *list = XMALLOC (struct list); + list->key = xstrdup (key); + list->cont = xstrdup (cont); + list->flag = flag; + list->next = NULL; + if (tailstore) + tailstore->next = list; + tailstore = list; + if (!namestore) + namestore = list; +} + +static const char *get_from_list (const char *key, int flag) +{ + struct list *list; + + for (list = namestore; list; list = list->next) + if (flag == list->flag && STREQ (key, list->key)) + return list->cont; + + return NULL; +} + +static struct list *iterate_over_list (struct list *prev, char *key, int flag) +{ + struct list *list; + + for (list = prev ? prev->next : namestore; list; list = list->next) + if (flag == list->flag && STREQ (key, list->key)) + return list; + + return NULL; +} + +/* Must not return DEFINEs set in ~/.manpath. This is used to fetch + * definitions used in raised-privilege code; if in doubt, be conservative! + * + * If not setuid, this is identical to get_def_user. + */ +const char *get_def (const char *thing, const char *def) +{ + const char *config_def; + + if (!running_setuid ()) + return get_def_user (thing, def); + + config_def = get_from_list (thing, DEFINE); + return config_def ? config_def : def; +} + +const char *get_def_user (const char *thing, const char *def) +{ + const char *config_def = get_from_list (thing, DEFINE_USER); + if (!config_def) + config_def = get_from_list (thing, DEFINE); + return config_def ? config_def : def; +} + +static void print_list (void) +{ + struct list *list; + + for (list = namestore; list; list = list->next) + debug ("`%s'\t`%s'\t`%d'\n", + list->key, list->cont, list->flag); +} + +static void add_sections (char *sections, int user) +{ + char *section_list = xstrdup (sections); + char *sect; + + for (sect = strtok (section_list, " "); sect; + sect = strtok (NULL, " ")) { + add_to_list (sect, "", user ? SECTION_USER : SECTION); + debug ("Added section `%s'.\n", sect); + } + free (section_list); +} + +const char **get_sections (void) +{ + struct list *list; + int length_user = 0, length = 0; + const char **sections, **sectionp; + int flag; + + for (list = namestore; list; list = list->next) { + if (list->flag == SECTION_USER) + length_user++; + else if (list->flag == SECTION) + length++; + } + if (length_user) { + sections = xnmalloc (length_user + 1, sizeof *sections); + flag = SECTION_USER; + } else { + sections = xnmalloc (length + 1, sizeof *sections); + flag = SECTION; + } + sectionp = sections; + for (list = namestore; list; list = list->next) + if (list->flag == flag) + *sectionp++ = list->key; + *sectionp = NULL; + return sections; +} + +static void add_def (char *thing, char *config_def, int flag, int user) +{ + add_to_list (thing, flag == 2 ? config_def : "", + user ? DEFINE_USER : DEFINE); + + debug ("Defined `%s' as `%s'.\n", thing, config_def); +} + +static void add_manpath_map (const char *path, const char *mandir) +{ + if (!path || !mandir) + return; + + add_to_list (path, mandir, MANPATH_MAP); + + debug ("Path `%s' mapped to mandir `%s'.\n", path, mandir); +} + +static void add_mandb_map (const char *mandir, const char *catdir, + int flag, int user) +{ + char *tmpcatdir; + + assert (flag > 0); + + if (!mandir) + return; + + if (flag == 1) + tmpcatdir = xstrdup (mandir); + else if (STREQ (catdir, "FSSTND")) + tmpcatdir = fsstnd (mandir); + else + tmpcatdir = xstrdup (catdir); + + if (!tmpcatdir) + return; + + add_to_list (mandir, tmpcatdir, user ? MANDB_MAP_USER : MANDB_MAP); + + debug ("%s mandir `%s', catdir `%s'.\n", + user ? "User" : "Global", mandir, tmpcatdir); + + free (tmpcatdir); +} + +static void add_mandatory (const char *mandir) +{ + if (!mandir) + return; + + add_to_list (mandir, "", MANDATORY); + + debug ("Mandatory mandir `%s'.\n", mandir); +} + +/* accept (NULL or oldpath) and new path component. return new path */ +static char *pathappend (char *oldpath, const char *appendage) +{ + assert ((!oldpath || *oldpath) && appendage); + /* Remove duplicates */ + if (oldpath) { + char *oldpathtok = xstrdup (oldpath), *tok; + char *app_dedup = xstrdup (appendage); + char *oldpathtok_ptr = oldpathtok; + for (tok = strsep (&oldpathtok_ptr, ":"); tok; + tok = strsep (&oldpathtok_ptr, ":")) { + char *search; + if (!*tok) /* ignore empty fields */ + continue; + search = strstr (app_dedup, tok); + while (search) { + char *terminator = search + strlen (tok); + if (!*terminator) { + /* End of the string, so chop here. */ + *search = 0; + while (search > app_dedup && + *--search == ':') + *search = 0; + break; + } else if (*terminator == ':') { + char *newapp; + *search = 0; + newapp = xasprintf ("%s%s", app_dedup, + terminator + 1); + free (app_dedup); + app_dedup = newapp; + } + search = strstr (terminator, tok); + } + } + free (oldpathtok); + if (!STREQ (appendage, app_dedup)) + debug ("%s:%s reduced to %s%s%s\n", + oldpath, appendage, + oldpath, *app_dedup ? ":" : "", app_dedup); + if (*app_dedup) + oldpath = appendstr (oldpath, ":", app_dedup, + (void *) 0); + free (app_dedup); + return oldpath; + } else + return xstrdup (appendage); +} + +static void gripe_reading_mp_config (const char *file) +{ + error (FAIL, 0, + _("can't make sense of the manpath configuration file %s"), + file); +} + +static void gripe_stat_file (const char *file) +{ + debug_error (_("warning: %s"), file); +} + +static void gripe_not_directory (const char *dir) +{ + if (!quiet) + error (0, 0, _("warning: %s isn't a directory"), dir); +} + +static void gripe_overlong_list (void) +{ + error (FAIL, 0, _("manpath list too long")); +} + +/* accept a manpath list, separated with ':', return the associated + catpath list */ +char *cat_manpath (char *manp) +{ + char *catp = NULL; + const char *path, *catdir; + + for (path = strsep (&manp, ":"); path; path = strsep (&manp, ":")) { + catdir = get_from_list (path, MANDB_MAP_USER); + if (!catdir) + catdir = get_from_list (path, MANDB_MAP); + catp = catdir ? pathappend (catp, catdir) + : pathappend (catp, path); + } + + return catp; +} + +/* Unpack a glibc-style locale into its component parts. + * + * This function was inspired by _nl_explode_name in libintl; I've rewritten + * it here with extensive modifications in order not to require libintl or + * glibc internals, because this API is more convenient for man-db, and to + * be consistent with surrounding style. I also dropped the normalised + * codeset handling, which we don't need here. + */ +void unpack_locale_bits (const char *locale, struct locale_bits *bits) +{ + const char *p, *start; + + bits->language = NULL; + bits->territory = NULL; + bits->codeset = NULL; + bits->modifier = NULL; + + /* Now we determine the single parts of the locale name. First look + * for the language. Termination symbols are '_', '.', and '@'. + */ + p = locale; + while (*p && *p != '_' && *p != '.' && *p != '@') + ++p; + if (p == locale) { + /* This does not make sense: language has to be specified. + * Use this entry as it is without exploding. Perhaps it is + * an alias. + */ + bits->language = xstrdup (locale); + goto out; + } + bits->language = xstrndup (locale, p - locale); + + if (*p == '_') { + /* Next is the territory. */ + start = ++p; + while (*p && *p != '.' && *p != '@') + ++p; + bits->territory = xstrndup (start, p - start); + } + + if (*p == '.') { + /* Next is the codeset. */ + start = ++p; + while (*p && *p != '@') + ++p; + bits->codeset = xstrndup (start, p - start); + } + + if (*p == '@') + /* Next is the modifier. */ + bits->modifier = xstrdup (++p); + +out: + if (!bits->territory) + bits->territory = xstrdup (""); + if (!bits->codeset) + bits->codeset = xstrdup (""); + if (!bits->modifier) + bits->modifier = xstrdup (""); +} + +/* Free the contents of a locale_bits structure populated by + * unpack_locale_bits. Does not free the pointer argument. + */ +void free_locale_bits (struct locale_bits *bits) +{ + free (bits->language); + free (bits->territory); + free (bits->codeset); + free (bits->modifier); +} + + +static char *get_nls_manpath (const char *manpathlist, const char *locale) +{ + struct locale_bits lbits; + char *manpath = NULL; + char *manpathlist_copy, *path, *manpathlist_ptr; + + unpack_locale_bits (locale, &lbits); + if (STREQ (lbits.language, "C") || STREQ (lbits.language, "POSIX")) { + free_locale_bits (&lbits); + return xstrdup (manpathlist); + } + + manpathlist_copy = xstrdup (manpathlist); + manpathlist_ptr = manpathlist_copy; + for (path = strsep (&manpathlist_ptr, ":"); path; + path = strsep (&manpathlist_ptr, ":")) { + DIR *mandir = opendir (path); + struct dirent *mandirent; + + if (!mandir) + continue; + + while ((mandirent = readdir (mandir)) != NULL) { + const char *name; + struct locale_bits mbits; + char *fullpath; + + name = mandirent->d_name; + if (STREQ (name, ".") || STREQ (name, "..")) + continue; + if (STRNEQ (name, "man", 3)) + continue; + fullpath = xasprintf ("%s/%s", path, name); + if (is_directory (fullpath) != 1) { + free (fullpath); + continue; + } + + unpack_locale_bits (name, &mbits); + if (STREQ (lbits.language, mbits.language) && + (!*mbits.territory || + STREQ (lbits.territory, mbits.territory)) && + (!*mbits.modifier || + STREQ (lbits.modifier, mbits.modifier))) + manpath = pathappend (manpath, fullpath); + free_locale_bits (&mbits); + free (fullpath); + } + + if (STREQ (lbits.language, "en")) + /* For English, we look in the subdirectories as + * above just in case there's something like + * en_GB.UTF-8, but it's more probable that English + * manual pages reside at the top level. + */ + manpath = pathappend (manpath, path); + + closedir (mandir); + } + free (manpathlist_copy); + + free_locale_bits (&lbits); + return manpath; +} + +char *add_nls_manpaths (const char *manpathlist, const char *locales) +{ + char *manpath = NULL; + char *locales_copy, *tok, *locales_ptr; + char *locale_manpath; + + debug ("add_nls_manpaths(): processing %s\n", manpathlist); + + if (locales == NULL || *locales == '\0') + return xstrdup (manpathlist); + + /* For each locale, we iterate over the manpath and find appropriate + * locale directories for each item. We then concatenate the results + * for all locales. In other words, LANGUAGE=fr:de and + * manpath=/usr/share/man:/usr/local/share/man could result in + * something like this list: + * + * /usr/share/man/fr + * /usr/local/share/man/fr + * /usr/share/man/de + * /usr/local/share/man/de + * /usr/share/man + * /usr/local/share/man + * + * This assumes that it's more important to have documentation in + * the preferred language than to have documentation for the correct + * object (in the case where there are different versions of a + * program in different hierarchies, for example). It is not + * entirely obvious that this is the right assumption, but on the + * other hand the other choice is not entirely obvious either. We + * tie-break on "we've always done it this way", and people can use + * 'man -a' or whatever in the occasional case where we get it + * wrong. + * + * We go to no special effort to de-duplicate directories here. + * create_pathlist will sort it out later; note that it preserves + * order in that it keeps the first of any duplicate set in its + * original position. + */ + + locales_copy = xstrdup (locales); + locales_ptr = locales_copy; + for (tok = strsep (&locales_ptr, ":"); tok; + tok = strsep (&locales_ptr, ":")) { + if (!*tok) /* ignore empty fields */ + continue; + debug ("checking for locale %s\n", tok); + + locale_manpath = get_nls_manpath (manpathlist, tok); + if (locale_manpath) { + if (manpath) + manpath = appendstr (manpath, ":", + locale_manpath, + (void *) 0); + else + manpath = xstrdup (locale_manpath); + free (locale_manpath); + } + } + free (locales_copy); + + /* Always try untranslated pages as a last resort. */ + locale_manpath = get_nls_manpath (manpathlist, "C"); + if (locale_manpath) { + if (manpath) + manpath = appendstr (manpath, ":", + locale_manpath, (void *) 0); + else + manpath = xstrdup (locale_manpath); + free (locale_manpath); + } + + return manpath; +} + +static char *add_system_manpath (const char *systems, const char *manpathlist) +{ + char *one_system; + char *manpath = NULL; + char *tmpsystems; + + if (!systems) + systems = getenv ("SYSTEM"); + + if (!systems || !*systems) + return xstrdup (manpathlist); + + /* Avoid breaking the environment. */ + tmpsystems = xstrdup (systems); + + /* For each systems component */ + + for (one_system = strtok (tmpsystems, ",:"); one_system; + one_system = strtok (NULL, ",:")) { + + /* For each manpathlist component */ + + if (!STREQ (one_system, "man")) { + const char *next, *path; + char *newdir = NULL; + for (path = manpathlist; path; path = next) { + int status; + char *element; + + next = strchr (path, ':'); + if (next) { + element = xstrndup (path, next - path); + ++next; + } else + element = xstrdup (path); + newdir = appendstr (newdir, element, "/", + one_system, (void *) 0); + free (element); + + status = is_directory (newdir); + + if (status == 0) + gripe_not_directory (newdir); + else if (status == 1) { + debug ("adding %s to manpathlist\n", + newdir); + manpath = pathappend (manpath, newdir); + } else + debug_error ("can't stat %s", newdir); + /* reset newdir */ + *newdir = '\0'; + } + free (newdir); + } else + manpath = pathappend (manpath, manpathlist); + } + free (tmpsystems); + + /* + * Thu, 21 Nov 1996 22:24:19 +0200 fpolacco@debian.org + * bug#5534 (man fails if env var SYSTEM is defined) + * with error [man: internal manpath equates to NULL] + * the reason: is_directory (newdir); returns -1 + */ + if (!manpath) { + debug ("add_system_manpath(): " + "internal manpath equates to NULL\n"); + return xstrdup (manpathlist); + } + return manpath; +} + +/* + * Always add system and locale directories to pathlist. + * If the environment variable MANPATH is set, return it. + * If the environment variable PATH is set and has a nonzero length, + * try to determine the corresponding manpath, otherwise, return the + * default manpath. + * + * The man_db.config file is used to map system wide /bin directories + * to top level man page directories. + * + * For directories which are in the user's path but not in the + * man_db.config file, see if there is a subdirectory `man' or `MAN'. + * If so, add that directory to the path. Example: user has + * $HOME/bin in his path and the directory $HOME/bin/man exists -- the + * directory $HOME/bin/man will be added to the manpath. + */ +static char *guess_manpath (const char *systems) +{ + const char *path = getenv ("PATH"); + char *manpathlist, *manpath; + + if (path == NULL || getenv ("MAN_TEST_DISABLE_PATH")) { + /* Things aren't going to work well, but hey... */ + if (path == NULL && !quiet) + error (0, 0, _("warning: $PATH not set")); + + manpathlist = def_path (MANDATORY); + } else { + if (strlen (path) == 0) { + /* Things aren't going to work well here either... */ + if (!quiet) + error (0, 0, _("warning: empty $PATH")); + + return add_system_manpath (systems, + def_path (MANDATORY)); + } + + manpathlist = get_manpath_from_path (path, 1); + } + manpath = add_system_manpath (systems, manpathlist); + free (manpathlist); + return manpath; +} + +char *get_manpath (const char *systems) +{ + char *manpathlist; + + /* need to read config file even if MANPATH set, for mandb(8) */ + read_config_file (0); + + manpathlist = getenv ("MANPATH"); + if (manpathlist && *manpathlist) { + char *system1, *system2, *guessed; + char *pos; + /* This must be it. */ + if (manpathlist[0] == ':') { + if (!quiet) + error (0, 0, + _("warning: $MANPATH set, " + "prepending %s"), + CONFIG_FILE); + system1 = add_system_manpath (systems, manpathlist); + guessed = guess_manpath (systems); + manpathlist = xasprintf ("%s%s", guessed, system1); + free (guessed); + free (system1); + } else if (manpathlist[strlen (manpathlist) - 1] == ':') { + if (!quiet) + error (0, 0, + _("warning: $MANPATH set, " + "appending %s"), + CONFIG_FILE); + system1 = add_system_manpath (systems, manpathlist); + guessed = guess_manpath (systems); + manpathlist = xasprintf ("%s%s", system1, guessed); + free (guessed); + free (system1); + } else if ((pos = strstr (manpathlist,"::"))) { + *(pos++) = '\0'; + if (!quiet) + error (0, 0, + _("warning: $MANPATH set, " + "inserting %s"), + CONFIG_FILE); + system1 = add_system_manpath (systems, manpathlist); + guessed = guess_manpath (systems); + system2 = add_system_manpath (systems, pos); + manpathlist = xasprintf ("%s:%s%s", system1, guessed, + system2); + free (system2); + free (guessed); + free (system1); + } else { + if (!quiet) + error (0, 0, + _("warning: $MANPATH set, ignoring %s"), + CONFIG_FILE); + manpathlist = add_system_manpath (systems, + manpathlist); + } + } else + manpathlist = guess_manpath (systems); + + return manpathlist; +} + +/* Parse the manpath.config file, extracting appropriate information. */ +static void add_to_dirlist (FILE *config, int user) +{ + char *bp; + char *buf = NULL; + size_t n = 0; + char key[512], cont[512]; + int val; + int c; + + while (getline (&buf, &n, config) >= 0) { + bp = buf; + + while (CTYPE (isspace, *bp)) + bp++; + + /* TODO: would like a (limited) replacement for sscanf() + * here that allocates its own memory. At that point check + * everything that sprintf()s manpath et al! + */ + if (*bp == '#' || *bp == '\0') + goto next; + else if (strncmp (bp, "NOCACHE", 7) == 0) + disable_cache = 1; + else if (strncmp (bp, "NO", 2) == 0) + goto next; /* match any word starting with NO */ + else if (sscanf (bp, "MANBIN %*s") == 1) + goto next; + else if (sscanf (bp, "MANDATORY_MANPATH %511s", key) == 1) + add_mandatory (key); + else if (sscanf (bp, "MANPATH_MAP %511s %511s", + key, cont) == 2) + add_manpath_map (key, cont); + else if ((c = sscanf (bp, "MANDB_MAP %511s %511s", + key, cont)) > 0) + add_mandb_map (key, cont, c, user); + else if ((c = sscanf (bp, "DEFINE %511s %511[^\n]", + key, cont)) > 0) + add_def (key, cont, c, user); + else if (sscanf (bp, "SECTION %511[^\n]", cont) == 1) + add_sections (cont, user); + else if (sscanf (bp, "SECTIONS %511[^\n]", cont) == 1) + /* Since I keep getting it wrong ... */ + add_sections (cont, user); + else if (sscanf (bp, "MINCATWIDTH %d", &val) == 1) + min_cat_width = val; + else if (sscanf (bp, "MAXCATWIDTH %d", &val) == 1) + max_cat_width = val; + else if (sscanf (bp, "CATWIDTH %d", &val) == 1) + cat_width = val; + else { + error (0, 0, _("can't parse directory list `%s'"), bp); + gripe_reading_mp_config (CONFIG_FILE); + } + +next: + free (buf); + buf = NULL; + } + + free (buf); +} + +static void free_config_file (void *unused ATTRIBUTE_UNUSED) +{ + struct list *list = namestore, *prev; + + while (list) { + free (list->key); + free (list->cont); + prev = list; + list = list->next; + free (prev); + } + + namestore = tailstore = NULL; +} + +void read_config_file (int optional) +{ + static int done = 0; + char *dotmanpath = NULL; + FILE *config; + + if (done) + return; + + push_cleanup (free_config_file, NULL, 0); + + if (user_config_file) + dotmanpath = xstrdup (user_config_file); + else { + char *home = getenv ("HOME"); + if (home) + dotmanpath = xasprintf ("%s/.manpath", home); + } + if (dotmanpath) { + config = fopen (dotmanpath, "r"); + if (config != NULL) { + debug ("From the config file %s:\n\n", dotmanpath); + add_to_dirlist (config, 1); + fclose (config); + } + free (dotmanpath); + } + + if (getenv ("MAN_TEST_DISABLE_SYSTEM_CONFIG") == NULL) { + config = fopen (CONFIG_FILE, "r"); + if (config == NULL) { + if (optional) + debug ("can't open %s; continuing anyway\n", + CONFIG_FILE); + else + error (FAIL, 0, + _("can't open the manpath " + "configuration file %s"), + CONFIG_FILE); + } else { + debug ("From the config file %s:\n\n", CONFIG_FILE); + + add_to_dirlist (config, 0); + fclose (config); + } + } + + print_list (); + + done = 1; +} + + +/* + * Construct the default manpath. This picks up mandatory manpaths + * only. + */ +static char *def_path (int flag) +{ + char *manpath = NULL; + struct list *list; + + for (list = namestore; list; list = list->next) + if (list->flag == flag) { + char **expanded_dirs; + int i; + + expanded_dirs = expand_path (list->key); + for (i = 0; expanded_dirs[i]; i++) { + int status = is_directory (expanded_dirs[i]); + + if (status < 0) + gripe_stat_file (expanded_dirs[i]); + else if (status == 0 && !quiet) + error (0, 0, + _("warning: mandatory " + "directory %s doesn't exist"), + expanded_dirs[i]); + else if (status == 1) + manpath = pathappend + (manpath, expanded_dirs[i]); + free (expanded_dirs[i]); + } + free (expanded_dirs); + } + + /* If we have complete config file failure... */ + if (!manpath) + return xstrdup ("/usr/man"); + + return manpath; +} + +/* + * If specified with configure, append OVERRIDE_DIR to dir param and add it + * to the lp list. + */ +static void insert_override_dir (char **lp, const char *dir) +{ + char *override_dir = NULL; + + if (!strlen (OVERRIDE_DIR)) + return; + + if ((override_dir = xasprintf ("%s/%s", dir, OVERRIDE_DIR))) { + add_dir_to_list (lp, override_dir); + free (override_dir); + } +} + +/* + * For each directory in the user's path, see if it is one of the + * directories listed in the man_db.config file. If so, and it is + * not already in the manpath, add it. If the directory is not listed + * in the man_db.config file, see if there is a subdirectory `../man' or + * `man', or, for FHS-compliance, `../share/man' or `share/man'. If so, + * and it is not already in the manpath, add it. + * Example: user has $HOME/bin in his path and the directory + * $HOME/man exists -- the directory $HOME/man will be added + * to the manpath. + */ +char *get_manpath_from_path (const char *path, int mandatory) +{ + int len; + char *tmppath; + char *t; + char *p; + char **lp; + char *end; + char *manpathlist; + struct list *list; + + tmppath = xstrdup (path); + + for (end = p = tmppath; end; p = end + 1) { + struct list *mandir_list; + + end = strchr (p, ':'); + if (end) + *end = '\0'; + + /* don't do this for current dir ("." or empty entry in PATH) */ + if (*p == '\0' || strcmp (p, ".") == 0) + continue; + + debug ("\npath directory %s ", p); + + mandir_list = iterate_over_list (NULL, p, MANPATH_MAP); + + /* + * The directory we're working on is in the config file. + * If we haven't added it to the list yet, do. + */ + + if (mandir_list) { + debug ("is in the config file\n"); + while (mandir_list) { + insert_override_dir (tmplist, + mandir_list->cont); + add_dir_to_list (tmplist, mandir_list->cont); + mandir_list = iterate_over_list + (mandir_list, p, MANPATH_MAP); + } + + /* The directory we're working on isn't in the config file. + See if it has ../man or man subdirectories. + If so, and it hasn't been added to the list, do. */ + + } else { + debug ("is not in the config file\n"); + + t = has_mandir (p); + if (t) { + debug ("but does have a ../man, man, " + "../share/man, or share/man " + "subdirectory\n"); + + insert_override_dir (tmplist, t); + add_dir_to_list (tmplist, t); + free (t); + } else + debug ("and doesn't have ../man, man, " + "../share/man, or share/man " + "subdirectories\n"); + } + } + + free (tmppath); + + if (mandatory) { + debug ("\nadding mandatory man directories\n\n"); + + for (list = namestore; list; list = list->next) + if (list->flag == MANDATORY) { + insert_override_dir (tmplist, list->key); + add_dir_to_list (tmplist, list->key); + } + } + + len = 0; + lp = tmplist; + while (*lp != NULL) { + len += strlen (*lp) + 1; + lp++; + } + + if (!len) + /* No path elements in configuration file or with + * appropriate subdirectories. + */ + return xstrdup (""); + + manpathlist = xmalloc (len); + *manpathlist = '\0'; + + lp = tmplist; + p = manpathlist; + while (*lp != NULL) { + len = strlen (*lp); + memcpy (p, *lp, len); + free (*lp); + *lp = NULL; + p += len; + *p++ = ':'; + lp++; + } + + p[-1] = '\0'; + + return manpathlist; +} + +/* Add a directory to the manpath list if it isn't already there. */ +static void add_expanded_dir_to_list (char **lp, const char *dir) +{ + int status; + int pos = 0; + + while (*lp != NULL) { + if (pos > MAXDIRS - 1) + gripe_overlong_list (); + if (!strcmp (*lp, dir)) { + debug ("%s is already in the manpath\n", dir); + return; + } + lp++; + pos++; + } + + /* Not found -- add it. */ + + status = is_directory (dir); + + if (status < 0) + gripe_stat_file (dir); + else if (status == 0) + gripe_not_directory (dir); + else if (status == 1) { + debug ("adding %s to manpath\n", dir); + + *lp = xstrdup (dir); + } +} + +/* + * Add a directory to the manpath list if it isn't already there, expanding + * wildcards. + */ +static void add_dir_to_list (char **lp, const char *dir) +{ + char **expanded_dirs; + int i; + + expanded_dirs = expand_path (dir); + for (i = 0; expanded_dirs[i]; i++) { + add_expanded_dir_to_list (lp, expanded_dirs[i]); + free (expanded_dirs[i]); + } + free (expanded_dirs); +} + +/* path does not exist in config file: check to see if path/../man, + path/man, path/../share/man, or path/share/man exist. If so return + it, if not return NULL. */ +static char *has_mandir (const char *path) +{ + char *newpath; + + /* don't assume anything about path, especially that it ends in + "bin" or even has a '/' in it! */ + + char *subdir = strrchr (path, '/'); + if (subdir) { + newpath = xasprintf ("%.*s/man", (int) (subdir - path), path); + if (is_directory (newpath) == 1) + return newpath; + free (newpath); + } + + newpath = xasprintf ("%s/man", path); + if (is_directory (newpath) == 1) + return newpath; + free (newpath); + + if (subdir) { + newpath = xasprintf ("%.*s/share/man", + (int) (subdir - path), path); + if (is_directory (newpath) == 1) + return newpath; + free (newpath); + } + + newpath = xasprintf ("%s/share/man", path); + if (is_directory (newpath) == 1) + return newpath; + free (newpath); + + return NULL; +} + +static char **add_dir_to_path_list (char **mphead, char **mp, const char *p) +{ + int status, i; + char *cwd, *d, **expanded_dirs; + + if (mp - mphead > MAXDIRS - 1) + gripe_overlong_list (); + + expanded_dirs = expand_path (p); + for (i = 0; expanded_dirs[i]; i++) { + d = expanded_dirs[i]; + + status = is_directory (d); + + if (status < 0) + gripe_stat_file (d); + else if (status == 0) + gripe_not_directory (d); + else { + /* deal with relative paths */ + if (*d != '/') { + cwd = xgetcwd (); + if (!cwd) + error (FATAL, errno, + _("can't determine current directory")); + *mp = appendstr (cwd, "/", d, (void *) 0); + } else + *mp = xstrdup (d); + + debug ("adding %s to manpathlist\n", *mp); + mp++; + } + free (d); + } + free (expanded_dirs); + + return mp; +} + +void create_pathlist (const char *manp, char **mp) +{ + const char *p, *end; + char **mphead = mp; + + /* Expand the manpath into a list for easier handling. */ + + for (p = manp;; p = end + 1) { + end = strchr (p, ':'); + if (end) { + char *element = xstrndup (p, end - p); + mp = add_dir_to_path_list (mphead, mp, element); + free (element); + } else { + mp = add_dir_to_path_list (mphead, mp, p); + break; + } + } + *mp = NULL; + + /* Eliminate duplicates due to symlinks. */ + mp = mphead; + while (*mp) { + char *target; + char **dupcheck; + int found_dup = 0; + + /* After resolving all symlinks, is the target also in the + * manpath? + */ + target = canonicalize_file_name (*mp); + if (!target) { + ++mp; + continue; + } + /* Only check up to the current list position, to keep item + * order stable across deduplication. + */ + for (dupcheck = mphead; *dupcheck && dupcheck != mp; + ++dupcheck) { + char *dupcheck_target = canonicalize_file_name + (*dupcheck); + if (!dupcheck_target) + continue; + if (!STREQ (target, dupcheck_target)) { + free (dupcheck_target); + continue; + } + free (dupcheck_target); + debug ("Removing duplicate manpath entry %s (%td) -> " + "%s (%td)\n", + *mp, mp - mphead, + *dupcheck, dupcheck - mphead); + free (*mp); + for (dupcheck = mp; *(dupcheck + 1); ++dupcheck) + *dupcheck = *(dupcheck + 1); + *dupcheck = NULL; + found_dup = 1; + break; + } + free (target); + if (!found_dup) + ++mp; + } + + if (debug_level) { + int first = 1; + + debug ("final search path = "); + for (mp = mphead; *mp; ++mp) { + if (first) { + debug ("%s", *mp); + first = 0; + } else + debug (":%s", *mp); + } + debug ("\n"); + } +} + +void free_pathlist (char **mp) +{ + while (*mp) { + free (*mp); + *mp++ = NULL; + } +} + +/* Routine to get list of named system and user manpaths (in reverse order). */ +char *get_mandb_manpath (void) +{ + char *manpath = NULL; + struct list *list; + + for (list = namestore; list; list = list->next) + if (list->flag == MANDB_MAP || list->flag == MANDB_MAP_USER) + manpath = pathappend (manpath, list->key); + + return manpath; +} + +/* Take manpath or manfile path as the first argument, and the type of + * catpaths we want as the other (system catpaths, user catpaths, or both). + * Return catdir mapping or NULL if it isn't a global/user mandir (as + * appropriate). + * + * This routine would seem to work correctly for nls subdirs and would + * specify the (correct) consistent catpath even if not defined in the + * config file. + * + * Do not return user catpaths when cattype == 0! This is used to decide + * whether to drop privileges. When cattype != 0 it's OK to return global + * catpaths. + */ +char *get_catpath (const char *name, int cattype) +{ + struct list *list; + + for (list = namestore; list; list = list->next) + if (((cattype & SYSTEM_CAT) && list->flag == MANDB_MAP) || + ((cattype & USER_CAT) && list->flag == MANDB_MAP_USER)) { + size_t manlen = strlen (list->key); + if (STRNEQ (name, list->key, manlen)) { + const char *suffix; + char *infix; + char *catpath = xstrdup (list->cont); + + /* For NLS subdirectories (e.g. + * /usr/share/man/de -> /var/cache/man/de), + * we need to find the second-last slash, as + * long as this strictly follows the key. + */ + suffix = strrchr (name, '/'); + if (!suffix) + return appendstr (catpath, + name + manlen, + (void *) 0); + + while (suffix > name + manlen) + if (*--suffix == '/') + break; + if (suffix < name + manlen) + suffix = name + manlen; + if (*suffix == '/') + ++suffix; + infix = xstrndup (name + manlen, + suffix - (name + manlen)); + catpath = appendstr (catpath, infix, + (void *) 0); + free (infix); + if (STRNEQ (suffix, "man", 3)) { + suffix += 3; + catpath = appendstr (catpath, "cat", + (void *) 0); + } + catpath = appendstr (catpath, suffix, + (void *) 0); + return catpath; + } + } + + return NULL; +} + +/* Check to see if the supplied man directory is a system-wide mandir. + * Obviously, user directories must not be included here. + */ +int is_global_mandir (const char *dir) +{ + struct list *list; + + for (list = namestore; list; list = list->next) + if (list->flag == MANDB_MAP && + STRNEQ (dir, list->key, strlen (list->key))) + return 1; + return 0; +} + +/* Accept a manpath (not a full pathname to a file) and return an FSSTND + equivalent catpath */ +static char *fsstnd (const char *path) +{ + char *manpath; + char *catpath; + char *element; + + if (strncmp (path, MAN_ROOT, sizeof MAN_ROOT - 1) != 0) { + if (!quiet) + error (0, 0, _("warning: %s does not begin with %s"), + path, MAN_ROOT); + return xstrdup (path); + } + /* get rid of initial "/usr" */ + path += sizeof MAN_ROOT - 1; + manpath = xstrdup (path); + catpath = xmalloc (strlen (path) + sizeof CAT_ROOT - 3); + + /* start with CAT_ROOT */ + (void) strcpy (catpath, CAT_ROOT); + + /* split up path into elements and deal with accordingly */ + for (element = strtok (manpath, "/"); element; + element = strtok (NULL, "/")) { + if (strncmp (element, "man", 3) == 0) { + if (*(element + 3)) { + *element = 'c'; + *(element + 2) = 't'; + } else + continue; + } + (void) strcat (catpath, "/"); + (void) strcat (catpath, element); + } + free (manpath); + return catpath; +} diff --git a/src/manp.h b/src/manp.h new file mode 100644 index 0000000..529bfa6 --- /dev/null +++ b/src/manp.h @@ -0,0 +1,47 @@ +/* + * manp.h: Interface to manpath calculations + * + * Copyright (C) 1990, 1991 John W. Eaton. + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +struct locale_bits { + char *language; + char *territory; + char *codeset; + char *modifier; +}; + +/* manp.c */ +extern char *cat_manpath (char *manp); +extern void unpack_locale_bits (const char *locale, struct locale_bits *bits); +extern void free_locale_bits (struct locale_bits *bits); +extern char *add_nls_manpaths (const char *manpathlist, const char *locales); +extern char *get_manpath (const char *systems); +extern char *get_manpath_from_path (const char *path, int mandatory); +extern void create_pathlist (const char *manp, char **mp); +extern void free_pathlist (char **mp); +extern char *get_mandb_manpath (void); +extern char *get_catpath (const char *name, int cattype); +extern int is_global_mandir (const char *dir); +extern void read_config_file (int optional); +extern const char *get_def (const char *thing, const char *def); +extern const char *get_def_user (const char *thing, const char *def); +extern const char **get_sections (void); diff --git a/src/manpath.c b/src/manpath.c new file mode 100644 index 0000000..de3a294 --- /dev/null +++ b/src/manpath.c @@ -0,0 +1,136 @@ +/* + * manpath.c: display either the manpath or catpath + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Thu Nov 17 08:29:39 GMT 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <limits.h> + +#include "argp.h" +#include "progname.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "error.h" +#include "sandbox.h" + +#include "manp.h" + +int quiet = 0; +man_sandbox *sandbox; /* unused, but needed by libman */ + +static int cat = 0; +static int global = 0; +static const char *alt_system = ""; +extern char *user_config_file; + +const char *argp_program_version = "manpath " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static struct argp_option options[] = { + { "catpath", 'c', 0, 0, N_("show relative catpaths") }, + { "global", 'g', 0, 0, N_("show the entire global manpath") }, + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "quiet", 'q', 0, 0, N_("produce fewer warnings") }, + { "config-file", 'C', N_("FILE"), 0, N_("use this user configuration file") }, + { "systems", 'm', N_("SYSTEM"), 0, N_("use manual pages from other systems") }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'c': + cat = 1; + return 0; + case 'g': + global = 1; + quiet = 1; + return 0; + case 'd': + debug_level = 1; + return 0; + case 'q': + quiet = 1; + return 0; + case 'C': + user_config_file = arg; + return 0; + case 'm': + alt_system = arg; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt }; + +/* + * Examine user's PATH and print a reasonable MANPATH. + */ +int main (int argc, char *argv[]) +{ + char *path_string; + + set_program_name (argv[0]); + + init_debug (); + init_locale (); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + path_string = get_manpath (alt_system); + + if (global) { + path_string = get_mandb_manpath (); + if (!path_string) + error (FAIL, 0, + _("warning: no global manpaths set in " + "config file %s"), + CONFIG_FILE); + } + if (cat) + path_string = cat_manpath (path_string); + + printf ("%s\n", path_string); + exit (OK); +} diff --git a/src/straycats.c b/src/straycats.c new file mode 100644 index 0000000..51f6617 --- /dev/null +++ b/src/straycats.c @@ -0,0 +1,391 @@ +/* + * straycats.c: find and process stray cat files + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2010, 2011 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Tue May 3 21:24:51 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> + +#include "canonicalize.h" +#include "dirname.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "decompress.h" +#include "encodings.h" +#include "orderfiles.h" +#include "sandbox.h" +#include "security.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "descriptions.h" +#include "manp.h" +#include "manconv_client.h" +#include "ult_src.h" + +extern man_sandbox *sandbox; + +static char *catdir, *mandir; + +static int check_for_stray (MYDBM_FILE dbf) +{ + DIR *cdir; + struct dirent *catlist; + char **names; + size_t names_len, names_max, i; + size_t lenman, lencat; + int strays = 0; + + cdir = opendir (catdir); + if (!cdir) { + error (0, errno, _("can't search directory %s"), catdir); + return 0; + } + + names_len = 0; + names_max = 1024; + names = XNMALLOC (names_max, char *); + + while ((catlist = readdir (cdir)) != NULL) { + if (*catlist->d_name == '.' && + strlen (catlist->d_name) < (size_t) 3) + continue; + if (names_len >= names_max) { + names_max *= 2; + names = xnrealloc (names, names_max, sizeof (char *)); + } + names[names_len++] = xstrdup (catlist->d_name); + } + closedir (cdir); + + order_files (catdir, names, names_len); + + mandir = appendstr (mandir, "/", (void *) 0); + catdir = appendstr (catdir, "/", (void *) 0); + lenman = strlen (mandir); + lencat = strlen (catdir); + + for (i = 0; i < names_len; ++i) { + struct mandata info; + char *ext, *section; + short found; + struct stat buf; +#ifdef COMP_SRC + struct compression *comp; +#endif + + memset (&info, 0, sizeof (struct mandata)); + + *(mandir + lenman) = *(catdir + lencat) = '\0'; + mandir = appendstr (mandir, names[i], (void *) 0); + catdir = appendstr (catdir, names[i], (void *) 0); + + ext = strrchr (mandir, '.'); + if (!ext) { + if (quiet < 2) + error (0, 0, + _("warning: %s: " + "ignoring bogus filename"), + catdir); + goto next_name; + +#if defined(COMP_SRC) || defined(COMP_CAT) + +# if defined(COMP_SRC) + } else if (comp_info (ext, 0)) { +# elif defined(COMP_CAT) + } else if (strcmp (ext + 1, COMPRESS_EXT) == 0) { +# endif /* COMP_* */ + *ext = '\0'; + info.comp = ext + 1; +#endif /* COMP_SRC || COMP_CAT */ + + } else + info.comp = NULL; + + ext = strrchr (mandir, '.'); + *(mandir + lenman - 1) = '\0'; + section = xstrdup (strrchr (mandir, '/') + 4); + *(mandir + lenman - 1) = '/'; + + /* check for bogosity */ + + if (!ext || strncmp (ext + 1, section, strlen (section)) != 0) { + if (quiet < 2) + error (0, 0, + _("warning: %s: " + "ignoring bogus filename"), + catdir); + goto next_section; + } + + /* + * now that we've stripped off the cat compression + * extension (if it has one), we can try some of ours. + */ + + debug ("Testing for existence: %s\n", mandir); + + if (stat (mandir, &buf) == 0) + found = 1; +#ifdef COMP_SRC + else if ((comp = comp_file (mandir))) { + found = 1; + free (comp->stem); + } +#endif + else + found = 0; + + if (!found) { + pipeline *decomp; + struct mandata *exists; + lexgrog lg; + char *lang, *page_encoding; + char *mandir_base; + pipecmd *col_cmd; + char *col_locale; + char *fullpath; + + /* we have a straycat. Need to filter it and get + its whatis (if necessary) */ + + lg.whatis = 0; + *(ext++) = '\0'; + info.ext = ext; + + /* see if we already have it, before going any + further */ + mandir_base = base_name (mandir); + exists = dblookup_exact (dbf, mandir_base, info.ext, + 1); +#ifndef FAVOUR_STRAYCATS + if (exists && exists->id != WHATIS_CAT) +#else /* FAVOUR_STRAYCATS */ + if (exists && exists->id != WHATIS_CAT && + exists->id != WHATIS_MAN) +#endif /* !FAVOUR_STRAYCATS */ + goto next_exists; + debug ("%s(%s) is not in the db.\n", + mandir_base, info.ext); + + /* fill in the missing parts of the structure */ + info.name = NULL; + info.sec = section; + info.id = STRAY_CAT; + info.pointer = NULL; + info.filter = "-"; + info.mtime.tv_sec = 0; + info.mtime.tv_nsec = 0; + + drop_effective_privs (); + decomp = decompress_open (catdir); + regain_effective_privs (); + if (!decomp) { + error (0, errno, _("can't open %s"), catdir); + goto next_exists; + } + + lang = lang_dir (mandir); + page_encoding = get_page_encoding (lang); + if (page_encoding) + add_manconv (decomp, page_encoding, "UTF-8"); + free (page_encoding); + free (lang); + + col_cmd = pipecmd_new_argstr + (get_def_user ("col", COL)); + pipecmd_arg (col_cmd, "-bx"); + col_locale = find_charset_locale ("UTF-8"); + if (col_locale) { + pipecmd_setenv (col_cmd, "LC_CTYPE", + col_locale); + free (col_locale); + } + pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (decomp, col_cmd); + + fullpath = canonicalize_file_name (catdir); + if (!fullpath) { + if (quiet < 2) { + if (errno == ENOENT) + error (0, 0, _("warning: %s is a dangling symlink"), fullpath); + else + error (0, errno, + _("can't resolve %s"), + catdir); + } + } else { + char *catdir_base; + + free (fullpath); + drop_effective_privs (); + pipeline_start (decomp); + regain_effective_privs (); + + strays++; + + lg.type = CATPAGE; + catdir_base = base_name (catdir); + if (find_name_decompressed (decomp, + catdir_base, + &lg)) { + struct page_description *descs; + strays++; + descs = parse_descriptions + (mandir_base, lg.whatis); + if (descs) { + store_descriptions + (dbf, descs, &info, + NULL, mandir_base, + NULL); + free_descriptions (descs); + } + } else if (quiet < 2) + error (0, 0, _("warning: %s: whatis parse for %s(%s) failed"), + catdir, mandir_base, info.sec); + free (catdir_base); + } + + free (lg.whatis); + pipeline_free (decomp); +next_exists: + free_mandata_struct (exists); + free (mandir_base); + } +next_section: + free (section); +next_name: + free (names[i]); + } + free (names); + return strays; +} + +static int open_catdir (MYDBM_FILE dbf) +{ + DIR *cdir; + struct dirent *catlist; + size_t catlen, manlen; + int strays = 0; + + cdir = opendir (catdir); + if (!cdir) { + error (0, errno, _("can't search directory %s"), catdir); + return 0; + } + + if (!quiet) + printf (_("Checking for stray cats under %s...\n"), catdir); + + catdir = appendstr (catdir, "/", (void *) 0); + mandir = appendstr (mandir, "/", (void *) 0); + catlen = strlen (catdir); + manlen = strlen (mandir); + + /* should make this case insensitive */ + while ((catlist = readdir (cdir))) { + char *t1; + + if (strncmp (catlist->d_name, "cat", 3) != 0) + continue; + + catdir = appendstr (catdir, catlist->d_name, (void *) 0); + mandir = appendstr (mandir, catlist->d_name, (void *) 0); + + *(t1 = mandir + manlen) = 'm'; + *(t1 + 2) = 'n'; + + strays += check_for_stray (dbf); + + *(catdir + catlen) = *(mandir + manlen) = '\0'; + } + closedir (cdir); + return strays; +} + +int straycats (const char *manpath) +{ + MYDBM_FILE dbf; + char *catpath; + int strays; + + dbf = MYDBM_RWOPEN (database); + if (dbf && dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + } + if (!dbf) { + error (0, errno, _("warning: can't update index cache %s"), + database); + return 0; + } + + catpath = get_catpath (manpath, SYSTEM_CAT | USER_CAT); + + /* look in the usual catpath location */ + mandir = xstrdup (manpath); + catdir = xstrdup (manpath); + strays = open_catdir (dbf); + + /* look in the alternate catpath location if we have one + and it's different from the usual catpath */ + + if (catpath) + debug ("catpath: %s, manpath: %s\n", catpath, manpath); + + if (catpath && strcmp (catpath, manpath) != 0) { + *mandir = *catdir = '\0'; + mandir = appendstr (mandir, manpath, (void *) 0); + catdir = appendstr (catdir, catpath, (void *) 0); + strays += open_catdir (dbf); + } + + free (mandir); + free (catdir); + + free (catpath); + + MYDBM_CLOSE (dbf); + return strays; +} diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..3d11394 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,50 @@ +## Process this file with automake to produce Makefile.in +## +## Copyright (C) 2009, 2010, 2011 Colin Watson. +## +## This file is part of man-db. +## +## man-db 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 2 of the License, or +## (at your option) any later version. +## +## man-db 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 man-db; if not, write to the Free Software Foundation, +## Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +TESTS_ENVIRONMENT = PATH=$(abs_builddir)/..:$$PATH; export PATH; \ + DBTYPE=$(DBTYPE); export DBTYPE; \ + MANDIR_LAYOUT=$(MANDIR_LAYOUT); export MANDIR_LAYOUT; \ + abs_top_builddir=$(abs_top_builddir); export abs_top_builddir; \ + OVERRIDE_DIR="$(override_dir)"; export OVERRIDE_DIR; +# Each test must use the configure-detected shell, not necessarily /bin/sh. +AM_LOG_FLAGS = $(SHELL) +ALL_TESTS = \ + lexgrog-1 lexgrog-2 lexgrog-3 \ + man-1 man-2 man-3 man-4 man-5 man-6 man-7 man-8 man-9 man-10 man-11 \ + manconv-1 manconv-2 manconv-3 \ + mandb-1 mandb-2 mandb-3 mandb-4 mandb-5 mandb-6 mandb-7 \ + whatis-1 \ + zsoelim-1 +if !CROSS_COMPILING +TESTS = $(ALL_TESTS) +endif + +AM_CPPFLAGS = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib +AM_CFLAGS = $(WARN_CFLAGS) +check_PROGRAMS = fspause +fspause_SOURCES = fspause.c +fspause_LDADD = \ + $(top_builddir)/gl/lib/libgnu.la \ + $(LIB_NANOSLEEP) + +dist_check_SCRIPTS = testlib.sh $(ALL_TESTS) diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in new file mode 100644 index 0000000..3c56222 --- /dev/null +++ b/src/tests/Makefile.in @@ -0,0 +1,2283 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +check_PROGRAMS = fspause$(EXEEXT) +subdir = src/tests +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/man-arg-automatic-create.m4 \ + $(top_srcdir)/m4/man-arg-automatic-update.m4 \ + $(top_srcdir)/m4/man-arg-cache-owner.m4 \ + $(top_srcdir)/m4/man-arg-cats.m4 \ + $(top_srcdir)/m4/man-arg-config-file.m4 \ + $(top_srcdir)/m4/man-arg-db.m4 \ + $(top_srcdir)/m4/man-arg-device.m4 \ + $(top_srcdir)/m4/man-arg-mandirs.m4 \ + $(top_srcdir)/m4/man-arg-override-dir.m4 \ + $(top_srcdir)/m4/man-arg-sections.m4 \ + $(top_srcdir)/m4/man-arg-setuid.m4 \ + $(top_srcdir)/m4/man-arg-systemdsystemunitdir.m4 \ + $(top_srcdir)/m4/man-arg-systemdtmpfilesdir.m4 \ + $(top_srcdir)/m4/man-arg-undoc.m4 $(top_srcdir)/m4/man-bdb.m4 \ + $(top_srcdir)/m4/man-check-progs.m4 \ + $(top_srcdir)/m4/man-compress-lib.m4 \ + $(top_srcdir)/m4/man-gnu-nroff.m4 \ + $(top_srcdir)/m4/man-heirloom-nroff.m4 \ + $(top_srcdir)/m4/man-libseccomp.m4 \ + $(top_srcdir)/m4/man-linguas.m4 $(top_srcdir)/m4/man-po4a.m4 \ + $(top_srcdir)/m4/man-tar-sort-name.m4 \ + $(top_srcdir)/m4/man-trans-subst.m4 \ + $(top_srcdir)/gl/m4/00gnulib.m4 \ + $(top_srcdir)/gl/m4/__inline.m4 \ + $(top_srcdir)/gl/m4/absolute-header.m4 \ + $(top_srcdir)/gl/m4/alloca.m4 $(top_srcdir)/gl/m4/argp.m4 \ + $(top_srcdir)/gl/m4/asm-underscore.m4 \ + $(top_srcdir)/gl/m4/btowc.m4 \ + $(top_srcdir)/gl/m4/builtin-expect.m4 \ + $(top_srcdir)/gl/m4/canonicalize.m4 \ + $(top_srcdir)/gl/m4/chdir-long.m4 \ + $(top_srcdir)/gl/m4/clock_time.m4 $(top_srcdir)/gl/m4/close.m4 \ + $(top_srcdir)/gl/m4/closedir.m4 $(top_srcdir)/gl/m4/codeset.m4 \ + $(top_srcdir)/gl/m4/d-ino.m4 $(top_srcdir)/gl/m4/d-type.m4 \ + $(top_srcdir)/gl/m4/dirent_h.m4 $(top_srcdir)/gl/m4/dirfd.m4 \ + $(top_srcdir)/gl/m4/dirname.m4 \ + $(top_srcdir)/gl/m4/double-slash-root.m4 \ + $(top_srcdir)/gl/m4/dup.m4 $(top_srcdir)/gl/m4/dup2.m4 \ + $(top_srcdir)/gl/m4/eealloc.m4 $(top_srcdir)/gl/m4/environ.m4 \ + $(top_srcdir)/gl/m4/errno_h.m4 $(top_srcdir)/gl/m4/error.m4 \ + $(top_srcdir)/gl/m4/exponentd.m4 \ + $(top_srcdir)/gl/m4/extensions.m4 \ + $(top_srcdir)/gl/m4/extern-inline.m4 \ + $(top_srcdir)/gl/m4/fchdir.m4 $(top_srcdir)/gl/m4/fcntl-o.m4 \ + $(top_srcdir)/gl/m4/fcntl.m4 $(top_srcdir)/gl/m4/fcntl_h.m4 \ + $(top_srcdir)/gl/m4/fdopendir.m4 \ + $(top_srcdir)/gl/m4/filenamecat.m4 \ + $(top_srcdir)/gl/m4/flexmember.m4 \ + $(top_srcdir)/gl/m4/float_h.m4 $(top_srcdir)/gl/m4/flock.m4 \ + $(top_srcdir)/gl/m4/fnmatch.m4 \ + $(top_srcdir)/gl/m4/fnmatch_h.m4 $(top_srcdir)/gl/m4/fstat.m4 \ + $(top_srcdir)/gl/m4/fstatat.m4 $(top_srcdir)/gl/m4/futimens.m4 \ + $(top_srcdir)/gl/m4/getcwd-abort-bug.m4 \ + $(top_srcdir)/gl/m4/getcwd-path-max.m4 \ + $(top_srcdir)/gl/m4/getcwd.m4 $(top_srcdir)/gl/m4/getdelim.m4 \ + $(top_srcdir)/gl/m4/getdtablesize.m4 \ + $(top_srcdir)/gl/m4/getline.m4 $(top_srcdir)/gl/m4/getlogin.m4 \ + $(top_srcdir)/gl/m4/getlogin_r.m4 \ + $(top_srcdir)/gl/m4/getopt.m4 \ + $(top_srcdir)/gl/m4/getpagesize.m4 \ + $(top_srcdir)/gl/m4/getprogname.m4 \ + $(top_srcdir)/gl/m4/gettext.m4 $(top_srcdir)/gl/m4/gettime.m4 \ + $(top_srcdir)/gl/m4/gettimeofday.m4 \ + $(top_srcdir)/gl/m4/glibc21.m4 $(top_srcdir)/gl/m4/glob.m4 \ + $(top_srcdir)/gl/m4/glob_h.m4 \ + $(top_srcdir)/gl/m4/gnulib-common.m4 \ + $(top_srcdir)/gl/m4/gnulib-comp.m4 \ + $(top_srcdir)/gl/m4/host-cpu-c-abi.m4 \ + $(top_srcdir)/gl/m4/iconv.m4 $(top_srcdir)/gl/m4/idpriv.m4 \ + $(top_srcdir)/gl/m4/include_next.m4 \ + $(top_srcdir)/gl/m4/intlmacosx.m4 \ + $(top_srcdir)/gl/m4/intmax_t.m4 \ + $(top_srcdir)/gl/m4/inttypes_h.m4 $(top_srcdir)/gl/m4/ioctl.m4 \ + $(top_srcdir)/gl/m4/langinfo_h.m4 \ + $(top_srcdir)/gl/m4/largefile.m4 \ + $(top_srcdir)/gl/m4/lib-ignore.m4 \ + $(top_srcdir)/gl/m4/lib-ld.m4 $(top_srcdir)/gl/m4/lib-link.m4 \ + $(top_srcdir)/gl/m4/lib-prefix.m4 \ + $(top_srcdir)/gl/m4/libtool.m4 $(top_srcdir)/gl/m4/limits-h.m4 \ + $(top_srcdir)/gl/m4/localcharset.m4 \ + $(top_srcdir)/gl/m4/locale-fr.m4 \ + $(top_srcdir)/gl/m4/locale-ja.m4 \ + $(top_srcdir)/gl/m4/locale-zh.m4 \ + $(top_srcdir)/gl/m4/locale_h.m4 \ + $(top_srcdir)/gl/m4/localeconv.m4 \ + $(top_srcdir)/gl/m4/localtime-buffer.m4 \ + $(top_srcdir)/gl/m4/lock.m4 $(top_srcdir)/gl/m4/longlong.m4 \ + $(top_srcdir)/gl/m4/lstat.m4 $(top_srcdir)/gl/m4/ltoptions.m4 \ + $(top_srcdir)/gl/m4/ltsugar.m4 \ + $(top_srcdir)/gl/m4/ltversion.m4 \ + $(top_srcdir)/gl/m4/lt~obsolete.m4 \ + $(top_srcdir)/gl/m4/malloc.m4 $(top_srcdir)/gl/m4/malloca.m4 \ + $(top_srcdir)/gl/m4/mbrtowc.m4 $(top_srcdir)/gl/m4/mbsinit.m4 \ + $(top_srcdir)/gl/m4/mbsrtowcs.m4 \ + $(top_srcdir)/gl/m4/mbstate_t.m4 $(top_srcdir)/gl/m4/mbtowc.m4 \ + $(top_srcdir)/gl/m4/memchr.m4 $(top_srcdir)/gl/m4/memmem.m4 \ + $(top_srcdir)/gl/m4/mempcpy.m4 $(top_srcdir)/gl/m4/memrchr.m4 \ + $(top_srcdir)/gl/m4/minmax.m4 $(top_srcdir)/gl/m4/mkdir.m4 \ + $(top_srcdir)/gl/m4/mkdtemp.m4 $(top_srcdir)/gl/m4/mkstemp.m4 \ + $(top_srcdir)/gl/m4/mmap-anon.m4 $(top_srcdir)/gl/m4/mode_t.m4 \ + $(top_srcdir)/gl/m4/msvc-inval.m4 \ + $(top_srcdir)/gl/m4/msvc-nothrow.m4 \ + $(top_srcdir)/gl/m4/multiarch.m4 \ + $(top_srcdir)/gl/m4/nanosleep.m4 \ + $(top_srcdir)/gl/m4/nl_langinfo.m4 $(top_srcdir)/gl/m4/nls.m4 \ + $(top_srcdir)/gl/m4/nocrash.m4 \ + $(top_srcdir)/gl/m4/nonblocking.m4 \ + $(top_srcdir)/gl/m4/off_t.m4 \ + $(top_srcdir)/gl/m4/open-cloexec.m4 \ + $(top_srcdir)/gl/m4/open.m4 $(top_srcdir)/gl/m4/openat.m4 \ + $(top_srcdir)/gl/m4/opendir.m4 $(top_srcdir)/gl/m4/pathmax.m4 \ + $(top_srcdir)/gl/m4/po.m4 $(top_srcdir)/gl/m4/printf.m4 \ + $(top_srcdir)/gl/m4/progtest.m4 \ + $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \ + $(top_srcdir)/gl/m4/raise.m4 $(top_srcdir)/gl/m4/rawmemchr.m4 \ + $(top_srcdir)/gl/m4/readdir.m4 $(top_srcdir)/gl/m4/readlink.m4 \ + $(top_srcdir)/gl/m4/realloc.m4 $(top_srcdir)/gl/m4/regex.m4 \ + $(top_srcdir)/gl/m4/rename.m4 $(top_srcdir)/gl/m4/rewinddir.m4 \ + $(top_srcdir)/gl/m4/rmdir.m4 $(top_srcdir)/gl/m4/same.m4 \ + $(top_srcdir)/gl/m4/save-cwd.m4 $(top_srcdir)/gl/m4/select.m4 \ + $(top_srcdir)/gl/m4/setenv.m4 $(top_srcdir)/gl/m4/sigaction.m4 \ + $(top_srcdir)/gl/m4/signal_h.m4 \ + $(top_srcdir)/gl/m4/signalblocking.m4 \ + $(top_srcdir)/gl/m4/size_max.m4 $(top_srcdir)/gl/m4/sleep.m4 \ + $(top_srcdir)/gl/m4/socketlib.m4 \ + $(top_srcdir)/gl/m4/sockets.m4 $(top_srcdir)/gl/m4/socklen.m4 \ + $(top_srcdir)/gl/m4/ssize_t.m4 \ + $(top_srcdir)/gl/m4/stat-time.m4 $(top_srcdir)/gl/m4/stat.m4 \ + $(top_srcdir)/gl/m4/std-gnu11.m4 \ + $(top_srcdir)/gl/m4/stdalign.m4 $(top_srcdir)/gl/m4/stdarg.m4 \ + $(top_srcdir)/gl/m4/stdbool.m4 $(top_srcdir)/gl/m4/stddef_h.m4 \ + $(top_srcdir)/gl/m4/stdint.m4 $(top_srcdir)/gl/m4/stdint_h.m4 \ + $(top_srcdir)/gl/m4/stdio_h.m4 $(top_srcdir)/gl/m4/stdlib_h.m4 \ + $(top_srcdir)/gl/m4/strcase.m4 \ + $(top_srcdir)/gl/m4/strcasestr.m4 \ + $(top_srcdir)/gl/m4/strchrnul.m4 $(top_srcdir)/gl/m4/strdup.m4 \ + $(top_srcdir)/gl/m4/strerror.m4 \ + $(top_srcdir)/gl/m4/string_h.m4 \ + $(top_srcdir)/gl/m4/strings_h.m4 \ + $(top_srcdir)/gl/m4/strndup.m4 $(top_srcdir)/gl/m4/strnlen.m4 \ + $(top_srcdir)/gl/m4/strsep.m4 \ + $(top_srcdir)/gl/m4/sys_file_h.m4 \ + $(top_srcdir)/gl/m4/sys_ioctl_h.m4 \ + $(top_srcdir)/gl/m4/sys_select_h.m4 \ + $(top_srcdir)/gl/m4/sys_socket_h.m4 \ + $(top_srcdir)/gl/m4/sys_stat_h.m4 \ + $(top_srcdir)/gl/m4/sys_time_h.m4 \ + $(top_srcdir)/gl/m4/sys_types_h.m4 \ + $(top_srcdir)/gl/m4/sys_uio_h.m4 \ + $(top_srcdir)/gl/m4/sysexits.m4 \ + $(top_srcdir)/gl/m4/tempname.m4 \ + $(top_srcdir)/gl/m4/threadlib.m4 $(top_srcdir)/gl/m4/time_h.m4 \ + $(top_srcdir)/gl/m4/timespec.m4 \ + $(top_srcdir)/gl/m4/unistd-safer.m4 \ + $(top_srcdir)/gl/m4/unistd_h.m4 $(top_srcdir)/gl/m4/utime.m4 \ + $(top_srcdir)/gl/m4/utime_h.m4 $(top_srcdir)/gl/m4/utimens.m4 \ + $(top_srcdir)/gl/m4/utimes.m4 \ + $(top_srcdir)/gl/m4/vasnprintf.m4 \ + $(top_srcdir)/gl/m4/vasprintf.m4 \ + $(top_srcdir)/gl/m4/vsnprintf.m4 \ + $(top_srcdir)/gl/m4/warn-on-use.m4 \ + $(top_srcdir)/gl/m4/warnings.m4 $(top_srcdir)/gl/m4/wchar_h.m4 \ + $(top_srcdir)/gl/m4/wchar_t.m4 $(top_srcdir)/gl/m4/wcrtomb.m4 \ + $(top_srcdir)/gl/m4/wctype_h.m4 $(top_srcdir)/gl/m4/wint_t.m4 \ + $(top_srcdir)/gl/m4/xalloc.m4 $(top_srcdir)/gl/m4/xgetcwd.m4 \ + $(top_srcdir)/gl/m4/xsize.m4 $(top_srcdir)/gl/m4/xstrndup.m4 \ + $(top_srcdir)/gl/m4/xvasprintf.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(dist_check_SCRIPTS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am_fspause_OBJECTS = fspause.$(OBJEXT) +fspause_OBJECTS = $(am_fspause_OBJECTS) +am__DEPENDENCIES_1 = +fspause_DEPENDENCIES = $(top_builddir)/gl/lib/libgnu.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/fspause.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(fspause_SOURCES) +DIST_SOURCES = $(fspause_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + fi; \ +} +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp \ + $(top_srcdir)/build-aux/test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +ALLOCA_H = @ALLOCA_H@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +ASM_SYMBOL_PREFIX = @ASM_SYMBOL_PREFIX@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@ +BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@ +BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@ +BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@ +BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBLIBS = @DBLIBS@ +DBTYPE = @DBTYPE@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ +EMULTIHOP_VALUE = @EMULTIHOP_VALUE@ +ENOLINK_HIDDEN = @ENOLINK_HIDDEN@ +ENOLINK_VALUE = @ENOLINK_VALUE@ +EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ +EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ +ERRNO_H = @ERRNO_H@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLOAT_H = @FLOAT_H@ +FNMATCH_H = @FNMATCH_H@ +GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLIBC21 = @GLIBC21@ +GLOB_H = @GLOB_H@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIB_ACCEPT = @GNULIB_ACCEPT@ +GNULIB_ACCEPT4 = @GNULIB_ACCEPT4@ +GNULIB_ALPHASORT = @GNULIB_ALPHASORT@ +GNULIB_ATOLL = @GNULIB_ATOLL@ +GNULIB_BIND = @GNULIB_BIND@ +GNULIB_BTOWC = @GNULIB_BTOWC@ +GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ +GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ +GNULIB_CHDIR = @GNULIB_CHDIR@ +GNULIB_CHOWN = @GNULIB_CHOWN@ +GNULIB_CLOSE = @GNULIB_CLOSE@ +GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@ +GNULIB_CONNECT = @GNULIB_CONNECT@ +GNULIB_CTIME = @GNULIB_CTIME@ +GNULIB_DIRFD = @GNULIB_DIRFD@ +GNULIB_DPRINTF = @GNULIB_DPRINTF@ +GNULIB_DUP = @GNULIB_DUP@ +GNULIB_DUP2 = @GNULIB_DUP2@ +GNULIB_DUP3 = @GNULIB_DUP3@ +GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ +GNULIB_ENVIRON = @GNULIB_ENVIRON@ +GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ +GNULIB_EXPLICIT_BZERO = @GNULIB_EXPLICIT_BZERO@ +GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ +GNULIB_FCHDIR = @GNULIB_FCHDIR@ +GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ +GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ +GNULIB_FCLOSE = @GNULIB_FCLOSE@ +GNULIB_FCNTL = @GNULIB_FCNTL@ +GNULIB_FDATASYNC = @GNULIB_FDATASYNC@ +GNULIB_FDOPEN = @GNULIB_FDOPEN@ +GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@ +GNULIB_FFLUSH = @GNULIB_FFLUSH@ +GNULIB_FFS = @GNULIB_FFS@ +GNULIB_FFSL = @GNULIB_FFSL@ +GNULIB_FFSLL = @GNULIB_FFSLL@ +GNULIB_FGETC = @GNULIB_FGETC@ +GNULIB_FGETS = @GNULIB_FGETS@ +GNULIB_FLOCK = @GNULIB_FLOCK@ +GNULIB_FNMATCH = @GNULIB_FNMATCH@ +GNULIB_FOPEN = @GNULIB_FOPEN@ +GNULIB_FPRINTF = @GNULIB_FPRINTF@ +GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ +GNULIB_FPURGE = @GNULIB_FPURGE@ +GNULIB_FPUTC = @GNULIB_FPUTC@ +GNULIB_FPUTS = @GNULIB_FPUTS@ +GNULIB_FREAD = @GNULIB_FREAD@ +GNULIB_FREOPEN = @GNULIB_FREOPEN@ +GNULIB_FSCANF = @GNULIB_FSCANF@ +GNULIB_FSEEK = @GNULIB_FSEEK@ +GNULIB_FSEEKO = @GNULIB_FSEEKO@ +GNULIB_FSTAT = @GNULIB_FSTAT@ +GNULIB_FSTATAT = @GNULIB_FSTATAT@ +GNULIB_FSYNC = @GNULIB_FSYNC@ +GNULIB_FTELL = @GNULIB_FTELL@ +GNULIB_FTELLO = @GNULIB_FTELLO@ +GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ +GNULIB_FUTIMENS = @GNULIB_FUTIMENS@ +GNULIB_FWRITE = @GNULIB_FWRITE@ +GNULIB_GETC = @GNULIB_GETC@ +GNULIB_GETCHAR = @GNULIB_GETCHAR@ +GNULIB_GETCWD = @GNULIB_GETCWD@ +GNULIB_GETDELIM = @GNULIB_GETDELIM@ +GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@ +GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@ +GNULIB_GETGROUPS = @GNULIB_GETGROUPS@ +GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@ +GNULIB_GETLINE = @GNULIB_GETLINE@ +GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@ +GNULIB_GETLOGIN = @GNULIB_GETLOGIN@ +GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@ +GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@ +GNULIB_GETPASS = @GNULIB_GETPASS@ +GNULIB_GETPEERNAME = @GNULIB_GETPEERNAME@ +GNULIB_GETSOCKNAME = @GNULIB_GETSOCKNAME@ +GNULIB_GETSOCKOPT = @GNULIB_GETSOCKOPT@ +GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ +GNULIB_GLOB = @GNULIB_GLOB@ +GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ +GNULIB_GRANTPT = @GNULIB_GRANTPT@ +GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ +GNULIB_IOCTL = @GNULIB_IOCTL@ +GNULIB_ISATTY = @GNULIB_ISATTY@ +GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ +GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ +GNULIB_LCHMOD = @GNULIB_LCHMOD@ +GNULIB_LCHOWN = @GNULIB_LCHOWN@ +GNULIB_LINK = @GNULIB_LINK@ +GNULIB_LINKAT = @GNULIB_LINKAT@ +GNULIB_LISTEN = @GNULIB_LISTEN@ +GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ +GNULIB_LOCALENAME = @GNULIB_LOCALENAME@ +GNULIB_LOCALTIME = @GNULIB_LOCALTIME@ +GNULIB_LSEEK = @GNULIB_LSEEK@ +GNULIB_LSTAT = @GNULIB_LSTAT@ +GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ +GNULIB_MBRLEN = @GNULIB_MBRLEN@ +GNULIB_MBRTOWC = @GNULIB_MBRTOWC@ +GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@ +GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@ +GNULIB_MBSCHR = @GNULIB_MBSCHR@ +GNULIB_MBSCSPN = @GNULIB_MBSCSPN@ +GNULIB_MBSINIT = @GNULIB_MBSINIT@ +GNULIB_MBSLEN = @GNULIB_MBSLEN@ +GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@ +GNULIB_MBSNLEN = @GNULIB_MBSNLEN@ +GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@ +GNULIB_MBSPBRK = @GNULIB_MBSPBRK@ +GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@ +GNULIB_MBSRCHR = @GNULIB_MBSRCHR@ +GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@ +GNULIB_MBSSEP = @GNULIB_MBSSEP@ +GNULIB_MBSSPN = @GNULIB_MBSSPN@ +GNULIB_MBSSTR = @GNULIB_MBSSTR@ +GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@ +GNULIB_MBTOWC = @GNULIB_MBTOWC@ +GNULIB_MEMCHR = @GNULIB_MEMCHR@ +GNULIB_MEMMEM = @GNULIB_MEMMEM@ +GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ +GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ +GNULIB_MKDIRAT = @GNULIB_MKDIRAT@ +GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ +GNULIB_MKFIFO = @GNULIB_MKFIFO@ +GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@ +GNULIB_MKNOD = @GNULIB_MKNOD@ +GNULIB_MKNODAT = @GNULIB_MKNODAT@ +GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ +GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ +GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ +GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ +GNULIB_MKTIME = @GNULIB_MKTIME@ +GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ +GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ +GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ +GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ +GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ +GNULIB_OPEN = @GNULIB_OPEN@ +GNULIB_OPENAT = @GNULIB_OPENAT@ +GNULIB_OPENDIR = @GNULIB_OPENDIR@ +GNULIB_OVERRIDES_STRUCT_STAT = @GNULIB_OVERRIDES_STRUCT_STAT@ +GNULIB_OVERRIDES_WINT_T = @GNULIB_OVERRIDES_WINT_T@ +GNULIB_PCLOSE = @GNULIB_PCLOSE@ +GNULIB_PERROR = @GNULIB_PERROR@ +GNULIB_PIPE = @GNULIB_PIPE@ +GNULIB_PIPE2 = @GNULIB_PIPE2@ +GNULIB_POPEN = @GNULIB_POPEN@ +GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@ +GNULIB_PREAD = @GNULIB_PREAD@ +GNULIB_PRINTF = @GNULIB_PRINTF@ +GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ +GNULIB_PSELECT = @GNULIB_PSELECT@ +GNULIB_PTHREAD_SIGMASK = @GNULIB_PTHREAD_SIGMASK@ +GNULIB_PTSNAME = @GNULIB_PTSNAME@ +GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@ +GNULIB_PUTC = @GNULIB_PUTC@ +GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ +GNULIB_PUTENV = @GNULIB_PUTENV@ +GNULIB_PUTS = @GNULIB_PUTS@ +GNULIB_PWRITE = @GNULIB_PWRITE@ +GNULIB_QSORT_R = @GNULIB_QSORT_R@ +GNULIB_RAISE = @GNULIB_RAISE@ +GNULIB_RANDOM = @GNULIB_RANDOM@ +GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ +GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ +GNULIB_READ = @GNULIB_READ@ +GNULIB_READDIR = @GNULIB_READDIR@ +GNULIB_READLINK = @GNULIB_READLINK@ +GNULIB_READLINKAT = @GNULIB_READLINKAT@ +GNULIB_REALLOCARRAY = @GNULIB_REALLOCARRAY@ +GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ +GNULIB_REALPATH = @GNULIB_REALPATH@ +GNULIB_RECV = @GNULIB_RECV@ +GNULIB_RECVFROM = @GNULIB_RECVFROM@ +GNULIB_REMOVE = @GNULIB_REMOVE@ +GNULIB_RENAME = @GNULIB_RENAME@ +GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ +GNULIB_REWINDDIR = @GNULIB_REWINDDIR@ +GNULIB_RMDIR = @GNULIB_RMDIR@ +GNULIB_RPMATCH = @GNULIB_RPMATCH@ +GNULIB_SCANDIR = @GNULIB_SCANDIR@ +GNULIB_SCANF = @GNULIB_SCANF@ +GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@ +GNULIB_SELECT = @GNULIB_SELECT@ +GNULIB_SEND = @GNULIB_SEND@ +GNULIB_SENDTO = @GNULIB_SENDTO@ +GNULIB_SETENV = @GNULIB_SETENV@ +GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ +GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ +GNULIB_SETSOCKOPT = @GNULIB_SETSOCKOPT@ +GNULIB_SHUTDOWN = @GNULIB_SHUTDOWN@ +GNULIB_SIGACTION = @GNULIB_SIGACTION@ +GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@ +GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@ +GNULIB_SLEEP = @GNULIB_SLEEP@ +GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ +GNULIB_SOCKET = @GNULIB_SOCKET@ +GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ +GNULIB_STAT = @GNULIB_STAT@ +GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ +GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ +GNULIB_STPCPY = @GNULIB_STPCPY@ +GNULIB_STPNCPY = @GNULIB_STPNCPY@ +GNULIB_STRCASESTR = @GNULIB_STRCASESTR@ +GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@ +GNULIB_STRDUP = @GNULIB_STRDUP@ +GNULIB_STRERROR = @GNULIB_STRERROR@ +GNULIB_STRERROR_R = @GNULIB_STRERROR_R@ +GNULIB_STRFTIME = @GNULIB_STRFTIME@ +GNULIB_STRNCAT = @GNULIB_STRNCAT@ +GNULIB_STRNDUP = @GNULIB_STRNDUP@ +GNULIB_STRNLEN = @GNULIB_STRNLEN@ +GNULIB_STRPBRK = @GNULIB_STRPBRK@ +GNULIB_STRPTIME = @GNULIB_STRPTIME@ +GNULIB_STRSEP = @GNULIB_STRSEP@ +GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@ +GNULIB_STRSTR = @GNULIB_STRSTR@ +GNULIB_STRTOD = @GNULIB_STRTOD@ +GNULIB_STRTOK_R = @GNULIB_STRTOK_R@ +GNULIB_STRTOLL = @GNULIB_STRTOLL@ +GNULIB_STRTOULL = @GNULIB_STRTOULL@ +GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ +GNULIB_SYMLINK = @GNULIB_SYMLINK@ +GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ +GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ +GNULIB_TIMEGM = @GNULIB_TIMEGM@ +GNULIB_TIME_R = @GNULIB_TIME_R@ +GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ +GNULIB_TMPFILE = @GNULIB_TMPFILE@ +GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ +GNULIB_TRUNCATE = @GNULIB_TRUNCATE@ +GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ +GNULIB_TZSET = @GNULIB_TZSET@ +GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ +GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ +GNULIB_UNLINK = @GNULIB_UNLINK@ +GNULIB_UNLINKAT = @GNULIB_UNLINKAT@ +GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@ +GNULIB_UNSETENV = @GNULIB_UNSETENV@ +GNULIB_USLEEP = @GNULIB_USLEEP@ +GNULIB_UTIME = @GNULIB_UTIME@ +GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@ +GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ +GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ +GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ +GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ +GNULIB_VFSCANF = @GNULIB_VFSCANF@ +GNULIB_VPRINTF = @GNULIB_VPRINTF@ +GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ +GNULIB_VSCANF = @GNULIB_VSCANF@ +GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ +GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ +GNULIB_WCPCPY = @GNULIB_WCPCPY@ +GNULIB_WCPNCPY = @GNULIB_WCPNCPY@ +GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ +GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@ +GNULIB_WCSCAT = @GNULIB_WCSCAT@ +GNULIB_WCSCHR = @GNULIB_WCSCHR@ +GNULIB_WCSCMP = @GNULIB_WCSCMP@ +GNULIB_WCSCOLL = @GNULIB_WCSCOLL@ +GNULIB_WCSCPY = @GNULIB_WCSCPY@ +GNULIB_WCSCSPN = @GNULIB_WCSCSPN@ +GNULIB_WCSDUP = @GNULIB_WCSDUP@ +GNULIB_WCSFTIME = @GNULIB_WCSFTIME@ +GNULIB_WCSLEN = @GNULIB_WCSLEN@ +GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@ +GNULIB_WCSNCAT = @GNULIB_WCSNCAT@ +GNULIB_WCSNCMP = @GNULIB_WCSNCMP@ +GNULIB_WCSNCPY = @GNULIB_WCSNCPY@ +GNULIB_WCSNLEN = @GNULIB_WCSNLEN@ +GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ +GNULIB_WCSPBRK = @GNULIB_WCSPBRK@ +GNULIB_WCSRCHR = @GNULIB_WCSRCHR@ +GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ +GNULIB_WCSSPN = @GNULIB_WCSSPN@ +GNULIB_WCSSTR = @GNULIB_WCSSTR@ +GNULIB_WCSTOK = @GNULIB_WCSTOK@ +GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@ +GNULIB_WCSXFRM = @GNULIB_WCSXFRM@ +GNULIB_WCTOB = @GNULIB_WCTOB@ +GNULIB_WCTOMB = @GNULIB_WCTOMB@ +GNULIB_WCTRANS = @GNULIB_WCTRANS@ +GNULIB_WCTYPE = @GNULIB_WCTYPE@ +GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ +GNULIB_WMEMCHR = @GNULIB_WMEMCHR@ +GNULIB_WMEMCMP = @GNULIB_WMEMCMP@ +GNULIB_WMEMCPY = @GNULIB_WMEMCPY@ +GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@ +GNULIB_WMEMSET = @GNULIB_WMEMSET@ +GNULIB_WRITE = @GNULIB_WRITE@ +GNULIB__EXIT = @GNULIB__EXIT@ +GREP = @GREP@ +HAVE_ACCEPT4 = @HAVE_ACCEPT4@ +HAVE_ALPHASORT = @HAVE_ALPHASORT@ +HAVE_ATOLL = @HAVE_ATOLL@ +HAVE_BTOWC = @HAVE_BTOWC@ +HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@ +HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ +HAVE_CHOWN = @HAVE_CHOWN@ +HAVE_CLOSEDIR = @HAVE_CLOSEDIR@ +HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ +HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ +HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@ +HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ +HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ +HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ +HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ +HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@ +HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ +HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ +HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@ +HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ +HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ +HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@ +HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ +HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ +HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ +HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ +HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ +HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ +HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@ +HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ +HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ +HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ +HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@ +HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ +HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@ +HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@ +HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ +HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ +HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DIRENT_H = @HAVE_DIRENT_H@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP2 = @HAVE_DUP2@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@ +HAVE_FACCESSAT = @HAVE_FACCESSAT@ +HAVE_FCHDIR = @HAVE_FCHDIR@ +HAVE_FCHMODAT = @HAVE_FCHMODAT@ +HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ +HAVE_FCNTL = @HAVE_FCNTL@ +HAVE_FDATASYNC = @HAVE_FDATASYNC@ +HAVE_FDOPENDIR = @HAVE_FDOPENDIR@ +HAVE_FEATURES_H = @HAVE_FEATURES_H@ +HAVE_FFS = @HAVE_FFS@ +HAVE_FFSL = @HAVE_FFSL@ +HAVE_FFSLL = @HAVE_FFSLL@ +HAVE_FLOCK = @HAVE_FLOCK@ +HAVE_FNMATCH = @HAVE_FNMATCH@ +HAVE_FNMATCH_H = @HAVE_FNMATCH_H@ +HAVE_FREELOCALE = @HAVE_FREELOCALE@ +HAVE_FSEEKO = @HAVE_FSEEKO@ +HAVE_FSTATAT = @HAVE_FSTATAT@ +HAVE_FSYNC = @HAVE_FSYNC@ +HAVE_FTELLO = @HAVE_FTELLO@ +HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ +HAVE_FUTIMENS = @HAVE_FUTIMENS@ +HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@ +HAVE_GETGROUPS = @HAVE_GETGROUPS@ +HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@ +HAVE_GETLOGIN = @HAVE_GETLOGIN@ +HAVE_GETOPT_H = @HAVE_GETOPT_H@ +HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@ +HAVE_GETPASS = @HAVE_GETPASS@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ +HAVE_GLOB = @HAVE_GLOB@ +HAVE_GLOB_H = @HAVE_GLOB_H@ +HAVE_GLOB_PATTERN_P = @HAVE_GLOB_PATTERN_P@ +HAVE_GRANTPT = @HAVE_GRANTPT@ +HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISWBLANK = @HAVE_ISWBLANK@ +HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ +HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@ +HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@ +HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@ +HAVE_LANGINFO_H = @HAVE_LANGINFO_H@ +HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ +HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ +HAVE_LCHMOD = @HAVE_LCHMOD@ +HAVE_LCHOWN = @HAVE_LCHOWN@ +HAVE_LINK = @HAVE_LINK@ +HAVE_LINKAT = @HAVE_LINKAT@ +HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@ +HAVE_LSTAT = @HAVE_LSTAT@ +HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ +HAVE_MBRLEN = @HAVE_MBRLEN@ +HAVE_MBRTOWC = @HAVE_MBRTOWC@ +HAVE_MBSINIT = @HAVE_MBSINIT@ +HAVE_MBSLEN = @HAVE_MBSLEN@ +HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@ +HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@ +HAVE_MEMCHR = @HAVE_MEMCHR@ +HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MKDIRAT = @HAVE_MKDIRAT@ +HAVE_MKDTEMP = @HAVE_MKDTEMP@ +HAVE_MKFIFO = @HAVE_MKFIFO@ +HAVE_MKFIFOAT = @HAVE_MKFIFOAT@ +HAVE_MKNOD = @HAVE_MKNOD@ +HAVE_MKNODAT = @HAVE_MKNODAT@ +HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ +HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ +HAVE_MKSTEMP = @HAVE_MKSTEMP@ +HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ +HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ +HAVE_NANOSLEEP = @HAVE_NANOSLEEP@ +HAVE_NEWLOCALE = @HAVE_NEWLOCALE@ +HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ +HAVE_OPENAT = @HAVE_OPENAT@ +HAVE_OPENDIR = @HAVE_OPENDIR@ +HAVE_OS_H = @HAVE_OS_H@ +HAVE_PCLOSE = @HAVE_PCLOSE@ +HAVE_PIPE = @HAVE_PIPE@ +HAVE_PIPE2 = @HAVE_PIPE2@ +HAVE_POPEN = @HAVE_POPEN@ +HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@ +HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@ +HAVE_PREAD = @HAVE_PREAD@ +HAVE_PSELECT = @HAVE_PSELECT@ +HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@ +HAVE_PTSNAME = @HAVE_PTSNAME@ +HAVE_PTSNAME_R = @HAVE_PTSNAME_R@ +HAVE_PWRITE = @HAVE_PWRITE@ +HAVE_QSORT_R = @HAVE_QSORT_R@ +HAVE_RAISE = @HAVE_RAISE@ +HAVE_RANDOM = @HAVE_RANDOM@ +HAVE_RANDOM_H = @HAVE_RANDOM_H@ +HAVE_RANDOM_R = @HAVE_RANDOM_R@ +HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ +HAVE_READDIR = @HAVE_READDIR@ +HAVE_READLINK = @HAVE_READLINK@ +HAVE_READLINKAT = @HAVE_READLINKAT@ +HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@ +HAVE_REALPATH = @HAVE_REALPATH@ +HAVE_RENAMEAT = @HAVE_RENAMEAT@ +HAVE_REWINDDIR = @HAVE_REWINDDIR@ +HAVE_RPMATCH = @HAVE_RPMATCH@ +HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@ +HAVE_SCANDIR = @HAVE_SCANDIR@ +HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@ +HAVE_SETENV = @HAVE_SETENV@ +HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@ +HAVE_SIGACTION = @HAVE_SIGACTION@ +HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@ +HAVE_SIGINFO_T = @HAVE_SIGINFO_T@ +HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ +HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ +HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ +HAVE_SIGSET_T = @HAVE_SIGSET_T@ +HAVE_SLEEP = @HAVE_SLEEP@ +HAVE_STDINT_H = @HAVE_STDINT_H@ +HAVE_STPCPY = @HAVE_STPCPY@ +HAVE_STPNCPY = @HAVE_STPNCPY@ +HAVE_STRCASECMP = @HAVE_STRCASECMP@ +HAVE_STRCASESTR = @HAVE_STRCASESTR@ +HAVE_STRCHRNUL = @HAVE_STRCHRNUL@ +HAVE_STRINGS_H = @HAVE_STRINGS_H@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOULL = @HAVE_STRTOULL@ +HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@ +HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@ +HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@ +HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@ +HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@ +HAVE_STRVERSCMP = @HAVE_STRVERSCMP@ +HAVE_SYMLINK = @HAVE_SYMLINK@ +HAVE_SYMLINKAT = @HAVE_SYMLINKAT@ +HAVE_SYSEXITS_H = @HAVE_SYSEXITS_H@ +HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@ +HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@ +HAVE_SYS_FILE_H = @HAVE_SYS_FILE_H@ +HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@ +HAVE_SYS_IOCTL_H = @HAVE_SYS_IOCTL_H@ +HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@ +HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ +HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@ +HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ +HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ +HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ +HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@ +HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ +HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ +HAVE_TZSET = @HAVE_TZSET@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +HAVE_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@ +HAVE_USLEEP = @HAVE_USLEEP@ +HAVE_UTIME = @HAVE_UTIME@ +HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ +HAVE_UTIME_H = @HAVE_UTIME_H@ +HAVE_VASPRINTF = @HAVE_VASPRINTF@ +HAVE_VDPRINTF = @HAVE_VDPRINTF@ +HAVE_WCHAR_H = @HAVE_WCHAR_H@ +HAVE_WCHAR_T = @HAVE_WCHAR_T@ +HAVE_WCPCPY = @HAVE_WCPCPY@ +HAVE_WCPNCPY = @HAVE_WCPNCPY@ +HAVE_WCRTOMB = @HAVE_WCRTOMB@ +HAVE_WCSCASECMP = @HAVE_WCSCASECMP@ +HAVE_WCSCAT = @HAVE_WCSCAT@ +HAVE_WCSCHR = @HAVE_WCSCHR@ +HAVE_WCSCMP = @HAVE_WCSCMP@ +HAVE_WCSCOLL = @HAVE_WCSCOLL@ +HAVE_WCSCPY = @HAVE_WCSCPY@ +HAVE_WCSCSPN = @HAVE_WCSCSPN@ +HAVE_WCSDUP = @HAVE_WCSDUP@ +HAVE_WCSFTIME = @HAVE_WCSFTIME@ +HAVE_WCSLEN = @HAVE_WCSLEN@ +HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@ +HAVE_WCSNCAT = @HAVE_WCSNCAT@ +HAVE_WCSNCMP = @HAVE_WCSNCMP@ +HAVE_WCSNCPY = @HAVE_WCSNCPY@ +HAVE_WCSNLEN = @HAVE_WCSNLEN@ +HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ +HAVE_WCSPBRK = @HAVE_WCSPBRK@ +HAVE_WCSRCHR = @HAVE_WCSRCHR@ +HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ +HAVE_WCSSPN = @HAVE_WCSSPN@ +HAVE_WCSSTR = @HAVE_WCSSTR@ +HAVE_WCSTOK = @HAVE_WCSTOK@ +HAVE_WCSWIDTH = @HAVE_WCSWIDTH@ +HAVE_WCSXFRM = @HAVE_WCSXFRM@ +HAVE_WCTRANS_T = @HAVE_WCTRANS_T@ +HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ +HAVE_WCTYPE_T = @HAVE_WCTYPE_T@ +HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ +HAVE_WINT_T = @HAVE_WINT_T@ +HAVE_WMEMCHR = @HAVE_WMEMCHR@ +HAVE_WMEMCMP = @HAVE_WMEMCMP@ +HAVE_WMEMCPY = @HAVE_WMEMCPY@ +HAVE_WMEMMOVE = @HAVE_WMEMMOVE@ +HAVE_WMEMSET = @HAVE_WMEMSET@ +HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ +HAVE_XLOCALE_H = @HAVE_XLOCALE_H@ +HAVE__BOOL = @HAVE__BOOL@ +HAVE__EXIT = @HAVE__EXIT@ +IGNORE_UNUSED_LIBRARIES_CFLAGS = @IGNORE_UNUSED_LIBRARIES_CFLAGS@ +INCLUDE_NEXT = @INCLUDE_NEXT@ +INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCOMPRESS = @LIBCOMPRESS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPTH = @LIBPTH@ +LIBPTH_PREFIX = @LIBPTH_PREFIX@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_GETLOGIN = @LIB_GETLOGIN@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_SELECT = @LIB_SELECT@ +LIMITS_H = @LIMITS_H@ +LINGUAS = @LINGUAS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALE_FR = @LOCALE_FR@ +LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ +LOCALE_JA = @LOCALE_JA@ +LOCALE_ZH_CN = @LOCALE_ZH_CN@ +LTALLOCA = @LTALLOCA@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ +LTLIBOBJS = @LTLIBOBJS@ +LTLIBPTH = @LTLIBPTH@ +LTLIBTHREAD = @LTLIBTHREAD@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANDIR_LAYOUT = @MANDIR_LAYOUT@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MAN_SUBDIRS = @MAN_SUBDIRS@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@ +NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ +NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ +NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@ +NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H = @NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H@ +NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ +NEXT_AS_FIRST_DIRECTIVE_GLOB_H = @NEXT_AS_FIRST_DIRECTIVE_GLOB_H@ +NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ +NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ +NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ +NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ +NEXT_AS_FIRST_DIRECTIVE_STDARG_H = @NEXT_AS_FIRST_DIRECTIVE_STDARG_H@ +NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ +NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ +NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ +NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@ +NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@ +NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@ +NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H = @NEXT_AS_FIRST_DIRECTIVE_SYSEXITS_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_FILE_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@ +NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@ +NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ +NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ +NEXT_AS_FIRST_DIRECTIVE_UTIME_H = @NEXT_AS_FIRST_DIRECTIVE_UTIME_H@ +NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ +NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ +NEXT_DIRENT_H = @NEXT_DIRENT_H@ +NEXT_ERRNO_H = @NEXT_ERRNO_H@ +NEXT_FCNTL_H = @NEXT_FCNTL_H@ +NEXT_FLOAT_H = @NEXT_FLOAT_H@ +NEXT_FNMATCH_H = @NEXT_FNMATCH_H@ +NEXT_GETOPT_H = @NEXT_GETOPT_H@ +NEXT_GLOB_H = @NEXT_GLOB_H@ +NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ +NEXT_LIMITS_H = @NEXT_LIMITS_H@ +NEXT_LOCALE_H = @NEXT_LOCALE_H@ +NEXT_SIGNAL_H = @NEXT_SIGNAL_H@ +NEXT_STDARG_H = @NEXT_STDARG_H@ +NEXT_STDDEF_H = @NEXT_STDDEF_H@ +NEXT_STDINT_H = @NEXT_STDINT_H@ +NEXT_STDIO_H = @NEXT_STDIO_H@ +NEXT_STDLIB_H = @NEXT_STDLIB_H@ +NEXT_STRINGS_H = @NEXT_STRINGS_H@ +NEXT_STRING_H = @NEXT_STRING_H@ +NEXT_SYSEXITS_H = @NEXT_SYSEXITS_H@ +NEXT_SYS_FILE_H = @NEXT_SYS_FILE_H@ +NEXT_SYS_IOCTL_H = @NEXT_SYS_IOCTL_H@ +NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@ +NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@ +NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@ +NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@ +NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@ +NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@ +NEXT_TIME_H = @NEXT_TIME_H@ +NEXT_UNISTD_H = @NEXT_UNISTD_H@ +NEXT_UTIME_H = @NEXT_UTIME_H@ +NEXT_WCHAR_H = @NEXT_WCHAR_H@ +NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PO4A = @PO4A@ +POSUB = @POSUB@ +PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ +PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC = @REPLACE_CALLOC@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ +REPLACE_CTIME = @REPLACE_CTIME@ +REPLACE_DIRFD = @REPLACE_DIRFD@ +REPLACE_DPRINTF = @REPLACE_DPRINTF@ +REPLACE_DUP = @REPLACE_DUP@ +REPLACE_DUP2 = @REPLACE_DUP2@ +REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ +REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ +REPLACE_FCLOSE = @REPLACE_FCLOSE@ +REPLACE_FCNTL = @REPLACE_FCNTL@ +REPLACE_FDOPEN = @REPLACE_FDOPEN@ +REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ +REPLACE_FFLUSH = @REPLACE_FFLUSH@ +REPLACE_FNMATCH = @REPLACE_FNMATCH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREELOCALE = @REPLACE_FREELOCALE@ +REPLACE_FREOPEN = @REPLACE_FREOPEN@ +REPLACE_FSEEK = @REPLACE_FSEEK@ +REPLACE_FSEEKO = @REPLACE_FSEEKO@ +REPLACE_FSTAT = @REPLACE_FSTAT@ +REPLACE_FSTATAT = @REPLACE_FSTATAT@ +REPLACE_FTELL = @REPLACE_FTELL@ +REPLACE_FTELLO = @REPLACE_FTELLO@ +REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@ +REPLACE_FUTIMENS = @REPLACE_FUTIMENS@ +REPLACE_GETCWD = @REPLACE_GETCWD@ +REPLACE_GETDELIM = @REPLACE_GETDELIM@ +REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@ +REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@ +REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ +REPLACE_GETLINE = @REPLACE_GETLINE@ +REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ +REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ +REPLACE_GETPASS = @REPLACE_GETPASS@ +REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ +REPLACE_GLOB = @REPLACE_GLOB@ +REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@ +REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_IOCTL = @REPLACE_IOCTL@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_ITOLD = @REPLACE_ITOLD@ +REPLACE_LCHOWN = @REPLACE_LCHOWN@ +REPLACE_LINK = @REPLACE_LINK@ +REPLACE_LINKAT = @REPLACE_LINKAT@ +REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ +REPLACE_LOCALTIME = @REPLACE_LOCALTIME@ +REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ +REPLACE_LSEEK = @REPLACE_LSEEK@ +REPLACE_LSTAT = @REPLACE_LSTAT@ +REPLACE_MALLOC = @REPLACE_MALLOC@ +REPLACE_MBRLEN = @REPLACE_MBRLEN@ +REPLACE_MBRTOWC = @REPLACE_MBRTOWC@ +REPLACE_MBSINIT = @REPLACE_MBSINIT@ +REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@ +REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@ +REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@ +REPLACE_MBTOWC = @REPLACE_MBTOWC@ +REPLACE_MEMCHR = @REPLACE_MEMCHR@ +REPLACE_MEMMEM = @REPLACE_MEMMEM@ +REPLACE_MKDIR = @REPLACE_MKDIR@ +REPLACE_MKFIFO = @REPLACE_MKFIFO@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ +REPLACE_MKTIME = @REPLACE_MKTIME@ +REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ +REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@ +REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ +REPLACE_NULL = @REPLACE_NULL@ +REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ +REPLACE_OPEN = @REPLACE_OPEN@ +REPLACE_OPENAT = @REPLACE_OPENAT@ +REPLACE_OPENDIR = @REPLACE_OPENDIR@ +REPLACE_PERROR = @REPLACE_PERROR@ +REPLACE_POPEN = @REPLACE_POPEN@ +REPLACE_PREAD = @REPLACE_PREAD@ +REPLACE_PRINTF = @REPLACE_PRINTF@ +REPLACE_PSELECT = @REPLACE_PSELECT@ +REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@ +REPLACE_PTSNAME = @REPLACE_PTSNAME@ +REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@ +REPLACE_PUTENV = @REPLACE_PUTENV@ +REPLACE_PWRITE = @REPLACE_PWRITE@ +REPLACE_QSORT_R = @REPLACE_QSORT_R@ +REPLACE_RAISE = @REPLACE_RAISE@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_READLINKAT = @REPLACE_READLINKAT@ +REPLACE_REALLOC = @REPLACE_REALLOC@ +REPLACE_REALPATH = @REPLACE_REALPATH@ +REPLACE_REMOVE = @REPLACE_REMOVE@ +REPLACE_RENAME = @REPLACE_RENAME@ +REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ +REPLACE_RMDIR = @REPLACE_RMDIR@ +REPLACE_SELECT = @REPLACE_SELECT@ +REPLACE_SETENV = @REPLACE_SETENV@ +REPLACE_SETLOCALE = @REPLACE_SETLOCALE@ +REPLACE_SLEEP = @REPLACE_SLEEP@ +REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ +REPLACE_SPRINTF = @REPLACE_SPRINTF@ +REPLACE_STAT = @REPLACE_STAT@ +REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ +REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ +REPLACE_STPNCPY = @REPLACE_STPNCPY@ +REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ +REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@ +REPLACE_STRDUP = @REPLACE_STRDUP@ +REPLACE_STRERROR = @REPLACE_STRERROR@ +REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ +REPLACE_STRFTIME = @REPLACE_STRFTIME@ +REPLACE_STRNCAT = @REPLACE_STRNCAT@ +REPLACE_STRNDUP = @REPLACE_STRNDUP@ +REPLACE_STRNLEN = @REPLACE_STRNLEN@ +REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ +REPLACE_STRSTR = @REPLACE_STRSTR@ +REPLACE_STRTOD = @REPLACE_STRTOD@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@ +REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@ +REPLACE_SYMLINK = @REPLACE_SYMLINK@ +REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@ +REPLACE_TIMEGM = @REPLACE_TIMEGM@ +REPLACE_TMPFILE = @REPLACE_TMPFILE@ +REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ +REPLACE_TRUNCATE = @REPLACE_TRUNCATE@ +REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ +REPLACE_TZSET = @REPLACE_TZSET@ +REPLACE_UNLINK = @REPLACE_UNLINK@ +REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ +REPLACE_UNSETENV = @REPLACE_UNSETENV@ +REPLACE_USLEEP = @REPLACE_USLEEP@ +REPLACE_UTIME = @REPLACE_UTIME@ +REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@ +REPLACE_VASPRINTF = @REPLACE_VASPRINTF@ +REPLACE_VDPRINTF = @REPLACE_VDPRINTF@ +REPLACE_VFPRINTF = @REPLACE_VFPRINTF@ +REPLACE_VPRINTF = @REPLACE_VPRINTF@ +REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@ +REPLACE_VSPRINTF = @REPLACE_VSPRINTF@ +REPLACE_WCRTOMB = @REPLACE_WCRTOMB@ +REPLACE_WCSFTIME = @REPLACE_WCSFTIME@ +REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ +REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ +REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@ +REPLACE_WCTOB = @REPLACE_WCTOB@ +REPLACE_WCTOMB = @REPLACE_WCTOMB@ +REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ +REPLACE_WRITE = @REPLACE_WRITE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ +SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ +STDALIGN_H = @STDALIGN_H@ +STDARG_H = @STDARG_H@ +STDBOOL_H = @STDBOOL_H@ +STDDEF_H = @STDDEF_H@ +STDINT_H = @STDINT_H@ +STRIP = @STRIP@ +SYSEXITS_H = @SYSEXITS_H@ +SYS_IOCTL_H_HAVE_WINSOCK2_H = @SYS_IOCTL_H_HAVE_WINSOCK2_H@ +SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ +TBL_X_FORMAT = @TBL_X_FORMAT@ +TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ +TRANS_APROPOS = @TRANS_APROPOS@ +TRANS_APROPOS_UPPER = @TRANS_APROPOS_UPPER@ +TRANS_CATMAN = @TRANS_CATMAN@ +TRANS_CATMAN_UPPER = @TRANS_CATMAN_UPPER@ +TRANS_LEXGROG = @TRANS_LEXGROG@ +TRANS_LEXGROG_UPPER = @TRANS_LEXGROG_UPPER@ +TRANS_MAN = @TRANS_MAN@ +TRANS_MANCONV = @TRANS_MANCONV@ +TRANS_MANCONV_UPPER = @TRANS_MANCONV_UPPER@ +TRANS_MANDB = @TRANS_MANDB@ +TRANS_MANDB_UPPER = @TRANS_MANDB_UPPER@ +TRANS_MANPATH = @TRANS_MANPATH@ +TRANS_MANPATH_UPPER = @TRANS_MANPATH_UPPER@ +TRANS_MAN_UPPER = @TRANS_MAN_UPPER@ +TRANS_WHATIS = @TRANS_WHATIS@ +TRANS_WHATIS_UPPER = @TRANS_WHATIS_UPPER@ +TRANS_ZSOELIM = @TRANS_ZSOELIM@ +TRANS_ZSOELIM_UPPER = @TRANS_ZSOELIM_UPPER@ +TROFF = @TROFF@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ +UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ +UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ +USE_NLS = @USE_NLS@ +UTIME_H = @UTIME_H@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ +WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@ +WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@ +WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@ +WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@ +WINT_T_SUFFIX = @WINT_T_SUFFIX@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +browser = @browser@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +bunzip2 = @bunzip2@ +bzip2 = @bzip2@ +cache_top_owner = @cache_top_owner@ +cat = @cat@ +col = @col@ +compress = @compress@ +compress_ext = @compress_ext@ +compressor = @compressor@ +config_file = @config_file@ +config_file_basename = @config_file_basename@ +config_file_dirname = @config_file_dirname@ +datadir = @datadir@ +datarootdir = @datarootdir@ +date = @date@ +docdir = @docdir@ +dvidir = @dvidir@ +eqn = @eqn@ +exec_prefix = @exec_prefix@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grap = @grap@ +grep = @grep@ +gunzip = @gunzip@ +gzip = @gzip@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libpipeline_CFLAGS = @libpipeline_CFLAGS@ +libpipeline_LIBS = @libpipeline_LIBS@ +libseccomp_CFLAGS = @libseccomp_CFLAGS@ +libseccomp_LIBS = @libseccomp_LIBS@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lzip = @lzip@ +lzma = @lzma@ +man_mode = @man_mode@ +man_owner = @man_owner@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +neqn = @neqn@ +nroff = @nroff@ +oldincludedir = @oldincludedir@ +override_dir = @override_dir@ +pager = @pager@ +pdfdir = @pdfdir@ +pic = @pic@ +preconv = @preconv@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +refer = @refer@ +roff_version = @roff_version@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sections = @sections@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +systemdtmpfilesdir = @systemdtmpfilesdir@ +target_alias = @target_alias@ +tbl = @tbl@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +tr = @tr@ +troff = @troff@ +uncompress = @uncompress@ +unlzip = @unlzip@ +unlzma = @unlzma@ +unxz = @unxz@ +vgrind = @vgrind@ +xz = @xz@ +TESTS_ENVIRONMENT = PATH=$(abs_builddir)/..:$$PATH; export PATH; \ + DBTYPE=$(DBTYPE); export DBTYPE; \ + MANDIR_LAYOUT=$(MANDIR_LAYOUT); export MANDIR_LAYOUT; \ + abs_top_builddir=$(abs_top_builddir); export abs_top_builddir; \ + OVERRIDE_DIR="$(override_dir)"; export OVERRIDE_DIR; + +# Each test must use the configure-detected shell, not necessarily /bin/sh. +AM_LOG_FLAGS = $(SHELL) +ALL_TESTS = \ + lexgrog-1 lexgrog-2 lexgrog-3 \ + man-1 man-2 man-3 man-4 man-5 man-6 man-7 man-8 man-9 man-10 man-11 \ + manconv-1 manconv-2 manconv-3 \ + mandb-1 mandb-2 mandb-3 mandb-4 mandb-5 mandb-6 mandb-7 \ + whatis-1 \ + zsoelim-1 + +@CROSS_COMPILING_FALSE@TESTS = $(ALL_TESTS) +AM_CPPFLAGS = \ + -I$(top_builddir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib + +AM_CFLAGS = $(WARN_CFLAGS) +fspause_SOURCES = fspause.c +fspause_LDADD = \ + $(top_builddir)/gl/lib/libgnu.la \ + $(LIB_NANOSLEEP) + +dist_check_SCRIPTS = testlib.sh $(ALL_TESTS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/tests/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +fspause$(EXEEXT): $(fspause_OBJECTS) $(fspause_DEPENDENCIES) $(EXTRA_fspause_DEPENDENCIES) + @rm -f fspause$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(fspause_OBJECTS) $(fspause_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fspause.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: $(check_PROGRAMS) $(dist_check_SCRIPTS) + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all $(check_PROGRAMS) $(dist_check_SCRIPTS) + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +lexgrog-1.log: lexgrog-1 + @p='lexgrog-1'; \ + b='lexgrog-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +lexgrog-2.log: lexgrog-2 + @p='lexgrog-2'; \ + b='lexgrog-2'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +lexgrog-3.log: lexgrog-3 + @p='lexgrog-3'; \ + b='lexgrog-3'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-1.log: man-1 + @p='man-1'; \ + b='man-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-2.log: man-2 + @p='man-2'; \ + b='man-2'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-3.log: man-3 + @p='man-3'; \ + b='man-3'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-4.log: man-4 + @p='man-4'; \ + b='man-4'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-5.log: man-5 + @p='man-5'; \ + b='man-5'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-6.log: man-6 + @p='man-6'; \ + b='man-6'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-7.log: man-7 + @p='man-7'; \ + b='man-7'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-8.log: man-8 + @p='man-8'; \ + b='man-8'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-9.log: man-9 + @p='man-9'; \ + b='man-9'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-10.log: man-10 + @p='man-10'; \ + b='man-10'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +man-11.log: man-11 + @p='man-11'; \ + b='man-11'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +manconv-1.log: manconv-1 + @p='manconv-1'; \ + b='manconv-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +manconv-2.log: manconv-2 + @p='manconv-2'; \ + b='manconv-2'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +manconv-3.log: manconv-3 + @p='manconv-3'; \ + b='manconv-3'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-1.log: mandb-1 + @p='mandb-1'; \ + b='mandb-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-2.log: mandb-2 + @p='mandb-2'; \ + b='mandb-2'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-3.log: mandb-3 + @p='mandb-3'; \ + b='mandb-3'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-4.log: mandb-4 + @p='mandb-4'; \ + b='mandb-4'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-5.log: mandb-5 + @p='mandb-5'; \ + b='mandb-5'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-6.log: mandb-6 + @p='mandb-6'; \ + b='mandb-6'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +mandb-7.log: mandb-7 + @p='mandb-7'; \ + b='mandb-7'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +whatis-1.log: whatis-1 + @p='whatis-1'; \ + b='whatis-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +zsoelim-1.log: zsoelim-1 + @p='zsoelim-1'; \ + b='zsoelim-1'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) \ + $(dist_check_SCRIPTS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/fspause.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/fspause.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-checkPROGRAMS clean-generic clean-libtool \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tests/fspause.c b/src/tests/fspause.c new file mode 100644 index 0000000..64a6e89 --- /dev/null +++ b/src/tests/fspause.c @@ -0,0 +1,112 @@ +/* + * fspause.c: pause until a file timestamp updates + * + * Copyright (C) 2014 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> + +#include "progname.h" +#include "stat-time.h" +#include "timespec.h" +#include "xalloc.h" + +#include "manconfig.h" + +static char *filename; +static int fd = -1; + +#define MUST(name, cond) \ + do { \ + if (!(cond)) { \ + fprintf (stderr, "fspause: " name " failed\n"); \ + abort (); \ + } \ + } while (0) + +static void unlink_tempfile (void) +{ + if (fd >= 0) { + MUST ("close", close (fd) >= 0); + MUST ("unlink", unlink (filename) >= 0); + } +} + +static void delay (int delay_ns) +{ + struct timespec delay_ts; + + delay_ts.tv_sec = delay_ns / 1000000000; + delay_ts.tv_nsec = delay_ns % 1000000000; + for (;;) { + errno = 0; + if (nanosleep (&delay_ts, NULL) == 0) + break; + MUST ("nanosleep", errno == 0 || errno == EINTR); + } +} + +static int try_delay (struct stat *st, int delay_ns) +{ + struct timespec start_ts, end_ts; + + start_ts = get_stat_mtime (st); + delay (delay_ns); + MUST ("write", write (fd, "\n", 1) == 1); + MUST ("fstat", fstat (fd, st) >= 0); + end_ts = get_stat_mtime (st); + return timespec_cmp (start_ts, end_ts) != 0; +} + +int main (int argc ATTRIBUTE_UNUSED, char **argv) +{ + struct stat st; + int delay_ns; + + set_program_name (argv[0]); + + filename = xstrdup ("fspause.tmp.XXXXXX"); + MUST ("mkstemp", (fd = mkstemp (filename)) >= 0); + atexit (unlink_tempfile); + MUST ("fstat", fstat (fd, &st) >= 0); + + /* 0x40000000 nanoseconds is just over a second. The effective + * maximum delay we will allow is thus about two seconds. This + * saves us having to keep track of anything more complicated than a + * single signed 32-bit int. + */ + for (delay_ns = 1; delay_ns < 0x40000000; delay_ns *= 2) { + if (try_delay (&st, delay_ns)) + return 0; + } + + fprintf (stderr, + "fspause: temporary file timestamp refuses to change!\n"); + return 1; +} diff --git a/src/tests/lexgrog-1 b/src/tests/lexgrog-1 new file mode 100755 index 0000000..8ab8a0f --- /dev/null +++ b/src/tests/lexgrog-1 @@ -0,0 +1,18 @@ +#! /bin/sh + +# Basic lexgrog tests. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${LEXGROG=lexgrog} + +init + +write_page lextest 1 "$tmpdir/usr/share/man/man1/lextest.1.gz" UTF-8 gz '' \ + 'lextest \- simple lexgrog test' +echo "$tmpdir/usr/share/man/man1/lextest.1.gz: \"lextest - simple lexgrog test\"" >"$tmpdir/1.exp" +run $LEXGROG "$tmpdir/usr/share/man/man1/lextest.1.gz" >"$tmpdir/1.out" +expect_pass 'simple lexgrog test' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/lexgrog-2 b/src/tests/lexgrog-2 new file mode 100755 index 0000000..eac8dbd --- /dev/null +++ b/src/tests/lexgrog-2 @@ -0,0 +1,26 @@ +#! /bin/sh + +# Test multiple whatis definitions. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${LEXGROG=lexgrog} + +init + +name_section="\ +lextest \\- one whatis definition +.br +lextest2 \\- another whatis definition" + +write_page lextest 1 "$tmpdir/usr/share/man/man1/lextest.1.gz" UTF-8 gz '' \ + "$name_section" +cat >"$tmpdir/2.exp" <<EOF +$tmpdir/usr/share/man/man1/lextest.1.gz: "lextest - one whatis definition" +$tmpdir/usr/share/man/man1/lextest.1.gz: "lextest2 - another whatis definition" +EOF +run $LEXGROG "$tmpdir/usr/share/man/man1/lextest.1.gz" >"$tmpdir/2.out" +expect_pass 'multiple whatis definitions' 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +finish diff --git a/src/tests/lexgrog-3 b/src/tests/lexgrog-3 new file mode 100644 index 0000000..a6a66a9 --- /dev/null +++ b/src/tests/lexgrog-3 @@ -0,0 +1,20 @@ +#! /bin/sh + +# Test handling of \- in the right-hand side of a NAME section. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${LEXGROG=lexgrog} + +init + +write_page lextest 1 "$tmpdir/usr/share/man/man1/lextest.1.gz" UTF-8 gz '' \ + 'lextest \- see lextest \-\-help' +cat >"$tmpdir/3.exp" <<EOF +$tmpdir/usr/share/man/man1/lextest.1.gz: "lextest - see lextest --help" +EOF +run $LEXGROG "$tmpdir/usr/share/man/man1/lextest.1.gz" >"$tmpdir/3.out" +expect_pass 'multiple whatis definitions' 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"' + +finish diff --git a/src/tests/man-1 b/src/tests/man-1 new file mode 100755 index 0000000..ff264d6 --- /dev/null +++ b/src/tests/man-1 @@ -0,0 +1,31 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/163347 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/local/man /usr/share/man +MANPATH="$tmpdir/usr/local/man:$tmpdir/usr/share/man" +export MANPATH + +write_page md5sum 1 "$tmpdir/usr/share/man/man1/md5sum.1.gz" \ + UTF-8 gz '' 'md5sum \- Debian md5sum manual page' +write_page md5sum 1 "$tmpdir/usr/share/man/man1/md5sum.textutils.1.gz" \ + UTF-8 gz '' 'md5sum \- coreutils md5sum manual page' +mkdir -p "$tmpdir/usr/local/man/man1" +ln -s ../../../share/man/man1/md5sum.textutils.1.gz \ + "$tmpdir/usr/local/man/man1/md5sum.1.gz" +cat >"$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man1/md5sum.textutils.1.gz +$abstmpdir/usr/share/man/man1/md5sum.1.gz +EOF +run $MAN -C "$tmpdir/manpath.config" -aw md5sum >"$tmpdir/1.out" +expect_pass 'symlinks with matching names win' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/man-10 b/src/tests/man-10 new file mode 100755 index 0000000..75ec2a5 --- /dev/null +++ b/src/tests/man-10 @@ -0,0 +1,26 @@ +#! /bin/sh + +# Test that man can run from a deleted directory. +# https://bugs.debian.org/764384 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +echo "MANDATORY_MANPATH $abstmpdir/usr/share/man" >"$tmpdir/manpath.config" +MANPATH="$abstmpdir/usr/share/man" +export MANPATH + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- test' +mkdir "$tmpdir/zombie" +cd "$tmpdir/zombie" +rmdir "$abstmpdir/zombie" || \ + skip "can't remove current working directory on this system" +run $MAN -C "$abstmpdir/manpath.config" test >/dev/null +code=$? +expect_pass 'run from deleted directory' 'test "$code" = 0' + +finish diff --git a/src/tests/man-11 b/src/tests/man-11 new file mode 100755 index 0000000..a16e41c --- /dev/null +++ b/src/tests/man-11 @@ -0,0 +1,45 @@ +#!/bin/sh + +# Test for: +# man chmod.2 => man 2 chmod +# man chmod.2p => man 2p chmod + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +page_name="chmod" + +write_page "$page_name" 1 "$tmpdir/usr/share/man/man1/${page_name}.1.gz" \ + UTF-8 gz '' "$page_name \- coreutils $page_name manual page" +write_page "$page_name" 2 "$tmpdir/usr/share/man/man2/${page_name}.2.gz" \ + UTF-8 gz '' "$page_name \- $page_name() syscall manual page" + +cat >"$tmpdir/2.exp" <<EOF +$abstmpdir/usr/share/man/man2/${page_name}.2.gz +EOF + +run $MAN -C "$tmpdir/manpath.config" -aw "$page_name".2 >"$tmpdir/2.out" +expect_pass '"man name.2" is the same as "man 2 name"' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +( + cd "$tmpdir/usr/share/man/man2/" + mv "${page_name}.2.gz" "${page_name}.2p.gz" +) + +cat >"$tmpdir/2p.exp" <<EOF +$abstmpdir/usr/share/man/man2/${page_name}.2p.gz +EOF + +run $MAN -C "$tmpdir/manpath.config" -aw "$page_name".2p >"$tmpdir/2p.out" +expect_pass '"man name.2p" is the same as "man 2p name"' \ + 'diff -u "$tmpdir/2p.exp" "$tmpdir/2p.out"' + +finish diff --git a/src/tests/man-2 b/src/tests/man-2 new file mode 100755 index 0000000..f05291b --- /dev/null +++ b/src/tests/man-2 @@ -0,0 +1,23 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/608490 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +write_page file 1 "$tmpdir/file.1" UTF-8 '' '' 'file \- test' +chmod +x "$tmpdir/file.1" +PATH="$PATH:$tmpdir" run $MAN \ + -C "$tmpdir/manpath.config" "$tmpdir/file.1" >/dev/null +code=$? +expect_pass 'executable page on path' 'test "$code" = 0' + +finish diff --git a/src/tests/man-3 b/src/tests/man-3 new file mode 100755 index 0000000..d2bac98 --- /dev/null +++ b/src/tests/man-3 @@ -0,0 +1,41 @@ +#! /bin/sh + +# Test for: +# https://bugzilla.redhat.com/show_bug.cgi?id=684977 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +case $MANDIR_LAYOUT in + ""|GNU) + ;; + *) + skip "only applicable to GNU layout" + ;; +esac + +: ${MAN=man} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +# Force default section order. +cat >>"$tmpdir/manpath.config" <<EOF +SECTION 1 n l 8 3 0 2 5 4 9 6 7 +EOF + +write_page md5sum 3pm "$tmpdir/usr/share/man/man3/open.3pm.gz" \ + UTF-8 gz '' 'open \- section 3pm' +write_page md5sum 3p "$tmpdir/usr/share/man/man3p/open.3p.gz" \ + UTF-8 gz '' 'open \- section 3p' +cat >"$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man3p/open.3p.gz +$abstmpdir/usr/share/man/man3/open.3pm.gz +EOF +run $MAN -C "$tmpdir/manpath.config" -aw 3p open >"$tmpdir/1.out" +expect_pass 'exact section matches win' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/man-4 b/src/tests/man-4 new file mode 100755 index 0000000..a729311 --- /dev/null +++ b/src/tests/man-4 @@ -0,0 +1,173 @@ +#! /bin/sh + +# Test for wildcards in MANDATORY_MANPATH in config file and in MANPATH. +# https://bugzilla.redhat.com/show_bug.cgi?id=677669 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +> "$tmpdir/manpath.config" + +MAN_TEST_DISABLE_PATH=1 +export MAN_TEST_DISABLE_PATH + +write_page manx 1 "$tmpdir/usr/share/man/man1/manx.1.gz" \ + UTF-8 gz '' 'manx \- an interface to the on-line reference manuals' +write_page manpathx 1 "$tmpdir/usr/share/prog/a/man/man1/manpathx.1.gz" \ + UTF-8 gz '' 'manpathx \- determine search path for manual pages' +write_page whatisx 1 "$tmpdir/usr/share/prog/b/man/man1/whatisx.1.gz" \ + UTF-8 gz '' 'whatisx \- display manual page descriptions' + +# +# Testing -M option +# + +# Without wildcards +Mpath="$tmpdir/usr/share/man" + +run $MAN -C "$tmpdir/manpath.config" \ + -aw -M "${Mpath}" manpathx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: -M option: without wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw -M "${Mpath}" manx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man1/manx.1.gz +EOF +expect_pass 'wildcards: -M option: without wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +# With wildcards +Mpath="$tmpdir/usr/share/prog/*/man" + +run $MAN -C "$tmpdir/manpath.config" \ + -aw -M "${Mpath}" manx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: -M option: with wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw -M "${Mpath}" manpathx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/a/man/man1/manpathx.1.gz +EOF +expect_pass 'wildcards: -M option: with wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +Mpath="$tmpdir/usr/share/prog/[ab]/man" + +run $MAN -C "$tmpdir/manpath.config" \ + -aw -M "${Mpath}" whatisx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/b/man/man1/whatisx.1.gz +EOF +expect_pass 'wildcards: -M option: with wildcards: check existing man page II' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +# +# Testing MANPATH +# + +# Without wildcards +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manpathx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: MANPATH: without wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man1/manx.1.gz +EOF +expect_pass 'wildcards: MANPATH: without wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +# With wildcards +MANPATH="$tmpdir/usr/share/prog/*/man" +export MANPATH + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: MANPATH: with wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manpathx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/a/man/man1/manpathx.1.gz +EOF +expect_pass 'wildcards: MANPATH: with wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +MANPATH="$tmpdir/usr/share/prog/[ab]/man" +export MANPATH + +run $MAN -C "$tmpdir/manpath.config" \ + -aw whatisx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/b/man/man1/whatisx.1.gz +EOF +expect_pass 'wildcards: MANPATH: with wildcards: check existing man page II' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +unset MANPATH + +# +# Testing MANDATORY_MANPATH +# + +# Without wildcards +fake_config /usr/share/man + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manpathx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: MANDATORY_MANPATH: without wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man1/manx.1.gz +EOF +expect_pass 'wildcards: MANDATORY_MANPATH: without wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +# With wildcards +fake_config "/usr/share/prog/*/man" + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manx > "$tmpdir/1.out" 2> /dev/null +> "$tmpdir/1.exp" +expect_pass 'wildcards: MANDATORY_MANPATH: with wildcards: check missing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" \ + -aw manpathx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/a/man/man1/manpathx.1.gz +EOF +expect_pass 'wildcards: MANDATORY_MANPATH: with wildcards: check existing man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +fake_config "/usr/share/prog/[ab]/man" + +run $MAN -C "$tmpdir/manpath.config" \ + -aw whatisx > "$tmpdir/1.out" +cat > "$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/prog/b/man/man1/whatisx.1.gz +EOF +expect_pass 'wildcards: MANDATORY_MANPATH: with wildcards: check existing man page II' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/man-5 b/src/tests/man-5 new file mode 100755 index 0000000..32eddaa --- /dev/null +++ b/src/tests/man-5 @@ -0,0 +1,90 @@ +#! /bin/sh + +# Test for relative .so links between man pages in the same section (e.g. ".so bar.1"). +# https://bugzilla.redhat.com/show_bug.cgi?id=693458 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +cat >"$tmpdir/fake-program" <<EOF +#! /bin/sh +exec cat +EOF +chmod +x "$tmpdir/fake-program" +PATH="$abstmpdir:$PATH" +export PATH + +cat >>"$tmpdir/manpath.config" <<EOF +DEFINE tbl fake-program +DEFINE nroff fake-program +EOF + +# There are 2 kind of tests. First, when destination is not gzipped, what means +# that .so link contains full filename and second, when the destination is +# gzipped, and .so link doesn't contain the file suffix. + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- top-level test page' +echo '.so man1/test.1' >"$tmpdir/usr/share/man/man1/test-fullso.1" +echo '.so test.1' >"$tmpdir/usr/share/man/man1/test-relso.1" + +write_page testb 1 "$tmpdir/usr/share/man/man1/testb.1.gz" \ + UTF-8 'gz' '' 'testb \- top-level test page' +echo '.so man1/testb.1' >"$tmpdir/usr/share/man/man1/test-fullsob.1" +echo '.so testb.1' >"$tmpdir/usr/share/man/man1/test-relsob.1" + +cat >"$tmpdir/1.exp" <<'EOF' +.TH test 1 +.SH NAME +test \- top-level test page +.SH DESCRIPTION +test +EOF + +cat >"$tmpdir/2.exp" <<'EOF' +.TH testb 1 +.SH NAME +testb \- top-level test page +.SH DESCRIPTION +test +EOF + +run $MAN -C "$tmpdir/manpath.config" test | \ + grep -v '^\.l[flt] ' >"$tmpdir/1.out" +expect_pass 'test(1) without .so link' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -C "$tmpdir/manpath.config" test-fullso | \ + grep -v '^\.l[flt] ' >"$tmpdir/2.out" +expect_pass 'test-fullso(1) .so link with section' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/2.out"' + +run $MAN -C "$tmpdir/manpath.config" test-relso | \ + grep -v '^\.l[flt] ' >"$tmpdir/3.out" +expect_pass 'test-relso(1) .so link without section' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/3.out"' + + +run $MAN -C "$tmpdir/manpath.config" testb | \ + grep -v '^\.l[flt] ' >"$tmpdir/4.out" +expect_pass 'testb(1) without .so link; gzipped' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/4.out"' + +run $MAN -C "$tmpdir/manpath.config" test-fullsob | \ + grep -v '^\.l[flt] ' >"$tmpdir/5.out" +expect_pass 'test-fullsob(1) .so link with section; gzipped' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/5.out"' + +run $MAN -C "$tmpdir/manpath.config" test-relsob | \ + grep -v '^\.l[flt] ' >"$tmpdir/6.out" +expect_pass 'test-relsob(1) .so link without section; gzipped' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/6.out"' + +finish diff --git a/src/tests/man-6 b/src/tests/man-6 new file mode 100755 index 0000000..c4301c5 --- /dev/null +++ b/src/tests/man-6 @@ -0,0 +1,28 @@ +#! /bin/sh + +# Testing empty locales on systems without /usr/share/i18n/SUPPORTED file. +# https://bugzilla.redhat.com/show_bug.cgi?id=657409 +# +# File /usr/share/i18n/SUPPORTED must be missing for this test to be effective. +# + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/share/man + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- top-level test page' + +LANG= +LC_CTYPE= +LC_ALL= +run $MAN -C "$tmpdir/manpath.config" -E UTF-8 test > /dev/null +# $? is deliberately expanded here. +expect_pass 'missing locales' "test $? -eq 0" + +finish + diff --git a/src/tests/man-7 b/src/tests/man-7 new file mode 100755 index 0000000..8c32e3d --- /dev/null +++ b/src/tests/man-7 @@ -0,0 +1,31 @@ +#! /bin/sh + +# Test for invalid DB entry. +# https://bugzilla.redhat.com/show_bug.cgi?id=841431 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} +: ${MANDB=mandb} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +MAN_TEST_DISABLE_UNDOCUMENTED=1 +export MAN_TEST_DISABLE_UNDOCUMENTED + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- top-level test page' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" + +rm -f "$tmpdir/usr/share/man/man1/test.1" + +echo "No manual entry for test" > "$tmpdir/1.exp" +LC_ALL=C run $MAN -C "$tmpdir/manpath.config" test 2> "$tmpdir/1.out" +expect_pass 'invalid DB entry' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/man-8 b/src/tests/man-8 new file mode 100755 index 0000000..cb19790 --- /dev/null +++ b/src/tests/man-8 @@ -0,0 +1,58 @@ +#! /bin/sh + +# Test additional language-specific requests for localized man pages. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +cat >"$tmpdir/fake-program" <<EOF +#! /bin/sh +exec cat +EOF +chmod +x "$tmpdir/fake-program" +PATH="$abstmpdir:$PATH" +export PATH + +cat >>"$tmpdir/manpath.config" <<EOF +DEFINE tbl fake-program +DEFINE nroff fake-program +EOF + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- top-level test page' + +write_page test 1 "$tmpdir/usr/share/man/xyzzy/man1/test.1" \ + UTF-8 '' '' 'test \- xyzzy language page for test' + +write_page xyz 1 "$tmpdir/usr/share/man/man1/xyz.1" \ + UTF-8 '' '' 'test \- top-level xyz page' + +cat >"$tmpdir/1.exp" <<'EOF' +. mso xyzzy.tmac +.hla xyzzy +test \- xyzzy language page for test +EOF + +cat >"$tmpdir/2.exp" <<'EOF' +.TH xyz 1 +test \- top-level xyz page +EOF + +run $MAN -L xyzzy_foo.bar -C "$tmpdir/manpath.config" test |\ + grep 'xyzzy' >"$tmpdir/1.out" +expect_pass 'language-specific requests for localized man page' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +run $MAN -L xyzzy_foo.bar -C "$tmpdir/manpath.config" xyz |\ + grep 'xyz' >"$tmpdir/2.out" +expect_pass 'no language-specific requests for top-level man page' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +finish diff --git a/src/tests/man-9 b/src/tests/man-9 new file mode 100755 index 0000000..4dc0331 --- /dev/null +++ b/src/tests/man-9 @@ -0,0 +1,46 @@ +#! /bin/sh + +# Testing override dir. This test covers both use cases - when override dir is +# enabled and when it's not. +# + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +if [ -n "$OVERRIDE_DIR" ]; then + OVERRIDE=$OVERRIDE_DIR +else + OVERRIDE="override" +fi + +init +fake_config /usr/share/man +mkdir -p "${tmpdir}/usr/share/man/${OVERRIDE}/man1" +MANPATH="$tmpdir/usr/share/man" +export MANPATH + + +write_page abc 1 "${tmpdir}/usr/share/man/man1/abc.1" \ + UTF-8 '' '' 'abc \- top-level test page' +write_page abc 1 "${tmpdir}/usr/share/man/${OVERRIDE}/man1/abc.1" \ + UTF-8 '' '' 'abc \- modified test page' + +if [ -n "$OVERRIDE_DIR" ]; then +cat >"$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/${OVERRIDE}/man1/abc.1 +$abstmpdir/usr/share/man/man1/abc.1 +EOF +else +cat >"$tmpdir/1.exp" <<EOF +$abstmpdir/usr/share/man/man1/abc.1 +EOF +fi + + +run $MAN -C "$tmpdir/manpath.config" -aw abc >"$tmpdir/1.out" +expect_pass 'testing override dir' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/manconv-1 b/src/tests/manconv-1 new file mode 100755 index 0000000..0ada300 --- /dev/null +++ b/src/tests/manconv-1 @@ -0,0 +1,43 @@ +#! /bin/sh + +# Test manconv's support for Emacs-style coding: tags. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANCONV=manconv} + +init + +cat >"$tmpdir/1.exp" <<'EOF' +'\" -*- coding: ISO-8859-1 +á +EOF +iconv -f UTF-8 -t ISO-8859-1 <"$tmpdir/1.exp" >"$tmpdir/1.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/1.inp" >"$tmpdir/1.out" +expect_pass 'simple coding tag' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +cat >"$tmpdir/2.exp" <<'EOF' +'\" -*- mode: troff; coding: ISO-8859-1 +á +EOF +iconv -f UTF-8 -t ISO-8859-1 <"$tmpdir/2.exp" >"$tmpdir/2.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/2.inp" >"$tmpdir/2.out" +expect_pass 'mode and coding tags' 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +cat >"$tmpdir/3.exp" <<'EOF' +'\" -*- mode: troff; coding: ISO-LATIN-1 +á +EOF +iconv -f UTF-8 -t ISO-8859-1 <"$tmpdir/3.exp" >"$tmpdir/3.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/3.inp" >"$tmpdir/3.out" +expect_pass 'iso-latin-1 coding alias' 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"' + +cat >"$tmpdir/4.inp" <<'EOF' +'\" -*- nroff -*- +EOF +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/4.inp" >"$tmpdir/4.out" +expect_pass 'preprocessor comment but no coding tag' \ + 'diff -u "$tmpdir/4.inp" "$tmpdir/4.out"' + +finish diff --git a/src/tests/manconv-2 b/src/tests/manconv-2 new file mode 100755 index 0000000..cc7a701 --- /dev/null +++ b/src/tests/manconv-2 @@ -0,0 +1,75 @@ +#! /bin/sh + +# Test manconv's handling of various odd encoding combinations. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANCONV=manconv} + +init + +(for x in $(seq 160 255); do + printf "\\$(printf %03o "$x")" +done +echo) >"$tmpdir/1.inp" + +iconv -f ISO-8859-1 -t UTF-8 <"$tmpdir/1.inp" >"$tmpdir/1.exp" +run $MANCONV -f UTF-8:ISO-8859-1 -t UTF-8 <"$tmpdir/1.inp" >"$tmpdir/1.out" +expect_pass '-f UTF-8:ISO-8859-1 -t UTF-8 on ISO-8859-1 input' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +iconv -f ISO-8859-2 -t UTF-8 <"$tmpdir/1.inp" >"$tmpdir/1-latin2.exp" +run $MANCONV -f UTF-8:ISO-8859-2 -t UTF-8 \ + <"$tmpdir/1.inp" >"$tmpdir/1-latin2.out" +expect_pass '-f UTF-8:ISO-8859-2 -t UTF-8 on ISO-8859-2 input' \ + 'diff -u "$tmpdir/1-latin2.exp" "$tmpdir/1-latin2.out"' + +(for x in $(seq 1 1000); do + printf '‐' +done +echo 'Б' | iconv -f UTF-8 -t KOI8-R +echo '‐') >"$tmpdir/2.inp" +iconv -f KOI8-R -t UTF-8 <"$tmpdir/2.inp" >"$tmpdir/2.exp" +run $MANCONV -f UTF-8:KOI8-R -t UTF-8 <"$tmpdir/2.inp" >"$tmpdir/2.out" +expect_pass '-f UTF-8:KOI8-R -t UTF-8 on KOI8-R input with UTF-8 prefix' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +(for x in $(seq 160 255); do + printf "\\$(printf %03o "$x")" +done +echo) | iconv -f ISO-8859-1 -t UTF-8 >"$tmpdir/3.inp" +run $MANCONV -f UTF-8:ISO-8859-1 -t UTF-8 <"$tmpdir/3.inp" >"$tmpdir/3.out" +expect_pass '-f UTF-8:ISO-8859-1 -t UTF-8 preserves UTF-8 input' \ + 'diff -u "$tmpdir/3.inp" "$tmpdir/3.out"' + +# U+00B7 MIDDLE DOT is not representable in ISO-8859-2, and so should be +# omitted. However, manconv should still recognise that the input was UTF-8 +# rather than falling back to ISO-8859-2. +cat >"$tmpdir/4.inp" <<'EOF' +š·ł +EOF +iconv -f UTF-8 -t ISO-8859-2 >"$tmpdir/4.exp" <<EOF +šł +EOF +run $MANCONV -f UTF-8:ISO-8859-2 -t ISO-8859-2//IGNORE \ + <"$tmpdir/4.inp" >"$tmpdir/4.out" +expect_pass 'recognises input encoding and omits invalid output character' \ + 'diff -u "$tmpdir/4.exp" "$tmpdir/4.out"' + +# 0xAE does not exist in ISO-8859-7, so manconv won't be able to recode this +# to UTF-8 without conversion errors. (In the original case where this was +# seen in the wild, the coding: tag should actually have read ISO-8859-13.) +iconv -f UTF-8 -t ISO-8859-13 >"$tmpdir/5.inp" <<'EOF' +'\" -*- coding: ISO-8859-7 +REGISTERED SIGN: ® +trailing data +EOF +iconv -f ISO-8859-7 -t UTF-8//IGNORE \ + <"$tmpdir/5.inp" >"$tmpdir/5.exp" 2>/dev/null +run $MANCONV -f UTF-8:ISO-8859-1 -t UTF-8//IGNORE \ + <"$tmpdir/5.inp" >"$tmpdir/5.out" +expect_pass 'copes with invalid input characters' \ + 'diff -u "$tmpdir/5.exp" "$tmpdir/5.out"' + +finish diff --git a/src/tests/manconv-3 b/src/tests/manconv-3 new file mode 100755 index 0000000..3557657 --- /dev/null +++ b/src/tests/manconv-3 @@ -0,0 +1,15 @@ +#! /bin/sh + +# Test manconv's handling of incomplete characters at end of file. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANCONV=manconv} + +init + +printf '\314' >"$tmpdir/1.inp" # 0xCC +expect_pass 'incomplete character at EOF' '! run $MANCONV -f EUC-JP -t UTF-8//IGNORE <"$tmpdir/1.inp" >/dev/null' + +finish diff --git a/src/tests/mandb-1 b/src/tests/mandb-1 new file mode 100755 index 0000000..0037bb4 --- /dev/null +++ b/src/tests/mandb-1 @@ -0,0 +1,24 @@ +#! /bin/sh + +# Basic mandb tests. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} +: ${ACCESSDB=accessdb} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH +db_ext="$(db_ext)" + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1.gz" UTF-8 gz t \ + 'test \- simple mandb test' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +echo 'test -> "- 1 1 MTIME A - - gz simple mandb test"' >"$tmpdir/1.exp" +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1.out" +expect_pass 'simple mandb test' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/tests/mandb-2 b/src/tests/mandb-2 new file mode 100755 index 0000000..79b6676 --- /dev/null +++ b/src/tests/mandb-2 @@ -0,0 +1,67 @@ +#! /bin/sh + +# What happens when a manual page changes from a regular file to a symbolic +# link and back? +# https://bugs.debian.org/490582 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} +: ${ACCESSDB=accessdb} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH +db_ext="$(db_ext)" + +write_page fs 5 "$tmpdir/usr/share/man/man5/fs.5.gz" \ + UTF-8 gz t 'fs \- fs(5)' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/1.exp" <<EOF +fs -> "- 5 5 MTIME A - - gz fs(5)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1.out" +expect_pass 'fs(5) setup' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +./fspause +write_page filesystems 5 "$tmpdir/usr/share/man/man5/filesystems.5.gz" \ + UTF-8 gz t 'filesystems \- filesystems(5)' +ln -sf filesystems.5.gz "$tmpdir/usr/share/man/man5/fs.5.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/2.exp" <<EOF +filesystems -> "- 5 5 MTIME A - - gz filesystems(5)" +fs -> "- 5 5 MTIME B - - gz filesystems(5)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/2.out" +expect_pass 'mandb notices regular file -> symlink' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +./fspause +ln -sf fs.5.gz "$tmpdir/usr/share/man/man5/fs2.5.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/3.exp" <<EOF +filesystems -> "- 5 5 MTIME A - - gz filesystems(5)" +fs -> "- 5 5 MTIME B - - gz filesystems(5)" +fs2 -> "- 5 5 MTIME B - - gz filesystems(5)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/3.out" +expect_pass 'mandb notices two-level symlink' \ + 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"' + +./fspause +rm -f "$tmpdir/usr/share/man/man5/fs.5.gz" +write_page fs 5 "$tmpdir/usr/share/man/man5/fs.5.gz" \ + UTF-8 gz t 'fs \- new fs(5)' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/4.exp" <<EOF +filesystems -> "- 5 5 MTIME A - - gz filesystems(5)" +fs -> "- 5 5 MTIME A - - gz new fs(5)" +fs2 -> "- 5 5 MTIME B - - gz filesystems(5)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/4.out" +expect_pass 'mandb notices symlink -> regular file' \ + 'diff -u "$tmpdir/4.exp" "$tmpdir/4.out"' + +finish diff --git a/src/tests/mandb-3 b/src/tests/mandb-3 new file mode 100755 index 0000000..23d2309 --- /dev/null +++ b/src/tests/mandb-3 @@ -0,0 +1,55 @@ +#! /bin/sh + +# Ensure that we don't repeatedly rescan when a whatis entry turns into a +# broken link. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} +: ${ACCESSDB=accessdb} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH +db_ext="$(db_ext)" + +NL=' +' + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1.gz" UTF-8 gz t \ + "test \- test page${NL}.br${NL}testlink \- link to test page" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/1.exp" <<EOF +test -> "- 1 1 MTIME A - - gz test page" +testlink -> "- 1 1 MTIME C test - gz " +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1.out" +expect_pass 'setup' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +./fspause +echo '.so nonexistent.1' | gzip -9c >"$tmpdir/usr/share/man/man1/testlink.1.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/2.exp" <<EOF +test -> "- 1 1 MTIME A - - gz test page" +testlink -> "- 1 1 MTIME C test - gz " +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/2.out" +expect_pass 'broken whatis' 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +./fspause +LC_ALL=C run $MANDB -C "$tmpdir/manpath.config" -u \ + "$tmpdir/usr/share/man" >"$tmpdir/3.out" 2>/dev/null +cat >"$tmpdir/3.exp" <<EOF +Purging old database entries in $abstmpdir/usr/share/man... +Processing manual pages under $abstmpdir/usr/share/man... +Processing manual pages under $abstmpdir/usr/share/man/cat1... +0 man subdirectories contained newer manual pages. +0 manual pages were added. +0 stray cats were added. +0 old database entries were purged. +EOF +expect_pass 'mandb does not rescan' 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"' + +finish diff --git a/src/tests/mandb-4 b/src/tests/mandb-4 new file mode 100755 index 0000000..379bbe0 --- /dev/null +++ b/src/tests/mandb-4 @@ -0,0 +1,60 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/204249 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} +: ${ACCESSDB=accessdb} + +init +fake_config /usr/share/man /usr/X11R6/man +MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/X11R6/man" +export MANPATH +db_ext="$(db_ext)" + +write_page xterm 1x "$tmpdir/usr/X11R6/man/man1/xterm.1x.gz" \ + UTF-8 gz '' 'xterm \- terminal emulator for X' +mkdir -p "$tmpdir/usr/share/man/man1" +ln -s ../../../X11R6/man/man1/xterm.1x.gz \ + "$tmpdir/usr/share/man/man1/x-terminal-emulator.1.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q \ + "$tmpdir/usr/share/man:$tmpdir/usr/X11R6/man" +cat >"$tmpdir/1-share.exp" <<EOF +x-terminal-emulator -> "- 1 1 MTIME B - - gz terminal emulator for X" +EOF +cat >"$tmpdir/1-X11R6.exp" <<EOF +xterm -> "- 1x 1 MTIME A - - gz terminal emulator for X" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1-share.out" +accessdb_filter "$tmpdir/usr/X11R6/man/index$db_ext" >"$tmpdir/1-X11R6.out" +expect_pass '/usr/share/man x-terminal-emulator -> xterm' \ + 'diff -u "$tmpdir/1-share.exp" "$tmpdir/1-share.out"' +expect_pass '/usr/X11R6/man x-terminal-emulator -> xterm' \ + 'diff -u "$tmpdir/1-X11R6.exp" "$tmpdir/1-X11R6.out"' + +./fspause +write_page uxterm 1x "$tmpdir/usr/X11R6/man/man1/uxterm.1x.gz" \ + UTF-8 gz '' \ + 'uxterm \- X terminal emulator for Unicode (UTF-8) environments' +ln -sf ../../../X11R6/man/man1/uxterm.1x.gz \ + "$tmpdir/usr/share/man/man1/x-terminal-emulator.1.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q \ + "$tmpdir/usr/share/man:$tmpdir/usr/X11R6/man" +cat >"$tmpdir/2-share.exp" <<EOF +x-terminal-emulator -> "- 1 1 MTIME B - - gz X terminal emulator for Unicode (UTF-8) environments" +EOF +cat >"$tmpdir/2-X11R6.exp" <<EOF +uxterm -> "- 1x 1 MTIME A - - gz X terminal emulator for Unicode (UTF-8) environments" +xterm -> "- 1x 1 MTIME A - - gz terminal emulator for X" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/2-share.out" +accessdb_filter "$tmpdir/usr/X11R6/man/index$db_ext" >"$tmpdir/2-X11R6.out" +expect_pass '/usr/share/man x-terminal-emulator -> uxterm' \ + 'diff -u "$tmpdir/2-share.exp" "$tmpdir/2-share.out"' +expect_pass '/usr/X11R6/man x-terminal-emulator -> uxterm' \ + 'diff -u "$tmpdir/2-X11R6.exp" "$tmpdir/2-X11R6.out"' + +finish diff --git a/src/tests/mandb-5 b/src/tests/mandb-5 new file mode 100755 index 0000000..88e6ad0 --- /dev/null +++ b/src/tests/mandb-5 @@ -0,0 +1,30 @@ +#! /bin/sh + +# Test handling of empty files. +# https://bugs.debian.org/622104 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} + +init +fake_config /usr/share/man /usr/X11R6/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH +db_ext="$(db_ext)" + +mkdir -p "$tmpdir/usr/share/man/man1" +touch "$tmpdir/usr/share/man/man1/empty.1" +gzip -9 "$tmpdir/usr/share/man/man1/empty.1" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +# $? is deliberately expanded here. +expect_pass 'empty page' "test $? -eq 0" + +./fspause +ln -s empty.1.gz "$tmpdir/usr/share/man/man1/empty2.1.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +# $? is deliberately expanded here. +expect_pass 'symlink to empty page' "test $? -eq 0" + +finish diff --git a/src/tests/mandb-6 b/src/tests/mandb-6 new file mode 100755 index 0000000..b0ec9aa --- /dev/null +++ b/src/tests/mandb-6 @@ -0,0 +1,25 @@ +#! /bin/sh + +# Test for double free or corruption crash with bogus filename and symlink of man page. +# https://bugzilla.redhat.com/show_bug.cgi?id=702904 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +mkdir -p "$tmpdir/usr/share/man/man8" +mkdir -p "$tmpdir/usr/lib/aa-bbb" +write_page test1 8 "$tmpdir/usr/lib/aa-bbb/aa-test1.8.gz" UTF-8 gz t \ + 'test1 \- testing man page' +ln -s "../../../lib/aa-bbb/aa-test1.8.gz" "$tmpdir/usr/share/man/man8/aa-test1.8.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +# $? is deliberately expanded here. +expect_pass 'double free' "test $? -eq 0" + +finish diff --git a/src/tests/mandb-7 b/src/tests/mandb-7 new file mode 100755 index 0000000..657c8e0 --- /dev/null +++ b/src/tests/mandb-7 @@ -0,0 +1,28 @@ +#! /bin/sh + +# Don't create CACHEDIR.TAG in manpath + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} + +init +fake_config /usr/share/man +mkdir -p "$tmpdir/usr/share/man" +mkdir -p "$tmpdir/usr/dir/man" +mkdir -p "$tmpdir/var/cache/man" +echo "MANDATORY_MANPATH $abstmpdir/usr/share/man" > "$tmpdir/manpath.config" +echo "MANDATORY_MANPATH $abstmpdir/usr/dir/man" >> "$tmpdir/manpath.config" +echo "MANDB_MAP $abstmpdir/usr/share/man $abstmpdir/var/cache/man" >> "$tmpdir/manpath.config" + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" UTF-8 '' '' \ + 'test \- simple mandb test' +write_page test2 1 "$tmpdir/usr/dir/man/man1/test2.1" UTF-8 '' '' \ + 'test2 \- simple mandb test' +run $MANDB -C "$tmpdir/manpath.config" -q "$tmpdir/usr/share/man:$tmpdir/usr/dir/man" +expect_pass "CACHEDIR.TAG exists" "[ -e $tmpdir/var/cache/man/CACHEDIR.TAG ]" +expect_pass "CACHEDIR.TAG doesn't exist 01" "[ ! -e $tmpdir/usr/share/man/CACHEDIR.TAG ]" +expect_pass "CACHEDIR.TAG doesn't exist 02" "[ ! -e $tmpdir/usr/dir/man/CACHEDIR.TAG ]" + +finish diff --git a/src/tests/testlib.sh b/src/tests/testlib.sh new file mode 100644 index 0000000..f23df4b --- /dev/null +++ b/src/tests/testlib.sh @@ -0,0 +1,108 @@ +failures=0 + +# Save tests the trouble of exporting variables they set when executing 'run'. +export LC_ALL + +# Isolate tests from whatever the system configuration may happen to be. +MAN_TEST_DISABLE_SYSTEM_CONFIG=1 +export MAN_TEST_DISABLE_SYSTEM_CONFIG + +init () { + # Create a temporary directory in /tmp or ./ , + # put path to it into $tmpdir and $abstmpdir, + # remove it on exit. + { + tmpdir=$(mktemp -d) && + abstmpdir="$tmpdir" && + test -d "$tmpdir" + } || { + tmpdir="tmp-${0##*/}" + abstmpdir="$(pwd -P)/$tmpdir" + mkdir "$tmpdir" + } || + exit $? + trap 'rm -rf "$tmpdir"' HUP INT QUIT TERM +} + +run () { + "$abs_top_builddir/libtool" --mode=execute \ + -dlopen "$abs_top_builddir/lib/.libs/libman.la" \ + -dlopen "$abs_top_builddir/libdb/.libs/libmandb.la" \ + "$@" +} + +fake_config () { + for dir; do + echo "MANDATORY_MANPATH $tmpdir$dir" + done >"$tmpdir/manpath.config" +} + +db_ext () { + case $DBTYPE in + gdbm) echo .db ;; + btree) echo .bt ;; + esac +} + +# Arguments: name section path encoding compression_extension preprocessor_line name_line +write_page () { + mkdir -p "${3%/*}" + >"$3.tmp1" + if [ "$6" ]; then + echo "'\\\" $6" >>"$3.tmp1" + fi + cat >>"$3.tmp1" <<EOF +.TH $1 $2 +.SH NAME +$7 +.SH DESCRIPTION +test +EOF + iconv -f UTF-8 -t "$4" <"$3.tmp1" >"$3.tmp2" + case $5 in + '') cat ;; + gz|z) gzip -9c ;; + Z) compress -c ;; + bz2) bzip2 -9c ;; + lzma) lzma -9c ;; + esac <"$3.tmp2" >"$3" + rm -f "$3.tmp1" "$3.tmp2" +} + +accessdb_filter () { + # e.g. 'test -> "- 1 1 1250702063 A - - gz simple mandb test"' + run $ACCESSDB "$1" | grep -v '^\$' | \ + sed 's/\(-> "[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \)[^ ][^ ]* [^ ][^ ]* /\1MTIME /' +} + +expect_pass () { + ret=0 + eval "$2" || ret=$? + if [ "$ret" = 0 ]; then + echo " PASS: $1" + else + failures="$(($failures + 1))" + echo " FAIL: $1" + fi +} + +skip () { + echo " SKIP: $1" + rm -rf "$abstmpdir" + exit 77 +} + +finish () { + case $failures in + 0) + rm -rf "$abstmpdir" + exit 0 + ;; + *) + if [ -z "$TEST_FAILURE_KEEP" ]; then + rm -rf "$abstmpdir" + fi + exit 1 + ;; + esac +} diff --git a/src/tests/whatis-1 b/src/tests/whatis-1 new file mode 100755 index 0000000..07b18a5 --- /dev/null +++ b/src/tests/whatis-1 @@ -0,0 +1,56 @@ +#! /bin/sh + +# Test that whatis behaves appropriately when given a path to an executable. + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MANDB=mandb} +: ${WHATIS=whatis} + +init +fake_config /usr/share/man /usr/local/man +cat >>"$tmpdir/manpath.config" <<EOF +MANPATH_MAP $tmpdir/usr/bin $tmpdir/usr/share/man +MANPATH_MAP $tmpdir/usr/local/bin $tmpdir/usr/local/man +EOF +MANPATH="$tmpdir/usr/share/man:$tmpdir/usr/local/man" +export MANPATH + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1.gz" \ + UTF-8 gz '' 'test \- /usr/bin/test' +write_page test 8 "$tmpdir/usr/local/man/man8/test.8.gz" \ + UTF-8 gz '' 'test \- /usr/local/bin/test' +mkdir -p "$tmpdir/usr/bin" "$tmpdir/usr/local/bin" +touch "$tmpdir/usr/bin/test" "$tmpdir/usr/local/bin/test" +chmod +x "$tmpdir/usr/bin/test" "$tmpdir/usr/local/bin/test" +run $MANDB -C "$tmpdir/manpath.config" -u -q \ + "$tmpdir/usr/share/man:$tmpdir/usr/local/man" + +cat >"$tmpdir/1.exp" <<EOF +test (1) - /usr/bin/test +test (8) - /usr/local/bin/test +EOF +PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" run $WHATIS \ + -C "$tmpdir/manpath.config" test >"$tmpdir/1.out" +expect_pass 'simple name returns all matches' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +cat >"$tmpdir/2.exp" <<EOF +test (1) - /usr/bin/test +EOF +PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" run $WHATIS \ + -C "$tmpdir/manpath.config" "$tmpdir/usr/bin/test" >"$tmpdir/2.out" +expect_pass '/usr/bin/test only returns appropriate match' \ + 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"' + +cat >"$tmpdir/3.exp" <<EOF +test (8) - /usr/local/bin/test +EOF +PATH="$PATH:$tmpdir/usr/bin:$tmpdir/usr/local/bin" run $WHATIS \ + -C "$tmpdir/manpath.config" "$tmpdir/usr/local/bin/test" \ + >"$tmpdir/3.out" +expect_pass '/usr/local/bin/test only returns appropriate match' \ + 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"' + +finish diff --git a/src/tests/zsoelim-1 b/src/tests/zsoelim-1 new file mode 100755 index 0000000..311bf16 --- /dev/null +++ b/src/tests/zsoelim-1 @@ -0,0 +1,61 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/503472 + +: ${srcdir=.} +. "$srcdir/testlib.sh" + +: ${MAN=man} + +init +fake_config /usr/local/man /usr/share/man +MANPATH="$tmpdir/usr/local/man:$tmpdir/usr/share/man" +export MANPATH + +cat >"$tmpdir/fake-program" <<EOF +#! /bin/sh +exec cat +EOF +chmod +x "$tmpdir/fake-program" +PATH="$abstmpdir:$PATH" +export PATH + +cat >>"$tmpdir/manpath.config" <<EOF +DEFINE tbl fake-program +DEFINE nroff fake-program +EOF + +write_page test 1 "$tmpdir/usr/share/man/man1/test.1" \ + UTF-8 '' '' 'test \- top-level test page' +echo '.so man7/test2.7' >>"$tmpdir/usr/share/man/man1/test.1" +write_page test2 7 "$tmpdir/usr/local/man/man7/test2.7" \ + UTF-8 '' '' 'test2 \- second-level local test page' +echo '.so test3.1' >>"$tmpdir/usr/local/man/man7/test2.7" +write_page test3 1 "$tmpdir/usr/local/man/man1/test3.1" \ + UTF-8 '' '' 'test3 \- third-level local test page' +write_page test3 1 "$tmpdir/usr/share/man/man1/test3.1" \ + UTF-8 '' '' 'test3 \- third-level test page' +cat >"$tmpdir/1.exp" <<'EOF' +.TH test 1 +.SH NAME +test \- top-level test page +.SH DESCRIPTION +test +.TH test2 7 +.SH NAME +test2 \- second-level local test page +.SH DESCRIPTION +test +.TH test3 1 +.SH NAME +test3 \- third-level test page +.SH DESCRIPTION +test +EOF +run $MAN -C "$tmpdir/manpath.config" test | \ + grep -v '^\.l[flt] ' >"$tmpdir/1.out" +expect_pass 'test(1) expanded correctly' \ + 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"' + +finish diff --git a/src/ult_src.c b/src/ult_src.c new file mode 100644 index 0000000..15c2e52 --- /dev/null +++ b/src/ult_src.c @@ -0,0 +1,405 @@ +/* + * ult_src.c: Find the ultimate source of a page + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, + * 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * code to seek out the original (ultimate) source man file for + * any specified man file. Soft and hard links and .so inclusions + * are traced. Use: reduce amount of cat files to a minimum. + * + * Mon May 2 11:14:28 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <assert.h> +#include <dirent.h> +#include <unistd.h> + +#include "canonicalize.h" +#include "dirname.h" +#include "error.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "pipeline.h" +#include "decompress.h" + +#include "globbing.h" +#include "ult_src.h" + +/* Find minimum value hard link filename for given file and inode. + * Returns a newly allocated string. + */ +static char *ult_hardlink (const char *fullpath, ino_t inode) +{ + DIR *mdir; + struct dirent *manlist; + char *base, *dir, *ret; + const char *slash; + + slash = strrchr (fullpath, '/'); + assert (slash); + dir = xstrndup (fullpath, slash - fullpath); + base = xstrdup (++slash); + + mdir = opendir (dir); + if (mdir == NULL) { + if (quiet < 2) + error (0, errno, _("can't search directory %s"), dir); + free (dir); + free (base); + return NULL; + } + + while ((manlist = readdir (mdir))) { + if (manlist->d_ino == inode && + strcmp (base, manlist->d_name) > 0) { + free (base); + base = xstrdup (manlist->d_name); + debug ("ult_hardlink: (%s)\n", base); + } + } + closedir (mdir); + + /* If we already are the link with the smallest name value */ + /* return NULL */ + + if (strcmp (base, slash) == 0) { + free (dir); + free (base); + return NULL; + } + + ret = xasprintf ("%s/%s", dir, base); + free (dir); + free (base); + return ret; +} + +/* Resolve all symbolic links within 'fullpath'. + * Returns a newly allocated string. + */ +static char *ult_softlink (const char *fullpath) +{ + char *resolved_path; + + resolved_path = canonicalize_file_name (fullpath); + if (!resolved_path) { + /* discard the unresolved path */ + if (quiet < 2) { + if (errno == ENOENT) + error (0, 0, + _("warning: %s is a dangling symlink"), + fullpath); + else + error (0, errno, _("can't resolve %s"), + fullpath); + } + return NULL; + } + + debug ("ult_softlink: (%s)\n", resolved_path); + + return resolved_path; +} + +/* Test 'buffer' to see if it contains a .so include. If so and it's not an + * absolute filename, return newly allocated string whose contents are the + * include. + */ +static char *test_for_include (const char *buffer) +{ + if (!buffer) + return NULL; + + /* strip out any leading whitespace (if any) */ + while (CTYPE (isspace, *buffer)) + buffer++; + + /* see if the `command' is a .so */ + if (strncmp (buffer, ".so", 3) == 0) { + buffer += 3; + + /* strip out any whitespace between the command and + it's argumant */ + while (CTYPE (isspace, *buffer)) + buffer++; + + /* If .so's argument is an absolute filename, it could be + * either (i) a macro inclusion, (ii) a non local manual page + * or (iii) a (somewhat bogus) reference to a local manual + * page. + * + * If (i) or (ii), we must not follow the reference. (iii) is + * a problem with the manual page, thus we don't want to + * follow any absolute inclusions in our quest for the + * ultimate source file */ + if (*buffer != '/') { + const char *end = buffer; + while (*end && !CTYPE (isspace, *end)) + ++end; + return xstrndup (buffer, end - buffer); + } + } + return NULL; +} + +static char *find_include (const char *name, const char *path, + const char *include) +{ + char *ret; + char *dirname; + char *temp_file; + + /* Restore the original path from before ult_softlink() etc., in + * case it went outside the mantree. + */ + ret = xasprintf ("%s/%s", path, include); + + /* If the original path from above doesn't exist, try to create new + * path as if the "include" was relative to the current man page. + */ + if (CAN_ACCESS (ret, F_OK)) + return ret; + + dirname = dir_name (name); + temp_file = xasprintf ("%s/%s", dirname, include); + free (dirname); + + if (CAN_ACCESS (temp_file, F_OK)) { + /* Just plain include. */ + free (ret); + ret = canonicalize_file_name (temp_file); + } else { + /* Try globbing - the file suffix might be missing. */ + char *temp_file_asterisk = xasprintf ("%s*", temp_file); + char **candidate_files = expand_path (temp_file_asterisk); + int i; + + free (temp_file_asterisk); + if (CAN_ACCESS (candidate_files[0], F_OK)) { + free (ret); + ret = canonicalize_file_name (candidate_files[0]); + } + for (i = 0; candidate_files[i]; i++) + free (candidate_files[i]); + free (candidate_files); + } + free (temp_file); + + return ret; +} + +static void ult_trace (struct ult_trace *trace, const char *s) +{ + if (!trace) + return; + if (trace->len >= trace->max) { + trace->max *= 2; + trace->names = xnrealloc (trace->names, trace->max, + sizeof (char *)); + } + trace->names[trace->len++] = xstrdup (s); +} + +void free_ult_trace (struct ult_trace *trace) +{ + size_t i; + for (i = 0; i < trace->len; ++i) + free (trace->names[i]); + free (trace->names); +} + +/* + * recursive function which finds the ultimate source file by following + * any ".so filename" directives in the first line of the man pages. + * Also (optionally) traces symlinks and hard links(!). + * + * name is full pathname, path is the MANPATH directory (/usr/man) + * flags is a combination of SO_LINK | SOFT_LINK | HARD_LINK + */ +const char *ult_src (const char *name, const char *path, + struct stat *buf, int flags, struct ult_trace *trace) +{ + static char *base; /* must be static */ + static short recurse; /* must be static */ + + /* initialise the function */ + + if (trace) { + if (!trace->names) { + trace->len = 0; + trace->max = 16; + trace->names = XNMALLOC (trace->max, char *); + } + ult_trace (trace, name); + } + + /* as ult_softlink() & ult_hardlink() do all of their respective + * resolving in one call, only need to sort them out once + */ + + if (recurse == 0) { + struct stat new_buf; + free (base); + base = xstrdup (name); + + debug ("\nult_src: File %s in mantree %s\n", name, path); + + /* If we don't have a buf, allocate and assign one */ + if (!buf && ((flags & SOFT_LINK) || (flags & HARD_LINK))) { + buf = &new_buf; + if (lstat (base, buf) == -1) { + if (quiet < 2) + error (0, errno, _("can't resolve %s"), + base); + return NULL; + } + } + + /* Permit semi local (inter-tree) soft links */ + if (flags & SOFT_LINK) { + assert (buf); /* initialised above */ + if (S_ISLNK (buf->st_mode)) { + /* Is a symlink, resolve it. */ + char *softlink = ult_softlink (base); + if (softlink) { + free (base); + base = softlink; + } else + return NULL; + } + } + + /* Only deal with local (inter-dir) HARD links */ + if (flags & HARD_LINK) { + assert (buf); /* initialised above */ + if (buf->st_nlink > 1) { + /* Has HARD links, find least value */ + char *hardlink = ult_hardlink (base, + buf->st_ino); + if (hardlink) { + free (base); + base = hardlink; + } + } + } + } + + /* keep a check on recursion level */ + else if (recurse == 10) { + if (quiet < 2) + error (0, 0, _("%s is self referencing"), name); + return NULL; + } + + if (flags & SO_LINK) { + const char *buffer; + char *decomp_base; + pipeline *decomp; + char *include; +#ifdef COMP_SRC + struct stat st; + + if (stat (base, &st) < 0) { + struct compression *comp = comp_file (base); + + if (comp) { + free (base); + base = comp->stem; + comp->stem = NULL; /* steal memory */ + } else { + if (quiet < 2) + error (0, errno, _("can't open %s"), + base); + return NULL; + } + } +#endif + + /* base may change for recursive calls to ult_src, but + * decompress_open doesn't keep its own copy. + */ + decomp_base = xstrdup (base); + decomp = decompress_open (decomp_base); + if (!decomp) { + if (quiet < 2) + error (0, errno, _("can't open %s"), base); + free (decomp_base); + return NULL; + } + pipeline_start (decomp); + + /* make sure that we skip over any comments */ + do { + buffer = pipeline_readline (decomp); + } while (buffer && STRNEQ (buffer, ".\\\"", 3)); + + include = test_for_include (buffer); + if (include) { + char *new_name; + const char *ult; + + free (base); + base = find_include (name, path, include); + free (include); + + debug ("ult_src: points to %s\n", base); + + recurse++; + /* Take a copy; it's unwise to pass base directly to + * a recursive call, as it may be freed. + */ + new_name = xstrdup (base); + ult = ult_src (new_name, path, NULL, flags, trace); + free (new_name); + recurse--; + + pipeline_wait (decomp); + pipeline_free (decomp); + free (decomp_base); + return ult; + } + + pipeline_wait (decomp); + pipeline_free (decomp); + free (decomp_base); + } + + /* We have the ultimate source */ + if (trace) + ult_trace (trace, base); + return base; +} diff --git a/src/ult_src.h b/src/ult_src.h new file mode 100644 index 0000000..6fad470 --- /dev/null +++ b/src/ult_src.h @@ -0,0 +1,43 @@ +/* + * ult_src.h: Interface to finding the ultimate source of a page + * + * Copyright (C) 1990, 1991 John W. Eaton. + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2002, 2003, 2011 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define SO_LINK 0001 +#define SOFT_LINK 0002 +#define HARD_LINK 0004 + +/* Trace of the link chain from a given file. Any names listed here should + * not have WHATIS_MAN entries created for them. + */ +struct ult_trace { + char **names; + size_t len; + size_t max; +}; + +struct stat; + +extern const char *ult_src (const char *name, const char *path, + struct stat *buf, int flags, + struct ult_trace *trace); +extern void free_ult_trace (struct ult_trace *trace); diff --git a/src/whatis.c b/src/whatis.c new file mode 100644 index 0000000..ee43f10 --- /dev/null +++ b/src/whatis.c @@ -0,0 +1,1009 @@ +/* + * whatis.c: search the index or whatis database(s) for words. + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011, + * 2012 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * routines for whatis and apropos programs. Whatis looks up the + * keyword for the description, apropos searches the entire database + * for word matches. + * + * Mon Aug 8 20:35:30 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * CJW: Add more safety in the face of corrupted databases. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#ifdef HAVE_ICONV +# include <iconv.h> +#endif /* HAVE_ICONV */ + +#include <sys/types.h> +#include <sys/stat.h> +#include "regex.h" + +#include "argp.h" +#include "dirname.h" +#include "fnmatch.h" +#include "progname.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "cleanup.h" +#include "error.h" +#include "pipeline.h" +#include "pathsearch.h" +#include "linelength.h" +#include "hashtable.h" +#include "lower.h" +#include "wordfnmatch.h" +#include "xregcomp.h" +#include "encodings.h" +#include "sandbox.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "manp.h" + +static char *manpathlist[MAXDIRS]; + +extern char *user_config_file; +static char **keywords; +static int num_keywords; + +int am_apropos; +char *database; +int quiet = 1; +man_sandbox *sandbox; + +#ifdef HAVE_ICONV +iconv_t conv_to_locale; +#endif /* HAVE_ICONV */ + +static regex_t *preg; +static int regex_opt; +static int exact; + +static int wildcard; + +static int require_all; + +static int long_output; + +static char **sections; + +static char *manp = NULL; +static const char *alt_systems = ""; +static const char *locale = NULL; +static char *multiple_locale = NULL, *internal_locale; + +static struct hashtable *display_seen = NULL; + +const char *argp_program_version; /* initialised in main */ +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("KEYWORD..."); +static const char apropos_doc[] = "\v" N_("The --regex option is enabled by default."); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "verbose", 'v', 0, 0, N_("print verbose warning messages") }, + { "regex", 'r', 0, 0, N_("interpret each keyword as a regex"), 10 }, + { "exact", 'e', 0, 0, N_("search each keyword for exact match") }, /* apropos only */ + { "wildcard", 'w', 0, 0, N_("the keyword(s) contain wildcards") }, + { "and", 'a', 0, 0, N_("require all keywords to match"), 20 }, /* apropos only */ + { "long", 'l', 0, 0, N_("do not trim output to terminal width"), 30 }, + { "sections", 's', N_("LIST"), 0, N_("search only these sections (colon-separated)"), 40 }, + { "section", 0, 0, OPTION_ALIAS }, + { "systems", 'm', N_("SYSTEM"), 0, N_("use manual pages from other systems") }, + { "manpath", 'M', N_("PATH"), 0, N_("set search path for manual pages to PATH") }, + { "locale", 'L', N_("LOCALE"), 0, N_("define the locale for this search") }, + { "config-file", 'C', N_("FILE"), 0, N_("use this user configuration file") }, + { "whatis", 'f', 0, OPTION_HIDDEN, 0 }, + { "apropos", 'k', 0, OPTION_HIDDEN, 0 }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static char **split_sections (const char *sections_str) +{ + int i = 0; + char *str = xstrdup (sections_str); + const char *section; + char **out = NULL; + + /* Although this is documented as colon-separated, at least Solaris + * man's -s option takes a comma-separated list, so we accept that + * too for compatibility. + */ + for (section = strtok (str, ":,"); section; + section = strtok (NULL, ":,")) { + out = xnrealloc (out, i + 2, sizeof *out); + out[i++] = xstrdup (section); + } + if (i) + out[i] = NULL; + + free (str); + return out; +} + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'v': + quiet = 0; + return 0; + case 'r': + regex_opt = 1; + return 0; + case 'e': + /* Only makes sense for apropos, but has + * historically been accepted by whatis anyway. + */ + regex_opt = 0; + exact = 1; + return 0; + case 'w': + regex_opt = 0; + wildcard = 1; + return 0; + case 'a': + if (am_apropos) + require_all = 1; + else + argp_usage (state); + return 0; + case 'l': + long_output = 1; + return 0; + case 's': + sections = split_sections (arg); + return 0; + case 'm': + alt_systems = arg; + return 0; + case 'M': + manp = xstrdup (arg); + return 0; + case 'L': + locale = arg; + return 0; + case 'C': + user_config_file = arg; + return 0; + case 'f': + /* helpful override if program name detection fails */ + am_apropos = 0; + return 0; + case 'k': + /* helpful override if program name detection fails */ + am_apropos = 1; + return 0; + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP & + ~ARGP_HELP_PRE_DOC); + break; + case ARGP_KEY_ARGS: + keywords = state->argv + state->next; + num_keywords = state->argc - state->next; + return 0; + case ARGP_KEY_NO_ARGS: + /* Make sure that we have a keyword! */ + printf (_("%s what?\n"), program_name); + exit (FAIL); + case ARGP_KEY_SUCCESS: + if (am_apropos && !exact && !wildcard) + regex_opt = 1; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, + void *input ATTRIBUTE_UNUSED) +{ + switch (key) { + case ARGP_KEY_HELP_PRE_DOC: + /* We have no pre-options help text, but the input + * text may contain header junk due to gettext (""). + */ + return NULL; + default: + return (char *) text; + } +} + +static struct argp apropos_argp = { options, parse_opt, args_doc, apropos_doc, + 0, help_filter }; +static struct argp whatis_argp = { options, parse_opt, args_doc }; + +static char *locale_manpath (const char *manpath) +{ + char *all_locales; + char *new_manpath; + + if (multiple_locale && *multiple_locale) { + if (internal_locale && *internal_locale) + all_locales = xasprintf ("%s:%s", multiple_locale, + internal_locale); + else + all_locales = xstrdup (multiple_locale); + } else { + if (internal_locale && *internal_locale) + all_locales = xstrdup (internal_locale); + else + all_locales = NULL; + } + + new_manpath = add_nls_manpaths (manpath, all_locales); + free (all_locales); + + return new_manpath; +} + +#ifdef HAVE_ICONV +static char *simple_convert (iconv_t conv, char *string) +{ + if (conv != (iconv_t) -1) { + size_t string_conv_alloc = strlen (string) + 1; + char *string_conv = xmalloc (string_conv_alloc); + for (;;) { + char *inptr = string, *outptr = string_conv; + size_t inleft = strlen (string); + size_t outleft = string_conv_alloc - 1; + if (iconv (conv, (ICONV_CONST char **) &inptr, &inleft, + &outptr, &outleft) == (size_t) -1 && + errno == E2BIG) { + string_conv_alloc <<= 1; + string_conv = xrealloc (string_conv, + string_conv_alloc); + } else { + /* Either we succeeded, or we've done our + * best; go ahead and print what we've got. + */ + string_conv[string_conv_alloc - 1 - outleft] = + '\0'; + break; + } + } + return string_conv; + } else + return xstrdup (string); +} +#else /* !HAVE_ICONV */ +# define simple_convert(conv, string) xstrdup (string) +#endif /* HAVE_ICONV */ + +/* Do the old thing, if we cannot find the relevant database. + * This invokes grep once per argument; we can't do much about this because + * we need to know which arguments failed. The only way to speed this up + * would be to implement grep internally, but it hardly seems worth it for a + * legacy mechanism. + */ +static void use_grep (const char * const *pages, int num_pages, char *manpath, + int *found) +{ + char *whatis_file = xasprintf ("%s/whatis", manpath); + + if (CAN_ACCESS (whatis_file, R_OK)) { + const char *flags; + int i; + + if (am_apropos) { + if (regex_opt) + flags = get_def_user ( + "apropos_regex_grep_flags", + APROPOS_REGEX_GREP_FLAGS); + else + flags = get_def_user ("apropos_grep_flags", + APROPOS_GREP_FLAGS); + } else + flags = get_def_user ("whatis_grep_flags", + WHATIS_GREP_FLAGS); + + for (i = 0; i < num_pages; ++i) { + pipeline *grep_pl; + pipecmd *grep_cmd; + char *anchored_page; + + if (am_apropos) + anchored_page = xstrdup (pages[i]); + else + anchored_page = xasprintf ("^%s", pages[i]); + + grep_cmd = pipecmd_new_argstr (get_def_user ("grep", + GREP)); + pipecmd_argstr (grep_cmd, flags); + pipecmd_args (grep_cmd, anchored_page, whatis_file, + (void *) 0); + pipecmd_pre_exec (grep_cmd, sandbox_load, sandbox_free, + sandbox); + grep_pl = pipeline_new_commands (grep_cmd, (void *) 0); + + if (pipeline_run (grep_pl) == 0) + found[i] = 1; + + free (anchored_page); + } + } else + debug ("warning: can't read the fallback whatis text database " + "%s/whatis\n", manpath); + + free (whatis_file); +} + +static struct mandata *resolve_pointers (MYDBM_FILE dbf, struct mandata *info, + const char *page) +{ + int rounds; + const char *newpage; + + if (*(info->pointer) == '-' || + ((!info->name || STREQ (info->name, page)) && + STREQ (info->pointer, page))) + return info; + + /* Now we have to work through pointers. The limit of 10 is fairly + * arbitrary: it's just there to avoid an infinite loop. + */ + newpage = info->pointer; + info = dblookup_exact (dbf, newpage, info->ext, 1); + for (rounds = 0; rounds < 10; rounds++) { + struct mandata *newinfo; + + /* If the pointer lookup fails, do nothing. */ + if (!info) + return NULL; + + if (*(info->pointer) == '-' || + ((!info->name || STREQ (info->name, newpage)) && + STREQ (info->pointer, newpage))) + return info; + + newinfo = dblookup_exact (dbf, info->pointer, info->ext, 1); + free_mandata_struct (info); + info = newinfo; + } + + if (!quiet) + error (0, 0, _("warning: %s contains a pointer loop"), page); + return NULL; +} + +/* fill_in_whatis() is really a ../libdb/db_lookup.c routine but whatis.c + is the only file that actually requires access to the whatis text... */ + +/* Take mandata struct (earlier returned from a dblookup()) and return + the relative whatis */ +static char *get_whatis (struct mandata *info, const char *page) +{ + if (!info) + return xstrdup (_("(unknown subject)")); + + /* See if we need to fill in the whatis here. */ + if (info->whatis != NULL && *(info->whatis)) + return xstrdup (info->whatis); + if (!quiet && *(info->pointer) != '-') + error (0, 0, _("warning: %s contains a pointer loop"), + page); + return xstrdup (_("(unknown subject)")); +} + +/* print out any matches found */ +static void display (MYDBM_FILE dbf, struct mandata *info, const char *page) +{ + struct mandata *newinfo; + char *string, *whatis, *string_conv; + const char *page_name; + char *key; + int line_len, rest; + + newinfo = resolve_pointers (dbf, info, page); + whatis = get_whatis (newinfo, page); + if (newinfo == NULL) + newinfo = info; + + dbprintf (newinfo); + + if (newinfo->name) + page_name = newinfo->name; + else + page_name = page; + + key = xasprintf ("%s (%s)", page_name, newinfo->ext); + if (hashtable_lookup_structure (display_seen, key, strlen (key))) + goto out; + hashtable_install (display_seen, key, strlen (key), NULL); + + line_len = get_line_length (); + + if (!long_output && strlen (page_name) > (size_t) (line_len / 2)) + string = xasprintf ("%.*s...", line_len / 2 - 3, page_name); + else + string = xstrdup (page_name); + string = appendstr (string, " (", newinfo->ext, ")", (void *) 0); + if (!STREQ (newinfo->pointer, "-") && !STREQ (newinfo->pointer, page)) + string = appendstr (string, " [", newinfo->pointer, "]", + (void *) 0); + + if (strlen (string) < (size_t) 20) { + int i; + string = xrealloc (string, 21); + for (i = strlen (string); i < 20; ++i) + string[i] = ' '; + string[i] = '\0'; + } + string = appendstr (string, " - ", (void *) 0); + + rest = line_len - strlen (string); + if (!long_output && strlen (whatis) > (size_t) rest) { + whatis[rest - 3] = '\0'; + string = appendstr (string, whatis, "...\n", (void *) 0); + } else + string = appendstr (string, whatis, "\n", (void *) 0); + + string_conv = simple_convert (conv_to_locale, string); + fputs (string_conv, stdout); + + free (string_conv); + free (string); + +out: + free (key); + free (whatis); + if (newinfo != info) + free_mandata_struct (newinfo); +} + +/* lookup the page and display the results */ +static int do_whatis_section (MYDBM_FILE dbf, + const char *page, const char *section) +{ + struct mandata *info; + int count = 0; + + info = dblookup_all (dbf, page, section, 0); + while (info) { + struct mandata *pinfo; + + display (dbf, info, page); + count++; + pinfo = info->next; /* go on to next structure */ + free_mandata_elements (info); + free (info); + info = pinfo; + } + return count; +} + +static int suitable_manpath (const char *manpath, const char *page_dir) +{ + char *page_manp, *pm; + char *page_manpathlist[MAXDIRS], **mp; + int ret; + + page_manp = get_manpath_from_path (page_dir, 0); + if (!page_manp || !*page_manp) { + free (page_manp); + return 0; + } + pm = locale_manpath (page_manp); + free (page_manp); + page_manp = pm; + create_pathlist (page_manp, page_manpathlist); + + ret = 0; + for (mp = page_manpathlist; *mp; ++mp) { + if (STREQ (*mp, manpath)) { + ret = 1; + break; + } + } + + for (mp = page_manpathlist; *mp; ++mp) + free (*mp); + free (page_manp); + return ret; +} + +static void do_whatis (MYDBM_FILE dbf, + const char * const *pages, int num_pages, + const char *manpath, int *found) +{ + int i; + + for (i = 0; i < num_pages; ++i) { + char *page = xstrdup (pages[i]); + struct stat st; + + if (strchr (page, '/') && stat (page, &st) == 0 && + !S_ISDIR (st.st_mode) && + st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { + /* Perhaps an executable. If its directory is on + * $PATH, then we only want to process this page for + * matching manual hierarchies. + */ + char *page_dir = dir_name (page); + + if (directory_on_path (page_dir)) { + if (suitable_manpath (manpath, page_dir)) { + char *old_page = page; + page = base_name (old_page); + free (old_page); + } else { + debug ("%s not on manpath for %s\n", + manpath, page); + free (page_dir); + free (page); + continue; + } + } + free (page_dir); + } + + if (sections) { + char * const *section; + + for (section = sections; *section; ++section) { + if (do_whatis_section (dbf, page, *section)) + found[i] = 1; + } + } else { + if (do_whatis_section (dbf, page, NULL)) + found[i] = 1; + } + + free (page); + } +} + +static int any_set (int num_pages, int *found_here) +{ + int i; + + for (i = 0; i < num_pages; ++i) + if (found_here[i]) + return 1; + return 0; +} + +static int all_set (int num_pages, int *found_here) +{ + int i; + + for (i = 0; i < num_pages; ++i) + if (!found_here[i]) + return 0; + return 1; +} + +static void parse_name (const char * const *pages, int num_pages, + const char *dbname, int *found, int *found_here) +{ + int i; + + if (regex_opt) { + for (i = 0; i < num_pages; ++i) { + if (regexec (&preg[i], dbname, 0, + (regmatch_t *) 0, 0) == 0) + found[i] = found_here[i] = 1; + } + return; + } + + if (am_apropos && !wildcard) { + char *lowdbname = lower (dbname); + + for (i = 0; i < num_pages; ++i) { + if (STREQ (lowdbname, pages[i])) + found[i] = found_here[i] = 1; + } + free (lowdbname); + return; + } + + for (i = 0; i < num_pages; ++i) { + if (fnmatch (pages[i], dbname, 0) == 0) + found[i] = found_here[i] = 1; + } +} + +/* return 1 on word match */ +static int match (const char *lowpage, const char *whatis) +{ + char *lowwhatis = lower (whatis); + size_t len = strlen (lowpage); + char *p, *begin; + + begin = lowwhatis; + + /* check for string match, then see if it is a _word_ */ + while (lowwhatis && (p = strstr (lowwhatis, lowpage))) { + char *left = p - 1; + char *right = p + len; + + if ((p == begin || (!CTYPE (islower, *left) && *left != '_')) && + (!*right || (!CTYPE (islower, *right) && *right != '_'))) { + free (begin); + return 1; + } + lowwhatis = p + 1; + } + + free (begin); + return 0; +} + +static void parse_whatis (const char * const *pages, char * const *lowpages, + int num_pages, const char *whatis, + int *found, int *found_here) +{ + int i; + + if (regex_opt) { + for (i = 0; i < num_pages; ++i) { + if (regexec (&preg[i], whatis, 0, + (regmatch_t *) 0, 0) == 0) + found[i] = found_here[i] = 1; + } + return; + } + + if (wildcard) { + for (i = 0; i < num_pages; ++i) { + if (exact) { + if (fnmatch (pages[i], whatis, 0) == 0) + found[i] = found_here[i] = 1; + } else { + if (word_fnmatch (pages[i], whatis)) + found[i] = found_here[i] = 1; + } + } + return; + } + + for (i = 0; i < num_pages; ++i) { + if (match (lowpages[i], whatis)) + found[i] = found_here[i] = 1; + } +} + +/* cjwatson: Optimized functions don't seem to be correct in some + * circumstances; disabled for now. + */ +#undef BTREE + +/* scan for the page, print any matches */ +static void do_apropos (MYDBM_FILE dbf, + const char * const *pages, int num_pages, int *found) +{ + datum key, cont; + char **lowpages; + int *found_here; + int (*combine) (int, int *); + int i; +#ifndef BTREE + datum nextkey; +#else /* BTREE */ + int end; +#endif /* !BTREE */ + + lowpages = XNMALLOC (num_pages, char *); + for (i = 0; i < num_pages; ++i) { + lowpages[i] = lower (pages[i]); + debug ("lower(%s) = \"%s\"\n", pages[i], lowpages[i]); + } + found_here = XNMALLOC (num_pages, int); + combine = require_all ? all_set : any_set; + +#ifndef BTREE + key = MYDBM_FIRSTKEY (dbf); + while (MYDBM_DPTR (key)) { + cont = MYDBM_FETCH (dbf, key); +#else /* BTREE */ + end = btree_nextkeydata (dbf, &key, &cont); + while (!end) { +#endif /* !BTREE */ + char *tab; + struct mandata info; + + memset (&info, 0, sizeof (info)); + + /* bug#4372, NULL pointer dereference in MYDBM_DPTR (cont), + * fix by dassen@wi.leidenuniv.nl (J.H.M.Dassen), thanx Ray. + * cjwatson: In that case, complain and exit, otherwise we + * might loop (bug #95052). + */ + if (!MYDBM_DPTR (cont)) + { + debug ("key was %s\n", MYDBM_DPTR (key)); + error (FATAL, 0, + _("Database %s corrupted; rebuild with " + "mandb --create"), + database); + } + + if (*MYDBM_DPTR (key) == '$') + goto nextpage; + + if (*MYDBM_DPTR (cont) == '\t') + goto nextpage; + + /* a real page */ + + split_content (MYDBM_DPTR (cont), &info); + + /* If there are sections given, does any of them match + * either the section or extension of this page? + */ + if (sections) { + char * const *section; + int matched = 0; + + for (section = sections; *section; ++section) { + if (STREQ (*section, info.sec) || + STREQ (*section, info.ext)) { + matched = 1; + break; + } + } + + if (!matched) + goto nextpage; + } + + tab = strrchr (MYDBM_DPTR (key), '\t'); + if (tab) + *tab = '\0'; + + memset (found_here, 0, num_pages * sizeof (*found_here)); + if (am_apropos) { + char *whatis; + + parse_name ((const char **) lowpages, num_pages, + MYDBM_DPTR (key), found, found_here); + whatis = info.whatis ? xstrdup (info.whatis) : NULL; + if (!combine (num_pages, found_here) && whatis) + parse_whatis (pages, lowpages, num_pages, + whatis, found, found_here); + free (whatis); + } else + parse_name (pages, num_pages, + MYDBM_DPTR (key), found, found_here); + if (combine (num_pages, found_here)) + display (dbf, &info, MYDBM_DPTR (key)); + + if (tab) + *tab = '\t'; +nextpage: +#ifndef BTREE + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (cont); + MYDBM_FREE_DPTR (key); + key = nextkey; +#else /* BTREE */ + MYDBM_FREE_DPTR (cont); + MYDBM_FREE_DPTR (key); + end = btree_nextkeydata (dbf, &key, &cont); +#endif /* !BTREE */ + info.addr = NULL; /* == MYDBM_DPTR (cont), freed above */ + free_mandata_elements (&info); + } + + free (found_here); + + for (i = 0; i < num_pages; ++i) + free (lowpages[i]); + free (lowpages); +} + +/* loop through the man paths, searching for a match */ +static int search (const char * const *pages, int num_pages) +{ + int *found = XCALLOC (num_pages, int); + char *catpath, **mp; + int any_found, i; + + for (mp = manpathlist; *mp; mp++) { + MYDBM_FILE dbf; + + catpath = get_catpath (*mp, SYSTEM_CAT | USER_CAT); + + if (catpath) { + database = mkdbname (catpath); + free (catpath); + } else + database = mkdbname (*mp); + + debug ("path=%s\n", *mp); + + dbf = MYDBM_RDOPEN (database); + if (dbf && dbver_rd (dbf)) { + MYDBM_CLOSE (dbf); + dbf = NULL; + } + if (!dbf) { + use_grep (pages, num_pages, *mp, found); + continue; + } + + if (am_apropos) + do_apropos (dbf, pages, num_pages, found); + else { + if (regex_opt || wildcard) + do_apropos (dbf, pages, num_pages, found); + else + do_whatis (dbf, pages, num_pages, *mp, found); + } + free (database); + database = NULL; + MYDBM_CLOSE (dbf); + } + + chkr_garbage_detector (); + + any_found = 0; + for (i = 0; i < num_pages; ++i) { + if (found[i]) + any_found = 1; + else + fprintf (stderr, _("%s: nothing appropriate.\n"), + pages[i]); + } + + free (found); + return any_found; +} + +int main (int argc, char *argv[]) +{ + char *program_base_name; +#ifdef HAVE_ICONV + char *locale_charset; +#endif + int status = OK; + + set_program_name (argv[0]); + program_base_name = base_name (program_name); + if (STREQ (program_base_name, APROPOS_NAME)) { + am_apropos = 1; + argp_program_version = "apropos " PACKAGE_VERSION; + } else { + struct argp_option *optionp; + am_apropos = 0; + argp_program_version = "whatis " PACKAGE_VERSION; + for (optionp = (struct argp_option *) whatis_argp.options; + optionp->name || optionp->key || optionp->arg || + optionp->flags || optionp->doc || optionp->group; + ++optionp) { + if (!optionp->name) + continue; + if (STREQ (optionp->name, "exact") || + STREQ (optionp->name, "and")) + optionp->flags |= OPTION_HIDDEN; + } + } + free (program_base_name); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + + internal_locale = setlocale (LC_MESSAGES, NULL); + /* Use LANGUAGE only when LC_MESSAGES locale category is + * neither "C" nor "POSIX". */ + if (internal_locale && strcmp (internal_locale, "C") && + strcmp (internal_locale, "POSIX")) + multiple_locale = getenv ("LANGUAGE"); + internal_locale = xstrdup (internal_locale ? internal_locale : "C"); + + if (argp_parse (am_apropos ? &apropos_argp : &whatis_argp, argc, argv, + 0, 0, 0)) + exit (FAIL); + + read_config_file (user_config_file != NULL); + + /* close this locale and reinitialise if a new locale was + issued as an argument or in $MANOPT */ + if (locale) { + free (internal_locale); + internal_locale = setlocale (LC_ALL, locale); + if (internal_locale) + internal_locale = xstrdup (internal_locale); + else + internal_locale = xstrdup (locale); + + debug ("main(): locale = %s, internal_locale = %s\n", + locale, internal_locale); + if (internal_locale) { + setenv ("LANGUAGE", internal_locale, 1); + locale_changed (); + multiple_locale = NULL; + } + } + + /* sort out the internal manpath */ + if (manp == NULL) + manp = locale_manpath (get_manpath (alt_systems)); + else + free (get_manpath (NULL)); + + create_pathlist (manp, manpathlist); + + display_seen = hashtable_create (&null_hashtable_free); + +#ifdef HAVE_ICONV + locale_charset = xasprintf ("%s//IGNORE", get_locale_charset ()); + conv_to_locale = iconv_open (locale_charset, "UTF-8"); + free (locale_charset); +#endif /* HAVE_ICONV */ + + if (regex_opt) { + int i; + preg = XNMALLOC (num_keywords, regex_t); + for (i = 0; i < num_keywords; ++i) + xregcomp (&preg[i], keywords[i], + REG_EXTENDED | REG_NOSUB | REG_ICASE); + } + + if (!search ((const char **) keywords, num_keywords)) + status = NOT_FOUND; + + if (regex_opt) { + int i; + for (i = 0; i < num_keywords; ++i) + regfree (&preg[i]); + free (preg); + } + +#ifdef HAVE_ICONV + if (conv_to_locale != (iconv_t) -1) + iconv_close (conv_to_locale); +#endif /* HAVE_ICONV */ + hashtable_free (display_seen); + free_pathlist (manpathlist); + free (manp); + free (internal_locale); + exit (status); +} diff --git a/src/zsoelim.c b/src/zsoelim.c new file mode 100644 index 0000000..a7225f6 --- /dev/null +++ b/src/zsoelim.c @@ -0,0 +1,2601 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#line 6 "zsoelim.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static const flex_int16_t yy_nxt[][13] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + }, + + { + 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14 + }, + + { + 13, 16, 16, 15, 16, 17, 16, 16, 16, 16, + 16, 16, 16 + }, + + { + 13, 18, 19, 20, 21, 18, 18, 18, 18, 18, + 18, 18, 18 + }, + + { + 13, 18, 19, 20, 21, 18, 18, 18, 18, 18, + 18, 18, 18 + + }, + + { + 13, 22, 22, 23, 22, 22, 22, 22, 22, 22, + 22, 22, 22 + }, + + { + 13, 22, 22, 23, 22, 24, 22, 22, 22, 22, + 22, 22, 22 + }, + + { + 13, 19, 25, 26, 19, 19, 19, 19, 19, 19, + 19, 19, 19 + }, + + { + 13, 19, 25, 26, 19, 19, 19, 19, 19, 19, + 19, 19, 19 + }, + + { + 13, 27, 27, 28, 29, 27, 30, 27, 27, 27, + 27, 27, 27 + + }, + + { + 13, 27, 27, 28, 29, 27, 30, 27, 27, 27, + 27, 27, 27 + }, + + { + 13, 31, 32, 33, 34, 31, 31, 31, 31, 31, + 31, 31, 31 + }, + + { + 13, 31, 32, 33, 34, 31, 31, 31, 31, 31, + 31, 31, 31 + }, + + { + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13 + }, + + { + 13, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14 + + }, + + { + 13, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15 + }, + + { + 13, 35, 35, -16, 35, 35, 35, 35, 35, 35, + 35, 35, 35 + }, + + { + 13, 36, 36, 36, 36, 36, 36, 37, 36, 36, + 38, 36, 39 + }, + + { + 13, 40, -18, -18, 41, 40, 40, 40, 40, 40, + 40, 40, 40 + }, + + { + 13, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19 + + }, + + { + 13, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20 + }, + + { + 13, 40, -21, -21, -21, 40, 40, 40, 40, 40, + 40, 40, 40 + }, + + { + 13, 42, 42, -22, 42, 42, 42, 42, 42, 42, + 42, 42, 42 + }, + + { + 13, -23, -23, -23, -23, -23, -23, -23, -23, -23, + -23, -23, -23 + }, + + { + 13, 42, 42, -24, 42, 43, 42, 42, 42, 42, + 42, 42, 42 + + }, + + { + 13, -25, 44, 45, -25, -25, -25, -25, -25, -25, + -25, -25, -25 + }, + + { + 13, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26 + }, + + { + 13, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27 + }, + + { + 13, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28 + }, + + { + 13, -29, -29, -29, -29, -29, 46, -29, -29, -29, + -29, -29, -29 + + }, + + { + 13, -30, -30, -30, 47, -30, 46, -30, -30, -30, + -30, -30, -30 + }, + + { + 13, 48, -31, -31, 49, 48, 48, 48, 48, 48, + 48, 48, 48 + }, + + { + 13, -32, 50, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32 + }, + + { + 13, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33 + }, + + { + 13, 48, -34, -34, -34, 48, 48, 48, 48, 48, + 48, 48, 48 + + }, + + { + 13, 35, 35, -35, 35, 35, 35, 35, 35, 35, + 35, 35, 35 + }, + + { + 13, 51, 51, -36, 51, 51, 51, 51, 51, 51, + 51, 51, 51 + }, + + { + 13, 51, 51, -37, 51, 51, 51, 51, 52, 51, + 51, 51, 51 + }, + + { + 13, 53, 53, 53, 53, 53, 53, 53, 53, 54, + 53, 53, 53 + }, + + { + 13, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 56, 55 + + }, + + { + 13, 40, -40, -40, 41, 40, 40, 40, 40, 40, + 40, 40, 40 + }, + + { + 13, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41 + }, + + { + 13, 42, 42, -42, 42, 42, 42, 42, 42, 42, + 42, 42, 42 + }, + + { + 13, 57, 57, -43, 57, 57, 57, 57, 57, 57, + 57, 57, 57 + }, + + { + 13, -44, 44, 45, -44, -44, -44, -44, -44, -44, + -44, -44, -44 + + }, + + { + 13, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45 + }, + + { + 13, -46, -46, -46, 47, -46, 46, -46, -46, -46, + -46, -46, -46 + }, + + { + 13, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47 + }, + + { + 13, 48, -48, -48, 49, 48, 48, 48, 48, 48, + 48, 48, 48 + }, + + { + 13, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49 + + }, + + { + 13, -50, 50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50 + }, + + { + 13, 51, 51, -51, 51, 51, 51, 51, 51, 51, + 51, 51, 51 + }, + + { + 13, 58, 59, -52, 58, 58, 58, 58, 58, 58, + 58, 58, 58 + }, + + { + 13, 60, 60, -53, 60, 60, 60, 60, 60, 60, + 60, 60, 60 + }, + + { + 13, -54, 61, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54 + + }, + + { + 13, 62, 62, -55, 62, 62, 62, 62, 62, 62, + 62, 62, 62 + }, + + { + 13, -56, 63, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56 + }, + + { + 13, 57, 57, -57, 57, 57, 57, 57, 57, 57, + 57, 57, 57 + }, + + { + 13, 58, 58, -58, 58, 58, 58, 58, 58, 58, + 58, 58, 58 + }, + + { + 13, 58, 59, -59, 58, 58, 58, 58, 58, 58, + 58, 58, 58 + + }, + + { + 13, 60, 60, -60, 60, 60, 60, 60, 60, 60, + 60, 60, 60 + }, + + { + 13, -61, 61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61 + }, + + { + 13, 62, 62, -62, 62, 62, 62, 62, 62, 62, + 62, 62, 62 + }, + + { + 13, -63, 63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63 + }, + + } ; + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 24 +#define YY_END_OF_BUFFER 25 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[64] = + { 0, + 0, 0, 0, 0, 16, 16, 0, 0, 0, 0, + 0, 0, 25, 10, 11, 4, 10, 12, 24, 14, + 24, 16, 17, 16, 24, 13, 22, 23, 22, 18, + 19, 20, 21, 22, 4, 5, 5, 9, 8, 12, + 12, 16, 15, 0, 13, 18, 18, 19, 19, 20, + 5, 5, 6, 3, 7, 2, 15, 1, 1, 6, + 3, 7, 2 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5, 1, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, + + 8, 9, 1, 1, 1, 1, 1, 10, 1, 1, + 11, 1, 1, 1, 12, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "zsoelim.l" + +#line 8 "zsoelim.l" + +/* + * zsoelim.l: eliminate .so includes within *roff source + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 1997 Fabrizio Polacco. + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Added functionality over gsoelim to allow for compressed .so includes. + * This is required as the first *roff preprocessor in order to deal with + * 100% of compressed source files correctly. A replacement tmac.andoc was + * considered, but would not have been portable to all systems. + * + * Wed Oct 12 18:46:11 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * Tue, 14 Oct 1997 Fabrizio Polacco <fpolacco@debian.org> + * - added changes that were done to .c instead of -l source + * - added new start condition to avoid execution of .so requests + * inside a macro definition. + */ + +#define MAX_SO_DEPTH 10 /* max .so recursion depth */ +#undef ACCEPT_QUOTES /* accept quoted roff requests */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#define NAME so_name[so_stack_ptr] +#define LINE so_line[so_stack_ptr] +#define PIPE so_pipe[so_stack_ptr] + +#include "dirname.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "decompress.h" + +#include "globbing.h" +#include "zsoelim.h" + +#ifdef ACCEPT_QUOTES +# define ZAP_QUOTES zap_quotes () +static void zap_quotes (void); +#else +# define ZAP_QUOTES +#endif + +static YY_BUFFER_STATE so_stack[MAX_SO_DEPTH]; +static char *so_name[MAX_SO_DEPTH]; +static int so_line[MAX_SO_DEPTH]; +static pipeline *so_pipe[MAX_SO_DEPTH]; +static int so_stack_ptr; +static int no_newline; +static char * const *so_manpathlist; +static const char *so_parent_path; + +struct zsoelim_stdin_data { + char *path; + char * const *manpathlist; +}; + +/* The flex documentation says that yyin is only used by YY_INPUT, so we + * should safely be able to abuse it as a handy way to keep track of the + * current 'pipeline *' rather than the usual 'FILE *'. + */ +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = pipeline_read ((pipeline *) yyin, &size); \ + if (block && size != 0) { \ + memcpy (buf, block, size); \ + buf[size] = '\0'; \ + result = size; \ + } else \ + result = YY_NULL; \ +} +#define YY_NO_INPUT +#line 872 "zsoelim.c" + +#line 874 "zsoelim.c" + +#define INITIAL 0 +#define so 1 +#define de 2 +#define end_request 3 +#define lfnumber 4 +#define lfname 5 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 128 "zsoelim.l" + + +#line 1100 "zsoelim.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) + { + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + + ++yy_cp; + } + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos) + 1; + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 130 "zsoelim.l" +{ + no_newline = 1; + ECHO; + BEGIN (de); /* Now we're inside of a macro definition: ends with a comment */ + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 136 "zsoelim.l" +{ + no_newline = 1; + BEGIN (so); /* Now we're in the .so environment */ + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 141 "zsoelim.l" +{ + no_newline = 1; + ECHO; /* Now we're in the .lf environment */ + BEGIN (lfnumber); + } + YY_BREAK +case 4: +#line 148 "zsoelim.l" +case 5: +/* rule 5 can match eol */ +#line 149 "zsoelim.l" +case 6: +/* rule 6 can match eol */ +#line 150 "zsoelim.l" +case 7: +/* rule 7 can match eol */ +#line 151 "zsoelim.l" +case 8: +/* rule 8 can match eol */ +#line 152 "zsoelim.l" +case 9: +/* rule 9 can match eol */ +#line 153 "zsoelim.l" +case 10: +/* rule 10 can match eol */ +YY_RULE_SETUP +#line 153 "zsoelim.l" +{ + no_newline = 1; + ECHO; + } + YY_BREAK +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 158 "zsoelim.l" +{ + no_newline = 0; + putchar ('\n'); + LINE++; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 165 "zsoelim.l" +{ /* file names including whitespace ? */ + if (so_stack_ptr == MAX_SO_DEPTH - 1) + error (FATAL, 0, + _("%s:%d: .so requests nested too " + "deeply or are recursive"), + NAME, LINE); + + ZAP_QUOTES; + so_stack[so_stack_ptr++] = YY_CURRENT_BUFFER; + LINE = 1; + + no_newline = 0; + + if (zsoelim_open_file (yytext, so_manpathlist, + so_parent_path)) { + --so_stack_ptr; +#ifndef __alpha + error (OK, 0, + _("%s:%d: warning: failed .so request"), + NAME, LINE); + printf (".so %s\n", yytext); +#endif + BEGIN (end_request); + } else { + printf (".lf 1 %s\n", yytext); + yy_switch_to_buffer + (yy_create_buffer (yyin, YY_BUF_SIZE)); + BEGIN (INITIAL); + } + + } + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 197 "zsoelim.l" +{ + no_newline = 0; + BEGIN (INITIAL); + } + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 202 "zsoelim.l" +{ + no_newline = 0; + error (OK, 0, + _("%s:%d: warning: newline in .so request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 213 "zsoelim.l" +{ + no_newline = 1; + ECHO; + BEGIN (INITIAL); + } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 219 "zsoelim.l" +{ + no_newline = 1; + ECHO; + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 224 "zsoelim.l" +{ + no_newline = 0; + putchar ('\n'); + LINE++; + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 231 "zsoelim.l" +{ + no_newline = 1; + ECHO; + ZAP_QUOTES; + LINE = atoi (yytext); + BEGIN (lfname); + } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 239 "zsoelim.l" +{ /* file names including whitespace ?? */ + no_newline = 1; + ECHO; + putchar ('\n'); + ZAP_QUOTES; + if (NAME) + free (NAME); + NAME = xstrdup (yytext); + BEGIN (end_request); + } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 250 "zsoelim.l" +{ + no_newline = 1; + ECHO; + } + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +#line 255 "zsoelim.l" +{ + no_newline = 0; + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 262 "zsoelim.l" +{ + no_newline = 1; + error (OK, 0, + _("%s:%d: warning: malformed .lf request, " + "ignoring"), + NAME, LINE); + putchar (*yytext); + BEGIN (INITIAL); + } + YY_BREAK +case 23: +/* rule 23 can match eol */ +YY_RULE_SETUP +#line 272 "zsoelim.l" +{ + no_newline = 0; + error (OK, 0, + _("%s:%d: warning: newline in .lf request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(so): +case YY_STATE_EOF(de): +case YY_STATE_EOF(end_request): +case YY_STATE_EOF(lfnumber): +case YY_STATE_EOF(lfname): +#line 283 "zsoelim.l" +{ + pipeline_wait (PIPE); + pipeline_free (PIPE); + PIPE = NULL; + free (NAME); + NAME = NULL; + so_manpathlist = NULL; + + if (no_newline) + putchar ('\n'); + + if (--so_stack_ptr < 0) { + yyterminate (); + } else { + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer (so_stack[so_stack_ptr]); + printf (".lf %d %s\n", LINE += 1, NAME); + } + no_newline = 0; + BEGIN (end_request); + } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 304 "zsoelim.l" +ECHO; + YY_BREAK +#line 1400 "zsoelim.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + yy_current_state = yy_nxt[yy_current_state][1]; + yy_is_jam = (yy_current_state <= 0); + + if ( ! yy_is_jam ) + { + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + } + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 304 "zsoelim.l" + + +#ifdef ACCEPT_QUOTES +/* remove leading and trailing quotes in requests */ +static void zap_quotes (void) +{ + if (*yytext == '"') { + if (yytext[yyleng - 1] == '"') { + yytext[yyleng - 1] = '\0'; + yytext++; + } else + error (OK, 0, + _("%s:%d: unterminated quote in roff request"), + NAME, LINE); + } +} +#endif + +/* initialise the stack and call the parser */ +void zsoelim_parse_file (char * const *manpathlist, const char *parent_path) +{ +#ifdef PP_COOKIE + const char *line; +#endif /* PP_COOKIE */ + int linenum = 1; + + so_stack_ptr = 0; + so_manpathlist = manpathlist; + so_parent_path = parent_path; + +#ifdef PP_COOKIE + /* Skip over the first line if it's something that manconv might + * need to know about. + */ + line = pipeline_peekline ((pipeline *) yyin); + if (line && + (STRNEQ (line, PP_COOKIE, 4) || STRNEQ (line, ".\\\" ", 4))) { + fputs (line, stdout); + pipeline_peek_skip ((pipeline *) yyin, strlen (line)); + ++linenum; + } +#endif /* PP_COOKIE */ + + printf (".lf %d %s\n", linenum, NAME); + LINE = 1; + yylex (); +} + +static pipeline *try_compressed (char **filename) +{ + struct compression *comp; + size_t len = strlen (*filename); + pipeline *decomp; + + /* Try the uncompressed name first. */ + (*filename)[len - 1] = '\0'; + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename); + if (decomp) + return decomp; + (*filename)[len - 1] = '.'; + + for (comp = comp_list; comp->ext; ++comp) { + *filename = appendstr (*filename, comp->ext, NULL); + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename); + if (decomp) + return decomp; + (*filename)[len] = '\0'; + } + + return NULL; +} + +/* This routine is used to open the specified file or uncompress a compressed + version and open that instead */ +int zsoelim_open_file (const char *filename, char * const *manpathlist, + const char *parent_path) +{ + pipeline *decomp; + char * const *mp; + + if (parent_path) + debug ("opening %s (parent path: %s)\n", + filename, parent_path); + else + debug ("opening %s\n", filename); + + if (strcmp (filename, "-") == 0) { + decomp = decompress_fdopen (dup (STDIN_FILENO)); + NAME = xstrdup (filename); + } else { + char *compfile; + + /* If there is no parent path, try opening directly first. */ + if (!parent_path) { + compfile = xasprintf ("%s.", filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + + if (manpathlist && strchr (filename, '/')) { + /* File name with a directory part. Try looking it + * up within each manpath entry. + */ + if (parent_path) { + compfile = xasprintf ("%s/%s.", parent_path, + filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + + for (mp = manpathlist; *mp; ++mp) { + if (parent_path && STREQ (*mp, parent_path)) + continue; + + compfile = xasprintf ("%s/%s.", *mp, filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + } else if (manpathlist) { + /* File name with no directory part. Try searching + * the manpath. + */ + char *name, *sec, *dot; + char **names; + char **np; + + name = xstrdup (filename); + dot = strchr (name, '.'); + if (!dot) { + free (name); + goto out; + } + *dot++ = '\0'; + sec = dot; + dot = strchr (dot, '.'); + if (dot) + *dot = '\0'; + + if (parent_path) { + names = look_for_file (parent_path, sec, name, + 0, LFF_MATCHCASE); + for (np = names; np && *np; ++np) { + decomp = decompress_open (*np); + if (decomp) { + NAME = xstrdup (*np); + goto out; + } + } + } + + for (mp = manpathlist; *mp; ++mp) { + if (parent_path && STREQ (*mp, parent_path)) + continue; + + names = look_for_file (*mp, sec, name, + 0, LFF_MATCHCASE); + for (np = names; np && *np; ++np) { + decomp = decompress_open (*np); + if (decomp) { + NAME = xstrdup (*np); + goto out; + } + } + } + + free (name); + } + + /* If there is a parent path, try opening directly last. */ + if (parent_path) { + compfile = xasprintf ("%s.", filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + +out: + if (!decomp) { + error (0, errno, _("can't open %s"), filename); + return 1; + } + } + + debug ("opened %s\n", NAME); + + pipeline_start (decomp); + PIPE = decomp; + /* only used by YY_INPUT, which casts it back to 'pipeline *' */ + yyin = (FILE *) decomp; + + return 0; +} + +void zsoelim_stdin (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + + zsoelim_open_file ("-", NULL, zsoelim_data->path); + zsoelim_parse_file (zsoelim_data->manpathlist, zsoelim_data->path); +} + +struct zsoelim_stdin_data *zsoelim_stdin_data_new (const char *path, + char * const *manpathlist) +{ + struct zsoelim_stdin_data *data = XMALLOC (struct zsoelim_stdin_data); + + data->path = path ? xstrdup (path) : NULL; + data->manpathlist = manpathlist; + + return data; +} + +void zsoelim_stdin_data_free (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + + free (zsoelim_data->path); + free (zsoelim_data); +} + diff --git a/src/zsoelim.h b/src/zsoelim.h new file mode 100644 index 0000000..f17c08e --- /dev/null +++ b/src/zsoelim.h @@ -0,0 +1,32 @@ +/* + * zsoelim.h: interface to eliminating .so includes within *roff source + * + * Copyright (C) 2008 Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +int zsoelim_open_file (const char *filename, char * const *manpathlist, + const char *parent_path); +void zsoelim_parse_file (char * const *manpathlist, const char *parent_path); + +struct zsoelim_stdin_data; + +void zsoelim_stdin (void *data); +struct zsoelim_stdin_data *zsoelim_stdin_data_new (const char *path, + char * const *manpathlist); +void zsoelim_stdin_data_free (void *data); diff --git a/src/zsoelim.l b/src/zsoelim.l new file mode 100644 index 0000000..b3dc780 --- /dev/null +++ b/src/zsoelim.l @@ -0,0 +1,545 @@ +%top{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ +} + +%{ + +/* + * zsoelim.l: eliminate .so includes within *roff source + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 1997 Fabrizio Polacco. + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Added functionality over gsoelim to allow for compressed .so includes. + * This is required as the first *roff preprocessor in order to deal with + * 100% of compressed source files correctly. A replacement tmac.andoc was + * considered, but would not have been portable to all systems. + * + * Wed Oct 12 18:46:11 BST 1994 Wilf. (G.Wilford@ee.surrey.ac.uk) + * + * Tue, 14 Oct 1997 Fabrizio Polacco <fpolacco@debian.org> + * - added changes that were done to .c instead of -l source + * - added new start condition to avoid execution of .so requests + * inside a macro definition. + */ + +#define MAX_SO_DEPTH 10 /* max .so recursion depth */ +#undef ACCEPT_QUOTES /* accept quoted roff requests */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#define NAME so_name[so_stack_ptr] +#define LINE so_line[so_stack_ptr] +#define PIPE so_pipe[so_stack_ptr] + +#include "dirname.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "error.h" +#include "pipeline.h" +#include "decompress.h" + +#include "globbing.h" +#include "zsoelim.h" + +#ifdef ACCEPT_QUOTES +# define ZAP_QUOTES zap_quotes () +static void zap_quotes (void); +#else +# define ZAP_QUOTES +#endif + +static YY_BUFFER_STATE so_stack[MAX_SO_DEPTH]; +static char *so_name[MAX_SO_DEPTH]; +static int so_line[MAX_SO_DEPTH]; +static pipeline *so_pipe[MAX_SO_DEPTH]; +static int so_stack_ptr; +static int no_newline; +static char * const *so_manpathlist; +static const char *so_parent_path; + +struct zsoelim_stdin_data { + char *path; + char * const *manpathlist; +}; + +/* The flex documentation says that yyin is only used by YY_INPUT, so we + * should safely be able to abuse it as a handy way to keep track of the + * current 'pipeline *' rather than the usual 'FILE *'. + */ +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = pipeline_read ((pipeline *) yyin, &size); \ + if (block && size != 0) { \ + memcpy (buf, block, size); \ + buf[size] = '\0'; \ + result = size; \ + } else \ + result = YY_NULL; \ +} +#define YY_NO_INPUT +%} + +%x so +%x de +%x end_request +%x lfnumber +%x lfname + +W [ \t] + +%option full noread ecs +%option 8bit batch never-interactive +%option noyywrap nounput + +%% + +^\.de{W}*.+ { + no_newline = 1; + ECHO; + BEGIN (de); /* Now we're inside of a macro definition: ends with a comment */ + } + +^\.so{W}* { + no_newline = 1; + BEGIN (so); /* Now we're in the .so environment */ + } + +^\.lf{W}* { + no_newline = 1; + ECHO; /* Now we're in the .lf environment */ + BEGIN (lfnumber); + } + +^[^\.\n].* | /* fallback */ +^\.[^sl].* | +^\.l[^f].* | +^\.s[^o].* | +^\.s | +^\.l | +. { + no_newline = 1; + ECHO; + } + +\n { + no_newline = 0; + putchar ('\n'); + LINE++; + } + + +<so>\"?[^ \t\n\"]+\"? { /* file names including whitespace ? */ + if (so_stack_ptr == MAX_SO_DEPTH - 1) + error (FATAL, 0, + _("%s:%d: .so requests nested too " + "deeply or are recursive"), + NAME, LINE); + + ZAP_QUOTES; + so_stack[so_stack_ptr++] = YY_CURRENT_BUFFER; + LINE = 1; + + no_newline = 0; + + if (zsoelim_open_file (yytext, so_manpathlist, + so_parent_path)) { + --so_stack_ptr; +#ifndef __alpha + error (OK, 0, + _("%s:%d: warning: failed .so request"), + NAME, LINE); + printf (".so %s\n", yytext); +#endif + BEGIN (end_request); + } else { + printf (".lf 1 %s\n", yytext); + yy_switch_to_buffer + (yy_create_buffer (yyin, YY_BUF_SIZE)); + BEGIN (INITIAL); + } + + } + +<end_request>{W}*\n { + no_newline = 0; + BEGIN (INITIAL); + } + +<so>\n { + no_newline = 0; + error (OK, 0, + _("%s:%d: warning: newline in .so request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<de>^\.\..* { + no_newline = 1; + ECHO; + BEGIN (INITIAL); + } + +<de>.* { + no_newline = 1; + ECHO; + } + +<de>\n { + no_newline = 0; + putchar ('\n'); + LINE++; + } + + +<lfnumber>\"?[0-9]+\"? { + no_newline = 1; + ECHO; + ZAP_QUOTES; + LINE = atoi (yytext); + BEGIN (lfname); + } + +<lfname>\"?[^ \t\n\"]+\"? { /* file names including whitespace ?? */ + no_newline = 1; + ECHO; + putchar ('\n'); + ZAP_QUOTES; + if (NAME) + free (NAME); + NAME = xstrdup (yytext); + BEGIN (end_request); + } + +<lfname>{W}+ { + no_newline = 1; + ECHO; + } + +<lfname>\n { + no_newline = 0; + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<lfnumber,lfname>. { + no_newline = 1; + error (OK, 0, + _("%s:%d: warning: malformed .lf request, " + "ignoring"), + NAME, LINE); + putchar (*yytext); + BEGIN (INITIAL); + } + +<lfnumber>\n { + no_newline = 0; + error (OK, 0, + _("%s:%d: warning: newline in .lf request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<<EOF>> { + pipeline_wait (PIPE); + pipeline_free (PIPE); + PIPE = NULL; + free (NAME); + NAME = NULL; + so_manpathlist = NULL; + + if (no_newline) + putchar ('\n'); + + if (--so_stack_ptr < 0) { + yyterminate (); + } else { + yy_delete_buffer (YY_CURRENT_BUFFER); + yy_switch_to_buffer (so_stack[so_stack_ptr]); + printf (".lf %d %s\n", LINE += 1, NAME); + } + no_newline = 0; + BEGIN (end_request); + } +%% + +#ifdef ACCEPT_QUOTES +/* remove leading and trailing quotes in requests */ +static void zap_quotes (void) +{ + if (*yytext == '"') { + if (yytext[yyleng - 1] == '"') { + yytext[yyleng - 1] = '\0'; + yytext++; + } else + error (OK, 0, + _("%s:%d: unterminated quote in roff request"), + NAME, LINE); + } +} +#endif + +/* initialise the stack and call the parser */ +void zsoelim_parse_file (char * const *manpathlist, const char *parent_path) +{ +#ifdef PP_COOKIE + const char *line; +#endif /* PP_COOKIE */ + int linenum = 1; + + so_stack_ptr = 0; + so_manpathlist = manpathlist; + so_parent_path = parent_path; + +#ifdef PP_COOKIE + /* Skip over the first line if it's something that manconv might + * need to know about. + */ + line = pipeline_peekline ((pipeline *) yyin); + if (line && + (STRNEQ (line, PP_COOKIE, 4) || STRNEQ (line, ".\\\" ", 4))) { + fputs (line, stdout); + pipeline_peek_skip ((pipeline *) yyin, strlen (line)); + ++linenum; + } +#endif /* PP_COOKIE */ + + printf (".lf %d %s\n", linenum, NAME); + LINE = 1; + yylex (); +} + +static pipeline *try_compressed (char **filename) +{ + struct compression *comp; + size_t len = strlen (*filename); + pipeline *decomp; + + /* Try the uncompressed name first. */ + (*filename)[len - 1] = '\0'; + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename); + if (decomp) + return decomp; + (*filename)[len - 1] = '.'; + + for (comp = comp_list; comp->ext; ++comp) { + *filename = appendstr (*filename, comp->ext, NULL); + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename); + if (decomp) + return decomp; + (*filename)[len] = '\0'; + } + + return NULL; +} + +/* This routine is used to open the specified file or uncompress a compressed + version and open that instead */ +int zsoelim_open_file (const char *filename, char * const *manpathlist, + const char *parent_path) +{ + pipeline *decomp; + char * const *mp; + + if (parent_path) + debug ("opening %s (parent path: %s)\n", + filename, parent_path); + else + debug ("opening %s\n", filename); + + if (strcmp (filename, "-") == 0) { + decomp = decompress_fdopen (dup (STDIN_FILENO)); + NAME = xstrdup (filename); + } else { + char *compfile; + + /* If there is no parent path, try opening directly first. */ + if (!parent_path) { + compfile = xasprintf ("%s.", filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + + if (manpathlist && strchr (filename, '/')) { + /* File name with a directory part. Try looking it + * up within each manpath entry. + */ + if (parent_path) { + compfile = xasprintf ("%s/%s.", parent_path, + filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + + for (mp = manpathlist; *mp; ++mp) { + if (parent_path && STREQ (*mp, parent_path)) + continue; + + compfile = xasprintf ("%s/%s.", *mp, filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + } else if (manpathlist) { + /* File name with no directory part. Try searching + * the manpath. + */ + char *name, *sec, *dot; + char **names; + char **np; + + name = xstrdup (filename); + dot = strchr (name, '.'); + if (!dot) { + free (name); + goto out; + } + *dot++ = '\0'; + sec = dot; + dot = strchr (dot, '.'); + if (dot) + *dot = '\0'; + + if (parent_path) { + names = look_for_file (parent_path, sec, name, + 0, LFF_MATCHCASE); + for (np = names; np && *np; ++np) { + decomp = decompress_open (*np); + if (decomp) { + NAME = xstrdup (*np); + goto out; + } + } + } + + for (mp = manpathlist; *mp; ++mp) { + if (parent_path && STREQ (*mp, parent_path)) + continue; + + names = look_for_file (*mp, sec, name, + 0, LFF_MATCHCASE); + for (np = names; np && *np; ++np) { + decomp = decompress_open (*np); + if (decomp) { + NAME = xstrdup (*np); + goto out; + } + } + } + + free (name); + } + + /* If there is a parent path, try opening directly last. */ + if (parent_path) { + compfile = xasprintf ("%s.", filename); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + +out: + if (!decomp) { + error (0, errno, _("can't open %s"), filename); + return 1; + } + } + + debug ("opened %s\n", NAME); + + pipeline_start (decomp); + PIPE = decomp; + /* only used by YY_INPUT, which casts it back to 'pipeline *' */ + yyin = (FILE *) decomp; + + return 0; +} + +void zsoelim_stdin (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + + zsoelim_open_file ("-", NULL, zsoelim_data->path); + zsoelim_parse_file (zsoelim_data->manpathlist, zsoelim_data->path); +} + +struct zsoelim_stdin_data *zsoelim_stdin_data_new (const char *path, + char * const *manpathlist) +{ + struct zsoelim_stdin_data *data = XMALLOC (struct zsoelim_stdin_data); + + data->path = path ? xstrdup (path) : NULL; + data->manpathlist = manpathlist; + + return data; +} + +void zsoelim_stdin_data_free (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + + free (zsoelim_data->path); + free (zsoelim_data); +} diff --git a/src/zsoelim_main.c b/src/zsoelim_main.c new file mode 100644 index 0000000..ef6d1b6 --- /dev/null +++ b/src/zsoelim_main.c @@ -0,0 +1,157 @@ +/* + * zsoelim_main.c: eliminate .so includes within *roff source + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 1997 Fabrizio Polacco. + * Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 + * Colin Watson. + * + * This file is part of man-db. + * + * man-db 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 2 of the License, or + * (at your option) any later version. + * + * man-db 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 man-db; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <stdlib.h> + +#include "argp.h" +#include "progname.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "error.h" +#include "pipeline.h" +#include "decompress.h" +#include "sandbox.h" + +#include "manp.h" +#include "zsoelim.h" + +int quiet = 1; +man_sandbox *sandbox; + +static char *manpathlist[MAXDIRS]; + +static char **files; +static int num_files; + +const char *argp_program_version = "zsoelim " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = N_("FILE..."); + +static struct argp_option options[] = { + { "debug", 'd', 0, 0, N_("emit debugging messages") }, + { "compatible", 'C', 0, 0, N_("compatibility switch (ignored)"), 1 }, + { 0, 'h', 0, OPTION_HIDDEN, 0 }, /* compatibility for --help */ + { 0 } +}; + +static error_t parse_opt (int key, char *arg ATTRIBUTE_UNUSED, + struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = 1; + return 0; + case 'C': + return 0; /* compatibility with GNU soelim */ + case 'h': + argp_state_help (state, state->out_stream, + ARGP_HELP_STD_HELP); + break; + case ARGP_KEY_NO_ARGS: + /* open stdin */ + files = xmalloc (sizeof *files); + files[0] = xstrdup ("-"); + num_files = 1; + return 0; + case ARGP_KEY_ARGS: + files = state->argv + state->next; + num_files = state->argc - state->next; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +int main (int argc, char *argv[]) +{ + char *multiple_locale = NULL, *internal_locale, *all_locales; + char *manp; + int i; + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + + internal_locale = setlocale (LC_MESSAGES, NULL); + /* Use LANGUAGE only when LC_MESSAGES locale category is + * neither "C" nor "POSIX". */ + if (internal_locale && strcmp (internal_locale, "C") && + strcmp (internal_locale, "POSIX")) + multiple_locale = getenv ("LANGUAGE"); + internal_locale = xstrdup (internal_locale ? internal_locale : "C"); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + if (multiple_locale && *multiple_locale) { + if (internal_locale && *internal_locale) + all_locales = xasprintf ("%s:%s", + multiple_locale, + internal_locale); + else + all_locales = xstrdup (multiple_locale); + } else { + if (internal_locale && *internal_locale) + all_locales = xstrdup (internal_locale); + else + all_locales = NULL; + } + + manp = add_nls_manpaths (get_manpath (NULL), all_locales); + free (all_locales); + + create_pathlist (manp, manpathlist); + + /* parse files in command line order */ + for (i = 0; i < num_files; ++i) { + if (zsoelim_open_file (files[i], manpathlist, NULL)) + continue; + zsoelim_parse_file (manpathlist, NULL); + } + + free_pathlist (manpathlist); + free (manp); + free (internal_locale); + + return OK; +} |