diff options
Diffstat (limited to 'src')
79 files changed, 31298 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..fbeccf4 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,221 @@ +## 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 \ + man-recode \ + 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_srcdir)/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 @LTLIBINTL@ +LIBMANDB = $(top_builddir)/libdb/libmandb.la $(LIBMAN) $(DBLIBS) + +accessdb_LDADD = $(LIBMANDB) +catman_LDADD = $(LIBMANDB) $(libpipeline_LIBS) +globbing_LDADD = $(LIBMAN) +lexgrog_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +man_LDADD = $(LIBMANDB) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +man_recode_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +manconv_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +mandb_LDADD = $(LIBMANDB) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +manpath_LDADD = $(LIBMAN) +whatis_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +zsoelim_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(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 = \ + convert.c \ + convert.h \ + decompress.c \ + decompress.h \ + descriptions.c \ + descriptions.h \ + globbing.c \ + globbing.h \ + lexgrog.h \ + lexgrog.l \ + lexgrog_test.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + ult_src.c \ + ult_src.h \ + utf8.c \ + utf8.h +man_SOURCES = \ + decompress.c \ + decompress.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 \ + utf8.c \ + utf8.h \ + zsoelim.h \ + zsoelim.l +man_recode_SOURCES = \ + decompress.c \ + decompress.h \ + man-recode.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + utf8.c \ + utf8.h +manconv_SOURCES = \ + decompress.c \ + decompress.h \ + manconv.c \ + manconv.h \ + manconv_main.c +mandb_SOURCES = \ + check_mandirs.c \ + check_mandirs.h \ + decompress.c \ + decompress.h \ + descriptions.c \ + descriptions.h \ + descriptions_store.c \ + globbing.c \ + globbing.h \ + lexgrog.h \ + lexgrog.l \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + mandb.c \ + manp.c \ + manp.h \ + straycats.c \ + straycats.h \ + ult_src.c \ + ult_src.h \ + utf8.c \ + utf8.h +manpath_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + manpath.c +whatis_SOURCES = \ + convert.c \ + convert.h \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + whatis.c +zsoelim_SOURCES = \ + decompress.c \ + decompress.h \ + 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)$(EXEEXT) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB)$(EXEEXT); \ + fi + chmod $(man_mode) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN)$(EXEEXT) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB)$(EXEEXT) + 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..b462221 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,2573 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 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) \ + man-recode$(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-manual.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-snapdir.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/calloc.m4 \ + $(top_srcdir)/gl/m4/canonicalize.m4 \ + $(top_srcdir)/gl/m4/chdir-long.m4 $(top_srcdir)/gl/m4/chown.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/ctype_h.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/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/free.m4 \ + $(top_srcdir)/gl/m4/fstat.m4 $(top_srcdir)/gl/m4/fstatat.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/getrandom.m4 \ + $(top_srcdir)/gl/m4/gettext.m4 $(top_srcdir)/gl/m4/gettime.m4 \ + $(top_srcdir)/gl/m4/gettimeofday.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.m4 \ + $(top_srcdir)/gl/m4/inttypes_h.m4 $(top_srcdir)/gl/m4/ioctl.m4 \ + $(top_srcdir)/gl/m4/isblank.m4 \ + $(top_srcdir)/gl/m4/langinfo_h.m4 \ + $(top_srcdir)/gl/m4/largefile.m4 $(top_srcdir)/gl/m4/lchown.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/lock.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/manywarnings.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-slash.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/pipe.m4 \ + $(top_srcdir)/gl/m4/po.m4 $(top_srcdir)/gl/m4/printf.m4 \ + $(top_srcdir)/gl/m4/progtest.m4 $(top_srcdir)/gl/m4/pselect.m4 \ + $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \ + $(top_srcdir)/gl/m4/pthread_sigmask.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/readlinkat.m4 \ + $(top_srcdir)/gl/m4/realloc.m4 \ + $(top_srcdir)/gl/m4/reallocarray.m4 \ + $(top_srcdir)/gl/m4/regex.m4 $(top_srcdir)/gl/m4/rename.m4 \ + $(top_srcdir)/gl/m4/renameat.m4 \ + $(top_srcdir)/gl/m4/rewinddir.m4 $(top_srcdir)/gl/m4/rmdir.m4 \ + $(top_srcdir)/gl/m4/save-cwd.m4 $(top_srcdir)/gl/m4/select.m4 \ + $(top_srcdir)/gl/m4/setenv.m4 \ + $(top_srcdir)/gl/m4/setlocale_null.m4 \ + $(top_srcdir)/gl/m4/sigaction.m4 \ + $(top_srcdir)/gl/m4/signal_h.m4 \ + $(top_srcdir)/gl/m4/signalblocking.m4 \ + $(top_srcdir)/gl/m4/sigpipe.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/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/stpcpy.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_random_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/termios_h.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/unlink.m4 \ + $(top_srcdir)/gl/m4/unlinkat.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/visibility.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/wmemchr.m4 $(top_srcdir)/gl/m4/wmempcpy.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)/gl/m4/year2038.m4 \ + $(top_srcdir)/gl/m4/zzgnulib.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 +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 = convert.$(OBJEXT) decompress.$(OBJEXT) \ + descriptions.$(OBJEXT) globbing.$(OBJEXT) lexgrog.$(OBJEXT) \ + lexgrog_test.$(OBJEXT) manconv.$(OBJEXT) \ + manconv_client.$(OBJEXT) ult_src.$(OBJEXT) utf8.$(OBJEXT) +lexgrog_OBJECTS = $(am_lexgrog_OBJECTS) +lexgrog_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +am_man_OBJECTS = decompress.$(OBJEXT) globbing.$(OBJEXT) man.$(OBJEXT) \ + manconv.$(OBJEXT) manconv_client.$(OBJEXT) manp.$(OBJEXT) \ + ult_src.$(OBJEXT) utf8.$(OBJEXT) zsoelim.$(OBJEXT) +man_OBJECTS = $(am_man_OBJECTS) +man_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +am_man_recode_OBJECTS = decompress.$(OBJEXT) man-recode.$(OBJEXT) \ + manconv.$(OBJEXT) manconv_client.$(OBJEXT) utf8.$(OBJEXT) +man_recode_OBJECTS = $(am_man_recode_OBJECTS) +man_recode_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +am_manconv_OBJECTS = decompress.$(OBJEXT) manconv.$(OBJEXT) \ + manconv_main.$(OBJEXT) +manconv_OBJECTS = $(am_manconv_OBJECTS) +manconv_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) +am_mandb_OBJECTS = check_mandirs.$(OBJEXT) decompress.$(OBJEXT) \ + descriptions.$(OBJEXT) descriptions_store.$(OBJEXT) \ + globbing.$(OBJEXT) lexgrog.$(OBJEXT) manconv.$(OBJEXT) \ + manconv_client.$(OBJEXT) mandb.$(OBJEXT) manp.$(OBJEXT) \ + straycats.$(OBJEXT) ult_src.$(OBJEXT) utf8.$(OBJEXT) +mandb_OBJECTS = $(am_mandb_OBJECTS) +mandb_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(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 = convert.$(OBJEXT) globbing.$(OBJEXT) \ + manp.$(OBJEXT) whatis.$(OBJEXT) +whatis_OBJECTS = $(am_whatis_OBJECTS) +whatis_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_2) \ + $(am__DEPENDENCIES_2) +am_zsoelim_OBJECTS = decompress.$(OBJEXT) globbing.$(OBJEXT) \ + manp.$(OBJEXT) zsoelim.$(OBJEXT) zsoelim_main.$(OBJEXT) +zsoelim_OBJECTS = $(am_zsoelim_OBJECTS) +zsoelim_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ + $(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)/convert.Po \ + ./$(DEPDIR)/decompress.Po ./$(DEPDIR)/descriptions.Po \ + ./$(DEPDIR)/descriptions_store.Po ./$(DEPDIR)/globbing.Po \ + ./$(DEPDIR)/globbing_test.Po ./$(DEPDIR)/lexgrog.Po \ + ./$(DEPDIR)/lexgrog_test.Po ./$(DEPDIR)/man-recode.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)/utf8.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 = +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) $(man_recode_SOURCES) \ + $(manconv_SOURCES) $(mandb_SOURCES) $(manpath_SOURCES) \ + $(whatis_SOURCES) $(zsoelim_SOURCES) +DIST_SOURCES = $(accessdb_SOURCES) $(catman_SOURCES) \ + $(globbing_SOURCES) $(lexgrog_SOURCES) $(man_SOURCES) \ + $(man_recode_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)` +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@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +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@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FLOAT_H = @FLOAT_H@ +FNMATCH_H = @FNMATCH_H@ +GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLOB_H = @GLOB_H@ +GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@ +GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@ +GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@ +GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@ +GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@ +GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@ +GL_GNULIB_ALPHASORT = @GL_GNULIB_ALPHASORT@ +GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@ +GL_GNULIB_BIND = @GL_GNULIB_BIND@ +GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@ +GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@ +GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@ +GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@ +GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@ +GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@ +GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@ +GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@ +GL_GNULIB_CLOSEDIR = @GL_GNULIB_CLOSEDIR@ +GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@ +GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@ +GL_GNULIB_CREAT = @GL_GNULIB_CREAT@ +GL_GNULIB_CTIME = @GL_GNULIB_CTIME@ +GL_GNULIB_DIRFD = @GL_GNULIB_DIRFD@ +GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@ +GL_GNULIB_DUP = @GL_GNULIB_DUP@ +GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@ +GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@ +GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@ +GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@ +GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@ +GL_GNULIB_EXECL = @GL_GNULIB_EXECL@ +GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@ +GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@ +GL_GNULIB_EXECV = @GL_GNULIB_EXECV@ +GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@ +GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@ +GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@ +GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@ +GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@ +GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@ +GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@ +GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@ +GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@ +GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@ +GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@ +GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@ +GL_GNULIB_FDOPENDIR = @GL_GNULIB_FDOPENDIR@ +GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@ +GL_GNULIB_FFS = @GL_GNULIB_FFS@ +GL_GNULIB_FFSL = @GL_GNULIB_FFSL@ +GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@ +GL_GNULIB_FGETC = @GL_GNULIB_FGETC@ +GL_GNULIB_FGETS = @GL_GNULIB_FGETS@ +GL_GNULIB_FLOCK = @GL_GNULIB_FLOCK@ +GL_GNULIB_FNMATCH = @GL_GNULIB_FNMATCH@ +GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@ +GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@ +GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@ +GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@ +GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@ +GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@ +GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@ +GL_GNULIB_FREAD = @GL_GNULIB_FREAD@ +GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@ +GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@ +GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@ +GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@ +GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@ +GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@ +GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@ +GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@ +GL_GNULIB_FTELL = @GL_GNULIB_FTELL@ +GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@ +GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@ +GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@ +GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@ +GL_GNULIB_GETC = @GL_GNULIB_GETC@ +GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@ +GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@ +GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@ +GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@ +GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@ +GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@ +GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@ +GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@ +GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@ +GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@ +GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@ +GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@ +GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@ +GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@ +GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@ +GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@ +GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@ +GL_GNULIB_GETRANDOM = @GL_GNULIB_GETRANDOM@ +GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@ +GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@ +GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@ +GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@ +GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@ +GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@ +GL_GNULIB_GLOB = @GL_GNULIB_GLOB@ +GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@ +GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@ +GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@ +GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@ +GL_GNULIB_IOCTL = @GL_GNULIB_IOCTL@ +GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@ +GL_GNULIB_ISBLANK = @GL_GNULIB_ISBLANK@ +GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@ +GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@ +GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@ +GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@ +GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@ +GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@ +GL_GNULIB_LINK = @GL_GNULIB_LINK@ +GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@ +GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@ +GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@ +GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@ +GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@ +GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@ +GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@ +GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@ +GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@ +GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@ +GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@ +GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@ +GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@ +GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@ +GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@ +GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@ +GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@ +GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@ +GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@ +GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@ +GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@ +GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@ +GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@ +GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@ +GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@ +GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@ +GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@ +GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@ +GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@ +GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@ +GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@ +GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@ +GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@ +GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@ +GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@ +GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@ +GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@ +GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@ +GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@ +GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@ +GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@ +GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@ +GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@ +GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@ +GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@ +GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@ +GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@ +GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@ +GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@ +GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@ +GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@ +GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@ +GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@ +GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@ +GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@ +GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@ +GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@ +GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@ +GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@ +GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@ +GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@ +GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@ +GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@ +GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@ +GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@ +GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@ +GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@ +GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@ +GL_GNULIB_MDA_UTIME = @GL_GNULIB_MDA_UTIME@ +GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@ +GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@ +GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@ +GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@ +GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@ +GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@ +GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@ +GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@ +GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@ +GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@ +GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@ +GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@ +GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@ +GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@ +GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@ +GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@ +GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@ +GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@ +GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@ +GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@ +GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@ +GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@ +GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@ +GL_GNULIB_OPEN = @GL_GNULIB_OPEN@ +GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@ +GL_GNULIB_OPENDIR = @GL_GNULIB_OPENDIR@ +GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@ +GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@ +GL_GNULIB_PERROR = @GL_GNULIB_PERROR@ +GL_GNULIB_PIPE = @GL_GNULIB_PIPE@ +GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@ +GL_GNULIB_POPEN = @GL_GNULIB_POPEN@ +GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@ +GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@ +GL_GNULIB_PREAD = @GL_GNULIB_PREAD@ +GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@ +GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@ +GL_GNULIB_PSELECT = @GL_GNULIB_PSELECT@ +GL_GNULIB_PTHREAD_SIGMASK = @GL_GNULIB_PTHREAD_SIGMASK@ +GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@ +GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@ +GL_GNULIB_PUTC = @GL_GNULIB_PUTC@ +GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@ +GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@ +GL_GNULIB_PUTS = @GL_GNULIB_PUTS@ +GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@ +GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@ +GL_GNULIB_RAISE = @GL_GNULIB_RAISE@ +GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@ +GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@ +GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@ +GL_GNULIB_READ = @GL_GNULIB_READ@ +GL_GNULIB_READDIR = @GL_GNULIB_READDIR@ +GL_GNULIB_READLINK = @GL_GNULIB_READLINK@ +GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@ +GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@ +GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@ +GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@ +GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@ +GL_GNULIB_RECV = @GL_GNULIB_RECV@ +GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@ +GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@ +GL_GNULIB_RENAME = @GL_GNULIB_RENAME@ +GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@ +GL_GNULIB_REWINDDIR = @GL_GNULIB_REWINDDIR@ +GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@ +GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@ +GL_GNULIB_SCANDIR = @GL_GNULIB_SCANDIR@ +GL_GNULIB_SCANF = @GL_GNULIB_SCANF@ +GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@ +GL_GNULIB_SELECT = @GL_GNULIB_SELECT@ +GL_GNULIB_SEND = @GL_GNULIB_SEND@ +GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@ +GL_GNULIB_SETENV = @GL_GNULIB_SETENV@ +GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@ +GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@ +GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@ +GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@ +GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@ +GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@ +GL_GNULIB_SIGACTION = @GL_GNULIB_SIGACTION@ +GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@ +GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@ +GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@ +GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@ +GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@ +GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@ +GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@ +GL_GNULIB_STAT = @GL_GNULIB_STAT@ +GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@ +GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@ +GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@ +GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@ +GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@ +GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@ +GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@ +GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@ +GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@ +GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@ +GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@ +GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@ +GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@ +GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@ +GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@ +GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@ +GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@ +GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@ +GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@ +GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@ +GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@ +GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@ +GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@ +GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@ +GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@ +GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@ +GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@ +GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@ +GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@ +GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@ +GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@ +GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@ +GL_GNULIB_TCGETSID = @GL_GNULIB_TCGETSID@ +GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@ +GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@ +GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@ +GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@ +GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@ +GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@ +GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@ +GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@ +GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@ +GL_GNULIB_TZSET = @GL_GNULIB_TZSET@ +GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@ +GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@ +GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@ +GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@ +GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@ +GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@ +GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@ +GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@ +GL_GNULIB_UTIME = @GL_GNULIB_UTIME@ +GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@ +GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@ +GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@ +GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@ +GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@ +GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@ +GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@ +GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@ +GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@ +GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@ +GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ +GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@ +GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@ +GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@ +GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@ +GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@ +GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@ +GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@ +GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@ +GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@ +GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@ +GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@ +GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@ +GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@ +GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@ +GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@ +GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@ +GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@ +GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@ +GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@ +GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@ +GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@ +GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@ +GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@ +GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@ +GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@ +GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@ +GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@ +GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@ +GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ +GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@ +GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@ +GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@ +GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@ +GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@ +GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@ +GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@ +GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@ +GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@ +GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ +GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GREP = @GREP@ +HAVE_ACCEPT4 = @HAVE_ACCEPT4@ +HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@ +HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ +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_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@ +HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ +HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ +HAVE_DECL_ECVT = @HAVE_DECL_ECVT@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@ +HAVE_DECL_FCVT = @HAVE_DECL_FCVT@ +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_GCVT = @HAVE_DECL_GCVT@ +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_IMAXABS = @HAVE_DECL_IMAXABS@ +HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@ +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_STRTOIMAX = @HAVE_DECL_STRTOIMAX@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@ +HAVE_DECL_TCGETSID = @HAVE_DECL_TCGETSID@ +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_WCSDUP = @HAVE_DECL_WCSDUP@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DIRENT_H = @HAVE_DIRENT_H@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXECVPE = @HAVE_EXECVPE@ +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_GETENTROPY = @HAVE_GETENTROPY@ +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_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ +HAVE_GETUMASK = @HAVE_GETUMASK@ +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_IMAXDIV_T = @HAVE_IMAXDIV_T@ +HAVE_INITSTATE = @HAVE_INITSTATE@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISBLANK = @HAVE_ISBLANK@ +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_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_MBTOWC = @HAVE_MBTOWC@ +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_MEMALIGN = @HAVE_POSIX_MEMALIGN@ +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_SETSTATE = @HAVE_SETSTATE@ +HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@ +HAVE_SIGACTION = @HAVE_SIGACTION@ +HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@ +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_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@ +HAVE_STRINGS_H = @HAVE_STRINGS_H@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOL = @HAVE_STRTOL@ +HAVE_STRTOLD = @HAVE_STRTOLD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOUL = @HAVE_STRTOUL@ +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_RANDOM_H = @HAVE_SYS_RANDOM_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_TERMIOS_H = @HAVE_TERMIOS_H@ +HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@ +HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ +HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +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_VISIBILITY = @HAVE_VISIBILITY@ +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_WMEMPCPY = @HAVE_WMEMPCPY@ +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@ +INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@ +INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@ +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@ +LIBMAN_EXPORT_LDFLAGS = @LIBMAN_EXPORT_LDFLAGS@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPMULTITHREAD = @LIBPMULTITHREAD@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSTDTHREAD = @LIBSTDTHREAD@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_GETLOGIN = @LIB_GETLOGIN@ +LIB_GETRANDOM = @LIB_GETRANDOM@ +LIB_HARD_LOCALE = @LIB_HARD_LOCALE@ +LIB_MBRTOWC = @LIB_MBRTOWC@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_NL_LANGINFO = @LIB_NL_LANGINFO@ +LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIB_SELECT = @LIB_SELECT@ +LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@ +LIMITS_H = @LIMITS_H@ +LINGUAS = @LINGUAS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@ +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@ +LTLIBTHREAD = @LTLIBTHREAD@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +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_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@ +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_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_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_RANDOM_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_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_TERMIOS_H = @NEXT_AS_FIRST_DIRECTIVE_TERMIOS_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_CTYPE_H = @NEXT_CTYPE_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_INTTYPES_H = @NEXT_INTTYPES_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_RANDOM_H = @NEXT_SYS_RANDOM_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_TERMIOS_H = @NEXT_TERMIOS_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@ +PRIPTR_PREFIX = @PRIPTR_PREFIX@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_ACCESS = @REPLACE_ACCESS@ +REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@ +REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHMOD = @REPLACE_CHMOD@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ +REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@ +REPLACE_CREAT = @REPLACE_CREAT@ +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_EXECL = @REPLACE_EXECL@ +REPLACE_EXECLE = @REPLACE_EXECLE@ +REPLACE_EXECLP = @REPLACE_EXECLP@ +REPLACE_EXECV = @REPLACE_EXECV@ +REPLACE_EXECVE = @REPLACE_EXECVE@ +REPLACE_EXECVP = @REPLACE_EXECVP@ +REPLACE_EXECVPE = @REPLACE_EXECVPE@ +REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHMODAT = @REPLACE_FCHMODAT@ +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_FFSLL = @REPLACE_FFSLL@ +REPLACE_FNMATCH = @REPLACE_FNMATCH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREE = @REPLACE_FREE@ +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_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@ +REPLACE_GETRANDOM = @REPLACE_GETRANDOM@ +REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ +REPLACE_GLOB = @REPLACE_GLOB@ +REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@ +REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_INITSTATE = @REPLACE_INITSTATE@ +REPLACE_IOCTL = @REPLACE_IOCTL@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@ +REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@ +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_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@ +REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@ +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_MKFIFOAT = @REPLACE_MKFIFOAT@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKNODAT = @REPLACE_MKNODAT@ +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_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@ +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 = @REPLACE_RANDOM@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_READLINKAT = @REPLACE_READLINKAT@ +REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@ +REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@ +REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@ +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_SETSTATE = @REPLACE_SETSTATE@ +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_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@ +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_STRTOIMAX = @REPLACE_STRTOIMAX@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_STRTOL = @REPLACE_STRTOL@ +REPLACE_STRTOLD = @REPLACE_STRTOLD@ +REPLACE_STRTOLL = @REPLACE_STRTOLL@ +REPLACE_STRTOUL = @REPLACE_STRTOUL@ +REPLACE_STRTOULL = @REPLACE_STRTOULL@ +REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@ +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_WCSTOK = @REPLACE_WCSTOK@ +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@ +TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@ +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_RECODE = @TRANS_MAN_RECODE@ +TRANS_MAN_RECODE_UPPER = @TRANS_MAN_RECODE_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@ +UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@ +UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ +UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@ +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@ +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@ +bzip2 = @bzip2@ +cache_top_owner = @cache_top_owner@ +cat = @cat@ +col = @col@ +compress = @compress@ +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_LIBOBJDEPS = @gl_LIBOBJDEPS@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grap = @grap@ +grep = @grep@ +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@ +snapdir = @snapdir@ +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@ +troff_as_troff_input = @troff_as_troff_input@ +troff_is_groff = @troff_is_groff@ +vgrind = @vgrind@ +xz = @xz@ +zstd = @zstd@ +SUBDIRS = . tests +noinst_DATA = man_db.conf +EXTRA_DIST = lexgrog.c zsoelim.c +AM_CPPFLAGS = \ + -I$(top_srcdir)/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 @LTLIBINTL@ +LIBMANDB = $(top_builddir)/libdb/libmandb.la $(LIBMAN) $(DBLIBS) +accessdb_LDADD = $(LIBMANDB) +catman_LDADD = $(LIBMANDB) $(libpipeline_LIBS) +globbing_LDADD = $(LIBMAN) +lexgrog_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +man_LDADD = $(LIBMANDB) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +man_recode_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +manconv_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +mandb_LDADD = $(LIBMANDB) $(LIBCOMPRESS) $(libpipeline_LIBS) $(LTLIBICONV) +manpath_LDADD = $(LIBMAN) +whatis_LDADD = $(LIBMANDB) $(libpipeline_LIBS) $(LTLIBICONV) +zsoelim_LDADD = $(LIBMAN) $(LIBCOMPRESS) $(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 = \ + convert.c \ + convert.h \ + decompress.c \ + decompress.h \ + descriptions.c \ + descriptions.h \ + globbing.c \ + globbing.h \ + lexgrog.h \ + lexgrog.l \ + lexgrog_test.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + ult_src.c \ + ult_src.h \ + utf8.c \ + utf8.h + +man_SOURCES = \ + decompress.c \ + decompress.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 \ + utf8.c \ + utf8.h \ + zsoelim.h \ + zsoelim.l + +man_recode_SOURCES = \ + decompress.c \ + decompress.h \ + man-recode.c \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + utf8.c \ + utf8.h + +manconv_SOURCES = \ + decompress.c \ + decompress.h \ + manconv.c \ + manconv.h \ + manconv_main.c + +mandb_SOURCES = \ + check_mandirs.c \ + check_mandirs.h \ + decompress.c \ + decompress.h \ + descriptions.c \ + descriptions.h \ + descriptions_store.c \ + globbing.c \ + globbing.h \ + lexgrog.h \ + lexgrog.l \ + manconv.c \ + manconv.h \ + manconv_client.c \ + manconv_client.h \ + mandb.c \ + manp.c \ + manp.h \ + straycats.c \ + straycats.h \ + ult_src.c \ + ult_src.h \ + utf8.c \ + utf8.h + +manpath_SOURCES = \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + manpath.c + +whatis_SOURCES = \ + convert.c \ + convert.h \ + globbing.c \ + globbing.h \ + manp.c \ + manp.h \ + whatis.c + +zsoelim_SOURCES = \ + decompress.c \ + decompress.h \ + 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: $(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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(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) + +man-recode$(EXEEXT): $(man_recode_OBJECTS) $(man_recode_DEPENDENCIES) $(EXTRA_man_recode_DEPENDENCIES) + @rm -f man-recode$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(man_recode_OBJECTS) $(man_recode_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)/convert.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decompress.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)/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-recode.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)/utf8.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)/convert.Po + -rm -f ./$(DEPDIR)/decompress.Po + -rm -f ./$(DEPDIR)/descriptions.Po + -rm -f ./$(DEPDIR)/descriptions_store.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-recode.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)/utf8.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)/convert.Po + -rm -f ./$(DEPDIR)/decompress.Po + -rm -f ./$(DEPDIR)/descriptions.Po + -rm -f ./$(DEPDIR)/descriptions_store.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-recode.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)/utf8.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)$(EXEEXT) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB)$(EXEEXT); \ + fi + chmod $(man_mode) \ + $(DESTDIR)$(bindir)/$(TRANS_MAN)$(EXEEXT) \ + $(DESTDIR)$(bindir)/$(TRANS_MANDB)$(EXEEXT) + 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..4b7adf5 --- /dev/null +++ b/src/accessdb.c @@ -0,0 +1,175 @@ +/* + * 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 <stdbool.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "argp.h" +#include "attribute.h" +#include "progname.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "debug.h" +#include "fatal.h" +#include "util.h" + +#include "mydbm.h" + +const char *cat_root; + +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[] = { + OPT ("debug", 'd', 0, N_ ("emit debugging messages")), + OPT_HELP_COMPAT, + {0} +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = true; + 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; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +static char *help_filter (int key, const char *text, void *input MAYBE_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; + } +} +#pragma GCC diagnostic pop + +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_NEW (database); + if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) { + MYDBM_FREE (dbf); + dbf = NULL; + } + if (!dbf) + 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); +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-double-free" +#endif + MYDBM_FREE_DPTR (content); +next: + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); +#pragma GCC diagnostic pop + key = nextkey; + } + + MYDBM_FREE (dbf); + exit (ret); +} diff --git a/src/catman.c b/src/catman.c new file mode 100644 index 0000000..e421d21 --- /dev/null +++ b/src/catman.c @@ -0,0 +1,448 @@ +/* + * 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 <stdbool.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 "error.h" +#include "gl_list.h" +#include "progname.h" +#include "xalloc.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "debug.h" +#include "fatal.h" +#include "filenames.h" +#include "glcontainers.h" +#include "pipeline.h" +#include "util.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; + +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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("manpath", 'M', N_("PATH"), + N_("set search path for manual pages to PATH")), + OPT ("config-file", 'C', N_("FILE"), + N_("use this user configuration file")), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + char *mansect; + + switch (key) { + case 'd': + debug_level = true; + 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 gl_list_t manpathlist; + +static void post_fork (void) +{ + pop_all_cleanups (); + MYDBM_FREE (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: %zu\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 (MYDBM_FILE dbf, + const char *manpath, const char *section) +{ + pipecmd *basecmd, *cmd; + datum key; + size_t arg_size, initial_bit; + bool message = true; + int first_arg; + + 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 */ +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + if (*MYDBM_DPTR (key) != '$') { +#pragma GCC diagnostic pop + datum content; + + content = MYDBM_FETCH (dbf, key); + + if (!MYDBM_DPTR (content)) + fatal (0, + _( "NULL content for key: %s"), + MYDBM_DPTR (key)); + + /* ignore overflow entries */ +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + if (*MYDBM_DPTR (content) != '\t') { +#pragma GCC diagnostic pop + struct mandata *entry; + + entry = split_content (dbf, + MYDBM_DPTR (content)); + + /* 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 = false; + } + + arg_size += add_arg (cmd, key) + 1; + + debug ("arg space free: %zu 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; + } + } + + free_mandata_struct (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; + } + + if (pipecmd_get_nargs (cmd) > first_arg) + catman (cmd); + else + pipecmd_free (cmd); + + pipecmd_free (basecmd); + + return 0; +} + +static bool check_access (const char *directory) +{ + if (!CAN_ACCESS (directory, W_OK)) { + error (0, errno, _("cannot write within %s"), directory); + return true; + } + + return false; +} + +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; 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; + } + + /* get the manpath as a list of pointers */ + manpathlist = create_pathlist (manp); + + GL_LIST_FOREACH (manpathlist, mp) { + char *catpath, *database; + MYDBM_FILE dbf; + 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); + } + dbf = MYDBM_NEW (database); + if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) { + error (0, errno, _("cannot read database %s"), + database); + goto next; + } + dbf_close_post_fork = dbf; + + len = strlen (catpath); + + for (sp = sections; sp && *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 (dbf, mp, *sp)) { + error (0, 0, _("unable to update %s"), mp); + break; + } + } + +next: + dbf_close_post_fork = NULL; + MYDBM_FREE (dbf); + free (database); + 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..75c6f5e --- /dev/null +++ b/src/check_mandirs.c @@ -0,0 +1,1018 @@ +/* + * 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 <assert.h> +#include <stdbool.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 "attribute.h" +#include "dirname.h" +#include "error.h" +#include "gl_array_list.h" +#include "gl_hash_map.h" +#include "gl_xlist.h" +#include "gl_xmap.h" +#include "stat-time.h" +#include "timespec.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "compression.h" +#include "debug.h" +#include "fatal.h" +#include "filenames.h" +#include "glcontainers.h" +#include "orderfiles.h" +#include "security.h" +#include "util.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "descriptions.h" +#include "globbing.h" +#include "lexgrog.h" +#include "manp.h" +#include "ult_src.h" +#include "check_mandirs.h" + +bool opt_test; /* don't update db */ +int pages; +bool force_rescan = false; + +gl_map_t whatis_map = NULL; + +struct whatis { + char *whatis; + char *filters; +}; + +static void whatis_free (const void *value) +{ + struct whatis *whatis = (struct whatis *) value; + + free (whatis->whatis); + free (whatis->filters); + free (whatis); +} + +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); +} + +/* Test whether an errno value is EAGAIN or (on systems where it differs) + * EWOULDBLOCK. This is a separate function mainly in order to be able to + * control GCC diagnostics in one place. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlogical-op" +static inline bool is_eagain (int err) +{ + return err == EAGAIN || err == EWOULDBLOCK; +} +#pragma GCC diagnostic pop + +static void gripe_rwopen_failed (MYDBM_FILE dbf) +{ + if (errno == EACCES || errno == EROFS) + debug ("database %s is read-only\n", dbf->name); + else if (is_eagain (errno)) + debug ("database %s is locked by another process\n", dbf->name); + else { +#ifdef MAN_DB_UPDATES + if (!quiet) +#endif /* MAN_DB_UPDATES */ + error (0, errno, _("can't update index cache %s"), + dbf->name); + } +} + +static bool ensure_db_open (MYDBM_FILE dbf) +{ + if (dbf->file) + return true; + if (!MYDBM_RWOPEN (dbf)) + return false; + return true; +} + +/* 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 struct ult_value *ult; + struct lexgrog lg; + struct mandata *info, *exists; + struct compression *comp; + struct stat buf; + size_t len; + const struct whatis *whatis; + + debug ("\ntest_manfile: considering %s\n", file); + + memset (&lg, 0, sizeof (struct lexgrog)); + + info = filename_info (file, quiet < 2); + if (!info) + return; + manpage_base = info->name; /* steal memory */ + info->name = NULL; + + comp = comp_info (file, true); + if (comp) { + len = strlen (comp->stem); + free (comp->stem); + } else + len = strlen (file); + + /* 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_mandata_struct (info); + return; + } + + /* Check for multiple pages whose details match except for having + * different compression extensions. + */ + exists = dblookup_exact (dbf, manpage_base, info->ext, true); + if (exists && !STREQ (exists->comp, info->comp ? info->comp : "-")) { + char *abs_filename; + + /* If the cached file still exists, then we have a collision: + * two pages that only differ by compression extension. + */ + 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_mandata_struct (info); + return; + } + } + free_mandata_struct (exists); + + /* 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); + + if (!ult) { + if (quiet < 2) + error (0, 0, + _("warning: %s: bad symlink or ROFF `.so' request"), + file); + free_mandata_struct (info); + return; + } + + pages++; /* pages seen so far */ + + if (strncmp (ult->path, 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->path as the hash key so we don't have + * to clear the hash between calls. + */ + + if (!whatis_map) + whatis_map = new_string_map (GL_HASH_MAP, whatis_free); + + whatis = gl_map_get (whatis_map, ult->path); + if (whatis) { + lg.whatis = whatis->whatis ? xstrdup (whatis->whatis) : NULL; + lg.filters = + whatis->filters ? xstrdup (whatis->filters) : NULL; + } else { + /* Cache miss; go and get the whatis info in its raw state. */ + char *file_base = base_name (file); + struct whatis *new_whatis; + + if (!STRNEQ (ult->path, file, len)) + debug ("test_manfile: link not in cache:\n" + " source = %s\n" + " target = %s\n", file, ult->path); + + lg.type = MANPAGE; + drop_effective_privs (); + find_name (ult->path, file_base, &lg, NULL); + free (file_base); + regain_effective_privs (); + + new_whatis = XMALLOC (struct whatis); + new_whatis->whatis = lg.whatis ? xstrdup (lg.whatis) : NULL; + new_whatis->filters = lg.filters ? xstrdup (lg.filters) : NULL; + gl_map_put (whatis_map, xstrdup (ult->path), new_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) { + gl_list_t descs = parse_descriptions (manpage_base, lg.whatis); + if (!opt_test) + store_descriptions (dbf, descs, info, path, + manpage_base, ult->trace); + gl_list_free (descs); + } else if (quiet < 2) { + (void) stat (ult->path, &buf); + if (buf.st_size == 0) + error (0, 0, _("warning: %s: ignoring empty file"), + ult->path); + else + error (0, 0, + _("warning: %s: whatis parse for %s(%s) failed"), + ult->path, manpage_base, info->ext); + } + + free_mandata_struct (info); + 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; + gl_list_t names; + const char *name; + + manpage = xasprintf ("%s/%s/", path, infile); + assert (manpage); + 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 = new_string_list (GL_ARRAY_LIST, false); + + /* 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; + gl_list_add_last (names, xstrdup (newdir->d_name)); + } + closedir (dir); + + order_files (infile, &names); + + GL_LIST_FOREACH (names, name) { + manpage = appendstr (manpage, name, (void *) 0); + test_manfile (dbf, manpage, path); + *(manpage + len) = '\0'; + } + + gl_list_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); + if (lchown (path, man_owner->pw_uid, man_owner->pw_gid) < 0) + fatal (0, _("can't chown %s"), path); + } +} +#else /* !MAN_OWNER */ +void chown_if_possible (const char *path MAYBE_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); + assert (catname); + 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 (MYDBM_FILE dbf, const char *path, const char *catpath, + struct timespec last, bool create) +{ + DIR *dir; + struct dirent *mandir; + int amount = 0; + bool created = false; + + 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; + + 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 */ + + if (!MYDBM_CTRWOPEN (dbf)) { + if (errno == EACCES || errno == EROFS) { + debug ("database %s is read-only\n", + dbf->name); + closedir (dir); + return 0; + } else { + error (0, errno, + _("can't create index cache %s"), + dbf->name); + closedir (dir); + return -1; + } + } + + dbver_wr (dbf); + + created = true; + } else if (!ensure_db_open (dbf)) { + gripe_rwopen_failed (dbf); + 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); + amount++; + } + closedir (dir); + + return amount; +} + +/* routine to prepare/create the db prior to calling testmandirs() */ +int create_db (MYDBM_FILE dbf, const char *manpath, const char *catpath) +{ + struct timespec time_zero; + int amount; + + debug ("create_db(%s): %s\n", manpath, dbf->name); + + time_zero.tv_sec = 0; + time_zero.tv_nsec = 0; + amount = testmandirs (dbf, manpath, catpath, time_zero, true); + + if (amount > 0 && !quiet) + fputs (_("done.\n"), stderr); + + return amount; +} + +/* Make sure an existing database is essentially sane. */ +static bool sanity_check_db (MYDBM_FILE dbf) +{ + datum key; + + if (dbver_rd (dbf)) + return false; + + 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", dbf->name, MYDBM_DPTR (key)); + MYDBM_FREE_DPTR (key); + return false; + } +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-double-free" +#endif + MYDBM_FREE_DPTR (content); + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); +#pragma GCC diagnostic pop + key = nextkey; + } + + return true; +} + +/* routine to update the db, ensure that it is consistent with the + filesystem */ +int update_db (MYDBM_FILE dbf, const char *manpath, const char *catpath) +{ + struct timespec mtime; + int new; + + if (!ensure_db_open (dbf) || !sanity_check_db (dbf)) { + debug ("failed to open %s O_RDONLY\n", dbf->name); + return -1; + } + mtime = MYDBM_GET_TIME (dbf); + + debug ("update_db(): %ld.%09ld\n", + (long) mtime.tv_sec, (long) mtime.tv_nsec); + new = testmandirs (dbf, manpath, catpath, mtime, false); + + if (new > 0 && !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 = NULL; + char *nicekey, *tab; + +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + /* Ignore db identifier keys. */ + if (*MYDBM_DPTR (key) == '$') + goto pointers_next; +#pragma GCC diagnostic pop + + 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'; + +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + if (*MYDBM_DPTR (content) == '\t') + goto pointers_contentnext; +#pragma GCC diagnostic pop + + entry = split_content (dbf, MYDBM_DPTR (content)); + 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_mandata_struct (entry); + 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 *ext, gl_list_t source, + struct timespec db_mtime) +{ + const char *walk; + int count = 0; + + GL_LIST_FOREACH (source, walk) { + struct mandata *info; + struct stat statbuf; + + 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; + } + + info = filename_info (walk, quiet < 2); + if (info) { + if (STREQ (ext, info->ext)) + ++count; + free_mandata_struct (info); + } + } + + 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, gl_list_t 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 (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, bool cat, + const char *name, struct mandata *info, + gl_list_t 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 (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 = true; + 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 = true; + return 1; + } else { + /* Does the real page still exist? */ + gl_list_t real_found; + bool save_debug = debug_level; + struct timespec t; + int count; + + debug_level = false; + 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; + count = count_glob_matches (info->ext, real_found, t); + gl_list_free (real_found); + if (count) + 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 bool check_multi_key (const char *name, const char *content) +{ + const char *walk, *next; + + if (!*content) + return false; + + 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. + */ + bool valid = true; + ++walk; /* skip over initial tab */ + next = strchr (walk, '\t'); + if (next) { + if (strncasecmp (name, walk, next - walk)) + valid = false; + } else { + if (strcasecmp (name, walk)) + valid = false; + } + if (!valid) { + debug ("%s: broken multi key \"%s\", " + "forcing a rescan\n", name, content); + force_rescan = true; + return true; + } + + /* If the name was valid, skip over the extension and + * continue the scan. + */ + walk = next; + next = walk ? strchr (walk + 1, '\t') : NULL; + } + + return false; +} + +/* Go through the database and purge references to man pages that no longer + * exist. + */ +int purge_missing (MYDBM_FILE dbf, const char *manpath, const char *catpath) +{ +#ifdef NDBM + char *dirfile; +#endif + struct stat st; + bool db_exists; + datum key; + int count = 0; + struct timespec db_mtime; + +#ifdef NDBM + dirfile = xasprintf ("%s.dir", dbf->name); + db_exists = stat (dirfile, &st) == 0; + free (dirfile); +#else + db_exists = stat (dbf->name, &st) == 0; +#endif + if (!db_exists) + /* nothing to purge */ + return 0; + + if (!quiet) + printf (_("Purging old database entries in %s...\n"), manpath); + + if (!ensure_db_open (dbf) || !sanity_check_db (dbf)) { + gripe_rwopen_failed (dbf); + 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; + bool save_debug; + gl_list_t found; + +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + /* Ignore db identifier keys. */ + if (*MYDBM_DPTR (key) == '$') { + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + continue; + } +#pragma GCC diagnostic pop + + 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'; + +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + /* 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; + } +#pragma GCC diagnostic pop + + entry = split_content (dbf, MYDBM_DPTR (content)); + + save_debug = debug_level; + debug_level = false; /* look_for_file() is quite noisy */ + if (entry->id <= WHATIS_MAN) + found = look_for_file (manpath, entry->ext, + entry->name ? entry->name + : nicekey, + false, LFF_MATCHCASE); + else + found = look_for_file (catpath, entry->ext, + entry->name ? entry->name + : nicekey, + true, 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, false, nicekey, + entry, found, db_mtime); + else /* entry->id == WHATIS_CAT */ + count += purge_whatis (dbf, catpath, true, nicekey, + entry, found, db_mtime); + + gl_list_free (found); + free (nicekey); + + free_mandata_struct (entry); + MYDBM_FREE_DPTR (content); + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + return count; +} diff --git a/src/check_mandirs.h b/src/check_mandirs.h new file mode 100644 index 0000000..d89ca98 --- /dev/null +++ b/src/check_mandirs.h @@ -0,0 +1,36 @@ +/* + * 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 <stdbool.h> + +#include "mydbm.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 (MYDBM_FILE dbf, + const char *manpath, const char *catpath); +extern int update_db (MYDBM_FILE dbf, + const char *manpath, const char *catpath); +extern void purge_pointers (MYDBM_FILE dbf, const char *name); +extern int purge_missing (MYDBM_FILE dbf, + const char *manpath, const char *catpath); diff --git a/src/convert.c b/src/convert.c new file mode 100644 index 0000000..447240c --- /dev/null +++ b/src/convert.c @@ -0,0 +1,99 @@ +/* + * convert.c: simple encoding conversions + * + * Copyright (C) 2007-2022 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 <stdbool.h> +#include <string.h> + +#ifdef HAVE_ICONV +# include <iconv.h> +#endif /* HAVE_ICONV */ + +#include "attribute.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "cleanup.h" +#include "encodings.h" + +#include "convert.h" + +#ifdef HAVE_ICONV +static bool conv_to_locale_initialized = false; +static iconv_t conv_to_locale = (iconv_t) -1; + +static void close_conv_to_locale (void *ignored MAYBE_UNUSED) +{ + iconv_close (conv_to_locale); +} + +char * ATTRIBUTE_MALLOC convert_to_locale (char *string) +{ + if (!conv_to_locale_initialized) { + char *locale_charset = xasprintf + ("%s//IGNORE", get_locale_charset ()); + conv_to_locale = iconv_open (locale_charset, "UTF-8"); + free (locale_charset); + if (conv_to_locale != (iconv_t) -1) + push_cleanup (close_conv_to_locale, NULL, 0); + conv_to_locale_initialized = true; + } + + if (conv_to_locale != (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_to_locale, + (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 */ +char * ATTRIBUTE_MALLOC convert_to_locale (char *string) +{ + return xstrdup (string); +} +#endif /* HAVE_ICONV */ diff --git a/src/convert.h b/src/convert.h new file mode 100644 index 0000000..962a619 --- /dev/null +++ b/src/convert.h @@ -0,0 +1,23 @@ +/* + * convert.h: interface to simple encoding conversions + * + * Copyright (C) 2007-2022 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 + */ + +char *convert_to_locale (char *string); diff --git a/src/decompress.c b/src/decompress.c new file mode 100644 index 0000000..c483241 --- /dev/null +++ b/src/decompress.c @@ -0,0 +1,435 @@ +/* + * decompress.c: decompression abstraction layer + * + * 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 <assert.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#ifdef HAVE_LIBZ +# include "zlib.h" +#endif /* HAVE_LIBZ */ + +#include "pipeline.h" + +#include "attribute.h" +#include "minmax.h" +#include "xalloc.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "compression.h" +#include "sandbox.h" + +#include "decompress.h" + +enum decompress_tag { + DECOMPRESS_PIPELINE, + DECOMPRESS_INPROCESS +}; + +struct decompress_inprocess { + char *buf; + size_t len; + size_t offset; + char *line_cache; +}; + +struct decompress { + enum decompress_tag tag; + union { + pipeline *p; + struct decompress_inprocess inprocess; + } u; +}; + +/* Create a new pipeline-based decompressor. Takes ownership of p. */ +static decompress *decompress_new_pipeline (pipeline *p) +{ + decompress *d = XMALLOC (decompress); + + d->tag = DECOMPRESS_PIPELINE; + d->u.p = p; + + return d; +} + +#ifdef HAVE_LIBZ + +/* Create a new in-process decompressor. Takes ownership of buf. */ +static decompress *decompress_new_inprocess (char *buf, size_t len) +{ + decompress *d = XMALLOC (decompress); + + d->tag = DECOMPRESS_INPROCESS; + d->u.inprocess.buf = buf; + d->u.inprocess.len = len; + d->u.inprocess.offset = 0; + d->u.inprocess.line_cache = NULL; + + return d; +} + +static void decompress_zlib (void *data MAYBE_UNUSED) +{ + gzFile zlibfile; + int fd; + + fd = dup (STDIN_FILENO); + if (fd < 0) + return; + + zlibfile = gzdopen (fd, "r"); + if (!zlibfile) { + close (fd); + return; + } + + for (;;) { + char buffer[4096]; + int r = gzread (zlibfile, buffer, 4096); + if (r <= 0) + break; + if (fwrite (buffer, 1, (size_t) r, stdout) < (size_t) r) + break; + } + + gzclose (zlibfile); + return; +} + +/* The largest number of uncompressed bytes we're prepared to read into + * memory. (We actually allow at most one fewer byte than this, for easy + * EOF detection.) + * + * At the time of writing, 11 out of 27959 (0.04%) installed manual pages on + * the author's system were larger than this. + * + * We could lift this restriction if we streamed in-process decompression + * instead, but that's a bit complicated: we'd also need to stream encoding + * conversion, and there's relatively little point until lexgrog can rely on + * preprocessor header lines rather than having to scan the whole file for + * preprocessor indications. For the time being, one-shot buffering is + * cheap enough and much simpler. + */ +#define MAX_INPROCESS 1048576 + +static decompress *decompress_try_zlib (const char *filename) +{ + gzFile zlibfile; + /* We only ever call this from the parent process (and don't + * currently use threads), and this lets us skip per-file memory + * allocation. + */ + static char buffer[MAX_INPROCESS]; + int len = 0; + + zlibfile = gzopen (filename, "r"); + if (!zlibfile) + return NULL; + + while (len < MAX_INPROCESS) { + /* Read one more byte than we're prepared to return, in + * order to detect EOF at the right position. The "len >= + * MAX_INPROCESS" check below catches the boundary case. + */ + int r = gzread (zlibfile, buffer + len, MAX_INPROCESS - len); + if (r < 0) { + gzclose (zlibfile); + return NULL; + } else if (r == 0) + break; + else + len += r; + } + + gzclose (zlibfile); + if (len >= MAX_INPROCESS) + return NULL; + /* Copy input data so that we don't have potential data corruption + * if more than one in-process decompressor is active at once. (An + * alternative might be to use a lock to prevent that situation.) + */ + return decompress_new_inprocess (xmemdup (buffer, (size_t) len), + (size_t) len); +} + +#define OPEN_FLAGS_UNUSED +#else /* !HAVE_LIBZ */ +#define OPEN_FLAGS_UNUSED MAYBE_UNUSED +#endif /* HAVE_LIBZ */ + +extern man_sandbox *sandbox; + +decompress *decompress_open (const char *filename, int flags OPEN_FLAGS_UNUSED) +{ + pipecmd *cmd; + pipeline *p; + struct stat st; +#ifdef HAVE_LIBZ + size_t filename_len; +#endif /* HAVE_LIBZ */ + char *ext; + struct compression *comp; + + if (stat (filename, &st) < 0 || S_ISDIR (st.st_mode)) + return NULL; + +#ifdef HAVE_LIBZ + filename_len = strlen (filename); + if (filename_len > 3 && STREQ (filename + filename_len - 3, ".gz")) { + if (flags & DECOMPRESS_ALLOW_INPROCESS) { + decompress *d = decompress_try_zlib (filename); + if (d) + return d; + } + + cmd = pipecmd_new_function ("zcat", &decompress_zlib, NULL, + NULL); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, sandbox); + p = pipeline_new_commands (cmd, (void *) 0); + goto got_pipeline; + } +#endif /* HAVE_LIBZ */ + + ext = strrchr (filename, '.'); + if (ext) { + ++ext; + + for (comp = comp_list; comp->ext; ++comp) { + if (!STREQ (comp->ext, ext)) + continue; + + cmd = pipecmd_new_argstr (comp->prog); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, + sandbox); + p = pipeline_new_commands (cmd, (void *) 0); + goto got_pipeline; + } + } + +#ifdef HAVE_GZIP + /* HP-UX */ + ext = strstr (filename, ".Z/"); + if (ext) { + cmd = pipecmd_new_argstr (PROG_GUNZIP); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, sandbox); + p = pipeline_new_commands (cmd, (void *) 0); + goto got_pipeline; + } +#endif + + p = pipeline_new (); + +got_pipeline: + pipeline_want_infile (p, filename); + pipeline_want_out (p, -1); + return decompress_new_pipeline (p); +} + +decompress *decompress_fdopen (int fd) +{ + pipeline *p; +#ifdef HAVE_LIBZ + pipecmd *cmd; +#endif /* HAVE_LIBZ */ + +#ifdef HAVE_LIBZ + cmd = pipecmd_new_function ("zcat", &decompress_zlib, NULL, NULL); + pipecmd_pre_exec (cmd, sandbox_load, sandbox_free, sandbox); + p = pipeline_new_commands (cmd, (void *) 0); +#else /* HAVE_LIBZ */ + p = pipeline_new (); +#endif /* HAVE_LIBZ */ + + pipeline_want_in (p, fd); + pipeline_want_out (p, -1); + return decompress_new_pipeline (p); +} + +bool ATTRIBUTE_PURE decompress_is_pipeline (decompress *d) +{ + return d->tag == DECOMPRESS_PIPELINE; +} + +pipeline * ATTRIBUTE_PURE decompress_get_pipeline (decompress *d) +{ + assert (d->tag == DECOMPRESS_PIPELINE); + return d->u.p; +} + +const char * ATTRIBUTE_PURE decompress_inprocess_buf (decompress *d) +{ + assert (d->tag == DECOMPRESS_INPROCESS); + return d->u.inprocess.buf; +} + +size_t ATTRIBUTE_PURE decompress_inprocess_len (decompress *d) +{ + assert (d->tag == DECOMPRESS_INPROCESS); + return d->u.inprocess.len; +} + +void decompress_inprocess_replace (decompress *d, char *buf, size_t len) +{ + assert (d->tag == DECOMPRESS_INPROCESS); + + free (d->u.inprocess.line_cache); + free (d->u.inprocess.buf); + + d->u.inprocess.buf = buf; + d->u.inprocess.len = len; + d->u.inprocess.offset = 0; + d->u.inprocess.line_cache = NULL; +} + +void decompress_start (decompress *d) +{ + if (d->tag == DECOMPRESS_PIPELINE) + pipeline_start (d->u.p); +} + +const char *decompress_read (decompress *d, size_t *len) +{ + if (d->tag == DECOMPRESS_PIPELINE) + return pipeline_read (d->u.p, len); + else { + const char *ret; + assert (d->tag == DECOMPRESS_INPROCESS); + *len = MIN (*len, d->u.inprocess.len - d->u.inprocess.offset); + ret = d->u.inprocess.buf + d->u.inprocess.offset; + d->u.inprocess.offset += *len; + return ret; + } +} + +const char *decompress_peek (decompress *d, size_t *len) +{ + if (d->tag == DECOMPRESS_PIPELINE) + return pipeline_peek (d->u.p, len); + else { + assert (d->tag == DECOMPRESS_INPROCESS); + *len = MIN (*len, d->u.inprocess.len - d->u.inprocess.offset); + return d->u.inprocess.buf + d->u.inprocess.offset; + } +} + +void decompress_peek_skip (decompress *d, size_t len) +{ + if (d->tag == DECOMPRESS_PIPELINE) + pipeline_peek_skip (d->u.p, len); + else { + assert (d->tag == DECOMPRESS_INPROCESS); + assert (len <= d->u.inprocess.len - d->u.inprocess.offset); + d->u.inprocess.offset += len; + } +} + +const char *decompress_readline (decompress *d) +{ + if (d->tag == DECOMPRESS_PIPELINE) + return pipeline_readline (d->u.p); + else { + const char *cur, *end; + assert (d->tag == DECOMPRESS_INPROCESS); + /* This isn't on the hot path (only called for a few lines + * at the start of the file), so we can afford to + * reallocate. + */ + if (d->u.inprocess.line_cache) { + free (d->u.inprocess.line_cache); + d->u.inprocess.line_cache = NULL; + } + cur = d->u.inprocess.buf + d->u.inprocess.offset; + end = memchr (cur, '\n', + d->u.inprocess.len - d->u.inprocess.offset); + if (end) { + d->u.inprocess.line_cache = xstrndup + (cur, end - cur + 1); + d->u.inprocess.offset += end - cur + 1; + return d->u.inprocess.line_cache; + } else + return NULL; + } +} + +const char *decompress_peekline (decompress *d) +{ + if (d->tag == DECOMPRESS_PIPELINE) + return pipeline_peekline (d->u.p); + else { + const char *cur, *end; + assert (d->tag == DECOMPRESS_INPROCESS); + /* This isn't on the hot path (only called for a few lines + * at the start of the file), so we can afford to + * reallocate. + */ + if (d->u.inprocess.line_cache) { + free (d->u.inprocess.line_cache); + d->u.inprocess.line_cache = NULL; + } + cur = d->u.inprocess.buf + d->u.inprocess.offset; + end = memchr (cur, '\n', + d->u.inprocess.len - d->u.inprocess.offset); + if (end) { + d->u.inprocess.line_cache = xstrndup + (cur, end - cur + 1); + return d->u.inprocess.line_cache; + } else + return NULL; + } +} + +int decompress_wait (decompress *d) +{ + if (d->tag == DECOMPRESS_PIPELINE) + return pipeline_wait (d->u.p); + else { + assert (d->tag == DECOMPRESS_INPROCESS); + return 0; + } +} + +void decompress_free (decompress *d) +{ + if (!d) + return; + if (d->tag == DECOMPRESS_PIPELINE) + pipeline_free (d->u.p); + else { + assert (d->tag == DECOMPRESS_INPROCESS); + free (d->u.inprocess.line_cache); + free (d->u.inprocess.buf); + } + free (d); +} diff --git a/src/decompress.h b/src/decompress.h new file mode 100644 index 0000000..f10ab88 --- /dev/null +++ b/src/decompress.h @@ -0,0 +1,139 @@ +/* + * decompress.h: interface to decompression abstraction layer + * + * 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 + */ + +#ifndef MAN_DECOMPRESS_H +#define MAN_DECOMPRESS_H + +#include <stdbool.h> + +#include "pipeline.h" + +struct decompress; +typedef struct decompress decompress; + +/* Flags, combined using bitwise-or. */ +enum { + /* Allow the resulting decompressor to be constructed by reading and + * buffering the decompressed file contents in-process, rather than + * by starting a subprocess and streaming the output. This is + * suitable if and only if the file contents are only going to be + * handled in-process rather than being passed as input to some + * other program, but if that is the case then this is a significant + * optimization. + */ + DECOMPRESS_ALLOW_INPROCESS = 1 +}; + +/* Open a decompressor reading from FILENAME. The caller must start the + * resulting decompressor. If the DECOMPRESS_ALLOW_INPROCESS flag is given, + * then the resulting decompressor may be in-process (in which case + * decompress_get_pipeline will fail). + */ +decompress *decompress_open (const char *filename, int flags); + +/* Open a decompressor reading from file descriptor FD. The caller must + * start the resulting decompressor. This always uses pipeline-based + * decompression, since if it attempted to decompress data in process it + * would be unable to recover if it found that the data was too large. + */ +decompress *decompress_fdopen (int fd); + +/* Return true if and only if this is a pipeline-based decompressor. */ +bool decompress_is_pipeline (decompress *d); + +/* Get the pipeline corresponding to a decompressor. Raises an assertion + * failure if this is not a pipeline-based decompressor. + */ +pipeline *decompress_get_pipeline (decompress *d); + +/* Return the start of the buffer stored in an in-process decompressor. + * Raises an assertion failure if this is not an in-process decompressor. + */ +const char *decompress_inprocess_buf (decompress *d); + +/* Return the total number of uncompressed bytes stored in an in-process + * decompressor. Raises an assertion failure if this is not an in-process + * decompressor. + */ +size_t decompress_inprocess_len (decompress *d); + +/* Replace an in-process decompressor's entire buffered file contents. + * + * In-process decompression works by buffering the whole file in memory, + * which works because we constrain it to only ever dealing with small + * files, and allows us to emulate streaming without having to resort to + * subprocesses, threads, or coroutines. However, there are some cases + * (notably encoding conversion) where it's useful to be able to do some + * kind of processing on the file contents in a way that similarly looks + * like streaming to its consumers. To allow for this, we allow consumers + * of decompressed data to replace the buffered file contents and reset the + * read offset so that their consumers in turn get the same useful read/peek + * API. + * + * This is of course a hack, and wouldn't be a wise thing to include in a + * general-purpose library API, but this is only used within man-db. + */ +void decompress_inprocess_replace (decompress *d, char *buf, size_t len); + +/* Start the processes in a pipeline-based decompressor. Does nothing for + * in-process decompressors. + */ +void decompress_start (decompress *d); + +/* Read len bytes of data from the decompressor, returning the data block. + * len is updated with the number of bytes read. + */ +const char *decompress_read (decompress *d, size_t *len); + +/* Look ahead in the decompressor's output for len bytes of data, returning + * the data block. len is updated with the number of bytes read. The + * starting position of the next read or peek is not affected by this call. + */ +const char *decompress_peek (decompress *d, size_t *len); + +/* Skip over and discard len bytes of data from the peek cache. Asserts that + * enough data is available to skip, so you may want to check using + * pipeline_peek_size first. + */ +void decompress_peek_skip (decompress *d, size_t len); + +/* Read a line of data from the decompressor, returning it. */ +const char *decompress_readline (decompress *d); + +/* Look ahead in the decompressor's output for a line of data, returning it. + * The starting position of the next read or peek is not affected by this + * call. + */ +const char *decompress_peekline (decompress *d); + +/* Wait for a decompressor to complete and return its combined exit status. + * For in-process decompressors, simply returns 0. + */ +int decompress_wait (decompress *d); + +/* Destroy a decompressor. Safely does nothing on NULL. For pipeline-based + * decompressors, may wait for the pipeline to complete if it has not already + * done so. + */ +void decompress_free (decompress *d); + +#endif /* MAN_DECOMPRESS_H */ diff --git a/src/descriptions.c b/src/descriptions.c new file mode 100644 index 0000000..de2dfb9 --- /dev/null +++ b/src/descriptions.c @@ -0,0 +1,163 @@ +/* + * 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 <stdbool.h> +#include <string.h> +#include <stdlib.h> + +#include "gl_array_list.h" +#include "gl_xlist.h" +#include "xalloc.h" +#include "xstrndup.h" + +#include "manconfig.h" + +#include "debug.h" +#include "util.h" + +#include "descriptions.h" + +/* Free a page description. */ +static void page_description_free (const void *value) +{ + struct page_description *desc = (struct page_description *) value; + + free (desc->name); + free (desc->whatis); + free (desc); +} + +/* Parse the description in a whatis line returned by find_name() into a + * list of names and whatis descriptions. + */ +gl_list_t parse_descriptions (const char *base, const char *whatis) +{ + const char *sep, *nextsep; + gl_list_t descs; + bool seen_base = false; + + descs = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, + page_description_free, true); + + if (!whatis) + return descs; + + 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 (!gl_list_size (descs)) + /* 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); + struct page_description *desc; + + /* 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. */ + desc = xmalloc (sizeof *desc); + desc->name = name; /* steal memory */ + desc->whatis = dash ? trim_spaces (dash + 3) : NULL; + gl_list_add_last (descs, desc); + + if (base && STREQ (base, desc->name)) + seen_base = true; + } + + 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) { + struct page_description *desc = xmalloc (sizeof *desc); + + desc->name = xstrdup (base); + desc->whatis = NULL; + if (gl_list_size (descs)) { + const struct page_description *first = + gl_list_get_at (descs, 0); + if (first->whatis) + desc->whatis = xstrdup (first->whatis); + } + gl_list_add_last (descs, desc); + } + + return descs; +} diff --git a/src/descriptions.h b/src/descriptions.h new file mode 100644 index 0000000..0712b64 --- /dev/null +++ b/src/descriptions.h @@ -0,0 +1,39 @@ +/* + * 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 "gl_list.h" + +#include "filenames.h" + +#include "mydbm.h" + +struct page_description { + char *name; + char *whatis; +}; + +/* Returns a list of struct page_description. */ +extern gl_list_t parse_descriptions (const char *base, const char *whatis); +extern void store_descriptions (MYDBM_FILE dbf, gl_list_t descs, + struct mandata *info, + const char *path, const char *base, + gl_list_t trace); diff --git a/src/descriptions_store.c b/src/descriptions_store.c new file mode 100644 index 0000000..8276973 --- /dev/null +++ b/src/descriptions_store.c @@ -0,0 +1,250 @@ +/* + * 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 <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include "gettext.h" +#define _(String) gettext (String) + +#include "error.h" +#include "gl_array_list.h" +#include "gl_hash_map.h" +#include "gl_xlist.h" +#include "gl_xmap.h" +#include "stat-time.h" +#include "xalloc.h" + +#include "manconfig.h" + +#include "debug.h" +#include "filenames.h" +#include "glcontainers.h" + +#include "db_storage.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 PARENT a prefix of CHILD, such that CHILD is in the manual hierarchy + * PARENT? This requires that the part of CHILD following PARENT start with + * "/man". + */ +static int is_prefix (const char *parent, const char *child) +{ + return (STRNEQ (child, parent, strlen (parent)) && + STRNEQ (child + strlen (parent), "/man", 4)); +} + +/* Take a list of descriptions returned by parse_descriptions() and store + * it into the database. + */ +void store_descriptions (MYDBM_FILE dbf, gl_list_t descs, struct mandata *info, + const char *path, const char *base, gl_list_t trace) +{ + const struct page_description *desc; + const char *trace_name; + gl_map_t trace_infos; + gl_list_t whatis_infos; + struct mandata *whatis_info; + const struct mandata *pointer_info; + + assert (trace); + assert (gl_list_size (trace) > 0); + + if (gl_list_size (descs)) { + GL_LIST_FOREACH (trace, trace_name) + debug ("trace: '%s'\n", trace_name); + } + + trace_infos = new_string_map (GL_HASH_MAP, + (gl_mapvalue_dispose_fn) + free_mandata_struct); + whatis_infos = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, + (gl_listelement_dispose_fn) + free_mandata_struct, + true); + + GL_LIST_FOREACH (trace, trace_name) + gl_map_put (trace_infos, xstrdup (trace_name), + filename_info (trace_name, quiet < 2)); + + GL_LIST_FOREACH (descs, desc) { + /* Either it's the real thing or merely a reference. Get the + * id and pointer right in either case. + */ + bool found_real_page = false; + bool found_external = false; + + whatis_info = XZALLOC (struct mandata); + whatis_info->ext = xstrdup (info->ext); + whatis_info->sec = xstrdup (info->sec); + whatis_info->id = info->id; + if (info->comp) + whatis_info->comp = xstrdup (info->comp); + if (info->filter) + whatis_info->filter = xstrdup (info->filter); + if (desc->whatis) + whatis_info->whatis = xstrdup (desc->whatis); + whatis_info->mtime = info->mtime; + + if (STREQ (base, desc->name)) + found_real_page = true; + else { + GL_LIST_FOREACH (trace, trace_name) { + const struct mandata *trace_info; + struct stat st; + + trace_info = gl_map_get (trace_infos, + trace_name); + if (!trace_info || + !STREQ (trace_info->name, desc->name)) + continue; + + if (path && !is_prefix (path, trace_name)) { + /* Link outside this manual + * hierarchy; skip this description. + */ + found_external = true; + break; + } + free (whatis_info->ext); + whatis_info->ext = xstrdup (trace_info->ext); + free (whatis_info->sec); + whatis_info->sec = xstrdup (trace_info->sec); + if (!gl_list_next_node (trace, trace_node)) { + if (info->id == SO_MAN) + whatis_info->id = ULT_MAN; + } else { + if (info->id == ULT_MAN) + whatis_info->id = SO_MAN; + } + free (whatis_info->comp); + if (trace_info->comp) + whatis_info->comp = xstrdup + (trace_info->comp); + else + whatis_info->comp = NULL; + if (lstat (trace_name, &st) == 0) + whatis_info->mtime = get_stat_mtime + (&st); + else + whatis_info->mtime = info->mtime; + found_real_page = true; + } + } + + if (found_external) { + debug ("skipping '%s'; link outside manual " + "hierarchy\n", desc->name); + free_mandata_struct (whatis_info); + continue; + } + + if (!found_real_page) { + whatis_info->name = xstrdup (desc->name); + if (info->id < STRAY_CAT) + whatis_info->id = WHATIS_MAN; + else + whatis_info->id = WHATIS_CAT; + /* Don't waste space storing the whatis in the db + * more than once. + */ + free (whatis_info->whatis); + whatis_info->whatis = NULL; + gl_list_add_last (whatis_infos, whatis_info); + continue; + } + + debug ("name = '%s', ext = '%s', id = %c\n", + desc->name, whatis_info->ext, whatis_info->id); + if (dbstore (dbf, whatis_info, desc->name) > 0) { + gripe_bad_store (base, whatis_info->ext); + free_mandata_struct (whatis_info); + goto out; + } + + free_mandata_struct (whatis_info); + } + + /* The pointer for a WHATIS_MAN or WHATIS_CAT entry should be the + * last entry in the trace that has the same section and extension + * as the starting page (which is always the first entry in the + * trace). If we were to add WHATIS_* entries for different + * extensions, then try_db -> add_candidate -> make_filename in + * man(1) would end up constructing a path that doesn't exist and is + * thus unusable. + */ + pointer_info = NULL; + GL_LIST_FOREACH (trace, trace_name) { + const struct mandata *trace_info; + + trace_info = gl_map_get (trace_infos, trace_name); + if (trace_info && + STREQ (trace_info->sec, info->sec) && + STREQ (trace_info->ext, info->ext)) + pointer_info = trace_info; + } + assert (pointer_info); + + GL_LIST_FOREACH (whatis_infos, whatis_info) { + char *name; + + name = whatis_info->name; + whatis_info->name = NULL; + + whatis_info->pointer = xstrdup (pointer_info->name); + + debug ("name = '%s', ext = '%s', id = %c, pointer = '%s'\n", + name, whatis_info->ext, whatis_info->id, + whatis_info->pointer); + if (dbstore (dbf, whatis_info, name) > 0) { + gripe_bad_store (base, whatis_info->ext); + free (name); + goto out; + } + + free (name); + } + +out: + gl_list_free (whatis_infos); + gl_map_free (trace_infos); +} diff --git a/src/globbing.c b/src/globbing.c new file mode 100644 index 0000000..b933898 --- /dev/null +++ b/src/globbing.c @@ -0,0 +1,435 @@ +/* + * 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 <assert.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <glob.h> +#include <sys/types.h> +#include <dirent.h> + +#include "error.h" +#include "fnmatch.h" +#include "gl_array_list.h" +#include "gl_hash_map.h" +#include "gl_xlist.h" +#include "gl_xmap.h" +#include "regex.h" +#include "xalloc.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "debug.h" +#include "glcontainers.h" +#include "util.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_names { + char **names; + size_t names_len, names_max; +}; + +static void dirent_names_free (const void *value) +{ + struct dirent_names *cache = (struct dirent_names *) value; + size_t i; + + for (i = 0; i < cache->names_len; ++i) + free (cache->names[i]); + free (cache->names); + free (cache); +} + +static gl_map_t dirent_map = 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_names *update_directory_cache (const char *path) +{ + struct dirent_names *cache; + DIR *dir; + struct dirent *entry; + + if (!dirent_map) { + dirent_map = new_string_map (GL_HASH_MAP, dirent_names_free); + push_cleanup ((cleanup_fun) gl_map_free, dirent_map, 0); + } + cache = (struct dirent_names *) gl_map_get (dirent_map, 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_names); + 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); + + gl_map_put (dirent_map, xstrdup (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 match_regex_in_directory (const char *path, const char *pattern, + int opts, gl_list_t matched, + struct dirent_names *cache) +{ + int flags; + regex_t preg; + size_t i; + + debug ("matching regex in %s: %s\n", path, pattern); + + flags = REG_EXTENDED | REG_NOSUB | + ((opts & LFF_MATCHCASE) ? 0 : REG_ICASE); + + xregcomp (&preg, pattern, flags); + + for (i = 0; i < cache->names_len; ++i) { + if (regexec (&preg, cache->names[i], 0, NULL, 0) != 0) + continue; + + debug ("matched: %s/%s\n", path, cache->names[i]); + + gl_list_add_last (matched, + xasprintf ("%s/%s", path, cache->names[i])); + } + + regfree (&preg); +} + +static void match_wildcard_in_directory (const char *path, const char *pattern, + int opts, gl_list_t matched, + struct dirent_names *cache) +{ + int flags; + struct pattern_bsearch pattern_start = { NULL, -1 }; + char **bsearched; + size_t i; + + debug ("matching wildcard in %s: %s\n", path, pattern); + + flags = (opts & LFF_MATCHCASE) ? 0 : FNM_CASEFOLD; + + 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) { + assert (pattern_start.pattern); + 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]); + + gl_list_add_last (matched, + xasprintf ("%s/%s", path, cache->names[i])); + } + + free (pattern_start.pattern); +} + +static void match_in_directory (const char *path, const char *pattern, + int opts, gl_list_t matched) +{ + struct dirent_names *cache; + + cache = update_directory_cache (path); + if (!cache) { + debug ("directory cache update failed\n"); + return; + } + + if (opts & LFF_REGEX) + match_regex_in_directory (path, pattern, opts, matched, cache); + else + match_wildcard_in_directory (path, pattern, opts, matched, + cache); +} + +gl_list_t look_for_file (const char *hier, const char *sec, + const char *unesc_name, bool cat, int opts) +{ + gl_list_t matched; + char *pattern, *path = NULL; + static int layout = -1; + char *name; + + matched = new_string_list (GL_ARRAY_LIST, false); + + /* 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) { + gl_list_t dirs; + const char *dir; + + dirs = new_string_list (GL_ARRAY_LIST, false); + pattern = xasprintf ("%s\t*", cat ? "cat" : "man"); + assert (pattern); + *strrchr (pattern, '\t') = *sec; + match_in_directory (hier, pattern, LFF_MATCHCASE, dirs); + free (pattern); + + pattern = make_pattern (name, sec, opts); + GL_LIST_FOREACH (dirs, dir) { + if (path) + *path = '\0'; + match_in_directory (dir, pattern, opts, matched); + } + free (pattern); + gl_list_free (dirs); + } + + /* Try HPUX style compressed man pages */ + if ((layout & LAYOUT_HPUX) && gl_list_size (matched) == 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, matched); + free (pattern); + } + + /* Try man pages without the section extension --- IRIX man pages */ + if ((layout & LAYOUT_IRIX) && gl_list_size (matched) == 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, matched); + free (pattern); + } + + /* Try Solaris style man page directories */ + if ((layout & LAYOUT_SOLARIS) && gl_list_size (matched) == 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, matched); + free (pattern); + } + + /* BSD cat pages take the extension .0 */ + if ((layout & LAYOUT_BSD) && gl_list_size (matched) == 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, matched); + free (pattern); + } + + free (name); + free (path); + + return matched; +} + +gl_list_t expand_path (const char *path) +{ + int res = 0; + gl_list_t result; + glob_t globbuf; + + result = new_string_list (GL_ARRAY_LIST, false); + + res = glob (path, GLOB_NOCHECK, NULL, &globbuf); + /* if glob failed, return the given path */ + if (res != 0) + gl_list_add_last (result, xstrdup (path)); + else { + size_t i; + for (i = 0; i < globbuf.gl_pathc; ++i) + gl_list_add_last (result, + xstrdup (globbuf.gl_pathv[i])); + } + + globfree (&globbuf); + + return result; +} diff --git a/src/globbing.h b/src/globbing.h new file mode 100644 index 0000000..7601395 --- /dev/null +++ b/src/globbing.h @@ -0,0 +1,38 @@ +/* + * 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 + */ + +#include <stdbool.h> + +#include "gl_list.h" + +enum look_for_file_opts { + LFF_MATCHCASE = 1, + LFF_REGEX = 2, + LFF_WILDCARD = 4 +}; + +/* globbing.c */ +extern gl_list_t look_for_file (const char *hier, const char *sec, + const char *unesc_name, bool cat, int opts); + +/* Expand path with wildcards into list of all existing directories. */ +extern gl_list_t expand_path (const char *path); diff --git a/src/globbing_test.c b/src/globbing_test.c new file mode 100644 index 0000000..61fcd54 --- /dev/null +++ b/src/globbing_test.c @@ -0,0 +1,140 @@ +/* + * 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 <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +#include "argp.h" +#include "error.h" +#include "gl_list.h" +#include "progname.h" + +#include "gettext.h" +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "debug.h" +#include "glcontainers.h" +#include "util.h" + +#include "globbing.h" + +extern const char *extension; +static bool match_case = false; +static bool regex_opt = false; +static bool wildcard = false; +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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("extension", 'e', N_("EXTENSION"), + N_("limit search to extension type EXTENSION")), + OPT ("ignore-case", 'i', 0, + N_("look for pages case-insensitively (default)")), + OPT ("match-case", 'I', 0, N_("look for pages case-sensitively")), + OPT ("regex", 'r', 0, N_("interpret page name as a regex")), + OPT ("wildcard", 'w', 0, N_("the page name contains wildcards")), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = true; + return 0; + case 'e': + extension = arg; + return 0; + case 'i': + match_case = false; + return 0; + case 'I': + match_case = true; + return 0; + case 'r': + regex_opt = true; + return 0; + case 'w': + wildcard = true; + 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; + case ARGP_KEY_NO_ARGS: + argp_usage (state); + break; + } + 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); + assert (remaining_args); + + for (i = 0; i <= 1; i++) { + gl_list_t files; + const char *file; + + files = look_for_file (remaining_args[0], remaining_args[1], + remaining_args[2], (bool) i, + (match_case ? LFF_MATCHCASE : 0) | + (regex_opt ? LFF_REGEX : 0) | + (wildcard ? LFF_WILDCARD : 0)); + GL_LIST_FOREACH (files, file) + printf ("%s\n", file); + gl_list_free (files); + } + return 0; +} diff --git a/src/lexgrog.c b/src/lexgrog.c new file mode 100644 index 0000000..56663b5 --- /dev/null +++ b/src/lexgrog.c @@ -0,0 +1,5398 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "manconfig.h" + +/* Flex emits several functions which might reasonably have various + * attributes applied and many unused macros; none of these are our problem. + */ +#if GNUC_PREREQ(8,0) +# pragma GCC diagnostic ignored "-Wsuggest-attribute=malloc" +#endif +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#pragma GCC diagnostic ignored "-Wunused-macros" + +#line 17 "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 141 +#define YY_END_OF_BUFFER 142 +/* 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[1585] = + { 0, + 0, 0, 0, 0, 67, 67, 67, 67, 0, 0, + 0, 0, 0, 0, 0, 0, 119, 119, 0, 0, + 0, 0, 0, 0, 126, 126, 8, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 142, 141, 29, 29, + 29, 140, 67, 67, 140, 140, 140, 138, 140, 136, + 83, 67, 67, 140, 83, 106, 106, 106, 101, 106, + 108, 108, 107, 113, 113, 113, 112, 118, 118, 118, + 118, 118, 119, 121, 121, 120, 123, 123, 122, 125, + 125, 124, 126, 126, 140, 137, 140, 140, 140, 7, + 10, 7, 7, 6, 6, 6, 4, 18, 18, 18, + + 19, 19, 0, 28, 0, 27, 27, 29, 67, 0, + 138, 0, 0, 139, 67, 67, 139, 135, 139, 139, + 135, 83, 67, 0, 0, 138, 0, 136, 70, 67, + 76, 0, 62, 0, 0, 64, 66, 0, 0, 61, + 63, 61, 0, 0, 0, 0, 0, 0, 67, 0, + 67, 67, 139, 135, 83, 67, 0, 64, 0, 106, + 0, 0, 101, 94, 95, 96, 97, 98, 99, 100, + 108, 107, 113, 0, 0, 0, 112, 112, 118, 0, + 0, 0, 119, 121, 120, 123, 122, 125, 124, 126, + 137, 0, 0, 126, 126, 139, 139, 139, 139, 126, + + 137, 54, 0, 126, 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, 57, 0, + 0, 67, 0, 0, 36, 36, 36, 36, 36, 36, + 36, 36, 0, 50, 0, 0, 0, 0, 0, 0, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 48, 0, 57, 0, 49, 0, 58, 76, + 72, 0, 0, 0, 0, 0, 0, 0, 0, 75, + 75, 75, 0, 0, 0, 0, 0, 0, 69, 0, + + 77, 78, 0, 79, 0, 0, 81, 0, 0, 67, + 0, 0, 36, 36, 36, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 93, 102, 103, 104, 105, 101, 94, 95, 96, 97, + 98, 99, 100, 0, 0, 0, 0, 0, 0, 60, + 0, 126, 38, 38, 126, 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, 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, 57, + 0, 0, 0, 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, 36, 51, 41, 0, 0, 0, + 0, 0, 128, 59, 0, 130, 47, 129, 0, 0, + 30, 0, 0, 0, 127, 34, 53, 0, 35, 33, + 52, 32, 0, 0, 0, 49, 84, 73, 62, 55, + + 63, 68, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 85, 0, 87, 92, 88, 89, 90, + 91, 0, 0, 0, 64, 0, 93, 102, 103, 104, + 105, 0, 0, 0, 116, 114, 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, 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, 0, 36, 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, 36, 36, 36, 40, 132, 131, + 45, 128, 59, 46, 47, 129, 134, 133, 30, 42, + 44, 31, 127, 34, 34, 53, 43, 35, 33, 52, + 32, 0, 84, 55, 74, 0, 71, 56, 80, 82, + + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 85, 86, 87, 92, 88, 89, + 90, 91, 0, 65, 0, 110, 0, 116, 117, 114, + 115, 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, 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, 4, 4, 4, 4, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 3, 25, 26, 22, + 24, 23, 56, 36, 36, 36, 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, 36, 132, 131, 45, + 134, 133, 44, 43, 56, 56, 82, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 86, 65, 109, + 110, 111, 117, 115, 7, 2, 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, 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, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 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, 3, 36, + + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 109, 111, 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, 1, 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, 1, 4, 4, 1, 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, 4, 4, 4, + 4, 4, 1, 1, 0, 0, 1, 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, 0, 0, 0, 0, 0, + 0, 3, 36, 36, 36, 7, 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, 1, 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, 1, 4, 4, 1, 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, 4, 4, 4, 4, + 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, + 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, + + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 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, 0, 0, + 0, 7, 3, 3, 4, 4, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 0, 0, 0, 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, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, 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, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 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, 90, 1, 1, 91, 92, 1, 1, + 93, 1, 94, 95, 96, 97, 1, 1, 98, 1, + 99, 100, 1, 1, 1, 101, 102, 103, 1, 1, + 104, 1, 1, 105, 106, 107, 108, 109, 110, 111, + 1, 1, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 1, 121, 122, 123, 1, 124, 125, 126, 127, + 1, 1, 1, 1, 128, 129, 1, 1, 1, 1, + + 1, 1, 1, 130, 1, 1, 1, 131, 132, 1, + 1, 1, 1, 1, 1, 133, 134, 1, 1, 1, + 1, 1, 1, 135, 1, 1, 1, 136, 137, 1, + 138, 1, 1, 1, 139, 140, 1, 1, 141, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[142] = + { 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, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1 + } ; + +static const flex_int16_t yy_base[1769] = + { 0, + 0, 0, 0, 2, 6, 0, 146, 150, 153, 154, + 234, 0, 375, 0, 152, 513, 6063, 6062, 591, 0, + 732, 0, 873, 0, 157, 166, 161, 174, 176, 177, + 0, 0, 181, 186, 6060, 6050, 6044, 7576, 7576, 206, + 6040, 7576, 516, 523, 1013, 5978, 5977, 191, 6014, 0, + 1066, 1024, 1031, 6024, 512, 7576, 6023, 5999, 202, 522, + 7576, 6007, 0, 7576, 5996, 156, 224, 7576, 5985, 5910, + 5888, 5881, 0, 7576, 5926, 0, 7576, 5915, 0, 7576, + 5905, 0, 1036, 1042, 5904, 534, 216, 5901, 5840, 0, + 551, 5893, 5890, 7576, 5883, 5830, 1054, 0, 546, 5881, + + 7576, 5871, 565, 569, 5861, 0, 1120, 1090, 1155, 1171, + 557, 5846, 1099, 7576, 1176, 1187, 1198, 5798, 5797, 5834, + 1252, 1327, 1216, 5834, 5601, 572, 574, 0, 7576, 1026, + 0, 1223, 7576, 1193, 511, 579, 7576, 1046, 519, 5607, + 7576, 7576, 5672, 0, 5671, 5675, 1332, 1054, 1206, 1020, + 1234, 1272, 5678, 1280, 1010, 1359, 1356, 7576, 1044, 7576, + 5600, 1245, 1418, 1018, 1019, 1058, 1085, 1112, 1117, 1132, + 7576, 0, 7576, 5609, 5615, 5614, 1181, 1204, 7576, 5598, + 5603, 5608, 0, 7576, 0, 7576, 0, 7576, 0, 1363, + 1370, 1426, 5668, 1393, 1442, 5669, 1050, 5666, 5613, 1447, + + 1451, 1455, 5666, 1227, 7576, 0, 1459, 1503, 5665, 1463, + 5662, 7576, 5659, 5658, 5657, 5656, 1435, 5655, 0, 1276, + 5658, 1437, 1282, 7576, 7576, 5657, 1472, 5647, 0, 1484, + 1490, 5578, 177, 1481, 5576, 1153, 5569, 1476, 1212, 1239, + 1252, 1521, 1552, 1558, 5643, 1563, 1569, 1034, 1100, 169, + 1642, 1717, 1431, 7576, 5642, 1543, 5601, 1576, 5600, 460, + 1472, 1553, 1624, 5570, 1200, 0, 5565, 5577, 508, 1099, + 5574, 1548, 7576, 5624, 1315, 1277, 0, 5622, 1532, 0, + 7576, 0, 5511, 160, 5510, 5485, 5500, 5487, 5495, 7576, + 0, 0, 1582, 0, 0, 983, 5481, 5496, 7576, 0, + + 7576, 7576, 0, 7576, 0, 1718, 7576, 1590, 0, 1606, + 1063, 5559, 1601, 5558, 1802, 1877, 5482, 1618, 5483, 5474, + 1041, 5473, 5471, 1586, 1123, 5460, 5475, 1152, 5458, 5473, + 1547, 1610, 1624, 1646, 1653, 1660, 1664, 1670, 1677, 1694, + 1703, 1708, 1710, 5465, 5460, 5457, 5473, 5462, 5461, 1744, + 1748, 1753, 0, 1757, 1764, 5530, 1777, 5526, 5472, 7576, + 1811, 0, 1962, 5525, 0, 1820, 5497, 499, 525, 979, + 1233, 1362, 1941, 1450, 5371, 5452, 5382, 5365, 98, 5383, + 5400, 5376, 1145, 5377, 5385, 5481, 0, 5476, 5475, 5474, + 5473, 1868, 5472, 5434, 5457, 5430, 5455, 5428, 7576, 5427, + + 0, 1728, 1752, 1758, 1759, 1780, 1834, 1850, 1854, 1856, + 1254, 5389, 5404, 1312, 5387, 5402, 5465, 1897, 1905, 1151, + 1916, 1967, 1289, 1193, 1901, 1910, 5464, 1990, 1373, 2013, + 1470, 1423, 2008, 1998, 2028, 1179, 1864, 2109, 1574, 1167, + 1625, 1533, 1303, 2052, 5463, 1923, 0, 2160, 5462, 5461, + 2007, 5451, 2020, 5459, 2035, 2044, 1184, 5458, 5457, 2185, + 2236, 2309, 1493, 2391, 2074, 7576, 1980, 1863, 1888, 1940, + 1992, 2031, 2047, 2057, 2079, 2098, 2104, 2111, 2112, 2117, + 2118, 2119, 2123, 2125, 2129, 2173, 0, 2131, 2162, 2163, + 0, 2164, 1519, 5376, 5391, 0, 2168, 7576, 7576, 2169, + + 7576, 7576, 0, 0, 5446, 5391, 5389, 0, 0, 5436, + 5431, 5438, 2244, 1339, 2362, 1476, 1059, 1729, 1636, 1683, + 2133, 5437, 2187, 2174, 5357, 2189, 2198, 2239, 2240, 2241, + 2246, 1545, 5355, 5370, 7576, 5379, 2250, 2252, 2254, 2288, + 2289, 5367, 5373, 5341, 2398, 2321, 5340, 0, 2418, 2423, + 5397, 0, 2394, 0, 0, 2472, 5398, 0, 2329, 1614, + 1648, 2369, 1791, 2401, 1797, 1852, 1858, 1877, 5384, 2343, + 1895, 1258, 1725, 1536, 5264, 5263, 1693, 5260, 5281, 5298, + 5264, 5298, 5267, 5380, 0, 5377, 5376, 5375, 5374, 2611, + 2750, 5373, 5372, 7576, 7576, 7576, 7576, 7576, 7576, 0, + + 0, 0, 2322, 0, 0, 0, 2323, 5322, 2380, 2392, + 0, 5364, 2361, 2431, 2400, 2440, 2454, 2459, 2460, 2464, + 2465, 2466, 2477, 2478, 2482, 2484, 2486, 2488, 2490, 2494, + 2500, 2501, 2502, 0, 2509, 2515, 2516, 0, 2521, 0, + 0, 0, 5317, 1645, 5316, 5291, 5306, 5293, 5301, 0, + 0, 2522, 1815, 1909, 5287, 5302, 0, 2863, 0, 0, + 2889, 0, 1781, 2521, 0, 2523, 1894, 7576, 0, 0, + 0, 2527, 2533, 2547, 2548, 2549, 0, 0, 2553, 2554, + 0, 2555, 2559, 2560, 2561, 0, 0, 2565, 2566, 0, + 2570, 5312, 2571, 2572, 7576, 5311, 7576, 2576, 7576, 0, + + 2577, 5284, 2578, 2582, 2583, 2584, 2588, 2589, 1935, 5282, + 5297, 1989, 5280, 5295, 2590, 2594, 2595, 2615, 2617, 2619, + 2621, 2623, 5305, 7576, 5292, 2625, 5279, 2627, 2629, 2631, + 2633, 2639, 2657, 0, 2665, 2644, 5344, 1956, 2669, 1971, + 5334, 1820, 1975, 2221, 2647, 2380, 2614, 2680, 2609, 2696, + 2623, 5334, 2603, 2635, 2624, 5304, 5228, 5251, 5233, 1277, + 1993, 5251, 5213, 5228, 5173, 2675, 5171, 5166, 5166, 5295, + 0, 0, 0, 0, 2972, 2734, 2658, 2658, 2651, 2652, + 2661, 2760, 2674, 5171, 1148, 5252, 5182, 5169, 125, 5187, + 5204, 5178, 1994, 5179, 5187, 2955, 2672, 2672, 2665, 2668, + + 2680, 2988, 2688, 5160, 1360, 5241, 5171, 5158, 1776, 5176, + 5193, 5168, 2106, 5169, 5177, 0, 0, 0, 0, 0, + 0, 0, 2709, 2139, 5194, 5209, 2264, 5192, 5207, 0, + 2713, 0, 0, 0, 0, 2724, 2725, 2756, 2762, 2763, + 0, 0, 2771, 2778, 0, 2780, 2793, 2798, 2802, 0, + 0, 2804, 2809, 0, 2816, 0, 0, 2820, 0, 0, + 0, 1965, 5217, 3089, 3115, 2021, 2064, 0, 0, 0, + 0, 0, 0, 0, 2824, 2826, 0, 2830, 2832, 2836, + 2838, 2840, 2842, 2844, 2846, 0, 5216, 2848, 7576, 2850, + 2852, 2854, 2856, 2870, 0, 2941, 2763, 2905, 5260, 2931, + + 2958, 2942, 3001, 2958, 2962, 2966, 5177, 5152, 2399, 5135, + 5132, 5130, 5117, 5135, 2399, 1959, 2623, 5124, 5124, 5138, + 5238, 0, 0, 3198, 3181, 2976, 2982, 2983, 2986, 2997, + 3214, 3003, 5113, 1977, 5194, 5123, 5110, 2160, 5128, 5143, + 5113, 2781, 5113, 5118, 3206, 2979, 3001, 3045, 2993, 3215, + 2986, 2997, 3000, 3001, 5203, 2965, 2999, 2967, 3331, 3281, + 2328, 2807, 5081, 5080, 2263, 5075, 5096, 5113, 5077, 5110, + 5047, 3242, 2996, 3018, 3197, 3041, 3357, 3034, 3166, 3180, + 3183, 5152, 2983, 3183, 2999, 5150, 3398, 2381, 2844, 5027, + 5023, 2912, 5017, 5032, 5046, 5012, 5048, 5017, 0, 2983, + + 5079, 3094, 0, 0, 0, 0, 0, 0, 0, 3167, + 0, 0, 3202, 0, 3228, 3210, 0, 3214, 3265, 0, + 3210, 3280, 3225, 3226, 3210, 3242, 3342, 2696, 5036, 3287, + 5023, 4995, 5014, 5012, 4988, 2989, 4999, 4980, 4978, 4988, + 4979, 4972, 5050, 0, 0, 3440, 3423, 3260, 3260, 3277, + 3279, 3292, 3456, 3298, 4926, 2345, 5005, 4935, 4916, 2508, + 4934, 4947, 4920, 3075, 4895, 4899, 3334, 3342, 3364, 3375, + 3357, 3457, 3351, 3361, 3362, 3363, 4982, 3301, 3355, 3183, + 3573, 3523, 2753, 3142, 4860, 4859, 3215, 4855, 4876, 4892, + 4857, 4893, 4860, 3448, 3388, 3335, 3404, 3484, 3399, 4966, + + 3348, 3406, 3422, 3492, 3424, 3591, 3576, 3438, 3627, 3450, + 4958, 3441, 3471, 3459, 3673, 3607, 3672, 3720, 4928, 4852, + 4873, 4855, 2612, 2383, 4850, 4811, 4826, 4798, 3389, 4795, + 4760, 4759, 3507, 3444, 3444, 3469, 3584, 3493, 4880, 3363, + 3494, 3519, 3605, 3520, 3695, 3673, 3530, 3748, 3536, 4880, + 3577, 3612, 3601, 0, 3742, 3793, 3797, 4850, 4773, 4795, + 4774, 2659, 2542, 4758, 4714, 4729, 4701, 3655, 4698, 4689, + 4689, 0, 3470, 3647, 3681, 0, 3610, 3686, 3730, 3796, + 4696, 4694, 4650, 4662, 4643, 4656, 3802, 3825, 3843, 4632, + 3863, 4763, 4758, 4757, 3936, 3855, 3779, 3732, 3816, 3829, + + 3759, 3887, 3886, 1507, 3824, 1595, 1967, 2759, 3565, 3306, + 2986, 1385, 3593, 2487, 3663, 3856, 3825, 3892, 3946, 3879, + 3968, 3836, 3873, 3940, 3941, 2165, 3883, 3918, 3905, 3449, + 4011, 3890, 3450, 2058, 3621, 3828, 2982, 3648, 3265, 2646, + 3781, 1353, 3767, 3901, 3995, 3992, 4038, 4006, 3510, 3575, + 3832, 4013, 4022, 4015, 4050, 4044, 3882, 4090, 4051, 2855, + 4007, 4054, 4055, 4746, 4097, 4135, 4139, 1766, 2322, 3914, + 3646, 4070, 3949, 3591, 1810, 3993, 3817, 4101, 2700, 3511, + 3951, 4100, 3761, 4190, 4082, 4105, 3323, 3961, 4113, 4035, + 4194, 4103, 4141, 4108, 4233, 3674, 3897, 3975, 3910, 3997, + + 3999, 3207, 1523, 2690, 4109, 4081, 4117, 4116, 3835, 3900, + 2025, 3779, 4162, 4265, 4153, 4148, 4740, 4142, 4174, 4199, + 4255, 4214, 4218, 4221, 4743, 4646, 4626, 4596, 4569, 3598, + 4550, 4545, 4550, 4487, 4505, 4046, 4086, 4079, 4487, 4479, + 4489, 4585, 7576, 4222, 4228, 4200, 4140, 4468, 4447, 4466, + 4299, 4303, 4309, 4316, 4321, 4326, 4330, 4334, 4338, 4342, + 4441, 4514, 0, 0, 7576, 4320, 4198, 0, 4348, 4357, + 4357, 4237, 4363, 4322, 4326, 4317, 4333, 4400, 4481, 4386, + 4195, 4398, 4252, 4380, 4352, 4347, 4311, 4287, 4084, 4296, + 4279, 4276, 4285, 4274, 4228, 0, 0, 4323, 4358, 4168, + + 4130, 4128, 4124, 4159, 4133, 4402, 4406, 4428, 4150, 4237, + 4449, 4104, 4087, 4378, 4373, 4454, 4454, 0, 4470, 4432, + 4433, 4005, 3978, 3965, 3961, 3872, 3856, 4441, 4460, 4461, + 3826, 4498, 4375, 4430, 4070, 4154, 4023, 3844, 4503, 3790, + 4461, 4468, 4519, 4446, 4271, 3678, 3660, 3630, 4507, 4542, + 4543, 4553, 4559, 4565, 4569, 4573, 4610, 4611, 4620, 4624, + 4628, 3568, 4500, 4492, 4635, 4639, 3507, 4626, 4549, 0, + 4652, 4511, 4592, 3445, 3371, 3145, 3132, 3136, 2990, 4653, + 4765, 4692, 4665, 4819, 4719, 4675, 4873, 4925, 2965, 4326, + 4382, 4681, 4623, 4641, 4437, 4460, 4344, 2955, 4979, 4720, + + 4934, 4726, 5033, 4777, 5085, 4828, 5139, 4874, 5094, 4882, + 2868, 2747, 4664, 4660, 4991, 4990, 2739, 4736, 5140, 5146, + 4740, 5150, 5154, 4950, 5158, 5191, 4473, 4479, 4559, 4560, + 5237, 5281, 5333, 5377, 5429, 5473, 2729, 2618, 2586, 2578, + 5525, 4997, 5553, 4998, 5552, 5034, 5580, 5042, 5632, 5195, + 5660, 5214, 4536, 4571, 4610, 4646, 4954, 5036, 5111, 4787, + 2473, 2385, 2300, 4576, 4656, 4579, 2064, 5223, 1711, 4717, + 4640, 1697, 1563, 4722, 4771, 1553, 1537, 4725, 4777, 5122, + 1499, 4845, 5227, 7576, 5713, 5724, 5735, 5746, 5757, 5768, + 5779, 5790, 5801, 5812, 5823, 5827, 5838, 5849, 5860, 5871, + + 5882, 5893, 5904, 5915, 5926, 5937, 5948, 5959, 5963, 5974, + 5985, 5996, 6007, 6012, 6013, 6018, 6029, 6040, 6051, 6062, + 6073, 6084, 6095, 6106, 6117, 6128, 6139, 6150, 6161, 1225, + 6172, 6183, 6194, 6205, 6216, 6227, 6238, 6249, 1197, 6251, + 6262, 6273, 6284, 6295, 6306, 6317, 6328, 6339, 6350, 6361, + 6372, 6383, 6394, 6405, 6416, 6427, 6438, 6449, 6460, 6471, + 1086, 6473, 6484, 6495, 6506, 6517, 6528, 6539, 6550, 6561, + 6572, 6583, 6594, 6605, 6616, 6627, 6638, 6649, 6660, 6671, + 6682, 6693, 6704, 6715, 6726, 6737, 6748, 6759, 6770, 6781, + 6792, 6803, 6814, 6825, 6836, 6847, 6858, 6869, 6880, 6891, + + 6902, 6913, 6924, 6935, 6946, 6957, 6968, 6979, 6990, 7001, + 7012, 7023, 7034, 7045, 7056, 7067, 7078, 7089, 7100, 7111, + 7122, 7133, 7144, 7155, 7166, 7177, 7188, 7199, 7210, 7221, + 7232, 7243, 7254, 7265, 7276, 7287, 7298, 7303, 7313, 7324, + 7335, 7346, 7357, 7368, 7379, 7390, 7401, 7412, 7423, 7434, + 1022, 7445, 7456, 7467, 7478, 7489, 7500, 7507, 7513, 7523, + 553, 7528, 541, 7538, 7549, 7560, 7565, 182 + } ; + +static const flex_int16_t yy_def[1769] = + { 0, + 1585, 1585, 1586, 1586, 1584, 5, 5, 5, 1587, 1587, + 1584, 11, 1584, 13, 1588, 1588, 1589, 1589, 1584, 19, + 1584, 21, 1584, 23, 1590, 1590, 1591, 1591, 1592, 1592, + 1585, 1585, 1593, 1593, 1594, 1594, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1595, 1584, 1584, 1584, 1584, 1584, 1596, + 1584, 1584, 1595, 1584, 51, 1584, 1584, 1584, 1597, 1584, + 1584, 1584, 1598, 1584, 1584, 1584, 1599, 1584, 1584, 1584, + 1584, 1584, 1600, 1584, 1584, 1601, 1584, 1584, 1602, 1584, + 1584, 1603, 1584, 1595, 1584, 1584, 1584, 1584, 1584, 1604, + 1584, 1604, 1604, 1584, 1584, 1584, 1605, 1606, 1584, 1606, + + 1584, 1584, 1584, 1584, 1584, 1607, 1607, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1608, 1584, 1584, 1584, 1584, + 1584, 1584, 1595, 1584, 1584, 1584, 1584, 1609, 1584, 1584, + 1610, 1584, 1584, 1611, 1612, 1584, 1584, 1584, 1613, 1584, + 1584, 1584, 1614, 1615, 1616, 1584, 1584, 1584, 1584, 1584, + 1584, 1608, 1584, 121, 122, 1595, 1611, 1584, 1613, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1617, 1584, 1584, 1584, 1584, 1618, 1584, 1584, 1584, + 1584, 1584, 1619, 1584, 1620, 1584, 1621, 1584, 1622, 1584, + 1584, 1584, 1584, 1584, 1623, 1584, 1584, 1584, 1584, 1595, + + 1584, 1584, 1584, 1584, 1584, 1624, 1584, 1584, 1584, 1584, + 1624, 1584, 1584, 1625, 1626, 1625, 1626, 1625, 1627, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1628, 1628, + 1628, 1628, 1628, 1628, 1628, 1628, 1628, 1628, 1584, 1584, + 1584, 1584, 1629, 1584, 1629, 1629, 1629, 1629, 1629, 1629, + 1629, 1629, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1630, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1631, 1584, 1584, 1632, 1584, 1584, 1633, + 1584, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1584, + 1635, 1636, 1584, 1637, 1638, 1638, 1638, 1638, 1584, 1639, + + 1584, 1584, 1640, 1584, 1641, 1584, 1584, 1584, 1642, 1584, + 1629, 1584, 1629, 1629, 1629, 1629, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1634, 1634, 1634, 1638, 1638, 1638, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1643, 1643, 1644, 1643, 1643, 1643, 1643, 1584, + 1584, 1645, 1584, 1584, 363, 363, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1645, 1646, 1647, 1647, 1648, + 1648, 1648, 1649, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1650, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1651, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1629, 1629, 1629, 1629, + 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, + 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, + 1629, 1629, 1629, 1629, 1629, 1629, 1652, 1629, 1629, 1629, + 1653, 1654, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, + 1629, 461, 1629, 1629, 1629, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1655, 1584, 1584, 1584, + 1656, 1584, 1584, 1584, 1584, 1657, 1584, 1584, 1584, 1584, + + 1584, 1584, 1658, 1659, 1660, 1584, 1584, 1661, 1662, 1663, + 1664, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, + 1665, 1629, 1629, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1666, 1666, 1666, + 1666, 1666, 1666, 1666, 1667, 1584, 1584, 556, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1667, 1668, 1669, 1669, 1670, 1670, 1670, + 1584, 1671, 1671, 1584, 1584, 1584, 1584, 1584, 1584, 1672, + + 1673, 1674, 1675, 1676, 1677, 1678, 1584, 1584, 1679, 1679, + 1680, 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, + 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, + 1679, 1679, 1679, 1681, 1679, 1679, 1679, 1682, 1679, 1683, + 1679, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1679, + 1685, 1679, 1686, 1679, 1679, 1679, 1679, 1679, 1679, 1679, + 1679, 1679, 1687, 1679, 1679, 1679, 1688, 1584, 1689, 1690, + 1691, 1584, 1584, 1584, 1584, 1584, 1692, 1693, 1584, 1584, + 1694, 1584, 1584, 1584, 1584, 1695, 1696, 1584, 1584, 1697, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1698, + + 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1699, 1699, + 1699, 1679, 1679, 1679, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1700, 1700, 1701, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1701, + 1702, 1703, 1704, 1705, 1704, 1705, 1704, 1704, 1704, 1704, + 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, 1704, + 1704, 1704, 1704, 1704, 1704, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1706, 1707, 1708, 1709, 1710, + 1711, 1712, 1584, 1679, 1679, 1679, 1679, 1679, 1679, 1713, + 1679, 1679, 1714, 1715, 1716, 1679, 1679, 1679, 1679, 1679, + 1717, 1718, 1679, 1679, 1719, 1679, 1679, 1679, 1679, 1720, + 1721, 1679, 1679, 1722, 1679, 1679, 1679, 1679, 1679, 1679, + 1723, 1724, 1679, 1679, 1679, 1725, 1726, 1727, 1728, 1729, + 1730, 1731, 1732, 1733, 1584, 1584, 1734, 1679, 1679, 1679, + 1679, 1679, 1679, 1679, 1679, 1679, 1679, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1735, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1735, 1736, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, + 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, + 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, + 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, + 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, + 1737, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1738, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1739, 1679, + + 1679, 1679, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1679, + 1679, 1679, 1679, 1679, 1747, 1679, 1679, 1584, 1584, 1748, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1748, 1749, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750, + 1750, 1750, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1751, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1752, 1679, 1679, 1747, 1753, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1754, 1755, 1756, 1584, + 1584, 1753, 1757, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1758, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1751, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1759, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1758, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1759, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1295, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1760, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1755, 1754, 1754, 1754, 1755, 1755, 1755, 1756, 1756, 1756, + 1584, 1584, 1757, 1757, 1584, 1584, 1584, 1761, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1762, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1760, 1760, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1754, 1755, 1756, 1584, 1584, + 1759, 1584, 1584, 1584, 1584, 1584, 1584, 1763, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1764, 1765, 1766, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1767, + 1584, 1584, 1762, 1584, 1584, 1584, 1584, 1584, 1765, 1764, + 1764, 1764, 1764, 1765, 1765, 1765, 1765, 1766, 1766, 1766, + 1766, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1768, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1764, + 1764, 1764, 1765, 1765, 1765, 1766, 1766, 1766, 1584, 1584, + 1584, 1767, 1584, 1584, 1584, 1584, 1584, 1584, 1764, 1764, + + 1764, 1764, 1765, 1765, 1765, 1765, 1766, 1766, 1766, 1766, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1481, 1764, 1764, + 1484, 1765, 1765, 1487, 1766, 1766, 1584, 1584, 1584, 1584, + 1764, 1481, 1765, 1484, 1766, 1487, 1584, 1584, 1584, 1584, + 1764, 1764, 1499, 1764, 1765, 1765, 1503, 1765, 1766, 1766, + 1507, 1766, 1584, 1584, 1584, 1584, 1532, 1534, 1536, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 0, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584 + } ; + +static const flex_int16_t yy_nxt[7718] = + { 0, + 1584, 1584, 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, 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, 1584, 86, 87, 58, 58, 91, 92, 93, 95, + 95, 86, 87, 99, 100, 425, 96, 96, 99, 100, + 70, 1492, 126, 97, 97, 126, 71, 575, 72, 576, + + 55, 59, 59, 163, 55, 402, 163, 103, 104, 105, + 103, 88, 402, 89, 174, 175, 106, 176, 202, 203, + 88, 70, 89, 107, 963, 178, 964, 71, 178, 72, + 500, 500, 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, + 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, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 69, 109, 110, 110, + 109, 474, 291, 157, 115, 116, 117, 115, 158, 559, + 475, 111, 112, 118, 119, 201, 201, 201, 201, 120, + 121, 164, 165, 166, 167, 168, 169, 170, 220, 221, + 1443, 70, 207, 208, 209, 207, 560, 71, 126, 72, + 559, 126, 1411, 222, 292, 159, 103, 225, 226, 103, + 113, 227, 228, 126, 487, 279, 126, 122, 279, 106, + 279, 296, 70, 279, 297, 488, 107, 560, 71, 298, + 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, 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, 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, 80, + + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 110, 123, 110, 110, 561, 337, + 338, 157, 337, 338, 130, 149, 158, 130, 149, 112, + 130, 1325, 151, 152, 153, 151, 1584, 190, 130, 111, + 190, 118, 119, 194, 195, 196, 194, 293, 154, 561, + 293, 191, 192, 507, 507, 308, 294, 215, 308, 339, + 216, 1584, 339, 324, 309, 311, 512, 112, 129, 129, + 130, 129, 131, 131, 132, 129, 133, 134, 150, 135, + 150, 360, 136, 137, 130, 155, 340, 197, 423, 340, + 193, 103, 104, 105, 103, 301, 198, 130, 199, 217, + + 106, 360, 1584, 130, 138, 130, 328, 107, 218, 329, + 240, 475, 360, 341, 330, 239, 341, 130, 342, 139, + 140, 342, 529, 141, 129, 138, 129, 129, 142, 143, + 217, 138, 360, 343, 144, 138, 343, 145, 146, 129, + 705, 129, 147, 130, 129, 138, 148, 138, 230, 129, + 129, 130, 241, 1584, 424, 231, 109, 110, 110, 109, + 232, 489, 489, 490, 233, 234, 235, 425, 236, 1584, + 111, 112, 110, 110, 110, 110, 130, 242, 243, 244, + 242, 1584, 178, 237, 130, 178, 1584, 112, 246, 116, + 247, 246, 112, 535, 535, 1584, 238, 248, 249, 110, + + 116, 110, 110, 250, 251, 178, 508, 149, 178, 113, + 149, 959, 408, 410, 112, 408, 410, 115, 116, 117, + 115, 111, 536, 536, 960, 112, 118, 119, 204, 633, + 113, 204, 120, 121, 484, 310, 311, 312, 310, 580, + 581, 252, 281, 281, 281, 281, 281, 281, 281, 281, + 629, 283, 112, 253, 254, 284, 253, 285, 286, 483, + 150, 657, 483, 287, 332, 333, 334, 335, 288, 255, + 122, 289, 562, 313, 152, 314, 313, 612, 220, 221, + 256, 193, 248, 249, 220, 221, 257, 258, 150, 315, + 259, 1584, 260, 222, 261, 611, 262, 263, 264, 222, + + 265, 411, 266, 562, 412, 1584, 124, 317, 318, 413, + 319, 267, 320, 268, 414, 269, 410, 415, 270, 410, + 321, 322, 416, 271, 607, 607, 316, 323, 272, 129, + 129, 130, 129, 131, 131, 132, 273, 133, 134, 493, + 274, 1584, 494, 275, 137, 130, 306, 495, 306, 755, + 307, 307, 307, 307, 307, 307, 307, 307, 307, 1365, + 151, 152, 153, 151, 190, 138, 638, 190, 755, 118, + 119, 201, 201, 201, 201, 1584, 154, 909, 191, 192, + 276, 140, 608, 608, 141, 129, 138, 129, 129, 142, + 143, 1365, 138, 563, 352, 144, 138, 352, 145, 146, + + 129, 909, 129, 147, 130, 129, 138, 148, 138, 192, + 129, 129, 130, 155, 283, 616, 701, 193, 325, 336, + 285, 326, 336, 986, 563, 1584, 327, 350, 350, 350, + 350, 288, 253, 254, 289, 253, 987, 332, 333, 334, + 335, 391, 351, 354, 355, 356, 354, 193, 194, 195, + 196, 194, 201, 201, 201, 201, 361, 361, 361, 361, + 207, 363, 364, 207, 207, 208, 209, 207, 394, 392, + 395, 1171, 1584, 476, 227, 228, 476, 571, 1584, 396, + 392, 397, 106, 398, 621, 401, 392, 357, 401, 107, + 399, 401, 197, 622, 401, 1584, 358, 994, 359, 663, + + 392, 198, 477, 199, 365, 366, 367, 365, 571, 402, + 406, 392, 620, 1365, 478, 406, 400, 392, 403, 402, + 402, 406, 242, 243, 244, 242, 406, 406, 402, 1365, + 368, 369, 406, 279, 403, 1584, 279, 112, 370, 371, + 404, 406, 372, 373, 467, 374, 406, 467, 537, 375, + 704, 537, 406, 418, 243, 419, 418, 406, 406, 110, + 243, 110, 110, 406, 421, 110, 418, 421, 420, 376, + 418, 116, 418, 418, 112, 113, 1584, 467, 468, 420, + 467, 468, 481, 293, 479, 420, 293, 468, 468, 692, + 692, 308, 294, 481, 308, 636, 636, 637, 480, 481, + + 309, 1365, 446, 1584, 470, 446, 420, 310, 311, 312, + 310, 538, 112, 481, 538, 723, 723, 422, 471, 467, + 470, 492, 467, 420, 481, 539, 472, 1584, 539, 1582, + 481, 377, 378, 379, 985, 380, 381, 382, 1584, 383, + 988, 384, 385, 426, 254, 1385, 426, 540, 532, 632, + 540, 533, 468, 468, 541, 513, 534, 541, 481, 427, + 150, 336, 468, 468, 336, 337, 738, 1579, 337, 481, + 428, 338, 758, 759, 338, 481, 429, 430, 339, 739, + 431, 339, 432, 1578, 433, 1584, 434, 435, 436, 481, + 437, 634, 438, 1575, 525, 340, 423, 738, 340, 526, + + 481, 439, 635, 440, 341, 441, 481, 341, 442, 342, + 739, 343, 342, 443, 343, 858, 858, 707, 444, 129, + 445, 446, 445, 447, 447, 448, 449, 450, 451, 401, + 452, 1584, 401, 453, 454, 446, 307, 307, 307, 307, + 307, 307, 307, 307, 307, 350, 350, 350, 350, 350, + 350, 350, 350, 401, 352, 455, 401, 352, 549, 601, + 602, 549, 601, 602, 708, 354, 355, 356, 354, 192, + 456, 457, 1365, 550, 458, 445, 455, 445, 445, 459, + 460, 603, 455, 510, 603, 461, 455, 417, 462, 463, + 445, 756, 445, 464, 446, 445, 455, 465, 455, 622, + + 445, 445, 446, 426, 254, 972, 426, 193, 552, 357, + 706, 551, 361, 361, 361, 361, 1365, 505, 358, 427, + 359, 558, 366, 367, 558, 417, 762, 1574, 552, 514, + 515, 743, 516, 763, 517, 604, 429, 430, 604, 552, + 431, 1571, 518, 519, 433, 748, 434, 435, 436, 520, + 437, 605, 438, 757, 605, 606, 423, 410, 606, 552, + 410, 439, 743, 440, 467, 441, 1584, 467, 442, 590, + 591, 590, 590, 443, 589, 990, 748, 991, 444, 129, + 445, 446, 445, 447, 447, 448, 449, 450, 521, 669, + 452, 749, 669, 522, 454, 446, 511, 750, 418, 110, + + 418, 418, 613, 1584, 417, 613, 418, 243, 418, 418, + 740, 426, 254, 420, 426, 455, 751, 421, 110, 418, + 421, 420, 749, 630, 446, 1584, 630, 446, 750, 740, + 523, 457, 420, 1333, 458, 445, 455, 445, 445, 459, + 460, 467, 455, 754, 467, 461, 455, 751, 462, 463, + 445, 420, 445, 464, 446, 445, 455, 465, 455, 420, + 445, 445, 446, 365, 556, 557, 365, 505, 564, 1584, + 422, 446, 565, 1365, 754, 1012, 566, 513, 609, 863, + 863, 467, 567, 425, 467, 446, 668, 897, 568, 368, + 369, 614, 1584, 670, 614, 569, 670, 370, 371, 564, + + 1584, 372, 373, 565, 374, 886, 886, 566, 375, 623, + 1584, 898, 623, 567, 614, 1584, 748, 614, 897, 568, + 610, 613, 1584, 510, 613, 615, 615, 1014, 376, 626, + 1584, 1365, 671, 615, 615, 671, 652, 1584, 624, 652, + 1081, 617, 898, 627, 446, 653, 1584, 748, 672, 907, + 625, 672, 446, 1082, 1584, 618, 615, 617, 673, 887, + 887, 673, 628, 619, 1365, 643, 511, 615, 570, 644, + 1037, 645, 646, 628, 1015, 666, 1584, 647, 666, 628, + 674, 806, 648, 674, 667, 649, 628, 910, 968, 969, + 377, 378, 379, 628, 380, 381, 382, 628, 383, 476, + + 384, 385, 476, 628, 628, 675, 654, 910, 675, 655, + 628, 1584, 676, 677, 656, 676, 677, 628, 678, 679, + 680, 678, 679, 680, 681, 639, 682, 681, 628, 682, + 683, 1395, 687, 683, 628, 687, 631, 631, 631, 631, + 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, + 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, + 631, 631, 1584, 688, 689, 691, 688, 689, 691, 693, + 694, 1365, 693, 694, 684, 715, 1150, 684, 715, 641, + 641, 641, 641, 641, 641, 641, 641, 1584, 1162, 1584, + 717, 643, 685, 717, 1570, 709, 658, 645, 710, 718, + + 995, 996, 718, 711, 659, 659, 659, 659, 648, 1000, + 1000, 649, 659, 659, 659, 659, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 659, 1584, 685, + 719, 720, 721, 719, 720, 721, 1584, 722, 446, 712, + 722, 537, 713, 538, 537, 539, 538, 714, 539, 1085, + 748, 1086, 446, 660, 660, 660, 660, 660, 660, 660, + 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, + 660, 660, 660, 660, 660, 660, 660, 660, 660, 540, + 541, 748, 540, 541, 660, 660, 660, 660, 660, 660, + + 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, + 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, + 661, 446, 730, 603, 694, 730, 603, 694, 1365, 446, + 735, 736, 737, 735, 1001, 1001, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 613, 614, 1584, 613, 614, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 1584, 1119, 553, 1125, 615, 553, 728, + + 740, 614, 728, 1126, 614, 664, 615, 664, 1230, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 729, 549, + 748, 1231, 549, 741, 732, 350, 732, 732, 744, 753, + 1566, 740, 614, 565, 550, 614, 1158, 832, 702, 733, + 745, 833, 824, 703, 833, 825, 753, 1158, 551, 746, + 826, 748, 565, 747, 827, 614, 1120, 828, 614, 744, + 834, 835, 829, 834, 835, 836, 837, 838, 836, 837, + 838, 745, 551, 558, 556, 557, 558, 1301, 623, 839, + 746, 623, 839, 840, 747, 841, 840, 842, 841, 843, + 842, 844, 843, 1365, 844, 845, 742, 1301, 845, 368, + + 369, 846, 847, 848, 846, 847, 848, 370, 371, 1159, + 851, 372, 373, 851, 374, 1565, 852, 853, 375, 852, + 853, 849, 855, 652, 666, 855, 652, 666, 672, 1028, + 1029, 672, 653, 667, 673, 1035, 1036, 673, 376, 665, + 665, 665, 665, 665, 665, 665, 665, 665, 674, 675, + 676, 674, 675, 676, 679, 680, 682, 679, 680, 682, + 683, 684, 684, 683, 684, 684, 688, 689, 849, 688, + 689, 691, 693, 694, 691, 693, 694, 876, 878, 880, + 876, 878, 880, 881, 882, 883, 881, 882, 883, 884, + 885, 715, 884, 885, 715, 888, 717, 997, 888, 717, + + 377, 378, 379, 1564, 380, 381, 382, 1234, 383, 1235, + 384, 385, 775, 591, 775, 775, 718, 776, 719, 718, + 720, 719, 721, 720, 722, 721, 891, 722, 728, 891, + 893, 728, 730, 893, 894, 730, 1331, 894, 777, 778, + 732, 350, 732, 732, 748, 896, 779, 780, 896, 900, + 781, 782, 1365, 783, 748, 905, 1331, 784, 732, 350, + 732, 732, 906, 901, 748, 785, 735, 736, 737, 735, + 735, 736, 737, 735, 748, 748, 915, 786, 748, 915, + 900, 735, 736, 737, 735, 748, 905, 748, 945, 946, + 947, 948, 949, 906, 901, 748, 1365, 735, 736, 737, + + 735, 957, 972, 973, 974, 748, 1365, 975, 1556, 748, + 876, 976, 1300, 876, 1002, 984, 1555, 1002, 748, 945, + 946, 947, 948, 949, 902, 836, 837, 903, 836, 837, + 1038, 1039, 957, 972, 973, 974, 1300, 748, 975, 787, + 788, 789, 976, 790, 791, 792, 984, 793, 1554, 794, + 795, 591, 591, 591, 591, 902, 796, 838, 903, 1330, + 838, 777, 778, 839, 840, 1365, 839, 840, 748, 779, + 780, 1169, 843, 781, 782, 843, 783, 797, 798, 844, + 784, 846, 844, 1330, 846, 799, 800, 950, 785, 801, + 802, 951, 803, 1179, 847, 952, 804, 847, 1021, 848, + + 786, 953, 848, 848, 805, 852, 848, 954, 852, 1180, + 853, 916, 917, 853, 955, 1179, 806, 855, 950, 1268, + 855, 1010, 951, 1386, 1010, 876, 952, 876, 876, 1021, + 876, 878, 953, 1016, 878, 1339, 1016, 880, 954, 881, + 880, 882, 881, 883, 882, 884, 883, 885, 884, 888, + 885, 1018, 888, 891, 1018, 1019, 891, 893, 1019, 1553, + 893, 1365, 787, 788, 789, 1322, 790, 791, 792, 1530, + 793, 894, 794, 795, 894, 1090, 1091, 1528, 807, 808, + 809, 1269, 810, 811, 812, 989, 813, 956, 814, 815, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 896, 1121, 1122, 896, 1022, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 924, 591, 924, 924, 1022, 925, 739, + 1160, 1161, 797, 798, 1010, 748, 1024, 1010, 1365, 565, + 799, 800, 1365, 1025, 801, 802, 1026, 803, 1527, 926, + + 927, 804, 735, 736, 737, 735, 1067, 928, 929, 805, + 739, 930, 931, 1068, 932, 977, 748, 1024, 933, 978, + 565, 806, 1069, 979, 1025, 1070, 934, 1026, 1071, 980, + 1079, 1097, 1098, 1102, 1107, 981, 1108, 1067, 935, 1109, + 1110, 748, 982, 1146, 1068, 1164, 977, 1113, 1136, 1137, + 978, 1112, 1165, 1069, 979, 1073, 1070, 1430, 1114, 1071, + 980, 1079, 1097, 1098, 1102, 1107, 981, 1108, 1112, 1151, + 1109, 1110, 748, 978, 1073, 993, 1099, 1114, 1113, 1136, + 1137, 1141, 1146, 807, 808, 809, 1151, 810, 811, 812, + 1153, 813, 978, 814, 815, 1002, 1186, 1039, 1002, 1100, + + 936, 937, 938, 1146, 939, 940, 941, 1099, 942, 1153, + 943, 944, 1141, 1146, 1166, 983, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, + 659, 659, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 1010, 1239, + 1240, 1010, 1101, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 662, + 662, 662, 662, 662, 662, 662, 662, 662, 662, 1046, + + 591, 1046, 1046, 1174, 1047, 1147, 1174, 1094, 1048, 1049, + 1094, 1016, 1095, 1365, 1016, 1018, 1050, 1051, 1018, 1148, + 1052, 1053, 1149, 1054, 1146, 1048, 1049, 1055, 1138, 417, + 877, 1152, 417, 1050, 1051, 1056, 1147, 1052, 1053, 1177, + 1054, 1072, 1103, 1133, 1055, 1073, 1133, 1057, 1134, 1074, + 1148, 1139, 1056, 1149, 1104, 1075, 740, 748, 1022, 1138, + 1096, 1076, 1152, 1105, 1057, 1498, 1019, 1106, 1077, 1019, + 1177, 1365, 1072, 1103, 1263, 1497, 1073, 1178, 1270, 1271, + 1074, 735, 736, 737, 735, 1104, 1075, 740, 748, 1022, + 1216, 1217, 1076, 1263, 1105, 1117, 1135, 1117, 1106, 1118, + + 1118, 1118, 1118, 1118, 1118, 1118, 1118, 1118, 1178, 1058, + 1059, 1060, 1365, 1061, 1062, 1063, 1218, 1064, 1219, 1065, + 1066, 1216, 1217, 1220, 1140, 1228, 1058, 1059, 1060, 1365, + 1061, 1062, 1063, 1374, 1064, 1243, 1065, 1066, 1243, 1384, + 1244, 1078, 1115, 735, 736, 737, 735, 1218, 1274, 1219, + 1116, 1116, 1116, 1116, 1220, 1275, 1228, 1168, 1116, 1116, + 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, + 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, 1116, + 1116, 1116, 1116, 1116, 1142, 1181, 1182, 1261, 1245, 1282, + 1306, 1222, 1282, 1306, 1246, 1247, 1143, 1251, 1283, 1256, + + 1257, 1258, 1259, 1262, 1261, 1144, 1248, 1181, 1182, 1145, + 1222, 1284, 1156, 992, 1156, 1142, 1157, 1157, 1157, 1157, + 1157, 1157, 1157, 1157, 1157, 1246, 1247, 1143, 1251, 1249, + 1256, 1257, 1258, 1259, 1262, 1285, 1144, 1248, 1248, 1286, + 1145, 1195, 591, 1195, 1195, 1312, 1196, 1256, 1312, 1243, + 1197, 1198, 1243, 1138, 1244, 1365, 1365, 1248, 1199, 1200, + 1154, 1256, 1201, 1202, 1256, 1203, 1285, 1197, 1198, 1204, + 1286, 1174, 1138, 1256, 1174, 1199, 1200, 1205, 1256, 1201, + 1202, 1256, 1203, 1221, 1252, 1243, 1204, 1222, 1243, 1206, + 1244, 1223, 1256, 1293, 1205, 1256, 1253, 1224, 1294, 1256, + + 1315, 1496, 1250, 1225, 1256, 1254, 1206, 1313, 1133, 1255, + 1226, 1133, 1256, 1134, 1221, 1252, 1365, 1365, 1222, 1256, + 1314, 1317, 1223, 1256, 1293, 1307, 1308, 1253, 1224, 1294, + 1256, 1315, 1256, 1316, 1225, 1146, 1254, 1266, 1245, 1266, + 1255, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, + 1256, 1207, 1208, 1209, 1256, 1210, 1211, 1212, 1146, 1213, + 1146, 1214, 1215, 1256, 1316, 1146, 1146, 1146, 1207, 1208, + 1209, 1365, 1210, 1211, 1212, 1495, 1213, 1243, 1214, 1215, + 1243, 1365, 1244, 1227, 1264, 1133, 1160, 1161, 1133, 1146, + 1134, 1146, 1265, 1265, 1265, 1265, 1146, 1365, 1146, 1365, + + 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, + 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, + 1265, 1265, 1265, 1265, 1265, 1265, 1288, 1365, 1243, 1323, + 1245, 1243, 1146, 1244, 1197, 1198, 1146, 1491, 1135, 1324, + 1289, 1146, 1199, 1200, 1344, 1146, 1201, 1202, 1174, 1203, + 1340, 1174, 1365, 1204, 1365, 1290, 1336, 1288, 1291, 1336, + 1323, 1296, 1489, 1146, 990, 1138, 991, 1146, 1256, 1365, + 1324, 1289, 1146, 1206, 1133, 1344, 1146, 1133, 1332, 1134, + 1365, 1245, 417, 877, 1138, 417, 1290, 995, 996, 1291, + 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1256, + + 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, + 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295, + 1295, 1295, 1295, 1295, 1295, 1295, 1345, 1135, 1381, 1382, + 1318, 735, 736, 737, 735, 1207, 1208, 1209, 1365, 1210, + 1211, 1212, 1479, 1213, 1319, 1214, 1215, 1197, 1198, 1133, + 1378, 1163, 1133, 1329, 1134, 1199, 1200, 1345, 1167, 1201, + 1202, 1318, 1203, 973, 998, 1365, 1204, 1365, 1133, 797, + 798, 1133, 1368, 1367, 1297, 1319, 1320, 799, 800, 1321, + 1312, 801, 802, 1312, 803, 1365, 1206, 1365, 804, 1146, + 976, 1337, 1338, 1478, 973, 1477, 1326, 735, 736, 737, + + 735, 1470, 1135, 1353, 736, 1354, 1353, 1320, 806, 972, + 1321, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, + 1146, 976, 1365, 1365, 797, 798, 1356, 736, 1357, 1356, + 1365, 1365, 799, 800, 1365, 1365, 801, 802, 1365, 803, + 972, 1365, 1365, 804, 1359, 736, 1360, 1359, 1207, 1208, + 1209, 1327, 1210, 1211, 1212, 974, 1213, 1133, 1214, 1215, + 1133, 1365, 1367, 806, 735, 736, 737, 735, 975, 1170, + 807, 808, 809, 1146, 810, 811, 812, 1136, 813, 1365, + 814, 815, 797, 798, 1146, 1365, 974, 986, 1365, 1365, + 799, 800, 1365, 1365, 801, 802, 1365, 803, 1365, 975, + + 987, 804, 1312, 1365, 1146, 1312, 1365, 1365, 1136, 805, + 1135, 1365, 1147, 984, 977, 1146, 1365, 1146, 978, 1141, + 1365, 806, 979, 1137, 1365, 807, 808, 809, 980, 810, + 811, 812, 748, 813, 981, 814, 815, 591, 591, 591, + 591, 982, 1366, 1147, 984, 977, 1365, 1365, 1146, 978, + 1141, 1335, 1365, 979, 1137, 1365, 1158, 1365, 1393, 980, + 1379, 1164, 1462, 797, 798, 981, 1152, 1365, 1165, 1151, + 1449, 799, 800, 978, 1365, 801, 802, 1138, 803, 1148, + 1149, 1365, 804, 807, 808, 809, 1151, 810, 811, 812, + 805, 813, 978, 814, 815, 1142, 1153, 1152, 1365, 1365, + + 1139, 1365, 806, 1365, 1328, 1365, 1448, 1143, 1138, 1137, + 1148, 1149, 1365, 1365, 983, 1153, 1144, 1365, 1159, 1365, + 1145, 1365, 1394, 1315, 1380, 1156, 1142, 1156, 1365, 1157, + 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1143, 1133, + 1137, 1365, 1133, 1331, 1367, 1133, 1316, 1144, 1133, 1146, + 1367, 1145, 1146, 1146, 1315, 1146, 1365, 1365, 1313, 1323, + 1365, 1365, 1146, 1331, 807, 808, 809, 1380, 810, 811, + 812, 1314, 813, 1140, 814, 815, 1365, 1316, 1447, 1375, + 1146, 1324, 1146, 1146, 1146, 1318, 1146, 1365, 1365, 1341, + 1323, 1133, 1135, 1146, 1133, 1146, 1367, 1446, 1135, 1319, + + 1334, 1312, 1336, 1365, 1312, 1336, 1365, 1365, 1445, 1365, + 1375, 1365, 1324, 1146, 1365, 1365, 1318, 1372, 1320, 1365, + 1467, 1321, 1365, 1365, 797, 798, 1146, 1381, 1382, 1383, + 1319, 1146, 799, 800, 978, 1444, 801, 802, 1377, 803, + 1146, 1365, 1467, 804, 1135, 1365, 1373, 1365, 1372, 1320, + 1440, 1326, 1321, 1157, 1157, 1157, 1157, 1157, 1157, 1157, + 1157, 1157, 1146, 806, 1465, 978, 797, 798, 1584, 1377, + 1330, 1146, 1376, 1368, 799, 800, 1328, 1373, 801, 802, + 1439, 803, 1388, 1389, 1465, 804, 1391, 1392, 1372, 1373, + 1137, 1427, 1392, 1327, 1330, 1133, 1365, 1390, 1133, 1312, + + 1367, 1146, 1312, 1376, 1370, 806, 1370, 1328, 1371, 1371, + 1371, 1371, 1371, 1371, 1371, 1371, 1371, 1388, 1389, 1372, + 1373, 1137, 1387, 1391, 1392, 807, 808, 809, 1390, 810, + 811, 812, 1146, 813, 1146, 814, 815, 1337, 1338, 1365, + 1402, 1410, 1189, 1375, 1584, 978, 748, 748, 1135, 1376, + 1466, 1377, 1584, 1584, 1584, 1584, 1133, 1438, 1437, 1133, + 1436, 1134, 1398, 1399, 1402, 1146, 1414, 807, 808, 809, + 1466, 810, 811, 812, 1375, 813, 978, 814, 815, 1370, + 1376, 1370, 1377, 1371, 1371, 1371, 1371, 1371, 1371, 1371, + 1371, 1371, 1420, 1398, 1399, 1146, 1400, 1414, 1435, 1401, + + 1356, 736, 1357, 1356, 1406, 736, 1354, 1406, 1421, 1135, + 1406, 736, 1354, 1406, 1420, 1432, 1400, 1406, 736, 1354, + 1406, 1401, 1407, 736, 1357, 1407, 1146, 1407, 736, 1357, + 1407, 1407, 736, 1357, 1407, 1408, 736, 1360, 1408, 1408, + 736, 1360, 1408, 1408, 736, 1360, 1408, 797, 798, 1133, + 1422, 1423, 1133, 1138, 1134, 799, 800, 1146, 1133, 801, + 802, 1133, 803, 1134, 1133, 1373, 804, 1133, 1415, 1134, + 1433, 1476, 1422, 1423, 805, 1371, 1371, 1371, 1371, 1371, + 1371, 1371, 1371, 1371, 1138, 1432, 806, 1133, 1146, 1431, + 1133, 1430, 1134, 1429, 1428, 1476, 1373, 1434, 1390, 1415, + + 1426, 1433, 1412, 1406, 736, 1354, 1406, 1407, 736, 1357, + 1407, 1413, 1441, 1442, 1416, 1463, 1416, 1135, 1417, 1417, + 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1511, 1434, 1408, + 736, 1360, 1408, 1133, 1133, 1146, 1133, 1133, 1134, 1134, + 1135, 1517, 1451, 1441, 1442, 1451, 1463, 1452, 807, 808, + 809, 1511, 810, 811, 812, 1584, 813, 1464, 814, 815, + 1584, 1455, 1459, 1517, 1455, 1459, 1456, 1460, 1584, 1584, + 1584, 1584, 1417, 1417, 1417, 1417, 1417, 1417, 1417, 1417, + 1417, 797, 798, 1512, 1425, 1424, 1135, 1135, 1464, 799, + 800, 1421, 1418, 801, 802, 1453, 803, 797, 798, 1133, + + 804, 1472, 1133, 1473, 1134, 799, 800, 1512, 1455, 801, + 802, 1455, 803, 1456, 1457, 1461, 804, 1468, 1410, 1468, + 806, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, 1469, + 1584, 1515, 1472, 748, 1473, 1409, 806, 748, 1584, 1584, + 1584, 1584, 1474, 1480, 1480, 1475, 1480, 1480, 1452, 1452, + 1133, 1515, 1135, 1133, 1480, 1134, 1516, 1480, 1493, 1452, + 1480, 1457, 1474, 1480, 748, 1452, 1483, 1475, 748, 1483, + 1483, 1456, 1537, 1483, 1483, 1456, 1516, 1483, 1405, 1456, + 1404, 1538, 807, 808, 809, 1403, 810, 811, 812, 1493, + 813, 1397, 814, 815, 1537, 1395, 1453, 1453, 807, 808, + + 809, 1394, 810, 811, 812, 1538, 813, 1453, 814, 815, + 1393, 1483, 1486, 1453, 1483, 1486, 1456, 1460, 1387, 1457, + 1386, 1486, 1481, 1457, 1486, 1486, 1460, 1457, 1486, 1486, + 1460, 1494, 1486, 1560, 1460, 1482, 735, 736, 737, 735, + 735, 736, 737, 735, 1469, 1469, 1469, 1469, 1469, 1469, + 1469, 1469, 1469, 1133, 1480, 1560, 1133, 1480, 1134, 1452, + 1539, 1540, 1494, 1513, 1457, 1461, 1483, 1561, 1514, 1483, + 1567, 1456, 1385, 1484, 1461, 1569, 1486, 1384, 1461, 1486, + 1383, 1460, 1461, 1380, 1539, 1540, 1485, 1561, 1380, 1379, + 1567, 1487, 1584, 1480, 1513, 1569, 1480, 1146, 1452, 1514, + + 1584, 1584, 1584, 1584, 1488, 1146, 1501, 1453, 1501, 1562, + 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1457, + 1483, 1480, 1378, 1483, 1480, 1456, 1452, 1480, 1146, 1461, + 1480, 1562, 1452, 1505, 1573, 1505, 1146, 1506, 1506, 1506, + 1506, 1506, 1506, 1506, 1506, 1506, 1453, 1450, 1563, 1584, + 1374, 1454, 1365, 1568, 1573, 1450, 1450, 1450, 1450, 1454, + 1454, 1454, 1454, 1365, 1364, 1490, 1480, 1362, 1361, 1480, + 1351, 1452, 1563, 1457, 1519, 1568, 1499, 1350, 1483, 1349, + 1520, 1483, 1348, 1456, 1500, 1500, 1500, 1500, 735, 736, + 737, 735, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + + 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1572, 1453, + 1483, 1576, 1580, 1483, 1347, 1456, 1346, 1341, 1340, 1483, + 1503, 1522, 1483, 1339, 1456, 1335, 1334, 1333, 1504, 1504, + 1504, 1504, 1572, 1576, 1580, 1332, 1504, 1504, 1504, 1504, + 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, + 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, 1504, + 1504, 1504, 1577, 1457, 1486, 1486, 1581, 1486, 1486, 1460, + 1460, 1329, 1523, 1486, 1507, 1328, 1486, 1158, 1460, 972, + 1322, 1317, 1508, 1508, 1508, 1508, 1577, 1311, 1581, 1310, + + 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, + 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, 1508, + 1508, 1508, 1508, 1508, 1508, 1508, 1486, 1461, 1525, 1486, + 1309, 1460, 1305, 1304, 1303, 1480, 1526, 1302, 1480, 1509, + 1452, 1509, 1583, 1510, 1510, 1510, 1510, 1510, 1510, 1510, + 1510, 1510, 1502, 1502, 1502, 1502, 1502, 1502, 1502, 1502, + 1502, 1458, 1299, 1298, 1583, 1450, 1268, 1216, 1292, 1458, + 1458, 1458, 1458, 1450, 1450, 1450, 1450, 1287, 1281, 1461, + 1480, 1280, 1279, 1480, 1278, 1452, 1277, 1276, 1453, 1273, + 1272, 1133, 1133, 1260, 1133, 1133, 1134, 1134, 1480, 1480, + + 1242, 1480, 1480, 1452, 1452, 1241, 1518, 1518, 1518, 1518, + 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, + 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518, + 1518, 1518, 1238, 1453, 1483, 1483, 1237, 1483, 1483, 1456, + 1456, 1236, 1233, 1483, 1135, 1135, 1483, 1454, 1456, 1206, + 1232, 1520, 1519, 1229, 1192, 1454, 1454, 1454, 1454, 1191, + 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, + 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, 1521, + 1521, 1521, 1521, 1521, 1521, 1521, 1483, 1457, 1523, 1483, + 1191, 1456, 1190, 1189, 1188, 1486, 1522, 1187, 1486, 1037, + + 1460, 1185, 748, 1506, 1506, 1506, 1506, 1506, 1506, 1506, + 1506, 1506, 1510, 1510, 1510, 1510, 1510, 1510, 1510, 1510, + 1510, 1529, 1458, 735, 736, 737, 735, 1184, 1183, 1180, + 1458, 1458, 1458, 1458, 1173, 1171, 1170, 1169, 1168, 1457, + 1486, 1480, 1167, 1486, 1480, 1460, 1452, 1480, 1461, 1166, + 1480, 1483, 1452, 1163, 1483, 1483, 1456, 1162, 1483, 1486, + 1456, 1154, 1486, 1150, 1460, 1132, 1524, 1524, 1524, 1524, + 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, + 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, 1524, + 1524, 1524, 1486, 1461, 1453, 1486, 1486, 1460, 1131, 1486, + + 1453, 1460, 1130, 1481, 1457, 1129, 1128, 1127, 1457, 1532, + 1124, 1123, 1461, 1484, 1111, 1486, 1531, 1534, 1486, 1093, + 1460, 1487, 1482, 1092, 1133, 1089, 1533, 1133, 1133, 1134, + 1485, 1133, 1088, 1134, 1535, 1087, 1084, 1057, 1480, 1083, + 1080, 1480, 1043, 1452, 1042, 1461, 1041, 1040, 1034, 1526, + 1033, 1541, 1032, 1541, 1536, 1542, 1542, 1542, 1542, 1542, + 1542, 1542, 1542, 1542, 1031, 1030, 1027, 1488, 1525, 1027, + 1023, 1017, 1013, 1001, 1001, 1000, 1000, 1135, 998, 997, + 994, 1135, 993, 992, 989, 806, 988, 985, 971, 970, + 967, 1453, 1543, 966, 965, 962, 935, 961, 958, 921, + + 1544, 1544, 1544, 1544, 920, 919, 918, 914, 1544, 1544, + 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, + 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544, + 1544, 1544, 1544, 1544, 1483, 913, 912, 1483, 911, 1456, + 908, 907, 756, 559, 904, 899, 736, 1545, 892, 1545, + 890, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, + 889, 887, 887, 886, 886, 879, 695, 875, 863, 863, + 860, 860, 858, 858, 859, 857, 831, 823, 817, 817, + 774, 774, 772, 772, 770, 769, 768, 1457, 1547, 767, + 766, 765, 764, 761, 760, 752, 1548, 1548, 1548, 1548, + + 556, 553, 731, 727, 1548, 1548, 1548, 1548, 1548, 1548, + 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, + 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548, + 1486, 726, 725, 1486, 724, 1460, 723, 723, 716, 1584, + 311, 700, 699, 1549, 698, 1549, 498, 1550, 1550, 1550, + 1550, 1550, 1550, 1550, 1550, 1550, 697, 692, 692, 1584, + 1584, 1584, 651, 1584, 1584, 1584, 466, 1584, 608, 608, + 607, 607, 599, 598, 597, 596, 595, 594, 593, 589, + 589, 587, 587, 1461, 1551, 584, 583, 582, 579, 578, + 577, 574, 1552, 1552, 1552, 1552, 376, 573, 572, 366, + + 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, + 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, 1552, + 1552, 1552, 1552, 1552, 1552, 1552, 1480, 363, 554, 1480, + 553, 1452, 355, 547, 546, 545, 544, 543, 542, 536, + 536, 535, 535, 1542, 1542, 1542, 1542, 1542, 1542, 1542, + 1542, 1542, 531, 1483, 530, 528, 1483, 527, 1456, 524, + 152, 311, 507, 507, 502, 502, 500, 500, 501, 499, + 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1453, + 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, + 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557, + + 1557, 1557, 1557, 1557, 1557, 1557, 1457, 1558, 1558, 1558, + 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, + 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558, + 1558, 1558, 1558, 1486, 497, 291, 1486, 491, 1460, 486, + 485, 482, 473, 469, 466, 1584, 409, 407, 405, 227, + 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 1550, 225, + 220, 393, 389, 391, 389, 387, 386, 208, 202, 205, + 204, 195, 204, 349, 348, 347, 346, 345, 344, 331, + 152, 305, 303, 300, 299, 278, 1461, 1559, 1559, 1559, + 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, + + 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, 1559, + 1559, 1559, 1559, 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, 162, 162, + 277, 162, 162, 162, 162, 162, 162, 162, 162, 172, + 239, 125, 124, 172, 172, 172, 172, 172, 172, 172, + 177, 177, 239, 104, 177, 177, 177, 177, 177, 177, + 177, 183, 183, 224, 183, 183, 183, 183, 183, 183, + 183, 183, 185, 223, 213, 212, 185, 185, 185, 185, + 185, 185, 185, 187, 211, 210, 205, 187, 187, 187, + + 187, 187, 187, 187, 189, 204, 200, 188, 189, 189, + 189, 189, 189, 189, 189, 206, 206, 186, 206, 206, + 206, 206, 206, 206, 206, 206, 214, 214, 184, 214, + 214, 214, 214, 214, 214, 214, 214, 219, 219, 182, + 219, 219, 219, 219, 219, 219, 219, 219, 229, 229, + 181, 229, 229, 229, 229, 229, 229, 229, 229, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 128, 128, 128, 128, 280, 280, 180, 280, 280, 280, + 280, 280, 280, 280, 280, 282, 282, 179, 282, 282, + 282, 282, 282, 282, 282, 282, 290, 290, 173, 290, + + 290, 290, 290, 290, 290, 290, 290, 295, 295, 171, + 295, 295, 295, 295, 295, 295, 295, 295, 301, 161, + 301, 301, 302, 302, 304, 160, 156, 304, 304, 172, + 127, 125, 124, 172, 172, 172, 172, 172, 172, 172, + 177, 177, 108, 1584, 177, 177, 177, 177, 177, 177, + 177, 183, 183, 102, 183, 183, 183, 183, 183, 183, + 183, 183, 185, 102, 38, 38, 185, 185, 185, 185, + 185, 185, 185, 187, 1584, 1584, 1584, 187, 187, 187, + 187, 187, 187, 187, 189, 1584, 1584, 1584, 189, 189, + 189, 189, 189, 189, 189, 353, 353, 353, 353, 353, + + 353, 353, 353, 353, 353, 353, 362, 362, 1584, 362, + 362, 362, 362, 362, 362, 362, 362, 388, 388, 1584, + 388, 388, 388, 388, 388, 388, 388, 388, 390, 390, + 1584, 390, 390, 390, 390, 390, 390, 390, 390, 219, + 219, 1584, 219, 219, 219, 219, 219, 219, 219, 219, + 229, 229, 1584, 229, 229, 229, 229, 229, 229, 229, + 229, 417, 417, 417, 417, 417, 417, 417, 417, 417, + 417, 417, 290, 290, 1584, 290, 290, 290, 290, 290, + 290, 290, 290, 496, 496, 1584, 496, 496, 496, 496, + 496, 496, 496, 496, 280, 280, 1584, 280, 280, 280, + + 280, 280, 280, 280, 280, 498, 498, 1584, 498, 498, + 498, 498, 498, 498, 498, 498, 503, 503, 1584, 503, + 503, 503, 503, 503, 503, 503, 503, 504, 504, 1584, + 504, 504, 504, 504, 504, 504, 504, 504, 505, 505, + 505, 505, 505, 1584, 505, 505, 505, 505, 505, 506, + 506, 1584, 506, 506, 506, 506, 506, 506, 506, 506, + 509, 509, 510, 510, 510, 510, 1584, 510, 510, 510, + 510, 510, 510, 511, 511, 511, 511, 511, 1584, 511, + 511, 511, 511, 511, 548, 548, 1584, 548, 548, 548, + 548, 548, 548, 548, 548, 353, 353, 353, 353, 353, + + 353, 353, 353, 353, 353, 353, 555, 555, 1584, 555, + 555, 555, 555, 555, 555, 555, 555, 585, 585, 1584, + 585, 585, 585, 585, 585, 585, 585, 585, 586, 586, + 1584, 586, 586, 586, 586, 586, 586, 586, 586, 588, + 588, 1584, 588, 588, 588, 588, 588, 588, 588, 588, + 592, 592, 1584, 592, 592, 592, 592, 592, 592, 592, + 592, 600, 600, 1584, 600, 600, 600, 600, 600, 600, + 600, 600, 229, 229, 1584, 229, 229, 229, 229, 229, + 229, 229, 229, 640, 640, 1584, 640, 640, 640, 640, + 640, 640, 640, 640, 642, 642, 1584, 642, 642, 642, + + 642, 642, 642, 642, 642, 650, 650, 1584, 650, 650, + 650, 650, 650, 650, 650, 650, 686, 686, 1584, 686, + 686, 686, 686, 686, 686, 686, 686, 690, 690, 1584, + 690, 690, 690, 690, 690, 690, 690, 690, 496, 496, + 1584, 496, 496, 496, 496, 496, 496, 496, 496, 695, + 695, 1584, 695, 695, 695, 695, 695, 695, 695, 695, + 696, 696, 1584, 696, 696, 696, 696, 696, 696, 696, + 696, 505, 505, 505, 505, 505, 505, 505, 505, 505, + 505, 505, 304, 304, 510, 510, 510, 510, 510, 510, + 510, 510, 510, 510, 510, 511, 511, 511, 511, 511, + + 511, 511, 511, 511, 511, 511, 642, 642, 1584, 642, + 642, 642, 642, 642, 642, 642, 642, 548, 548, 1584, + 548, 548, 548, 548, 548, 548, 548, 548, 734, 734, + 1584, 734, 734, 734, 734, 734, 734, 734, 734, 585, + 585, 1584, 585, 585, 585, 585, 585, 585, 585, 585, + 771, 771, 1584, 771, 771, 771, 771, 771, 771, 771, + 771, 773, 773, 1584, 773, 773, 773, 773, 773, 773, + 773, 773, 816, 816, 1584, 816, 816, 816, 816, 816, + 816, 816, 816, 600, 600, 1584, 600, 600, 600, 600, + 600, 600, 600, 600, 818, 818, 1584, 818, 818, 818, + + 818, 818, 818, 818, 818, 819, 819, 1584, 819, 819, + 819, 819, 819, 819, 819, 819, 229, 229, 1584, 229, + 229, 229, 229, 229, 229, 229, 229, 820, 820, 1584, + 820, 820, 820, 820, 820, 820, 820, 820, 821, 821, + 1584, 821, 821, 821, 821, 821, 821, 821, 821, 822, + 822, 1584, 822, 822, 822, 822, 822, 822, 822, 822, + 417, 417, 1584, 417, 417, 417, 417, 417, 417, 417, + 417, 830, 830, 1584, 830, 830, 830, 830, 830, 830, + 830, 830, 850, 850, 1584, 850, 850, 850, 850, 850, + 850, 850, 850, 854, 854, 1584, 854, 854, 854, 854, + + 854, 854, 854, 854, 640, 640, 1584, 640, 640, 640, + 640, 640, 640, 640, 640, 856, 856, 1584, 856, 856, + 856, 856, 856, 856, 856, 856, 861, 861, 1584, 861, + 861, 861, 861, 861, 861, 861, 861, 862, 862, 862, + 862, 862, 862, 862, 862, 862, 862, 862, 866, 866, + 866, 866, 866, 866, 866, 866, 866, 866, 866, 867, + 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, + 868, 868, 1584, 868, 868, 868, 868, 868, 868, 868, + 868, 869, 869, 1584, 869, 869, 869, 869, 869, 869, + 869, 869, 870, 870, 1584, 870, 870, 870, 870, 870, + + 870, 870, 870, 871, 871, 1584, 871, 871, 871, 871, + 871, 871, 871, 871, 872, 872, 1584, 872, 872, 872, + 872, 872, 872, 872, 872, 873, 873, 1584, 873, 873, + 873, 873, 873, 873, 873, 873, 686, 686, 1584, 686, + 686, 686, 686, 686, 686, 686, 686, 874, 874, 1584, + 874, 874, 874, 874, 874, 874, 874, 874, 690, 690, + 1584, 690, 690, 690, 690, 690, 690, 690, 690, 877, + 1584, 877, 877, 877, 877, 877, 877, 877, 877, 877, + 856, 856, 1584, 856, 856, 856, 856, 856, 856, 856, + 856, 548, 548, 548, 548, 548, 548, 548, 548, 548, + + 548, 548, 895, 895, 1584, 895, 895, 895, 895, 895, + 895, 895, 895, 922, 922, 1584, 922, 922, 922, 922, + 922, 922, 922, 922, 771, 771, 1584, 771, 771, 771, + 771, 771, 771, 771, 771, 923, 923, 1584, 923, 923, + 923, 923, 923, 923, 923, 923, 773, 773, 1584, 773, + 773, 773, 773, 773, 773, 773, 773, 999, 999, 1584, + 999, 999, 999, 999, 999, 999, 999, 999, 816, 816, + 1584, 816, 816, 816, 816, 816, 816, 816, 816, 818, + 818, 1584, 818, 818, 818, 818, 818, 818, 818, 818, + 819, 819, 1584, 819, 819, 819, 819, 819, 819, 819, + + 819, 820, 820, 1584, 820, 820, 820, 820, 820, 820, + 820, 820, 821, 821, 1584, 821, 821, 821, 821, 821, + 821, 821, 821, 822, 822, 1584, 822, 822, 822, 822, + 822, 822, 822, 822, 830, 830, 1584, 830, 830, 830, + 830, 830, 830, 830, 830, 1003, 1003, 1584, 1003, 1003, + 1003, 1003, 1003, 1003, 1003, 1003, 1004, 1004, 1584, 1004, + 1004, 1004, 1004, 1004, 1004, 1004, 1004, 1005, 1005, 1584, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1006, 1006, + 1584, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1007, + 1007, 1584, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, + + 1008, 1008, 1584, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1008, 850, 850, 1584, 850, 850, 850, 850, 850, 850, + 850, 850, 1009, 1009, 1584, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1009, 854, 854, 1584, 854, 854, 854, 854, + 854, 854, 854, 854, 1011, 1011, 1584, 1011, 1011, 1011, + 1011, 1011, 1011, 1011, 1011, 862, 862, 862, 862, 862, + 862, 862, 862, 862, 862, 862, 866, 866, 866, 866, + 866, 866, 866, 866, 866, 866, 866, 867, 867, 867, + 867, 867, 867, 867, 867, 867, 867, 867, 868, 868, + 1584, 868, 868, 868, 868, 868, 868, 868, 868, 869, + + 869, 1584, 869, 869, 869, 869, 869, 869, 869, 869, + 870, 870, 1584, 870, 870, 870, 870, 870, 870, 870, + 870, 871, 871, 1584, 871, 871, 871, 871, 871, 871, + 871, 871, 872, 872, 1584, 872, 872, 872, 872, 872, + 872, 872, 872, 873, 873, 1584, 873, 873, 873, 873, + 873, 873, 873, 873, 874, 874, 1584, 874, 874, 874, + 874, 874, 874, 874, 874, 877, 1584, 877, 877, 877, + 877, 877, 877, 877, 877, 877, 1020, 1020, 1584, 1020, + 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1044, 1044, 1584, + 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1044, 1045, 1045, + + 1584, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1045, 1155, + 1584, 1155, 1155, 1172, 1172, 1584, 1172, 1172, 1172, 1172, + 1172, 1172, 1172, 1172, 1003, 1003, 1584, 1003, 1003, 1003, + 1003, 1003, 1003, 1003, 1003, 1004, 1004, 1584, 1004, 1004, + 1004, 1004, 1004, 1004, 1004, 1004, 1005, 1005, 1584, 1005, + 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1006, 1006, 1584, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1007, 1007, + 1584, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1008, + 1008, 1584, 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1008, + 1009, 1009, 1584, 1009, 1009, 1009, 1009, 1009, 1009, 1009, + + 1009, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, + 1175, 1175, 1176, 1176, 1584, 1176, 1176, 1176, 1176, 1176, + 1176, 1176, 1176, 1193, 1193, 1584, 1193, 1193, 1193, 1193, + 1193, 1193, 1193, 1193, 1194, 1194, 1584, 1194, 1194, 1194, + 1194, 1194, 1194, 1194, 1194, 1342, 1342, 1584, 1342, 1342, + 1342, 1342, 1342, 1342, 1342, 1342, 1343, 1343, 1584, 1343, + 1343, 1343, 1343, 1343, 1343, 1343, 1343, 1352, 1352, 1352, + 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1352, 1355, 1355, + 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1355, 1358, + 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, 1358, + + 1363, 1363, 1584, 1363, 1363, 1363, 1363, 1363, 1363, 1363, + 1363, 1155, 1584, 1155, 1584, 1155, 1155, 1369, 1584, 1369, + 1584, 1369, 1369, 1396, 1396, 1584, 1396, 1396, 1396, 1396, + 1396, 1396, 1396, 1396, 1419, 1584, 1419, 1419, 1450, 1450, + 1584, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1450, 1454, + 1454, 1584, 1454, 1454, 1454, 1454, 1454, 1454, 1454, 1454, + 1458, 1458, 1584, 1458, 1458, 1458, 1458, 1458, 1458, 1458, + 1458, 1471, 1584, 1471, 1471, 37, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584 + } ; + +static const flex_int16_t yy_chk[7718] = + { 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, 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, 250, 25, 25, 9, 10, 28, 28, 28, 29, + 30, 26, 26, 33, 33, 250, 29, 30, 34, 34, + 15, 1768, 48, 29, 30, 48, 15, 379, 15, 379, + + 7, 9, 10, 59, 8, 233, 59, 40, 40, 40, + 40, 25, 233, 25, 66, 66, 40, 66, 87, 87, + 26, 15, 26, 40, 789, 67, 789, 15, 67, 15, + 284, 284, 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, + 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, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 16, 43, 43, 43, + 43, 260, 135, 55, 44, 44, 44, 44, 55, 368, + 260, 43, 43, 44, 44, 86, 86, 86, 86, 44, + 44, 60, 60, 60, 60, 60, 60, 60, 99, 99, + 1763, 16, 91, 91, 91, 91, 369, 16, 111, 16, + 368, 111, 1761, 99, 135, 55, 103, 103, 103, 103, + 43, 104, 104, 126, 269, 127, 126, 44, 127, 104, + 136, 139, 16, 136, 139, 269, 104, 369, 16, 139, + 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, 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, 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, 23, + + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 45, 45, 45, 45, 370, 164, + 165, 155, 164, 165, 150, 52, 155, 130, 52, 45, + 130, 1751, 53, 53, 53, 53, 248, 83, 150, 52, + 83, 53, 53, 84, 84, 84, 84, 138, 53, 370, + 138, 83, 83, 296, 296, 148, 138, 97, 148, 166, + 97, 517, 166, 155, 148, 311, 311, 45, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 52, 51, + 130, 197, 51, 51, 51, 53, 167, 84, 248, 167, + 83, 108, 108, 108, 108, 1661, 84, 150, 84, 97, + + 108, 197, 249, 113, 51, 150, 159, 108, 97, 159, + 113, 321, 197, 168, 159, 113, 168, 113, 169, 51, + 51, 169, 321, 51, 51, 51, 51, 51, 51, 51, + 97, 51, 197, 170, 51, 51, 170, 51, 51, 51, + 517, 51, 51, 51, 51, 51, 51, 51, 107, 51, + 51, 51, 113, 420, 249, 107, 109, 109, 109, 109, + 107, 270, 270, 270, 107, 107, 107, 420, 107, 440, + 109, 109, 110, 110, 110, 110, 113, 115, 115, 115, + 115, 436, 177, 107, 113, 177, 457, 110, 116, 116, + 116, 116, 115, 325, 325, 424, 107, 116, 116, 117, + + 117, 117, 117, 116, 116, 178, 1639, 149, 178, 109, + 149, 785, 236, 239, 117, 236, 239, 123, 123, 123, + 123, 149, 328, 328, 785, 110, 123, 123, 204, 440, + 115, 204, 123, 123, 1630, 151, 151, 151, 151, 383, + 383, 116, 132, 132, 132, 132, 132, 132, 132, 132, + 436, 134, 117, 121, 121, 134, 121, 134, 134, 265, + 149, 457, 265, 134, 162, 162, 162, 162, 134, 121, + 123, 134, 371, 152, 152, 152, 152, 424, 220, 220, + 121, 204, 152, 152, 223, 223, 121, 121, 151, 152, + 121, 423, 121, 220, 121, 423, 121, 121, 121, 223, + + 121, 240, 121, 371, 240, 443, 121, 154, 154, 240, + 154, 121, 154, 121, 241, 121, 275, 241, 121, 275, + 154, 154, 241, 121, 411, 411, 152, 154, 121, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 276, + 122, 514, 276, 122, 122, 122, 147, 276, 147, 572, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 1242, + 156, 156, 156, 156, 190, 122, 443, 190, 572, 156, + 156, 191, 191, 191, 191, 429, 156, 760, 190, 190, + 122, 122, 414, 414, 122, 122, 122, 122, 122, 122, + 122, 1212, 122, 372, 194, 122, 122, 194, 122, 122, + + 122, 760, 122, 122, 122, 122, 122, 122, 122, 194, + 122, 122, 122, 156, 157, 429, 514, 190, 157, 163, + 157, 157, 163, 805, 372, 432, 157, 192, 192, 192, + 192, 157, 253, 253, 157, 253, 805, 163, 163, 163, + 163, 217, 192, 195, 195, 195, 195, 194, 200, 200, + 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, + 207, 207, 207, 207, 210, 210, 210, 210, 222, 217, + 222, 1242, 431, 261, 227, 227, 261, 374, 516, 222, + 217, 222, 227, 222, 432, 230, 217, 195, 230, 227, + 222, 231, 200, 432, 231, 463, 195, 1212, 195, 463, + + 217, 200, 261, 200, 208, 208, 208, 208, 374, 234, + 238, 217, 431, 1204, 261, 234, 222, 217, 231, 230, + 234, 238, 242, 242, 242, 242, 234, 238, 230, 1303, + 208, 208, 234, 279, 231, 442, 279, 242, 208, 208, + 231, 238, 208, 208, 256, 208, 234, 256, 331, 208, + 516, 331, 238, 243, 243, 243, 243, 234, 238, 244, + 244, 244, 244, 234, 246, 246, 246, 246, 243, 208, + 247, 247, 247, 247, 244, 242, 439, 258, 256, 246, + 258, 262, 272, 293, 262, 247, 293, 256, 262, 493, + 493, 308, 293, 272, 308, 442, 442, 442, 262, 272, + + 308, 1206, 313, 313, 258, 313, 243, 310, 310, 310, + 310, 332, 244, 272, 332, 532, 532, 246, 258, 318, + 258, 272, 318, 247, 272, 333, 258, 441, 333, 1581, + 272, 208, 208, 208, 1204, 208, 208, 208, 519, 208, + 1206, 208, 208, 251, 251, 1303, 251, 334, 324, 439, + 334, 324, 263, 318, 335, 313, 324, 335, 263, 251, + 310, 336, 318, 263, 336, 337, 560, 1577, 337, 263, + 251, 338, 574, 574, 338, 263, 251, 251, 339, 561, + 251, 339, 251, 1576, 251, 520, 251, 251, 251, 263, + 251, 441, 251, 1573, 318, 340, 251, 560, 340, 318, + + 263, 251, 441, 251, 341, 251, 263, 341, 251, 342, + 561, 343, 342, 251, 343, 644, 644, 519, 251, 252, + 252, 252, 252, 252, 252, 252, 252, 252, 252, 402, + 252, 518, 402, 252, 252, 252, 306, 306, 306, 306, + 306, 306, 306, 306, 306, 350, 350, 350, 350, 351, + 351, 351, 351, 403, 352, 252, 403, 352, 354, 404, + 405, 354, 404, 405, 520, 355, 355, 355, 355, 352, + 252, 252, 1268, 354, 252, 252, 252, 252, 252, 252, + 252, 406, 252, 663, 406, 252, 252, 663, 252, 252, + 252, 573, 252, 252, 252, 252, 252, 252, 252, 518, + + 252, 252, 252, 315, 315, 1268, 315, 352, 357, 355, + 518, 354, 361, 361, 361, 361, 1275, 653, 355, 315, + 355, 366, 366, 366, 366, 653, 577, 1572, 357, 315, + 315, 563, 315, 577, 315, 407, 315, 315, 407, 357, + 315, 1569, 315, 315, 315, 565, 315, 315, 315, 315, + 315, 408, 315, 573, 408, 409, 315, 410, 409, 357, + 410, 315, 563, 315, 468, 315, 437, 468, 315, 392, + 392, 392, 392, 315, 392, 809, 565, 809, 315, 316, + 316, 316, 316, 316, 316, 316, 316, 316, 316, 469, + 316, 566, 469, 316, 316, 316, 667, 567, 418, 418, + + 418, 418, 425, 425, 667, 425, 419, 419, 419, 419, + 742, 426, 426, 418, 426, 316, 568, 421, 421, 421, + 421, 419, 566, 437, 446, 446, 437, 446, 567, 742, + 316, 316, 421, 1275, 316, 316, 316, 316, 316, 316, + 316, 470, 316, 571, 470, 316, 316, 568, 316, 316, + 316, 418, 316, 316, 316, 316, 316, 316, 316, 419, + 316, 316, 316, 363, 363, 363, 363, 862, 373, 422, + 421, 422, 373, 1207, 571, 862, 373, 446, 422, 654, + 654, 467, 373, 422, 467, 422, 467, 738, 373, 363, + 363, 428, 428, 471, 428, 373, 471, 363, 363, 373, + + 434, 363, 363, 373, 363, 709, 709, 373, 363, 433, + 433, 740, 433, 373, 430, 430, 743, 430, 738, 373, + 422, 453, 453, 866, 453, 428, 434, 866, 363, 434, + 435, 1311, 472, 434, 428, 472, 455, 455, 433, 455, + 934, 430, 740, 434, 422, 455, 456, 743, 473, 916, + 433, 473, 422, 934, 444, 430, 435, 430, 474, 712, + 712, 474, 435, 430, 1234, 451, 867, 435, 373, 451, + 916, 451, 451, 435, 867, 465, 465, 451, 465, 435, + 475, 1207, 451, 475, 465, 451, 444, 761, 793, 793, + 363, 363, 363, 435, 363, 363, 363, 444, 363, 476, + + 363, 363, 476, 444, 435, 477, 456, 761, 477, 456, + 435, 438, 478, 479, 456, 478, 479, 444, 480, 481, + 482, 480, 481, 482, 483, 444, 484, 483, 444, 484, + 485, 1311, 488, 485, 444, 488, 438, 438, 438, 438, + 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, + 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, + 438, 438, 448, 489, 490, 492, 489, 490, 492, 497, + 500, 1226, 497, 500, 486, 524, 1226, 486, 524, 448, + 448, 448, 448, 448, 448, 448, 448, 460, 1234, 523, + 526, 521, 486, 526, 1567, 521, 460, 521, 521, 527, + + 813, 813, 527, 521, 460, 460, 460, 460, 521, 824, + 824, 521, 460, 460, 460, 460, 460, 460, 460, 460, + 460, 460, 460, 460, 460, 460, 460, 460, 460, 460, + 460, 460, 460, 460, 460, 460, 460, 460, 461, 486, + 528, 529, 530, 528, 529, 530, 513, 531, 513, 523, + 531, 537, 523, 538, 537, 539, 538, 523, 539, 938, + 744, 938, 513, 461, 461, 461, 461, 461, 461, 461, + 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, + 461, 461, 461, 461, 461, 461, 461, 461, 461, 540, + 541, 744, 540, 541, 461, 461, 461, 461, 461, 461, + + 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, + 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, + 462, 513, 546, 603, 607, 546, 603, 607, 1269, 513, + 559, 559, 559, 559, 827, 827, 462, 462, 462, 462, + 462, 462, 462, 462, 462, 462, 462, 462, 462, 462, + 462, 462, 462, 462, 462, 462, 462, 462, 462, 462, + 462, 462, 613, 515, 515, 613, 515, 462, 462, 462, + 462, 462, 462, 462, 462, 462, 462, 462, 462, 462, + 462, 462, 462, 462, 462, 462, 462, 462, 462, 462, + 462, 462, 462, 464, 961, 553, 965, 515, 553, 545, + + 562, 615, 545, 965, 615, 464, 515, 464, 1056, 464, + 464, 464, 464, 464, 464, 464, 464, 464, 545, 549, + 746, 1056, 549, 562, 550, 550, 550, 550, 564, 570, + 1563, 562, 614, 570, 549, 614, 1269, 614, 515, 550, + 564, 616, 609, 515, 616, 609, 570, 988, 553, 564, + 609, 746, 570, 564, 610, 617, 961, 610, 617, 564, + 618, 619, 610, 618, 619, 620, 621, 622, 620, 621, + 622, 564, 549, 556, 556, 556, 556, 1124, 623, 624, + 564, 623, 624, 625, 564, 626, 625, 627, 626, 628, + 627, 629, 628, 1214, 629, 630, 562, 1124, 630, 556, + + 556, 631, 632, 633, 631, 632, 633, 556, 556, 988, + 635, 556, 556, 635, 556, 1562, 636, 637, 556, 636, + 637, 633, 639, 652, 666, 639, 652, 666, 672, 909, + 909, 672, 652, 666, 673, 915, 915, 673, 556, 664, + 664, 664, 664, 664, 664, 664, 664, 664, 674, 675, + 676, 674, 675, 676, 679, 680, 682, 679, 680, 682, + 683, 684, 685, 683, 684, 685, 688, 689, 633, 688, + 689, 691, 693, 694, 691, 693, 694, 698, 701, 703, + 698, 701, 703, 704, 705, 706, 704, 705, 706, 707, + 708, 715, 707, 708, 715, 716, 717, 1214, 716, 717, + + 556, 556, 556, 1561, 556, 556, 556, 1060, 556, 1060, + 556, 556, 590, 590, 590, 590, 718, 590, 719, 718, + 720, 719, 721, 720, 722, 721, 726, 722, 728, 726, + 729, 728, 730, 729, 731, 730, 1163, 731, 590, 590, + 732, 732, 732, 732, 749, 736, 590, 590, 736, 747, + 590, 590, 1240, 590, 751, 753, 1163, 590, 733, 733, + 733, 733, 754, 747, 755, 590, 735, 735, 735, 735, + 739, 739, 739, 739, 745, 749, 766, 590, 745, 766, + 747, 748, 748, 748, 748, 751, 753, 745, 777, 778, + 779, 780, 781, 754, 747, 755, 1304, 750, 750, 750, + + 750, 783, 797, 798, 799, 745, 1279, 800, 1540, 745, + 823, 801, 1123, 823, 831, 803, 1539, 831, 745, 777, + 778, 779, 780, 781, 750, 836, 837, 750, 836, 837, + 917, 917, 783, 797, 798, 799, 1123, 750, 800, 590, + 590, 590, 801, 590, 590, 590, 803, 590, 1538, 590, + 590, 591, 591, 591, 591, 750, 591, 838, 750, 1162, + 838, 776, 776, 839, 840, 1208, 839, 840, 750, 776, + 776, 1240, 843, 776, 776, 843, 776, 591, 591, 844, + 776, 846, 844, 1162, 846, 591, 591, 782, 776, 591, + 591, 782, 591, 1028, 847, 782, 591, 847, 897, 848, + + 776, 782, 848, 849, 591, 852, 849, 782, 852, 1028, + 853, 766, 766, 853, 782, 1028, 591, 855, 782, 1083, + 855, 858, 782, 1304, 858, 875, 782, 876, 875, 897, + 876, 878, 782, 879, 878, 1279, 879, 880, 782, 881, + 880, 882, 881, 883, 882, 884, 883, 885, 884, 888, + 885, 890, 888, 891, 890, 892, 891, 893, 892, 1537, + 893, 1260, 776, 776, 776, 1260, 776, 776, 776, 1517, + 776, 894, 776, 776, 894, 942, 942, 1512, 591, 591, + 591, 1083, 591, 591, 591, 1208, 591, 782, 591, 591, + 658, 658, 658, 658, 658, 658, 658, 658, 658, 658, + + 658, 658, 658, 658, 658, 658, 658, 658, 658, 658, + 658, 658, 658, 658, 658, 658, 661, 661, 661, 661, + 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, + 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, + 661, 661, 896, 962, 962, 896, 898, 661, 661, 661, + 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, + 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, + 661, 661, 661, 775, 775, 775, 775, 898, 775, 900, + 989, 989, 796, 796, 1000, 901, 902, 1000, 1237, 904, + 796, 796, 1211, 905, 796, 796, 906, 796, 1511, 775, + + 775, 796, 903, 903, 903, 903, 926, 775, 775, 796, + 900, 775, 775, 927, 775, 802, 901, 902, 775, 802, + 904, 796, 928, 802, 905, 929, 775, 906, 930, 802, + 932, 946, 947, 949, 951, 802, 952, 926, 775, 953, + 954, 903, 802, 1498, 927, 992, 802, 957, 973, 974, + 802, 956, 992, 928, 802, 956, 929, 1489, 958, 930, + 802, 932, 946, 947, 949, 951, 802, 952, 956, 983, + 953, 954, 903, 983, 956, 1211, 948, 958, 957, 973, + 974, 976, 978, 796, 796, 796, 983, 796, 796, 796, + 985, 796, 983, 796, 796, 1002, 1036, 1036, 1002, 948, + + 775, 775, 775, 1479, 775, 775, 775, 948, 775, 985, + 775, 775, 976, 978, 1237, 802, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 1010, 1064, + 1064, 1010, 948, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 865, + 865, 865, 865, 865, 865, 865, 865, 865, 865, 924, + + 924, 924, 924, 1013, 924, 979, 1013, 945, 925, 925, + 945, 1016, 945, 1302, 1016, 1018, 925, 925, 1018, 980, + 925, 925, 981, 925, 1478, 924, 924, 925, 975, 1015, + 1015, 984, 1015, 924, 924, 925, 979, 924, 924, 1021, + 924, 931, 950, 972, 924, 931, 972, 925, 972, 931, + 980, 975, 924, 981, 950, 931, 1023, 1024, 1025, 975, + 945, 931, 984, 950, 924, 1477, 1019, 950, 931, 1019, + 1021, 1239, 931, 950, 1080, 1476, 931, 1026, 1084, 1084, + 931, 1022, 1022, 1022, 1022, 950, 931, 1023, 1024, 1025, + 1048, 1049, 931, 1080, 950, 960, 972, 960, 950, 960, + + 960, 960, 960, 960, 960, 960, 960, 960, 1026, 925, + 925, 925, 1210, 925, 925, 925, 1050, 925, 1051, 925, + 925, 1048, 1049, 1052, 975, 1054, 924, 924, 924, 1287, + 924, 924, 924, 1287, 924, 1067, 924, 924, 1067, 1302, + 1067, 931, 959, 1027, 1027, 1027, 1027, 1050, 1087, 1051, + 959, 959, 959, 959, 1052, 1087, 1054, 1239, 959, 959, + 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 959, 959, 959, 959, 959, 959, + 959, 959, 959, 959, 977, 1030, 1030, 1078, 1067, 1095, + 1129, 1078, 1095, 1129, 1068, 1069, 977, 1071, 1096, 1073, + + 1074, 1075, 1076, 1079, 1078, 977, 1070, 1030, 1030, 977, + 1078, 1096, 987, 1210, 987, 977, 987, 987, 987, 987, + 987, 987, 987, 987, 987, 1068, 1069, 977, 1071, 1070, + 1073, 1074, 1075, 1076, 1079, 1097, 977, 1070, 1101, 1099, + 977, 1046, 1046, 1046, 1046, 1134, 1046, 1102, 1134, 1094, + 1047, 1047, 1094, 1140, 1094, 1230, 1233, 1101, 1047, 1047, + 1230, 1103, 1047, 1047, 1105, 1047, 1097, 1046, 1046, 1047, + 1099, 1173, 1140, 1108, 1173, 1046, 1046, 1047, 1102, 1046, + 1046, 1110, 1046, 1053, 1072, 1098, 1046, 1053, 1098, 1047, + 1098, 1053, 1103, 1112, 1046, 1105, 1072, 1053, 1113, 1114, + + 1136, 1475, 1070, 1053, 1108, 1072, 1046, 1135, 1133, 1072, + 1053, 1133, 1110, 1133, 1053, 1072, 1249, 1280, 1053, 1104, + 1135, 1249, 1053, 1104, 1112, 1129, 1129, 1072, 1053, 1113, + 1114, 1136, 1104, 1138, 1053, 1141, 1072, 1082, 1098, 1082, + 1072, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, 1082, + 1104, 1047, 1047, 1047, 1104, 1047, 1047, 1047, 1142, 1047, + 1144, 1047, 1047, 1104, 1138, 1147, 1141, 1149, 1046, 1046, + 1046, 1209, 1046, 1046, 1046, 1474, 1046, 1107, 1046, 1046, + 1107, 1250, 1107, 1053, 1081, 1137, 1233, 1233, 1137, 1142, + 1137, 1144, 1081, 1081, 1081, 1081, 1147, 1274, 1149, 1213, + + 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, + 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, 1081, + 1081, 1081, 1081, 1081, 1081, 1081, 1106, 1235, 1109, 1151, + 1107, 1109, 1143, 1109, 1116, 1116, 1143, 1467, 1137, 1152, + 1106, 1153, 1116, 1116, 1177, 1143, 1116, 1116, 1174, 1116, + 1280, 1174, 1271, 1116, 1238, 1109, 1168, 1106, 1109, 1168, + 1151, 1116, 1462, 1143, 1209, 1250, 1209, 1143, 1109, 1215, + 1152, 1106, 1153, 1116, 1146, 1177, 1143, 1146, 1274, 1146, + 1296, 1109, 1175, 1175, 1250, 1175, 1109, 1213, 1213, 1109, + 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1117, 1109, + + 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, + 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, 1115, + 1115, 1115, 1115, 1115, 1115, 1115, 1178, 1146, 1330, 1330, + 1145, 1179, 1179, 1179, 1179, 1116, 1116, 1116, 1198, 1116, + 1116, 1116, 1448, 1116, 1145, 1116, 1116, 1118, 1118, 1148, + 1296, 1235, 1148, 1271, 1148, 1118, 1118, 1178, 1238, 1118, + 1118, 1145, 1118, 1198, 1215, 1201, 1118, 1283, 1243, 1155, + 1155, 1243, 1283, 1243, 1118, 1145, 1148, 1155, 1155, 1148, + 1312, 1155, 1155, 1312, 1155, 1197, 1118, 1241, 1155, 1148, + 1201, 1168, 1168, 1447, 1198, 1446, 1155, 1180, 1180, 1180, + + 1180, 1440, 1148, 1187, 1187, 1187, 1187, 1148, 1155, 1197, + 1148, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, 1156, + 1148, 1201, 1199, 1277, 1157, 1157, 1188, 1188, 1188, 1188, + 1205, 1217, 1157, 1157, 1236, 1200, 1157, 1157, 1251, 1157, + 1197, 1309, 1222, 1157, 1189, 1189, 1189, 1189, 1118, 1118, + 1118, 1157, 1118, 1118, 1118, 1199, 1118, 1216, 1118, 1118, + 1216, 1196, 1216, 1157, 1191, 1191, 1191, 1191, 1200, 1241, + 1155, 1155, 1155, 1251, 1155, 1155, 1155, 1217, 1155, 1223, + 1155, 1155, 1196, 1196, 1222, 1220, 1199, 1205, 1257, 1227, + 1196, 1196, 1203, 1202, 1196, 1196, 1232, 1196, 1218, 1200, + + 1205, 1196, 1244, 1297, 1251, 1244, 1310, 1244, 1217, 1196, + 1216, 1229, 1223, 1203, 1202, 1222, 1299, 1257, 1202, 1220, + 1270, 1196, 1202, 1218, 1228, 1157, 1157, 1157, 1202, 1157, + 1157, 1157, 1438, 1157, 1202, 1157, 1157, 1195, 1195, 1195, + 1195, 1202, 1195, 1223, 1203, 1202, 1224, 1225, 1257, 1202, + 1220, 1277, 1219, 1202, 1218, 1273, 1232, 1281, 1309, 1202, + 1297, 1236, 1431, 1195, 1195, 1202, 1228, 1288, 1236, 1227, + 1427, 1195, 1195, 1227, 1221, 1195, 1195, 1219, 1195, 1224, + 1225, 1298, 1195, 1196, 1196, 1196, 1227, 1196, 1196, 1196, + 1195, 1196, 1227, 1196, 1196, 1221, 1229, 1228, 1246, 1276, + + 1219, 1245, 1195, 1300, 1270, 1301, 1426, 1221, 1219, 1288, + 1224, 1225, 1248, 1261, 1202, 1229, 1221, 1231, 1232, 1252, + 1221, 1254, 1310, 1246, 1299, 1231, 1221, 1231, 1253, 1231, + 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1231, 1221, 1247, + 1288, 1290, 1247, 1273, 1247, 1256, 1248, 1221, 1256, 1253, + 1256, 1221, 1252, 1253, 1246, 1254, 1255, 1259, 1245, 1261, + 1262, 1263, 1253, 1273, 1195, 1195, 1195, 1298, 1195, 1195, + 1195, 1245, 1195, 1219, 1195, 1195, 1272, 1248, 1425, 1290, + 1253, 1262, 1259, 1252, 1253, 1255, 1254, 1306, 1285, 1281, + 1261, 1258, 1247, 1253, 1258, 1263, 1258, 1424, 1256, 1255, + + 1276, 1282, 1278, 1265, 1282, 1278, 1282, 1278, 1423, 1292, + 1290, 1286, 1262, 1259, 1294, 1305, 1255, 1285, 1258, 1289, + 1437, 1258, 1308, 1307, 1265, 1265, 1263, 1300, 1300, 1301, + 1255, 1258, 1265, 1265, 1292, 1422, 1265, 1265, 1294, 1265, + 1289, 1266, 1437, 1265, 1258, 1267, 1286, 1293, 1285, 1258, + 1413, 1265, 1258, 1266, 1266, 1266, 1266, 1266, 1266, 1266, + 1266, 1266, 1258, 1265, 1435, 1292, 1267, 1267, 1313, 1294, + 1272, 1289, 1293, 1313, 1267, 1267, 1337, 1286, 1267, 1267, + 1412, 1267, 1336, 1336, 1435, 1267, 1338, 1338, 1315, 1316, + 1318, 1389, 1389, 1267, 1272, 1291, 1284, 1337, 1291, 1367, + + 1291, 1319, 1367, 1293, 1284, 1267, 1284, 1307, 1284, 1284, + 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1306, 1306, 1315, + 1316, 1318, 1305, 1308, 1308, 1265, 1265, 1265, 1307, 1265, + 1265, 1265, 1319, 1265, 1291, 1265, 1265, 1278, 1278, 1295, + 1347, 1410, 1409, 1320, 1295, 1322, 1405, 1404, 1291, 1323, + 1436, 1324, 1295, 1295, 1295, 1295, 1321, 1403, 1402, 1321, + 1401, 1321, 1344, 1345, 1347, 1291, 1372, 1267, 1267, 1267, + 1436, 1267, 1267, 1267, 1320, 1267, 1322, 1267, 1267, 1314, + 1323, 1314, 1324, 1314, 1314, 1314, 1314, 1314, 1314, 1314, + 1314, 1314, 1381, 1344, 1345, 1321, 1346, 1372, 1400, 1346, + + 1351, 1351, 1351, 1351, 1352, 1352, 1352, 1352, 1381, 1321, + 1353, 1353, 1353, 1353, 1381, 1395, 1346, 1354, 1354, 1354, + 1354, 1346, 1355, 1355, 1355, 1355, 1321, 1356, 1356, 1356, + 1356, 1357, 1357, 1357, 1357, 1358, 1358, 1358, 1358, 1359, + 1359, 1359, 1359, 1360, 1360, 1360, 1360, 1366, 1366, 1369, + 1383, 1383, 1369, 1374, 1369, 1366, 1366, 1375, 1371, 1366, + 1366, 1371, 1366, 1371, 1373, 1376, 1366, 1373, 1377, 1373, + 1398, 1445, 1383, 1383, 1366, 1370, 1370, 1370, 1370, 1370, + 1370, 1370, 1370, 1370, 1374, 1394, 1366, 1380, 1375, 1393, + 1380, 1392, 1380, 1391, 1390, 1445, 1376, 1399, 1388, 1377, + + 1387, 1398, 1369, 1406, 1406, 1406, 1406, 1407, 1407, 1407, + 1407, 1371, 1414, 1415, 1378, 1433, 1378, 1373, 1378, 1378, + 1378, 1378, 1378, 1378, 1378, 1378, 1378, 1490, 1399, 1408, + 1408, 1408, 1408, 1420, 1421, 1386, 1420, 1421, 1420, 1421, + 1380, 1497, 1428, 1414, 1415, 1428, 1433, 1428, 1366, 1366, + 1366, 1490, 1366, 1366, 1366, 1411, 1366, 1434, 1366, 1366, + 1411, 1429, 1430, 1497, 1429, 1430, 1429, 1430, 1411, 1411, + 1411, 1411, 1416, 1416, 1416, 1416, 1416, 1416, 1416, 1416, + 1416, 1417, 1417, 1491, 1385, 1384, 1420, 1421, 1434, 1417, + 1417, 1382, 1379, 1417, 1417, 1428, 1417, 1419, 1419, 1432, + + 1417, 1441, 1432, 1442, 1432, 1419, 1419, 1491, 1449, 1419, + 1419, 1449, 1419, 1449, 1429, 1430, 1419, 1439, 1362, 1439, + 1417, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, 1439, + 1443, 1495, 1441, 1463, 1442, 1361, 1419, 1464, 1443, 1443, + 1443, 1443, 1444, 1450, 1451, 1444, 1450, 1451, 1450, 1451, + 1469, 1495, 1432, 1469, 1452, 1469, 1496, 1452, 1472, 1452, + 1453, 1449, 1444, 1453, 1463, 1453, 1454, 1444, 1464, 1454, + 1455, 1454, 1527, 1455, 1456, 1455, 1496, 1456, 1350, 1456, + 1349, 1528, 1417, 1417, 1417, 1348, 1417, 1417, 1417, 1472, + 1417, 1342, 1417, 1417, 1527, 1341, 1450, 1451, 1419, 1419, + + 1419, 1340, 1419, 1419, 1419, 1528, 1419, 1452, 1419, 1419, + 1339, 1457, 1458, 1453, 1457, 1458, 1457, 1458, 1335, 1454, + 1334, 1459, 1453, 1455, 1459, 1460, 1459, 1456, 1460, 1461, + 1460, 1473, 1461, 1553, 1461, 1453, 1465, 1465, 1465, 1465, + 1466, 1466, 1466, 1466, 1468, 1468, 1468, 1468, 1468, 1468, + 1468, 1468, 1468, 1471, 1480, 1553, 1471, 1480, 1471, 1480, + 1529, 1530, 1473, 1493, 1457, 1458, 1483, 1554, 1494, 1483, + 1564, 1483, 1333, 1457, 1459, 1566, 1486, 1332, 1460, 1486, + 1331, 1486, 1461, 1329, 1529, 1530, 1457, 1554, 1328, 1327, + 1564, 1461, 1492, 1482, 1493, 1566, 1482, 1513, 1482, 1494, + + 1492, 1492, 1492, 1492, 1461, 1514, 1482, 1480, 1482, 1555, + 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1482, 1483, + 1485, 1500, 1326, 1485, 1500, 1485, 1500, 1502, 1513, 1486, + 1502, 1555, 1502, 1485, 1571, 1485, 1514, 1485, 1485, 1485, + 1485, 1485, 1485, 1485, 1485, 1485, 1482, 1518, 1556, 1325, + 1317, 1521, 1264, 1565, 1571, 1518, 1518, 1518, 1518, 1521, + 1521, 1521, 1521, 1194, 1193, 1465, 1481, 1192, 1190, 1481, + 1186, 1481, 1556, 1485, 1500, 1565, 1481, 1185, 1504, 1184, + 1502, 1504, 1183, 1504, 1481, 1481, 1481, 1481, 1560, 1560, + 1560, 1560, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, + + 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, + 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1570, 1481, + 1484, 1574, 1578, 1484, 1182, 1484, 1181, 1171, 1170, 1506, + 1484, 1504, 1506, 1169, 1506, 1167, 1166, 1165, 1484, 1484, + 1484, 1484, 1570, 1574, 1578, 1164, 1484, 1484, 1484, 1484, + 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, + 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, 1484, + 1484, 1484, 1575, 1484, 1487, 1508, 1579, 1487, 1508, 1487, + 1508, 1161, 1506, 1510, 1487, 1160, 1510, 1159, 1510, 1158, + 1150, 1139, 1487, 1487, 1487, 1487, 1575, 1132, 1579, 1131, + + 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, + 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, 1487, + 1487, 1487, 1487, 1487, 1487, 1487, 1488, 1487, 1508, 1488, + 1130, 1488, 1128, 1127, 1126, 1501, 1510, 1125, 1501, 1488, + 1501, 1488, 1582, 1488, 1488, 1488, 1488, 1488, 1488, 1488, + 1488, 1488, 1501, 1501, 1501, 1501, 1501, 1501, 1501, 1501, + 1501, 1524, 1122, 1121, 1582, 1557, 1120, 1119, 1111, 1524, + 1524, 1524, 1524, 1557, 1557, 1557, 1557, 1100, 1093, 1488, + 1499, 1092, 1091, 1499, 1090, 1499, 1089, 1088, 1501, 1086, + 1085, 1516, 1515, 1077, 1516, 1515, 1516, 1515, 1542, 1544, + + 1066, 1542, 1544, 1542, 1544, 1065, 1499, 1499, 1499, 1499, + 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, + 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, 1499, + 1499, 1499, 1063, 1499, 1503, 1546, 1062, 1503, 1546, 1503, + 1546, 1061, 1059, 1548, 1516, 1515, 1548, 1558, 1548, 1058, + 1057, 1542, 1544, 1055, 1043, 1558, 1558, 1558, 1558, 1042, + 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, + 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, 1503, + 1503, 1503, 1503, 1503, 1503, 1503, 1505, 1503, 1546, 1505, + 1041, 1505, 1040, 1039, 1038, 1509, 1548, 1037, 1509, 1035, + + 1509, 1034, 1033, 1505, 1505, 1505, 1505, 1505, 1505, 1505, + 1505, 1505, 1509, 1509, 1509, 1509, 1509, 1509, 1509, 1509, + 1509, 1515, 1559, 1580, 1580, 1580, 1580, 1032, 1031, 1029, + 1559, 1559, 1559, 1559, 1001, 998, 997, 996, 995, 1505, + 1507, 1519, 994, 1507, 1519, 1507, 1519, 1520, 1509, 993, + 1520, 1522, 1520, 991, 1522, 1523, 1522, 990, 1523, 1525, + 1523, 986, 1525, 982, 1525, 971, 1507, 1507, 1507, 1507, + 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, + 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, 1507, + 1507, 1507, 1526, 1507, 1519, 1526, 1550, 1526, 970, 1550, + + 1520, 1550, 969, 1519, 1522, 968, 967, 966, 1523, 1520, + 964, 963, 1525, 1522, 955, 1552, 1519, 1523, 1552, 944, + 1552, 1525, 1520, 943, 1568, 941, 1522, 1568, 1583, 1568, + 1523, 1583, 940, 1583, 1525, 939, 937, 936, 1531, 935, + 933, 1531, 921, 1531, 920, 1526, 919, 918, 914, 1550, + 913, 1531, 912, 1531, 1526, 1531, 1531, 1531, 1531, 1531, + 1531, 1531, 1531, 1531, 911, 910, 908, 1526, 1552, 907, + 899, 887, 863, 829, 828, 826, 825, 1568, 815, 814, + 812, 1583, 811, 810, 808, 807, 806, 804, 795, 794, + 792, 1531, 1532, 791, 790, 788, 787, 786, 784, 770, + + 1532, 1532, 1532, 1532, 769, 768, 767, 765, 1532, 1532, + 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, + 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, 1532, + 1532, 1532, 1532, 1532, 1533, 764, 763, 1533, 762, 1533, + 759, 758, 757, 756, 752, 741, 737, 1533, 727, 1533, + 725, 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1533, + 723, 714, 713, 711, 710, 702, 696, 692, 656, 655, + 649, 648, 647, 646, 645, 643, 612, 608, 593, 592, + 589, 588, 587, 586, 584, 583, 582, 1533, 1534, 581, + 580, 579, 578, 576, 575, 569, 1534, 1534, 1534, 1534, + + 557, 551, 547, 544, 1534, 1534, 1534, 1534, 1534, 1534, + 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, + 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534, + 1535, 543, 542, 1535, 536, 1535, 534, 533, 525, 522, + 512, 511, 510, 1535, 507, 1535, 506, 1535, 1535, 1535, + 1535, 1535, 1535, 1535, 1535, 1535, 505, 495, 494, 459, + 458, 454, 452, 450, 449, 445, 427, 417, 416, 415, + 413, 412, 400, 398, 397, 396, 395, 394, 393, 391, + 390, 389, 388, 1535, 1536, 386, 385, 384, 382, 381, + 380, 378, 1536, 1536, 1536, 1536, 377, 376, 375, 367, + + 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, + 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, + 1536, 1536, 1536, 1536, 1536, 1536, 1541, 364, 359, 1541, + 358, 1541, 356, 349, 348, 347, 346, 345, 344, 330, + 329, 327, 326, 1541, 1541, 1541, 1541, 1541, 1541, 1541, + 1541, 1541, 323, 1545, 322, 320, 1545, 319, 1545, 317, + 314, 312, 298, 297, 289, 288, 287, 286, 285, 283, + 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1545, 1541, + 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, + 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543, + + 1543, 1543, 1543, 1543, 1543, 1543, 1545, 1547, 1547, 1547, + 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, + 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547, + 1547, 1547, 1547, 1549, 278, 274, 1549, 271, 1549, 268, + 267, 264, 259, 257, 255, 245, 237, 235, 232, 228, + 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549, 226, + 221, 218, 216, 215, 214, 213, 211, 209, 203, 199, + 198, 196, 193, 182, 181, 180, 176, 175, 174, 161, + 153, 146, 145, 143, 140, 125, 1549, 1551, 1551, 1551, + 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, + + 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, 1551, + 1551, 1551, 1551, 1585, 1585, 1585, 1585, 1585, 1585, 1585, + 1585, 1585, 1585, 1585, 1586, 1586, 1586, 1586, 1586, 1586, + 1586, 1586, 1586, 1586, 1586, 1587, 1587, 1587, 1587, 1587, + 1587, 1587, 1587, 1587, 1587, 1587, 1588, 1588, 1588, 1588, + 1588, 1588, 1588, 1588, 1588, 1588, 1588, 1589, 1589, 1589, + 1589, 1589, 1589, 1589, 1589, 1589, 1589, 1589, 1590, 1590, + 1590, 1590, 1590, 1590, 1590, 1590, 1590, 1590, 1590, 1591, + 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, 1591, + 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, 1592, + + 1592, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, 1593, + 1593, 1593, 1594, 1594, 1594, 1594, 1594, 1594, 1594, 1594, + 1594, 1594, 1594, 1595, 1595, 1595, 1595, 1595, 1595, 1595, + 1595, 1595, 1595, 1595, 1596, 1596, 1596, 1596, 1597, 1597, + 124, 1597, 1597, 1597, 1597, 1597, 1597, 1597, 1597, 1598, + 120, 119, 118, 1598, 1598, 1598, 1598, 1598, 1598, 1598, + 1599, 1599, 112, 105, 1599, 1599, 1599, 1599, 1599, 1599, + 1599, 1600, 1600, 102, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1601, 100, 96, 95, 1601, 1601, 1601, 1601, + 1601, 1601, 1601, 1602, 93, 92, 89, 1602, 1602, 1602, + + 1602, 1602, 1602, 1602, 1603, 88, 85, 81, 1603, 1603, + 1603, 1603, 1603, 1603, 1603, 1604, 1604, 78, 1604, 1604, + 1604, 1604, 1604, 1604, 1604, 1604, 1605, 1605, 75, 1605, + 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1606, 1606, 72, + 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1607, 1607, + 71, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1607, 1608, + 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608, + 1609, 1609, 1609, 1609, 1610, 1610, 70, 1610, 1610, 1610, + 1610, 1610, 1610, 1610, 1610, 1611, 1611, 69, 1611, 1611, + 1611, 1611, 1611, 1611, 1611, 1611, 1612, 1612, 65, 1612, + + 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1613, 1613, 62, + 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1614, 58, + 1614, 1614, 1615, 1615, 1616, 57, 54, 1616, 1616, 1617, + 49, 47, 46, 1617, 1617, 1617, 1617, 1617, 1617, 1617, + 1618, 1618, 41, 37, 1618, 1618, 1618, 1618, 1618, 1618, + 1618, 1619, 1619, 36, 1619, 1619, 1619, 1619, 1619, 1619, + 1619, 1619, 1620, 35, 18, 17, 1620, 1620, 1620, 1620, + 1620, 1620, 1620, 1621, 0, 0, 0, 1621, 1621, 1621, + 1621, 1621, 1621, 1621, 1622, 0, 0, 0, 1622, 1622, + 1622, 1622, 1622, 1622, 1622, 1623, 1623, 1623, 1623, 1623, + + 1623, 1623, 1623, 1623, 1623, 1623, 1624, 1624, 0, 1624, + 1624, 1624, 1624, 1624, 1624, 1624, 1624, 1625, 1625, 0, + 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1625, 1626, 1626, + 0, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1626, 1627, + 1627, 0, 1627, 1627, 1627, 1627, 1627, 1627, 1627, 1627, + 1628, 1628, 0, 1628, 1628, 1628, 1628, 1628, 1628, 1628, + 1628, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, 1629, + 1629, 1629, 1631, 1631, 0, 1631, 1631, 1631, 1631, 1631, + 1631, 1631, 1631, 1632, 1632, 0, 1632, 1632, 1632, 1632, + 1632, 1632, 1632, 1632, 1633, 1633, 0, 1633, 1633, 1633, + + 1633, 1633, 1633, 1633, 1633, 1634, 1634, 0, 1634, 1634, + 1634, 1634, 1634, 1634, 1634, 1634, 1635, 1635, 0, 1635, + 1635, 1635, 1635, 1635, 1635, 1635, 1635, 1636, 1636, 0, + 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1636, 1637, 1637, + 1637, 1637, 1637, 0, 1637, 1637, 1637, 1637, 1637, 1638, + 1638, 0, 1638, 1638, 1638, 1638, 1638, 1638, 1638, 1638, + 1640, 1640, 1641, 1641, 1641, 1641, 0, 1641, 1641, 1641, + 1641, 1641, 1641, 1642, 1642, 1642, 1642, 1642, 0, 1642, + 1642, 1642, 1642, 1642, 1643, 1643, 0, 1643, 1643, 1643, + 1643, 1643, 1643, 1643, 1643, 1644, 1644, 1644, 1644, 1644, + + 1644, 1644, 1644, 1644, 1644, 1644, 1645, 1645, 0, 1645, + 1645, 1645, 1645, 1645, 1645, 1645, 1645, 1646, 1646, 0, + 1646, 1646, 1646, 1646, 1646, 1646, 1646, 1646, 1647, 1647, + 0, 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1648, + 1648, 0, 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648, + 1649, 1649, 0, 1649, 1649, 1649, 1649, 1649, 1649, 1649, + 1649, 1650, 1650, 0, 1650, 1650, 1650, 1650, 1650, 1650, + 1650, 1650, 1651, 1651, 0, 1651, 1651, 1651, 1651, 1651, + 1651, 1651, 1651, 1652, 1652, 0, 1652, 1652, 1652, 1652, + 1652, 1652, 1652, 1652, 1653, 1653, 0, 1653, 1653, 1653, + + 1653, 1653, 1653, 1653, 1653, 1654, 1654, 0, 1654, 1654, + 1654, 1654, 1654, 1654, 1654, 1654, 1655, 1655, 0, 1655, + 1655, 1655, 1655, 1655, 1655, 1655, 1655, 1656, 1656, 0, + 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1656, 1657, 1657, + 0, 1657, 1657, 1657, 1657, 1657, 1657, 1657, 1657, 1658, + 1658, 0, 1658, 1658, 1658, 1658, 1658, 1658, 1658, 1658, + 1659, 1659, 0, 1659, 1659, 1659, 1659, 1659, 1659, 1659, + 1659, 1660, 1660, 1660, 1660, 1660, 1660, 1660, 1660, 1660, + 1660, 1660, 1662, 1662, 1663, 1663, 1663, 1663, 1663, 1663, + 1663, 1663, 1663, 1663, 1663, 1664, 1664, 1664, 1664, 1664, + + 1664, 1664, 1664, 1664, 1664, 1664, 1665, 1665, 0, 1665, + 1665, 1665, 1665, 1665, 1665, 1665, 1665, 1666, 1666, 0, + 1666, 1666, 1666, 1666, 1666, 1666, 1666, 1666, 1667, 1667, + 0, 1667, 1667, 1667, 1667, 1667, 1667, 1667, 1667, 1668, + 1668, 0, 1668, 1668, 1668, 1668, 1668, 1668, 1668, 1668, + 1669, 1669, 0, 1669, 1669, 1669, 1669, 1669, 1669, 1669, + 1669, 1670, 1670, 0, 1670, 1670, 1670, 1670, 1670, 1670, + 1670, 1670, 1671, 1671, 0, 1671, 1671, 1671, 1671, 1671, + 1671, 1671, 1671, 1672, 1672, 0, 1672, 1672, 1672, 1672, + 1672, 1672, 1672, 1672, 1673, 1673, 0, 1673, 1673, 1673, + + 1673, 1673, 1673, 1673, 1673, 1674, 1674, 0, 1674, 1674, + 1674, 1674, 1674, 1674, 1674, 1674, 1675, 1675, 0, 1675, + 1675, 1675, 1675, 1675, 1675, 1675, 1675, 1676, 1676, 0, + 1676, 1676, 1676, 1676, 1676, 1676, 1676, 1676, 1677, 1677, + 0, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1677, 1678, + 1678, 0, 1678, 1678, 1678, 1678, 1678, 1678, 1678, 1678, + 1679, 1679, 0, 1679, 1679, 1679, 1679, 1679, 1679, 1679, + 1679, 1680, 1680, 0, 1680, 1680, 1680, 1680, 1680, 1680, + 1680, 1680, 1681, 1681, 0, 1681, 1681, 1681, 1681, 1681, + 1681, 1681, 1681, 1682, 1682, 0, 1682, 1682, 1682, 1682, + + 1682, 1682, 1682, 1682, 1683, 1683, 0, 1683, 1683, 1683, + 1683, 1683, 1683, 1683, 1683, 1684, 1684, 0, 1684, 1684, + 1684, 1684, 1684, 1684, 1684, 1684, 1685, 1685, 0, 1685, + 1685, 1685, 1685, 1685, 1685, 1685, 1685, 1686, 1686, 1686, + 1686, 1686, 1686, 1686, 1686, 1686, 1686, 1686, 1687, 1687, + 1687, 1687, 1687, 1687, 1687, 1687, 1687, 1687, 1687, 1688, + 1688, 1688, 1688, 1688, 1688, 1688, 1688, 1688, 1688, 1688, + 1689, 1689, 0, 1689, 1689, 1689, 1689, 1689, 1689, 1689, + 1689, 1690, 1690, 0, 1690, 1690, 1690, 1690, 1690, 1690, + 1690, 1690, 1691, 1691, 0, 1691, 1691, 1691, 1691, 1691, + + 1691, 1691, 1691, 1692, 1692, 0, 1692, 1692, 1692, 1692, + 1692, 1692, 1692, 1692, 1693, 1693, 0, 1693, 1693, 1693, + 1693, 1693, 1693, 1693, 1693, 1694, 1694, 0, 1694, 1694, + 1694, 1694, 1694, 1694, 1694, 1694, 1695, 1695, 0, 1695, + 1695, 1695, 1695, 1695, 1695, 1695, 1695, 1696, 1696, 0, + 1696, 1696, 1696, 1696, 1696, 1696, 1696, 1696, 1697, 1697, + 0, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1697, 1698, + 0, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, + 1699, 1699, 0, 1699, 1699, 1699, 1699, 1699, 1699, 1699, + 1699, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, + + 1700, 1700, 1701, 1701, 0, 1701, 1701, 1701, 1701, 1701, + 1701, 1701, 1701, 1702, 1702, 0, 1702, 1702, 1702, 1702, + 1702, 1702, 1702, 1702, 1703, 1703, 0, 1703, 1703, 1703, + 1703, 1703, 1703, 1703, 1703, 1704, 1704, 0, 1704, 1704, + 1704, 1704, 1704, 1704, 1704, 1704, 1705, 1705, 0, 1705, + 1705, 1705, 1705, 1705, 1705, 1705, 1705, 1706, 1706, 0, + 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1706, 1707, 1707, + 0, 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1708, + 1708, 0, 1708, 1708, 1708, 1708, 1708, 1708, 1708, 1708, + 1709, 1709, 0, 1709, 1709, 1709, 1709, 1709, 1709, 1709, + + 1709, 1710, 1710, 0, 1710, 1710, 1710, 1710, 1710, 1710, + 1710, 1710, 1711, 1711, 0, 1711, 1711, 1711, 1711, 1711, + 1711, 1711, 1711, 1712, 1712, 0, 1712, 1712, 1712, 1712, + 1712, 1712, 1712, 1712, 1713, 1713, 0, 1713, 1713, 1713, + 1713, 1713, 1713, 1713, 1713, 1714, 1714, 0, 1714, 1714, + 1714, 1714, 1714, 1714, 1714, 1714, 1715, 1715, 0, 1715, + 1715, 1715, 1715, 1715, 1715, 1715, 1715, 1716, 1716, 0, + 1716, 1716, 1716, 1716, 1716, 1716, 1716, 1716, 1717, 1717, + 0, 1717, 1717, 1717, 1717, 1717, 1717, 1717, 1717, 1718, + 1718, 0, 1718, 1718, 1718, 1718, 1718, 1718, 1718, 1718, + + 1719, 1719, 0, 1719, 1719, 1719, 1719, 1719, 1719, 1719, + 1719, 1720, 1720, 0, 1720, 1720, 1720, 1720, 1720, 1720, + 1720, 1720, 1721, 1721, 0, 1721, 1721, 1721, 1721, 1721, + 1721, 1721, 1721, 1722, 1722, 0, 1722, 1722, 1722, 1722, + 1722, 1722, 1722, 1722, 1723, 1723, 0, 1723, 1723, 1723, + 1723, 1723, 1723, 1723, 1723, 1724, 1724, 1724, 1724, 1724, + 1724, 1724, 1724, 1724, 1724, 1724, 1725, 1725, 1725, 1725, + 1725, 1725, 1725, 1725, 1725, 1725, 1725, 1726, 1726, 1726, + 1726, 1726, 1726, 1726, 1726, 1726, 1726, 1726, 1727, 1727, + 0, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1727, 1728, + + 1728, 0, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1729, 1729, 0, 1729, 1729, 1729, 1729, 1729, 1729, 1729, + 1729, 1730, 1730, 0, 1730, 1730, 1730, 1730, 1730, 1730, + 1730, 1730, 1731, 1731, 0, 1731, 1731, 1731, 1731, 1731, + 1731, 1731, 1731, 1732, 1732, 0, 1732, 1732, 1732, 1732, + 1732, 1732, 1732, 1732, 1733, 1733, 0, 1733, 1733, 1733, + 1733, 1733, 1733, 1733, 1733, 1734, 0, 1734, 1734, 1734, + 1734, 1734, 1734, 1734, 1734, 1734, 1735, 1735, 0, 1735, + 1735, 1735, 1735, 1735, 1735, 1735, 1735, 1736, 1736, 0, + 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1737, 1737, + + 0, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1737, 1738, + 0, 1738, 1738, 1739, 1739, 0, 1739, 1739, 1739, 1739, + 1739, 1739, 1739, 1739, 1740, 1740, 0, 1740, 1740, 1740, + 1740, 1740, 1740, 1740, 1740, 1741, 1741, 0, 1741, 1741, + 1741, 1741, 1741, 1741, 1741, 1741, 1742, 1742, 0, 1742, + 1742, 1742, 1742, 1742, 1742, 1742, 1742, 1743, 1743, 0, + 1743, 1743, 1743, 1743, 1743, 1743, 1743, 1743, 1744, 1744, + 0, 1744, 1744, 1744, 1744, 1744, 1744, 1744, 1744, 1745, + 1745, 0, 1745, 1745, 1745, 1745, 1745, 1745, 1745, 1745, + 1746, 1746, 0, 1746, 1746, 1746, 1746, 1746, 1746, 1746, + + 1746, 1747, 1747, 1747, 1747, 1747, 1747, 1747, 1747, 1747, + 1747, 1747, 1748, 1748, 0, 1748, 1748, 1748, 1748, 1748, + 1748, 1748, 1748, 1749, 1749, 0, 1749, 1749, 1749, 1749, + 1749, 1749, 1749, 1749, 1750, 1750, 0, 1750, 1750, 1750, + 1750, 1750, 1750, 1750, 1750, 1752, 1752, 0, 1752, 1752, + 1752, 1752, 1752, 1752, 1752, 1752, 1753, 1753, 0, 1753, + 1753, 1753, 1753, 1753, 1753, 1753, 1753, 1754, 1754, 1754, + 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1755, 1755, + 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1756, + 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756, + + 1757, 1757, 0, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1758, 0, 1758, 0, 1758, 1758, 1759, 0, 1759, + 0, 1759, 1759, 1760, 1760, 0, 1760, 1760, 1760, 1760, + 1760, 1760, 1760, 1760, 1762, 0, 1762, 1762, 1764, 1764, + 0, 1764, 1764, 1764, 1764, 1764, 1764, 1764, 1764, 1765, + 1765, 0, 1765, 1765, 1765, 1765, 1765, 1765, 1765, 1765, + 1766, 1766, 0, 1766, 1766, 1766, 1766, 1766, 1766, 1766, + 1766, 1767, 0, 1767, 1767, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + + 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, 1584, + 1584, 1584, 1584, 1584, 1584, 1584, 1584 + } ; + +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 19 "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 <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "error.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "encodings.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" +#include "util.h" + +#include "decompress.h" +#include "lexgrog.h" +#include "manconv.h" +#include "manconv_client.h" + +#define YY_READ_BUF_SIZE 1024 +#define MAX_NAME 8192 + +/* defines the ordered list of filters detected by lexgrog */ +enum { + TBL_FILTER = 0, /* tbl */ + EQN_FILTER, /* eqn */ + PIC_FILTER, /* pic */ + GRAP_FILTER, /* grap */ + REF_FILTER, /* refer */ + VGRIND_FILTER, /* vgrind */ + MAX_FILTERS /* delimiter */ +}; + +#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 bool fill_mode; +static bool waiting_for_quote; + +static decompress *decomp; + +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = decompress_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 2974 "lexgrog.c" + +#line 309 "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]. + */ + /* ИМЕ also works for mk */ + /* NOME also works for gl, pt */ + /* eptgrv : eqn, pic, tbl, grap, refer, vgrind */ +#line 2985 "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 360 "lexgrog.l" + + + /* begin NAME section processing */ +#line 3221 "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 >= 1585 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 1584 ); + 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 363 "lexgrog.l" +BEGIN (MAN_PRENAME); + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 364 "lexgrog.l" +BEGIN (CAT_NAME); + YY_BREAK +/* general text matching */ + +case 3: +#line 369 "lexgrog.l" +case 4: +#line 370 "lexgrog.l" +case 5: +#line 371 "lexgrog.l" +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 371 "lexgrog.l" + + YY_BREAK + + +case 7: +#line 376 "lexgrog.l" +case 8: +#line 377 "lexgrog.l" +case 9: +/* rule 9 can match eol */ +#line 378 "lexgrog.l" +case 10: +/* rule 10 can match eol */ +YY_RULE_SETUP +#line 378 "lexgrog.l" + + YY_BREAK + + +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 382 "lexgrog.l" +filters[TBL_FILTER] = 't'; + YY_BREAK +case 12: +/* rule 12 can match eol */ +YY_RULE_SETUP +#line 383 "lexgrog.l" +filters[EQN_FILTER] = 'e'; + YY_BREAK +case 13: +/* rule 13 can match eol */ +YY_RULE_SETUP +#line 384 "lexgrog.l" +filters[PIC_FILTER] = 'p'; + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 385 "lexgrog.l" +filters[GRAP_FILTER] = 'g'; + YY_BREAK +case 15: +/* rule 15 can match eol */ +#line 387 "lexgrog.l" +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 387 "lexgrog.l" +filters[REF_FILTER] = 'r'; + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 388 "lexgrog.l" +filters[VGRIND_FILTER] = 'v'; + YY_BREAK + +case YY_STATE_EOF(MAN_REST): +#line 390 "lexgrog.l" +{ /* exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} + YY_BREAK +case 18: +/* rule 18 can match eol */ +YY_RULE_SETUP +#line 394 "lexgrog.l" + + YY_BREAK +/* rules to end NAME section processing */ +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 397 "lexgrog.l" +{ /* forced exit */ + *p_name = '\0'; /* terminate the string */ + yyterminate (); +} + YY_BREAK +case 20: +/* rule 20 can match eol */ +#line 403 "lexgrog.l" +YY_RULE_SETUP +case YY_STATE_EOF(MAN_PRENAME): +#line 403 "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 412 "lexgrog.l" +case 22: +/* rule 22 can match eol */ +#line 413 "lexgrog.l" +case 23: +/* rule 23 can match eol */ +#line 414 "lexgrog.l" +case 24: +/* rule 24 can match eol */ +#line 415 "lexgrog.l" +case 25: +/* rule 25 can match eol */ +#line 416 "lexgrog.l" +case 26: +/* rule 26 can match eol */ +YY_RULE_SETUP +#line 416 "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 424 "lexgrog.l" + + YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +#line 426 "lexgrog.l" +yyless (1); + YY_BREAK +case 29: +/* rule 29 can match eol */ +YY_RULE_SETUP +#line 428 "lexgrog.l" +{ + yyless (0); + BEGIN (MAN_NAME); +} + YY_BREAK + +case 30: +/* rule 30 can match eol */ +#line 435 "lexgrog.l" +case 31: +/* rule 31 can match eol */ +#line 436 "lexgrog.l" +case 32: +/* rule 32 can match eol */ +#line 437 "lexgrog.l" +case 33: +/* rule 33 can match eol */ +#line 438 "lexgrog.l" +case 34: +/* rule 34 can match eol */ +#line 439 "lexgrog.l" +case 35: +/* rule 35 can match eol */ +#line 440 "lexgrog.l" +case 36: +/* rule 36 can match eol */ +#line 441 "lexgrog.l" +YY_RULE_SETUP +case YY_STATE_EOF(MAN_NAME): +YY_RULE_SETUP +case YY_STATE_EOF(MAN_DESC): +#line 441 "lexgrog.l" +{ /* terminate the string */ + *p_name = '\0'; + BEGIN (MAN_REST); + } + YY_BREAK + + +case 37: +/* rule 37 can match eol */ +#line 449 "lexgrog.l" +case 38: +/* rule 38 can match eol */ +#line 450 "lexgrog.l" +case 39: +/* rule 39 can match eol */ +YY_RULE_SETUP +#line 450 "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 460 "lexgrog.l" +{ + newline_found (); + waiting_for_quote = true; + } + YY_BREAK +case 41: +/* rule 41 can match eol */ +#line 466 "lexgrog.l" +case 42: +/* rule 42 can match eol */ +#line 467 "lexgrog.l" +case 43: +/* rule 43 can match eol */ +#line 468 "lexgrog.l" +case 44: +/* rule 44 can match eol */ +#line 469 "lexgrog.l" +case 45: +/* rule 45 can match eol */ +#line 470 "lexgrog.l" +case 46: +/* rule 46 can match eol */ +#line 471 "lexgrog.l" +case 47: +/* rule 47 can match eol */ +#line 472 "lexgrog.l" +case 48: +/* rule 48 can match eol */ +#line 473 "lexgrog.l" +case 49: +/* rule 49 can match eol */ +YY_RULE_SETUP +#line 473 "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 480 "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 481 "lexgrog.l" +newline_found (); + YY_BREAK + +/* Toggle fill mode */ + +case 52: +/* rule 52 can match eol */ +YY_RULE_SETUP +#line 486 "lexgrog.l" +fill_mode = false; + YY_BREAK +case 53: +/* rule 53 can match eol */ +YY_RULE_SETUP +#line 487 "lexgrog.l" +fill_mode = true; + YY_BREAK + +case 54: +/* rule 54 can match eol */ +YY_RULE_SETUP +#line 490 "lexgrog.l" +/* strip continuations */ + YY_BREAK +/* convert to DASH */ + +case 55: +/* rule 55 can match eol */ +#line 495 "lexgrog.l" +case 56: +/* rule 56 can match eol */ +#line 496 "lexgrog.l" +case 57: +/* rule 57 can match eol */ +#line 497 "lexgrog.l" +case 58: +/* rule 58 can match eol */ +#line 498 "lexgrog.l" +case 59: +/* rule 59 can match eol */ +YY_RULE_SETUP +#line 498 "lexgrog.l" +{ + add_separator_to_whatis (); + BEGIN (MAN_DESC); + } + YY_BREAK + +case 60: +/* rule 60 can match eol */ +YY_RULE_SETUP +#line 503 "lexgrog.l" +add_separator_to_whatis (); + YY_BREAK +/* escape sequences and special characters */ + +case 61: +/* rule 61 can match eol */ +YY_RULE_SETUP +#line 507 "lexgrog.l" +add_char_to_whatis ('\\'); + YY_BREAK +case 62: +/* rule 62 can match eol */ +YY_RULE_SETUP +#line 508 "lexgrog.l" +add_char_to_whatis ('\''); + YY_BREAK +case 63: +/* rule 63 can match eol */ +YY_RULE_SETUP +#line 509 "lexgrog.l" +add_char_to_whatis ('`'); + YY_BREAK +case 64: +/* rule 64 can match eol */ +YY_RULE_SETUP +#line 510 "lexgrog.l" +add_char_to_whatis ('-'); + YY_BREAK +case 65: +/* rule 65 can match eol */ +YY_RULE_SETUP +#line 511 "lexgrog.l" +add_char_to_whatis ('-'); + YY_BREAK +case 66: +/* rule 66 can match eol */ +YY_RULE_SETUP +#line 512 "lexgrog.l" +add_char_to_whatis ('.'); + YY_BREAK +case 67: +/* rule 67 can match eol */ +YY_RULE_SETUP +#line 513 "lexgrog.l" +add_char_to_whatis (' '); + YY_BREAK +case 68: +/* rule 68 can match eol */ +YY_RULE_SETUP +#line 514 "lexgrog.l" +add_char_to_whatis ('_'); + YY_BREAK +case 69: +/* rule 69 can match eol */ +YY_RULE_SETUP +#line 515 "lexgrog.l" +add_char_to_whatis ('\t'); + YY_BREAK +case 70: +/* rule 70 can match eol */ +YY_RULE_SETUP +#line 517 "lexgrog.l" +/* various useless control chars */ + YY_BREAK +case 71: +/* rule 71 can match eol */ +YY_RULE_SETUP +#line 518 "lexgrog.l" +/* various inline functions */ + YY_BREAK +case 72: +/* rule 72 can match eol */ +YY_RULE_SETUP +#line 520 "lexgrog.l" +/* interpolate arg */ + YY_BREAK +/* roff named glyphs */ +case 73: +/* rule 73 can match eol */ +YY_RULE_SETUP +#line 523 "lexgrog.l" +add_glyph_to_whatis (yytext + 2, 2); + YY_BREAK +/* perldoc strings */ +case 74: +/* rule 74 can match eol */ +YY_RULE_SETUP +#line 525 "lexgrog.l" +add_perldoc_to_whatis (yytext + 3, 2); + YY_BREAK +case 75: +/* rule 75 can match eol */ +YY_RULE_SETUP +#line 526 "lexgrog.l" +add_perldoc_to_whatis (yytext + 2, 1); + YY_BREAK +case 76: +/* rule 76 can match eol */ +YY_RULE_SETUP +#line 528 "lexgrog.l" +/* comment */ + YY_BREAK +case 77: +/* rule 77 can match eol */ +YY_RULE_SETUP +#line 530 "lexgrog.l" +/* font changes */ + YY_BREAK +case 78: +/* rule 78 can match eol */ +YY_RULE_SETUP +#line 531 "lexgrog.l" +/* mark input place in register */ + YY_BREAK +case 79: +/* rule 79 can match eol */ +YY_RULE_SETUP +#line 533 "lexgrog.l" +/* interpolate number register */ + YY_BREAK +case 80: +/* rule 80 can match eol */ +YY_RULE_SETUP +#line 534 "lexgrog.l" +/* overstrike chars */ + YY_BREAK +case 81: +/* rule 81 can match eol */ +YY_RULE_SETUP +#line 536 "lexgrog.l" +/* size changes */ + YY_BREAK +case 82: +/* rule 82 can match eol */ +YY_RULE_SETUP +#line 537 "lexgrog.l" +/* width of string */ + YY_BREAK +case 83: +/* rule 83 can match eol */ +YY_RULE_SETUP +#line 539 "lexgrog.l" +/* catch all */ + YY_BREAK +case 84: +/* rule 84 can match eol */ +YY_RULE_SETUP +#line 541 "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 85: +/* rule 85 can match eol */ +YY_RULE_SETUP +#line 548 "lexgrog.l" +BEGIN (MAN_DESC_AT); + YY_BREAK +case 86: +/* rule 86 can match eol */ +YY_RULE_SETUP +#line 549 "lexgrog.l" +BEGIN (MAN_DESC_BSX); + YY_BREAK +case 87: +/* rule 87 can match eol */ +YY_RULE_SETUP +#line 550 "lexgrog.l" +BEGIN (MAN_DESC_BX); + YY_BREAK +case 88: +/* rule 88 can match eol */ +YY_RULE_SETUP +#line 551 "lexgrog.l" +BEGIN (MAN_DESC_FX); + YY_BREAK +case 89: +/* rule 89 can match eol */ +YY_RULE_SETUP +#line 552 "lexgrog.l" +BEGIN (MAN_DESC_NX); + YY_BREAK +case 90: +/* rule 90 can match eol */ +YY_RULE_SETUP +#line 553 "lexgrog.l" +BEGIN (MAN_DESC_OX); + YY_BREAK +case 91: +/* rule 91 can match eol */ +YY_RULE_SETUP +#line 554 "lexgrog.l" +add_word_to_whatis ("UNIX"); + YY_BREAK +case 92: +/* rule 92 can match eol */ +YY_RULE_SETUP +#line 556 "lexgrog.l" +{ + add_word_to_whatis ("\""); + BEGIN (MAN_DESC_DQ); + } + YY_BREAK + + +case 93: +YY_RULE_SETUP +#line 563 "lexgrog.l" +mdoc_text ("Version 32V AT&T UNIX"); + YY_BREAK +case 94: +YY_RULE_SETUP +#line 564 "lexgrog.l" +mdoc_text ("Version 1 AT&T UNIX"); + YY_BREAK +case 95: +YY_RULE_SETUP +#line 565 "lexgrog.l" +mdoc_text ("Version 2 AT&T UNIX"); + YY_BREAK +case 96: +YY_RULE_SETUP +#line 566 "lexgrog.l" +mdoc_text ("Version 3 AT&T UNIX"); + YY_BREAK +case 97: +YY_RULE_SETUP +#line 567 "lexgrog.l" +mdoc_text ("Version 4 AT&T UNIX"); + YY_BREAK +case 98: +YY_RULE_SETUP +#line 568 "lexgrog.l" +mdoc_text ("Version 5 AT&T UNIX"); + YY_BREAK +case 99: +YY_RULE_SETUP +#line 569 "lexgrog.l" +mdoc_text ("Version 6 AT&T UNIX"); + YY_BREAK +case 100: +YY_RULE_SETUP +#line 570 "lexgrog.l" +mdoc_text ("Version 7 AT&T UNIX"); + YY_BREAK +case 101: +YY_RULE_SETUP +#line 571 "lexgrog.l" +mdoc_text ("AT&T System V UNIX"); + YY_BREAK +case 102: +YY_RULE_SETUP +#line 572 "lexgrog.l" +mdoc_text ("AT&T System V.1 UNIX"); + YY_BREAK +case 103: +YY_RULE_SETUP +#line 573 "lexgrog.l" +mdoc_text ("AT&T System V.2 UNIX"); + YY_BREAK +case 104: +YY_RULE_SETUP +#line 574 "lexgrog.l" +mdoc_text ("AT&T System V.3 UNIX"); + YY_BREAK +case 105: +YY_RULE_SETUP +#line 575 "lexgrog.l" +mdoc_text ("AT&T System V.4 UNIX"); + YY_BREAK +case 106: +/* rule 106 can match eol */ +YY_RULE_SETUP +#line 576 "lexgrog.l" +{ + yyless (0); + mdoc_text ("AT&T UNIX"); + } + YY_BREAK + + +case 107: +YY_RULE_SETUP +#line 583 "lexgrog.l" +{ + add_word_to_whatis ("BSD/OS"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 108: +/* rule 108 can match eol */ +YY_RULE_SETUP +#line 588 "lexgrog.l" +{ + yyless (0); + mdoc_text ("BSD/OS"); + } + YY_BREAK + + +case 109: +YY_RULE_SETUP +#line 595 "lexgrog.l" +mdoc_text ("BSD (currently in alpha test)"); + YY_BREAK +case 110: +YY_RULE_SETUP +#line 596 "lexgrog.l" +mdoc_text ("BSD (currently in beta test)"); + YY_BREAK +case 111: +YY_RULE_SETUP +#line 597 "lexgrog.l" +mdoc_text ("BSD (currently under development"); + YY_BREAK +case 112: +YY_RULE_SETUP +#line 598 "lexgrog.l" +{ + add_wordn_to_whatis (yytext, yyleng); + add_str_to_whatis ("BSD", 3); + BEGIN (MAN_DESC_BX_RELEASE); + } + YY_BREAK +case 113: +/* rule 113 can match eol */ +YY_RULE_SETUP +#line 603 "lexgrog.l" +{ + yyless (0); + mdoc_text ("BSD"); + } + YY_BREAK + + +case 114: +YY_RULE_SETUP +#line 610 "lexgrog.l" +{ + add_str_to_whatis ("-Reno", 5); + BEGIN (MAN_DESC); + } + YY_BREAK +case 115: +YY_RULE_SETUP +#line 614 "lexgrog.l" +{ + add_str_to_whatis ("-Tahoe", 6); + BEGIN (MAN_DESC); + } + YY_BREAK +case 116: +YY_RULE_SETUP +#line 618 "lexgrog.l" +{ + add_str_to_whatis ("-Lite", 5); + BEGIN (MAN_DESC); + } + YY_BREAK +case 117: +YY_RULE_SETUP +#line 622 "lexgrog.l" +{ + add_str_to_whatis ("-Lite2", 6); + BEGIN (MAN_DESC); + } + YY_BREAK +case 118: +/* rule 118 can match eol */ +YY_RULE_SETUP +#line 626 "lexgrog.l" +{ + yyless (0); + BEGIN (MAN_DESC); + } + YY_BREAK + +case 119: +YY_RULE_SETUP +#line 632 "lexgrog.l" +{ + add_str_to_whatis (yytext, yyleng); + add_char_to_whatis ('"'); + BEGIN (MAN_DESC); +} + YY_BREAK + +case 120: +YY_RULE_SETUP +#line 639 "lexgrog.l" +{ + add_word_to_whatis ("FreeBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 121: +/* rule 121 can match eol */ +YY_RULE_SETUP +#line 644 "lexgrog.l" +{ + yyless (0); + mdoc_text ("FreeBSD"); + } + YY_BREAK + + +case 122: +YY_RULE_SETUP +#line 651 "lexgrog.l" +{ + add_word_to_whatis ("NetBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 123: +/* rule 123 can match eol */ +YY_RULE_SETUP +#line 656 "lexgrog.l" +{ + yyless (0); + mdoc_text ("NetBSD"); + } + YY_BREAK + + +case 124: +YY_RULE_SETUP +#line 663 "lexgrog.l" +{ + add_word_to_whatis ("OpenBSD"); + add_wordn_to_whatis (yytext, yyleng); + BEGIN (MAN_DESC); + } + YY_BREAK +case 125: +/* rule 125 can match eol */ +YY_RULE_SETUP +#line 668 "lexgrog.l" +{ + yyless (0); + mdoc_text ("OpenBSD"); + } + YY_BREAK + +/* collapse spaces, escaped spaces, tabs, newlines to a single space */ +case 126: +/* rule 126 can match eol */ +YY_RULE_SETUP +#line 675 "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 127: +/* rule 127 can match eol */ +#line 682 "lexgrog.l" +case 128: +/* rule 128 can match eol */ +#line 683 "lexgrog.l" +case 129: +/* rule 129 can match eol */ +#line 684 "lexgrog.l" +case 130: +/* rule 130 can match eol */ +#line 685 "lexgrog.l" +case 131: +/* rule 131 can match eol */ +#line 686 "lexgrog.l" +case 132: +/* rule 132 can match eol */ +#line 687 "lexgrog.l" +case 133: +/* rule 133 can match eol */ +#line 688 "lexgrog.l" +case 134: +/* rule 134 can match eol */ +YY_RULE_SETUP +#line 688 "lexgrog.l" +{ + add_char_to_whatis ((char) 0x11); + BEGIN (MAN_NAME); + } + YY_BREAK + +/* any other roff request we don't recognise terminates definitions */ +case 135: +/* rule 135 can match eol */ +YY_RULE_SETUP +#line 695 "lexgrog.l" +{ + *p_name = '\0'; + BEGIN (MAN_REST); +} + YY_BREAK +/* pass words as a chunk. speed optimization */ +case 136: +YY_RULE_SETUP +#line 701 "lexgrog.l" +add_str_to_whatis (yytext, yyleng); + YY_BREAK +/* normalise the comma (,) separators */ +case 137: +/* rule 137 can match eol */ +#line 705 "lexgrog.l" +case 138: +/* rule 138 can match eol */ +YY_RULE_SETUP +#line 705 "lexgrog.l" +add_str_to_whatis (", ", 2); + YY_BREAK +case 139: +/* rule 139 can match eol */ +YY_RULE_SETUP +#line 707 "lexgrog.l" +{ + newline_found (); + add_char_to_whatis (yytext[yyleng - 1]); +} + YY_BREAK +case 140: +YY_RULE_SETUP +#line 712 "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 715 "lexgrog.l" +return 1; + YY_BREAK +case 141: +YY_RULE_SETUP +#line 717 "lexgrog.l" +ECHO; + YY_BREAK +#line 4165 "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 >= 1585 ) + 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 >= 1585 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 1584); + + 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 717 "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 = false; + 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 = false; +} + +int find_name (const char *file, const char *filename, lexgrog *p_lg, + const char *encoding) +{ + int ret = 0; + decompress *d; + char *page_encoding = NULL; + bool run_col = p_lg->type == CATPAGE && *PROG_COL != '\0'; + + if (strcmp (file, "-") == 0) { + d = decompress_fdopen (dup (STDIN_FILENO)); + } else { + struct stat st; + int decompress_flags; + 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 (); + decompress_flags = 0; + /* If we're looking at a cat page, then we need to run col + * over it, which doesn't work conveniently with an + * in-process decompressor. + */ + if (!run_col) + decompress_flags |= DECOMPRESS_ALLOW_INPROCESS; + d = decompress_open (file, decompress_flags); + if (!d) { + 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) { + if (decompress_is_pipeline (d)) + add_manconv (decompress_get_pipeline (d), + page_encoding, "UTF-8"); + else if (manconv_inprocess (d, page_encoding, "UTF-8") != 0) + /* manconv should already have written to stderr, so + * just return zero (i.e. no result). + */ + goto out; + } + if (run_col) { + pipecmd *col_cmd; + col_cmd = pipecmd_new_args + (PROG_COL, "-b", "-p", "-x", (void *) 0); + pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (decompress_get_pipeline (d), col_cmd); + } + decompress_start (d); + + ret = find_name_decompressed (d, filename, p_lg); + +out: + free (page_encoding); + decompress_free (d); + return ret; +} + +int find_name_decompressed (decompress *d, const char *filename, lexgrog *p_lg) +{ + int ret; + + decomp = d; + + fname = filename; + *(p_name = newname) = '\0'; + memset (filters, '_', sizeof (filters)); + + fill_mode = true; + waiting_for_quote = false; + + if (p_lg->type == CATPAGE) + BEGIN (CAT_FILE); + else + BEGIN (MAN_FILE); + + drop_effective_privs (); + + yyrestart (NULL); + ret = yylex (); + + regain_effective_privs (); + + decompress_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.h b/src/lexgrog.h new file mode 100644 index 0000000..6349bd7 --- /dev/null +++ b/src/lexgrog.h @@ -0,0 +1,38 @@ +/* + * lexgrog.h: interface to extracting whatis info + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001-2022 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 MANPAGE 0 +#define CATPAGE 1 + +#include "decompress.h" + +typedef struct lexgrog { + int type; + char *whatis; + char *filters; +} lexgrog; + +extern int find_name (const char *file, const char *filename, + lexgrog *p_lg, const char *encoding); +extern int find_name_decompressed (decompress *d, const char *filename, + lexgrog *p_lg); diff --git a/src/lexgrog.l b/src/lexgrog.l new file mode 100644 index 0000000..41527a4 --- /dev/null +++ b/src/lexgrog.l @@ -0,0 +1,981 @@ +%top{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "manconfig.h" + +/* Flex emits several functions which might reasonably have various + * attributes applied and many unused macros; none of these are our problem. + */ +#if GNUC_PREREQ(8,0) +# pragma GCC diagnostic ignored "-Wsuggest-attribute=malloc" +#endif +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#pragma GCC diagnostic ignored "-Wunused-macros" +} + +%{ + +/* + * 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 <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "error.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "encodings.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" +#include "util.h" + +#include "decompress.h" +#include "lexgrog.h" +#include "manconv.h" +#include "manconv_client.h" + +#define YY_READ_BUF_SIZE 1024 +#define MAX_NAME 8192 + +/* defines the ordered list of filters detected by lexgrog */ +enum { + TBL_FILTER = 0, /* tbl */ + EQN_FILTER, /* eqn */ + PIC_FILTER, /* pic */ + GRAP_FILTER, /* grap */ + REF_FILTER, /* refer */ + VGRIND_FILTER, /* vgrind */ + MAX_FILTERS /* delimiter */ +}; + +#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 bool fill_mode; +static bool waiting_for_quote; + +static decompress *decomp; + +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = decompress_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]. + */ +ar_name (اﻹسم|الإسم) + /* ИМЕ also works for mk */ +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] +eo_name N[Oo][Mm][Oo] +es_name N[Oo][Mm][Bb][Rr][Ee] +fa_name نام +fi_name N[Ii][Mm][Ii] +fr_name N[Oo][Mm] +hu_name N(É|é|\\\('[Ee]|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 P[Aa][Vv][Aa][Dd][Ii][Nn][Ii][Mm][Aa][Ss] +nl_name N[Aa][Aa][Mm] +pl_name N[Aa][Zz][Ww][Aa] +ro_name N[Uu][Mm][Ee] +ru_name (И(М|м)(Я|я)|Н(А|а)(З|з)(В|в)(А|а)(Н|н)(И|и)(Е|е)|Н(А|а)(И|и)(М|м)(Е|е)(Н|н)(О|о)(В|в)(А|а)(Н|н)(И|и)(Е|е)) +sk_name M[Ee][Nn][Oo] +sr_name (И(М|м)(Е|е)|Н(А|а)(З|з)(И|и)(В|в)) +srlatin_name (I[Mm][Ee]|N[Aa][Zz][Ii][Vv]) +sv_name N[Aa][Mm][Nn] +ta_name பெய +tr_name (A[Dd]|(İ|i)S(İ|i)M) +uk_name Н(А|а)(З|з)(В|в)(А|а) +vi_name T(Ê|ê)[Nn] +zh_CN_name 名{blank}?(称|字){blank}?.* +zh_TW_name (名{blank}?(稱|字)|命令名){blank}?.* +name ({ar_name}|{bg_name}|{cs_name}|{da_name}|{de_name}|{en_name}|{eo_name}|{es_name}|{fa_name}|{fi_name}|{fr_name}|{hu_name}|{id_name}|{it_name}|{ja_name}|{ko_name}|{latin_name}|{lt_name}|{nl_name}|{pl_name}|{ro_name}|{ru_name}|{sk_name}|{sr_name}|{srlatin_name}|{sv_name}|{ta_name}|{tr_name}|{uk_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 = true; + } + + {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 = false; + {bol}\.fi.* fill_mode = true; +} + +<CAT_NAME>-{eol}{blank_eol}* /* strip continuations */ + + /* convert to DASH */ +<MAN_NAME>{ + {next}{blank}*\\\((mi|hy|em|en){blank}* | + {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}\\\[(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 = false; + 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 = false; +} + +int find_name (const char *file, const char *filename, lexgrog *p_lg, + const char *encoding) +{ + int ret = 0; + decompress *d; + char *page_encoding = NULL; + bool run_col = p_lg->type == CATPAGE && *PROG_COL != '\0'; + + if (strcmp (file, "-") == 0) { + d = decompress_fdopen (dup (STDIN_FILENO)); + } else { + struct stat st; + int decompress_flags; + 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 (); + decompress_flags = 0; + /* If we're looking at a cat page, then we need to run col + * over it, which doesn't work conveniently with an + * in-process decompressor. + */ + if (!run_col) + decompress_flags |= DECOMPRESS_ALLOW_INPROCESS; + d = decompress_open (file, decompress_flags); + if (!d) { + 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) { + if (decompress_is_pipeline (d)) + add_manconv (decompress_get_pipeline (d), + page_encoding, "UTF-8"); + else if (manconv_inprocess (d, page_encoding, "UTF-8") != 0) + /* manconv should already have written to stderr, so + * just return zero (i.e. no result). + */ + goto out; + } + if (run_col) { + pipecmd *col_cmd; + col_cmd = pipecmd_new_args + (PROG_COL, "-b", "-p", "-x", (void *) 0); + pipecmd_pre_exec (col_cmd, sandbox_load, sandbox_free, + sandbox); + pipeline_command (decompress_get_pipeline (d), col_cmd); + } + decompress_start (d); + + ret = find_name_decompressed (d, filename, p_lg); + +out: + free (page_encoding); + decompress_free (d); + return ret; +} + +int find_name_decompressed (decompress *d, const char *filename, lexgrog *p_lg) +{ + int ret; + + decomp = d; + + fname = filename; + *(p_name = newname) = '\0'; + memset (filters, '_', sizeof (filters)); + + fill_mode = true; + waiting_for_quote = false; + + if (p_lg->type == CATPAGE) + BEGIN (CAT_FILE); + else + BEGIN (MAN_FILE); + + drop_effective_privs (); + + yyrestart (NULL); + ret = yylex (); + + regain_effective_privs (); + + decompress_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..f5278f3 --- /dev/null +++ b/src/lexgrog_test.c @@ -0,0 +1,260 @@ +/* + * 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 <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> + +#include "argp.h" +#include "attribute.h" +#include "error.h" +#include "gl_list.h" +#include "progname.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "debug.h" +#include "glcontainers.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" +#include "util.h" + +#include "convert.h" +#include "descriptions.h" +#include "lexgrog.h" +#include "ult_src.h" + +int quiet = 1; +man_sandbox *sandbox; + +static bool parse_man = false, parse_cat = false; +static bool show_whatis = false, show_filters = false; +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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("man", 'm', 0, N_("parse as man page"), 1), + OPT ("cat", 'c', 0, N_("parse as cat page")), + OPT ("whatis", 'w', 0, N_("show whatis information"), 2), + OPT ("filters", 'f', 0, + N_("show guessed series of preprocessing filters")), + OPT ("encoding", 'E', N_("ENCODING"), + N_("use selected output encoding"), 3), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = true; + return 0; + case 'm': + parse_man = true; + return 0; + case 'c': + parse_cat = true; + return 0; + case 'w': + show_whatis = true; + return 0; + case 'f': + show_filters = true; + 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 = true; + if (!show_whatis && !show_filters) + show_whatis = true; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, void *input MAYBE_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 = MANPAGE; + int i; + bool some_failed = false; + + 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 = MANPAGE; + else + type = CATPAGE; + + for (i = 0; i < num_files; ++i) { + lexgrog lg; + const char *file = NULL; + bool found = false; + + lg.type = type; + + if (STREQ (files[i], "-")) + file = files[i]; + else { + char *path, *pathend; + struct stat statbuf; + const struct ult_value *ult; + + 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; + } + + ult = ult_src (files[i], path ? path : ".", + &statbuf, SO_LINK); + if (ult) + file = ult->path; + free (path); + } + + if (file && find_name (file, "-", &lg, encoding)) { + gl_list_t descs = parse_descriptions (NULL, lg.whatis); + const struct page_description *desc; + GL_LIST_FOREACH (descs, desc) { + if (!desc->name || !desc->whatis) + continue; + found = true; + printf ("%s", files[i]); + if (show_filters) + printf (" (%s)", lg.filters); + if (show_whatis) { + char *name_conv = convert_to_locale + (desc->name); + char *whatis_conv = convert_to_locale + (desc->whatis); + printf (": \"%s - %s\"", + name_conv, whatis_conv); + free (whatis_conv); + free (name_conv); + } + printf ("\n"); + } + gl_list_free (descs); + free (lg.filters); + free (lg.whatis); + } + + if (!found) { + printf ("%s: parse failed\n", files[i]); + some_failed = true; + } + } + + sandbox_free (sandbox); + + if (some_failed) + return FATAL; + else + return OK; +} diff --git a/src/man-recode.c b/src/man-recode.c new file mode 100644 index 0000000..e198d17 --- /dev/null +++ b/src/man-recode.c @@ -0,0 +1,296 @@ +/* + * man-recode.c: convert manual pages to another encoding + * + * Copyright (C) 2019 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 <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "argp.h" +#include "dirname.h" +#include "error.h" +#include "gl_array_list.h" +#include "gl_xlist.h" +#include "progname.h" +#include "tempname.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "pipeline.h" + +#include "cleanup.h" +#include "compression.h" +#include "debug.h" +#include "encodings.h" +#include "fatal.h" +#include "glcontainers.h" +#include "sandbox.h" +#include "util.h" + +#include "decompress.h" +#include "manconv.h" +#include "manconv_client.h" + +int quiet = 0; +man_sandbox *sandbox; + +static char *to_code; +static gl_list_t filenames; +static const char *suffix; +static bool in_place; + +struct try_file_at_args { + int dir_fd; + int flags; +}; + +static int +try_file_at (char *tmpl, void *flags) +{ + struct try_file_at_args *args = flags; + return openat (args->dir_fd, tmpl, + (args->flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR); +} + +static int +mkstempat (int dir_fd, char *xtemplate) +{ + struct try_file_at_args args; + + args.dir_fd = dir_fd; + args.flags = 0; + return try_tempname (xtemplate, 0, &args, try_file_at); +} + +enum opts { + OPT_SUFFIX = 256, + OPT_IN_PLACE = 257, + OPT_MAX +}; + +const char *argp_program_version = "man-recode " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; +error_t argp_err_exit_status = FAIL; + +static const char args_doc[] = + N_("-t CODE {--suffix SUFFIX | --in-place} FILENAME..."); + +static struct argp_option options[] = { + OPT ("to-code", 't', N_("CODE"), N_("encoding for output")), + OPT ("suffix", OPT_SUFFIX, N_("SUFFIX"), + N_("suffix to append to output file name")), + OPT ("in-place", OPT_IN_PLACE, 0, + N_("overwrite input files in place")), + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("quiet", 'q', 0, N_("produce fewer warnings")), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 't': + to_code = xstrdup (arg); + return 0; + case OPT_SUFFIX: + suffix = arg; + return 0; + case OPT_IN_PLACE: + in_place = true; + return 0; + case 'd': + debug_level = true; + 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: + gl_list_add_last (filenames, xstrdup (arg)); + return 0; + case ARGP_KEY_NO_ARGS: + argp_usage (state); + break; + case ARGP_KEY_SUCCESS: + if (!to_code) + argp_error (state, + _("must specify an output " + "encoding")); + if (!suffix && !in_place) + argp_error (state, + _("must use either --suffix or " + "--in-place")); + if (suffix && in_place) + argp_error (state, + _("--suffix and --in-place are " + "mutually exclusive")); + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +static void recode (const char *filename) +{ + decompress *decomp; + pipeline *convert, *decomp_p; + struct compression *comp; + int dir_fd = -1; + char *dirname, *basename, *stem, *outfilename; + char *page_encoding; + int status; + + decomp = decompress_open (filename, 0); + if (!decomp) + error (FAIL, 0, _("can't open %s"), filename); + + dirname = dir_name (filename); + basename = base_name (filename); + comp = comp_info (basename, true); + if (comp) + stem = comp->stem; /* steal memory */ + else + stem = xstrdup (basename); + + convert = pipeline_new (); + if (suffix) { + outfilename = xasprintf ("%s/%s%s", dirname, stem, suffix); + pipeline_want_outfile (convert, outfilename); + } else { + int dir_fd_open_flags; + char *template_path; + int outfd; + + dir_fd_open_flags = O_SEARCH | O_DIRECTORY; +#ifdef O_PATH + dir_fd_open_flags |= O_PATH; +#endif + dir_fd = open (dirname, dir_fd_open_flags); + if (dir_fd < 0) + fatal (errno, _("can't open %s"), dirname); + + outfilename = xasprintf ("%s.XXXXXX", stem); + /* For error messages. */ + template_path = xasprintf ("%s/%s", dirname, outfilename); + outfd = mkstempat (dir_fd, outfilename); + if (outfd == -1) + fatal (errno, + _("can't open temporary file %s"), + template_path); + free (template_path); + pipeline_want_out (convert, outfd); + } + + decompress_start (decomp); + page_encoding = check_preprocessor_encoding (decomp, NULL, NULL); + if (!page_encoding) { + char *lang = lang_dir (filename); + page_encoding = get_page_encoding (lang); + free (lang); + } + debug ("guessed input encoding %s for %s\n", page_encoding, filename); + add_manconv (convert, page_encoding, to_code); + + if (!pipeline_get_ncommands (convert)) + pipeline_command (convert, pipecmd_new_passthrough ()); + + decomp_p = decompress_get_pipeline (decomp); + pipeline_connect (decomp_p, convert, (void *) 0); + pipeline_pump (decomp_p, convert, (void *) 0); + pipeline_wait (decomp_p); + status = pipeline_wait (convert); + if (status != 0) + error (CHILD_FAIL, 0, _("command exited with status %d: %s"), + status, pipeline_tostring (convert)); + + if (in_place) { + assert (dir_fd != -1); + if (renameat (dir_fd, outfilename, dir_fd, stem) == -1) { + char *outfilepath = xasprintf + ("%s/%s", dirname, outfilename); + unlink (outfilename); + fatal (errno, _("can't rename %s to %s"), + outfilepath, filename); + } + debug ("stem: %s, basename: %s\n", stem, basename); + if (!STREQ (stem, basename)) { + if (unlinkat (dir_fd, basename, 0) == -1) + fatal (errno, _("can't remove %s"), filename); + } + } + + free (page_encoding); + free (outfilename); + free (stem); + free (basename); + free (dirname); + if (dir_fd) + close (dir_fd); + pipeline_free (convert); + decompress_free (decomp); +} + +int main (int argc, char *argv[]) +{ + const char *filename; + + set_program_name (argv[0]); + + init_debug (); + pipeline_install_post_fork (pop_all_cleanups); + sandbox = sandbox_init (); + init_locale (); + filenames = new_string_list (GL_ARRAY_LIST, true); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + GL_LIST_FOREACH (filenames, filename) + recode (filename); + + free (to_code); + + gl_list_free (filenames); + sandbox_free (sandbox); + + return 0; +} diff --git a/src/man.c b/src/man.c new file mode 100644 index 0000000..f072c75 --- /dev/null +++ b/src/man.c @@ -0,0 +1,4474 @@ +/* + * 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 <stdbool.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> +#include <limits.h> +#include <fcntl.h> +#include <ctype.h> +#include <signal.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "argp.h" +#include "attribute.h" +#include "dirname.h" +#include "error.h" +#include "gl_array_list.h" +#include "gl_hash_map.h" +#include "gl_list.h" +#include "gl_xlist.h" +#include "gl_xmap.h" +#include "minmax.h" +#include "progname.h" +#include "regex.h" +#include "stat-time.h" +#include "utimens.h" +#include "xalloc.h" +#include "xgetcwd.h" +#include "xstdopen.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "compression.h" +#include "debug.h" +#include "fatal.h" +#include "filenames.h" +#include "glcontainers.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 "tempfile.h" +#include "util.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "globbing.h" +#include "ult_src.h" +#include "manp.h" +#include "zsoelim.h" +#include "manconv.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 bool global_manpath; /* global or user manual page hierarchy? */ +static bool 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 +}; + +static gl_list_t manpathlist; + +/* globals */ +int quiet = 1; +extern const char *extension; /* for globbing.c */ +extern char *user_config_file; /* defined in manp.c */ +extern bool disable_cache; +extern int min_cat_width, max_cat_width, cat_width; +man_sandbox *sandbox; + +/* locals */ +static const char *alt_system_name; +static gl_list_t 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 gl_map_t db_map = NULL; + +static bool troff; +static const char *roff_device = NULL; +static const char *want_encoding = NULL; +#ifdef NROFF_WARNINGS +static const char default_roff_warnings[] = "mac"; +static gl_list_t roff_warnings; +#endif /* NROFF_WARNINGS */ +static bool global_apropos; +static bool print_where, print_where_cat; +static bool catman; +static bool local_man_file; +static bool findall; +static bool update; +static bool match_case; +static bool regex_opt; +static bool wildcard; +static bool names_only; +static int ult_flags = SO_LINK | SOFT_LINK | HARD_LINK; +static const char *recode = NULL; +static bool no_hyphenation; +static bool no_justification; +static bool subpages = true; + +static bool ascii; /* insert tr in the output pipe */ +static bool save_cat; /* security breach? Can we save the cat? */ + +static int first_arg; + +#ifdef MAN_CATS +static char *tmp_cat_file; /* for open_cat_stream(), close_cat_stream() */ +static bool 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 bool ditroff; +static const char *gxditview; +static bool 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 HAS_TROFF +# ifdef TROFF_IS_GROFF +# define ONLY_TROFF_IS_GROFF 0 +# else +# define ONLY_TROFF_IS_GROFF OPTION_HIDDEN +# endif +# endif /* HAS_TROFF */ + +/* Please keep these options in the same order as in parse_opt below. */ +static struct argp_option options[] = { + OPT ("config-file", 'C', N_("FILE"), + N_("use this user configuration file")), + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("default", 'D', 0, + N_("reset all options to their default values")), + OPT_FULL ("warnings", OPT_WARNINGS, N_("WARNINGS"), + ONLY_NROFF_WARNINGS | OPTION_ARG_OPTIONAL, + N_("enable warnings from groff")), + + OPT_GROUP_HEADER (N_("Main modes of operation:"), 10), + OPT ("whatis", 'f', 0, N_("equivalent to whatis")), + OPT ("apropos", 'k', 0, N_("equivalent to apropos")), + OPT ("global-apropos", 'K', 0, N_("search for text in all pages")), + OPT ("where", 'w', 0, N_("print physical location of man page(s)")), + OPT_ALIAS ("path", 0), + OPT_ALIAS ("location", 0), + OPT ("where-cat", 'W', 0, + N_("print physical location of cat file(s)")), + OPT_ALIAS ("location-cat", 0), + OPT ("local-file", 'l', 0, + N_("interpret PAGE argument(s) as local filename(s)")), + OPT ("catman", 'c', 0, + N_("used by catman to reformat out of date cat pages"), 11), + OPT ("recode", 'R', N_("ENCODING"), + N_("output source page encoded in ENCODING")), + + OPT_GROUP_HEADER (N_("Finding manual pages:"), 20), + OPT ("locale", 'L', N_("LOCALE"), + N_("define the locale for this particular man search")), + OPT ("systems", 'm', N_("SYSTEM"), + N_("use manual pages from other systems")), + OPT ("manpath", 'M', N_("PATH"), + N_("set search path for manual pages to PATH")), + OPT ("sections", 'S', N_("LIST"), + N_("use colon separated section list"), 21), + OPT_ALIAS (0, 's'), + OPT ("extension", 'e', N_("EXTENSION"), + N_("limit search to extension type EXTENSION"), 22), + OPT ("ignore-case", 'i', 0, + N_("look for pages case-insensitively (default)"), 23), + OPT ("match-case", 'I', 0, N_("look for pages case-sensitively")), + OPT ("regex", OPT_REGEX, 0, N_("show all pages matching regex"), 24), + OPT ("wildcard", OPT_WILDCARD, 0, + N_("show all pages matching wildcard")), + OPT ("names-only", OPT_NAMES, 0, + N_("make --regex and --wildcard match page names only, not " + "descriptions"), + 25), + OPT ("all", 'a', 0, N_("find all matching manual pages"), 26), + OPT ("update", 'u', 0, N_("force a cache consistency check")), + OPT ("no-subpages", OPT_NO_SUBPAGES, 0, + N_("don't try subpages, e.g. 'man foo bar' => 'man foo-bar'"), + 27), + + OPT_GROUP_HEADER (N_("Controlling formatted output:"), 30), + OPT ("pager", 'P', N_("PAGER"), + N_("use program PAGER to display output")), + OPT ("prompt", 'r', N_("STRING"), + N_("provide the `less' pager with a prompt")), + OPT ("ascii", '7', 0, + N_("display ASCII translation of certain latin1 chars"), 31), + OPT ("encoding", 'E', N_("ENCODING"), + N_("use selected output encoding")), + OPT ("no-hyphenation", OPT_NO_HYPHENATION, 0, + N_("turn off hyphenation")), + OPT_ALIAS ("nh", 0), + OPT ("no-justification", OPT_NO_JUSTIFICATION, 0, + N_("turn off justification")), + OPT_ALIAS ("nj", 0), + OPT ("preprocessor", 'p', N_("STRING"), + 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 + OPT ("troff", 't', 0, N_("use %s to format pages"), 32), + OPT_FULL ("troff-device", 'T', N_("DEVICE"), OPTION_ARG_OPTIONAL, + N_("use %s with selected device")), + OPT_FULL ("html", 'H', N_("BROWSER"), + ONLY_TROFF_IS_GROFF | OPTION_ARG_OPTIONAL, + N_("use %s or BROWSER to display HTML output"), 33), + OPT_FULL ("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")), + OPT_FULL ("ditroff", 'Z', 0, ONLY_TROFF_IS_GROFF, + N_("use groff and force it to produce ditroff")), +#endif /* HAS_TROFF */ + + OPT_HELP_COMPAT, + { 0 } +}; + +#ifdef TROFF_IS_GROFF +static void init_html_pager (void) +{ + html_pager = getenv ("BROWSER"); + if (!html_pager) + html_pager = PROG_BROWSER; +} +#endif /* TROFF_IS_GROFF */ + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + static bool 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 = true; + 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 = false; +#ifdef TROFF_IS_GROFF + ditroff = false; + gxditview = NULL; + htmlout = false; + 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, ",")) + gl_list_add_last (roff_warnings, + xstrdup (warning)); + + free (s); + } +#endif /* NROFF_WARNINGS */ + return 0; + + case 'f': + external = WHATIS; + whatis = true; + return 0; + case 'k': + external = APROPOS; + apropos = true; + return 0; + case 'K': + global_apropos = true; + return 0; + case 'w': + print_where = true; + return 0; + case 'W': + print_where_cat = true; + return 0; + case 'l': + local_man_file = true; + return 0; + case 'c': + catman = true; + 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 = false; + return 0; + case 'I': + match_case = true; + return 0; + case OPT_REGEX: + regex_opt = true; + findall = true; + return 0; + case OPT_WILDCARD: + wildcard = true; + findall = true; + return 0; + case OPT_NAMES: + names_only = true; + return 0; + case 'a': + findall = true; + return 0; + case 'u': + update = true; + return 0; + case OPT_NO_SUBPAGES: + subpages = false; + return 0; + + case 'P': + pager = arg; + return 0; + case 'r': + prompt_string = arg; + return 0; + case '7': + ascii = true; + 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 = true; + return 0; + case OPT_NO_JUSTIFICATION: + no_justification = true; + return 0; + case 'p': + preprocessors = arg; + return 0; +#ifdef HAS_TROFF + case 't': + troff = true; + 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 = true; + return 0; + case 'H': +# ifdef TROFF_IS_GROFF + if (arg) + html_pager = arg; + htmlout = true; + troff = true; + roff_device = "html"; +# endif /* TROFF_IS_GROFF */ + return 0; + case 'X': +# ifdef TROFF_IS_GROFF + troff = true; + gxditview = (arg ? arg : "75"); +# endif /* TROFF_IS_GROFF */ + return 0; + case 'Z': +# ifdef TROFF_IS_GROFF + ditroff = true; + troff = true; +# 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 ((int) troff + (int) whatis + (int) apropos + + (int) catman + + (int) (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 ((int) regex_opt + (int) 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; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" +static char *help_filter (int key, const char *text, void *input MAYBE_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; + } +} +#pragma GCC diagnostic pop + +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); + fputs (_("For example, try 'man man'.\n"), stderr); + + exit (FAIL); +} + +#ifdef HAVE_TERMIOS_H +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); + } + } +} +#else /* !HAVE_TERMIOS_H */ +static void get_term (void) +{ +} +#endif /* HAVE_TERMIOS_H */ + +#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, bool *save_cat_p) +{ + int length; + pipecmd *ret = NULL; + + if (!catman && cat_width) + debug ("Cat pages forced to terminal width %d\n", cat_width); + else 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 = false; + } + } + + 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) { + char c = *string++; + + if (c == '$') + /* Dollar signs are difficult to handle properly, and + * not really worth the trouble, so just replace them + * with question marks. See + * https://bugs.debian.org/1021951. + */ + c = '?'; + + if (strchr ("?:.%\\", c)) + *ptr++ = '\\'; + + *ptr++ = c; + } + + *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 (bool 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 * ATTRIBUTE_PURE is_section (const char *name) +{ + const char *vs; + + GL_LIST_FOREACH (section_list, 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 (decompress *decomp, int prefixes) +{ + 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 = decompress_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); + } + return NULL; +} + + +/* Determine pre-processors, set save_cat and return string */ +static char *get_preprocessors (decompress *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 = true; + } else if (preprocessors) { + pp_string = xstrdup (preprocessors); + pp_source = "command line"; + save_cat = false; + } else if ((pp_string = get_preprocessors_from_file (decomp, + prefixes))) { + pp_source = "file"; + save_cat = true; + } else if ((env = getenv ("MANROFFSEQ"))) { + pp_string = xstrdup (env); + pp_source = "environment"; + save_cat = false; + } else if (!dbfilters) { + pp_string = xstrdup (DEFAULT_MANROFFSEQ); + pp_source = "default"; + save_cat = true; + } else { + pp_string = xstrdup (""); + pp_source = "no filters"; + save_cat = true; + } + + 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 (PROG_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); +} + +static void add_filter (pipeline *p, pipecmd *cmd, + bool wants_dev, bool wants_post) +{ + 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); + if (strstr (gxditview, "-12")) + pipecmd_argf (cmd, "-rS12"); + } +#endif /* TROFF_IS_GROFF */ + } + + if (wants_post) { +#ifdef TROFF_IS_GROFF + if (gxditview) + /* -X arranges for the correct options to be passed + * to troff. Normally it would run gxditview as + * well, but we suppress that with -Z so that we can + * do it ourselves; this lets us set a better window + * title, and means that we don't have to worry + * about sandboxing text processing and an X program + * in the same way. + */ + pipecmd_args (cmd, "-X", "-Z", (void *) 0); +#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); +} + +/* Return pipeline to format file to stdout. */ +static pipeline *make_roff_command (const char *dir, const char *file, + decompress *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, NULL, NULL); + 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) { + char *pp_string_initial; + const char *pp; +#ifndef GNU_NROFF + bool using_tbl = false; +#endif /* GNU_NROFF */ +#ifdef NROFF_WARNINGS + const char *warning; +#endif /* NROFF_WARNINGS */ + + /* Add preprocessors. Per groff(1), grap, chem, and ideal must + * come before pic, and tbl must come before eqn. + */ + pp_string_initial = xstrndup (pp_string, + strcspn (pp_string, " -")); + if (strchr (pp_string_initial, 'r')) { + cmd = pipecmd_new_argstr + (get_def ("refer", PROG_REFER)); + add_filter (p, cmd, false, false); + } + if (strchr (pp_string_initial, 'g')) { + cmd = pipecmd_new_argstr (get_def ("grap", PROG_GRAP)); + add_filter (p, cmd, false, false); + } + if (strchr (pp_string_initial, 'p')) { + cmd = pipecmd_new_argstr (get_def ("pic", PROG_PIC)); + add_filter (p, cmd, false, false); + } + if (strchr (pp_string_initial, 't')) { + cmd = pipecmd_new_argstr (get_def ("tbl", PROG_TBL)); + add_filter (p, cmd, false, false); +#ifndef GNU_NROFF + using_tbl = true; +#endif /* GNU_NROFF */ + } + if (strchr (pp_string_initial, 'e')) { + const char *eqn; + if (troff) + eqn = get_def ("eqn", PROG_EQN); + else + eqn = get_def ("neqn", PROG_NEQN); + cmd = pipecmd_new_argstr (eqn); + /* eqn wants device options. */ + add_filter (p, cmd, true, false); + } + if (strchr (pp_string_initial, 'v')) { + cmd = pipecmd_new_argstr + (get_def ("vgrind", PROG_VGRIND)); + add_filter (p, cmd, false, false); + } + for (pp = pp_string_initial; *pp; ++pp) { + if (!strchr ("rgptev", *pp)) + error (0, 0, + _("ignoring unknown preprocessor `%c'"), + *pp); + } + free (pp_string_initial); + + /* Add *roff itself. */ + if (troff) { + cmd = pipecmd_new_argstr + (get_def ("troff", PROG_TROFF)); + save_cat = false; + } else + cmd = pipecmd_new_argstr + (get_def ("nroff", PROG_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 + GL_LIST_FOREACH (roff_warnings, warning) + pipecmd_argf (cmd, "-w%s", warning); +#endif /* NROFF_WARNINGS */ + +#ifdef HEIRLOOM_NROFF + if (running_setuid ()) + pipecmd_unsetenv (cmd, "TROFFMACS"); +#endif /* HEIRLOOM_NROFF */ + + pipecmd_argstr (cmd, roff_opt); + + /* *roff wants both device and postprocessor arguments. */ + add_filter (p, cmd, true, true); + + if (!troff && *PROG_COL != '\0') { + 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 && *PROG_COL != '\0') + 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); + bool found_percent_s = false; + 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 = true; + 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 MAYBE_UNUSED) +{ + char *line = NULL; + size_t len = 0; + + while (getline (&line, &len, stdin) != -1) { + bool in_blank_line = true; + bool got_blank_line = false; + + while (in_blank_line) { + char *p; + for (p = line; *p; ++p) { + if (!CTYPE (isspace, *p)) { + in_blank_line = false; + break; + } + } + + if (in_blank_line) { + got_blank_line = true; + 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 && *PROG_COL != '\0') { + /* 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); + } + +#ifdef TROFF_IS_GROFF + if (gxditview) { + char *x_resource = xasprintf ("*iconName:%s", title); + pipeline_command_args + (p, "gxditview", + "-title", title, "-xrm", x_resource, "-", + (void *) 0); + free (x_resource); + return p; + } +#endif /* TROFF_IS_GROFF */ + + /* 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", PROG_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 = false; + + debug ("creating temporary cat for %s\n", cat_file); + + tmp_cat_file = tmp_cat_filename (cat_file); + if (tmp_cat_file) + created_tmp_cat = true; + 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 + 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", PROG_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 (decompress *d, + pipeline *format_cmd, + pipeline *disp_cmd, + const char *cat_file, const char *encoding) +{ + pipeline *decomp = decompress_get_pipeline (d); + 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 */ + +#ifdef TROFF_IS_GROFF +# define MAN_FILE_UNUSED +#else /* !TROFF_IS_GROFF */ +# define MAN_FILE_UNUSED MAYBE_UNUSED +#endif /* TROFF_IS_GROFF */ + +/* 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 (decompress *d, + pipeline *format_cmd, pipeline *disp_cmd, + const char *man_file MAN_FILE_UNUSED) +{ + pipeline *decomp = decompress_get_pipeline (d); + 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) + 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) + 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, false) == -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"); + } else if (!disp_status) + sleep (5); /* firefox runs into background too fast */ + + free (browser_list); + if (remove_directory (htmldir, false) == -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, decompress *d, + pipeline *format_cmd, const char *encoding) +{ + char *tmpcat = tmp_cat_filename (cat_file); + pipeline *decomp = decompress_get_pipeline (d); +#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", PROG_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 MAYBE_UNUSED) +{ + fputs (".nh\n" + ".de hy\n" + "..\n" + ".lf 1\n", stdout); +} + +static void disable_justification (void *data MAYBE_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 = false; + 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 = true; + 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; + bool display_to_stdout; + decompress *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, 0); + 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) { + pipeline *decomp_p = decompress_get_pipeline (decomp); + + assert (pipeline_get_ncommands (decomp_p) <= 1); + if (pipeline_get_ncommands (decomp_p)) { + pipecmd_sequence_command + (seq, + pipeline_get_command (decomp_p, 0)); + pipeline_set_command (decomp_p, 0, seq); + } else { + pipecmd_sequence_command + (seq, pipecmd_new_passthrough ()); + pipeline_command (decomp_p, seq); + } + } else + pipecmd_free (seq); + } + + if (decomp) { + char *pp_string; + + decompress_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 || gxditview) + display_to_stdout = false; +#endif + if (recode) + display_to_stdout = true; + + 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) { + pipeline *decomp_p = decompress_get_pipeline (decomp); + int status; + if (prompt && do_prompt (title)) { + pipeline_free (format_cmd); + decompress_free (decomp); + free (formatted_encoding); + return 0; + } + drop_effective_privs (); + pipeline_connect (decomp_p, format_cmd, (void *) 0); + pipeline_pump (decomp_p, format_cmd, (void *) 0); + pipeline_wait (decomp_p); + status = pipeline_wait (format_cmd); + regain_effective_privs (); + if (status != 0) + gripe_system (format_cmd, status); + } + } else { + bool format = true; + 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 + || gxditview +#endif + || local_man_file + || recode + || disable_cache + || no_hyphenation + || no_justification) + save_cat = false; + + if (!man_file) { + /* Stray cat. */ + assert (cat_file); + format = false; + } else if (!cat_file) { + assert (man_file); + save_cat = false; + format = true; + } 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 && *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", + (int) format, (int) save_cat, found); + + if (!found) { + pipeline_free (format_cmd); + decompress_free (decomp); + return found; + } + + if (print_where || print_where_cat) { + bool printed = false; + if (print_where && man_file) { + printf ("%s", man_file); + printed = true; + } + if (print_where_cat && cat_file && !format) { + if (printed) + putchar (' '); + printf ("%s", cat_file); + printed = true; + } + 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); + decompress_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; + decompress *decomp_cat; + + if (prompt && do_prompt (title)) { + pipeline_free (format_cmd); + decompress_free (decomp); + return 0; + } + + decomp_cat = decompress_open (cat_file, 0); + if (!decomp_cat) { + error (0, errno, _("can't open %s"), cat_file); + pipeline_free (format_cmd); + decompress_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); + decompress_free (decomp_cat); + } + } + + free (formatted_encoding); + + pipeline_free (format_cmd); + decompress_free (decomp); + + if (!prompt) + prompt = found; + + return found; +} + +static _Noreturn void gripe_converting_name (const char *name) +{ + fatal (0, _("Can't convert %s to cat name"), name); +} + +/* 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, bool fsstnd) +{ + char *to_name, *t1 = NULL; + char *t2 = NULL; + struct compression *comp; + char *namestem; + + comp = comp_info (name, true); + if (comp) + namestem = comp->stem; + else + 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, true); + 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, false); + free (cat_path); + } else if (STRNEQ (man_file, path, path_len) && + man_file[path_len] == '/') + cat_file = convert_name (man_file, true); + 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, false); + free (cat_path); + } else + cat_file = convert_name (original, true); + + 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 true if so, otherwise false. + */ +static bool duplicate_candidates (struct candidate *left, + struct candidate *right) +{ + const char *slash1, *slash2; + struct locale_bits bits1, bits2; + bool ret; + + if (left->ult && right->ult && STREQ (left->ult, right->ult)) + return true; /* 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 false; /* different name/section/extension */ + + if (STREQ (left->path, right->path)) + return true; /* 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 false; /* 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 = false; /* different language/territory/modifier */ + else + /* Everything seems to be the same; we can find nothing to + * choose between them. + */ + ret = true; + + free_locale_bits (&bits1); + free_locale_bits (&bits2); + return ret; +} + +/* Return zero if the candidates are in different base paths or if both + * candidates or neither are in OVERRIDE_DIR relative to their base path; + * negative if left is in OVERRIDE_DIR and right is not; or positive if + * right is in OVERRIDE_DIR and left is not. + */ +static int compare_override_dir (const struct candidate *left, + const struct candidate *right) +{ + size_t left_len, right_len; + + if (!*OVERRIDE_DIR) + return 0; + + left_len = strlen (left->path); + right_len = strlen (right->path); + if (left_len == right_len || + !STRNEQ (left->path, right->path, MIN (left_len, right_len))) + return 0; + + if (left_len > right_len) { + if (left->path[right_len] == '/' && + STREQ (left->path + right_len + 1, OVERRIDE_DIR)) + return -1; + } else { + if (right->path[left_len] == '/' && + STREQ (right->path + left_len + 1, OVERRIDE_DIR)) + return 1; + } + + return 0; +} + +static int compare_candidates (const struct candidate *left, + const struct candidate *right) +{ + const struct mandata *lsource = left->source, *rsource = right->source; + 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; + } + + /* ULT_MAN comes first, etc. Consider SO_MAN equivalent to ULT_MAN. + * This has the effect of sorting mere whatis references below real + * pages. + */ + cmp = compare_ids (lsource->id, rsource->id, true); + if (cmp) + return cmp; + + /* Compare pure sections first, then extensions. + * + * 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)) { + size_t index_left, index_right; + + /* 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. Sections missing from section_list are + * sorted to the end. + */ + index_left = gl_list_indexof (section_list, lsource->ext); + if (index_left == (size_t) -1 && strlen (lsource->ext) > 1) { + char *sec_left = xstrndup (lsource->ext, 1); + index_left = gl_list_indexof (section_list, sec_left); + free (sec_left); + if (index_left == (size_t) -1) + index_left = gl_list_size (section_list); + } + index_right = gl_list_indexof (section_list, rsource->ext); + if (index_right == (size_t) -1 && strlen (rsource->ext) > 1) { + char *sec_right = xstrndup (rsource->ext, 1); + index_right = gl_list_indexof (section_list, + sec_right); + free (sec_right); + if (index_right == (size_t) -1) + index_right = gl_list_size (section_list); + } + if (index_left < index_right) + return -1; + else if (index_left > index_right) + return 1; + + cmp = strcmp (lsource->sec, rsource->sec); + 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; + + /* If one candidate is in OVERRIDE_DIR within the same base path as + * the other candidate, then the candidate in OVERRIDE_DIR comes + * first. + */ + cmp = compare_override_dir (left, right); + 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.elt, bits2.elt); \ + 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; + const struct ult_value *ult_value; + + 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_value = ult_src (filename, path, NULL, + get_ult_flags (from_db, source->id)); + if (ult_value) + ult = ult_value->path; + 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) { + bool 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, + (int) 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; + gl_list_t names = NULL; + const char *found_name; + 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 PROG_NROFF */ + /* + * Look for man page source files. + */ + + names = look_for_file (path, sec, name, false, lff_opts); + if (!gl_list_size (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) { + if (names) + gl_list_free (names); + names = look_for_file (path, sec, name, true, + lff_opts); + cat = 1; + } + } + if (!names) + return 0; + + order_files (path, &names); + + GL_LIST_FOREACH (names, found_name) { + struct mandata *info = filename_info (found_name, quiet < 2); + const struct ult_value *ult; + int f; + + if (!info) + continue; + + /* 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 (found_name, path, NULL, ult_flags); + if (!ult) { + /* already warned */ + debug ("try_section(): bad link %s\n", found_name); + free_mandata_struct (info); + continue; + } + if (STREQ (ult->path, found_name)) + info->id = ULT_MAN; + else + info->id = SO_MAN; + + f = add_candidate (cand_head, CANDIDATE_FILESYSTEM, + cat, name, path, ult->path, info); + found += f; + /* Free info if it wasn't added to the candidates. */ + if (f == 0) + free_mandata_struct (info); + /* Don't free info here. */ + } + + gl_list_free (names); + 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 struct ult_value *man_ult; + char *cat_file; + + man_ult = ult_src (filename, candp->path, NULL, ult_flags); + if (!man_ult) + goto out; + + debug ("found ultimate source file %s\n", man_ult->path); + lang = lang_dir (man_ult->path); + + cat_file = find_cat_file (candp->path, filename, + man_ult->path); + found = display (candp->path, man_ult->path, 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, + const char *manpath) +{ + if (!catman) { + char *catpath, *database; + MYDBM_FILE dbf; + + catpath = get_catpath (manpath, + global_manpath ? SYSTEM_CAT : USER_CAT); + database = mkdbname (catpath ? catpath : manpath); + dbf = MYDBM_NEW (database); + if (MYDBM_RWOPEN (dbf)) { + if (dbdelete (dbf, page, info) == 1) + debug ("%s(%s) not in db!\n", page, info->ext); + } + + MYDBM_FREE (dbf); + free (database); + free (catpath); + } +} +#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 PROG_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 struct ult_value *man_ult; + char *cat_file; + + man_ult = ult_src (file, candp->path, NULL, + get_ult_flags (1, in->id)); + if (!man_ult) { + free (title); + return found; /* zero */ + } + + debug ("found ultimate source file %s\n", + man_ult->path); + lang = lang_dir (man_ult->path); + + cat_file = find_cat_file (candp->path, file, + man_ult->path); + found += display (candp->path, man_ult->path, 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; + } + + /* 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, %s)\n", + candp->req_name, candp->source, candp->path); + dbdelete_wrapper (candp->req_name, candp->source, candp->path); + } +#endif /* MAN_DB_UPDATES */ + + return exists; +} + +#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 (false, 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 */ + +static void db_map_value_free (const void *value) +{ + /* The value may be NULL to indicate that opening the database at + * this location already failed. + */ + if (value) + gl_list_free ((gl_list_t) value); +} + +/* 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) +{ + gl_list_t matches; + struct mandata *loc; + char *catpath, *database; + MYDBM_FILE dbf = NULL; + int found = 0; +#ifdef MAN_DB_UPDATES + bool found_stale = false; +#endif /* MAN_DB_UPDATES */ + + /* find out where our db for this manpath should be */ + + catpath = get_catpath (manpath, global_manpath ? SYSTEM_CAT : USER_CAT); + database = mkdbname (catpath ? catpath : manpath); + + if (!db_map) + db_map = new_string_map (GL_HASH_MAP, db_map_value_free); + + /* If we haven't looked here already, do so now. */ + if (!gl_map_search (db_map, manpath, (const void **) &matches)) { + dbf = MYDBM_NEW (database); + if (MYDBM_RDOPEN (dbf) && !dbver_rd (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) + matches = dblookup_pattern + (dbf, name, section, match_case, + regex_opt, !names_only); + else + matches = dblookup_all (dbf, name, section, + match_case); + gl_map_put (db_map, xstrdup (manpath), matches); +#ifdef MAN_DB_CREATES + } else if (!global_manpath) { + /* create one */ + debug ("Failed to open %s O_RDONLY\n", database); + if (run_mandb (true, manpath, NULL)) { + gl_map_put (db_map, xstrdup (manpath), NULL); + found = TRY_DATABASE_OPEN_FAILED; + goto out; + } + found = TRY_DATABASE_CREATED; + goto out; +#endif /* MAN_DB_CREATES */ + } else { + debug ("Failed to open %s O_RDONLY\n", database); + gl_map_put (db_map, xstrdup (manpath), NULL); + found = TRY_DATABASE_OPEN_FAILED; + goto out; + } + assert (matches != NULL); + } + + /* We already tried (and failed) to open this db before. */ + if (!matches) { + found = TRY_DATABASE_OPEN_FAILED; + goto out; + } + +#ifdef MAN_DB_UPDATES + /* Check that all the entries found are up to date. If not, the + * caller should try again. + */ + GL_LIST_FOREACH (matches, loc) + 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 = true; + + if (found_stale) { + gl_map_remove (db_map, manpath); + found = TRY_DATABASE_UPDATED; + goto out; + } +#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 */ + GL_LIST_FOREACH (matches, loc) + 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); + +out: + MYDBM_FREE (dbf); + free (database); + free (catpath); + 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; + decompress *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, DECOMPRESS_ALLOW_INPROCESS); + if (!decomp) + return 0; + decompress_start (decomp); + while ((line = decompress_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; + } + } + } + + decompress_free (decomp); + return ret; +} + +static int do_global_apropos_section (const char *path, const char *sec, + const char *name) +{ + int found = 0; + gl_list_t names; + const char *found_name; + 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, "*", false, LFF_WILDCARD); + + if (regex_opt) + xregcomp (&search, name, + REG_EXTENDED | REG_NOSUB | + (match_case ? 0 : REG_ICASE)); + else + memset (&search, 0, sizeof search); + + order_files (path, &names); + + GL_LIST_FOREACH (names, found_name) { + struct mandata *info; + char *title = NULL; + const struct ult_value *man_ult; + char *cat_file = NULL; + + if (!grep (found_name, name, &search)) + continue; + + info = filename_info (found_name, quiet < 2); + if (!info) + goto next; + + title = xasprintf ("%s(%s)", info->name, info->ext); + man_ult = ult_src (found_name, path, NULL, ult_flags); + if (!man_ult) + goto next; + lang = lang_dir (man_ult->path); + cat_file = find_cat_file (path, found_name, man_ult->path); + if (display (path, man_ult->path, cat_file, title, NULL)) + found = 1; + free (lang); + lang = NULL; + +next: + free (cat_file); + free (title); + free_mandata_struct (info); + } + + gl_list_free (names); + + if (regex_opt) + regfree (&search); + + if (!global_manpath) + regain_effective_privs (); + + return found; +} + +static int do_global_apropos (const char *name, int *found) +{ + gl_list_t my_section_list; + const char *sec; + + if (section) { + my_section_list = gl_list_create_empty (GL_ARRAY_LIST, NULL, + NULL, NULL, false); + gl_list_add_last (my_section_list, section); + } else + my_section_list = section_list; + + GL_LIST_FOREACH (my_section_list, sec) { + char *mp; + + GL_LIST_FOREACH (manpathlist, mp) + *found += do_global_apropos_section (mp, sec, name); + } + + if (section) + gl_list_free (my_section_list); + + return *found ? OK : NOT_FOUND; +} + +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; + bool local_mf = local_man_file; + + drop_effective_privs (); + local_man_file = true; + 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; + gl_list_t old_manpathlist; + + debug ("recalculating manpath for executable " + "in %s\n", argv_dir); + + new_manp = get_manpath_from_path (argv_dir, + false); + 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 = manpathlist; + manpathlist = create_pathlist (new_manp); + + man (argv_base, &found); + + free_pathlist (manpathlist); + manpathlist = 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]" or "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, *lparen, *rparen; + + dot = strrchr (page_name, '.'); + if (dot && is_section (dot + 1)) { + *ret_name = xstrndup (page_name, dot - page_name); + *ret_section = xstrdup (dot + 1); + return; + } + + lparen = strrchr (page_name, '('); + rparen = strrchr (page_name, ')'); + if (lparen && rparen && rparen > lparen) { + char *paren_section = xstrndup + (lparen + 1, rparen - lparen - 1); + if (is_section (paren_section)) { + *ret_name = xstrndup (page_name, lparen - page_name); + *ret_section = paren_section; /* steal memory */ + return; + } + free (paren_section); + } + + *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; + + GL_LIST_FOREACH (manpathlist, 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 (section) + locate_page_in_manpath (section, name, &candidates, found); + else { + const char *sec; + + GL_LIST_FOREACH (section_list, sec) + locate_page_in_manpath (sec, 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 int man_maybe_local (const char *name, int *found) +{ + *found = 0; + if (strchr (name, '/')) { + int status = local_man_loop (name); + if (status == OK) + *found = 1; + return status; + } + return man (name, found); +} + + +static gl_list_t get_section_list (void) +{ + gl_list_t config_sections, sections; + char *section_list_copy; + const char *sec; + + /* Section list from configuration file, or STD_SECTIONS if it's + * empty. + */ + config_sections = get_sections (); + if (!gl_list_size (config_sections)) { + int i; + for (i = 0; std_sections[i]; ++i) + gl_list_add_last (config_sections, + xstrdup (std_sections[i])); + } + + 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. + */ + sections = new_string_list (GL_ARRAY_LIST, true); + section_list_copy = xstrdup (colon_sep_section_list); + for (sec = strtok (section_list_copy, ":,"); sec; + sec = strtok (NULL, ":,")) + gl_list_add_last (sections, xstrdup (sec)); + free (section_list_copy); + + if (gl_list_size (sections)) { + gl_list_free (config_sections); + return sections; + } else { + gl_list_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]); + + 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"); + + xstdopen (); + +/* 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 */ + +#ifdef NROFF_WARNINGS + roff_warnings = new_string_list (GL_ARRAY_LIST, true); +#endif /* NROFF_WARNINGS */ + + /* 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 */ + + /* 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 (PROG_PAGER); + if (pathsearch_executable (pager_program)) + pager = PROG_PAGER; + else + pager = ""; + free (pager_program); + } + if (*pager == '\0') + pager = get_def_user ("cat", PROG_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 ("using %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)); + + manpathlist = create_pathlist (manp); + + /* 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 (false, 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 bool maybe_section = false; + 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 = true; + } + } + + 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 = false; + if (global_apropos) + status = do_global_apropos (nextarg, &found); + else { + bool found_subpage = false; + if (subpages && first_arg < argc) { + char *subname = xasprintf ( + "%s-%s", nextarg, argv[first_arg]); + assert (subname); + status = man (subname, &found); + free (subname); + if (status == OK) { + found_subpage = true; + ++first_arg; + } + } + if (!found_subpage && subpages && first_arg < argc) { + char *subname = xasprintf ( + "%s_%s", nextarg, argv[first_arg]); + assert (subname); + status = man (subname, &found); + free (subname); + if (status == OK) { + found_subpage = true; + ++first_arg; + } + } + if (!found_subpage) + status = man_maybe_local (nextarg, &found); + } + + /* clean out the cache of database lookups for each man page */ + if (db_map) { + gl_map_free (db_map); + db_map = NULL; + } + + if (section && maybe_section) { + if (status != OK && !catman) { + /* Maybe the section wasn't a section after + * all? e.g. 'man 9wm fvwm'. + */ + bool found_subpage = false; + 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 = true; + ++first_arg; + } + } + if (!found_subpage) + status = man_maybe_local (tmp, &found); + if (db_map) { + gl_map_free (db_map); + db_map = 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 = false; + } + if (db_map) { + gl_map_free (db_map); + db_map = NULL; + } + + drop_effective_privs (); + + gl_list_free (section_list); + free_pathlist (manpathlist); + free (internal_locale); + sandbox_free (sandbox); + exit (exit_status); +} diff --git a/src/man_db.conf.in b/src/man_db.conf.in new file mode 100644 index 0000000..3bb8ebd --- /dev/null +++ b/src/man_db.conf.in @@ -0,0 +1,132 @@ +# @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 +MANDB_MAP @snapdir@/man /var/cache/man/snap +# +#--------------------------------------------------------- +# 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, 3type, 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..e775b1b --- /dev/null +++ b/src/manconv.c @@ -0,0 +1,570 @@ +/* + * 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 <assert.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#ifdef HAVE_ICONV +# include <iconv.h> +#endif /* HAVE_ICONV */ + +#include "argp.h" +#include "attribute.h" +#include "error.h" +#include "gl_list.h" +#include "xalloc.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "debug.h" +#include "fatal.h" +#include "glcontainers.h" + +#include "decompress.h" +#include "manconv.h" + +/* Encoding conversions from groff-1.20/src/preproc/preconv/preconv.cpp. + * I've only included those not already recognised by GNU libiconv. + */ +struct conversion_entry { + const char *from; + const char *to; +}; + +static struct conversion_entry conversion_table[] = { + { "chinese-big5", "Big5" }, + { "chinese-euc", "GB2312" }, + { "chinese-iso-8bit", "GB2312" }, + { "cn-gb-2312", "GB2312" }, + { "cp878", "KOI8-R" }, + { "cyrillic-iso-8bit", "ISO-8859-5" }, + { "cyrillic-koi8", "KOI8-R" }, + { "euc-china", "GB2312" }, + { "euc-japan", "EUC-JP" }, + { "euc-japan-1990", "EUC-JP" }, + { "euc-kr", "EUC-KR" }, + { "greek-iso-8bit", "ISO-8859-7" }, + { "iso-latin-1", "ISO-8859-1" }, + { "iso-latin-2", "ISO-8859-2" }, + { "iso-latin-5", "ISO-8859-9" }, + { "iso-latin-7", "ISO-8859-13" }, + { "iso-latin-9", "ISO-8859-15" }, + { "japanese-iso-8bit", "EUC-JP" }, + { "japanese-euc", "EUC-JP" }, + { "jis8", "EUC-JP" }, + { "korean-euc", "EUC-KR" }, + { "korean-iso-8bit", "EUC-KR" }, + { "latin-0", "ISO-8859-15" }, + { "latin-1", "ISO-8859-1" }, + { "latin-2", "ISO-8859-2" }, + { "latin-5", "ISO-8859-9" }, + { "latin-7", "ISO-8859-13" }, + { "mule-utf-16", "UTF-16" }, + { "mule-utf-16be", "UTF-16BE" }, + { "mule-utf-16-be", "UTF-16BE" }, + { "mule-utf-16be-with-signature", "UTF-16" }, + { "mule-utf-16le", "UTF-16LE" }, + { "mule-utf-16-le", "UTF-16LE" }, + { "mule-utf-16le-with-signature", "UTF-16" }, + { "mule-utf-8", "UTF-8" }, + { "utf-16-be", "UTF-16BE" }, + { "utf-16be-with-signature", "UTF-16" }, + { "utf-16-be-with-signature", "UTF-16" }, + { "utf-16-le", "UTF-16LE" }, + { "utf-16le-with-signature", "UTF-16" }, + { "utf-16-le-with-signature", "UTF-16" }, + { NULL, NULL } +}; + +/* Convert Emacs-style coding tags to ones that libiconv understands. */ +static char *convert_encoding (char *encoding) +{ + size_t encoding_len = strlen (encoding); + const struct conversion_entry *entry; + +#define STRIP(s, l) do { \ + if (encoding_len > (l) && \ + !strcasecmp (encoding + encoding_len - (l), (s))) \ + encoding[encoding_len - (l)] = '\0'; \ +} while (0) + + STRIP ("-dos", 4); + STRIP ("-mac", 4); + STRIP ("-unix", 5); + +#undef STRIP + + for (entry = conversion_table; entry->from; ++entry) + if (!strcasecmp (entry->from, encoding)) { + free (encoding); + return xstrdup (entry->to); + } + + return encoding; +} + +/* Inspect the first line of data from a decompressor for preprocessor + * encoding declarations. + * + * If to_encoding and modified_line are both non-NULL, and if the encoding + * declaration in the input does not match to_encoding, then return an + * encoding declaration line modified to refer to the given to_encoding in + * *modified_line. The caller should free *modified_line. + */ +char *check_preprocessor_encoding (decompress *decomp, const char *to_encoding, + char **modified_line) +{ + char *pp_encoding = NULL; + const char *line = decompress_peekline (decomp); + const char *directive = NULL, *directive_end = NULL, *pp_search = NULL; + size_t pp_encoding_len = 0; + + /* Some people use .\" incorrectly. We allow it for encoding + * declarations but not for preprocessor declarations. + */ + if (line && + (STRNEQ (line, PP_COOKIE, 4) || STRNEQ (line, ".\\\" ", 4))) { + const char *newline = strchr (line, '\n'); + + directive = line + 4; + directive_end = newline ? newline : strchr (directive, '\0'); + pp_search = memmem (directive, directive_end - directive, + "-*-", 3); + } + + if (directive && pp_search) { + pp_search += 3; + while (pp_search && pp_search < directive_end && *pp_search) { + while (*pp_search == ' ') + ++pp_search; + if (STRNEQ (pp_search, "coding:", 7)) { + const char *pp_encoding_allow; + pp_search += 7; + while (*pp_search == ' ') + ++pp_search; + pp_encoding_allow = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_/:.()"; + pp_encoding_len = strspn (pp_search, + pp_encoding_allow); + pp_encoding = xstrndup (pp_search, + pp_encoding_len); + pp_encoding = convert_encoding (pp_encoding); + debug ("preprocessor encoding: %s\n", + pp_encoding); + break; + } else { + pp_search = memchr (pp_search, ';', + directive_end - pp_search); + if (pp_search) + ++pp_search; + } + } + } + + if (to_encoding && modified_line && + pp_encoding && strcasecmp (pp_encoding, to_encoding)) { + assert (directive_end); + assert (pp_search); + *modified_line = xasprintf + ("%.*s%s%.*s\n", + (int) (pp_search - line), line, + to_encoding, + (int) (directive_end - (pp_search + pp_encoding_len)), + pp_search + pp_encoding_len); + } + + return pp_encoding; +} + +static int add_output (const char *inbuf, size_t inlen, + struct manconv_outbuf *outbuf) +{ + int ret = 0; + + if (outbuf) { + if (outbuf->len + inlen >= outbuf->max) + fatal (0, "out of space in output buffer"); + memcpy (outbuf->buf + outbuf->len, inbuf, inlen); + outbuf->len += inlen; + } else { + int errno_save = errno; + if (fwrite (inbuf, 1, inlen, stdout) < inlen || + ferror (stdout)) { + error (0, 0, _("can't write to standard output")); + ret = -1; + } + errno = errno_save; + } + + return ret; +} + +#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; +} + +typedef enum { + TRIED_ICONV_OK = 0, + TRIED_ICONV_ERROR = -1, /* can continue with another encoding */ + TRIED_ICONV_FATAL = -2 /* must give up */ +} tried_iconv; + +static tried_iconv try_iconv (decompress *decomp, const char *try_from_code, + const char *to, bool last, + struct manconv_outbuf *outbuf) +{ + 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; + bool 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"; + bool ignore_errors = (strstr (try_to_code, "//IGNORE") != NULL); + tried_iconv ret = TRIED_ICONV_OK; + + 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 TRIED_ICONV_ERROR; + } + + 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 TRIED_ICONV_ERROR; + } + } + + input = decompress_peek (decomp, &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 = decompress_peek (decomp, &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, *outptr; + 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 = TRIED_ICONV_ERROR; + 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. + */ + outptr = output; + else if (to_utf8) { + memcpy (output, utf8, utf8left); + outptr = output + 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. */ + if (add_output (output, outleft, outbuf) != 0) { + ret = TRIED_ICONV_FATAL; + goto out; + } + } + + 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. */ + if (add_output (output, outleft, + outbuf) != 0) { + ret = TRIED_ICONV_FATAL; + goto out; + } + } + } 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); + } + ret = TRIED_ICONV_FATAL; + goto out; + } 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 (0, 0, "byte %jd: %s", error_pos, + _("iconv: incomplete character " + "at end of buffer")); + } + ret = TRIED_ICONV_FATAL; + goto out; + } + } + + if (inptr != input) { + decompress_peek_skip (decomp, 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 = decompress_peek (decomp, &input_size); + while (input_size < buf_size) { + size_t old_input_size = input_size; + input_size = buf_size; + input = decompress_peek (decomp, &input_size); + if (input_size == old_input_size) + break; + } + } + } + +out: + if (!to_utf8) + iconv_close (cd); + iconv_close (cd_utf8); + free (try_to_code); + + return ret; +} + +int manconv (decompress *decomp, gl_list_t from, const char *to, + struct manconv_outbuf *outbuf) +{ + char *pp_encoding; + const char *try_from_code; + char *plain_to, *modified_pp_line = NULL; + tried_iconv tried; + int ret = 0; + + plain_to = xstrndup (to, strcspn (to, "/")); + pp_encoding = check_preprocessor_encoding + (decomp, plain_to, &modified_pp_line); + if (pp_encoding) { + if (modified_pp_line) { + size_t len = strlen (modified_pp_line); + decompress_readline (decomp); + if (add_output (modified_pp_line, len, outbuf) != 0) { + ret = -1; + goto out; + } + } + tried = try_iconv (decomp, pp_encoding, to, 1, outbuf); + if (tried == TRIED_ICONV_FATAL) + ret = -1; + } else { + GL_LIST_FOREACH (from, try_from_code) { + bool last = !gl_list_next_node (from, from_node); + tried = try_iconv (decomp, try_from_code, to, last, + outbuf); + if (tried == TRIED_ICONV_OK) + break; + else if (tried == TRIED_ICONV_FATAL) { + ret = -1; + goto out; + } + } + } + +out: + free (modified_pp_line); + free (pp_encoding); + free (plain_to); + return ret; +} + +#else /* !HAVE_ICONV */ + +/* If we don't have iconv, there isn't much we can do; just pass everything + * through unchanged. + */ +int manconv (decompress *decomp, gl_list_t from MAYBE_UNUSED, + const char *to MAYBE_UNUSED, struct manconv_outbuf *outbuf) +{ + for (;;) { + size_t len = 4096; + const char *buffer = decompress_read (decomp, &len); + if (len == 0) + break; + if (add_output (buffer, len, outbuf) != 0) + return -1; + } + return 0; +} + +#endif /* HAVE_ICONV */ diff --git a/src/manconv.h b/src/manconv.h new file mode 100644 index 0000000..8ac261e --- /dev/null +++ b/src/manconv.h @@ -0,0 +1,35 @@ +/* + * 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 + */ + +#include "gl_list.h" + +#include "decompress.h" + +struct manconv_outbuf { + char *buf; + size_t len, max; +}; + +char *check_preprocessor_encoding (decompress *decomp, const char *to_code, + char **modified_line); +int manconv (decompress *decomp, gl_list_t from, const char *to, + struct manconv_outbuf *outbuf); diff --git a/src/manconv_client.c b/src/manconv_client.c new file mode 100644 index 0000000..7cdb1b8 --- /dev/null +++ b/src/manconv_client.c @@ -0,0 +1,218 @@ +/* + * 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 "gl_array_list.h" +#include "gl_xlist.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "pipeline.h" + +#include "appendstr.h" +#include "glcontainers.h" +#include "sandbox.h" +#include "security.h" + +#include "decompress.h" +#include "manconv.h" +#include "manconv_client.h" +#include "utf8.h" + +extern man_sandbox *sandbox; + +struct manconv_codes { + gl_list_t from; + char *to; +}; + +static void manconv_stdin (void *data) +{ + struct manconv_codes *codes = data; + decompress *decomp; + + decomp = decompress_fdopen (dup (STDIN_FILENO)); + decompress_start (decomp); + if (manconv (decomp, codes->from, codes->to, NULL) != 0) + /* manconv already wrote an error message to stderr. Just + * exit non-zero. + */ + exit (FATAL); + decompress_wait (decomp); + decompress_free (decomp); +} + +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; + + gl_list_free (codes->from); + free (codes->to); + free (codes); +} + +void add_manconv (pipeline *p, + const char *source_encoding, const char *target_encoding) +{ + struct manconv_codes *codes; + char *name; + pipecmd *cmd; + + if (STREQ (source_encoding, target_encoding)) + return; + + codes = xmalloc (sizeof *codes); + /* informational only; no shell quoting concerns */ + name = xasprintf ("%s -f ", MANCONV); + codes->from = new_string_list (GL_ARRAY_LIST, true); + if (STREQ (source_encoding, "UTF-8")) { + gl_list_add_last (codes->from, xstrdup (source_encoding)); + name = appendstr (name, source_encoding, (void *) 0); + } else { + gl_list_add_last (codes->from, xstrdup ("UTF-8")); + gl_list_add_last (codes->from, xstrdup (source_encoding)); + name = appendstr (name, "UTF-8:", source_encoding, (void *) 0); + } + codes->to = xasprintf ("%s//IGNORE", target_encoding); + /* 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 ()) { + gl_list_t from = codes->from; + const char *from_code; + char *sources = NULL; + + cmd = pipecmd_new_args (MANCONV, "-f", (void *) 0); + GL_LIST_FOREACH (from, from_code) { + sources = appendstr (sources, from_code, (void *) 0); + if (gl_list_next_node (from, from_node)) + 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); +} + +/* Convert the result of in-process decompression to a target encoding. + * + * This converts the buffered result of decompression to a new buffer, then + * replaces the decompress object's buffer with the converted one for use by + * later stages of processing. + * + * Returns zero on success or non-zero on failure. + */ +int manconv_inprocess (decompress *d, + const char *source_encoding, + const char *target_encoding) +{ + gl_list_t from; + char *to; + struct manconv_outbuf outbuf; + int ret = 0; + + if (STREQ (source_encoding, target_encoding)) + return 0; + + from = new_string_list (GL_ARRAY_LIST, true); + if (STREQ (source_encoding, "UTF-8")) + gl_list_add_last (from, xstrdup (source_encoding)); + else { + if (STREQ (target_encoding, "UTF-8")) { + /* If the target encoding is UTF-8, then instead of + * starting with trial conversion from UTF-8 to + * UTF-8, we can start by simply performing UTF-8 + * validation, avoiding a copy. (The source + * encoding cannot be UTF-8 in this case, since we + * already checked that the source and target + * encodings are different.) + */ + if (utf8_validate_len (decompress_inprocess_buf (d), + decompress_inprocess_len (d))) + goto out; + } else + gl_list_add_last (from, xstrdup ("UTF-8")); + gl_list_add_last (from, xstrdup (source_encoding)); + } + to = xasprintf ("%s//IGNORE", target_encoding); + + outbuf.len = 0; + /* UTF-8 uses at most four bytes per Unicode code point. We assume + * that this conversion will be no worse than 1:4. + */ + outbuf.max = decompress_inprocess_len (d) * 4; + outbuf.buf = xmalloc (outbuf.max); + + if (manconv (d, from, to, &outbuf) == 0) + decompress_inprocess_replace (d, outbuf.buf, outbuf.len); + else { + /* manconv already wrote an error message to stderr. Just + * return non-zero. + */ + free (outbuf.buf); + ret = -1; + } + + free (to); +out: + gl_list_free (from); + return ret; +} diff --git a/src/manconv_client.h b/src/manconv_client.h new file mode 100644 index 0000000..cd93db9 --- /dev/null +++ b/src/manconv_client.h @@ -0,0 +1,31 @@ +/* + * 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 + */ + +#include "pipeline.h" + +#include "decompress.h" + +void add_manconv (struct pipeline *p, + const char *source_encoding, const char *target_encoding); +int manconv_inprocess (decompress *d, + const char *source_encoding, + const char *target_encoding); diff --git a/src/manconv_main.c b/src/manconv_main.c new file mode 100644 index 0000000..e0d9972 --- /dev/null +++ b/src/manconv_main.c @@ -0,0 +1,209 @@ +/* + * 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 <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "argp.h" +#include "error.h" +#include "gl_array_list.h" +#include "gl_xlist.h" +#include "progname.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "debug.h" +#include "encodings.h" +#include "pipeline.h" +#include "glcontainers.h" +#include "sandbox.h" +#include "util.h" + +#include "decompress.h" +#include "manconv.h" + +int quiet = 0; +man_sandbox *sandbox; + +static const char *from_codes; +static char *to_code; +static gl_list_t from_code; +static const char *filename; + +static gl_list_t split_codes (const char *codestr) +{ + char *codestrtok, *codestrtok_ptr; + char *tok; + gl_list_t codelist = new_string_list (GL_ARRAY_LIST, true); + + if (!codestr) + return codelist; + + codestrtok = xstrdup (codestr); + codestrtok_ptr = codestrtok; + + for (tok = strsep (&codestrtok_ptr, ":"); tok; + tok = strsep (&codestrtok_ptr, ":")) { + if (!*tok) + continue; /* ignore empty fields */ + gl_list_add_last (codelist, xstrdup (tok)); + } + + free (codestrtok); + + return codelist; +} + +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[] = { + OPT ("from-code", 'f', N_("CODE[:...]"), + N_("possible encodings of original text")), + OPT ("to-code", 't', N_("CODE"), N_("encoding for output")), + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("quiet", 'q', 0, N_("produce fewer warnings")), + OPT_HELP_COMPAT, + { 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 = true; + 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 (!to_code) + argp_error (state, + _("must specify an output " + "encoding")); + from_code = split_codes (from_codes); + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { options, parse_opt, args_doc }; + +int main (int argc, char *argv[]) +{ + decompress *decomp; + + 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); + assert (from_code); + + if (filename) { + decomp = decompress_open (filename, 0); + if (!decomp) + error (FAIL, 0, _("can't open %s"), filename); + } else + decomp = decompress_fdopen (dup (STDIN_FILENO)); + decompress_start (decomp); + + if (!gl_list_size (from_code)) { + char *lang, *page_encoding; + + /* Note that we don't need to explicitly check the page's + * preprocessor encoding here, as the manconv function will + * do that itself and override the requested input encoding + * with it if it finds one. + */ + lang = lang_dir (filename); + page_encoding = get_page_encoding (lang); + if (STREQ (page_encoding, "UTF-8")) { + /* Steal memory. */ + gl_list_add_last (from_code, page_encoding); + debug ("guessed input encoding %s for %s\n", + page_encoding, filename); + } else { + gl_list_add_last (from_code, xstrdup ("UTF-8")); + /* Steal memory. */ + gl_list_add_last (from_code, page_encoding); + debug ("guessed input encodings UTF-8:%s for %s\n", + page_encoding, filename); + } + + free (lang); + } + + if (manconv (decomp, from_code, to_code, NULL) != 0) + /* manconv already wrote an error message to stderr. Just + * exit non-zero. + */ + exit (FATAL); + + free (to_code); + gl_list_free (from_code); + + decompress_wait (decomp); + + sandbox_free (sandbox); + + return 0; +} diff --git a/src/mandb.c b/src/mandb.c new file mode 100644 index 0000000..e62085e --- /dev/null +++ b/src/mandb.c @@ -0,0 +1,1027 @@ +/* + * 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 <stdbool.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 "error.h" +#include "gl_hash_map.h" +#include "gl_list.h" +#include "gl_xmap.h" +#include "progname.h" +#include "stat-time.h" +#include "timespec.h" +#include "utimens.h" +#include "xalloc.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "debug.h" +#include "filenames.h" +#include "glcontainers.h" +#include "pipeline.h" +#include "sandbox.h" +#include "security.h" +#include "util.h" + +#include "db_storage.h" +#include "mydbm.h" + +#include "check_mandirs.h" +#include "manp.h" +#include "straycats.h" + +int quiet = 1; +extern bool opt_test; /* don't update db */ +char *manp; +extern char *extension; /* for globbing.c */ +extern bool 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 bool check_for_strays = true; +static bool purge = true; +static bool user; +static bool create; +static const char *arg_manp; + +struct tried_catdirs_entry { + char *manpath; + bool 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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("quiet", 'q', 0, N_("work quietly, except for 'bogus' warning")), + OPT ("no-straycats", 's', 0, + N_("don't look for or add stray cats to the dbs")), + OPT ("no-purge", 'p', 0, + N_("don't purge obsolete entries from the dbs")), + OPT ("user-db", 'u', 0, N_("produce user databases only")), + OPT ("create", 'c', 0, + N_("create dbs from scratch, rather than updating")), + OPT ("test", 't', 0, N_("check manual pages for correctness")), + OPT ("filename", 'f', N_("FILENAME"), + N_("update just the entry for this filename")), + OPT ("config-file", 'C', N_("FILE"), + N_("use this user configuration file")), + OPT_HELP_COMPAT, + { 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 = true; + return 0; + case 'q': + ++quiet_temp; + return 0; + case 's': + check_for_strays = false; + return 0; + case 'p': + purge = false; + return 0; + case 'u': + user = true; + return 0; + case 'c': + create = true; + purge = false; + return 0; + case 't': + opt_test = true; + return 0; + case 'f': + single_filename = arg; + create = false; + purge = false; + check_for_strays = false; + 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 gl_list_t manpathlist; + +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; +} + +static void dbpaths_init (struct dbpaths *dbpaths, + const char *base, const char *tmpbase) +{ +#ifdef NDBM +# ifdef BERKELEY_DB + dbpaths->dbfile = xasprintf ("%s.db", base); + dbpaths->tmpdbfile = xasprintf ("%s.db", tmpbase); +# else /* !BERKELEY_DB NDBM */ + dbpaths->dirfile = xasprintf ("%s.dir", base); + dbpaths->pagfile = xasprintf ("%s.pag", base); + dbpaths->tmpdirfile = xasprintf ("%s.dir", tmpbase); + dbpaths->tmppagfile = xasprintf ("%s.pag", tmpbase); +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + dbpaths->xfile = xstrdup (base); + dbpaths->xtmpfile = xstrdup (tmpbase); +#endif /* NDBM */ +} + +static int dbpaths_copy_to_tmp (struct dbpaths *dbpaths) +{ +#ifdef NDBM +# ifdef BERKELEY_DB + return xcopy (dbpaths->dbfile, dbpaths->tmpdbfile); +# else /* !BERKELEY_DB NDBM */ + int ret = xcopy (dbpaths->dirfile, dbpaths->tmpdirfile); + if (ret < 0) + return ret; + return xcopy (dbpaths->pagfile, dbpaths->tmppagfile); +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + return xcopy (dbpaths->xfile, dbpaths->xtmpfile); +#endif /* NDBM */ +} + +static void dbpaths_remove_tmp (struct dbpaths *dbpaths) +{ +#ifdef NDBM +# ifdef BERKELEY_DB + check_remove (dbpaths->tmpdbfile); +# else /* !BERKELEY_DB NDBM */ + check_remove (dbpaths->tmpdirfile); + check_remove (dbpaths->tmppagfile); +# endif /* BERKELEY_DB NDBM */ +#else /* !NDBM */ + check_remove (dbpaths->xtmpfile); +#endif /* NDBM */ +} + +static void dbpaths_rename_from_tmp (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 dbpaths_chown_if_possible (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 */ + +/* Remove incomplete databases. This is async-signal-safe. */ +static void dbpaths_unlink_tmp (struct dbpaths *dbpaths) +{ +#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 */ +} + +static void dbpaths_free_elements (struct dbpaths *dbpaths) +{ +#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 */ +} + +/* Reorganize a database by reading in all the items (assuming that the + * database layer provides them in sorted order) and writing them back out. + * This has the effect of giving the underlying database the best chance to + * produce deterministic output files based only on the set of items and not + * on their insertion order, although we may not be able to guarantee that + * for all database types. + */ +static void reorganize (const char *catpath, bool global_manpath MAYBE_UNUSED) +{ + char *dbname, *tmpdbname; + struct dbpaths *dbpaths; + MYDBM_FILE dbf, tmpdbf; + datum key; + + dbname = mkdbname (catpath); + tmpdbname = xasprintf ("%s/%d", catpath, getpid ()); + dbpaths = XZALLOC (struct dbpaths); + dbpaths_init (dbpaths, dbname, tmpdbname); + dbf = MYDBM_NEW (dbname); + tmpdbf = MYDBM_NEW (tmpdbname); + if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) { + debug ("Failed to open %s read-only\n", dbname); + goto out; + } + if (!MYDBM_CTRWOPEN (tmpdbf)) { + debug ("Failed to create %s\n", tmpdbname); + goto out; + } + + key = MYDBM_FIRSTKEY (dbf); + while (MYDBM_DPTR (key)) { + datum content, nextkey; + int insert_status; + + content = MYDBM_FETCH (dbf, key); + insert_status = MYDBM_INSERT (tmpdbf, key, content); + MYDBM_FREE_DPTR (content); + if (insert_status != 0) { + MYDBM_FREE_DPTR (key); + goto out; + } + nextkey = MYDBM_NEXTKEY (dbf, key); + MYDBM_FREE_DPTR (key); + key = nextkey; + } + + dbpaths_rename_from_tmp (dbpaths); +#ifdef MAN_OWNER + if (global_manpath) + dbpaths_chown_if_possible (dbpaths); +#endif /* MAN_OWNER */ + +out: + MYDBM_FREE (tmpdbf); + MYDBM_FREE (dbf); + dbpaths_unlink_tmp (dbpaths); + dbpaths_free_elements (dbpaths); + free (dbpaths); + free (tmpdbname); + free (dbname); +} + +/* Update a single file in an existing database. */ +static int update_one_file (MYDBM_FILE dbf, + const char *manpath, const char *filename) +{ + if (dbf->file || MYDBM_RWOPEN (dbf)) { + struct mandata *info; + + info = filename_info (filename, quiet < 2); + if (info) { + dbdelete (dbf, info->name, info); + purge_pointers (dbf, info->name); + } + free_mandata_struct (info); + + test_manfile (dbf, filename, manpath); + } + + return 1; +} + +/* dont actually create any dbs, just do an update */ +static int update_db_wrapper (MYDBM_FILE dbf, + const char *manpath, const char *catpath) +{ + int amount; + + if (single_filename) + return update_one_file (dbf, manpath, single_filename); + + amount = update_db (dbf, manpath, catpath); + if (amount >= 0) + return amount; + + return create_db (dbf, manpath, catpath); +} + +#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, + bool global_manpath) +{ + char *database; + int amount; + char *dbname; + MYDBM_FILE dbf; + bool should_create; + + dbname = mkdbname (catpath); + database = xasprintf ("%s/%d", catpath, getpid ()); + dbf = MYDBM_NEW (database); + + if (!STREQ (catpath, manpath)) { + char *cachedir_tag; + int fd; + bool cachedir_tag_exists = false; + + cachedir_tag = xasprintf ("%s/CACHEDIR.TAG", catpath); + assert (cachedir_tag); + 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 = true; + fputs (CACHEDIR_TAG, cachedir_tag_file); + fclose (cachedir_tag_file); + } + } else { + cachedir_tag_exists = true; + 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 || opt_test); + + dbpaths_init (dbpaths, dbname, database); + if (!should_create && dbpaths_copy_to_tmp (dbpaths) < 0) + should_create = true; + if (should_create) + dbpaths_remove_tmp (dbpaths); + + if (!should_create) { + force_rescan = false; + if (purge) + purged += purge_missing (dbf, manpath, catpath); + + if (force_rescan) { + /* We have an existing database and hadn't been + * going to recreate it, but purge_missing has + * discovered some kind of consistency problem and + * requested that we do so anyway. Close the + * database and remove temporary copies so that we + * start from scratch. + */ + MYDBM_FREE (dbf); + dbpaths_remove_tmp (dbpaths); + dbf = MYDBM_NEW (database); + should_create = true; + } + } + + if (!quiet) + printf (_("Processing manual pages under %s...\n"), manpath); + + if (should_create) + amount = create_db (dbf, manpath, catpath); + else + amount = update_db_wrapper (dbf, manpath, catpath); + + if (check_for_strays && dbf->file) + strays += straycats (dbf, manpath); + + MYDBM_FREE (dbf); + free (database); + free (dbname); + return amount; +} + +static int process_manpath (const char *manpath, bool global_manpath, + gl_map_t tried_catdirs) +{ + char *catpath; + struct tried_catdirs_entry *tried; + struct stat st; + bool run_mandb = false; + struct dbpaths *dbpaths = NULL; + int amount = 0; + bool new_purged = false; + bool new_strays = false; + + 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 = false; + gl_map_put (tried_catdirs, xstrdup (catpath), tried); + + if (stat (manpath, &st) < 0 || !S_ISDIR (st.st_mode)) + goto out; + tried->seen = true; + + 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 = true; + free (manpath_prefix); + } else + run_mandb = true; + + dbpaths = XZALLOC (struct dbpaths); + push_cleanup ((cleanup_fun) dbpaths_free_elements, dbpaths, 0); + push_cleanup ((cleanup_fun) dbpaths_unlink_tmp, dbpaths, 1); + if (run_mandb) { + int purged_before = purged; + int strays_before = strays; + int ret = mandb (dbpaths, catpath, manpath, global_manpath); + if (ret < 0) { + amount = ret; + goto out; + } + amount += ret; + new_purged = purged != purged_before; + new_strays = strays != strays_before; + + if (!opt_test && (amount || new_purged || new_strays)) { + dbpaths_rename_from_tmp (dbpaths); +#ifdef MAN_OWNER + if (global_manpath) + dbpaths_chown_if_possible (dbpaths); +#endif /* MAN_OWNER */ + reorganize (catpath, global_manpath); + } + } + +out: + if (dbpaths) { + dbpaths_unlink_tmp (dbpaths); + pop_cleanup ((cleanup_fun) dbpaths_unlink_tmp, dbpaths); + dbpaths_free_elements (dbpaths); + pop_cleanup ((cleanup_fun) dbpaths_free_elements, dbpaths); + free (dbpaths); + } + + free (catpath); + + return amount; +} + +static bool 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 (const void *value) +{ + struct tried_catdirs_entry *tried = + (struct tried_catdirs_entry *) value; + + free (tried->manpath); + free (tried); +} + +static void purge_catdir (gl_map_t tried_catdirs, const char *path) +{ + struct stat st; + + if (stat (path, &st) == 0 && S_ISDIR (st.st_mode) && + !gl_map_get (tried_catdirs, path)) { + if (!quiet) + printf (_("Removing obsolete cat directory %s...\n"), + path); + remove_directory (path, true); + } +} + +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); + assert (mandir); + catdir = xasprintf ("%s/%s", catpath, ent->d_name); + assert (catdir); + + if (stat (mandir, &st) != 0 && errno == ENOENT) { + if (!quiet) + printf (_("Removing obsolete cat directory " + "%s...\n"), catdir); + remove_directory (catdir, true); + } + + 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 (gl_map_t tried_catdirs) +{ + const char *path; + struct tried_catdirs_entry *tried; + + GL_MAP_FOREACH (tried_catdirs, path, tried) { + 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; + const struct tried_catdirs_entry *subtried; + + 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); + + subtried = gl_map_get (tried_catdirs, subdirpath); + if (subtried && subtried->seen) { + debug ("Seen mandir for %s; not deleting\n", + subdirpath); + /* However, we may still need to purge cat* + * subdirectories. + */ + purge_catsubdirs (subtried->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; + gl_map_t tried_catdirs; + struct sigaction sa; + +#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 (); + + /* 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); + + 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 = true; +#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); + } + + /* get the manpath as a list of pointers */ + manpathlist = create_pathlist (manp); + + /* finished manpath processing, regain privs */ + regain_effective_privs (); + + tried_catdirs = new_string_map (GL_HASH_MAP, tried_catdirs_free); + + GL_LIST_FOREACH (manpathlist, mp) { + bool 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); + assert (subdirpath); + 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 (); + } + + purge_catdirs (tried_catdirs); + gl_map_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); + } + sandbox_free (sandbox); + exit (OK); +} diff --git a/src/manp.c b/src/manp.c new file mode 100644 index 0000000..174b292 --- /dev/null +++ b/src/manp.c @@ -0,0 +1,1369 @@ +/* + * 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 <stdbool.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 <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "attribute.h" +#include "canonicalize.h" +#include "error.h" +#include "gl_array_list.h" +#include "gl_linkedhash_list.h" +#include "gl_xlist.h" +#include "xalloc.h" +#include "xgetcwd.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "debug.h" +#include "fatal.h" +#include "glcontainers.h" +#include "security.h" +#include "util.h" + +#include "manp.h" +#include "globbing.h" + +enum config_flag { + MANDATORY, + MANPATH_MAP, + MANDB_MAP, + MANDB_MAP_USER, + DEFINE, + DEFINE_USER, + SECTION, + SECTION_USER +}; + +struct config_item { + char *key; + char *cont; + enum config_flag flag; +}; + +static gl_list_t config; + +char *user_config_file = NULL; +bool disable_cache; +int min_cat_width = 80, max_cat_width = 80, cat_width = 0; + +static void add_man_subdirs (gl_list_t list, const char *p); +static char *fsstnd (const char *path); +static char *def_path (enum config_flag flag); +static void add_dir_to_list (gl_list_t list, const char *dir); +static void add_dir_to_path_list (gl_list_t list, const char *p); + + +static void config_item_free (const void *elt) +{ + /* gl_list declares the argument as const, but there doesn't seem to + * be a good reason for this. + */ + struct config_item *item = (struct config_item *) elt; + free (item->key); + free (item->cont); + free (item); +} + +static void add_config (const char *key, const char *cont, + enum config_flag flag) +{ + struct config_item *item = XMALLOC (struct config_item); + item->key = xstrdup (key); + item->cont = xstrdup (cont); + item->flag = flag; + gl_list_add_last (config, item); +} + +static const char * ATTRIBUTE_PURE get_config (const char *key, + enum config_flag flag) +{ + const struct config_item *item; + char *cont = NULL; + + GL_LIST_FOREACH (config, item) + if (flag == item->flag && STREQ (key, item->key)) { + cont = item->cont; + break; + } + + return cont; +} + +/* 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 * ATTRIBUTE_PURE get_def (const char *thing, const char *def) +{ + const char *config_def; + + if (!running_setuid ()) + return get_def_user (thing, def); + + config_def = get_config (thing, DEFINE); + return config_def ? config_def : def; +} + +const char * ATTRIBUTE_PURE get_def_user (const char *thing, const char *def) +{ + const char *config_def = get_config (thing, DEFINE_USER); + if (!config_def) + config_def = get_config (thing, DEFINE); + return config_def ? config_def : def; +} + +static void add_sections (char *sections, bool user) +{ + char *section_list = xstrdup (sections); + char *sect; + bool first = true; + + debug (" Added sections: "); + for (sect = strtok (section_list, " "); sect; + sect = strtok (NULL, " ")) { + add_config (sect, "", user ? SECTION_USER : SECTION); + if (!first) + debug (", "); + debug ("`%s'", sect); + first = false; + } + debug (".\n"); + free (section_list); +} + +gl_list_t get_sections (void) +{ + const struct config_item *item; + int length_user = 0, length = 0; + gl_list_t sections; + enum config_flag flag; + + GL_LIST_FOREACH (config, item) { + if (item->flag == SECTION_USER) + length_user++; + else if (item->flag == SECTION) + length++; + } + sections = new_string_list (GL_ARRAY_LIST, true); + if (length_user) + flag = SECTION_USER; + else + flag = SECTION; + GL_LIST_FOREACH (config, item) + if (item->flag == flag) + gl_list_add_last (sections, xstrdup (item->key)); + return sections; +} + +static void add_def (const char *thing, const char *config_def, bool user) +{ + add_config (thing, 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_config (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, bool user) +{ + char *tmpcatdir; + + if (!mandir) + return; + + if (STREQ (catdir, "FSSTND")) + tmpcatdir = fsstnd (mandir); + else + tmpcatdir = xstrdup (catdir); + + if (!tmpcatdir) + return; + + add_config (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_config (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 (search > app_dedup && search[-1] != ':') + /* Ignore suffix matches. */ + ; + else 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); + assert (newapp); + 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); +} + +/* 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_config (path, MANDB_MAP_USER); + if (!catdir) + catdir = get_config (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, true); + } + 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 (false); + + 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_file, bool user) +{ + char *bp; + char *buf = NULL; + size_t n = 0; + char key[512], cont[512]; + int val; + int c; + + while (getline (&buf, &n, config_file) >= 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 = true; + 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, c == 2 ? cont : key, user); + else if ((c = sscanf (bp, "DEFINE %511s %511[^\n]", + key, cont)) > 0) + add_def (key, c == 2 ? cont : "", 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 MAYBE_UNUSED) +{ + gl_list_free (config); +} + +void read_config_file (bool optional) +{ + static bool done = false; + char *dotmanpath = NULL; + FILE *config_file; + + if (done) + return; + + config = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, + config_item_free, true); + 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_file = fopen (dotmanpath, "r"); + if (config_file != NULL) { + debug ("From the config file %s:\n", dotmanpath); + add_to_dirlist (config_file, true); + fclose (config_file); + } + free (dotmanpath); + } + + if (getenv ("MAN_TEST_DISABLE_SYSTEM_CONFIG") == NULL) { + config_file = fopen (CONFIG_FILE, "r"); + if (config_file == 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", CONFIG_FILE); + + add_to_dirlist (config_file, false); + fclose (config_file); + } + } + + done = true; +} + + +/* + * Construct the default manpath. This picks up mandatory manpaths + * only. + */ +static char *def_path (enum config_flag flag) +{ + char *manpath = NULL; + const struct config_item *item; + + GL_LIST_FOREACH (config, item) + if (item->flag == flag) { + gl_list_t expanded_dirs; + const char *expanded_dir; + + expanded_dirs = expand_path (item->key); + GL_LIST_FOREACH (expanded_dirs, expanded_dir) { + int status = is_directory (expanded_dir); + + if (status < 0) + gripe_stat_file (expanded_dir); + else if (status == 0 && !quiet) + error (0, 0, + _("warning: mandatory " + "directory %s doesn't exist"), + expanded_dir); + else if (status == 1) + manpath = pathappend (manpath, + expanded_dir); + } + gl_list_free (expanded_dirs); + } + + /* If we have complete config file failure... */ + if (!manpath) + return xstrdup ("/usr/man"); + + return manpath; +} + +/* + * 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, bool mandatory) +{ + gl_list_t tmplist; + const struct config_item *config_item; + int len; + char *tmppath; + char *p; + char *end; + char *manpathlist; + char *item; + + tmplist = new_string_list (GL_LINKEDHASH_LIST, false); + tmppath = xstrdup (path); + + for (end = p = tmppath; end; p = end + 1) { + bool manpath_map_found = false; + + 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 ("path directory %s ", p); + + /* If the directory we're working on has MANPATH_MAP entries + * in the config file, add them to the list. + */ + GL_LIST_FOREACH (config, config_item) { + if (MANPATH_MAP != config_item->flag || + !STREQ (p, config_item->key)) + continue; + if (!manpath_map_found) + debug ("is in the config file\n"); + manpath_map_found = true; + add_dir_to_list (tmplist, config_item->cont); + } + + /* The directory we're working on isn't in the config file. + See if it has ../man, man, ../share/man, or share/man + subdirectories. If so, and they haven't been added to + the list, do. */ + + if (!manpath_map_found) { + debug ("is not in the config file\n"); + add_man_subdirs (tmplist, p); + } + } + + free (tmppath); + + if (mandatory) { + debug ("adding mandatory man directories\n"); + + GL_LIST_FOREACH (config, config_item) { + if (config_item->flag == MANDATORY) + add_dir_to_list (tmplist, config_item->key); + } + } + + len = 0; + GL_LIST_FOREACH (tmplist, item) + len += strlen (item) + 1; + + if (!len) + /* No path elements in configuration file or with + * appropriate subdirectories. + */ + return xstrdup (""); + + manpathlist = xmalloc (len); + *manpathlist = '\0'; + + p = manpathlist; + GL_LIST_FOREACH (tmplist, item) { + len = strlen (item); + memcpy (p, item, len); + p += len; + *p++ = ':'; + } + + p[-1] = '\0'; + + gl_list_free (tmplist); + + return manpathlist; +} + +/* Add a directory to the manpath list if it isn't already there. */ +static void add_expanded_dir_to_list (gl_list_t list, const char *dir) +{ + int status; + + if (gl_list_search (list, dir)) + return; + + /* 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); + gl_list_add_last (list, xstrdup (dir)); + } +} + +/* + * Add a directory to the manpath list if it isn't already there, expanding + * wildcards. + */ +static void add_dir_to_list (gl_list_t list, const char *dir) +{ + gl_list_t expanded_dirs; + const char *expanded_dir; + + expanded_dirs = expand_path (dir); + GL_LIST_FOREACH (expanded_dirs, expanded_dir) + add_expanded_dir_to_list (list, expanded_dir); + gl_list_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, and add them to the + list if they do. */ +static void add_man_subdirs (gl_list_t list, 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) + add_dir_to_list (list, newpath); + free (newpath); + } + + newpath = xasprintf ("%s/man", path); + if (is_directory (newpath) == 1) + add_dir_to_list (list, newpath); + free (newpath); + + if (subdir) { + newpath = xasprintf ("%.*s/share/man", + (int) (subdir - path), path); + if (is_directory (newpath) == 1) + add_dir_to_list (list, newpath); + free (newpath); + } + + newpath = xasprintf ("%s/share/man", path); + if (is_directory (newpath) == 1) + add_dir_to_list (list, newpath); + free (newpath); +} + +struct canonicalized_path { + char *path; + char *canon_path; +}; + +static struct canonicalized_path *canonicalized_path_new (const char *path) +{ + char *canon_path; + struct canonicalized_path *cp = NULL; + + canon_path = canonicalize_file_name (path); + if (canon_path) { + cp = XMALLOC (struct canonicalized_path); + cp->path = xstrdup (path); + cp->canon_path = canon_path; /* steal memory */ + } + return cp; +} + +static bool ATTRIBUTE_PURE canonicalized_path_equals (const void *elt1, + const void *elt2) +{ + const struct canonicalized_path *cp1 = elt1, *cp2 = elt2; + return string_equals (cp1->canon_path, cp2->canon_path); +} + +static size_t ATTRIBUTE_PURE canonicalized_path_hash (const void *elt) +{ + const struct canonicalized_path *cp = elt; + return string_hash (cp->canon_path); +} + +static void canonicalized_path_free (const void *elt) +{ + /* gl_list declares the argument as const, but there doesn't seem to + * be a good reason for this. + */ + struct canonicalized_path *cp = (struct canonicalized_path *) elt; + free (cp->path); + free (cp->canon_path); + free (cp); +} + +static void add_dir_to_path_list (gl_list_t list, const char *p) +{ + gl_list_t expanded_dirs; + char *expanded_dir; + + expanded_dirs = expand_path (p); + GL_LIST_FOREACH (expanded_dirs, expanded_dir) { + int status = is_directory (expanded_dir); + + if (status < 0) + gripe_stat_file (expanded_dir); + else if (status == 0) + gripe_not_directory (expanded_dir); + else { + char *path; + struct canonicalized_path *cp; + + /* deal with relative paths */ + if (*expanded_dir != '/') { + char *cwd = xgetcwd (); + if (!cwd) + fatal (errno, + _("can't determine current directory")); + path = appendstr (cwd, "/", expanded_dir, + (void *) 0); + } else + path = xstrdup (expanded_dir); + + cp = canonicalized_path_new (path); + if (cp && !gl_list_search (list, cp)) { + debug ("adding %s to manpathlist\n", path); + gl_list_add_last (list, cp); + } else if (cp) + canonicalized_path_free (cp); + free (path); + } + } + gl_list_free (expanded_dirs); +} + +gl_list_t create_pathlist (const char *manp) +{ + gl_list_t canonicalized_list, list; + const char *p, *end; + const struct canonicalized_path *cp; + + /* Expand the manpath into a list of (path, canonicalized path) + * pairs for easier handling. add_dir_to_path_list only adds items + * if they do not have the same canonicalized path as an existing + * item, thereby eliminating duplicates due to symlinks. + * For each entry, add corresponding OVERRIDE_DIR if configured. + */ + + canonicalized_list = gl_list_create_empty + (GL_LINKEDHASH_LIST, canonicalized_path_equals, + canonicalized_path_hash, canonicalized_path_free, false); + for (p = manp;; p = end + 1) { + char *element; + + end = strchr (p, ':'); + element = end ? xstrndup (p, end - p) : xstrdup (p); + + if (*OVERRIDE_DIR) { + char *element_override = xasprintf + ("%s/%s", element, OVERRIDE_DIR); + add_dir_to_path_list + (canonicalized_list, element_override); + free (element_override); + } + + add_dir_to_path_list (canonicalized_list, element); + free (element); + + if (!end) + break; + } + + list = new_string_list (GL_ARRAY_LIST, false); + GL_LIST_FOREACH (canonicalized_list, cp) + gl_list_add_last (list, xstrdup (cp->path)); + + if (debug_level) { + debug ("final search path = "); + GL_LIST_FOREACH (list, p) { + if (!gl_list_previous_node (list, list_node)) + debug ("%s", p); + else + debug (":%s", p); + } + debug ("\n"); + } + + gl_list_free (canonicalized_list); + return list; +} + +void free_pathlist (gl_list_t list) +{ + gl_list_free (list); +} + +/* Routine to get list of named system and user manpaths (in reverse order). */ +char *get_mandb_manpath (void) +{ + char *manpath = NULL; + const struct config_item *item; + + GL_LIST_FOREACH (config, item) + if (item->flag == MANDB_MAP || item->flag == MANDB_MAP_USER) + manpath = pathappend (manpath, item->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) +{ + const struct config_item *item; + char *ret = NULL; + + GL_LIST_FOREACH (config, item) + if (((cattype & SYSTEM_CAT) && item->flag == MANDB_MAP) || + ((cattype & USER_CAT) && item->flag == MANDB_MAP_USER)) { + size_t manlen = strlen (item->key); + if (STRNEQ (name, item->key, manlen)) { + const char *suffix; + char *infix; + char *catpath = xstrdup (item->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) { + ret = appendstr (catpath, + name + manlen, + (void *) 0); + break; + } + + 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); + ret = catpath; + break; + } + } + + return ret; +} + +/* Check to see if the supplied man directory is a system-wide mandir. + * Obviously, user directories must not be included here. + */ +bool ATTRIBUTE_PURE is_global_mandir (const char *dir) +{ + const struct config_item *item; + bool ret = false; + + GL_LIST_FOREACH (config, item) + if (item->flag == MANDB_MAP && + STRNEQ (dir, item->key, strlen (item->key))) { + ret = true; + break; + } + + return ret; +} + +/* 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..195315d --- /dev/null +++ b/src/manp.h @@ -0,0 +1,51 @@ +/* + * 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 + */ + +#include <stdbool.h> + +#include "gl_list.h" + +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, bool mandatory); +extern gl_list_t create_pathlist (const char *manp); +extern void free_pathlist (gl_list_t list); +extern char *get_mandb_manpath (void); +extern char *get_catpath (const char *name, int cattype); +extern bool is_global_mandir (const char *dir); +extern void read_config_file (bool 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 gl_list_t get_sections (void); diff --git a/src/manpath.c b/src/manpath.c new file mode 100644 index 0000000..35ba5f7 --- /dev/null +++ b/src/manpath.c @@ -0,0 +1,139 @@ +/* + * 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 <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <limits.h> + +#include "argp.h" +#include "error.h" +#include "progname.h" + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "debug.h" +#include "util.h" + +#include "manp.h" + +int quiet = 0; + +static bool cat = false; +static bool global = false; +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[] = { + OPT ("catpath", 'c', 0, N_("show relative catpaths")), + OPT ("global", 'g', 0, N_("show the entire global manpath")), + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("quiet", 'q', 0, N_("produce fewer warnings")), + OPT ("config-file", 'C', N_("FILE"), + N_("use this user configuration file")), + OPT ("systems", 'm', N_("SYSTEM"), + N_("use manual pages from other systems")), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'c': + cat = true; + return 0; + case 'g': + global = true; + quiet = 1; + return 0; + case 'd': + debug_level = true; + 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..932230b --- /dev/null +++ b/src/straycats.c @@ -0,0 +1,362 @@ +/* + * 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 <assert.h> +#include <stdbool.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 "error.h" +#include "gl_array_list.h" +#include "gl_xlist.h" +#include "xalloc.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "appendstr.h" +#include "compression.h" +#include "debug.h" +#include "filenames.h" +#include "glcontainers.h" +#include "pipeline.h" +#include "decompress.h" +#include "encodings.h" +#include "orderfiles.h" +#include "sandbox.h" +#include "security.h" +#include "util.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "descriptions.h" +#include "lexgrog.h" +#include "manp.h" +#include "manconv_client.h" +#include "straycats.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; + gl_list_t names; + const char *name; + size_t lenman, lencat; + int strays = 0; + + cdir = opendir (catdir); + if (!cdir) { + error (0, errno, _("can't search directory %s"), catdir); + return 0; + } + + names = new_string_list (GL_ARRAY_LIST, false); + + while ((catlist = readdir (cdir)) != NULL) { + if (*catlist->d_name == '.' && + strlen (catlist->d_name) < (size_t) 3) + continue; + gl_list_add_last (names, xstrdup (catlist->d_name)); + } + closedir (cdir); + + order_files (catdir, &names); + + mandir = appendstr (mandir, "/", (void *) 0); + catdir = appendstr (catdir, "/", (void *) 0); + lenman = strlen (mandir); + lencat = strlen (catdir); + + GL_LIST_FOREACH (names, name) { + struct mandata *info; + char *ext, *section = NULL; + short found; + struct stat buf; + struct compression *comp; + + info = XZALLOC (struct mandata); + + *(mandir + lenman) = *(catdir + lencat) = '\0'; + mandir = appendstr (mandir, name, (void *) 0); + catdir = appendstr (catdir, name, (void *) 0); + + ext = strrchr (mandir, '.'); + if (!ext) { + if (quiet < 2) + error (0, 0, + _("warning: %s: " + "ignoring bogus filename"), + catdir); + goto next; + } else if (comp_info (ext, false)) { + *ext = '\0'; + info->comp = xstrdup (ext + 1); + } + + 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; + } + + /* + * 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; + else if ((comp = comp_file (mandir))) { + found = 1; + free (comp->stem); + } else + found = 0; + + if (!found) { + decompress *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 = xstrdup (ext); + + /* see if we already have it, before going any + further */ + mandir_base = base_name (mandir); + exists = dblookup_exact (dbf, mandir_base, info->ext, + true); + if (exists && + compare_ids (STRAY_CAT, exists->id, false) >= 0) + 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->sec = xstrdup (section); + info->id = STRAY_CAT; + info->filter = xstrdup ("-"); + info->mtime.tv_sec = 0; + info->mtime.tv_nsec = 0; + + drop_effective_privs (); + decomp = decompress_open (catdir, 0); + 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 (decompress_get_pipeline (decomp), + page_encoding, "UTF-8"); + free (page_encoding); + free (lang); + + col_cmd = pipecmd_new_argstr + (get_def_user ("col", PROG_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 (decompress_get_pipeline (decomp), + col_cmd); + + fullpath = canonicalize_file_name (catdir); + if (!fullpath) + gripe_canonicalize_failed (catdir); + else { + char *catdir_base; + + free (fullpath); + drop_effective_privs (); + decompress_start (decomp); + regain_effective_privs (); + + strays++; + + lg.type = CATPAGE; + catdir_base = base_name (catdir); + if (find_name_decompressed (decomp, + catdir_base, + &lg)) { + gl_list_t descs, trace; + strays++; + descs = parse_descriptions + (mandir_base, lg.whatis); + trace = new_string_list (GL_ARRAY_LIST, + true); + gl_list_add_last (trace, + xstrdup (catdir)); + store_descriptions (dbf, descs, info, + NULL, mandir_base, + trace); + gl_list_free (trace); + gl_list_free (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); + decompress_free (decomp); +next_exists: + free_mandata_struct (exists); + free (mandir_base); + } +next: + free (section); + free_mandata_struct (info); + } + gl_list_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 (MYDBM_FILE dbf, const char *manpath) +{ + char *catpath; + int strays; + + assert (dbf->file); + + 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); + + return strays; +} diff --git a/src/straycats.h b/src/straycats.h new file mode 100644 index 0000000..cb82f08 --- /dev/null +++ b/src/straycats.h @@ -0,0 +1,26 @@ +/* + * straycats.h: interface to finding and processing stray cat files + * + * Copyright (C) 1994, 1995 Graeme W. Wilford. (Wilf.) + * Copyright (C) 2001-2022 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 "mydbm.h" + +extern int straycats (MYDBM_FILE dbf, const char *manpath); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..3cadd2c --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,80 @@ +## Process this file with automake to produce Makefile.in +## +## Copyright (C) 2009-2019 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; \ + troff_is_groff=$(troff_is_groff); export troff_is_groff; +# Each test must use the configure-detected shell, not necessarily /bin/sh. +AM_LOG_FLAGS = $(SHELL) +ALL_TESTS = \ + lexgrog-backslash-dash-rhs \ + lexgrog-basic \ + lexgrog-multiple-whatis \ + man-deleted-directory \ + man-exact-section-matches \ + man-executable-page-on-path \ + man-invalid-db-entry \ + man-language-specific-requests \ + man-mandatory-manpath \ + man-missing-locales \ + man-override-dir \ + man-recode-in-place \ + man-recode-suffix \ + man-so-links-same-section \ + man-suffixed-extension \ + man-symlinks-with-matching-names \ + manconv-coding-tags \ + manconv-guess-from-encoding \ + manconv-incomplete-char-at-eof \ + manconv-odd-combinations \ + mandb-basic \ + mandb-bogus-symlink \ + mandb-cachedir-tag \ + mandb-empty-page \ + mandb-purge-updates-timestamp \ + mandb-regular-file-symlink-changes \ + mandb-symlink-beats-whatis-ref \ + mandb-symlink-target-timestamp \ + mandb-whatis-broken-link-changes \ + whatis-path-to-executable \ + zsoelim-so-includes +if !CROSS_COMPILING +TESTS = $(ALL_TESTS) +endif + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib \ + -I$(top_srcdir)/lib +AM_CFLAGS = $(WARN_CFLAGS) +check_PROGRAMS = fspause get-mtime + +fspause_SOURCES = fspause.c +fspause_LDADD = \ + $(top_builddir)/gl/lib/libgnu.la \ + $(LIB_NANOSLEEP) +get_mtime_SOURCES = get-mtime.c +get_mtime_LDADD = $(top_builddir)/lib/libman.la + +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..90d026c --- /dev/null +++ b/src/tests/Makefile.in @@ -0,0 +1,2556 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 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) get-mtime$(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-manual.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-snapdir.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/calloc.m4 \ + $(top_srcdir)/gl/m4/canonicalize.m4 \ + $(top_srcdir)/gl/m4/chdir-long.m4 $(top_srcdir)/gl/m4/chown.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/ctype_h.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/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/free.m4 \ + $(top_srcdir)/gl/m4/fstat.m4 $(top_srcdir)/gl/m4/fstatat.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/getrandom.m4 \ + $(top_srcdir)/gl/m4/gettext.m4 $(top_srcdir)/gl/m4/gettime.m4 \ + $(top_srcdir)/gl/m4/gettimeofday.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.m4 \ + $(top_srcdir)/gl/m4/inttypes_h.m4 $(top_srcdir)/gl/m4/ioctl.m4 \ + $(top_srcdir)/gl/m4/isblank.m4 \ + $(top_srcdir)/gl/m4/langinfo_h.m4 \ + $(top_srcdir)/gl/m4/largefile.m4 $(top_srcdir)/gl/m4/lchown.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/lock.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/manywarnings.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-slash.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/pipe.m4 \ + $(top_srcdir)/gl/m4/po.m4 $(top_srcdir)/gl/m4/printf.m4 \ + $(top_srcdir)/gl/m4/progtest.m4 $(top_srcdir)/gl/m4/pselect.m4 \ + $(top_srcdir)/gl/m4/pthread_rwlock_rdlock.m4 \ + $(top_srcdir)/gl/m4/pthread_sigmask.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/readlinkat.m4 \ + $(top_srcdir)/gl/m4/realloc.m4 \ + $(top_srcdir)/gl/m4/reallocarray.m4 \ + $(top_srcdir)/gl/m4/regex.m4 $(top_srcdir)/gl/m4/rename.m4 \ + $(top_srcdir)/gl/m4/renameat.m4 \ + $(top_srcdir)/gl/m4/rewinddir.m4 $(top_srcdir)/gl/m4/rmdir.m4 \ + $(top_srcdir)/gl/m4/save-cwd.m4 $(top_srcdir)/gl/m4/select.m4 \ + $(top_srcdir)/gl/m4/setenv.m4 \ + $(top_srcdir)/gl/m4/setlocale_null.m4 \ + $(top_srcdir)/gl/m4/sigaction.m4 \ + $(top_srcdir)/gl/m4/signal_h.m4 \ + $(top_srcdir)/gl/m4/signalblocking.m4 \ + $(top_srcdir)/gl/m4/sigpipe.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/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/stpcpy.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_random_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/termios_h.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/unlink.m4 \ + $(top_srcdir)/gl/m4/unlinkat.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/visibility.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/wmemchr.m4 $(top_srcdir)/gl/m4/wmempcpy.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)/gl/m4/year2038.m4 \ + $(top_srcdir)/gl/m4/zzgnulib.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_get_mtime_OBJECTS = get-mtime.$(OBJEXT) +get_mtime_OBJECTS = $(am_get_mtime_OBJECTS) +get_mtime_DEPENDENCIES = $(top_builddir)/lib/libman.la +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 ./$(DEPDIR)/get-mtime.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) $(get_mtime_SOURCES) +DIST_SOURCES = $(fspause_SOURCES) $(get_mtime_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)` +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` +AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)' +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@ +CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +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@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +FLOAT_H = @FLOAT_H@ +FNMATCH_H = @FNMATCH_H@ +GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ +GETOPT_H = @GETOPT_H@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GLOB_H = @GLOB_H@ +GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@ +GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@ +GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@ +GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@ +GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@ +GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@ +GL_GNULIB_ALPHASORT = @GL_GNULIB_ALPHASORT@ +GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@ +GL_GNULIB_BIND = @GL_GNULIB_BIND@ +GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@ +GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@ +GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@ +GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@ +GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@ +GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@ +GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@ +GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@ +GL_GNULIB_CLOSEDIR = @GL_GNULIB_CLOSEDIR@ +GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@ +GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@ +GL_GNULIB_CREAT = @GL_GNULIB_CREAT@ +GL_GNULIB_CTIME = @GL_GNULIB_CTIME@ +GL_GNULIB_DIRFD = @GL_GNULIB_DIRFD@ +GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@ +GL_GNULIB_DUP = @GL_GNULIB_DUP@ +GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@ +GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@ +GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@ +GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@ +GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@ +GL_GNULIB_EXECL = @GL_GNULIB_EXECL@ +GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@ +GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@ +GL_GNULIB_EXECV = @GL_GNULIB_EXECV@ +GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@ +GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@ +GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@ +GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@ +GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@ +GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@ +GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@ +GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@ +GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@ +GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@ +GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@ +GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@ +GL_GNULIB_FDOPENDIR = @GL_GNULIB_FDOPENDIR@ +GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@ +GL_GNULIB_FFS = @GL_GNULIB_FFS@ +GL_GNULIB_FFSL = @GL_GNULIB_FFSL@ +GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@ +GL_GNULIB_FGETC = @GL_GNULIB_FGETC@ +GL_GNULIB_FGETS = @GL_GNULIB_FGETS@ +GL_GNULIB_FLOCK = @GL_GNULIB_FLOCK@ +GL_GNULIB_FNMATCH = @GL_GNULIB_FNMATCH@ +GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@ +GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@ +GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@ +GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@ +GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@ +GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@ +GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@ +GL_GNULIB_FREAD = @GL_GNULIB_FREAD@ +GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@ +GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@ +GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@ +GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@ +GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@ +GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@ +GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@ +GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@ +GL_GNULIB_FTELL = @GL_GNULIB_FTELL@ +GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@ +GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@ +GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@ +GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@ +GL_GNULIB_GETC = @GL_GNULIB_GETC@ +GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@ +GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@ +GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@ +GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@ +GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@ +GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@ +GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@ +GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@ +GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@ +GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@ +GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@ +GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@ +GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@ +GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@ +GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@ +GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@ +GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@ +GL_GNULIB_GETRANDOM = @GL_GNULIB_GETRANDOM@ +GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@ +GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@ +GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@ +GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@ +GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@ +GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@ +GL_GNULIB_GLOB = @GL_GNULIB_GLOB@ +GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@ +GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@ +GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@ +GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@ +GL_GNULIB_IOCTL = @GL_GNULIB_IOCTL@ +GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@ +GL_GNULIB_ISBLANK = @GL_GNULIB_ISBLANK@ +GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@ +GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@ +GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@ +GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@ +GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@ +GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@ +GL_GNULIB_LINK = @GL_GNULIB_LINK@ +GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@ +GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@ +GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@ +GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@ +GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@ +GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@ +GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@ +GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@ +GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@ +GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@ +GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@ +GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@ +GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@ +GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@ +GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@ +GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@ +GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@ +GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@ +GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@ +GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@ +GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@ +GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@ +GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@ +GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@ +GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@ +GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@ +GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@ +GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@ +GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@ +GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@ +GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@ +GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@ +GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@ +GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@ +GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@ +GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@ +GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@ +GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@ +GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@ +GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@ +GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@ +GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@ +GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@ +GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@ +GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@ +GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@ +GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@ +GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@ +GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@ +GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@ +GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@ +GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@ +GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@ +GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@ +GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@ +GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@ +GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@ +GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@ +GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@ +GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@ +GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@ +GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@ +GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@ +GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@ +GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@ +GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@ +GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@ +GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@ +GL_GNULIB_MDA_UTIME = @GL_GNULIB_MDA_UTIME@ +GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@ +GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@ +GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@ +GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@ +GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@ +GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@ +GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@ +GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@ +GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@ +GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@ +GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@ +GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@ +GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@ +GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@ +GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@ +GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@ +GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@ +GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@ +GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@ +GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@ +GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@ +GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@ +GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@ +GL_GNULIB_OPEN = @GL_GNULIB_OPEN@ +GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@ +GL_GNULIB_OPENDIR = @GL_GNULIB_OPENDIR@ +GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@ +GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@ +GL_GNULIB_PERROR = @GL_GNULIB_PERROR@ +GL_GNULIB_PIPE = @GL_GNULIB_PIPE@ +GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@ +GL_GNULIB_POPEN = @GL_GNULIB_POPEN@ +GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@ +GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@ +GL_GNULIB_PREAD = @GL_GNULIB_PREAD@ +GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@ +GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@ +GL_GNULIB_PSELECT = @GL_GNULIB_PSELECT@ +GL_GNULIB_PTHREAD_SIGMASK = @GL_GNULIB_PTHREAD_SIGMASK@ +GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@ +GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@ +GL_GNULIB_PUTC = @GL_GNULIB_PUTC@ +GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@ +GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@ +GL_GNULIB_PUTS = @GL_GNULIB_PUTS@ +GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@ +GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@ +GL_GNULIB_RAISE = @GL_GNULIB_RAISE@ +GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@ +GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@ +GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@ +GL_GNULIB_READ = @GL_GNULIB_READ@ +GL_GNULIB_READDIR = @GL_GNULIB_READDIR@ +GL_GNULIB_READLINK = @GL_GNULIB_READLINK@ +GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@ +GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@ +GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@ +GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@ +GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@ +GL_GNULIB_RECV = @GL_GNULIB_RECV@ +GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@ +GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@ +GL_GNULIB_RENAME = @GL_GNULIB_RENAME@ +GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@ +GL_GNULIB_REWINDDIR = @GL_GNULIB_REWINDDIR@ +GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@ +GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@ +GL_GNULIB_SCANDIR = @GL_GNULIB_SCANDIR@ +GL_GNULIB_SCANF = @GL_GNULIB_SCANF@ +GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@ +GL_GNULIB_SELECT = @GL_GNULIB_SELECT@ +GL_GNULIB_SEND = @GL_GNULIB_SEND@ +GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@ +GL_GNULIB_SETENV = @GL_GNULIB_SETENV@ +GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@ +GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@ +GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@ +GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@ +GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@ +GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@ +GL_GNULIB_SIGACTION = @GL_GNULIB_SIGACTION@ +GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@ +GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@ +GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@ +GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@ +GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@ +GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@ +GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@ +GL_GNULIB_STAT = @GL_GNULIB_STAT@ +GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@ +GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@ +GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@ +GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@ +GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@ +GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@ +GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@ +GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@ +GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@ +GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@ +GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@ +GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@ +GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@ +GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@ +GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@ +GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@ +GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@ +GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@ +GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@ +GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@ +GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@ +GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@ +GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@ +GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@ +GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@ +GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@ +GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@ +GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@ +GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@ +GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@ +GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@ +GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@ +GL_GNULIB_TCGETSID = @GL_GNULIB_TCGETSID@ +GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@ +GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@ +GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@ +GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@ +GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@ +GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@ +GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@ +GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@ +GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@ +GL_GNULIB_TZSET = @GL_GNULIB_TZSET@ +GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@ +GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@ +GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@ +GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@ +GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@ +GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@ +GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@ +GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@ +GL_GNULIB_UTIME = @GL_GNULIB_UTIME@ +GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@ +GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@ +GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@ +GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@ +GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@ +GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@ +GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@ +GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@ +GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@ +GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@ +GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ +GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@ +GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@ +GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@ +GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@ +GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@ +GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@ +GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@ +GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@ +GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@ +GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@ +GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@ +GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@ +GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@ +GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@ +GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@ +GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@ +GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@ +GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@ +GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@ +GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@ +GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@ +GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@ +GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@ +GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@ +GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@ +GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@ +GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@ +GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@ +GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ +GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@ +GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@ +GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@ +GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@ +GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@ +GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@ +GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@ +GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@ +GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@ +GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ +GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@ +GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ +GREP = @GREP@ +HAVE_ACCEPT4 = @HAVE_ACCEPT4@ +HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@ +HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ +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_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@ +HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ +HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ +HAVE_DECL_ECVT = @HAVE_DECL_ECVT@ +HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ +HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@ +HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ +HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@ +HAVE_DECL_FCVT = @HAVE_DECL_FCVT@ +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_GCVT = @HAVE_DECL_GCVT@ +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_IMAXABS = @HAVE_DECL_IMAXABS@ +HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@ +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_STRTOIMAX = @HAVE_DECL_STRTOIMAX@ +HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ +HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@ +HAVE_DECL_TCGETSID = @HAVE_DECL_TCGETSID@ +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_WCSDUP = @HAVE_DECL_WCSDUP@ +HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ +HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ +HAVE_DIRENT_H = @HAVE_DIRENT_H@ +HAVE_DPRINTF = @HAVE_DPRINTF@ +HAVE_DUP3 = @HAVE_DUP3@ +HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ +HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ +HAVE_EXECVPE = @HAVE_EXECVPE@ +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_GETENTROPY = @HAVE_GETENTROPY@ +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_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ +HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ +HAVE_GETUMASK = @HAVE_GETUMASK@ +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_IMAXDIV_T = @HAVE_IMAXDIV_T@ +HAVE_INITSTATE = @HAVE_INITSTATE@ +HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ +HAVE_ISBLANK = @HAVE_ISBLANK@ +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_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_MBTOWC = @HAVE_MBTOWC@ +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_MEMALIGN = @HAVE_POSIX_MEMALIGN@ +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_SETSTATE = @HAVE_SETSTATE@ +HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@ +HAVE_SIGACTION = @HAVE_SIGACTION@ +HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@ +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_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@ +HAVE_STRINGS_H = @HAVE_STRINGS_H@ +HAVE_STRPBRK = @HAVE_STRPBRK@ +HAVE_STRPTIME = @HAVE_STRPTIME@ +HAVE_STRSEP = @HAVE_STRSEP@ +HAVE_STRTOD = @HAVE_STRTOD@ +HAVE_STRTOL = @HAVE_STRTOL@ +HAVE_STRTOLD = @HAVE_STRTOLD@ +HAVE_STRTOLL = @HAVE_STRTOLL@ +HAVE_STRTOUL = @HAVE_STRTOUL@ +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_RANDOM_H = @HAVE_SYS_RANDOM_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_TERMIOS_H = @HAVE_TERMIOS_H@ +HAVE_TIMEGM = @HAVE_TIMEGM@ +HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@ +HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@ +HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ +HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ +HAVE_UNISTD_H = @HAVE_UNISTD_H@ +HAVE_UNLINKAT = @HAVE_UNLINKAT@ +HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ +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_VISIBILITY = @HAVE_VISIBILITY@ +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_WMEMPCPY = @HAVE_WMEMPCPY@ +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@ +INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@ +INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@ +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@ +LIBMAN_EXPORT_LDFLAGS = @LIBMAN_EXPORT_LDFLAGS@ +LIBMULTITHREAD = @LIBMULTITHREAD@ +LIBOBJS = @LIBOBJS@ +LIBPMULTITHREAD = @LIBPMULTITHREAD@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSTDTHREAD = @LIBSTDTHREAD@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_GETLOGIN = @LIB_GETLOGIN@ +LIB_GETRANDOM = @LIB_GETRANDOM@ +LIB_HARD_LOCALE = @LIB_HARD_LOCALE@ +LIB_MBRTOWC = @LIB_MBRTOWC@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ +LIB_NL_LANGINFO = @LIB_NL_LANGINFO@ +LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ +LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ +LIB_SELECT = @LIB_SELECT@ +LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@ +LIMITS_H = @LIMITS_H@ +LINGUAS = @LINGUAS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ +LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@ +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@ +LTLIBTHREAD = @LTLIBTHREAD@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +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_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@ +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_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_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_RANDOM_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_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_TERMIOS_H = @NEXT_AS_FIRST_DIRECTIVE_TERMIOS_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_CTYPE_H = @NEXT_CTYPE_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_INTTYPES_H = @NEXT_INTTYPES_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_RANDOM_H = @NEXT_SYS_RANDOM_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_TERMIOS_H = @NEXT_TERMIOS_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@ +PRIPTR_PREFIX = @PRIPTR_PREFIX@ +PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +RANLIB = @RANLIB@ +REPLACE_ACCESS = @REPLACE_ACCESS@ +REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@ +REPLACE_BTOWC = @REPLACE_BTOWC@ +REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@ +REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@ +REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ +REPLACE_CHMOD = @REPLACE_CHMOD@ +REPLACE_CHOWN = @REPLACE_CHOWN@ +REPLACE_CLOSE = @REPLACE_CLOSE@ +REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ +REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@ +REPLACE_CREAT = @REPLACE_CREAT@ +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_EXECL = @REPLACE_EXECL@ +REPLACE_EXECLE = @REPLACE_EXECLE@ +REPLACE_EXECLP = @REPLACE_EXECLP@ +REPLACE_EXECV = @REPLACE_EXECV@ +REPLACE_EXECVE = @REPLACE_EXECVE@ +REPLACE_EXECVP = @REPLACE_EXECVP@ +REPLACE_EXECVPE = @REPLACE_EXECVPE@ +REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ +REPLACE_FCHMODAT = @REPLACE_FCHMODAT@ +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_FFSLL = @REPLACE_FFSLL@ +REPLACE_FNMATCH = @REPLACE_FNMATCH@ +REPLACE_FOPEN = @REPLACE_FOPEN@ +REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@ +REPLACE_FPRINTF = @REPLACE_FPRINTF@ +REPLACE_FPURGE = @REPLACE_FPURGE@ +REPLACE_FREE = @REPLACE_FREE@ +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_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@ +REPLACE_GETRANDOM = @REPLACE_GETRANDOM@ +REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ +REPLACE_GLOB = @REPLACE_GLOB@ +REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@ +REPLACE_GMTIME = @REPLACE_GMTIME@ +REPLACE_INITSTATE = @REPLACE_INITSTATE@ +REPLACE_IOCTL = @REPLACE_IOCTL@ +REPLACE_ISATTY = @REPLACE_ISATTY@ +REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ +REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ +REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@ +REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@ +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_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@ +REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@ +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_MKFIFOAT = @REPLACE_MKFIFOAT@ +REPLACE_MKNOD = @REPLACE_MKNOD@ +REPLACE_MKNODAT = @REPLACE_MKNODAT@ +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_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@ +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 = @REPLACE_RANDOM@ +REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ +REPLACE_READ = @REPLACE_READ@ +REPLACE_READLINK = @REPLACE_READLINK@ +REPLACE_READLINKAT = @REPLACE_READLINKAT@ +REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@ +REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@ +REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@ +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_SETSTATE = @REPLACE_SETSTATE@ +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_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@ +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_STRTOIMAX = @REPLACE_STRTOIMAX@ +REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ +REPLACE_STRTOL = @REPLACE_STRTOL@ +REPLACE_STRTOLD = @REPLACE_STRTOLD@ +REPLACE_STRTOLL = @REPLACE_STRTOLL@ +REPLACE_STRTOUL = @REPLACE_STRTOUL@ +REPLACE_STRTOULL = @REPLACE_STRTOULL@ +REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@ +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_WCSTOK = @REPLACE_WCSTOK@ +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@ +TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@ +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_RECODE = @TRANS_MAN_RECODE@ +TRANS_MAN_RECODE_UPPER = @TRANS_MAN_RECODE_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@ +UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@ +UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@ +UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ +UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ +UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@ +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@ +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@ +bzip2 = @bzip2@ +cache_top_owner = @cache_top_owner@ +cat = @cat@ +col = @col@ +compress = @compress@ +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_LIBOBJDEPS = @gl_LIBOBJDEPS@ +gl_LIBOBJS = @gl_LIBOBJS@ +gl_LTLIBOBJS = @gl_LTLIBOBJS@ +gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@ +gltests_LIBOBJS = @gltests_LIBOBJS@ +gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ +gltests_WITNESS = @gltests_WITNESS@ +grap = @grap@ +grep = @grep@ +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@ +snapdir = @snapdir@ +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@ +troff_as_troff_input = @troff_as_troff_input@ +troff_is_groff = @troff_is_groff@ +vgrind = @vgrind@ +xz = @xz@ +zstd = @zstd@ +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; \ + troff_is_groff=$(troff_is_groff); export troff_is_groff; + +# Each test must use the configure-detected shell, not necessarily /bin/sh. +AM_LOG_FLAGS = $(SHELL) +ALL_TESTS = \ + lexgrog-backslash-dash-rhs \ + lexgrog-basic \ + lexgrog-multiple-whatis \ + man-deleted-directory \ + man-exact-section-matches \ + man-executable-page-on-path \ + man-invalid-db-entry \ + man-language-specific-requests \ + man-mandatory-manpath \ + man-missing-locales \ + man-override-dir \ + man-recode-in-place \ + man-recode-suffix \ + man-so-links-same-section \ + man-suffixed-extension \ + man-symlinks-with-matching-names \ + manconv-coding-tags \ + manconv-guess-from-encoding \ + manconv-incomplete-char-at-eof \ + manconv-odd-combinations \ + mandb-basic \ + mandb-bogus-symlink \ + mandb-cachedir-tag \ + mandb-empty-page \ + mandb-purge-updates-timestamp \ + mandb-regular-file-symlink-changes \ + mandb-symlink-beats-whatis-ref \ + mandb-symlink-target-timestamp \ + mandb-whatis-broken-link-changes \ + whatis-path-to-executable \ + zsoelim-so-includes + +@CROSS_COMPILING_FALSE@TESTS = $(ALL_TESTS) +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/gl/lib \ + -I$(top_srcdir)/gl/lib \ + -I$(top_srcdir)/lib + +AM_CFLAGS = $(WARN_CFLAGS) +fspause_SOURCES = fspause.c +fspause_LDADD = \ + $(top_builddir)/gl/lib/libgnu.la \ + $(LIB_NANOSLEEP) + +get_mtime_SOURCES = get-mtime.c +get_mtime_LDADD = $(top_builddir)/lib/libman.la +dist_check_SCRIPTS = testlib.sh $(ALL_TESTS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: $(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: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(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) + +get-mtime$(EXEEXT): $(get_mtime_OBJECTS) $(get_mtime_DEPENDENCIES) $(EXTRA_get_mtime_DEPENDENCIES) + @rm -f get-mtime$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(get_mtime_OBJECTS) $(get_mtime_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 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get-mtime.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"$(AM_TESTSUITE_SUMMARY_HEADER)"$${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-backslash-dash-rhs.log: lexgrog-backslash-dash-rhs + @p='lexgrog-backslash-dash-rhs'; \ + b='lexgrog-backslash-dash-rhs'; \ + $(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-basic.log: lexgrog-basic + @p='lexgrog-basic'; \ + b='lexgrog-basic'; \ + $(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-multiple-whatis.log: lexgrog-multiple-whatis + @p='lexgrog-multiple-whatis'; \ + b='lexgrog-multiple-whatis'; \ + $(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-deleted-directory.log: man-deleted-directory + @p='man-deleted-directory'; \ + b='man-deleted-directory'; \ + $(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-exact-section-matches.log: man-exact-section-matches + @p='man-exact-section-matches'; \ + b='man-exact-section-matches'; \ + $(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-executable-page-on-path.log: man-executable-page-on-path + @p='man-executable-page-on-path'; \ + b='man-executable-page-on-path'; \ + $(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-invalid-db-entry.log: man-invalid-db-entry + @p='man-invalid-db-entry'; \ + b='man-invalid-db-entry'; \ + $(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-language-specific-requests.log: man-language-specific-requests + @p='man-language-specific-requests'; \ + b='man-language-specific-requests'; \ + $(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-mandatory-manpath.log: man-mandatory-manpath + @p='man-mandatory-manpath'; \ + b='man-mandatory-manpath'; \ + $(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-missing-locales.log: man-missing-locales + @p='man-missing-locales'; \ + b='man-missing-locales'; \ + $(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-override-dir.log: man-override-dir + @p='man-override-dir'; \ + b='man-override-dir'; \ + $(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-recode-in-place.log: man-recode-in-place + @p='man-recode-in-place'; \ + b='man-recode-in-place'; \ + $(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-recode-suffix.log: man-recode-suffix + @p='man-recode-suffix'; \ + b='man-recode-suffix'; \ + $(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-so-links-same-section.log: man-so-links-same-section + @p='man-so-links-same-section'; \ + b='man-so-links-same-section'; \ + $(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-suffixed-extension.log: man-suffixed-extension + @p='man-suffixed-extension'; \ + b='man-suffixed-extension'; \ + $(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-symlinks-with-matching-names.log: man-symlinks-with-matching-names + @p='man-symlinks-with-matching-names'; \ + b='man-symlinks-with-matching-names'; \ + $(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-coding-tags.log: manconv-coding-tags + @p='manconv-coding-tags'; \ + b='manconv-coding-tags'; \ + $(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-guess-from-encoding.log: manconv-guess-from-encoding + @p='manconv-guess-from-encoding'; \ + b='manconv-guess-from-encoding'; \ + $(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-incomplete-char-at-eof.log: manconv-incomplete-char-at-eof + @p='manconv-incomplete-char-at-eof'; \ + b='manconv-incomplete-char-at-eof'; \ + $(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-odd-combinations.log: manconv-odd-combinations + @p='manconv-odd-combinations'; \ + b='manconv-odd-combinations'; \ + $(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-basic.log: mandb-basic + @p='mandb-basic'; \ + b='mandb-basic'; \ + $(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-bogus-symlink.log: mandb-bogus-symlink + @p='mandb-bogus-symlink'; \ + b='mandb-bogus-symlink'; \ + $(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-cachedir-tag.log: mandb-cachedir-tag + @p='mandb-cachedir-tag'; \ + b='mandb-cachedir-tag'; \ + $(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-empty-page.log: mandb-empty-page + @p='mandb-empty-page'; \ + b='mandb-empty-page'; \ + $(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-purge-updates-timestamp.log: mandb-purge-updates-timestamp + @p='mandb-purge-updates-timestamp'; \ + b='mandb-purge-updates-timestamp'; \ + $(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-regular-file-symlink-changes.log: mandb-regular-file-symlink-changes + @p='mandb-regular-file-symlink-changes'; \ + b='mandb-regular-file-symlink-changes'; \ + $(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-symlink-beats-whatis-ref.log: mandb-symlink-beats-whatis-ref + @p='mandb-symlink-beats-whatis-ref'; \ + b='mandb-symlink-beats-whatis-ref'; \ + $(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-symlink-target-timestamp.log: mandb-symlink-target-timestamp + @p='mandb-symlink-target-timestamp'; \ + b='mandb-symlink-target-timestamp'; \ + $(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-whatis-broken-link-changes.log: mandb-whatis-broken-link-changes + @p='mandb-whatis-broken-link-changes'; \ + b='mandb-whatis-broken-link-changes'; \ + $(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-path-to-executable.log: whatis-path-to-executable + @p='whatis-path-to-executable'; \ + b='whatis-path-to-executable'; \ + $(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-so-includes.log: zsoelim-so-includes + @p='zsoelim-so-includes'; \ + b='zsoelim-so-includes'; \ + $(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 ./$(DEPDIR)/get-mtime.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 ./$(DEPDIR)/get-mtime.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..4f573c6 --- /dev/null +++ b/src/tests/fspause.c @@ -0,0 +1,113 @@ +/* + * 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 "attribute.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 MAYBE_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/get-mtime.c b/src/tests/get-mtime.c new file mode 100644 index 0000000..b23eb87 --- /dev/null +++ b/src/tests/get-mtime.c @@ -0,0 +1,75 @@ +/* + * get-mtime.c: get a file's modification time + * + * Copyright (C) 2022 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 <stdlib.h> + +#include "argp.h" +#include "progname.h" +#include "stat-time.h" + +#include "manconfig.h" + +#include "fatal.h" + +char *path; + +static const char args_doc[] = "PATH"; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case ARGP_KEY_ARG: + if (path) + argp_usage (state); + path = arg; + return 0; + case ARGP_KEY_NO_ARGS: + argp_usage (state); + break; + } + return ARGP_ERR_UNKNOWN; +} + +static struct argp argp = { NULL, parse_opt, args_doc }; + +int main (int argc, char **argv) +{ + struct stat st; + struct timespec ts; + + set_program_name (argv[0]); + + if (argp_parse (&argp, argc, argv, 0, 0, 0)) + exit (FAIL); + + if (lstat (path, &st) < 0) + fatal (errno, "can't lstat %s", path); + ts = get_stat_mtime (&st); + printf ("%ld.%09ld\n", (long) ts.tv_sec, ts.tv_nsec); + + exit (OK); +} diff --git a/src/tests/lexgrog-backslash-dash-rhs b/src/tests/lexgrog-backslash-dash-rhs new file mode 100644 index 0000000..3b5ddee --- /dev/null +++ b/src/tests/lexgrog-backslash-dash-rhs @@ -0,0 +1,22 @@ +#! /bin/sh + +# Test handling of \- in the right-hand side of a NAME section. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'multiple whatis definitions' \ + "$tmpdir/3.exp" "$tmpdir/3.out" + +finish diff --git a/src/tests/lexgrog-basic b/src/tests/lexgrog-basic new file mode 100755 index 0000000..b30048b --- /dev/null +++ b/src/tests/lexgrog-basic @@ -0,0 +1,19 @@ +#! /bin/sh + +# Basic lexgrog tests. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'simple lexgrog test' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/lexgrog-multiple-whatis b/src/tests/lexgrog-multiple-whatis new file mode 100755 index 0000000..bf66393 --- /dev/null +++ b/src/tests/lexgrog-multiple-whatis @@ -0,0 +1,28 @@ +#! /bin/sh + +# Test multiple whatis definitions. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'multiple whatis definitions' \ + "$tmpdir/2.exp" "$tmpdir/2.out" + +finish diff --git a/src/tests/man-deleted-directory b/src/tests/man-deleted-directory new file mode 100755 index 0000000..f2bad68 --- /dev/null +++ b/src/tests/man-deleted-directory @@ -0,0 +1,26 @@ +#! /bin/sh + +# Test that man can run from a deleted directory. +# https://bugs.debian.org/764384 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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" || exit 1 +rmdir "$abstmpdir/zombie" || \ + skip "can't remove current working directory on this system" +run $MAN -C "$abstmpdir/manpath.config" test >/dev/null +report 'run from deleted directory' "$?" + +finish diff --git a/src/tests/man-exact-section-matches b/src/tests/man-exact-section-matches new file mode 100755 index 0000000..783796e --- /dev/null +++ b/src/tests/man-exact-section-matches @@ -0,0 +1,41 @@ +#! /bin/sh + +# Test for: +# https://bugzilla.redhat.com/show_bug.cgi?id=684977 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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 3type 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_files_equal 'exact section matches win' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/man-executable-page-on-path b/src/tests/man-executable-page-on-path new file mode 100755 index 0000000..108e157 --- /dev/null +++ b/src/tests/man-executable-page-on-path @@ -0,0 +1,23 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/608490 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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 +report 'executable page on path' "$?" + +finish diff --git a/src/tests/man-invalid-db-entry b/src/tests/man-invalid-db-entry new file mode 100755 index 0000000..ef24716 --- /dev/null +++ b/src/tests/man-invalid-db-entry @@ -0,0 +1,31 @@ +#! /bin/sh + +# Test for invalid DB entry. +# https://bugzilla.redhat.com/show_bug.cgi?id=841431 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'invalid DB entry' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/man-language-specific-requests b/src/tests/man-language-specific-requests new file mode 100755 index 0000000..5051d50 --- /dev/null +++ b/src/tests/man-language-specific-requests @@ -0,0 +1,65 @@ +#! /bin/sh + +# Test additional language-specific requests for localized man pages. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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' + +: >"$tmpdir/1.exp" +# shellcheck disable=SC2154 +if [ "$troff_is_groff" = yes ]; then + cat >>"$tmpdir/1.exp" <<'EOF' +. mso xyzzy.tmac +.hla xyzzy +EOF +fi +cat >>"$tmpdir/1.exp" <<'EOF' +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_files_equal 'language-specific requests for localized man page' \ + "$tmpdir/1.exp" "$tmpdir/1.out" + +run $MAN -L xyzzy_foo.bar -C "$tmpdir/manpath.config" xyz |\ + grep 'xyz' >"$tmpdir/2.out" +expect_files_equal 'no language-specific requests for top-level man page' \ + "$tmpdir/2.exp" "$tmpdir/2.out" + +finish diff --git a/src/tests/man-mandatory-manpath b/src/tests/man-mandatory-manpath new file mode 100755 index 0000000..af76ff0 --- /dev/null +++ b/src/tests/man-mandatory-manpath @@ -0,0 +1,189 @@ +#! /bin/sh + +# Test for wildcards in MANDATORY_MANPATH in config file and in MANPATH. +# https://bugzilla.redhat.com/show_bug.cgi?id=677669 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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 system 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_files_equal \ + 'wildcards: -M option: without wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: -M option: without wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: -M option: with wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: -M option: with wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: -M option: with wildcards: check existing man page II' \ + "$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_files_equal \ + 'wildcards: MANPATH: without wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: MANPATH: without wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: MANPATH: with wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: MANPATH: with wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: MANPATH: with wildcards: check existing man page II' \ + "$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_files_equal \ + 'wildcards: MANDATORY_MANPATH: without wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: MANDATORY_MANPATH: without wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: MANDATORY_MANPATH: with wildcards: check missing man page' \ + "$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_files_equal \ + 'wildcards: MANDATORY_MANPATH: with wildcards: check existing man page' \ + "$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_files_equal \ + 'wildcards: MANDATORY_MANPATH: with wildcards: check existing man page II' \ + "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/man-missing-locales b/src/tests/man-missing-locales new file mode 100755 index 0000000..95819c0 --- /dev/null +++ b/src/tests/man-missing-locales @@ -0,0 +1,27 @@ +#! /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=.}" +# shellcheck source-path=SCRIPTDIR +. "$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 +report 'missing locales' "$?" + +finish diff --git a/src/tests/man-override-dir b/src/tests/man-override-dir new file mode 100755 index 0000000..dc47649 --- /dev/null +++ b/src/tests/man-override-dir @@ -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=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'testing override dir' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/man-recode-in-place b/src/tests/man-recode-in-place new file mode 100755 index 0000000..45c63ad --- /dev/null +++ b/src/tests/man-recode-in-place @@ -0,0 +1,47 @@ +#! /bin/sh + +# Test man-recode's --in-place behaviour. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MAN_RECODE=man-recode}" + +init + +cat >"$tmpdir/a.1.exp" <<'EOF' +.SH NAME +a \- á +EOF +cp "$tmpdir/a.1.exp" "$tmpdir/a.1" +cat >"$tmpdir/b.1.exp" <<'EOF' +'\" -*- coding: UTF-8 -*- +.SH NAME +b \- é +EOF +gzip -c <"$tmpdir/b.1.exp" >"$tmpdir/b.1.gz" +cat >"$tmpdir/c.1.exp" <<'EOF' +'\" -*- coding: UTF-8 +.SH NAME +b \- é +EOF +cat >"$tmpdir/c.1" <<'EOF' +'\" -*- coding: ISO-8859-1 +EOF +<"$tmpdir/c.1.exp" tail -n +2 | iconv -f UTF-8 -t ISO-8859-1 >>"$tmpdir/c.1" +gzip "$tmpdir/c.1" + +run $MAN_RECODE -t UTF-8 --in-place \ + "$tmpdir/a.1" "$tmpdir/b.1.gz" "$tmpdir/c.1.gz" +expect_files_equal '--in-place with no coding tag' \ + "$tmpdir/a.1.exp" "$tmpdir/a.1" +expect_files_equal '--in-place with gzip and coding tag matching target encoding' \ + "$tmpdir/b.1.exp" "$tmpdir/b.1" +expect_files_equal \ + '--in-place with gzip and coding tag not matching target encoding' \ + "$tmpdir/c.1.exp" "$tmpdir/c.1" +test ! -f "$tmpdir/b.1.gz" && test ! -f "$tmpdir/c.1.gz" +report '--in-place removes compressed input files' "$?" + +finish diff --git a/src/tests/man-recode-suffix b/src/tests/man-recode-suffix new file mode 100755 index 0000000..7c0a32c --- /dev/null +++ b/src/tests/man-recode-suffix @@ -0,0 +1,46 @@ +#! /bin/sh + +# Test man-recode's --suffix behaviour. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MAN_RECODE=man-recode}" + +init + +cat >"$tmpdir/a.1.exp" <<'EOF' +.SH NAME +a \- á +EOF +cp "$tmpdir/a.1.exp" "$tmpdir/a.1" +cat >"$tmpdir/b.1.exp" <<'EOF' +'\" -*- coding: UTF-8 -*- +.SH NAME +b \- é +EOF +gzip -c <"$tmpdir/b.1.exp" >"$tmpdir/b.1.gz" +cat >"$tmpdir/c.1.exp" <<'EOF' +'\" -*- coding: UTF-8 +.SH NAME +b \- é +EOF +cat >"$tmpdir/c.1" <<'EOF' +'\" -*- coding: ISO-8859-1 +EOF +<"$tmpdir/c.1.exp" tail -n +2 | iconv -f UTF-8 -t ISO-8859-1 >>"$tmpdir/c.1" +gzip "$tmpdir/c.1" + +run $MAN_RECODE -t UTF-8 --suffix .out \ + "$tmpdir/a.1" "$tmpdir/b.1.gz" "$tmpdir/c.1.gz" +expect_files_equal '--suffix with no coding tag' \ + "$tmpdir/a.1.exp" "$tmpdir/a.1.out" +expect_files_equal \ + '--suffix with gzip and coding tag matching target encoding' \ + "$tmpdir/b.1.exp" "$tmpdir/b.1.out" +expect_files_equal \ + '--suffix with gzip and coding tag not matching target encoding' \ + "$tmpdir/c.1.exp" "$tmpdir/c.1.out" + +finish diff --git a/src/tests/man-so-links-same-section b/src/tests/man-so-links-same-section new file mode 100755 index 0000000..bda7190 --- /dev/null +++ b/src/tests/man-so-links-same-section @@ -0,0 +1,91 @@ +#! /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=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'test(1) without .so link' \ + "$tmpdir/1.exp" "$tmpdir/1.out" + +run $MAN -C "$tmpdir/manpath.config" test-fullso | \ + grep -v '^\.l[flt] ' >"$tmpdir/2.out" +expect_files_equal 'test-fullso(1) .so link with section' \ + "$tmpdir/1.exp" "$tmpdir/2.out" + +run $MAN -C "$tmpdir/manpath.config" test-relso | \ + grep -v '^\.l[flt] ' >"$tmpdir/3.out" +expect_files_equal 'test-relso(1) .so link without section' \ + "$tmpdir/1.exp" "$tmpdir/3.out" + + +run $MAN -C "$tmpdir/manpath.config" testb | \ + grep -v '^\.l[flt] ' >"$tmpdir/4.out" +expect_files_equal 'testb(1) without .so link; gzipped' \ + "$tmpdir/2.exp" "$tmpdir/4.out" + +run $MAN -C "$tmpdir/manpath.config" test-fullsob | \ + grep -v '^\.l[flt] ' >"$tmpdir/5.out" +expect_files_equal 'test-fullsob(1) .so link with section; gzipped' \ + "$tmpdir/2.exp" "$tmpdir/5.out" + +run $MAN -C "$tmpdir/manpath.config" test-relsob | \ + grep -v '^\.l[flt] ' >"$tmpdir/6.out" +expect_files_equal 'test-relsob(1) .so link without section; gzipped' \ + "$tmpdir/2.exp" "$tmpdir/6.out" + +finish diff --git a/src/tests/man-suffixed-extension b/src/tests/man-suffixed-extension new file mode 100755 index 0000000..1921e9b --- /dev/null +++ b/src/tests/man-suffixed-extension @@ -0,0 +1,52 @@ +#!/bin/sh + +# Test for: +# man chmod.2 => man 2 chmod +# man 'chmod(2)' => man 2 chmod +# man chmod.2p => man 2p chmod +# man 'chmod(2p)' => man 2p chmod + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal '"man name.2" is the same as "man 2 name"' \ + "$tmpdir/2.exp" "$tmpdir/2.out" +run $MAN -C "$tmpdir/manpath.config" -aw "$page_name(2)" >"$tmpdir/2.out" +expect_files_equal '"man '\''name(2)'\''" is the same as "man 2 name"' \ + "$tmpdir/2.exp" "$tmpdir/2.out" + +mv "$tmpdir/usr/share/man/man2/$page_name.2.gz" \ + "$tmpdir/usr/share/man/man2/$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_files_equal '"man name.2p" is the same as "man 2p name"' \ + "$tmpdir/2p.exp" "$tmpdir/2p.out" +run $MAN -C "$tmpdir/manpath.config" -aw "$page_name(2p)" >"$tmpdir/2p.out" +expect_files_equal '"man '\''name(2p)'\''" is the same as "man 2p name"' \ + "$tmpdir/2p.exp" "$tmpdir/2p.out" + +finish diff --git a/src/tests/man-symlinks-with-matching-names b/src/tests/man-symlinks-with-matching-names new file mode 100755 index 0000000..f8c3bb8 --- /dev/null +++ b/src/tests/man-symlinks-with-matching-names @@ -0,0 +1,32 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/163347 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'symlinks with matching names win' \ + "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/manconv-coding-tags b/src/tests/manconv-coding-tags new file mode 100755 index 0000000..7e75307 --- /dev/null +++ b/src/tests/manconv-coding-tags @@ -0,0 +1,62 @@ +#! /bin/sh + +# Test manconv's support for Emacs-style coding: tags. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANCONV=manconv}" + +init + +cat >"$tmpdir/1.exp" <<'EOF' +'\" -*- coding: UTF-8 +á +EOF +cat >"$tmpdir/1.inp" <<'EOF' +'\" -*- coding: ISO-8859-1 +EOF +<"$tmpdir/1.exp" tail -n +2 | iconv -f UTF-8 -t ISO-8859-1 >>"$tmpdir/1.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/1.inp" >"$tmpdir/1.out" +expect_files_equal 'simple coding tag' "$tmpdir/1.exp" "$tmpdir/1.out" + +cat >"$tmpdir/2.exp" <<'EOF' +'\" -*- mode: troff; coding: UTF-8 -*- +á +EOF +cat >"$tmpdir/2.inp" <<'EOF' +'\" -*- mode: troff; coding: ISO-8859-1 -*- +EOF +<"$tmpdir/2.exp" tail -n +2 | iconv -f UTF-8 -t ISO-8859-1 >>"$tmpdir/2.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/2.inp" >"$tmpdir/2.out" +expect_files_equal 'mode and coding tags' "$tmpdir/2.exp" "$tmpdir/2.out" + +cat >"$tmpdir/3.exp" <<'EOF' +'\" -*- mode: troff; coding: UTF-8 -*- +á +EOF +cat >"$tmpdir/3.inp" <<'EOF' +'\" -*- mode: troff; coding: ISO-LATIN-1 -*- +EOF +<"$tmpdir/3.exp" tail -n +2 | iconv -f UTF-8 -t ISO-8859-1 >>"$tmpdir/3.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/3.inp" >"$tmpdir/3.out" +expect_files_equal 'iso-latin-1 coding alias' "$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_files_equal 'preprocessor comment but no coding tag' \ + "$tmpdir/4.inp" "$tmpdir/4.out" + +cat >"$tmpdir/5.exp" <<'EOF' +'\" -*- coding: utf-8 +á +EOF +cp "$tmpdir/5.exp" "$tmpdir/5.inp" +run $MANCONV -f UTF-8 -t UTF-8 <"$tmpdir/5.inp" >"$tmpdir/5.out" +expect_files_equal 'coding tag matches target encoding' \ + "$tmpdir/5.inp" "$tmpdir/5.out" + +finish diff --git a/src/tests/manconv-guess-from-encoding b/src/tests/manconv-guess-from-encoding new file mode 100755 index 0000000..2fd5a98 --- /dev/null +++ b/src/tests/manconv-guess-from-encoding @@ -0,0 +1,39 @@ +#! /bin/sh + +# Test manconv's support for guessing the input encoding if it is not +# explicitly specified. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANCONV=manconv}" + +init + +write_page coding-tag 7 \ + "$tmpdir/usr/share/man/man7/coding-tag.7" \ + ISO-8859-1 '' '' 'coding-tag \- é' +iconv -f ISO-8859-1 -t UTF-8 \ + <"$tmpdir/usr/share/man/man7/coding-tag.7" \ + >"$tmpdir/coding-tag.7.exp" +run $MANCONV -t UTF-8 "$tmpdir/usr/share/man/man7/coding-tag.7" \ + >"$tmpdir/coding-tag.7.out" +expect_files_equal 'recode from encoding guessed from directory name' \ + "$tmpdir/coding-tag.7.exp" "$tmpdir/coding-tag.7.out" + +write_page lang-dir 7 \ + "$tmpdir/usr/share/man/fr_FR.ISO-8859-1/man7/lang-dir.7.gz" \ + ISO-8859-1 gz '-*- coding: ISO-8859-1 -*-' 'lang-dir \- é' +cat >"$tmpdir/lang-dir.7.exp" <<'EOF' +'\" -*- coding: UTF-8 -*- +EOF +zcat "$tmpdir/usr/share/man/fr_FR.ISO-8859-1/man7/lang-dir.7.gz" | \ + tail -n +2 | iconv -f ISO-8859-1 -t UTF-8 >>"$tmpdir/lang-dir.7.exp" +run $MANCONV -t UTF-8 \ + "$tmpdir/usr/share/man/fr_FR.ISO-8859-1/man7/lang-dir.7.gz" \ + >"$tmpdir/lang-dir.7.out" +expect_files_equal 'recode from encoding guessed from directory name' \ + "$tmpdir/lang-dir.7.exp" "$tmpdir/lang-dir.7.out" + +finish diff --git a/src/tests/manconv-incomplete-char-at-eof b/src/tests/manconv-incomplete-char-at-eof new file mode 100755 index 0000000..96f88cf --- /dev/null +++ b/src/tests/manconv-incomplete-char-at-eof @@ -0,0 +1,17 @@ +#! /bin/sh + +# Test manconv's handling of incomplete characters at end of file. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANCONV=manconv}" + +init + +printf '\314' >"$tmpdir/1.inp" # 0xCC +! run $MANCONV -f EUC-JP -t UTF-8//IGNORE <"$tmpdir/1.inp" >/dev/null +report 'incomplete character at EOF' "$?" + +finish diff --git a/src/tests/manconv-odd-combinations b/src/tests/manconv-odd-combinations new file mode 100755 index 0000000..087d6fc --- /dev/null +++ b/src/tests/manconv-odd-combinations @@ -0,0 +1,81 @@ +#! /bin/sh + +# Test manconv's handling of various odd encoding combinations. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANCONV=manconv}" + +init + +(for x in $(seq 160 255); do + printf %b "\\$(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_files_equal '-f UTF-8:ISO-8859-1 -t UTF-8 on ISO-8859-1 input' \ + "$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_files_equal '-f UTF-8:ISO-8859-2 -t UTF-8 on ISO-8859-2 input' \ + "$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_files_equal \ + '-f UTF-8:KOI8-R -t UTF-8 on KOI8-R input with UTF-8 prefix' \ + "$tmpdir/2.exp" "$tmpdir/2.out" + +(for x in $(seq 160 255); do + printf %b "\\$(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_files_equal '-f UTF-8:ISO-8859-1 -t UTF-8 preserves UTF-8 input' \ + "$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_files_equal \ + 'recognises input encoding and omits invalid output character' \ + "$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 +cat >"$tmpdir/5.exp" <<'EOF' +'\" -*- coding: UTF-8 +EOF +<"$tmpdir/5.inp" tail -n +2 | iconv -f ISO-8859-7 -t UTF-8//IGNORE \ + >>"$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_files_equal 'copes with invalid input characters' \ + "$tmpdir/5.exp" "$tmpdir/5.out" + +finish diff --git a/src/tests/mandb-basic b/src/tests/mandb-basic new file mode 100755 index 0000000..053438c --- /dev/null +++ b/src/tests/mandb-basic @@ -0,0 +1,25 @@ +#! /bin/sh + +# Basic mandb tests. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'simple mandb test' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/mandb-bogus-symlink b/src/tests/mandb-bogus-symlink new file mode 100755 index 0000000..0e8cca5 --- /dev/null +++ b/src/tests/mandb-bogus-symlink @@ -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=.}" +# shellcheck source-path=SCRIPTDIR +. "$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" +report 'double free' "$?" + +finish diff --git a/src/tests/mandb-cachedir-tag b/src/tests/mandb-cachedir-tag new file mode 100755 index 0000000..77f21b7 --- /dev/null +++ b/src/tests/mandb-cachedir-tag @@ -0,0 +1,32 @@ +#! /bin/sh + +# Don't create CACHEDIR.TAG in manpath + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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" +test -e "$tmpdir/var/cache/man/CACHEDIR.TAG" +report "CACHEDIR.TAG exists" "$?" +test ! -e "$tmpdir/usr/share/man/CACHEDIR.TAG" +report "CACHEDIR.TAG doesn't exist 01" "$?" +test ! -e "$tmpdir/usr/dir/man/CACHEDIR.TAG" +report "CACHEDIR.TAG doesn't exist 02" "$?" + +finish diff --git a/src/tests/mandb-empty-page b/src/tests/mandb-empty-page new file mode 100755 index 0000000..66bdf74 --- /dev/null +++ b/src/tests/mandb-empty-page @@ -0,0 +1,28 @@ +#! /bin/sh + +# Test handling of empty files. +# https://bugs.debian.org/622104 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANDB=mandb}" + +init +fake_config /usr/share/man /usr/X11R6/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH + +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" +report 'empty page' "$?" + +./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" +report 'symlink to empty page' "$?" + +finish diff --git a/src/tests/mandb-purge-updates-timestamp b/src/tests/mandb-purge-updates-timestamp new file mode 100755 index 0000000..48666d8 --- /dev/null +++ b/src/tests/mandb-purge-updates-timestamp @@ -0,0 +1,70 @@ +#! /bin/sh + +# If mandb purges missing pages, it updates the database's timestamp, +# without confusing itself into not scanning for newer pages. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$srcdir/testlib.sh" + +: "${MANDB=mandb}" +: "${ACCESSDB=accessdb}" + +init +fake_config /usr/share/man +MANPATH="$tmpdir/usr/share/man" +export MANPATH +db_ext="$(db_ext)" +case $DBTYPE in + ndbm) full_db_ext=.pag ;; + *) full_db_ext="$db_ext" ;; +esac + +write_page test1 1 "$tmpdir/usr/share/man/man1/test1.1.gz" \ + UTF-8 gz t 'test1 \- test1(1)' +write_page test2 1 "$tmpdir/usr/share/man/man1/test2.1.gz" \ + UTF-8 gz t 'test2 \- test2(1)' +write_page test3 1 "$tmpdir/usr/share/man/man1/test3.1.gz" \ + UTF-8 gz t 'test3 \- test3(1)' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/1.exp" <<EOF +test1 -> "- 1 1 MTIME A - - gz test1(1)" +test2 -> "- 1 1 MTIME A - - gz test2(1)" +test3 -> "- 1 1 MTIME A - - gz test3(1)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1.out" +expect_files_equal 'setup' "$tmpdir/1.exp" "$tmpdir/1.out" +mtime1="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")" + +./fspause +rm -f "$tmpdir/usr/share/man/man1/test3.1.gz" +# Fool mandb into believing that this directory was not modified. It will +# still run its purge step. +touch -r "$tmpdir/usr/share/man/index$db_ext" "$tmpdir/usr/share/man/man1" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/2.exp" <<EOF +test1 -> "- 1 1 MTIME A - - gz test1(1)" +test2 -> "- 1 1 MTIME A - - gz test2(1)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/2.out" +expect_files_equal 'remove test3' "$tmpdir/2.exp" "$tmpdir/2.out" +mtime2="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")" +test "$mtime1" != "$mtime2" +report 'mtime changed (1)' "$?" + +./fspause +rm -f "$tmpdir/usr/share/man/man1/test2.1.gz" +write_page test4 1 "$tmpdir/usr/share/man/man1/test4.1.gz" \ + UTF-8 gz t 'test4 \- test4(1)' +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/3.exp" <<EOF +test1 -> "- 1 1 MTIME A - - gz test1(1)" +test4 -> "- 1 1 MTIME A - - gz test4(1)" +EOF +accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/3.out" +expect_files_equal 'remove test2, add test4' "$tmpdir/3.exp" "$tmpdir/3.out" +mtime3="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")" +test "$mtime2" != "$mtime3" +report 'mtime changed (2)' "$?" + +finish diff --git a/src/tests/mandb-regular-file-symlink-changes b/src/tests/mandb-regular-file-symlink-changes new file mode 100755 index 0000000..900d6b6 --- /dev/null +++ b/src/tests/mandb-regular-file-symlink-changes @@ -0,0 +1,68 @@ +#! /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=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'fs(5) setup' "$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_files_equal 'mandb notices regular file -> symlink' \ + "$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_files_equal 'mandb notices two-level symlink' \ + "$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_files_equal 'mandb notices symlink -> regular file' \ + "$tmpdir/4.exp" "$tmpdir/4.out" + +finish diff --git a/src/tests/mandb-symlink-beats-whatis-ref b/src/tests/mandb-symlink-beats-whatis-ref new file mode 100755 index 0000000..f177ddb --- /dev/null +++ b/src/tests/mandb-symlink-beats-whatis-ref @@ -0,0 +1,61 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/204249 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal '/usr/share/man x-terminal-emulator -> xterm' \ + "$tmpdir/1-share.exp" "$tmpdir/1-share.out" +expect_files_equal '/usr/X11R6/man x-terminal-emulator -> xterm' \ + "$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_files_equal '/usr/share/man x-terminal-emulator -> uxterm' \ + "$tmpdir/2-share.exp" "$tmpdir/2-share.out" +expect_files_equal '/usr/X11R6/man x-terminal-emulator -> uxterm' \ + "$tmpdir/2-X11R6.exp" "$tmpdir/2-X11R6.out" + +finish diff --git a/src/tests/mandb-symlink-target-timestamp b/src/tests/mandb-symlink-target-timestamp new file mode 100755 index 0000000..e366d96 --- /dev/null +++ b/src/tests/mandb-symlink-target-timestamp @@ -0,0 +1,32 @@ +#! /bin/sh + +# mandb stores the mtime for a symlink target as the mtime of the target +# file, not the mtime of the symlink. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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 \- test(1)' +./fspause +ln -s test.1.gz "$tmpdir/usr/share/man/man1/test-link.1.gz" +run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man" +cat >"$tmpdir/1.exp" <<EOF +test -> "- 1 1 $(./get-mtime "$tmpdir/usr/share/man/man1/test.1.gz" | sed 's/\.0*\([0-9]\)/ \1/') A - - gz test(1)" +test-link -> "- 1 1 $(./get-mtime "$tmpdir/usr/share/man/man1/test-link.1.gz" | sed 's/\.0*\([0-9]\)/ \1/') B - - gz test(1)" +EOF +run $ACCESSDB "$tmpdir/usr/share/man/index$db_ext" | \ + grep -v '^\$' >"$tmpdir/1.out" +expect_files_equal 'correct mtimes' "$tmpdir/1.exp" "$tmpdir/1.out" + +finish diff --git a/src/tests/mandb-whatis-broken-link-changes b/src/tests/mandb-whatis-broken-link-changes new file mode 100755 index 0000000..2facd5d --- /dev/null +++ b/src/tests/mandb-whatis-broken-link-changes @@ -0,0 +1,57 @@ +#! /bin/sh + +# Ensure that we don't repeatedly rescan when a whatis entry turns into a +# broken link. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'setup' "$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_files_equal 'broken whatis' "$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... +Checking for stray cats 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_files_equal 'mandb does not rescan' "$tmpdir/3.exp" "$tmpdir/3.out" + +finish diff --git a/src/tests/testlib.sh b/src/tests/testlib.sh new file mode 100644 index 0000000..9732f8f --- /dev/null +++ b/src/tests/testlib.sh @@ -0,0 +1,115 @@ +# shellcheck shell=sh + +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 () { + # shellcheck disable=SC2154 + "$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 /' +} + +report () { + if [ "$2" = 0 ]; then + echo " PASS: $1" + else + failures="$((failures + 1))" + echo " FAIL: $1" + fi +} + +expect_files_equal () { + ret=0 + diff -u "$2" "$3" || ret=$? + report "$1" "$ret" +} + +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-path-to-executable b/src/tests/whatis-path-to-executable new file mode 100755 index 0000000..d358aad --- /dev/null +++ b/src/tests/whatis-path-to-executable @@ -0,0 +1,57 @@ +#! /bin/sh + +# Test that whatis behaves appropriately when given a path to an executable. + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'simple name returns all matches' \ + "$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_files_equal '/usr/bin/test only returns appropriate match' \ + "$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_files_equal '/usr/local/bin/test only returns appropriate match' \ + "$tmpdir/3.exp" "$tmpdir/3.out" + +finish diff --git a/src/tests/zsoelim-so-includes b/src/tests/zsoelim-so-includes new file mode 100755 index 0000000..9a43c1a --- /dev/null +++ b/src/tests/zsoelim-so-includes @@ -0,0 +1,61 @@ +#! /bin/sh + +# Test for: +# https://bugs.debian.org/503472 + +: "${srcdir=.}" +# shellcheck source-path=SCRIPTDIR +. "$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_files_equal 'test(1) expanded correctly' "$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..08413d2 --- /dev/null +++ b/src/ult_src.c @@ -0,0 +1,452 @@ +/* + * 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 <stdbool.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 "gl_array_list.h" +#include "gl_hash_map.h" +#include "gl_xlist.h" +#include "gl_xmap.h" +#include "xalloc.h" +#include "xstrndup.h" +#include "xvasprintf.h" + +#include "gettext.h" +#define _(String) gettext (String) + +#include "manconfig.h" + +#include "compression.h" +#include "debug.h" +#include "glcontainers.h" + +#include "decompress.h" +#include "ult_src.h" + +void gripe_canonicalize_failed (const char *path) +{ + if (quiet < 2) { + if (errno == ENOENT) + error (0, 0, _("warning: %s is a dangling symlink"), + path); + else + error (0, errno, _("can't resolve %s"), path); + } +} + +/* 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 */ + gripe_canonicalize_failed (fullpath); + return NULL; + } + + debug ("ult_softlink: (%s)\n", resolved_path); + + return resolved_path; +} + +static char *find_include_directive (char *path) +{ + decompress *decomp; + const char *buffer; + char *directive; + + decomp = decompress_open (path, DECOMPRESS_ALLOW_INPROCESS); + if (!decomp) { + if (quiet < 2) + error (0, errno, _("can't open %s"), path); + return NULL; + } + decompress_start (decomp); + + /* make sure that we skip over any comments */ + do { + buffer = decompress_readline (decomp); + } while (buffer && STRNEQ (buffer, ".\\\"", 3)); + + directive = xstrdup (buffer ? buffer : ""); + + decompress_wait (decomp); + decompress_free (decomp); + + return directive; +} + +/* 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 *target; + struct compression *comp; + + /* Restore the original path from before ult_softlink() etc., in + * case it went outside the mantree. + */ + target = xasprintf ("%s/%s", path, include); + assert (target); + + /* 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 (target, F_OK)) { + comp = comp_file (target); + free (target); + if (comp) { + target = comp->stem; + comp->stem = NULL; /* steal memory */ + } else + target = NULL; + } + + if (!target) { + char *dirname = dir_name (name); + char *temp_file = xasprintf ("%s/%s", dirname, include); + assert (temp_file); + free (dirname); + + if (CAN_ACCESS (temp_file, F_OK)) + /* Just plain include. */ + target = xstrdup (temp_file); + else { + comp = comp_file (temp_file); + if (comp) { + target = comp->stem; + comp->stem = NULL; /* steal memory */ + } + } + free (temp_file); + } + + if (target) { + char *canonicalized = canonicalize_file_name (target); + if (canonicalized) + return canonicalized; + else { + gripe_canonicalize_failed (target); + free (target); + return NULL; + } + } else { + if (quiet < 2) + error (0, 0, _("can't resolve %s"), include); + return NULL; + } +} + +struct ult_key { + char *name; + int flags; +}; + +static struct ult_key *ult_key_new (const char *name, int flags) +{ + struct ult_key *ukey = XMALLOC (struct ult_key); + ukey->name = xstrdup (name); + ukey->flags = flags; + return ukey; +} + +static bool ATTRIBUTE_PURE ult_key_equals (const void *key1, const void *key2) +{ + struct ult_key *ukey1 = (struct ult_key *) key1; + struct ult_key *ukey2 = (struct ult_key *) key2; + return ukey1->flags == ukey2->flags && + STREQ (ukey1->name, ukey2->name); +} + +static size_t ATTRIBUTE_PURE ult_key_hash (const void *key) +{ + struct ult_key *ukey = (struct ult_key *) key; + return string_hash (ukey->name) ^ (size_t) ukey->flags; +} + +static void ult_key_free (const void *key) +{ + struct ult_key *ukey = (struct ult_key *) key; + free (ukey->name); + free (ukey); +} + +static struct ult_value *ult_value_new (void) +{ + struct ult_value *uvalue = XMALLOC (struct ult_value); + uvalue->path = NULL; + uvalue->trace = new_string_list (GL_ARRAY_LIST, true); + return uvalue; +} + +static void ult_value_free (const void *value) +{ + struct ult_value *uvalue = (struct ult_value *) value; + if (uvalue) { + free (uvalue->path); + gl_list_free (uvalue->trace); + free (uvalue); + } +} + +gl_map_t ult_cache = NULL; + +/* + * Find the ultimate source file by following any ".so filename" directives + * in the first line of the man pages. Also (optionally) trace 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 struct ult_value *ult_src (const char *name, const char *path, + struct stat *buf, int flags) +{ + char *base = xstrdup (name); + struct ult_key *key; + const struct ult_value *existing; + struct ult_value *value; + struct stat new_buf; + + if (!ult_cache) + ult_cache = gl_map_create_empty (GL_HASH_MAP, + ult_key_equals, ult_key_hash, + ult_key_free, ult_value_free); + key = ult_key_new (name, flags); + if (gl_map_search (ult_cache, key, (const void **) &existing)) { + ult_key_free (key); + return existing; + } + value = ult_value_new (); + + debug ("ult_src: File %s in mantree %s\n", name, path); + + gl_list_add_last (value->trace, xstrdup (name)); + + /* as ult_softlink() & ult_hardlink() do all of their respective + * resolving in one call, only need to sort them out once + */ + + /* 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); + goto err; + } + } + + /* 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 + goto err; + } + } + + /* 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; + } + } + } + + if (flags & SO_LINK) { + int i; + for (i = 0; i < 10; ++i) { + char *directive, *include; + + directive = find_include_directive (base); + if (!directive) + goto err; + + include = test_for_include (directive); + free (directive); + if (!include) + break; + + free (base); + base = find_include (name, path, include); + free (include); + if (!base) + goto err; + + debug ("ult_src: points to %s\n", base); + + gl_list_add_last (value->trace, xstrdup (base)); + } + if (i == 10) { + if (quiet < 2) + error (0, 0, _("%s is self referencing"), + name); + goto err; + } + } + + /* We have the ultimate source */ + value->path = xstrdup (base); + gl_list_add_last (value->trace, xstrdup (base)); + gl_map_put (ult_cache, key, value); + free (base); + return value; + +err: + /* The cache is short-lived and only within a single process, so + * negative caching is fine. + */ + ult_value_free (value); + gl_map_put (ult_cache, key, NULL); + free (base); + return NULL; +} diff --git a/src/ult_src.h b/src/ult_src.h new file mode 100644 index 0000000..833d600 --- /dev/null +++ b/src/ult_src.h @@ -0,0 +1,45 @@ +/* + * 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 + */ + +#include "gl_list.h" + +#define SO_LINK 0001 +#define SOFT_LINK 0002 +#define HARD_LINK 0004 + +struct stat; + +struct ult_value { + /* Path to the ultimate source file. */ + char *path; + /* A list of `const char *`, containing a trace of the link chain + * from a given file. Any names listed here should not have + * `WHATIS_MAN` entries created for them. + */ + gl_list_t trace; +}; + +extern void gripe_canonicalize_failed (const char *path); +extern const struct ult_value *ult_src (const char *name, const char *path, + struct stat *buf, int flags); diff --git a/src/utf8.c b/src/utf8.c new file mode 100644 index 0000000..d766ee6 --- /dev/null +++ b/src/utf8.c @@ -0,0 +1,138 @@ +/* + * utf8.c: UTF-8 validation + * + * Based on glib's gutf8.c, which is: + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <https://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> + +#include "attribute.h" + +#include "manconfig.h" + +#include "utf8.h" + +#define VALIDATE_BYTE(mask, expect) \ + do { \ + if (UNLIKELY ((*(unsigned char *) p & (mask)) != (expect))) \ + goto error; \ + } while (0) + +/* see IETF RFC 3629 Section 4 */ + +static const char * ATTRIBUTE_PURE fast_validate_len (const char *str, + size_t max_len) +{ + const char *p; + const char *end = str + max_len; + + for (p = str; p < end && *p; p++) { + const char *last; + + if (*(unsigned char *) p < 128) + continue; + + last = p; + if (*(unsigned char *) p < 0xe0) { + /* 110xxxxx */ + if (UNLIKELY (end - p < 2)) + goto error; + + if (UNLIKELY (*(unsigned char *) p < 0xc2)) + goto error; + } else if (*(unsigned char *)p < 0xf0) { + /* 1110xxxx */ + if (UNLIKELY (end - p < 3)) + goto error; + + switch (*(unsigned char *) p++ & 0x0f) { + case 0: + /* 0xa0 ... 0xbf */ + VALIDATE_BYTE (0xe0, 0xa0); + break; + case 0x0d: + /* 0x80 ... 0x9f */ + VALIDATE_BYTE (0xe0, 0x80); + break; + default: + /* 10xxxxxx */ + VALIDATE_BYTE (0xc0, 0x80); + } + } else if (*(unsigned char *) p < 0xf5) { + /* 11110xxx excluding out-of-range */ + if (UNLIKELY (end - p < 4)) + goto error; + + switch (*(unsigned char *) p++ & 0x07) { + case 0: + /* 0x90 ... 0xbf */ + VALIDATE_BYTE (0xc0, 0x80); + if (UNLIKELY ((*(unsigned char *) p & + 0x30) == 0)) + goto error; + break; + case 4: + /* 0x80 ... 0x8f */ + VALIDATE_BYTE(0xf0, 0x80); + break; + default: + /* 10xxxxxx */ + VALIDATE_BYTE(0xc0, 0x80); + } + p++; + /* 10xxxxxx */ + VALIDATE_BYTE(0xc0, 0x80); + } else + goto error; + + p++; + /* 10xxxxxx */ + VALIDATE_BYTE(0xc0, 0x80); + + continue; + +error: + return last; + } + + return p; +} + +/* Validates UTF-8 encoded text. str is the text to validate; max_len is + * the number of bytes to validate. + * + * Note that utf8_validate() returns false if any of the max_len bytes are + * NUL. + * + * Returns true if the text was valid UTF-8. + */ +bool ATTRIBUTE_PURE utf8_validate_len (const char *str, size_t max_len) +{ + const char *p; + + p = fast_validate_len (str, max_len); + + return p == str + max_len; +} diff --git a/src/utf8.h b/src/utf8.h new file mode 100644 index 0000000..de0811b --- /dev/null +++ b/src/utf8.h @@ -0,0 +1,26 @@ +/* + * utf8.h: interface to UTF-8 validation + * + * Based on glib's gutf8.c, which is: + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <https://www.gnu.org/licenses/>. + */ + +#include <stdbool.h> +#include <stddef.h> + +bool utf8_validate_len (const char *str, size_t max_len); diff --git a/src/whatis.c b/src/whatis.c new file mode 100644 index 0000000..7306ad7 --- /dev/null +++ b/src/whatis.c @@ -0,0 +1,943 @@ +/* + * 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 <assert.h> +#include <stdbool.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) + +#include <sys/types.h> +#include <sys/stat.h> +#include "regex.h" + +#include "argp.h" +#include "attribute.h" +#include "dirname.h" +#include "error.h" +#include "gl_hash_set.h" +#include "gl_list.h" +#include "gl_xset.h" +#include "fnmatch.h" +#include "progname.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "manconfig.h" + +#include "appendstr.h" +#include "cleanup.h" +#include "debug.h" +#include "fatal.h" +#include "filenames.h" +#include "glcontainers.h" +#include "pipeline.h" +#include "pathsearch.h" +#include "linelength.h" +#include "wordfnmatch.h" +#include "xregcomp.h" +#include "encodings.h" +#include "sandbox.h" +#include "util.h" + +#include "mydbm.h" +#include "db_storage.h" + +#include "convert.h" +#include "manp.h" + +static gl_list_t manpathlist; + +extern char *user_config_file; +static char **keywords; +static int num_keywords; + +bool am_apropos; +int quiet = 1; +man_sandbox *sandbox; + +static regex_t *preg; +static bool regex_opt; +static bool exact; + +static bool wildcard; + +static bool require_all; + +static bool 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 gl_set_t 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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("verbose", 'v', 0, N_("print verbose warning messages")), + OPT ("regex", 'r', 0, N_("interpret each keyword as a regex"), 10), + /* apropos only */ + OPT ("exact", 'e', 0, N_("search each keyword for exact match")), + OPT ("wildcard", 'w', 0, N_("the keyword(s) contain wildcards")), + /* apropos only */ + OPT ("and", 'a', 0, N_("require all keywords to match"), 20), + OPT ("long", 'l', 0, N_("do not trim output to terminal width"), 30), + OPT ("sections", 's', N_("LIST"), + N_("search only these sections (colon-separated)"), 40), + OPT_ALIAS ("section", 0), + OPT ("systems", 'm', N_("SYSTEM"), + N_("use manual pages from other systems")), + OPT ("manpath", 'M', N_("PATH"), + N_("set search path for manual pages to PATH")), + OPT ("locale", 'L', N_("LOCALE"), + N_("define the locale for this search")), + OPT ("config-file", 'C', N_("FILE"), + N_("use this user configuration file")), + OPT_HIDDEN ("whatis", 'f'), + OPT_HIDDEN ("apropos", 'k'), + OPT_HELP_COMPAT, + { 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 = true; + return 0; + case 'v': + quiet = 0; + return 0; + case 'r': + regex_opt = true; + return 0; + case 'e': + /* Only makes sense for apropos, but has + * historically been accepted by whatis anyway. + */ + regex_opt = false; + exact = true; + return 0; + case 'w': + regex_opt = false; + wildcard = true; + return 0; + case 'a': + if (am_apropos) + require_all = true; + else + argp_usage (state); + return 0; + case 'l': + long_output = true; + 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 = false; + return 0; + case 'k': + /* helpful override if program name detection fails */ + am_apropos = true; + 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 = true; + return 0; + } + return ARGP_ERR_UNKNOWN; +} + +static char *help_filter (int key, const char *text, void *input MAYBE_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; +} + +/* 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, + bool *found) +{ + char *whatis_file = xasprintf ("%s/whatis", manpath); + assert (whatis_file); + + 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", PROG_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] = true; + + 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, true); + 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, true); + 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 (gl_set_search (display_seen, key)) + goto out; + gl_set_add (display_seen, xstrdup (key)); + + 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 = convert_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) +{ + gl_list_t infos; + struct mandata *info; + int count = 0; + + infos = dblookup_all (dbf, page, section, false); + GL_LIST_FOREACH (infos, info) { + display (dbf, info, page); + count++; + } + gl_list_free (infos); + return count; +} + +static bool suitable_manpath (const char *manpath, const char *page_dir) +{ + char *page_manp, *pm; + gl_list_t page_manpathlist; + bool ret; + + page_manp = get_manpath_from_path (page_dir, false); + if (!page_manp || !*page_manp) { + free (page_manp); + return false; + } + pm = locale_manpath (page_manp); + free (page_manp); + page_manp = pm; + page_manpathlist = create_pathlist (page_manp); + + ret = gl_list_search (page_manpathlist, manpath) ? true : false; + + free_pathlist (page_manpathlist); + free (page_manp); + return ret; +} + +static void do_whatis (MYDBM_FILE dbf, + const char * const *pages, int num_pages, + const char *manpath, bool *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] = true; + } + } else { + if (do_whatis_section (dbf, page, NULL)) + found[i] = true; + } + + free (page); + } +} + +static bool any_set (int num_pages, bool *found_here) +{ + int i; + + for (i = 0; i < num_pages; ++i) + if (found_here[i]) + return true; + return false; +} + +static bool all_set (int num_pages, bool *found_here) +{ + int i; + + for (i = 0; i < num_pages; ++i) + if (!found_here[i]) + return false; + return true; +} + +static void parse_name (const char * const *pages, int num_pages, + const char *dbname, bool *found, bool *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] = true; + } + return; + } + + if (am_apropos && !wildcard) { + for (i = 0; i < num_pages; ++i) { + if (strcasecmp (dbname, pages[i]) == 0) + found[i] = found_here[i] = true; + } + return; + } + + for (i = 0; i < num_pages; ++i) { + if (fnmatch (pages[i], dbname, FNM_CASEFOLD) == 0) + found[i] = found_here[i] = true; + } +} + +/* return true on word match */ +static bool ATTRIBUTE_PURE match (const char *page, const char *whatis) +{ + size_t len = strlen (page); + const char *begin; + char *p; + + begin = whatis; + + /* check for string match, then see if it is a _word_ */ + while (whatis && (p = strcasestr (whatis, page))) { + char *left = p - 1; + char *right = p + len; + + if ((p == begin || (!CTYPE (isalpha, *left) && *left != '_')) && + (!*right || (!CTYPE (isalpha, *right) && *right != '_'))) + return true; + whatis = p + 1; + } + + return false; +} + +static void parse_whatis (const char * const *pages, int num_pages, + const char *whatis, bool *found, bool *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] = true; + } + return; + } + + if (wildcard) { + for (i = 0; i < num_pages; ++i) { + if (exact) { + if (fnmatch (pages[i], whatis, 0) == 0) + found[i] = found_here[i] = true; + } else { + if (word_fnmatch (pages[i], whatis)) + found[i] = found_here[i] = true; + } + } + return; + } + + for (i = 0; i < num_pages; ++i) { + if (match (pages[i], whatis)) + found[i] = found_here[i] = true; + } +} + +/* 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, bool *found) +{ + datum key, cont; + bool *found_here; + bool (*combine) (int, bool *); +#ifndef BTREE + datum nextkey; +#else /* BTREE */ + int end; +#endif /* !BTREE */ + + found_here = XNMALLOC (num_pages, bool); + 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 = man_btree_nextkeydata (dbf, &key, &cont); + while (!end) { +#endif /* !BTREE */ + char *tab; + struct mandata *info = NULL; + + /* 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)); + fatal (0, + _("Database %s corrupted; rebuild with " + "mandb --create"), + dbf->name); + } + +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-use-after-free" +#endif + if (*MYDBM_DPTR (key) == '$') + goto nextpage; + + if (*MYDBM_DPTR (cont) == '\t') + goto nextpage; +#pragma GCC diagnostic pop + + /* a real page */ + + info = split_content (dbf, MYDBM_DPTR (cont)); + + /* If there are sections given, does any of them match + * either the section or extension of this page? + */ + if (sections) { + char * const *section; + bool matched = false; + + for (section = sections; *section; ++section) { + if (STREQ (*section, info->sec) || + STREQ (*section, info->ext)) { + matched = true; + break; + } + } + + if (!matched) + goto nextpage; + } + + tab = strrchr (MYDBM_DPTR (key), '\t'); + if (tab) + *tab = '\0'; + + memset (found_here, 0, num_pages * sizeof (*found_here)); + parse_name (pages, num_pages, + MYDBM_DPTR (key), found, found_here); + if (am_apropos) { + char *whatis; + + whatis = info->whatis ? xstrdup (info->whatis) : NULL; + if (!combine (num_pages, found_here) && whatis) + parse_whatis (pages, num_pages, + whatis, found, found_here); + free (whatis); + } + if (combine (num_pages, found_here)) + display (dbf, info, MYDBM_DPTR (key)); + + if (tab) + *tab = '\t'; +nextpage: +#pragma GCC diagnostic push +#if GNUC_PREREQ(10,0) +# pragma GCC diagnostic ignored "-Wanalyzer-double-free" +#endif +#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 = man_btree_nextkeydata (dbf, &key, &cont); +#endif /* !BTREE */ +#pragma GCC diagnostic pop + free_mandata_struct (info); + } + + free (found_here); +} + +/* loop through the man paths, searching for a match */ +static bool search (const char * const *pages, int num_pages) +{ + bool *found = XCALLOC (num_pages, bool); + char *mp; + bool any_found; + int i; + + GL_LIST_FOREACH (manpathlist, mp) { + char *catpath, *database; + MYDBM_FILE dbf; + + catpath = get_catpath (mp, SYSTEM_CAT | USER_CAT); + database = mkdbname (catpath ? catpath : mp); + + debug ("path=%s\n", mp); + + dbf = MYDBM_NEW (database); + if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) { + use_grep (pages, num_pages, mp, found); + goto next; + } + + 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); + } + +next: + MYDBM_FREE (dbf); + free (database); + free (catpath); + } + + any_found = false; + for (i = 0; i < num_pages; ++i) { + if (found[i]) + any_found = true; + else + fprintf (stderr, _("%s: nothing appropriate.\n"), + pages[i]); + } + + free (found); + return any_found; +} + +int main (int argc, char *argv[]) +{ + char *program_base_name; + int status = OK; + + set_program_name (argv[0]); + program_base_name = base_name (program_name); + if (STREQ (program_base_name, APROPOS_NAME)) { + am_apropos = true; + argp_program_version = "apropos " PACKAGE_VERSION; + } else { + struct argp_option *optionp; + am_apropos = false; + 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)); + + manpathlist = create_pathlist (manp); + + display_seen = new_string_set (GL_HASH_SET); + + 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); + } + + gl_set_free (display_seen); + free_pathlist (manpathlist); + free (manp); + free (internal_locale); + sandbox_free (sandbox); + exit (status); +} diff --git a/src/zsoelim.c b/src/zsoelim.c new file mode 100644 index 0000000..ad4fd4c --- /dev/null +++ b/src/zsoelim.c @@ -0,0 +1,2632 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "manconfig.h" + +/* Flex emits several functions which might reasonably have various + * attributes applied and many unused macros; none of these are our problem. + */ +#if GNUC_PREREQ(8,0) +# pragma GCC diagnostic ignored "-Wsuggest-attribute=malloc" +#endif +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#pragma GCC diagnostic ignored "-Wunused-macros" + +#line 17 "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 19 "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 <assert.h> +#include <stdbool.h> +#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 "error.h" +#include "gl_linkedhash_list.h" +#include "gl_xlist.h" +#include "xalloc.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "appendstr.h" +#include "compression.h" +#include "debug.h" +#include "fatal.h" +#include "glcontainers.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 decompress *so_pipe[MAX_SO_DEPTH]; +static int so_stack_ptr; +static bool no_newline; +static gl_list_t so_manpathlist; +static const char *so_parent_path; + +struct zsoelim_stdin_data { + char *path; + gl_list_t 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 'decompress *' rather than the usual 'FILE *'. + */ +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = decompress_read ((decompress *) yyin, &size); \ + if (block && size != 0) { \ + memcpy (buf, block, size); \ + buf[size] = '\0'; \ + result = size; \ + } else \ + result = YY_NULL; \ +} +#define YY_NO_INPUT +#line 890 "zsoelim.c" + +#line 892 "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 146 "zsoelim.l" + + +#line 1118 "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 148 "zsoelim.l" +{ + no_newline = true; + ECHO; + BEGIN (de); /* Now we're inside of a macro definition: ends with a comment */ + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 154 "zsoelim.l" +{ + no_newline = true; + BEGIN (so); /* Now we're in the .so environment */ + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 159 "zsoelim.l" +{ + no_newline = true; + ECHO; /* Now we're in the .lf environment */ + BEGIN (lfnumber); + } + YY_BREAK +case 4: +#line 166 "zsoelim.l" +case 5: +/* rule 5 can match eol */ +#line 167 "zsoelim.l" +case 6: +/* rule 6 can match eol */ +#line 168 "zsoelim.l" +case 7: +/* rule 7 can match eol */ +#line 169 "zsoelim.l" +case 8: +/* rule 8 can match eol */ +#line 170 "zsoelim.l" +case 9: +/* rule 9 can match eol */ +#line 171 "zsoelim.l" +case 10: +/* rule 10 can match eol */ +YY_RULE_SETUP +#line 171 "zsoelim.l" +{ + no_newline = true; + ECHO; + } + YY_BREAK +case 11: +/* rule 11 can match eol */ +YY_RULE_SETUP +#line 176 "zsoelim.l" +{ + no_newline = false; + putchar ('\n'); + LINE++; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 183 "zsoelim.l" +{ /* file names including whitespace ? */ + if (so_stack_ptr == MAX_SO_DEPTH - 1) + 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 = false; + + 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 215 "zsoelim.l" +{ + no_newline = false; + BEGIN (INITIAL); + } + YY_BREAK +case 14: +/* rule 14 can match eol */ +YY_RULE_SETUP +#line 220 "zsoelim.l" +{ + no_newline = false; + 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 231 "zsoelim.l" +{ + no_newline = true; + ECHO; + BEGIN (INITIAL); + } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 237 "zsoelim.l" +{ + no_newline = true; + ECHO; + } + YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +#line 242 "zsoelim.l" +{ + no_newline = false; + putchar ('\n'); + LINE++; + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 249 "zsoelim.l" +{ + no_newline = true; + ECHO; + ZAP_QUOTES; + LINE = atoi (yytext); + BEGIN (lfname); + } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 257 "zsoelim.l" +{ /* file names including whitespace ?? */ + no_newline = true; + ECHO; + putchar ('\n'); + ZAP_QUOTES; + if (NAME) + free (NAME); + NAME = xstrdup (yytext); + BEGIN (end_request); + } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 268 "zsoelim.l" +{ + no_newline = true; + ECHO; + } + YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +#line 273 "zsoelim.l" +{ + no_newline = false; + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 280 "zsoelim.l" +{ + no_newline = true; + debug ( + "%s:%d: warning: unhandled .lf request; " + "line numbers may be wrong\n", + NAME, LINE); + putchar (*yytext); + BEGIN (INITIAL); + } + YY_BREAK +case 23: +/* rule 23 can match eol */ +YY_RULE_SETUP +#line 290 "zsoelim.l" +{ + no_newline = false; + 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 301 "zsoelim.l" +{ + decompress_wait (PIPE); + decompress_free (PIPE); + PIPE = NULL; + free (NAME); + NAME = 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 = false; + BEGIN (end_request); + } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 321 "zsoelim.l" +ECHO; + YY_BREAK +#line 1417 "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 321 "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 (gl_list_t manpathlist, const char *parent_path) +{ + const char *line; + int linenum = 1; + + so_stack_ptr = 0; + so_manpathlist = manpathlist; + so_parent_path = parent_path; + + /* Skip over the first line if it's something that manconv might + * need to know about. + */ + line = decompress_peekline ((decompress *) yyin); + if (line && + (STRNEQ (line, PP_COOKIE, 4) || STRNEQ (line, ".\\\" ", 4))) { + fputs (line, stdout); + decompress_peek_skip ((decompress *) yyin, strlen (line)); + ++linenum; + } + + printf (".lf %d %s\n", linenum, NAME); + LINE = 1; + yylex (); +} + +static decompress *try_compressed (char **filename) +{ + struct compression *comp; + size_t len = strlen (*filename); + decompress *decomp; + + /* Try the uncompressed name first. */ + (*filename)[len - 1] = '\0'; + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename, DECOMPRESS_ALLOW_INPROCESS); + 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, + DECOMPRESS_ALLOW_INPROCESS); + 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 */ +bool zsoelim_open_file (const char *filename, gl_list_t manpathlist, + const char *parent_path) +{ + decompress *decomp = NULL; + + 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; + const char *mp; + + /* If there is no parent path, try opening directly first. */ + if (!parent_path) { + compfile = xasprintf ("%s.", filename); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + + if (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); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + + GL_LIST_FOREACH (manpathlist, mp) { + if (parent_path && STREQ (mp, parent_path)) + continue; + + compfile = xasprintf ("%s/%s.", mp, filename); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + } else { + /* File name with no directory part. Try searching + * the manpath. + */ + char *name, *sec, *dot; + gl_list_t names; + const char *found_name; + + 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, + false, LFF_MATCHCASE); + GL_LIST_FOREACH (names, found_name) { + decomp = decompress_open + (found_name, + DECOMPRESS_ALLOW_INPROCESS); + if (decomp) { + NAME = xstrdup (found_name); + gl_list_free (names); + goto out; + } + } + gl_list_free (names); + } + + GL_LIST_FOREACH (manpathlist, mp) { + if (parent_path && STREQ (mp, parent_path)) + continue; + + names = look_for_file (mp, sec, name, + false, LFF_MATCHCASE); + GL_LIST_FOREACH (names, found_name) { + decomp = decompress_open + (found_name, + DECOMPRESS_ALLOW_INPROCESS); + if (decomp) { + NAME = xstrdup (found_name); + gl_list_free (names); + free (name); + goto out; + } + } + gl_list_free (names); + } + + free (name); + } + + /* If there is a parent path, try opening directly last. */ + if (parent_path) { + compfile = xasprintf ("%s.", filename); + assert (compfile); + + 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 true; + } + } + + debug ("opened %s\n", NAME); + + decompress_start (decomp); + PIPE = decomp; + /* only used by YY_INPUT, which casts it back to 'decompress *' */ + yyin = (FILE *) decomp; + + return false; +} + +void zsoelim_stdin (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + gl_list_t empty; + + empty = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL, + true); + zsoelim_open_file ("-", empty, zsoelim_data->path); + gl_list_free (empty); + zsoelim_parse_file (zsoelim_data->manpathlist, zsoelim_data->path); +} + +struct zsoelim_stdin_data *zsoelim_stdin_data_new (const char *path, + gl_list_t 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..901732d --- /dev/null +++ b/src/zsoelim.h @@ -0,0 +1,36 @@ +/* + * 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 + */ + +#include <stdbool.h> + +#include "gl_list.h" + +bool zsoelim_open_file (const char *filename, gl_list_t manpathlist, + const char *parent_path); +void zsoelim_parse_file (gl_list_t 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, + gl_list_t manpathlist); +void zsoelim_stdin_data_free (void *data); diff --git a/src/zsoelim.l b/src/zsoelim.l new file mode 100644 index 0000000..8470b34 --- /dev/null +++ b/src/zsoelim.l @@ -0,0 +1,576 @@ +%top{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "manconfig.h" + +/* Flex emits several functions which might reasonably have various + * attributes applied and many unused macros; none of these are our problem. + */ +#if GNUC_PREREQ(8,0) +# pragma GCC diagnostic ignored "-Wsuggest-attribute=malloc" +#endif +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#pragma GCC diagnostic ignored "-Wunused-macros" +} + +%{ + +/* + * 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 <assert.h> +#include <stdbool.h> +#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 "error.h" +#include "gl_linkedhash_list.h" +#include "gl_xlist.h" +#include "xalloc.h" +#include "xgetcwd.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define _(String) gettext (String) + +#include "appendstr.h" +#include "compression.h" +#include "debug.h" +#include "fatal.h" +#include "glcontainers.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 decompress *so_pipe[MAX_SO_DEPTH]; +static int so_stack_ptr; +static bool no_newline; +static gl_list_t so_manpathlist; +static const char *so_parent_path; + +struct zsoelim_stdin_data { + char *path; + gl_list_t 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 'decompress *' rather than the usual 'FILE *'. + */ +#define YY_INPUT(buf,result,max_size) { \ + size_t size = max_size; \ + const char *block = decompress_read ((decompress *) 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 = true; + ECHO; + BEGIN (de); /* Now we're inside of a macro definition: ends with a comment */ + } + +^\.so{W}* { + no_newline = true; + BEGIN (so); /* Now we're in the .so environment */ + } + +^\.lf{W}* { + no_newline = true; + ECHO; /* Now we're in the .lf environment */ + BEGIN (lfnumber); + } + +^[^\.\n].* | /* fallback */ +^\.[^sl].* | +^\.l[^f].* | +^\.s[^o].* | +^\.s | +^\.l | +. { + no_newline = true; + ECHO; + } + +\n { + no_newline = false; + putchar ('\n'); + LINE++; + } + + +<so>\"?[^ \t\n\"]+\"? { /* file names including whitespace ? */ + if (so_stack_ptr == MAX_SO_DEPTH - 1) + 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 = false; + + 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 = false; + BEGIN (INITIAL); + } + +<so>\n { + no_newline = false; + error (OK, 0, + _("%s:%d: warning: newline in .so request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<de>^\.\..* { + no_newline = true; + ECHO; + BEGIN (INITIAL); + } + +<de>.* { + no_newline = true; + ECHO; + } + +<de>\n { + no_newline = false; + putchar ('\n'); + LINE++; + } + + +<lfnumber>\"?[0-9]+\"? { + no_newline = true; + ECHO; + ZAP_QUOTES; + LINE = atoi (yytext); + BEGIN (lfname); + } + +<lfname>\"?[^ \t\n\"]+\"? { /* file names including whitespace ?? */ + no_newline = true; + ECHO; + putchar ('\n'); + ZAP_QUOTES; + if (NAME) + free (NAME); + NAME = xstrdup (yytext); + BEGIN (end_request); + } + +<lfname>{W}+ { + no_newline = true; + ECHO; + } + +<lfname>\n { + no_newline = false; + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<lfnumber,lfname>. { + no_newline = true; + debug ( + "%s:%d: warning: unhandled .lf request; " + "line numbers may be wrong\n", + NAME, LINE); + putchar (*yytext); + BEGIN (INITIAL); + } + +<lfnumber>\n { + no_newline = false; + error (OK, 0, + _("%s:%d: warning: newline in .lf request, " + "ignoring"), + NAME, LINE); + putchar ('\n'); + LINE++; + BEGIN (INITIAL); + } + +<<EOF>> { + decompress_wait (PIPE); + decompress_free (PIPE); + PIPE = NULL; + free (NAME); + NAME = 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 = false; + 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 (gl_list_t manpathlist, const char *parent_path) +{ + const char *line; + int linenum = 1; + + so_stack_ptr = 0; + so_manpathlist = manpathlist; + so_parent_path = parent_path; + + /* Skip over the first line if it's something that manconv might + * need to know about. + */ + line = decompress_peekline ((decompress *) yyin); + if (line && + (STRNEQ (line, PP_COOKIE, 4) || STRNEQ (line, ".\\\" ", 4))) { + fputs (line, stdout); + decompress_peek_skip ((decompress *) yyin, strlen (line)); + ++linenum; + } + + printf (".lf %d %s\n", linenum, NAME); + LINE = 1; + yylex (); +} + +static decompress *try_compressed (char **filename) +{ + struct compression *comp; + size_t len = strlen (*filename); + decompress *decomp; + + /* Try the uncompressed name first. */ + (*filename)[len - 1] = '\0'; + debug ("trying %s\n", *filename); + decomp = decompress_open (*filename, DECOMPRESS_ALLOW_INPROCESS); + 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, + DECOMPRESS_ALLOW_INPROCESS); + 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 */ +bool zsoelim_open_file (const char *filename, gl_list_t manpathlist, + const char *parent_path) +{ + decompress *decomp = NULL; + + 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; + const char *mp; + + /* If there is no parent path, try opening directly first. */ + if (!parent_path) { + compfile = xasprintf ("%s.", filename); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } else + free (compfile); + } + + if (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); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + + GL_LIST_FOREACH (manpathlist, mp) { + if (parent_path && STREQ (mp, parent_path)) + continue; + + compfile = xasprintf ("%s/%s.", mp, filename); + assert (compfile); + + decomp = try_compressed (&compfile); + if (decomp) { + NAME = compfile; + goto out; + } + + free (compfile); + } + } else { + /* File name with no directory part. Try searching + * the manpath. + */ + char *name, *sec, *dot; + gl_list_t names; + const char *found_name; + + 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, + false, LFF_MATCHCASE); + GL_LIST_FOREACH (names, found_name) { + decomp = decompress_open + (found_name, + DECOMPRESS_ALLOW_INPROCESS); + if (decomp) { + NAME = xstrdup (found_name); + gl_list_free (names); + goto out; + } + } + gl_list_free (names); + } + + GL_LIST_FOREACH (manpathlist, mp) { + if (parent_path && STREQ (mp, parent_path)) + continue; + + names = look_for_file (mp, sec, name, + false, LFF_MATCHCASE); + GL_LIST_FOREACH (names, found_name) { + decomp = decompress_open + (found_name, + DECOMPRESS_ALLOW_INPROCESS); + if (decomp) { + NAME = xstrdup (found_name); + gl_list_free (names); + free (name); + goto out; + } + } + gl_list_free (names); + } + + free (name); + } + + /* If there is a parent path, try opening directly last. */ + if (parent_path) { + compfile = xasprintf ("%s.", filename); + assert (compfile); + + 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 true; + } + } + + debug ("opened %s\n", NAME); + + decompress_start (decomp); + PIPE = decomp; + /* only used by YY_INPUT, which casts it back to 'decompress *' */ + yyin = (FILE *) decomp; + + return false; +} + +void zsoelim_stdin (void *data) +{ + struct zsoelim_stdin_data *zsoelim_data = data; + gl_list_t empty; + + empty = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL, + true); + zsoelim_open_file ("-", empty, zsoelim_data->path); + gl_list_free (empty); + zsoelim_parse_file (zsoelim_data->manpathlist, zsoelim_data->path); +} + +struct zsoelim_stdin_data *zsoelim_stdin_data_new (const char *path, + gl_list_t 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..b4057b4 --- /dev/null +++ b/src/zsoelim_main.c @@ -0,0 +1,163 @@ +/* + * 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 <stdbool.h> +#include <stdlib.h> + +#include "argp.h" +#include "attribute.h" +#include "error.h" +#include "gl_list.h" +#include "progname.h" +#include "xalloc.h" +#include "xvasprintf.h" + +#include "gettext.h" +#include <locale.h> +#define N_(String) gettext_noop (String) + +#include "manconfig.h" + +#include "cleanup.h" +#include "debug.h" +#include "pipeline.h" +#include "sandbox.h" +#include "util.h" + +#include "decompress.h" +#include "manp.h" +#include "zsoelim.h" + +int quiet = 1; +man_sandbox *sandbox; + +static gl_list_t manpathlist; + +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[] = { + OPT ("debug", 'd', 0, N_("emit debugging messages")), + OPT ("compatible", 'C', 0, N_("compatibility switch (ignored)"), 1), + OPT_HELP_COMPAT, + { 0 } +}; + +static error_t parse_opt (int key, char *arg MAYBE_UNUSED, + struct argp_state *state) +{ + switch (key) { + case 'd': + debug_level = true; + 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); + + manpathlist = create_pathlist (manp); + + /* 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); + sandbox_free (sandbox); + + return OK; +} |