diff options
Diffstat (limited to 'Build/source/texk/contrib')
45 files changed, 19022 insertions, 0 deletions
diff --git a/Build/source/texk/contrib/ChangeLog b/Build/source/texk/contrib/ChangeLog new file mode 100644 index 00000000000..f0462901d4b --- /dev/null +++ b/Build/source/texk/contrib/ChangeLog @@ -0,0 +1,290 @@ +2003-01-08 Olaf Weber <olaf@infovore.xs4all.nl> + + * mktex.h: Update from Fabrice. + + * mktex.c: Update from Fabrice. + +2002-12-14 Olaf Weber <olaf@infovore.xs4all.nl> + + * fmtutil.c: Sync with TeXlive tree. + + * glob/configure.bat: sync with TeXlive tree. + +2002-10-06 Olaf Weber <olaf@infovore.xs4all.nl> + + * variables.c: TeXlive merge. + + * stackenv.h: TeXlive merge. + + * stackenv.c: TeXlive merge. + + * mktexlib.h: TeXlive merge. + + * mktex.h: TeXlive merge. + + * mktex.c: TeXlive merge. + + * makempx.c: TeXlive merge. + + * main.c: TeXlive merge. + + * fmtutil.h: TeXlive merge. + + * fmtutil.c: TeXlive merge. + + * fileutils.c: TeXlive merge. + + * dvihp.c: TeXlive merge. + +2000-04-21 Olaf Weber <olaf@infovore.xs4all.nl> + + * makempx.c, stackenv.c, fmtutil.c: Update from Fabrice. + +2000-04-03 Olaf Weber <olaf@infovore.xs4all.nl> + + * All files: Update from Fabrice Popineau + <popineau@esemetz.ese-metz.fr>. + +1999-03-17 Olaf Weber <olaf@infovore.xs4all.nl> + + * fmtutil.c: TEXMF_CNF -> VARTEXMF. From Thomas. + +1999-03-15 Olaf Weber <olaf@infovore.xs4all.nl> + + * mktex.c (do_mktexmf): Correction for 11 point fonts, addition + for the CB font family. From Kimon Kontovasilis + <kimon@cyclades.nrcps.ariadne-t.gr>. + +1999-02-06 Olaf Weber <olaf@infovore.xs4all.nl> + + * mktex.c (do_mktexmf): Special-case 30 and 36 points, as with the + mktexmf script. From Fabrice. + +1999-02-04 Olaf Weber <olaf@infovore.xs4all.nl> + + * stackenv.h (oops): Removed __cdecl, from Fabrice. + + * stackenv.c (oops): Removed __cdecl, from Fabrice. + + * mktexlib.h [!WIN32]: Removed define of __cdecl. From Fabrice. + + * mktex.c (main): Removed __cdecl, from Fabrice. + + * makempx.c (main): Removed __cdecl, from Fabrice. + + * main.c (main): Removed __cdecl, from Fabrice. + + * fmtutil.c (main): Removed __cdecl, from Fabrice. + + * dvihp.c (main): Removed __cdecl, from Fabrice. + +1999-01-27 Olaf Weber <olaf@infovore.xs4all.nl> + + * fileutils.h: New file from Fabrice Popineau. + + * fileutils.c: New file from Fabrice Popineau. + + * Makefile: Update for new files from Fabrice Popineau. + + * General updates of the other files from Fabrice. + +Fri Jun 12 11:39:22 1998 Fabrice POPINEAU <popineau@ese-metz.fr> + + * variables.c (normalize): added UNC names handling. + * mktex.c (do_makedir): same thing. + +Tue Apr 14 21:52:37 1998 Fabrice POPINEAU <popineau@ese-metz.fr> + + * mktex.c: split mktex.c into (mktex.c, main.c). The goal is to + build a mktex dll, directly callable from other programs. The + command line programs are kept through main.c . + +1998-03-10 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (main): Diagnose empty or bogus $TEXMFMAIN setting. + (read_mktexcnf): Don't free mtsite, as it is recorded in the hash + table. + +1998-03-09 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (do_mktexupdate): Call `mktexlsr', not `do_mktexlr', as + the latter doesn't redirect its output to the `ls-R' file. + (get_mode_from_mf): Fix the METAFONT command line. + (mktexlsr): Record the name of the temporary db_file_tmp. + (is_db_file_tmp): New function. + (print_path): Call it to check whether a file is the temporary + database itself, and if so, don't record it. + +1998-03-08 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (mktex_opt): Reinstate the sanity check of + $MT_VARTEXFONTS, like the script does. + + * mktex.c (mktexpk): Revert to calling `system' instead of + `execute_command'. + +1998-03-04 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (do_mktexnames): Changes in the $VARTEXFONTS logic, to + track the shell script. + + * variables.c (subst): If no match, return a copy of the original + string. From Fabrice Popineau. + + * stackenv.c (execute_command): New function, from Fabrice + Popineau. + + * mktex.c (string_to_lower): New function, from Fabrice Popineau. + (do_mktexnames): Fold case when matching relfmt with stdfontpath, + on case-insensitive systems. From Fabrice Popineau. + (do_mktextfm, mktexpk): Call `execute_command' instead of + `system'. From Fabrice Popineau. + +1998-03-03 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (is_casesensitive): Use the CASE_SENSITIVE flag, not + CASE_PRESERVED, as the latter doesn't imply the former. From + Fabrice Popineau. + +1998-03-02 Eli Zaretskii <eliz@is.elta.co.il> + + * stackenv.c (test_file): Let 'w' check stat mod bits, in addition + to `access', to make it more like "test -w foo". + + * mktex.c (findmap): Fix the case where $SUPPLIER is shorter than + 3 characters. + (do_mktexnames): Expand stdfontpath _after_ concatenation. + (path_included): Fold case only for case-insensitive filesystems. + (do_mktexnames): Fix comparison of $MT_DESTROOT and $SYSTEMXF. + +1998-02-23 Eli Zaretskii <eliz@is.elta.co.il> + + * stackenv.c (is_writable): Remove temporary file we created. + + * mktex.c (mktexnam_opt): When dosnames is in effect, set + MT_PKBASE, not MT_PKNAME. + +1998-02-17 Eli Zaretskii <eliz@is.elta.co.il> + + * dvihp.c (main): Catch SIGINT, SIGQUIT, SIGHUP and SIGTERM + signals, so we have a chance to clean up. Create temporary + directory which is writeable only by owner. + + * makempx.c (main): Catch SIGQUIT, SIGHUP and SIGTERM signals as + well, like the script does. + + * mktex.c: Update the usage strings according to latest scripts. + (mktex_opt): Catch SIGHUP and SIGTERM signals as well, like the + scripts do. + +1998-02-16 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (main): Compute $MT_TEXMFMAIN, like all the scripts do + now. + (do_mktexmf): Compute $MT_MFNAME. + (do_mktexnames): Changes in $MT_xxx variables. + (mktexpk): Handle non-positional options, like the script does. + Mask off write access bits to the temporary file for group/other. + (mktextfm): Handle non-positional options, like the script does. + Mask off write access bits to the temporary files for + group/other. + (chmod_as_dir): Mask off some access bits as given by an + additional parameter MASK. + (do_makedir): Set permissions for created directories by calling + `chmod'. + + * dvihp.c (main): Make `main' be __cdecl for the Win32 port. + + * makempx.c (main): Ditto. + + * mktex.c (mktexpk): Move $NAME.${DPI}pk to $PKNAME if the latter + isn't produced by `gftopk'. + (mktex_opt): Remove computation of $TEXMFMAIN. Support exported + cached $MT_xxx variables, like the scripts do. + (read_mktexcnf): Set $MT_MKTEX_CNF if unset. + +1998-02-15 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (do_mktexmf): Free unused strings. Make division by 100 + be in sync with the script. + (mktexmf): Remove redundant print-out before exiting. + (do_mktextfm): Free unused strings. Move $NAME.log only if + non-empty, like the script does; fix the second argument to + `mvfile' when moving $NAME.log. + (get_mode_from_mf): Remove redundant backslashes. + (mktexpk): Free unused strings. Move $NAME.log only if non-empty, + like the script does; fix the second argument to `mvfile' when + moving $NAME.log. + +1998-02-12 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (mktexnam_opt): Fix error messages. + (mktexnames): Print names separated by ENV_SEP_STRING, as the + script now does. Remove redundant calls to `expand_var'. + +1998-02-11 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c [!S_ISLNK] (readlink): New function, a dummy version for + systems which don't support symlinks and therefore don't have + `readlink' in their libraries. + (mktexlsr): Follow symlinks, like the script does. Set access + permissions for db_file_tmp before moving it to db_file. + (do_mktexnames): Use `setval' instead of `setval_default', to + track changes in the script. Delete MT_xxPART variables, for the + same reason. New way of computing the destination directory, + after the script. Free `vars' and its elements. + +1998-02-10 +02 Eli Zaretskii <eliz@is.elta.co.il> + + * mktex.c (mktex_opt): Changes to track modifications in + kpathsea/mktex.opt. + (read_mktexcnf): Call kpse_find_file to find mktex.cnf. + + * variables.c (setval_default): Only assign to unset variables, + leave set but empty ones unchanged. Do not put the variable into + the environment. + (setval): Do not put the variable into the environment. + (expand_var): Remove leading "!!" from path elements. Return NULL + for NULL argument. + +Tue Feb 10 18:06:31 1998 Olaf Weber <infovore@xs4all.nl> + + * Makefile: Add check target. + + * dvihp.c: Patches from Eli Zaretskii. + + * makempx.c: Patches from Eli Zaretskii. + + * mktex.c: Patches from Eli Zaretskii. + +1998-02-09 Eli Zaretskii <eliz@is.elta.co.il> + + * stackenv.c (is_writable): Handle null or empty argument without + crashing. + +Fri Feb 6 18:04:36 1998 Olaf Weber <infovore@xs4all.nl> + + * Makefile: Add distclean target. + +Tue Feb 3 17:09:18 1998 Olaf Weber <infovore@xs4all.nl> + + * Makefile (clean): Add makempx and dvihp to list of programs to + be removed. + +Sun Feb 1 16:22:59 1998 Olaf Weber <infovore@xs4all.nl> + + * dvihp.c: Patch from Eli Zaretskii; replace D_OK with R_OK|W_OK. + + * makempx.c: Patch from Eli Zaretskii. + + * mktex.c: Patch from Eli Zaretskii; replace the kpathsea include + with kpathsea.h. + + * stackenv.c: Patch from Eli Zaretskii. + +Wed Jan 28 20:19:07 1998 Olaf Weber <infovore@xs4all.nl> + + * C replacements for the mktex scripts. Written by Fabrice + Popineau with help from Eli Zaretskii. May not work on your + system. + diff --git a/Build/source/texk/contrib/INSTALL b/Build/source/texk/contrib/INSTALL new file mode 100644 index 00000000000..4def5256c28 --- /dev/null +++ b/Build/source/texk/contrib/INSTALL @@ -0,0 +1,12 @@ +To build the replacement programs, chdir to this directory and type +"make". This builds the main programs mktex, makempx and dvihp, and +the mktex... programs which are really symlinks to mktex. + +To install the compiled programs, copy them all into the same directory +where you install the other binaries ($prefix/bin, which is usually +/usr/local/bin). + +The supplied Makefile was tested with DJGPP, but it should also work +with any reasonable Unix setup. For platforms other than these two, +you might need to tweak the Makefile a bit; the macros $EXE, $O, $LN_S +and $RM are provided to make this easier. diff --git a/Build/source/texk/contrib/README b/Build/source/texk/contrib/README new file mode 100644 index 00000000000..546ba53bc32 --- /dev/null +++ b/Build/source/texk/contrib/README @@ -0,0 +1,22 @@ +This directory contains: replacement mktex... programs which emulate +the mktex... shell scripts in ../kpathsea directory; a replacement for +the makempx script from ../web2c/mpware; and a replacement for the +dvihp script from ../dviljk. These C programs are primarily for use +in those environments where the standard Unix shell and utilities +invoked by the scripts are not readily available. However, they can +also be used on Unix platforms, although they were tested almost +exclusively on MS-DOS and MS-Windows systems. + +Caveats: currently, the emulation programs don't support edited *.opt +files, they emulate internally the effect of the original *.opt files +distributed with Web2c sources. Variables set from the mktex.cnf file +*are* supported. + +All of the programs except dvihp.c were written by Fabrice Popineau +<popineau@esemetz.ese-metz.fr>. dvihp.c was written by Eli Zaretskii +<eliz@is.elta.co.il>. + +See `INSTALL' for instructions to build and install. + +This is free software. See the files COPYING* for copying permissions. + diff --git a/Build/source/texk/contrib/config.h b/Build/source/texk/contrib/config.h new file mode 100644 index 00000000000..aa4a7474013 --- /dev/null +++ b/Build/source/texk/contrib/config.h @@ -0,0 +1,11 @@ +/* config.h: master configuration file, included first by all compilable + source files (not headers). */ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef WIN32 +# include <win32lib.h> +#endif + +#endif /* CONFIG_H */ diff --git a/Build/source/texk/contrib/depend.mak b/Build/source/texk/contrib/depend.mak new file mode 100644 index 00000000000..642d55552f2 --- /dev/null +++ b/Build/source/texk/contrib/depend.mak @@ -0,0 +1,559 @@ +$(objdir)/mktex.obj: \ + stackenv.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + variables.h \ + fileutils.h \ + mktex.h + +$(objdir)/irun.obj: \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/c-vararg.h \ + irun.h + +$(objdir)/pdfdde.obj: \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/getopt.h + +$(objdir)/fmtutil.obj: \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + mktex.h \ + mktexlib.h \ + fileutils.h \ + stackenv.h \ + variables.h \ + fmtutil.h + +$(objdir)/fileutils.obj: \ + fileutils.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + stackenv.h + +$(objdir)/makempx.obj: \ + mktex.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + stackenv.h \ + fileutils.h + +$(objdir)/stackenv.obj: \ + stackenv.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + variables.h + +$(objdir)/mkofm.obj: \ + $(gnuw32dir)/win32lib.h + +$(objdir)/dvihp.obj: \ + mktex.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + stackenv.h + +$(objdir)/variables.obj: \ + stackenv.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + fileutils.h \ + variables.h \ + $(regexdir)/regex.h + +$(objdir)/main.obj: \ + mktex.h \ + mktexlib.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + stackenv.h \ + variables.h \ + fileutils.h + +$(objdir)/mkocp.obj: \ + $(kpathseadir)/kpathsea.h \ + $(kpathseadir)/config.h \ + $(kpathseadir)/c-auto.h \ + $(kpathseadir)/c-std.h \ + $(kpathseadir)/c-unistd.h \ + $(kpathseadir)/systypes.h \ + $(kpathseadir)/c-memstr.h \ + $(kpathseadir)/c-errno.h \ + $(kpathseadir)/c-minmax.h \ + $(kpathseadir)/c-limits.h \ + $(kpathseadir)/c-proto.h \ + $(gnuw32dir)/win32lib.h \ + $(kpathseadir)/debug.h \ + $(kpathseadir)/types.h \ + $(kpathseadir)/lib.h \ + $(kpathseadir)/progname.h \ + $(kpathseadir)/absolute.h \ + $(kpathseadir)/c-ctype.h \ + $(gnuw32dir)/oldnames.h \ + $(kpathseadir)/c-dir.h \ + $(kpathseadir)/c-fopen.h \ + $(kpathseadir)/c-namemx.h \ + $(kpathseadir)/c-pathch.h \ + $(kpathseadir)/c-pathmx.h \ + $(kpathseadir)/c-stat.h \ + $(kpathseadir)/c-vararg.h \ + $(kpathseadir)/cnf.h \ + $(kpathseadir)/concatn.h \ + $(kpathseadir)/db.h \ + $(kpathseadir)/str-list.h \ + $(kpathseadir)/default.h \ + $(kpathseadir)/expand.h \ + $(kpathseadir)/fn.h \ + $(kpathseadir)/fontmap.h \ + $(kpathseadir)/hash.h \ + $(kpathseadir)/getopt.h \ + $(kpathseadir)/line.h \ + $(kpathseadir)/magstep.h \ + $(kpathseadir)/paths.h \ + $(kpathseadir)/pathsearch.h \ + $(kpathseadir)/str-llist.h \ + $(kpathseadir)/proginit.h \ + $(kpathseadir)/readable.h \ + $(kpathseadir)/remote.h \ + $(kpathseadir)/tex-file.h \ + $(kpathseadir)/tex-glyph.h \ + $(kpathseadir)/tex-hush.h \ + $(kpathseadir)/tex-make.h \ + $(kpathseadir)/tilde.h \ + $(kpathseadir)/truncate.h \ + $(kpathseadir)/variable.h \ + $(kpathseadir)/xopendir.h \ + $(kpathseadir)/xstat.h \ + stackenv.h \ + mktexlib.h + diff --git a/Build/source/texk/contrib/depend.mk b/Build/source/texk/contrib/depend.mk new file mode 100644 index 00000000000..d34121b3e2e --- /dev/null +++ b/Build/source/texk/contrib/depend.mk @@ -0,0 +1,155 @@ +# DO NOT DELETE + +$(objdir)/dvihp.obj: dvihp.c stackenv.h mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h \ + fileutils.h +$(objdir)/fileutils.obj: fileutils.c mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h \ + stackenv.h +$(objdir)/fmtutil.obj: fmtutil.c $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h $(kpathsea_srcdir)/c-dir.h \ + $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h $(kpathsea_srcdir)/c-pathch.h \ + $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h $(kpathsea_srcdir)/c-vararg.h \ + $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h $(kpathsea_srcdir)/db.h \ + $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h $(kpathsea_srcdir)/expand.h \ + $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h $(kpathsea_srcdir)/hash.h \ + $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h $(kpathsea_srcdir)/magstep.h \ + $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h $(kpathsea_srcdir)/str-llist.h \ + $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h $(kpathsea_srcdir)/tex-file.h \ + $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h $(kpathsea_srcdir)/tex-make.h \ + $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h $(kpathsea_srcdir)/variable.h \ + $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h fileutils.h mktexlib.h \ + stackenv.h variables.h fmtutil.h +$(objdir)/main.obj: main.c stackenv.h mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h mktex.h \ + stackenv.h +$(objdir)/makempx.obj: makempx.c mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h \ + fileutils.h +$(objdir)/mktex.obj: mktex.c stackenv.h mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h \ + variables.h fileutils.h mktex.h +$(objdir)/stackenv.obj: stackenv.c stackenv.h mktexlib.h $(kpathsea_srcdir)/config.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h $(kpathsea_dir)/c-auto.h \ + $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h $(kpathsea_srcdir)/c-unistd.h \ + $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h $(kpathsea_srcdir)/c-errno.h \ + $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h $(kpathsea_srcdir)/debug.h \ + $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \ + $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h $(kpathsea_srcdir)/c-ctype.h \ + $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h $(kpathsea_srcdir)/c-namemx.h \ + $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h $(kpathsea_srcdir)/c-stat.h \ + $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h $(kpathsea_srcdir)/concatn.h \ + $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h $(kpathsea_srcdir)/default.h \ + $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h $(kpathsea_srcdir)/fontmap.h \ + $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h $(kpathsea_srcdir)/line.h \ + $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h $(kpathsea_srcdir)/pathsearch.h \ + $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h $(kpathsea_srcdir)/readable.h \ + $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h $(kpathsea_srcdir)/tex-hush.h \ + $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h $(kpathsea_srcdir)/truncate.h \ + $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h $(kpathsea_srcdir)/xstat.h \ + variables.h +$(objdir)/variables.obj: variables.c stackenv.h mktexlib.h \ + $(kpathsea_srcdir)/config.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/win32lib.h \ + $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/c-std.h \ + $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h $(kpathsea_srcdir)/c-memstr.h \ + $(kpathsea_srcdir)/c-errno.h $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \ + $(kpathsea_srcdir)/debug.h $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h \ + $(kpathsea_srcdir)/progname.h $(kpathsea_srcdir)/kpathsea.h $(kpathsea_srcdir)/absolute.h \ + $(kpathsea_srcdir)/c-ctype.h $(kpathsea_srcdir)/c-dir.h $(kpathsea_srcdir)/c-fopen.h \ + $(kpathsea_srcdir)/c-namemx.h $(kpathsea_srcdir)/c-pathch.h $(kpathsea_srcdir)/c-pathmx.h \ + $(kpathsea_srcdir)/c-stat.h $(kpathsea_srcdir)/c-vararg.h $(kpathsea_srcdir)/cnf.h \ + $(kpathsea_srcdir)/concatn.h $(kpathsea_srcdir)/db.h $(kpathsea_srcdir)/str-list.h \ + $(kpathsea_srcdir)/default.h $(kpathsea_srcdir)/expand.h $(kpathsea_srcdir)/fn.h \ + $(kpathsea_srcdir)/fontmap.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/getopt.h \ + $(kpathsea_srcdir)/line.h $(kpathsea_srcdir)/magstep.h $(kpathsea_dir)/paths.h \ + $(kpathsea_srcdir)/pathsearch.h $(kpathsea_srcdir)/str-llist.h $(kpathsea_srcdir)/proginit.h \ + $(kpathsea_srcdir)/readable.h $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/tex-glyph.h \ + $(kpathsea_srcdir)/tex-hush.h $(kpathsea_srcdir)/tex-make.h $(kpathsea_srcdir)/tilde.h \ + $(kpathsea_srcdir)/truncate.h $(kpathsea_srcdir)/variable.h $(kpathsea_srcdir)/xopendir.h \ + $(kpathsea_srcdir)/xstat.h fileutils.h variables.h \ + $(root_srcdir)/libs/regex-0.12/regex.h diff --git a/Build/source/texk/contrib/dvihp.c b/Build/source/texk/contrib/dvihp.c new file mode 100644 index 00000000000..e595f734d16 --- /dev/null +++ b/Build/source/texk/contrib/dvihp.c @@ -0,0 +1,433 @@ +/* dvihp.c: emulate the dvihp shell script + + Converted to C by Eli Zaretskii <eliz@is.elta.co.il> + Adapted to Win32 by Fabrice POPINEAU + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "mktex.h" +#include "stackenv.h" + +static const char rcs_id[] = + "$Id: dvihp.c,v 1.7 2002/10/06 14:02:09 olaf Exp $"; +static char rcs_revision[] = "$Revision: 1.7 $"; + +static void usage (void) +{ + printf ("Usage: %s [OPTIONS] [DVIFILE[.dvi]].\n\ + Translate the given DVIFILE to Hewlett-Packard PCL by calling dvicopy\n\ + and then $DVILJ (dvilj4 by default).\n\ + In the absence of other options, pipe the PCL to $SPOOL (lpr by default).\n\ +\n\ + Options are recognized from dvips where possible:\n\ +-A print odd pages\n\ +-B print even pages\n\ +-d # set debug bits to # (see documentation)\n\ +-D # set resolution to #\n\ +-f run as filter\n\ +-l # don't print pages after #\n\ +-m manual feed\n\ +-n # print # pages\n\ +-O #,# set/change paper offset to #,# mm\n\ +-o s output to s instead of spooling\n\ +-p # don't print pages before #\n\ +-Ps pass directly to lpr\n\ +-v verbose operation\n\ +-x # set magnification to #\n\ +\n\ +Other options are passed to the dvilj program.\n\ +\n\ +Email bug reports to tex-k@mail.tug.org.\n", program_invocation_short_name); + fflush (stdout); +} + +/* Emulate `rm -f prefix*' */ + +void rmfiles (const_string prefix) +{ +#ifdef _WIN32 + /* Win32 doesn't have POSIX dirent functions. */ + WIN32_FIND_DATA ffd; + HANDLE hnd; + boolean go_on; + string temp = concat (prefix, "*"); + string directory = xdirname (prefix); + + pushd (directory); + hnd = FindFirstFile(temp, &ffd); + go_on = (hnd != INVALID_HANDLE_VALUE); + while (go_on) { + /* FIXME: can this remove read-only files also, like rm -f does? */ + DeleteFile(ffd.cFileName); + go_on = (FindNextFile(hnd, &ffd) == TRUE); + } + FindClose(hnd); + free(temp); + popd (); +#else /* not _WIN32 */ + DIR *dp; + struct dirent *de; + int temp_len = strlen (prefix); + string directory = "./"; + const_string base = xbasename (prefix); + + /* Copy the directory part of PREFIX with the trailing slash, if any. */ + if (base != prefix) + { + directory = (string) xmalloc (base - prefix + 1); + directory[0] = '\0'; + strncat (directory, prefix, base - prefix); + } + + /* Find matching files and delete them. */ + if ((dp = opendir (directory)) != 0) { + while ((de = readdir (dp)) != 0) + { + string found = concat (directory, de->d_name); + + if (FILESTRNCASEEQ (found, prefix, temp_len)) + /* On POSIX-compliant systems, including DJGPP, this will also + remove read-only files and empty directories, like rm -f does. */ + if (remove (found)) + perror (found); + free (found); + } + } +#endif /* not _WIN32 */ +} + +void __cdecl output_and_cleanup(int code) +{ + /* FIXME : what cleanup should be done ? */ +} + +int +main (int argc, char *argv[]) +{ + string opt = (string) xmalloc (1); + string output = "", infile = ""; + string output_opt = " -e"; + string dvilj; + string spool; + string tmpdir; + string spool_opt = ""; + char template[PATH_MAX]; + string vfless_dvi, dvicopy_log, dvilj_log; + int verbose = 0; + string cmdline, maybe_spool_cmd = ""; + const_string space = " "; + + output_and_cleanup_function = output_and_cleanup; + + progname = argv[0]; + kpse_set_progname (progname); + +#ifdef _WIN32 + SetConsoleCtrlHandler((PHANDLER_ROUTINE)mt_exit, TRUE); +#else +# ifdef SIGINT + signal (SIGINT, sigint_handler); +# endif +# ifdef SIGQUIT + signal (SIGQUIT, sigint_handler); +# endif +# ifdef SIGHUP + signal (SIGHUP, sigint_handler); +# endif +# ifdef SIGTERM + signal (SIGTERM, sigint_handler); +# endif +#endif + + dvilj = kpse_var_value ("DVILJ"); + spool = kpse_var_value ("SPOOL"); + tmpdir = kpse_var_value ("TMPDIR"); + opt[0] = '\0'; + + /* Set default values for variables: + + ${DVILJ=dvilj4} the dvilj variant to run + ${SPOOL=lpr} used to print an LJ file + ${TMPDIR=/tmp} for the dvicopy output */ + if (!dvilj || !*dvilj) + dvilj = "dvilj4"; + if (!spool || !*spool) + { +#ifdef __DJGPP__ + /* Feature: if they don't have LPR installed, make the + default be to print to the local printer device. */ + char lpr_path[PATH_MAX]; + extern char *__dosexec_find_on_path (const char *, char **, char *); + extern char **environ; + + if (!__dosexec_find_on_path ("lpr", (char **)0, lpr_path) + && !__dosexec_find_on_path ("lpr", environ, lpr_path)) + spool = "> PRN"; + else +#endif + spool = "| lpr"; + } + + if (!tmpdir || !*tmpdir) + { + tmpdir = "/tmp"; + if (access (tmpdir, R_OK|W_OK) != 0) + { + mkdir (tmpdir, 0755); +#ifdef DOSISH + if (access (tmpdir, R_OK|W_OK) != 0) + { + /* Maybe this is a read-only filesystem (CD-ROM)? */ + tmpdir = "c:/tmp"; + mkdir (tmpdir, 0755); /* in case they don't have it */ + } +#endif + } + } + + if (argc <= 1) + { + fprintf (stderr, "%s: Missing argument(s).\nTry `%s --help' for more information.\n", + program_invocation_short_name, program_invocation_short_name); + return 0; + } + + while (--argc) + { + char *arg = *++argv; + + if (STREQ (arg, "-help") || STREQ (arg, "--help")) + { + usage (); + return 0; + } + else if (STREQ (arg, "-version") || STREQ (arg, "--version")) + { + printf ("%s: (Dviljk 2.6) %s\nThere is NO warranty. This program is public domain.\n", + program_invocation_short_name, rcs_revision); + return 0; + } + else if (arg[0] == '-') + { + string newopt = NULL; + + switch (arg[1]) + { + case 'A': /* -A => -D1 (odd pages) */ + newopt = concat (opt, " -D1"); + break; + case 'B': /* -B -> -D2 (even pages) */ + newopt = concat (opt, " -D2"); + break; + case 'd': /* -d => --D (debug) */ + if (arg[2] == '\0') + { + argc--; + newopt = concat3 (opt, " --D", *++argv); + } + else + newopt = concat3 (opt, " --D", arg + 2); + break; + case 'D': /* -D => -R (resolution) */ + argc--; + newopt = concat3 (opt, " -R", *++argv); + break; + case 'f': /* -f (run as filter) */ + infile = ""; + output = "-"; + break; + case 'l': /* -l => -t (ending page) */ + if (arg[2] == '\0') + { + argc--; + newopt = concat3 (opt, " -t", *++argv); + } + else + newopt = concat3 (opt, " -t", arg + 2); + break; + case 'm': /* -m => -A (manual feed) */ + newopt = concat (opt, " -A"); + break; + case 'n': /* -n => -p (page count) */ + if (arg[2] == '\0') + { + argc--; + newopt = concat3 (opt, " -t", *++argv); + } + else + newopt = concat3 (opt, " -t", arg + 2); + break; + case 'o': /* -o (output file) */ + { + string inbase = xstrdup (xbasename (infile)); + if (argc == 1 && *inbase) + { + /* No remaining args, output to foo.lj. */ + int inbaselen = strlen (inbase); + + if (FILESTRCASEEQ (inbase + inbaselen - 4, ".dvi")) + output = strcpy (inbase + inbaselen - 4, ".lj"); + else + { +#if defined (MSDOS) && defined _PC_NAME_MAX + if (pathconf (infile, _PC_NAME_MAX) <= 12) + { + /* Plain MS-DOS (not Windows 95), can't have + more than a single dot in a filename. */ + char *dot = strchr (inbase, '.'); + + if (dot) + *dot = '\0'; + } +#endif + output = concat (inbase, ".lj"); + free (inbase); + } + } + else if (arg[2] == '\0') + { + argc--; + output = *++argv; + } + else + output = arg + 2; + break; + } + case 'O': /* -O => -x, -y (page offsets) */ + { + int x_len; + char *params = arg + 2; + char *x; + + if (arg[2] == '\0') + { + argc--; + params = *++argv; + } + + x_len = strcspn (params, ","); + x = (char *)xmalloc (x_len + 1); + x[0] = '\0'; + strncat (x, params, x_len); + if (params[x_len] == ',') + x_len++; /* get past the comma, if any */ + newopt = concatn (opt, " -x", x, " y", params + x_len, NULL); + break; + } + case 'p': /* -p => -f (starting page) */ + if (arg[2] == '\0') + { + argc--; + newopt = concat3 (opt, " -f", *++argv); + } + else + newopt = concat3 (opt, " -f", arg + 2); + break; + case 'P': /* -Pprinter */ + output = ""; + if (spool[0] == '>') /* direct printing: replace device */ + spool = concat ("> ", arg[2] ? arg + 2 : *++argv); + else + spool_opt = concat ("-P", arg[2] ? arg + 2 : *++argv); + if (arg[2] == '\0') + argc--; + break; + case 'v': /* verbose */ + verbose = 1; + newopt = concat (opt, " -v"); + break; + case 'x': /* -x => -m (magnification) */ + if (arg[2] == '\0') + { + argc--; + newopt = concat3 (opt, " -m", *++argv); + } + else + newopt = concat3 (opt, " -m", arg + 2); + break; + case '-': /* -- => end of options */ + argc--; + infile = *++argv; + break; + default: /* pass other options through */ + newopt = concat3 (opt, space, arg); + break; + } + + if (newopt) + { + free (opt); + opt = newopt; + } + } + else + infile = arg; + } + + /* Generate temporary filenames. Assumes PID is 5 digits. */ + sprintf (template, "%s/dvi%5.5d.", tmpdir, getpid ()); + vfless_dvi = concat (template, "-vf"); + /* FIXME: where are these two used? */ + dvicopy_log = concat (template, "copy"); + dvilj_log = concat (template, "lj"); + + /* Expand VF references. + If INFILE is null, this will read standard input. + dvilj can't read from a pipe, so always write to a file. */ + if (verbose) + fprintf (stderr, "Running dvicopy %s >%s\n", infile, vfless_dvi); + + /* FIXME: special characters in filenames aren't protected from the shell. */ + cmdline = concatn ("dvicopy ", infile, " >", vfless_dvi, NULL); + if (system (cmdline)) + { + fprintf (stderr, "%s: dvicopy %s failed.\n", progname, infile); + return 1; + } + free (cmdline); + + if (verbose) + { + struct stat st_buf; + + if (stat (vfless_dvi, &st_buf)) + perror (vfless_dvi); + else /* assume they only want to see the size and timestamp */ + fprintf (stderr, " %ld %s %s\n", + (long)st_buf.st_size, ctime (&st_buf.st_mtime), vfless_dvi); + } + if (!*output) + { + output = "-"; /* output to stdout */ + maybe_spool_cmd = concat (spool, spool_opt); + } + + /* Translate DVI to LJ. */ + cmdline = concatn (dvilj, space, opt, output_opt, output, + space, vfless_dvi, space, maybe_spool_cmd, NULL); + if (verbose) + fprintf (stderr, "Running %s\n", cmdline); + if (system (cmdline)) + { + fprintf (stderr, "%s: %s failed.\n", progname, dvilj); + return 2; + } + + /* rm -f $TMPDIR/dvi$$.* */ + rmfiles (template); + + return 0; +} diff --git a/Build/source/texk/contrib/dvihp.rc b/Build/source/texk/contrib/dvihp.rc new file mode 100644 index 00000000000..1ad4f54943b --- /dev/null +++ b/Build/source/texk/contrib/dvihp.rc @@ -0,0 +1,35 @@ +/* dvihp.rc: dvihp resources -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " dvihp 1.7" + +#define VER_INTERNALNAME_STR "Dvihp" +#define VER_ORIGINALFILENAME_STR "dvihp.exe" + +#define VER_LEGALCOPYRIGHT_STR " Copyright (c) 1996-1997 by Eli Zaretskii." + +#define VER_FILEDESCRIPTION_STR "Driver for DviLJ programs" + +#include <texlive.version> + +/* dvihp.rc ends here */ diff --git a/Build/source/texk/contrib/fileutils.c b/Build/source/texk/contrib/fileutils.c new file mode 100644 index 00000000000..cfd9e3b0db2 --- /dev/null +++ b/Build/source/texk/contrib/fileutils.c @@ -0,0 +1,561 @@ +/* stackenv.c: routines that help to deal with files and directories. + +Copyright (C) 1997 Fabrice POPINEAU. + +Adapted to DJGPP by Eli Zaretskii. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "fileutils.h" + +/* A few utility functions shared by both mktex and makempx. */ + +int mt_append_mask = 0; + +/* Execute a command, much like system() but using popen() */ +int +execute_command(string cmd) +{ + int retcode = 0; + FILE *fcmd = NULL; + if ((fcmd = popen(cmd, "r")) == NULL) + return -1; + retcode = pclose(fcmd); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "executing %s => %d\n", cmd, retcode); + } + return retcode; +} + +/* Copy a file, appending if required. */ + +int catfile (const char *from, const char *to, int append) +{ + FILE *finp, *fout; + unsigned char buf[16*1024]; + int rbytes; + + finp = fopen (from, "rb"); + if (!finp) + return FALSE; + fout = fopen (to, append ? "ab" : "wb"); + if (!fout) { + fclose (finp); + return FALSE; + } + + while ((rbytes = fread (buf, 1, sizeof buf, finp)) > 0) { + int wbytes = fwrite (buf, 1, rbytes, fout); + + if (wbytes < rbytes) { + if (wbytes >= 0) + fprintf (stderr, "%s: disk full\n", to); + fclose (finp); + fclose (fout); + unlink (to); + return FALSE; + } + } + + fclose (finp); + fclose (fout); + return TRUE; +} + +/* Move a file using rename if possible, copy if necessary. */ + +int mvfile (const char *from, const char *to) +{ + int e = errno; + int retval = TRUE; + char errstring[PATH_MAX*4]; + + errno = 0; + if (rename (from, to) == 0) { + errno = e; + return TRUE; + } + +#ifndef DOSISH + /* I don't want to rely on this on DOSISH systems. First, not all + of them know about EXDEV. And second, DOS will fail `rename' + with EACCES when the target is more than 8 directory levels deep. */ + if (errno != EXDEV) + retval = FALSE; + else +#endif + + /* `rename' failed on cross-filesystem move. Copy, then delete. */ + if (catfile (from, to, 0) == FALSE) + retval = FALSE; + else + unlink (from); /* ignore possible errors */ + + /* Simulate error message from `mv'. */ + if (retval == FALSE) { + sprintf(errstring, "%s: can't move %s to %s", kpse_program_name, from, to); + perror(errstring); + } + + if (!errno) + errno = e; + return retval; +} + +/* Like the test function from Unix */ + +boolean test_file(int c, string path) +{ + struct stat stat_buf; + boolean file_exists; + + if (c == 'z') + return (path == NULL || *path == '\0'); + + if (c == 'n') + return (path != NULL && *path != '\0'); + +#ifdef WIN32 + /* Bug under W95 */ + if (c == 'd') + return dir_p(path); +#endif + + file_exists = (stat(path, &stat_buf) != -1); + +#ifdef DOSISH + /* When they say "test -x foo", make so we find "foo.exe" etc. */ + if (c == 'x' && !file_exists) + { + static string try_ext[] = { + ".exe", + ".bat", + ".cmd", + ".btm", + 0 + }; + string *p = try_ext; + + while (p) + { + string try = concat(path, *p++); + if (stat(try, &stat_buf) != -1) + { + file_exists = 1; + free(try); + break; + } + free(try); + } + } +#endif + + if (!file_exists) return FALSE; + switch (c) { + case 'd': + return ((stat_buf.st_mode & S_IFMT) == S_IFDIR); + case 'e': + case 'r': + return TRUE; + case 'f': + return ((stat_buf.st_mode & S_IFMT) == S_IFREG); + case 's': + return (stat_buf.st_size > 0); + case 'x': + return ((stat_buf.st_mode & S_IFMT) == S_IFREG + && (stat_buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))); + case 'w': + { + return ( +#ifdef DOSISH + /* DOSISH systems allow to create files in read-only + directories, and `is_writable' knows about that. So we + artificially look at the write bit returned by `stat' + and refuse to write in read-only directories. */ + (stat_buf.st_mode & S_IWUSR) != 0 && +#endif + is_writable(path)); + } + default: + return FALSE; + } +} + +#ifdef _WIN32 + +boolean is_writable(string path) +{ + DWORD dw; + char tmppath[PATH_MAX*2]; + int writable; + + /* Test 2 cases: directory or file */ + if ((dw = GetFileAttributes(path)) == 0xFFFFFFFF) { + /* Invalid Path, not writable */ + writable = false; + errno = ENOENT; /* like `access' does */ + } + else if (dw & FILE_ATTRIBUTE_READONLY) { + writable = false; + } + else if (dw & FILE_ATTRIBUTE_DIRECTORY) { + /* Trying to open a file */ + if (GetTempFileName(path, "foo", 0, tmppath) == 0) { + writable = false; + } + else { + writable = true; + } + DeleteFile(tmppath); + } + else { + writable = true; + } + return writable; +} + +#else /* !_WIN32 */ + +boolean is_writable(string path) +{ + if (!path || !*path) /* like `access' called with empty variable as arg */ + return false; +#ifdef MSDOS + /* Directories always return as writable, even on read-only filesystems + such as CD-ROMs or write-protected floppies. Need to try harder... */ + if (access(path, D_OK) == 0) { + /* Use a unique file name. */ + string template = concat3(path, "/", "wrXXXXXX"); + int fd; + + if (mktemp(template) && (fd = creat(template, S_IRUSR | S_IWUSR)) >= 0) { + close(fd); + unlink(template); + free(template); + return true; + } + + free(template); + + /* Simulate errno from `access'. */ +#ifdef EROFS + errno = EROFS; /* POSIX platforms should have this */ +#else + errno = EACCES; +#endif + return false; + } + else +#endif /* MSDOS */ + return access(path, W_OK) == 0 ? true : false; +} + +#endif /* !_WIN32 */ + +/* + Recursive walk through the directory tree. Depth-first order. +*/ +void recurse_dir(string path, execfn before, execfn after) +{ + /* In depth traversal of the subdir tree */ +#if defined(_WIN32) + WIN32_FIND_DATA find_file_data; + HANDLE hnd; +#else + DIR *dp; + struct dirent *ep; +#endif + struct stat stat_buf; /* We have to have one local because + of after */ + + int path_len = strlen(path); + + /* current node */ + if (stat(path, &stat_buf)) + perror(path); + + /* execute before for the current node */ + if (before) + (*before)(path, &stat_buf); + + /* if it is a directory, recurse through all sons */ + if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) { +#if defined(_WIN32) + strcat(path, "/*"); + hnd = FindFirstFile(path, &find_file_data); + while (hnd != INVALID_HANDLE_VALUE && + FindNextFile(hnd, &find_file_data) != FALSE) { + if(!strcmp(find_file_data.cFileName, ".") + || !strcmp(find_file_data.cFileName, "..")) + continue; + path[path_len+1] = '\0'; + strcat(path, find_file_data.cFileName); + recurse_dir(path, before, after); + } + path[path_len] = '\0'; + FindClose(hnd); +#else + if ((dp = opendir(path))) { + while ((ep = readdir(dp))) + if (strcmp(ep->d_name, ".") && + strcmp(ep->d_name, "..")) { + path[path_len] = '/'; + strcpy(path+path_len+1, ep->d_name); + recurse_dir(path, before, after); + } + path[path_len] = '\0'; + closedir(dp); + } + else + perror(path); +#endif + } + /* execute after for the current node */ + if (after) + (*after)(path, &stat_buf); +} + +void do_rmdir(string path) +{ + static char name[PATH_MAX]; + strcpy(name,path); + + if (test_file('d', path)) { + recurse_dir(name, NULL, remove_path); + } + else + unlink(path); +} + +/* Recursively destructs files & directories from path. */ +void rec_rmdir(string path) +{ + string p; + + for(p=path+strlen(path)-1; IS_DIR_SEP(*p) && (p > path) ; p--) { + *p = '\0'; + } + do_rmdir(path); +} + +/* Creates path, and all intermediate directories if necessary. */ + +int do_makedir(string path) +{ + struct stat stat_buf; + string p = path; + mode_t dir_perms = 0777 & ~umask (0); /* default permissions for `mkdir' */ + mode_t parent_perms = 0; + + /* We can't authorize multiple slashes here */ + normalize(path); + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Creating directory: %s\n", path); + } + + if (stat(path, &stat_buf) == 0 && + (stat_buf.st_mode & S_IFMT) == S_IFDIR) + return 0; /* The path already exists */ + +#ifdef WIN32 + /* Handling of UNC names */ + if (IS_UNC_NAME(path)) { + /* UNC pathname : \\server\dir\... + We must begin at the third component. + Name is normalized, so only '/' as dir sep. + */ + p = strchr(path+3, '/'); + if (!p) { + /* invalid pathname */ + return ENOTDIR; + } + p = strchr(p+1, '/'); + if (!p) { + /* invalid pathname */ + return ENOTDIR; + } + p++; + } + else { + if (NAME_BEGINS_WITH_DEVICE(path)) { + p = path+2; + } + if (IS_DIR_SEP(*p)) + p++; + } +#else + /* Finding the [drive letter][:] */ + if (IS_DEVICE_SEP(*(p+1))) + p +=2; + + if (IS_DIR_SEP(*p)) + p++; +#endif + for ( ; *p ; p++) { + if (IS_DIR_SEP(*p)) { + *p = '\0'; + errno = 0; + if (!test_file('d', path)) { + if ((mkdir(path, dir_perms) == -1)) { + return errno; + } else if (parent_perms == 0 && errno == 0) { + /* The first time we actually create a directory, remember the + permission bits of its parent. */ + string parent = concat(path, "/.."); + + if (stat(parent, &stat_buf) == 0) { + parent_perms = stat_buf.st_mode; + /* Use the correct bits from now on. */ + dir_perms = parent_perms | mt_append_mask; + } + free(parent); + } + /* chmod the directory we just created. */ + chmod(path, dir_perms); + } + *p = DIR_SEP; + } + } + /* and for the whole path */ + if (mkdir(path, dir_perms) == -1) { + return errno; + } + chmod(path, dir_perms); + + return 0; +} + +/* remove something which already exists */ +void remove_path(string path, struct stat* st) +{ + int e = errno; + + if ((st->st_mode & S_IFMT) == S_IFDIR) { + errno = 0; + if (rmdir(path) == -1 && errno == EBUSY) { + /* `rmdir' will fail (at least on MS-DOS) if PATH is the current + working directory on another drive, or the parent of the + working directory. To work around that, we chdir to the root + of that drive, then try to rmdir again. */ + char drv_root[4], *p = drv_root; + + if (path[0] && path[1] == ':') { + *p++ = path[0]; + *p++ = path[1]; + } + *p++ = '/'; + *p = '\0'; + pushd(drv_root); + if (rmdir(path) == 0) { + errno = e; + popd(); + return; + } + } + else if (errno) + perror(path); + else + errno = e; + } + else { + if (unlink(path) == -1) + perror(path); + } +} + +/* + Rewrite path with the same DIR_SEP and deleting multiple ones + FIXME: does this eliminates the trailing ones ? W95 doesn't grok + stat() on pathes that end up in PATH_SEP. + */ +char *normalize(string path) +{ + string p, q; + int offset = 0; + + /* Be safe */ + if (path == NULL) return path; + + /* Delete any multiple slashes, except leading ones on WIN32 (UNC names) */ +#ifdef WIN32 + if (IS_UNC_NAME(path)) { + path[0] = path[1] = DIR_SEP; + offset = 2; + } +#endif + for ( p = q = path+offset; *p != '\0'; p++, q++) { + *q = (IS_DIR_SEP(*p) ? DIR_SEP : *p); + if (IS_DIR_SEP(*p)) + while (*(p+1) && IS_DIR_SEP(*(p+1))) p++; + } + *q = '\0'; + + return path; +} + + +/* Smart concatenation of 2 pathes: add the separator only + when needed. Allocates a new path. */ +string concat_pathes(const_string p1, const_string p2) +{ + string res; + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Concat pathes %s and %s\n", p1, p2); + } + + assert (p1 && p2); + + res = normalize(concat3(p1, DIR_SEP_STRING, p2)); + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "\t=> %s\n", res); + } + + return res; +} + +/* + Kpathsea's basename does not strip suffixes + */ +string my_basename(string name, string suffix) +{ + string res = (string)xbasename(name); + if (suffix) { + int suffix_len = strlen(suffix); + if (FILESTRCASEEQ(res+strlen(res)-suffix_len, suffix)) + *(res+strlen(res)-suffix_len) = '\0'; + } + return xstrdup(res); +} + +#if 0 +/* + Kpathsea's kpse_find_file() is not parametrized by '--progname'. + This is an attempt to do that. + */ + +/* The path spec we are defining, one element of the global array. */ +#define FMT_INFO kpse_format_info[format] +/* Call add_suffixes. */ +#define SUFFIXES(args) add_suffixes(&FMT_INFO.suffix, args, NULL) +#define ALT_SUFFIXES(args) add_suffixes (&FMT_INFO.alt_suffix, args, NULL) + +/* Call `init_path', including appending the trailing NULL to the envvar + list. Also initialize the fields not needed in setting the path. */ +#define INIT_FORMAT(text, default_path, envs) \ + FMT_INFO.type = text; \ + init_path (&FMT_INFO, default_path, envs, NULL) +#endif diff --git a/Build/source/texk/contrib/fileutils.h b/Build/source/texk/contrib/fileutils.h new file mode 100644 index 00000000000..a09eeb569db --- /dev/null +++ b/Build/source/texk/contrib/fileutils.h @@ -0,0 +1,26 @@ +#ifndef _FILEUTILS_H_ + +#define _FILEUTILS_H_ + +#include "mktexlib.h" +#include "stackenv.h" + + +/* Type of function to execute */ +typedef void (*execfn)(string, struct stat*); + +extern MKTEXDLL void recurse_dir(string, execfn, execfn); +extern MKTEXDLL void do_rmdir(string); +extern MKTEXDLL void rec_rmdir(string); +extern MKTEXDLL int do_makedir(string); +extern MKTEXDLL void remove_path(string, struct stat*); +extern MKTEXDLL int mvfile(const char *, const char *); +extern MKTEXDLL int catfile(const char *, const char *, int); +extern MKTEXDLL boolean test_file(int, string); +extern MKTEXDLL boolean is_writable(string); +extern MKTEXDLL int execute_command(string); +extern MKTEXDLL char *normalize(char *path); +extern MKTEXDLL char *my_basename(char *name,char *suffix); +extern MKTEXDLL char *concat_pathes(const char *p1,const char *p2); + +#endif /* _FILEUTILS_H_ */ diff --git a/Build/source/texk/contrib/fmtutil.c b/Build/source/texk/contrib/fmtutil.c new file mode 100644 index 00000000000..0012d754ef2 --- /dev/null +++ b/Build/source/texk/contrib/fmtutil.c @@ -0,0 +1,1312 @@ +/* fmtutil.c: this program emulates the fmtutil shell script from tetex. + +Copyright (C) 1998 Fabrice POPINEAU. + +Time-stamp: <04/03/20 16:03:00 popineau> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Maximum number of lines per usage message. */ +#define MAX_LINES 32 + +#define SEPARATORS " \t\n\"" + +#include <signal.h> + +#include <kpathsea/kpathsea.h> +extern KPSEDLL char* kpathsea_version_string; + +#include "mktex.h" +#include "fileutils.h" +#include "stackenv.h" +#include "variables.h" +#include "fmtutil.h" + +#ifdef _WIN32 +#define isatty _isatty +#else +#include <glob.h> +#endif + +extern string fmtutil_version_string; + +/* + Global Variables found in the fmtutil script +*/ + +static string texmfmain; +static string tempenv; +static string cwd; + +static string mode, bdpi; + +/* fmtutil.cnf */ + +static boolean downcase_names; +char cmd_buf[1024]; /* Hope it is enough for handling command */ +char cmd_sys[1024]; /* system() calls */ +char msg_buf[1024]; + +static int errstatus; +static string log_failure_msg = NULL; + +static void usage(void); + +/* Test whether getopt found an option ``A''. + Assumes the option index is in the variable `option_index', and the + option table in a variable `long_options'. */ +#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a) + +static struct option long_options [] = { + { "all", 0, 0, 0}, + { "quiet", 0, 0, 0}, + { "test", 0, 0, 0}, + { "force", 0, 0, 0}, + { "dolinks", 0, 0, 0}, + { "missing", 0, 0, 0}, + { "byfmt", 1, 0, 0}, + { "byhyphen", 1, 0, 0}, + { "enablefmt", 1, 0, 0}, + { "disablefmt", 1, 0, 0}, + { "listcfg", 1, 0, 0}, + { "showhyphen", 1, 0, 0}, + { "edit", 0, 0, 0}, + { "help", 0, 0, 0}, + { "cnffile", 1, 0, 0}, + { "fmtdir", 1, 0, 0}, + { "debug", 1, 0, 0}, + {0, 0, 0, 0} +}; + +enum { + NONE, ALL, MISSING, BYFMT, BYHYPHEN, + ENABLEFMT, DISABLEFMT, LISTCFG, SHOWHYPHEN, EDIT +}; + +#define MAX_FMTS 128 + +typedef struct fmtdesc { + string format; /* e.g.: latex.fmt */ + string shortformat; /* e.g.: latex */ + string engine; /* e.g.: tex */ + string progname; /* e.g.: latex */ + string hyphenation; /* e.g.: - */ + string texargs; + string inifile; + string inifile_short; /* remember it */ + string pool; + string poolbase; + string tcx; + string tcxoption; +} fmtdesc; + +static fmtdesc fmts[MAX_FMTS]; +static int nb_formats = 0; + +string unrmable_engines[] = { + "tex", "pdftex", "etex", "pdfetex", "omega", "eomega", "aleph", "mf", "mpost", NULL +}; + +/* + First argument takes progname; + Other arguments take no arguments. + */ +static string usage_msg[][MAX_LINES] = { + { + "Usage: fmtutil [option] ... command\n\n", + "Valid options:\n", + " --cnffile file\n", + " --fmtdir directory\n", + " --debug=<n> set debug level to n\n", + " --quiet no output except error messages\n", + " --test only print what would be done\n", + " --dolinks link engine to format\n\n", + " --force force links even if target exists\n\n", + "Valid commands:\n", + " --all recreate all format files\n", + " --missing create all missing format files\n", + " --byfmt formatname (re)create format for `formatname'\n", + " --byhyphen hyphenfile (re)create formats that depend on `hyphenfile'\n", + " --enablefmt formatname enable `formatname' in config file\n", + " --disablefmt formatname disable formatname in config file\n", + " --listcfg list (enabled and disabled) configurations\n", + " --showhyphen formatname print name of hyphenfile for format `formatname'\n", + " --edit edit fmtutil.cnf file\n", + " --version display version information\n", + " --help show this message\n", + 0 + }, + { + "Usage: mktexfmt [[option] format.ext | command]\n\n", + "Valid options:\n", + " --debug=<n> set debug level to n\n", + " --quiet no output except error messages\n", + " --test only print what would be done\n", + " --dolinks link engine to format\n\n", + " --force force links even if target exists\n\n", + "Valid commands:\n", + " --version display version information\n", + " --help show this message\n", + 0 + } +}; + +static string fmtutil_version_string = "Revision: 0.40"; + +static string cnf_default = "fmtutil.cnf"; +static string cnf_file = NULL; +static string arg = NULL; +static string destdir = NULL; +static int cmd= NONE; +static boolean quiet = false; +static boolean norebuild = false; +static boolean dolinks = false; +static boolean force = false; +static enum { FMTUTIL, MKTEXFMT, LAST_PROGRAM } incarnation = FMTUTIL; + +#define MAX_LINKS 128 + +struct _links { + string src; + string dst; +} to_link[MAX_LINKS]; +int nb_links = 0; + +void link_formats(); + +void log_failure(string msg) +{ + if (log_failure_msg == NULL) { + log_failure_msg = xstrdup(msg); + } + else { + string tmp = log_failure_msg; + log_failure_msg = concat(log_failure_msg, msg); + free(tmp); + } +} + +/* + First part: fmtutil.opt + */ +int fmtutil_opt(int argc, char *argv[]) +{ + int g; /* getopt return code */ + int i; + int option_index; + + for(;;) { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') + return 1; /* Unknown option. */ + + /* assert (g == 0); */ /* We have no short option names. */ + + if (ARGUMENT_IS ("debug")) { + kpathsea_debug |= atoi (optarg); + } + else if (ARGUMENT_IS ("quiet")) { + quiet = true; + } + else if (ARGUMENT_IS ("test")) { + norebuild = true; + } + else if (ARGUMENT_IS ("dolinks")) { + dolinks = true; + } + else if (ARGUMENT_IS ("force")) { + force = true; + } + else if (ARGUMENT_IS ("help")) { + usage(); + exit(0); + } + else if (ARGUMENT_IS ("version")) { + fprintf(stderr, "%s (version %s) of %s.\n", progname, + fmtutil_version_string, + kpathsea_version_string); + exit(0); + } + else if (incarnation == MKTEXFMT) { + /* no othe options */ + } + else if (incarnation == FMTUTIL) { + if (ARGUMENT_IS("all")) { + cmd = ALL; + } + else if (ARGUMENT_IS("missing")) { + cmd = MISSING; + } + else if (ARGUMENT_IS("byfmt")) { + cmd = BYFMT; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("byhyphen")) { + cmd = BYHYPHEN; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("enablefmt")) { + cmd = ENABLEFMT; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("disablefmt")) { + cmd = DISABLEFMT; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("listcfg")) { + cmd = LISTCFG; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("showhyphen")) { + cmd = SHOWHYPHEN; + arg = xstrdup(optarg); + } + else if (ARGUMENT_IS("edit")) { + cmd = EDIT; + } + else if (ARGUMENT_IS("cnffile")) { + cnf_file = xstrdup(optarg); + } + else if (ARGUMENT_IS("fmtdir")) { + destdir = xstrdup(optarg); + } + } + } + + if (incarnation == MKTEXFMT) { + cmd = BYFMT; + if (optind < argc) { + string ext = NULL; + /* Make `mktexfmt <format.ext>' equivalent to `fmtutil --byfmt=<format>' */ + cmd = BYFMT; + arg = xstrdup(xbasename(argv[optind++])); + /* remove any extension */ + ext = strrchr(arg, '.'); + if (ext) *ext = '\0'; + } + } + + /* shifting options from argv[] list */ + for (i = 1; optind < argc; i++, optind++) + argv[i] = argv[optind]; + argv[i] = NULL; + + argc = i; + + if (argc > 1) { + fprintf(stderr, "%s: Extra arguments", progname); + fprintf (stderr, "\nTry `%s --help' for more information.\n", + kpse_program_name); + exit(1); + } + + if (argc == 0 || cmd == NONE) { + fprintf(stderr, "%s: Missing arguments", progname); + fprintf (stderr, "\nTry `%s --help' for more information.\n", + kpse_program_name); + exit(1); + } + + return argc; +} + +/* Reading fmtutil.cnf */ +boolean parse_line(string line) +{ + string format = NULL, + engine = NULL, + hyphenation = NULL, + texargs = NULL, + inifile = NULL, + pool = NULL, + tcx = NULL; + string p, end; + + end = line + strlen(line); + + format = strtok(line, "\t "); + if (!format || !*format) + return false; + engine = strtok(NULL, "\t "); + if (!engine || !*engine) + return false; + hyphenation = strtok(NULL, "\t "); + if (!hyphenation || !*hyphenation) + return false; + texargs = strtok(NULL, " \t"); + if (!texargs || !*texargs) + return false; + if (strncasecmp(texargs, "nls=", 4) == 0) { + pool = texargs+4; + if (tcx = strchr(pool, ',')) { + *tcx = '\0'; + } + texargs = strtok(NULL, " \t"); + } + + p = texargs + strlen(texargs); + if (p < end && *p == '\0') + *p = ' '; + + /* Get last argument */ + for (inifile = texargs + strlen(texargs) - 1; + isspace(*inifile) && inifile > texargs; + inifile--) + *inifile = '\0'; + for ( ; !isspace(*(inifile - 1)) && inifile > texargs; inifile--); + + inifile = (*inifile == '*' ? inifile+1 : inifile); + + fmts[nb_formats].inifile_short = (inifile ? xstrdup(inifile) : NULL); + +#if 0 + fprintf(stderr, "parse_line : pool = %s, hyphen = %s, tcx = %s, inifile = %s\n", pool, hyphenation, tcx, inifile); +#endif + kpse_reset_program_name(format); + if (STREQ(engine, "mf") || STREQ(engine, "mf-nowin")) { + if (!kpse_find_file(inifile, kpse_mf_format, false)) { + /* Do not log it : we don't know if it has been requested or not ! */ + /* sprintf(msg_buf, "%s: ini file %s not found\n", cnf_file, inifile); */ + /* log_failure(msg_buf); */ + inifile = NULL; + } + fmts[nb_formats].progname = xstrdup(engine); + fmts[nb_formats].shortformat = xstrdup(format); + fmts[nb_formats].format = concat(format, ".base"); + } + else if (STREQ(engine, "mpost")) { + if (!kpse_find_file(inifile, kpse_mp_format, false)) { +/* sprintf(msg_buf, "%s: ini file %s not found\n", cnf_file, inifile); */ +/* log_failure(msg_buf); */ + inifile = NULL; + } + fmts[nb_formats].progname = xstrdup(engine); + fmts[nb_formats].shortformat = xstrdup(format); + fmts[nb_formats].format = concat(format, ".mem"); + } + else { + if (!kpse_find_file(inifile, kpse_tex_format, false)) { +/* sprintf(msg_buf, "%s: ini file %s not found\n", cnf_file, inifile); */ +/* log_failure(msg_buf); */ + inifile = NULL; + } + fmts[nb_formats].progname = xstrdup(format); + fmts[nb_formats].shortformat = xstrdup(format); + + if (STREQ(engine, "etex") + || STREQ(engine, "pdfetex")) { + fmts[nb_formats].format = concat(format, ".efmt"); + } + else if (STREQ(engine, "aleph") + || STREQ(engine, "pdfaleph")) { + fmts[nb_formats].format = concat(format, ".afmt"); + } + else if (STREQ(engine, "eomega") + || STREQ(engine, "pdfeomega")) { + fmts[nb_formats].format = concat(format, ".eoft"); + } + else if (STREQ(engine, "omega")) { + fmts[nb_formats].format = concat(format, ".oft"); + } + else { + fmts[nb_formats].format = concat(format, ".fmt"); + } + } + kpse_reset_program_name(progname); + fmts[nb_formats].engine = xstrdup(engine); + fmts[nb_formats].hyphenation = xstrdup(hyphenation); + fmts[nb_formats].texargs = xstrdup(texargs); + fmts[nb_formats].inifile = (inifile ? xstrdup(inifile) : NULL); + if (pool == NULL) { + fmts[nb_formats].poolbase = NULL; + fmts[nb_formats].pool = NULL; + } + else { + fmts[nb_formats].poolbase = xstrdup(pool); + fmts[nb_formats].pool = concat(pool, ".pool"); + } + if (tcx == NULL) { + fmts[nb_formats].tcx = xstrdup(""); + fmts[nb_formats].tcxoption = xstrdup(""); + } + else { + fmts[nb_formats].tcx = xstrdup(tcx); + fmts[nb_formats].tcxoption = concat("-translate-file=",tcx); + } + nb_formats++; + + return true; +} + +void read_fmtutilcnf() +{ + FILE *f; + string line; + + if (test_file('n', cnf_file) && test_file('r', cnf_file)) { + f = fopen(cnf_file, "r"); + if (KPSE_DEBUG_P(FMTUTIL_DEBUG)) { + fprintf(stderr, "Reading fmtutil_cnf file: %s\n", cnf_file); + } + while ((line = read_line(f)) != NULL) { + /* skip comments */ + if (*line == '#' || *line == '%' || isspace(*line) + || *line == '\0' || *line == '\n') + continue; + + if (!parse_line(line)) + fprintf(stderr, "%s: syntax error: %s\n", cnf_file, line); + free(line); + } + fclose(f); + if (KPSE_DEBUG_P(FMTUTIL_DEBUG)) { + int i; + for (i = 0; i < nb_formats; i++) { + fprintf(stderr, "Line %d: fmt = %s engine = %s progname = %s hyph = %s tex = %s ini = %s\n", + i, fmts[i].format, fmts[i].engine, fmts[i].progname, + fmts[i].hyphenation, fmts[i].texargs, fmts[i].inifile); + } + } + + } +} + +void __cdecl output_and_cleanup(int code) +{ + /* FIXME : what cleanup ? */ + int count = 0; + + if (test_file('d', tmpdir)) + rec_rmdir(tmpdir); + + if (code != 0 && log_failure_msg && *log_failure_msg) { + fprintf(stderr, "\ +###############################################################################\n\ +%s: Error! Not all formats have been built successfully.\n\ +Visit the log files in directory\n\ + %s\n\ +for details.\n\ +###############################################################################\n\ +\n\ +This is a summary of all `failed' messages and warnings:\n\ +%s\n", + kpse_program_name, destdir, log_failure_msg); + } +} + +static void usage() +{ + int i; + fprintf(stderr, "%s of %s\n", progname, kpathsea_version_string); + fprintf(stderr, "Fmtutil version %s\n", fmtutil_version_string); + fprintf(stderr,usage_msg[incarnation][0], progname ); + fputs("\n", stderr); + for(i = 1; usage_msg[incarnation][i] != NULL; ++i) + fputs(usage_msg[incarnation][i], stderr); +} + + +int main(int argc, char* argv[]) +{ + string texinputs, texformats; + +#if defined(WIN32) + /* if _DEBUG is not defined, these macros will result in nothing. */ + SETUP_CRTDBG; + /* Set the debug-heap flag so that freed blocks are kept on the + linked list, to catch any inadvertent use of freed memory */ + SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF ); +#endif + output_and_cleanup_function = output_and_cleanup; + + if (!progname) + progname = argv[0]; + kpse_set_program_name (progname, NULL); + + if (FILESTRCASEEQ(kpse_program_name, "fmtutil")) { + incarnation = FMTUTIL; + progname = "fmtutil"; + } + else if (FILESTRCASEEQ(kpse_program_name, "mktexfmt")) { + incarnation = MKTEXFMT; + progname = "mktexfmt"; + } + else { + fprintf(stderr, "This program was incorrectly copied to the name %s\n", + argv[0]); + return 1; + } + + /* initialize the symbol table */ + init_vars(); + + /* `kpse_init_prog' will put MODE and DPI into environment as values of + the two variables below. We need to leave these variables as they are. */ + mode = getval("MAKETEX_MODE"); + bdpi = getval("MAKETEX_BASE_DPI"); + + /* NULL for no fallback font. */ + kpse_init_prog (uppercasify (progname), + bdpi && atoi(bdpi) ? atoi(bdpi) : 600, mode, NULL); + + /* fmtutil_opt may modify argc and shift argv */ + argc = fmtutil_opt(argc, argv); + + setval_default("DPI", getval("BDPI")); + setval_default("MAG", "1.0"); + + /* if no cnf_file from command-line, look it up with kpsewhich: */ + if (test_file('z', cnf_file)) { + cnf_file = kpse_find_file(cnf_default, kpse_web2c_format, true); + if (test_file('z', cnf_file)) { + fprintf(stderr, "%s: fatal error, configuration file not found.\n", + progname); + exit(1); + } + } + if (!test_file('f', cnf_file)) { + fprintf(stderr, "%s: config file `%s' not found.\n", progname, cnf_file); + exit(1); + } + + /* read the fmtutil.cnf file */ + read_fmtutilcnf(); + + if (cmd == SHOWHYPHEN) { + exit(show_hyphen_file(arg)); + } + else if (cmd == EDIT) { + exit(edit_fmtutil_cnf()); + } + + cache_vars(); + + texmfmain = getval("MT_TEXMFMAIN"); + if (test_file('z', texmfmain) || !test_file('d', texmfmain)) { + fprintf(stderr, "%s: $TEXMFMAIN is undefined or points to a non-existent directory;\n%s: check your installation.\n", progname, progname); + exit(1); /* not mt_exit, since temporary files were not created yet */ + } + + /* setup dest dir */ + if (test_file('z', destdir)) { + setval_default("VARTEXMF", expand_var("$VARTEXMF")); + if (test_file('z', getval("VARTEXMF"))) + setval("VARTEXMF", expand_var("$MT_TEXMFMAIN")); + destdir = concat(getval("VARTEXMF"), "/web2c"); + } + if (!test_file('d', destdir)) { + do_makedir(destdir); + if (!test_file('d', destdir)) { + fprintf(stderr, "%s: format directory `%s' does not exist.\n", + progname, destdir); + exit(1); + } + } + + cwd = xgetcwd(); + if (test_file('n', cwd)) { + /* Fixme : is it enough ? */ + if (getenv("KPSE_DOT") == NULL) { + xputenv("KPSE_DOT", cwd); + } + texinputs = getval("TEXINPUTS"); + if (test_file('z', texinputs)) { + xputenv("TEXINPUTS", concat(cwd, ENV_SEP_STRING)); + } + else { + xputenv("TEXINPUTS", concatn(cwd, ENV_SEP_STRING, + texinputs, ENV_SEP_STRING, NULL)); + } + } + + /* Catch signals, so we clean up if the child is interrupted. + This emulates "trap 'whatever' 1 2 15". */ +#ifdef _WIN32 + SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigint_handler, TRUE); +#else +# ifdef SIGINT + signal (SIGINT, sigint_handler); +# endif +# ifdef SIGHUP + signal (SIGHUP, sigint_handler); +# endif +# ifdef SIGTERM + signal (SIGTERM, sigint_handler); +# endif +#endif + + tempenv = getval("TMPDIR"); + if (test_file ('z', tempenv)) + tempenv = getval("TEMP"); + if (test_file ('z', tempenv)) + tempenv = getval("TMP"); +#ifdef DOSISH + if (test_file ('z', tempenv)) + tempenv = "c:/tmp"; /* "/tmp" is not good if we are on a CD-ROM */ +#else + if (test_file ('z', tempenv)) + tempenv = "/tmp"; +#endif + sprintf(tmpdir, "%s/fmXXXXXX", tempenv); + mktemp(tmpdir); + if (do_makedir(tmpdir)) { + perror(tmpdir); + exit(1); + } + setval("TEMPDIR", tmpdir); + setval("STDOUT", concat_pathes(tmpdir, "astdout")); + pushd(tmpdir); + + /* Kludge to get dependency between formats working + in one pass : formats are build in tmpdir before + being sent to their final destination. */ + texformats = concatn(tmpdir, + ENV_SEP_STRING, + kpse_var_expand("$TEXFORMATS"), + ENV_SEP_STRING, + NULL); + xputenv("TEXFORMATS", texformats); + + +#if 0 + if ((fout = fopen(getval("STDOUT"), "w")) == NULL) { + perror(output); + mt_exit(1); + } +#endif + + /* make local pathes absolute */ + if (! kpse_absolute_p(destdir, FALSE) ) { + destdir = concat3(cwd, DIR_SEP_STRING, destdir); + } + if (! kpse_absolute_p(cnf_file, FALSE) ) { + cnf_file = concat3(cwd, DIR_SEP_STRING, cnf_file); + } + + + /* umask = 0 */ + umask(0); /* for those platforms who support it */ + + errstatus = 0; + + switch (cmd) { + case ALL: + errstatus = recreate_all(); + break; + case MISSING: + errstatus = create_missing(); + break; + case BYFMT: + errstatus = create_one_format(arg); + break; + case BYHYPHEN: + errstatus = recreate_by_hyphenfile(arg); + break; + } + + /* Install the log files and format files */ + process_multiple_files("*.log", move_log); + process_multiple_files("*.base", move_fmt); + process_multiple_files("*.mem", move_fmt); + process_multiple_files("*.fmt", move_fmt); + process_multiple_files("*.efmt", move_fmt); + process_multiple_files("*.oft", move_fmt); + process_multiple_files("*.eoft", move_fmt); + process_multiple_files("*.afmt", move_fmt); + + if (dolinks) + link_formats(); + + mt_exit(errstatus != true); + +} + +/* +############################################################################### +# cache_vars() +# locate files / kpathsea variables and export variables to environment +# this speeds up future calls to e.g. mktexupd +############################################################################### +*/ +void cache_vars() +{ + setval_default("MT_VARTEXFONTS", expand_var("$VARTEXFONTS")); + setval_default("MT_TEXMFMAIN", kpse_path_expand("$TEXMFMAIN")); + setval_default("MT_MKTEX_CNF", kpse_find_file("mktex.cnf", kpse_web2c_format, false)); + setval_default("MT_MKTEX_OPT", kpse_find_file("mktex.opt", kpse_web2c_format, false)); + /* This should give us the ls-R default path */ + if (!kpse_format_info[kpse_db_format].type) /* needed if arg was numeric */ + kpse_init_format (kpse_db_format); + setval_default("MT_LSR_PATH", kpse_format_info[kpse_db_format].path); +} + +int do_format(int f) +{ + string cmdfmt = "%s -ini %s %s=%s -progname=%s %s <nul"; + string fmtswitch; + string prgswitch; + int ret = 0; + + /* Do nothing if inifile has not been found */ + if (fmts[f].inifile == NULL) { + sprintf(msg_buf, "%s: ini file %s not found\n", cnf_file, fmts[f].inifile_short); + log_failure(msg_buf); + return -1; + } + + fmtswitch = "-jobname"; + + prgswitch = fmts[f].progname; + /* Kludge for context : avoid to set texmf.cnf parameters for + every cont-?? format. */ + if (strlen(prgswitch) == strlen("cont-??") + && FILESTRNCASEEQ(prgswitch, "cont-", 5)) { + prgswitch = "context"; + } + else if (strlen(prgswitch) == strlen("mptopdf") + && FILESTRCASEEQ(prgswitch, "mptopdf")) { + prgswitch = "context"; + } + else if (strlen(prgswitch) == strlen("metafun") + && FILESTRCASEEQ(prgswitch, "metafun")) { + prgswitch = "mpost"; + } + + if (sprintf(cmd_sys, cmdfmt, fmts[f].engine, fmts[f].tcxoption, fmtswitch, fmts[f].shortformat, + prgswitch, fmts[f].texargs) > 1023) { + fprintf(stderr, "Warning: do_format buffer overrun!\n"); + fprintf(stderr, "no command run.\n"); + return -1; + } + + if (fmts[f].pool != NULL) { + string poolfile; + string local_poolfile = concat(fmts[f].engine, ".pool"); + + kpse_reset_program_name(fmts[f].engine); + + if (STREQ(fmts[f].engine, "mf") || STREQ(fmts[f].engine, "mf-nowin")) { + poolfile = kpse_find_file(fmts[f].pool, kpse_mfpool_format, true); + } + else if (STREQ(fmts[f].engine, "mpost")) { + poolfile = kpse_find_file(fmts[f].pool, kpse_mppool_format, true); + } + else { + poolfile = kpse_find_file(fmts[f].pool, kpse_texpool_format, true); + } + + process_multiple_files("*.pool", remove_file); + if (test_file('n', poolfile) && test_file('f', poolfile)) { + fprintf(stderr, "%s: attempting to create localized format using pool=$pool and tcx=$tcx.\n", + kpse_program_name, fmts[f].poolbase, fmts[f].tcx); + catfile(poolfile, local_poolfile, false); + xputenv("TEXPOOL", "."); + } + kpse_reset_program_name(progname); + } + + /* run discarding stdout */ + start_redirection(quiet); + + if (!quiet) + fprintf(stdout, "running `%s' ...\n", cmd_sys); + + if (!norebuild) { + unlink(fmts[f].format); + ret = system(cmd_sys); + if (ret == -1 || !test_file('f', fmts[f].format)) { + sprintf(msg_buf, "%s: command `%s' failed (ret = %d, %s).\n", progname, cmd_sys, ret, fmts[f].format); + log_failure(msg_buf); + unlink(fmts[f].format); + } + } + + pop_fd(); + + if (dolinks) { + to_link[nb_links].src = fmts[f].engine; + to_link[nb_links].dst = fmts[f].progname; + nb_links++; + } + return ret; +} + +int recreate_all() +{ + int i, ret = true; + + for (i = 0; i < nb_formats; i++) { + if (do_format(i) != 0) + ret = false; + } + + return ret; +} + +int create_missing() +{ + int i, ret = true; + string destfmt; + + for (i = 0; i < nb_formats; i++) { + destfmt = concat_pathes(destdir, fmts[i].format); + if (! test_file('f', destfmt)) { + if (do_format(i) != 0) + ret = false; + } + free(destfmt); + } + return ret; +} + +int create_one_format(string fmtname) +{ + int i, ret = true; + boolean created = false; + + for (i = 0; i < nb_formats; i++) { + if (FILESTRCASEEQ(fmtname, fmts[i].shortformat)) { + if (do_format(i) != 0) + ret = false; + created = true; + break; + } + } + + if (! created) { + fprintf(stderr, "%s: format file %s not found in fmtutil.cnf.\n", + progname, fmtname); + ret = false; + } + + return ret; +} + +int recreate_by_hyphenfile(string hyphenfile) +{ + int i, ret = true; + boolean created = false; + + for (i = 0; i < nb_formats; i++) { + if (FILESTRCASEEQ(hyphenfile, fmts[i].hyphenation)) { + if (do_format(i) != 0) + ret = false; + created = true; + break; + } + } + + if (! created) { + fprintf(stderr, "%s: hyphen file %s not found in fmtutil.cnf.\n", + progname, hyphenfile); + ret = false; + } + + return ret; +} + +int enable_format_file(string format) +{ + FILE *fin, *fout; + char line[256]; + string bak_file = concat(cnf_file, ".bak"); + + fin = fopen(cnf_file, "r"); + if (! fin) { + perror(cnf_file); + return false; + } + fout = fopen (bak_file, "w"); + if (! fout) { + perror(bak_file); + return false; + } + while (fgets(line, sizeof(line), fin)) { + if (strncmp(line, "#! ", 3) == 0 + && strncmp(line+3, format, strlen(format)) == 0 + && isspace(line+3+strlen(format))) { + fputs(line + 3, fout); + } + else { + fputs(line, fout); + } + } + fclose(fin); + fclose(fout); + mvfile(bak_file, cnf_file); + free(bak_file); + return true; +} + +int disable_format_file(string format) +{ + FILE *fin, *fout; + char line[256]; + string bak_file = concat(cnf_file, ".bak"); + + fin = fopen(cnf_file, "r"); + if (! fin) { + perror(cnf_file); + return false; + } + fout = fopen (bak_file, "w"); + if (! fout) { + perror(bak_file); + return false; + } + while (fgets(line, sizeof(line), fin)) { + if (strncmp(line, format, strlen(format)) == 0 + && isspace(line + strlen(format))) { + fputs("#! ", fout); + } + fputs(line, fout); + } + fclose(fin); + fclose(fout); + mvfile(bak_file, cnf_file); + free(bak_file); + return true; +} + +int list_config_file() +{ + FILE *fin; + char line[256]; + + fin = fopen(cnf_file, "r"); + if (! fin) { + perror(cnf_file); + return false; + } + while (fgets(line, sizeof(line), fin)) { + if (isalpha(line[0]) + || strncmp(line, "#! ", 3) == 0) + fputs(line, stdout); + } + fclose(fin); + return true; +} + +int show_hyphen_file(string format) +{ + int i, ret; + string hyphenfile; + + for (i = 0; i < nb_formats; i++) { + if (FILESTRCASEEQ(format, fmts[i].shortformat)) { + if (STREQ(fmts[i].hyphenation, "-")) { + printf("%s\n", fmts[i].hyphenation); + return 0; + } + kpse_reset_program_name(format); + kpse_format_info[kpse_tex_format].cnf_path = kpse_cnf_get("TEXINPUTS"); + if (!(hyphenfile + = kpse_find_file(fmts[i].hyphenation, kpse_tex_format, false))) { + fprintf(stderr, "%s: hyphen file %s not found\n", progname, + fmts[i].hyphenation); + ret = -1; + } + else { + printf("%s\n", hyphenfile); + free(hyphenfile); + ret = 0; + } + kpse_reset_program_name(progname); + return ret; + } + } + fprintf(stderr, "no info for format %s\n", format); + return 0; +} + +int edit_fmtutil_cnf() +{ + string editor = kpse_var_expand("$EDITOR"); + string command, p; + int ret; + + if (test_file('z', editor)) { + editor = kpse_var_expand("$VISUAL"); + if (test_file('z', editor)) { + editor = kpse_var_expand("$TEXEDIT"); + if (test_file('z', editor)) { + editor = "wordpad"; + } + } + } + + p = editor; + + while (isspace(*p++)); + if (*p == '\"') { + do { + p++; + } while (*p != '\"' && *p != '\0'); + if (*p == '\"') { + *(p+1) = '\0'; + } + else { + fprintf(stderr, "%s: unterminated quoted string for editor specification.\n", + progname); + exit(1); + } + } + else { + do { + p++; + } while (!isspace(*p) && *p != '\0'); + *p = '\0'; + } + + command = concat3(editor, " ", cnf_file); +#ifdef WIN32 + ret = win32_system(command, true); +#else + ret = system (command); +#endif + if (ret != 0) + fprintf (stderr, "! Trouble executing `%s'.\n", command); + + return ret; +} + +/* + This function expects a globbing file specification. + There is no recursive call here. +*/ +void process_multiple_files(string filespec, process_fn fn) +{ + + char path[PATH_MAX]; + int path_len; +#if defined(_WIN32) + WIN32_FIND_DATA find_file_data; + HANDLE hnd; +#else + glob_t gl; +#endif + + strcpy(path, filespec); + + /* If it is a directory, then get all the files there */ + if (!(strrchr(path, '*') || strrchr(path, '?')) + && test_file('d', path)) { + path_len = strlen(path); + strcat(path, "/*"); + } + else { + path_len = strlen(path) - strlen(xbasename(path)) -1; + } + +#if defined(_WIN32) + hnd = FindFirstFile(path, &find_file_data); + while (hnd != INVALID_HANDLE_VALUE) { + if(!strcmp(find_file_data.cFileName, ".") + || !strcmp(find_file_data.cFileName, "..")) + continue; + path[path_len+1] = '\0'; + strcat(path, find_file_data.cFileName); + if (KPSE_DEBUG_P(FMTUTIL_DEBUG)) { + fprintf(stderr, "Processing %s\n", path); + } + (*fn)(path); + if (FindNextFile(hnd, &find_file_data) == FALSE) + break; + } + path[path_len+1] = '\0'; + FindClose(hnd); + +#else /* ! WIN32 */ + + switch (glob(path, GLOB_NOCHECK, NULL, &gl)) { + case 0: /* success */ + for (i = 0; i < gl.gl_pathc; i++) { + (*fn)(gl.gl_pathv[i]); + } + globfree(&gl); + break; + + case GLOB_NOSPACE: + fprintf(stderr, "%s: Out of memory while globbing %s.\n", + kpse_program_name, filespec); + mt_exit(1); + break; + + default: + break; + } +#endif + +} + +void remove_file(string filename) +{ + unlink(filename); +} + +void move_log(string logname) +{ + string logdest; + logdest = concat3(destdir, DIR_SEP_STRING, logname); + unlink(logdest); + mvfile(logname, logdest); + free(logdest); +} + +void move_fmt(string fmtname) +{ + string fmtdest; + string texfmt, plainfmt; + char cmd[4096]; + string cmdfmt = "mktexupd \"%s\" %s"; + + fmtdest = concat3(destdir, DIR_SEP_STRING, fmtname); + unlink(fmtdest); + if (KPSE_DEBUG_P(FMTUTIL_DEBUG)) { + fprintf(stderr, "Moving %s to %s\n", fmtname, fmtdest); + } + mvfile(fmtname, fmtdest); + fprintf(stderr, "%s: %s successfully generated.\n", progname, fmtdest); + sprintf(cmd, cmdfmt, destdir, fmtname); +#if 1 + if (KPSE_DEBUG_P(FMTUTIL_DEBUG)) { + fprintf(stderr, "Calling system(%s)\n", cmd); + } +#endif + system(cmd); + /* if we have been called to build a format at runtime */ + if (incarnation == MKTEXFMT) { + fputs(fmtdest, stdout); + } + free(fmtdest); + + texfmt = concat3(destdir, DIR_SEP_STRING, "tex.fmt"); + plainfmt = concat3(destdir, DIR_SEP_STRING, "plain.fmt"); + if (test_file('f', texfmt) && !test_file('f', plainfmt)) { + catfile(texfmt, plainfmt, FALSE); + sprintf(cmd, cmdfmt, destdir, "plain.fmt"); + system(cmd); + } + free(texfmt); + free(plainfmt); + + texfmt = concat3(destdir, DIR_SEP_STRING, "tex.efmt"); + plainfmt = concat3(destdir, DIR_SEP_STRING, "plain.efmt"); + if (test_file('f', texfmt) && !test_file('f', plainfmt)) { + catfile(texfmt, plainfmt, FALSE); + sprintf(cmd, cmdfmt, destdir, "plain.efmt"); + system(cmd); + } + free(texfmt); + free(plainfmt); + + texfmt = concat3(destdir, DIR_SEP_STRING, "mf.base"); + plainfmt = concat3(destdir, DIR_SEP_STRING, "plain.base"); + if (test_file('f', texfmt) && !test_file('f', plainfmt)) { + catfile(texfmt, plainfmt, FALSE); + sprintf(cmd, cmdfmt, destdir, "plain.base"); + system(cmd); + } + free(texfmt); + free(plainfmt); + + texfmt = concat3(destdir, DIR_SEP_STRING, "mpost.mem"); + plainfmt = concat3(destdir, DIR_SEP_STRING, "plain.mem"); + if (test_file('f', texfmt) && !test_file('f', plainfmt)) { + catfile(texfmt, plainfmt, FALSE); + sprintf(cmd, cmdfmt, destdir, "plain.mem"); + system(cmd); + } + free(texfmt); + free(plainfmt); +} + +void link_formats() +{ + int i, j; + boolean skip; + string src, srcdll, srcexe, dstexe; + + for (i = 0; i < nb_links; i++) { + src = expand_var(concat("$SELFAUTOLOC/", to_link[i].src)); + /* Check that the destination is not among the ones that should + *never* be removed */ + skip = false; + for (j = 0; unrmable_engines[j] != NULL; j++) { + if (FILESTRCASEEQ(to_link[i].dst, unrmable_engines[j])) { + fprintf(stderr, + "%s: %s is a basic engine, won't remove it... skipping.\n", + kpse_program_name, unrmable_engines[j]); + skip = true; + break; + } + } + /* Any smarter way to do that ? */ + if (skip) + continue; + + dstexe = expand_var(concatn("$SELFAUTOLOC/", to_link[i].dst, ".exe", NULL)); + if (test_file('f', dstexe) && force == false) { + fprintf(stderr, "%s: destination %s already exists, skipping.\n", kpse_program_name, dstexe); + free(dstexe); + continue; + } +#if 0 + srcexe = concat(src, ".exe"); + srcdll = concat(src, ".dll"); + if (FILESTRCASEEQ(srcexe, dstexe)) { + printf("same files: %s and %s, doing nothing\n", srcexe, dstexe); + } + else if (test_file('f', srcdll)) { + if (norebuild) { + printf("copy %s to %s\n", srcexe, dstexe); + } + else if (catfile(srcexe, dstexe, false) == false) { + fprintf(stderr, "%s: failed to copy %s to %s\n", + kpse_program_name, srcexe, dstexe); + } + } + else { + sprintf(cmd_sys,"lnexe %s %s", srcexe, dstexe); + if (norebuild) { + printf("lnexe %s to %s\n", srcexe, dstexe); + } + else if (system(cmd_sys) == -1) { + fprintf(stderr, "%s: failed to lnexe %s to %s\n", + kpse_program_name, srcexe, dstexe); + } + } + free(srcdll); +#else + srcexe = concat(src, ".exe"); + if (FILESTRCASEEQ(srcexe, dstexe)) { + printf("same files: %s and %s, doing nothing\n", srcexe, dstexe); + } + else if (norebuild) { + printf("copy %s to %s\n", srcexe, dstexe); + } + else if (catfile(srcexe, dstexe, false) == false) { + fprintf(stderr, "%s: failed to copy %s to %s\n", + kpse_program_name, srcexe, dstexe); + } +#endif + free(srcexe); + free(dstexe); + } +} diff --git a/Build/source/texk/contrib/fmtutil.h b/Build/source/texk/contrib/fmtutil.h new file mode 100644 index 00000000000..9d35b8a24dd --- /dev/null +++ b/Build/source/texk/contrib/fmtutil.h @@ -0,0 +1,43 @@ +/* fmtutil.h: definitions for fmtutil lib exports. + +Copyright (C) 1998 Fabrice POPINEAU. + +Time-stamp: <02/04/03 15:15:00 popineau> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _FMTUTIL_H_ +#define _FMTUTIL_H_ + +#include <kpathsea/c-proto.h> +#include <kpathsea/debug.h> + +#define FMTUTIL_DEBUG (KPSE_LAST_DEBUG+5) + +typedef void (* process_fn )(string); + +void move_log(string fname); +void move_fmt(string fname); +void remove_file(string fname); +void process_multiple_files(string pattern, process_fn); +void cache_vars(); +int recreate_all(); +int create_missing(); +int create_one_format(string); +int recreate_by_hyphenfile(string); +int show_hyphen_file(string); +int edit_fmtutil_cnf(); + +#endif /* _FMTUTIL_H_ */ diff --git a/Build/source/texk/contrib/glob/COPYING.LIB b/Build/source/texk/contrib/glob/COPYING.LIB new file mode 100644 index 00000000000..eb685a5ec98 --- /dev/null +++ b/Build/source/texk/contrib/glob/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Build/source/texk/contrib/glob/Makefile.ami b/Build/source/texk/contrib/glob/Makefile.ami new file mode 100644 index 00000000000..3666d3ef3a3 --- /dev/null +++ b/Build/source/texk/contrib/glob/Makefile.ami @@ -0,0 +1,69 @@ +# Makefile for standalone distribution of libglob.a (fnmatch, glob). + +# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License +# as published by the Free Software Foundation; either version 2 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = /glob/ +# This must repeat the value, because configure will remove `VPATH = .'. +srcdir = /glob/ + +CC = sc +RM = delete +CPPFLAGS = +CFLAGS = + +# Information determined by configure. +DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \ + Define HAVE_DIRENT_H + +# How to invoke ar. +AR = join +ARFLAGS = as + +# How to invoke ranlib. +RANLIB = ; + +.PHONY: all +all: glob.lib + +glob.lib : glob.o fnmatch.o + $(AR) $(ARFLAGS) $@ glob.o fnmatch.o + $(RANLIB) $@ + +# For some reason, Unix make wants the dependencies on the source files. +# Otherwise it refuses to use an implicit rule! +# And, get this: it doesn't work to use $(srcdir)foo.c!! +glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c +fnmatch.o: $(srcdir)fnmatch.h fnmatch.c + +OUTPUT_OPTION = +.c.o: + $(CC) IDir "" \ + $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +.PHONY: clean realclean glob-clean glob-realclean distclean +clean glob-clean: + -$(RM) glob.lib "#?.o" core +distclean glob-realclean: clean + -$(RM) TAGS tags Makefile config.status config.h config.log +realcean: distclean + +# For inside the C library. +glob.tar glob.tar.Z: + $(MAKE) -C .. $@ diff --git a/Build/source/texk/contrib/glob/Makefile.in b/Build/source/texk/contrib/glob/Makefile.in new file mode 100644 index 00000000000..8c091b33ac9 --- /dev/null +++ b/Build/source/texk/contrib/glob/Makefile.in @@ -0,0 +1,66 @@ +# Makefile for standalone distribution of libglob.a (fnmatch, glob). + +# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License +# as published by the Free Software Foundation; either version 2 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = @srcdir@ +# This must repeat the value, because configure will remove `VPATH = .'. +srcdir = @srcdir@ + +CC = @CC@ +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ + +# Information determined by configure. +DEFS = @DEFS@ + +# How to invoke ar. +AR = @AR@ +ARFLAGS = rv + +# How to invoke ranlib. +RANLIB = @RANLIB@ + +.PHONY: all +all: libglob.a + +libglob.a: glob.o fnmatch.o + $(AR) $(ARFLAGS) $@ glob.o fnmatch.o + $(RANLIB) $@ + +# For some reason, Unix make wants the dependencies on the source files. +# Otherwise it refuses to use an implicit rule! +# And, get this: it doesn't work to use $(srcdir)/foo.c!! +glob.o: $(srcdir)/glob.h $(srcdir)/fnmatch.h glob.c +fnmatch.o: $(srcdir)/fnmatch.h fnmatch.c + +.c.o: + $(CC) -I. -I$(srcdir) -c \ + $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +.PHONY: clean realclean glob-clean glob-realclean distclean +clean glob-clean: + -rm -f libglob.a *.o core +distclean glob-realclean: clean + -rm -f TAGS tags Makefile config.status config.h config.log +realcean: distclean + +# For inside the C library. +glob.tar glob.tar.Z: + $(MAKE) -C .. $@ diff --git a/Build/source/texk/contrib/glob/SCOPTIONS b/Build/source/texk/contrib/glob/SCOPTIONS new file mode 100644 index 00000000000..f89daae12f7 --- /dev/null +++ b/Build/source/texk/contrib/glob/SCOPTIONS @@ -0,0 +1,13 @@ +ERRORREXX +OPTIMIZE +NOVERSION +OPTIMIZERTIME +OPTIMIZERALIAS +DEFINE INCLUDEDIR="include:" +DEFINE LIBDIR="lib:" +DEFINE NO_ALLOCA +DEFINE NO_FLOAT +DEFINE NO_ARCHIVES +IGNORE=161 +IGNORE=100 +STARTUP=cres diff --git a/Build/source/texk/contrib/glob/SMakefile b/Build/source/texk/contrib/glob/SMakefile new file mode 100644 index 00000000000..1c82e0a076a --- /dev/null +++ b/Build/source/texk/contrib/glob/SMakefile @@ -0,0 +1,69 @@ +# Makefile for standalone distribution of libglob.a (fnmatch, glob). + +# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License +# as published by the Free Software Foundation; either version 2 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 +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with this library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = /glob/ +# This must repeat the value, because configure will remove `VPATH = .'. +srcdir = /glob/ + +CC = sc +CPPFLAGS = +CFLAGS = +MAKE = smake +RM = delete + +# Information determined by configure. +DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \ + Define HAVE_DIRENT_H + +# How to invoke ar. +AR = join +ARFLAGS = as + +# How to invoke ranlib. +RANLIB = ; + +.PHONY: all +all: glob.lib + +glob.lib : glob.o fnmatch.o + $(AR) $(ARFLAGS) $@ glob.o fnmatch.o + $(RANLIB) $@ + +# For some reason, Unix make wants the dependencies on the source files. +# Otherwise it refuses to use an implicit rule! +# And, get this: it doesn't work to use $(srcdir)foo.c!! +glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c +fnmatch.o: $(srcdir)fnmatch.h fnmatch.c + +.c.o: + $(CC) IDir "" \ + $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +.PHONY: clean realclean glob-clean glob-realclean distclean +clean glob-clean: + -$(RM) -f glob.lib *.o core +distclean glob-realclean: clean + -$(RM) -f TAGS tags Makefile config.status config.h config.log +realcean: distclean + +# For inside the C library. +glob.tar glob.tar.Z: + $(MAKE) -C .. $@ diff --git a/Build/source/texk/contrib/glob/configure b/Build/source/texk/contrib/glob/configure new file mode 100755 index 00000000000..d946ae36162 --- /dev/null +++ b/Build/source/texk/contrib/glob/configure @@ -0,0 +1,2139 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +ac_config_files= +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_envvar| sed 's/[_a-zA-Z0-9]//g'`"; then + { echo "configure: error: invalid variable name: $ac_envvar" 1>&2; exit 1; } + fi + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=fnmatch.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:538: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test $ac_x $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:569: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test $ac_x $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:621: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test $ac_x $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:654: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 665 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:670: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:696: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:701: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:710: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:729: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:763: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test $ac_x $ac_dir/$ac_word; then + ac_cv_prog_AR="ar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:794: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + if test -z "$COMSPEC"; then ac_x=-f; else ac_x=-x; fi + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test $ac_x $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:823: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 838 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:844: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 855 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:861: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 872 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:878: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + echo $ac_n "checking for AIX""... $ac_c" 1>&6 +echo "configure:902: checking for AIX" >&5 +cat > conftest.$ac_ext <<EOF +#line 904 "configure" +#include "confdefs.h" +#ifdef _AIX + yes +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF +#define _ALL_SOURCE 1 +EOF + +else + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* + + +ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +echo "configure:927: checking for minix/config.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 932 "configure" +#include "confdefs.h" +#include <minix/config.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:937: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +echo "configure:975: checking for POSIXized ISC" >&5 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:996: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1001 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1050: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1071: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1076 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1084: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1101 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1119 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1140 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1151: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +for ac_hdr in memory.h unistd.h string.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1178: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1183 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1188: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1219: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1224 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1232: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + ac_header_dirent=$ac_hdr; break +else + echo "$ac_t""no" 1>&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1257: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1265 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:1276: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1298: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1306 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:1317: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether closedir returns void""... $ac_c" 1>&6 +echo "configure:1340: checking whether closedir returns void" >&5 +if eval "test \"`echo '$''{'ac_cv_func_closedir_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_closedir_void=yes +else + cat > conftest.$ac_ext <<EOF +#line 1348 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <$ac_header_dirent> +int closedir(); main() { exit(closedir(opendir(".")) != 0); } +EOF +if { (eval echo configure:1354: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_closedir_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_closedir_void=yes +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_closedir_void" 1>&6 +if test $ac_cv_func_closedir_void = yes; then + cat >> confdefs.h <<\EOF +#define CLOSEDIR_VOID 1 +EOF + +fi + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1379: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1384 "configure" +#include "confdefs.h" +#include <alloca.h> +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1391: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1412: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1417 "configure" +#include "confdefs.h" + +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1445: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1477: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1482 "configure" +#include "confdefs.h" +#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1507: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1512 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1535: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<EOF +#define CRAY_STACKSEG_END $ac_func +EOF + + break +else + echo "$ac_t""no" 1>&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1562: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext <<EOF +#line 1570 "configure" +#include "confdefs.h" +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:1589: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <<EOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +EOF + +fi + +echo $ac_n "checking for working strcoll""... $ac_c" 1>&6 +echo "configure:1611: checking for working strcoll" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strcoll_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_strcoll_works=no +else + cat > conftest.$ac_ext <<EOF +#line 1619 "configure" +#include "confdefs.h" +#include <string.h> +main () +{ + exit (strcoll ("abc", "def") >= 0 || + strcoll ("ABC", "DEF") >= 0 || + strcoll ("123", "456") >= 0); +} +EOF +if { (eval echo configure:1629: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_strcoll_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_strcoll_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_strcoll_works" 1>&6 +if test $ac_cv_func_strcoll_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_STRCOLL 1 +EOF + +fi + +ac_config_files="$ac_config_files Makefile" + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + + +trap 'rm -fr `echo "$ac_config_files " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CC@%$CC%g +s%@AR@%$AR%g +s%@RANLIB@%$RANLIB%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"$ac_config_files"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*|[A-z]:/*) # Absolute path. + srcdir="$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + rm -f conftest.in + ac_file_inputs=`echo $ac_file_in|sed -e "s%:% $ac_given_srcdir/%g" -e "s%^%$ac_given_srcdir/%"` + cat $ac_file_inputs > conftest.in + # + # Replace lines of the form ac_include foo with the contents of foo: + # first, from the ac_include lines construct a list of file names. + # From that list, we construct a second list of those files that exist. + # Then we construct lists of sed commands for including those files, + # and a sed command that removes the ac_include lines. We don't attempt + # to read non-existent files because some (buggy) versions of sed choke + # on this. Have to use sed because old (Ultrix, SunOS) awk does not support + # getline or system. (Anyway, configure scripts aren't supposed to use awk.) + # Can't use only one -e and commands {dr foo} because foo has to be last. + # Be careful, because the filename may contain /. Be careful with + # whitespace; we need to use echo. + # + file_substs=`sed -n '/^ac_include/s%ac_include[ ]*\(.*\)%\1%p' conftest.in` + # Create the sed command line ... + if test -n "$file_substs"; then + echo "configure: warning: ac_include is obsolete; instead use kpse_include" 1>&2 + file_subst_cmd="sed -e 's/^ac_include/kpse_include/'" + else + file_subst_cmd='sed' + fi + kpse_substs=`sed -n '/^kpse_include/s%kpse_include[ ]*\(.*\)%\1%p' conftest.in` + for ac_inc in $file_substs $kpse_substs; do + if test -f "$ac_given_srcdir/$ac_inc"; then + ac_mung=`echo $ac_inc | sed 's,/,%,g'` + file_subst_cmd="$file_subst_cmd -e '/^kpse_include $ac_mung$/r $ac_given_srcdir/$ac_inc'" + fi + done + file_subst_cmd="$file_subst_cmd -e '/^kpse_include/d'" + # ... and fix the whitespace and escaped slashes. + file_subst_cmd=`echo "$file_subst_cmd" | sed -e 's,%,\\\/,g' \ +-e 's/kpse_include /kpse_include[ ]*/g'` + # I can't find any way to do variable substitution in the sed commands + # (so the user could have, e.g., $top_srcdir in their ac_include line). + (eval $file_subst_cmd conftest.in) \ + | sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* conftest.in + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ].*$%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%:% $ac_given_srcdir/%g" -e "s%^%$ac_given_srcdir/%"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + + +EOF +cat >> $CONFIG_STATUS <<\EOF + + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in : $subdirs; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; } + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*|[A-z]:/*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f ./configure; then + ac_sub_configure=./configure + elif test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2 + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /*|[A-z]:/*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac + + echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; } + fi + fi + + cd $ac_popdir + done +fi + diff --git a/Build/source/texk/contrib/glob/configure.bat b/Build/source/texk/contrib/glob/configure.bat new file mode 100644 index 00000000000..f3a0f5db681 --- /dev/null +++ b/Build/source/texk/contrib/glob/configure.bat @@ -0,0 +1,26 @@ +@echo off
+echo Configuring glob for GO32
+rem This batch file assumes a unix-type "sed" program
+
+echo # Makefile generated by "configure.bat"> Makefile
+
+if exist config.sed del config.sed
+
+echo "s/@srcdir@/./ ">> config.sed
+echo "s/@CC@/gcc/ ">> config.sed
+echo "s/@CFLAGS@/-O2 -g/ ">> config.sed
+echo "s/@CPPFLAGS@/-DHAVE_CONFIG_H -I../ ">> config.sed
+echo "s/@AR@/ar/ ">> config.sed
+echo "s/@RANLIB@/ranlib/ ">> config.sed
+echo "s/@LDFLAGS@// ">> config.sed
+echo "s/@DEFS@// ">> config.sed
+echo "s/@ALLOCA@// ">> config.sed
+echo "s/@LIBS@// ">> config.sed
+echo "s/@LIBOBJS@// ">> config.sed
+echo "s/^Makefile *:/_Makefile:/ ">> config.sed
+echo "s/^config.h *:/_config.h:/ ">> config.sed
+
+sed -e "s/^\"//" -e "s/\"$//" -e "s/[ ]*$//" config.sed > config2.sed
+sed -f config2.sed Makefile.in >> Makefile
+del config.sed
+del config2.sed
diff --git a/Build/source/texk/contrib/glob/configure.in b/Build/source/texk/contrib/glob/configure.in new file mode 100644 index 00000000000..ff35fcf660f --- /dev/null +++ b/Build/source/texk/contrib/glob/configure.in @@ -0,0 +1,20 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(fnmatch.c) dnl A distinctive file to look for in srcdir. +AC_PREREQ(2.1) dnl Minimum Autoconf version required. +AC_PROG_CC +AC_CHECK_PROG(AR, ar, ar, ar) +AC_PROG_RANLIB +AC_PROG_CPP dnl Later checks need this. +dnl These two want to come early. +AC_AIX +AC_MINIX +AC_ISC_POSIX +AC_CONST +AC_HEADER_STDC +AC_CHECK_HEADERS(memory.h unistd.h string.h) +AC_HEADER_DIRENT +AC_FUNC_CLOSEDIR_VOID +AC_FUNC_ALLOCA +AC_FUNC_STRCOLL +KPSE_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/Build/source/texk/contrib/glob/fnmatch.c b/Build/source/texk/contrib/glob/fnmatch.c new file mode 100644 index 00000000000..de45941f8f9 --- /dev/null +++ b/Build/source/texk/contrib/glob/fnmatch.c @@ -0,0 +1,230 @@ +/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include <errno.h> +#include <fnmatch.h> +#include <ctype.h> + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#ifndef errno +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (FOLD (*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if ((flags & FNM_FILE_NAME) && *n == '/') + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0') + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == '\0') + return 0; + + { + char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD (*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD (*n) >= cstart && FOLD (*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD (*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/Build/source/texk/contrib/glob/fnmatch.h b/Build/source/texk/contrib/glob/fnmatch.h new file mode 100644 index 00000000000..9a0036e53aa --- /dev/null +++ b/Build/source/texk/contrib/glob/fnmatch.h @@ -0,0 +1,68 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) \ + || defined (WIN32)) +#undef __P +#define __P(protos) protos +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in <unistd.h>. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/Build/source/texk/contrib/glob/glob.c b/Build/source/texk/contrib/glob/glob.c new file mode 100644 index 00000000000..76060e14259 --- /dev/null +++ b/Build/source/texk/contrib/glob/glob.c @@ -0,0 +1,906 @@ +/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +/* Enable GNU extensions in glob.h. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GLOB_INTERFACE_VERSION 1 +#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#include <gnu-versions.h> +#if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + +#ifdef STDC_HEADERS +#include <stddef.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#ifndef POSIX +#ifdef _POSIX_VERSION +#define POSIX +#endif +#endif +#endif + +#if !defined (_AMIGA) && !defined (VMS) && !defined(WIN32) +#include <pwd.h> +#endif + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +#ifndef NULL +#define NULL 0 +#endif + + +#if defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__) +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# ifdef HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# ifdef HAVE_NDIR_H +# include <ndir.h> +# endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ +#endif + + +/* In GNU systems, <dirent.h> defines this macro for us. */ +#ifdef _D_NAMLEN +#undef NAMLEN +#define NAMLEN(d) _D_NAMLEN(d) +#endif + + +#if (defined (POSIX) || defined (WIN32)) && !defined (__GNU_LIBRARY__) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +#define REAL_DIR_ENTRY(dp) 1 +#else +#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* POSIX */ + +#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) +#include <stdlib.h> +#include <string.h> +#define ANSI_STRING +#else /* No standard headers. */ + +extern char *getenv (); + +#ifdef HAVE_STRING_H +#include <string.h> +#define ANSI_STRING +#else +#include <strings.h> +#endif +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif + +extern char *malloc (), *realloc (); +extern void free (); + +extern void qsort (); +extern void abort (), exit (); + +#endif /* Standard headers. */ + +#ifndef ANSI_STRING + +#ifndef bzero +extern void bzero (); +#endif +#ifndef bcopy +extern void bcopy (); +#endif + +#define memcpy(d, s, n) bcopy ((s), (d), (n)) +#define strrchr rindex +/* memset is only used for zero here, but let's be paranoid. */ +#define memset(s, better_be_zero, n) \ + ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0))) +#endif /* Not ANSI_STRING. */ + +#ifndef HAVE_STRCOLL +#define strcoll strcmp +#endif + + +#ifndef __GNU_LIBRARY__ +#ifdef __GNUC__ +__inline +#endif +#ifndef __SASC +#ifdef WIN32 +static void * +#else +static char * +#endif +my_realloc (p, n) + char *p; + unsigned int n; +{ + /* These casts are the for sake of the broken Ultrix compiler, + which warns of illegal pointer combinations otherwise. */ + if (p == NULL) + return (char *) malloc (n); + return (char *) realloc (p, n); +} +#define realloc my_realloc +#endif /* __SASC */ +#endif /* __GNU_LIBRARY__ */ + + +#if !defined(__alloca) && !defined(__GNU_LIBRARY__) + +#ifdef __GNUC__ +#undef alloca +#define alloca(n) __builtin_alloca (n) +#else /* Not GCC. */ +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#else /* Not HAVE_ALLOCA_H. */ +#ifndef _AIX +#ifdef WIN32 +#include <malloc.h> +#else +extern char *alloca (); +#endif /* WIN32 */ +#endif /* Not _AIX. */ +#endif /* sparc or HAVE_ALLOCA_H. */ +#endif /* GCC. */ + +#define __alloca alloca + +#endif + +#ifndef __GNU_LIBRARY__ +#define __stat stat +#ifdef STAT_MACROS_BROKEN +#undef S_ISDIR +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#endif + +#ifndef STDC_HEADERS +#undef size_t +#define size_t unsigned int +#endif + +/* Some system header files erroneously define these. + We want our own definitions from <fnmatch.h> to take precedence. */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD +#include <fnmatch.h> + +/* Some system header files erroneously define these. + We want our own definitions from <glob.h> to take precedence. */ +#undef GLOB_ERR +#undef GLOB_MARK +#undef GLOB_NOSORT +#undef GLOB_DOOFFS +#undef GLOB_NOCHECK +#undef GLOB_APPEND +#undef GLOB_NOESCAPE +#undef GLOB_PERIOD +#include <glob.h> + +static int glob_pattern_p __P ((const char *pattern, int quote)); +static int glob_in_dir __P ((const char *pattern, const char *directory, + int flags, + int (*errfunc) __P ((const char *, int)), + glob_t *pglob)); +static int prefix_array __P ((const char *prefix, char **array, size_t n)); +static int collated_compare __P ((const __ptr_t, const __ptr_t)); + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +int +glob (pattern, flags, errfunc, pglob) + const char *pattern; + int flags; + int (*errfunc) __P ((const char *, int)); + glob_t *pglob; +{ + const char *filename; + char *dirname; + size_t dirlen; + int status; + int oldcount; + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + errno = EINVAL; + return -1; + } + + if (flags & GLOB_BRACE) + { + const char *begin = strchr (pattern, '{'); + if (begin != NULL) + { + int firstc; + size_t restlen; + const char *p, *end, *next; + unsigned int depth = 0; + + /* Find the end of the brace expression, by counting braces. + While we're at it, notice the first comma at top brace level. */ + end = begin + 1; + next = NULL; + while (1) + { + switch (*end++) + { + case ',': + if (depth == 0 && next == NULL) + next = end; + continue; + case '{': + ++depth; + continue; + case '}': + if (depth-- == 0) + break; + continue; + case '\0': + return glob (pattern, flags &~ GLOB_BRACE, errfunc, pglob); + } + break; + } + restlen = strlen (end) + 1; + if (next == NULL) + next = end; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + + if (!(flags & GLOB_APPEND)) + { + /* This call is to set a new vector, so clear out the + vector so we can append to it. */ + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + firstc = pglob->gl_pathc; + + /* In this loop P points to the beginning of the current element + and NEXT points past its terminator. */ + p = begin + 1; + while (1) + { + /* Construct a whole name that is one of the brace + alternatives in a temporary buffer. */ + int result; + size_t bufsz = (begin - pattern) + (next - 1 - p) + restlen; +#ifdef __GNUC__ + char onealt[bufsz]; +#else + char *onealt = malloc (bufsz); + if (onealt == NULL) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return GLOB_NOSPACE; + } +#endif + memcpy (onealt, pattern, begin - pattern); + memcpy (&onealt[begin - pattern], p, next - 1 - p); + memcpy (&onealt[(begin - pattern) + (next - 1 - p)], + end, restlen); + result = glob (onealt, + ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) | + GLOB_APPEND), errfunc, pglob); +#ifndef __GNUC__ + free (onealt); +#endif + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return result; + } + + /* Advance past this alternative and process the next. */ + p = next; + depth = 0; + scan: + switch (*p++) + { + case ',': + if (depth == 0) + { + /* Found the next alternative. Loop to glob it. */ + next = p; + continue; + } + goto scan; + case '{': + ++depth; + goto scan; + case '}': + if (depth-- == 0) + /* End of the brace expression. Break out of the loop. */ + break; + goto scan; + } + } + + if (pglob->gl_pathc == firstc && + !(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + + /* Find the filename. */ + filename = strrchr (pattern, '/'); + if (filename == NULL) + { + filename = pattern; +#ifdef _AMIGA + dirname = (char *) ""; +#else + dirname = (char *) "."; +#endif + dirlen = 0; + } + else if (filename == pattern) + { + /* "/pattern". */ + dirname = (char *) "/"; + dirlen = 1; + ++filename; + } + else + { + dirlen = filename - pattern; + dirname = (char *) __alloca (dirlen + 1); + memcpy (dirname, pattern, dirlen); + dirname[dirlen] = '\0'; + ++filename; + } + + if (filename[0] == '\0' && dirlen > 1) + /* "pattern/". Expand "pattern", appending slashes. */ + { + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK); + return val; + } + + if (!(flags & GLOB_APPEND)) + { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + + oldcount = pglob->gl_pathc; + +#ifndef VMS + if ((flags & GLOB_TILDE) && dirname[0] == '~') + { + if (dirname[1] == '\0') + { + /* Look up home directory. */ + dirname = getenv ("HOME"); +#ifdef _AMIGA + if (dirname == NULL || dirname[0] == '\0') + dirname = "SYS:"; +#else +#ifdef WIN32 + if (dirname == NULL || dirname[0] == '\0') + dirname = "c:/users/default"; /* poor default */ +#else + if (dirname == NULL || dirname[0] == '\0') + { + extern char *getlogin __P ((void)); + char *name = getlogin (); + if (name != NULL) + { + struct passwd *p = getpwnam (name); + if (p != NULL) + dirname = p->pw_dir; + } + } + if (dirname == NULL || dirname[0] == '\0') + dirname = (char *) "~"; /* No luck. */ +#endif /* WIN32 */ +#endif + } + else + { +#ifdef _AMIGA + if (dirname == NULL || dirname[0] == '\0') + dirname = "SYS:"; +#else +#ifdef WIN32 + if (dirname == NULL || dirname[0] == '\0') + dirname = "c:/users/default"; /* poor default */ +#else + /* Look up specific user's home directory. */ + struct passwd *p = getpwnam (dirname + 1); + if (p != NULL) + dirname = p->pw_dir; +#endif /* WIN32 */ +#endif + } + } +#endif /* Not VMS. */ + + if (glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) + { + /* The directory name contains metacharacters, so we + have to glob for the directory, and then glob for + the pattern in each directory found. */ + glob_t dirs; + register int i; + + status = glob (dirname, + ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) | + GLOB_NOSORT), + errfunc, &dirs); + if (status != 0) + return status; + + /* We have successfully globbed the preceding directory name. + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) + { + int oldcount; + +#ifdef SHELL + { + /* Make globbing interruptible in the bash shell. */ + extern int interrupt_state; + + if (interrupt_state) + { + globfree (&dirs); + globfree (&files); + return GLOB_ABEND; + } + } +#endif /* SHELL. */ + + oldcount = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + (flags | GLOB_APPEND) & ~GLOB_NOCHECK, + errfunc, pglob); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + return status; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[oldcount], + pglob->gl_pathc - oldcount)) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + } + + flags |= GLOB_MAGCHAR; + + if (pglob->gl_pathc == oldcount) + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t len = strlen (pattern) + 1; + char *patcopy = (char *) malloc (len); + if (patcopy == NULL) + return GLOB_NOSPACE; + memcpy (patcopy, pattern, len); + + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + 1 + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + { + free (patcopy); + return GLOB_NOSPACE; + } + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + pglob->gl_pathv[pglob->gl_pathc++] = patcopy; + pglob->gl_pathv[pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + } + else + return GLOB_NOMATCH; + } + else + { + status = glob_in_dir (filename, dirname, flags, errfunc, pglob); + if (status != 0) + return status; + + if (dirlen > 0) + { + /* Stick the directory on the front of each name. */ + if (prefix_array (dirname, + &pglob->gl_pathv[oldcount], + pglob->gl_pathc - oldcount)) + { + globfree (pglob); + return GLOB_NOSPACE; + } + } + } + + if (flags & GLOB_MARK) + { + /* Append slashes to directory names. */ + int i; + struct stat st; + for (i = oldcount; i < pglob->gl_pathc; ++i) + if (((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_stat) (pglob->gl_pathv[i], &st) : + __stat (pglob->gl_pathv[i], &st)) == 0 && + S_ISDIR (st.st_mode)) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + return GLOB_NOSPACE; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } + } + + if (!(flags & GLOB_NOSORT)) + /* Sort the vector. */ + qsort ((__ptr_t) &pglob->gl_pathv[oldcount], + pglob->gl_pathc - oldcount, + sizeof (char *), collated_compare); + + return 0; +} + + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (pglob) + register glob_t *pglob; +{ + if (pglob->gl_pathv != NULL) + { + register int i; + for (i = 0; i < pglob->gl_pathc; ++i) + if (pglob->gl_pathv[i] != NULL) + free ((__ptr_t) pglob->gl_pathv[i]); + free ((__ptr_t) pglob->gl_pathv); + } +} + + +/* Do a collated comparison of A and B. */ +static int +collated_compare (a, b) + const __ptr_t a; + const __ptr_t b; +{ + const char *const s1 = *(const char *const * const) a; + const char *const s2 = *(const char *const * const) b; + + if (s1 == s2) + return 0; + if (s1 == NULL) + return 1; + if (s2 == NULL) + return -1; + return strcoll (s1, s2); +} + + +/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's + elements in place. Return nonzero if out of memory, zero if successful. + A slash is inserted between DIRNAME and each elt of ARRAY, + unless DIRNAME is just "/". Each old element of ARRAY is freed. */ +static int +prefix_array (dirname, array, n) + const char *dirname; + char **array; + size_t n; +{ + register size_t i; + size_t dirlen = strlen (dirname); + + if (dirlen == 1 && dirname[0] == '/') + /* DIRNAME is just "/", so normal prepending would get us "//foo". + We want "/foo" instead, so don't prepend any chars from DIRNAME. */ + dirlen = 0; + + for (i = 0; i < n; ++i) + { + size_t eltlen = strlen (array[i]) + 1; + char *new = (char *) malloc (dirlen + 1 + eltlen); + if (new == NULL) + { + while (i > 0) + free ((__ptr_t) array[--i]); + return 1; + } + + memcpy (new, dirname, dirlen); + new[dirlen] = '/'; + memcpy (&new[dirlen + 1], array[i], eltlen); + free ((__ptr_t) array[i]); + array[i] = new; + } + + return 0; +} + + +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +static int +glob_pattern_p (pattern, quote) + const char *pattern; + int quote; +{ + register const char *p; + int open = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote && p[1] != '\0') + ++p; + break; + + case '[': + open = 1; + break; + + case ']': + if (open) + return 1; + break; + } + + return 0; +} + + +/* Like `glob', but PATTERN is a final pathname component, + and matches are searched for in DIRECTORY. + The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. + The GLOB_APPEND flag is assumed to be set (always appends). */ +static int +glob_in_dir (pattern, directory, flags, errfunc, pglob) + const char *pattern; + const char *directory; + int flags; + int (*errfunc) __P ((const char *, int)); + glob_t *pglob; +{ + __ptr_t stream; + + struct globlink + { + struct globlink *next; + char *name; + }; + struct globlink *names = NULL; + size_t nfound = 0; + + if (!glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) + { + stream = NULL; + flags |= GLOB_NOCHECK; + } + else + { + flags |= GLOB_MAGCHAR; + + stream = ((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_opendir) (directory) : + (__ptr_t) opendir (directory)); + if (stream == NULL) + { + if ((errfunc != NULL && (*errfunc) (directory, errno)) || + (flags & GLOB_ERR)) + return GLOB_ABEND; + } + else + while (1) + { + const char *name; + size_t len; + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ? + (*pglob->gl_readdir) (stream) : + readdir ((DIR *) stream)); + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; + + name = d->d_name; + + if (fnmatch (pattern, name, + (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | + ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#ifdef _AMIGA + | FNM_CASEFOLD +#endif + ) == 0) + { + struct globlink *new + = (struct globlink *) __alloca (sizeof (struct globlink)); + len = NAMLEN (d); + new->name + = (char *) malloc (len + 1); + if (new->name == NULL) + goto memory_error; + memcpy ((__ptr_t) new->name, name, len); + new->name[len] = '\0'; + new->next = names; + names = new; + ++nfound; + } + } + } + + if (nfound == 0 && (flags & GLOB_NOMAGIC) && + ! glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) + flags |= GLOB_NOCHECK; + + if (nfound == 0 && (flags & GLOB_NOCHECK)) + { + size_t len = strlen (pattern); + nfound = 1; + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->next = NULL; + names->name = (char *) malloc (len + 1); + if (names->name == NULL) + goto memory_error; + memcpy (names->name, pattern, len); + names->name[len] = '\0'; + } + + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + + nfound + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + goto memory_error; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (; names != NULL; names = names->next) + pglob->gl_pathv[pglob->gl_pathc++] = names->name; + pglob->gl_pathv[pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + + if (stream != NULL) + { + int save = errno; + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + errno = save; + } + return nfound == 0 ? GLOB_NOMATCH : 0; + + memory_error: + { + int save = errno; + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + errno = save; + } + while (names != NULL) + { + if (names->name != NULL) + free ((__ptr_t) names->name); + names = names->next; + } + return GLOB_NOSPACE; +} + +#endif /* Not ELIDE_CODE. */ + diff --git a/Build/source/texk/contrib/glob/glob.h b/Build/source/texk/contrib/glob/glob.h new file mode 100644 index 00000000000..571bd5e4053 --- /dev/null +++ b/Build/source/texk/contrib/glob/glob.h @@ -0,0 +1,108 @@ +/* Copyright (C) 1991, 1992, 1995, 1996 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _GLOB_H + +#define _GLOB_H 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#undef __ptr_t +#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) \ + || defined (WIN32)) +#undef __P +#define __P(protos) protos +#define __ptr_t void * +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(protos) () +#undef const +#define const +#define __ptr_t char * +#endif /* C++ or ANSI C. */ + +/* Bits set in the FLAGS argument to `glob'. */ +#define GLOB_ERR (1 << 0)/* Return on read errors. */ +#define GLOB_MARK (1 << 1)/* Append a slash to each name. */ +#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */ +#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */ +#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */ +#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */ +#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */ +#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */ +#define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \ + GLOB_NOMAGIC|GLOB_TILDE) + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE) +#define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */ +#define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ +#define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */ +#define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */ +#define GLOB_TILDE (1 <<12)/* Expand ~user and ~ to home directories. */ +#endif + +/* Error returns from `glob'. */ +#define GLOB_NOSPACE 1 /* Ran out of memory. */ +#define GLOB_ABEND 2 /* Read error. */ +#define GLOB_NOMATCH 3 /* No matches found. */ + +/* Structure describing a globbing run. */ +#if !defined (_AMIGA) && !defined (VMS) /* Buggy compiler. */ +struct stat; +#endif +typedef struct + { + int gl_pathc; /* Count of paths matched by the pattern. */ + char **gl_pathv; /* List of matched pathnames. */ + int gl_offs; /* Slots to reserve in `gl_pathv'. */ + int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */ + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) __P ((void *)); + struct dirent *(*gl_readdir) __P ((void *)); + __ptr_t (*gl_opendir) __P ((const char *)); + int (*gl_lstat) __P ((const char *, struct stat *)); + int (*gl_stat) __P ((const char *, struct stat *)); + } glob_t; + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +extern int glob __P ((const char *__pattern, int __flags, + int (*__errfunc) __P ((const char *, int)), + glob_t *__pglob)); + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +extern void globfree __P ((glob_t *__pglob)); + + +#ifdef __cplusplus +} +#endif + +#endif /* glob.h */ diff --git a/Build/source/texk/contrib/irun.c b/Build/source/texk/contrib/irun.c new file mode 100644 index 00000000000..48eac01d9bb --- /dev/null +++ b/Build/source/texk/contrib/irun.c @@ -0,0 +1,569 @@ +/* link.c + +Copyright (C) 1997 - 2003 +Fabrice Popineau <Fabrice.Popineau@supelec.fr> + +This file is part of Web2c for Win32. + +Web2c For Win32 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, or +(at your option) any later version. + +Web2c For Win32 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 Web2c For Win32; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. */ + +/* + the goal of this file is to mimic Unix's ln command. This is a quick + hack, in that it will only allow to remap to predefined .exe files. +*/ + +#include <kpathsea/config.h> +#include <kpathsea/lib.h> +#include <kpathsea/proginit.h> +#include <kpathsea/progname.h> +#include <kpathsea/tex-file.h> + +#define IS_DIRSEP(c) ((c) == '/' || (c) == '\\') + +/* To be determined by 'dumpbin /symbols irun.exe' + web2c/Makefile automagically determines this value by making two passes + when compiling irun.exe +*/ + +typedef void (* PFN_kpse_set_program_name)(const_string, const_string); +typedef void (* PFN_kpse_init_prog)(const_string, unsigned, const_string, const_string); +typedef string (* PFN_kpse_find_file)(const_string, kpse_file_format_type, boolean); + +#ifndef RDATA +#include "irun.h" +#endif + +#pragma section("FOOBAR", read) + +#define marker "foobar" + +#undef DEBUG + +/* Initialized with marker string */ + __declspec(allocate("FOOBAR")) const char newargv0[MAX_PATH] = marker; + +/* + This programme should emulate Unix's ln for .exe files under Win32. + + Usage: irun <src> <dest> + + Method used: this .exe file is located, copied to the destination + using the new name for the destination, while changing the newargv0 + constant to the src file name. + + Caveat: to be portable, the src file name should not be absolute. + It should be either a pathname relative to the current executable file, + either a simple name which may be looked for along the PATH, or only + in the same directory as the current executable file. + + Adopted strategy: relative pathes are ok, absolute one will give a + warning when doing the link. + +*/ + +#define DIR_SEP '/' +#define DIR_SEP_STRING "/" +#define IS_DEVICE_SEP(ch) ((ch) == ':') +#define NAME_BEGINS_WITH_DEVICE(name) (*(name) && IS_DEVICE_SEP((name)[1])) +/* On DOS, it's good to allow both \ and / between directories. */ +#define IS_DIR_SEP(ch) ((ch) == '/' || (ch) == '\\') +/* On win32, UNC names are authorized */ +#define IS_UNC_NAME(name) (strlen(name)>=3 && IS_DIR_SEP(*name) \ + && IS_DIR_SEP(*(name+1)) && isalnum(*(name+2))) + +char cmdline[MAX_PATH]; +char autoloc[MAX_PATH]; +char *progname; + +BOOL WINAPI catch_interrupt(DWORD arg) +{ + switch (arg) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + return TRUE; + default: + /* No need to set interrupt as we are exiting anyway */ + return FALSE; + } +} + +#if 0 +static BOOL +is_absolute(const char *filename) +{ + BOOL absolute = IS_DIR_SEP (*filename) + /* Novell allows non-alphanumeric drive letters. */ + || (*filename && IS_DEVICE_SEP (filename[1])) + /* UNC names */ + || IS_UNC_NAME(filename) + ; + BOOL explicit_relative = (*filename == '.' && (IS_DIR_SEP (filename[1]) + || (filename[1] == '.' && IS_DIR_SEP (filename[2])))); + /* FIXME: On UNIX an IS_DIR_SEP of any but the last character in the name + implies relative. */ + return absolute || explicit_relative; +} +#else +is_absolute(const char *path) +{ + return IS_DIRSEP(*path) + || ( isalpha(*path) && *(path+1) == ':' && IS_DIRSEP(*path) ); +} +#endif + +is_relative(const char *path) +{ + return (*path == '.' && + (IS_DIRSEP(*(path+1)) + || (*(path+1) == '.' && IS_DIRSEP(*(path+2))))); +} + +char *look_for_target(char *name, char *cmdline) +{ + char name_drive[_MAX_DRIVE], name_dir[_MAX_DIR], name_fname[_MAX_FNAME], name_ext[_MAX_EXT]; + char *cmd = NULL, *script = NULL, *exepath; + char *cmdarg = NULL; + + _splitpath(name, 0, 0, name_fname, name_ext); +#ifdef DEBUG + fprintf(stderr, "name = %s\n", name); +#endif + if (_stricmp(name_ext, ".exe") == 0) { + if (is_relative(name)) { + /* In this case, catenate the directory of the invoked program + with the relative name stored in the link */ + char *unquoted_cmd; + _splitpath(_pgmptr, name_drive, name_dir, 0, 0); + unquoted_cmd = concatn(name_drive, name_dir, name, NULL); + cmd = quote_filename(unquoted_cmd); + free(unquoted_cmd); + /* Do not forget to se the new name to the result, used below */ + name = xdirsimplify(cmd); + } + else { + cmd = name; + } + } + else { + if (_stricmp(name_ext, ".pl") == 0) { + cmd = "perl.exe"; + } + else if (_stricmp(name_ext, ".py") == 0) { + cmd = "python.exe"; + } + else if (_stricmp(name_ext, ".rb") == 0) { + cmd = "ruby.exe"; + } + else if (_stricmp(name_ext, ".java") == 0) { + cmd = "java.exe"; + } + else if (_stricmp(name_ext, ".jar") == 0) { + cmd = "java.exe"; + cmdarg = " -cp "; + } + else { + fprintf (stderr, "Unknown file type: %s%s\n", name_fname, name_ext); + return NULL; + } + } + + if (look_for_cmd(cmd, &exepath) == FALSE) { + fprintf (stderr, "File not found: %s\n", cmd); + return NULL; + } + + { + char *quoted_exepath = quote_filename(exepath); + strcpy(cmdline, quoted_exepath); +#ifdef DEBUG + fprintf(stderr, "quoted_exepath = %s\n", quoted_exepath); +#endif + free(exepath); + free(quoted_exepath); + } + + if (cmd != name) { + /* This is a script, need to find it */ + if (is_absolute(name)) { + script = name; + } + else { + /* Let's try kpathsea if available ! */ + HMODULE hKPSEDll = 0; + PFN_kpse_set_program_name pkpsedll_set_program_name = NULL; + PFN_kpse_init_prog pkpsedll_init_prog = NULL; + PFN_kpse_find_file pkpsedll_find_file = NULL; + char *progname = xstrdup(cmd); + unsigned int dpi = 600; + char *p = strrchr(progname, '.'); + if (p) *p = '\0'; +#ifdef DEBUG + fprintf(stderr, "progname = %s\n", progname); +#endif + if ((hKPSEDll = LoadLibrary(KPATHSEA_DLL)) != NULL) { + + pkpsedll_set_program_name = (PFN_kpse_set_program_name)GetProcAddress(hKPSEDll, "@kpse_set_program_name@8"); + pkpsedll_init_prog = (PFN_kpse_init_prog)GetProcAddress(hKPSEDll, "@kpse_init_prog@16"); + pkpsedll_find_file = (PFN_kpse_find_file)GetProcAddress(hKPSEDll, "@kpse_find_file@12"); + if (pkpsedll_set_program_name && pkpsedll_init_prog && pkpsedll_find_file) { + (*pkpsedll_set_program_name)("irun", progname); + (*pkpsedll_init_prog)(uppercasify (kpse_program_name), dpi, NULL, NULL); + script = (*pkpsedll_find_file)(name, kpse_texmfscripts_format, TRUE); + } + FreeLibrary(hKPSEDll); + } + if (! script) { + fprintf(stderr, "irun: no %s script\nof name %s can be found.\nAborting.\n", + cmd, name); + *cmdline = '\0'; + } + free(progname); + } + } + + if (script) { + char *quoted_script = quote_filename(script); + if (cmdarg) + strcat(cmdline, cmdarg); + else + strcat(cmdline, " "); + strcat(cmdline, quoted_script); + strcat(cmdline, " "); + free (quoted_script); + free (script); + } + +#ifdef DEBUG + fprintf(stderr, "cmdline = %s\n", cmdline); +#endif + return cmdline; +} + +int link(char *src, char *dest, int force, int verbose, char *args[], int argc) +{ + int fdest; + int cmdlen; + +#ifdef DEBUG + if (1) +#else + if (verbose) +#endif + fprintf(stdout, "Linking %s to %s.\n", src, dest); + + if (is_absolute(src)) + fprintf(stderr, "Warning: source file %s is absolute!\n", src); + + /* Looking for the source. */ + if (SearchPath(NULL, "irun", ".exe", MAX_PATH, autoloc, + NULL) == 0) { + fprintf(stderr, "irun: can't find the program.\n"); + exit(1); + } + +#ifdef DEBUG + fprintf(stderr, "Autoloc = %s\n", autoloc); +#endif + + if (CopyFile(autoloc, dest, !force) == 0) { + fprintf(stderr, "Can't copy to %s (file may already exist).\n", + dest); + exit(1); + } + + /* Don't look for target now: it will be looked for at run time */ + strcpy(cmdline, src); + cmdlen = strlen(cmdline); + + /* if there are arguments left on the command line, catenate them */ + while (argc--) { + strcpy(cmdline+cmdlen+1, *args); + cmdlen += strlen(*args) + 1; +#ifdef DEBUG + fprintf(stderr, "argc = %d, cmdlen = %d, args = %s\n", argc, cmdlen, *args); +#endif + args++; + } + cmdline[cmdlen+1] = '\0'; + +#ifdef DEBUG + fprintf(stderr, "Cmdline = %s\n", cmdline); +#endif + + /* Now we need to put cmdline into the newargv0 variable in dest + file. + We could use the PE file format specfication to locate the .rdata + section , but is it actually needed :-) + In fact, we need to find the marker string "foobarbaz" and store + the name here. + */ + /* Open the file */ + if ((fdest = _open(dest, _O_RDWR | _O_BINARY)) == 0) { + perror("Can't open target file"); + exit(1); + } + /* Look for the marker string */ + if (_lseek(fdest, RDATA, SEEK_SET) < 0) { + perror("Can't seek to .rdata"); + exit(1); + } + + if (_read(fdest, autoloc, MAX_PATH) < 0) { + perror("Can't read into dest file"); + exit(1); + } + if (strcmp(autoloc, newargv0) != 0) { + fprintf(stderr, "irun: marker string not found in %s.\n", dest); + exit(1); + } + + if (_lseek(fdest, RDATA, SEEK_SET) < 0) { + perror("Can't seek (2) to .rdata"); + exit(1); + } + + if (_write(fdest, cmdline, cmdlen+1) < 1) { + perror("Can't write into dest file"); + exit(1); + } + + /* Close the file */ + _close(fdest); + + return 0; +} + +char *usage_msg = + "Usage: %s [-f] [-v] <src> <dest>\nwill link <src> to <dest>\n" + "Option -f will force the link, -v is verbose.\n" + " If src is absolute, a warning is emitted because the hard link\n" + " is not portable.\n" + " If src is a relative path, it is relative to the dest path.\n" + " If src has one of the .java, .jar, .pl, .py or .rb extension,\n" + " it is assumed to be a script, and the executable linked to is\n" + " java.exe (for .java and .jar), perl.exe, python.exe and ruby.exe.\n" + " Those programs must be in accessible through your PATH.\n" + " If the script is not found, kpathsea is used to locate it through\n" + " the $JAVAINPUTS, $PERLINPUTS, $PYTHONINPUTS and $RUBYINPUTS variables.\n"; + +void usage() +{ + fprintf(stderr, usage_msg, progname); + exit(1); +} + +int +main (int argc, char *argv[]) + +{ + int rc; + size_t j = 0; + int force = 0, verbose = 0; + + for (progname = argv[0] + strlen(argv[0]) -1; + progname > argv[0] && *(progname-1) != '/' && *(progname-1) != '\\'; + progname--); +#ifdef DEBUG + fprintf(stderr, "progname = %s\n", progname); +#endif + +#ifdef DEBUG + fprintf(stderr, "argc = %d, argv[0] = %s\n", argc, argv[0]); +#endif + + if (strcasecmp(progname, "irun.exe") == 0 + || strcasecmp(progname, "irun") == 0) { + /* Doing the link */ + + if (argc == 1) + usage(); + + /* First, parse arguments */ + while (--argc > 0 && *(++argv)[0] == '-') { +#ifdef DEBUG + fprintf(stderr, "arg: %s\n", argv[0]); +#endif + switch (*(argv[0]+1) == '-' ? *(argv[0]+2) : *(argv[0]+1)) { + case 'f': + force = 1; + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(); + exit(0); + } + } + + if (argc < 2) + usage(); + + link(argv[0], argv[1], force, verbose, argv+2, argc - 2); + } + else { + /* Calling the target program. Unfortunately, exec does not seem + to work under NT as expected. */ + + char *newargv[256]; + boolean quoted = false; + char *p, *q, *newcmd, *new_line, *new_argv_i; + int i, newargc = 0; + STARTUPINFO si; + PROCESS_INFORMATION pi; + + SetConsoleCtrlHandler(catch_interrupt, TRUE); + + /* Looking for the target. */ + /* Either it is an executable or a (Perl|Python|Ruby|Java) script */ + /* If it is a script and kpathsea is available, then it should be + searched for */ + if (look_for_target(newargv0, autoloc) == NULL) { + fprintf(stderr, "%s: can't find the target %s.\n", + progname, newargv0); + exit(1); + } + + p = q = autoloc; +#ifdef DEBUG + fprintf(stderr, "autoloc = %s\n", autoloc); +#endif + /* Fix up in the case of a script */ + do { + if (*p == '"') { + quoted = !quoted; + p++; + } + + if (*p == ' ' && !quoted) { + *p = '\0'; + newargv[newargc++] = unquote_filename(q); + q = ++p; + } + else if (*p == '\0') { + newargv[newargc++] = unquote_filename(q); + break; + } + else { + p++; + } + } while (1); +#ifdef DEBUG + fprintf(stderr, "stage1\n"); + for (i = 0; i < newargc; i++) { + fprintf(stderr, "newargv[%d] = %s\n", i, newargv[i]); + } +#endif + + /* Add any argument */ + p = newargv0 + strlen(newargv0) + 1; + while (*p) { + newargv[newargc++] = p; + p += strlen(p) + 1; + } +#ifdef DEBUG + fprintf(stderr, "stage2\n"); + for (i = 0; i < newargc; i++) { + fprintf(stderr, "newargv[%d] = %s\n", i, newargv[i]); + } +#endif + + if (*p) { + newargv[newargc++] = unquote_filename(p); + } +#ifdef DEBUG + fprintf(stderr, "stage3\n"); + for (i = 0; i < newargc; i++) { + fprintf(stderr, "newargv[%d] = %s\n", i, newargv[i]); + } +#endif + + for (i = 1; i < argc; i++) { + newargv[newargc++] = argv[i]; + } + newargv[newargc] = NULL; +#ifdef DEBUG + fprintf(stderr, "stage4\n"); + for (i = 0; i < newargc; i++) { + fprintf(stderr, "newargv[%d] = %s\n", i, newargv[i]); + } +#endif + +#if 1 + newcmd = quote_filename(_pgmptr); + for (i = 1; newargv[i]; i++) { + new_argv_i = quote_filename(newargv[i]); + new_line = concat3(newcmd, " ", new_argv_i); + free(newcmd); + free(new_argv_i); + newcmd = new_line; + } + + ZeroMemory( &si, sizeof(STARTUPINFO) ); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ; + si.wShowWindow = 0 ; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + +#ifdef DEBUG + fprintf(stderr, "argv0 = %s, newargv0 = %s\n", _pgmptr, newargv[0]); +#endif + /* creating child process */ + if (CreateProcess(newargv[0], /* pointer to name of executable module */ + newcmd, /* pointer to command line string */ + NULL, /* pointer to process security attributes */ + NULL, /* pointer to thread security attributes */ + TRUE, /* handle inheritance flag */ + 0, /* creation flags */ + NULL, /* pointer to environment */ + NULL, /* pointer to current directory */ + &si, /* pointer to STARTUPINFO */ + &pi /* pointer to PROCESS_INFORMATION */ + ) == FALSE) { + fprintf(stderr, "irun: CreateProcess %x\n", GetLastError()); + return NULL; + } + + /* Only the process handle is needed, ignore errors */ + CloseHandle(pi.hThread); + + /* Waiting for the process to terminate */ + if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) { + fprintf(stderr, "irun: error, process still active\n"); + rc = -1; + } + + /* retrieving the exit code */ + if (GetExitCodeProcess(pi.hProcess, &rc) == 0) { + fprintf(stderr, "irun: can't get process exit code\n"); + rc = -1; + } +#else + + rc = _spawnvp (_P_WAIT, newargv[0], newargv); +#endif + if (rc < 0) { + perror (cmdline); + return (1); + } + return (rc); + } + return 0; +} + +/* link.c ends here */ diff --git a/Build/source/texk/contrib/irun.h b/Build/source/texk/contrib/irun.h new file mode 100644 index 00000000000..fa0a72e0ec0 --- /dev/null +++ b/Build/source/texk/contrib/irun.h @@ -0,0 +1 @@ +#define RDATA 0x2000 diff --git a/Build/source/texk/contrib/irun.rc b/Build/source/texk/contrib/irun.rc new file mode 100644 index 00000000000..2c005745d38 --- /dev/null +++ b/Build/source/texk/contrib/irun.rc @@ -0,0 +1,34 @@ +/* irun.rc: irun resources -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " irun 1.0" + +#define VER_INTERNALNAME_STR "irun" +#define VER_ORIGINALFILENAME_STR "irun.exe" + +#define VER_FILEDESCRIPTION_STR "Emulate Unix's ln -s for .exe|.pl|.py|.rb files" + +#define VER_LEGALCOPYRIGHT_STR " Copyright (c) 1997-2003 by Fabrice Popineau." + +#include <texlive.version> + +/* irun.rc ends here */ diff --git a/Build/source/texk/contrib/libmktex.rc b/Build/source/texk/contrib/libmktex.rc new file mode 100644 index 00000000000..0724ec5ccd8 --- /dev/null +++ b/Build/source/texk/contrib/libmktex.rc @@ -0,0 +1,36 @@ +/* libmktex.rc: libmktex resources -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " mktex library 2.0" + +#define VER_INTERNALNAME_STR TEXLIVE_LIBRARYPREFIX_STR "mktx" +#define VER_ORIGINALFILENAME_STR TEXLIVE_LIBRARYPREFIX_STR "mktx.dll" + +#define VER_FILEDESCRIPTION_STR "MkTeX all-purpose build TeX files" + +#define VER_LEGALCOPYRIGHT_STR "(C) 1997-2003 Fabrice Popineau & Eli Zaretskii\0" + +#define VER_FILETYPE VFT_DLL + +#include <texlive.version> + +/* libmktex.rc ends here */ diff --git a/Build/source/texk/contrib/main.c b/Build/source/texk/contrib/main.c new file mode 100644 index 00000000000..650c9cc682b --- /dev/null +++ b/Build/source/texk/contrib/main.c @@ -0,0 +1,91 @@ + +#include "mktex.h" +#include "stackenv.h" +#include "variables.h" +#include "fileutils.h" + +void __cdecl output_and_cleanup(int code) +{ + FILE *f; + string line; + + if (code == 0) { + /* output result if any */ + if ((f = fopen(getval("STDOUT"), "r")) != NULL) { + if (redirect_stdout >= 0) { + int fds[3]; + + fds[0] = 0; + fds[1] = redirect_stdout; + fds[2] = 2; + push_fd(fds); + } + while((line = read_line(f)) != NULL) { + fputs(line, stdout); + free (line); + } + fclose(f); + if (redirect_stdout >= 0) { + pop_fd(); + redirect_stdout = -1; + } + } + } + + if (test_file('d', tmpdir)) + rec_rmdir(tmpdir); + + { + int count = 0; + /* Give more than one chance to remove the files */ + while ((count++ < 20) && test_file('d', tmpdir)) { + Sleep(250); + rec_rmdir(tmpdir); + } + } +} + +int main(int argc, char* argv[]) +{ + program_description * program = 0; + int i, errstatus; +#if defined(WIN32) + /* if _DEBUG is not defined, these macros will result in nothing. */ + SETUP_CRTDBG; + /* Set the debug-heap flag so that freed blocks are kept on the + linked list, to catch any inadvertent use of freed memory */ + SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF ); +#endif + + redirect_stdout = -1; + output_and_cleanup_function = output_and_cleanup; + +#if 0 + extern MKTEXDLL string (* var_lookup)(const_string); + var_lookup = getval; +#endif + + mktexinit(argc, argv); + + for(i = 0; makedesc[i].name; ++i) { + if (FILESTRCASEEQ(kpse_program_name, makedesc[i].name)) { + program_number = i; + progname = makedesc[i].name; + program = makedesc+i; + break; + } + } + if (!makedesc[i].name) { + fprintf(stderr, "This program was incorrectly copied to the name %s\n", + argv[0]); + return 1; + } + + /* mktex_opt may modify argc and shift argv */ + argc = mktex_opt(argc, argv, program); + + errstatus = program->prog(argc, argv); + + mt_exit(errstatus); + return 0; /* Not reached !!! */ +} diff --git a/Build/source/texk/contrib/makempx.c b/Build/source/texk/contrib/makempx.c new file mode 100644 index 00000000000..d6c2fda5dfb --- /dev/null +++ b/Build/source/texk/contrib/makempx.c @@ -0,0 +1,630 @@ +/* makempx.c: this program emulates the makempx shell script from Metapost. + +Copyright (C) 1997 Fabrice POPINEAU. + +Adapted to DJGPP by Eli Zaretskii. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* #!/bin/sh */ +/* # '$Id: makempx.c,v 1.10 2002/10/06 14:03:14 olaf Exp $' */ +/* # Make an MPX file from the labels in a MetaPost source file, */ +/* # using mpto and either dvitomp (TeX) or dmp (troff). */ +/* # From John Hobby's original (though there's not much of it left by now). */ +/* # Public domain. */ + +/* rcs_revision='$Revision: 1.10 $' */ +/* version=`set - $rcs_revision; echo $2` */ + +/* : ${DMP=dmp} */ +/* : ${DVITOMP=dvitomp} */ +/* : ${MAKEMPX_BINDIR="j:\\TeX\\bin"} */ +/* : ${MPTEXPRE=mptexpre.tex} */ +/* : ${MPTOTEX="mpto -tex"} */ +/* : ${MPTOTR="mpto -troff"} */ +/* : ${NEWER=newer} */ +/* : ${TEX=tex} */ +/* : ${TROFF='eqn -d\$\$ | troff -Tpost'} */ + +/* PATH=$MAKEMPX_BINDIR:/bin:/usr/bin:$PATH */ + +/* # These names are documented in the MetaPost manual, so it's */ +/* # unwise to change them. */ +/* ERRLOG=mpxerr.log # file for an error log if necessary */ +/* TEXERR=mpxerr.tex # file for erroneous TeX if any */ +/* DVIERR=mpxerr.dvi # troublesome dvi file if any */ +/* TROFF_INERR=mpxerr # file for erroneous troff input, if any */ +/* TROFF_OUTERR=mpxerr.t # file for troublesome troff output, if any */ + + +/* usage="Usage: $0 [-tex|-troff] MPFILE MPXFILE. */ +/* If MPXFILE is older than MPFILE, translate the labels from the MetaPost */ +/* input file MPFIle to low-level commands in MPXFILE, by running */ +/* $MPTOTEX, $TEX, and $DVITOMP */ +/* by default; or, if -troff is specified, */ +/* $MPTOTR, $TROFF, and $DMP. */ + +/* The current directory is used for writing temporary files. Errors are */ +/* left in mpxerr.{tex,log,dvi}. */ + +/* If the file named in \$MPTEXPRE (mptexpre.tex by default) exists, it is */ +/* prepended to the output in tex mode. */ + +/* Email bug reports to tex-k@mail.tug.org." */ + + +/* mode=tex */ + +/* while test $# -gt 0; do */ +/* case "$1" in */ +/* -help|--help) */ +/* echo "$usage"; exit 0;; */ +/* -version|--version) */ +/* echo "`basename $0` (Web2c 6.98) $version" */ +/* echo "There is NO warranty. This script is public domain. */ +/* Primary author: John Hobby; Web2c maintainer: K. Berry." */ +/* exit 0;; */ +/* -troff|--troff) mode=troff;; */ +/* -tex|--tex) mode=tex;; */ +/* -*) */ +/* echo "$0: Invalid option: $1." >&2 */ +/* echo "Try \``basename $0` --help' for more information." >&2 */ +/* exit 1;; */ +/* *) */ +/* if test -z "$MPFILE"; then */ +/* MPFILE=$1 # input file */ +/* elif test -z "$MPXFILE"; then */ +/* MPXFILE=$1 # output file */ +/* else */ +/* echo "$0: Extra argument $1." >&2 */ +/* echo "Try \``basename $0` --help' for more information." >&2 */ +/* exit 1 */ +/* fi;; */ +/* esac */ +/* shift */ +/* done */ + +/* if test -z "$MPFILE" || test -z "$MPXFILE"; then */ +/* echo "$0: Need exactly two file arguments." >&2 */ +/* echo "Try \``basename $0` --help' for more information." >&2 */ +/* exit 1 */ +/* fi */ + +/* trap "rm -f mpx$$.* $ERRLOG; exit 4" 1 2 3 15 */ + +/* # If MPX file is up-to-date, do nothing. */ +/* if $NEWER $MPFILE $MPXFILE; then */ + +/* # Have to remake. */ +/* # Step 0: Check typesetter mode for consistency. */ +/* case "$mode" in */ +/* tex) MPTO="$MPTOTEX";; */ +/* troff) MPTO="$MPTOTR";; */ +/* *) echo "$0: Unknown typesetter mode: $mode" >&2 */ +/* exit 1;; */ +/* esac */ + +/* # Step 1: Extract typesetter source from MetaPost source. */ +/* if $MPTO $MPFILE >mpx$$.tex 2>$ERRLOG; then :; */ +/* # success */ +/* else */ +/* # failure */ +/* echo "$0: Command failed: $MPTO $MPFILE" >&2 */ +/* cat $ERRLOG >&2 */ +/* rm -f mpx$$.tex */ +/* exit 1 */ +/* fi */ +/* if test "$mode" = troff; then */ +/* mv -f mpx$$.tex mpx$$.i */ +/* fi */ + +/* # Step 2: Run typesetter. */ +/* if test "$mode" = tex; then */ +/* if test -r $MPTEXPRE; then */ +/* # Prepend user file. */ +/* cat $MPTEXPRE mpx$$.tex >mpx$$.tmp */ +/* mv mpx$$.tmp mpx$$.tex */ +/* fi */ + +/* if $TEX '\batchmode\input 'mpx$$.tex </dev/null >/dev/null; then */ +/* WHATEVER_TO_MPX="$DVITOMP" */ +/* INFILE=mpx$$.dvi */ +/* INERROR=$DVIERR */ +/* else */ +/* # failure */ +/* mv -f mpx$$.tex $TEXERR */ +/* mv -f mpx$$.log $ERRLOG */ +/* echo "$0: Command failed: $TEX $TEXERR; see $ERRLOG" >&2 */ +/* exit 2 */ +/* fi */ +/* elif test "$mode" = troff; then */ +/* if cat mpx$$.i | eval $TROFF >mpx$$.t; then */ +/* # success, prepare for step 3. */ +/* WHATEVER_TO_MPX="$DMP" */ +/* INFILE=mpx$$.t */ +/* INERROR=$TROFF_OUTERR */ +/* else */ +/* # failure */ +/* mv -f mpx$$.i $TROFF_INERR */ +/* echo "$0: Command failed: cat $TROFFERR | $TROFF" >&2 */ +/* rm -f mpx$$.t */ +/* exit 2 */ +/* fi */ +/* else */ +/* echo "$0: Unknown typesetter mode: $mode; how did this happen?" >&2 */ +/* exit 2 */ +/* fi */ + +/* # Step 3: Translate typesetter output to a MetaPost MPX. */ +/* if $WHATEVER_TO_MPX $INFILE $MPXFILE >$ERRLOG; then */ +/* : # success */ +/* else */ +/* # failure */ +/* mv -f $INFILE $INERROR */ +/* test $mode = troff && mv -f mpx$$.i $TROFF_INERR */ +/* echo "$0: Command failed: $WHATEVER_TO_MPX $INERROR $MPXFILE" >&2 */ +/* # Better to remove $MPXFILE if something went wrong rather than */ +/* # leaving behind an unfinished or unusable version since $NEWER */ +/* # might think that all is fine if $MPXFILE exists. */ +/* rm -f $MPXFILE */ +/* cat $ERRLOG >&2 */ +/* exit 3 */ +/* fi */ + +/* rm -f $ERRLOG mpx$$.* */ +/* fi */ + +/* exit 0 */ + +/* + Global Variables + */ +/* #include <assert.h> */ +#include "mktex.h" +#include "stackenv.h" +#include "fileutils.h" + +static char *DMP; +static char *DVITOMP; +static char *MAKEMPX_BINDIR; +static char *MPTEXPRE; +static char *MPTOTEX; +static char *MPTOTR; +static char *NEWER; +static char *TEX; +static char *TROFF; + +static struct alist { + char *key; + char **var; + char *val; +} vardef[] = { + {"DMP", &DMP, "dmp"}, + {"DVITOMP", &DVITOMP, "dvitomp"}, +#ifdef _WIN32 + {"MAKEMPX_BINDIR", &MAKEMPX_BINDIR, "c:\\TeX\\bin"}, +#else +#ifdef __DJGPP__ + {"MAKEMPX_BINDIR", &MAKEMPX_BINDIR, "c:/djgpp/bin"}, +#else + {"MAKEMPX_BINDIR", &MAKEMPX_BINDIR, "/usr/local/bin"}, +#endif +#endif + {"MPTEXPRE", &MPTEXPRE, "mptexpre.tex"}, + {"MPTOTEX", &MPTOTEX, "mpto -tex"}, + {"MPTOTR", &MPTOTR, "mpto -troff"}, + {"NEWER", &NEWER, "newer"}, + {"TEX", &TEX, "tex --parse-first-line"}, +#ifdef _WIN32 + {"TROFF", &TROFF, "eqn -d$$ | troff -Tpost"}, +#else +#ifdef __DJGPP__ + /* DJGPP users are likely to have Groff whose PostScript device is `ps'. */ + {"TROFF", &TROFF, "eqn -d'$$' | troff -Tps"}, +#else + {"TROFF", &TROFF, "eqn -d'$$' | troff -Tpost"}, +#endif +#endif + {NULL, NULL, NULL} +}; + +static char *MPTO, *INFILE, *INERROR, *WHATEVER_TO_MPX; +static char mptemplate[FILENAME_MAX]; + +/* These names are documented in the MetaPost manual, so it's */ +/* unwise to change them. */ +char *ERRLOG="mpxerr.log"; /* file for an error log if necessary */ +char *TEXERR="mpxerr.tex"; /* file for erroneous TeX if any */ +char *DVIERR="mpxerr.dvi"; /* troublesome dvi file if any */ +char *TROFF_INERR="mpxerr"; /* file for erroneous troff input, if any */ +char *TROFF_OUTERR="mpxerr.t";; /* file for troublesome troff output, if any */ +char *MPFILE = NULL; +char *MPXFILE = NULL; + +char *version = "Revision: 1.7"; +extern MKTEXDLL string mktex_version_string; + +typedef enum { TEXMODE = 0, TROFFMODE} typeset_mode; + +#ifdef __GNUC__ +void __attribute__((noreturn)) usage(int exit_code) +#else +void usage(int exit_code) +#endif +{ + fprintf(stderr, "Usage: %s [-tex|-tex=<program>|-troff] MPFILE MPXFILE.\n\ + If MPXFILE is older than MPFILE, translate the labels from the MetaPost\n\ + input file MPFILE to low-level commands in MPXFILE, by running\n\ + %s, %s, and %s\n\ + by default; or, if -troff is specified,\n\ + %s, %s, and %s.\n\ +\n\ + If the TeX mode is choosen, the TeX <program> used to typeset the labels\n\ + can be specified and is `tex' by default.\n\ +\n\ + The current directory is used for writing temporary files. Errors are\n\ + left in mpxerr.{tex,log,dvi}.\n\ +\n\ + If the file named in $MPTEXPRE (mptexpre.tex by default) exists, it is\n\ + prepended to the output in tex mode.\n\ +\n\ + Email bug reports to tex-k@mail.tug.org.\n", + progname, MPTOTEX, TEX, DVITOMP, MPTOTR, TROFF, DMP); + mt_exit(exit_code); +} + +void printversion(void) +{ + fprintf(stderr, "%s: (Web2c 7.0) %s\n", progname, version); + fprintf(stderr, "%s: C replacement version %s\n", progname, mktex_version_string); + fprintf(stderr, "There is NO warranty. This program is public domain.\n\ +Primary author: John Hobby; Web2c maintainer: K. Berry;\n\ +C version: F. Popineau and Eli Zaretskii."); + mt_exit(0); +} + +void output_file(FILE *f, const_string name) +{ + FILE *fp; + string line; + + if ((fp = fopen(name, "r")) == NULL) { + perror(name); + } + else { + while((line = read_line(fp)) != NULL) { + fputs(line, f); + free(line); + } + fclose(fp); + } +} + +void __cdecl output_and_cleanup(int code) +{ +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + HANDLE hnd; + boolean go_on; + + if (mptemplate && *mptemplate) { + string temp = concat(mptemplate, ".*"); + /* rm -f mpxXXXXX.* */ + hnd = FindFirstFile(temp, &ffd); + go_on = (hnd != INVALID_HANDLE_VALUE); + while (go_on) { + if (! (ffd.cFileName[0] == '.' + && (ffd.cFileName[1] == '\0' + || (ffd.cFileName[1] == '.' + && ffd.cFileName[2] == '\0')))) { + DeleteFile(ffd.cFileName); + } + go_on = (FindNextFile(hnd, &ffd) == TRUE); + } + FindClose(hnd); + free(temp); + } +#else + DIR *dp; + struct dirent *de; + int temp_len = strlen(mptemplate) + 1; /* +1 for the dot */ + + if ((dp = opendir(".")) != 0) { + while ((de = readdir(dp)) != 0) + if (FILESTRNCASEEQ(de->d_name, mptemplate, temp_len)) + remove(de->d_name); + } +#endif + + /* ERRLOG is removed only on normal exit. */ + if (code == 0) + remove(ERRLOG); + +} + +char *change_suffix(char *old, char *suf) +{ + char *p, *new; + new = xstrdup(old); + p = strrchr(new, '.'); /* assumes there are no slashes in OLD */ + if (p) + strcpy(p, suf); + else + strcat(new, suf); + return new; +} + +/* This does what `newer' does, but avoids forking a child. */ +int newer(const char *first, const char *second) +{ + struct stat x, y; + + /* does the first file exist? */ + if (stat(first, &x) < 0) + return 0; + + /* does the second file exist? */ + if (stat(second, &y) < 0) + return 1; + + /* is the first file older than the second? */ + if (x.st_mtime < y.st_mtime) + return 0; + + return 1; +} + +int main(int argc, char *argv[]) +{ + struct alist *p; + char buf[1024]; + char cmd[512]; + typeset_mode mode = TEXMODE; + int i, newfd[3]; + FILE *ferr, *fmpx, *ftroff; + char mpxtex[32]; + char *mpxi = NULL, *mpxt, *mpxtmp, *mpxlog, *mpxdvi; + string path; + string mpto_cmd; + char errbuf[PATH_MAX*2]; + int mpto_status; + + output_and_cleanup_function = output_and_cleanup; + mptemplate[0] = '\0'; + + if (!progname) + progname = argv[0]; + kpse_set_progname (progname); + + /* initialize the symbol table */ + init_vars(); + +#ifdef WIN32 + SetConsoleCtrlHandler((PHANDLER_ROUTINE)mt_exit, TRUE); +#else +# ifdef SIGINT + signal (SIGINT, sigint_handler); +# endif +# ifdef SIGQUIT + signal (SIGQUIT, sigint_handler); +# endif +# ifdef SIGHUP + signal (SIGHUP, sigint_handler); +# endif +# ifdef SIGTERM + signal (SIGTERM, sigint_handler); +# endif +#endif + + /* First assigning default values to all variables. */ + for(p = vardef; p->key != NULL; p++) { + /* testing if there is an env var */ + strcpy(buf, "$"); strcat(buf, p->key); + *(p->var) = kpse_var_expand(buf); + if (*(p->var) == NULL || **(p->var) == '\0') + *(p->var) = p->val; + } + + /* Modifying $PATH */ + + /* The SELFAUTOLOC stuff is NOT in the original makempx script. + However, it is a handy way to get the installation directory + without modifying the source at compile time. + + Also note that if $PATH is undefined, the null pointer returned + by `getenv' will serve as the trailing NULL to `concatn'. */ + path = concatn(MAKEMPX_BINDIR, ENV_SEP_STRING, + kpse_var_value("SELFAUTOLOC"), ENV_SEP_STRING, + getenv("PATH"), NULL); + xputenv("PATH", path); + free(path); + + for (i = 1; i <argc; i++) { + if (!strcmp(argv[i], "-help") || !strcmp(argv[i], "--help") + || !strcmp(argv[i], "-h")) { + usage(0); + } + if (!strcmp(argv[i], "-version") || !strcmp(argv[i], "--version") + || !strcmp(argv[i], "-v")) { + printversion(); + } + if (!strcmp(argv[i], "-troff") || !strcmp(argv[i], "--troff")) { + mode = TROFFMODE; + } + else if (!strcmp(argv[i], "-tex") || !strcmp(argv[i], "--tex")) { + mode = TEXMODE; + } + else if (!strncmp(argv[i], "-tex=", 5) || !strncmp(argv[i], "--tex=", 6)) { + TEX = strchr(argv[i], '=') + 1; + mode = TEXMODE; + } + /* FIXME: this disallows arguments with a leading dash, but + that's how the original shell script works. */ + else if (*argv[i] == '-') { + fprintf(stderr, "%s: Invalid option: %s.\nTry `%s --help' for more information.\n", + progname, argv[i], program_invocation_short_name); + mt_exit(1); + } + else if (!MPFILE || !*MPFILE) + MPFILE = argv[i]; + else if (!MPXFILE || !*MPXFILE) + MPXFILE = argv[i]; + else { + fprintf(stderr, "%s: Extra argument %s.\nTry `%s --help' for more information.\n", + progname, argv[i], program_invocation_short_name); + mt_exit(1); + } + } + + if (!MPXFILE || !*MPXFILE || !MPFILE || !*MPFILE) { + fprintf(stderr, "%s: Need exactly two file arguments.\nTry `%s --help' for more information.", + progname, program_invocation_short_name); + mt_exit(1); + } + + /* If MPX file is up-to-date, do nothing. */ + if (!newer (MPFILE, MPXFILE)) + mt_exit(0); + + /* Have to remake. */ + + /* Step 0: Check typesetter mode for consistency. */ + *cmd = '\0'; + switch(mode) { + case TEXMODE: + MPTO = MPTOTEX; + break; + case TROFFMODE: + MPTO = MPTOTR; + break; + default: + fprintf(stderr, "%s: Unknown typesetter mode\n", progname); + mt_exit(1); + } + + /* Step 1: Extract typesetter source from MetaPost source. */ + + sprintf(mptemplate, "mpx%d", getpid()); + strcpy(mpxtex, mptemplate); strcat(mpxtex, ".tex"); + /* redirecting 1 -> mpx$$.tex 2 -> ERRLOG */ + if (!(fmpx = fopen(mpxtex, "w"))) { + perror(mpxtex); + mt_exit(1); + } + if (!(ferr = fopen(ERRLOG, "w"))) { + perror(ERRLOG); + mt_exit(1); + } + + newfd[0] = 0; newfd[1] = fileno(fmpx); newfd[2] = fileno(ferr); + push_fd(newfd); + + mpto_cmd = concat3(MPTO, " ", MPFILE); + mpto_status = system(mpto_cmd); + free(mpto_cmd); + pop_fd(); + fclose(fmpx); + fclose(ferr); + if (mpto_status != 0) { + fprintf(stderr, "%s: Command failed: %s %s\n", progname, MPTO, MPFILE); + + output_file(stderr, ERRLOG); + /* rm -f mpx$$.tex -- this is done by the wrap-up code */ + mt_exit(1); + } + + /* Step 2: Run typesetter. */ + + switch(mode) { + case TEXMODE: + mpxdvi = change_suffix(mpxtex, ".dvi"); + mpxtmp = change_suffix(mpxtex, ".tmp"); + mpxlog = change_suffix(mpxtex, ".log"); + + if (test_file('r', MPTEXPRE)) { + if (catfile(MPTEXPRE, mpxtmp, 0) == FALSE + || catfile(mpxtex, mpxtmp, 1) == FALSE) { + sprintf(errbuf, "%s: cat %s %s > %s", + program_invocation_short_name, MPTEXPRE, mpxtex, mpxtmp); + perror(errbuf); + mt_exit(1); + } + mvfile(mpxtmp, mpxtex); + } +#ifdef _WIN32 + sprintf(cmd, "%s --interaction=batchmode %s < nul > nul", TEX, mpxtex); +#else + sprintf(cmd, "%s --interaction=batchmode %s </dev/null >/dev/null", + TEX, mpxtex); +#endif + if (system(cmd)) { + fprintf(stderr, "%s: Command failed: %s %s; see %s\n", + progname, TEX, TEXERR, ERRLOG); + mvfile(mpxtex, TEXERR); + mvfile(mpxlog, ERRLOG); + mt_exit(2); + } + WHATEVER_TO_MPX = DVITOMP; + INFILE = mpxdvi; + INERROR = DVIERR; + break; + case TROFFMODE: + mpxi = change_suffix(mpxtex, ".i"); + mpxt = change_suffix(mpxtex, ".t"); + mvfile(mpxtex, mpxi); + sprintf(cmd, "%s > %s", TROFF, mpxt); + if ((ftroff = popen(cmd, "w")) == NULL) { + perror(cmd); + mt_exit(1); + } + if (!(fmpx = fopen(mpxi, "r"))) { + perror(mpxi); + mt_exit(1); + } + while (fgets(buf, 1024, fmpx)) + fputs(buf, ftroff); + if (pclose(ftroff) != 0) { + fprintf(stderr, "%s: Command failed: cat %s | %s\n", progname, + TROFF_INERR, TROFF); + mvfile(mpxi, TROFF_INERR); + /* rm -f mpx$$.t : this is done in wrap-up code */ + mt_exit(2); + } + fclose(fmpx); + WHATEVER_TO_MPX = DMP; + INFILE = mpxt; + INERROR = TROFF_OUTERR; + break; + default: + fprintf(stderr, "%s: Unknown typesetter mode; how did this happen?\n", + progname); + mt_exit(2); + } + + /* Step 3: Translate typesetter output to a MetaPost MPX. */ + + sprintf(cmd, "%s %s %s > %s", WHATEVER_TO_MPX, INFILE, MPXFILE, ERRLOG); + if (system(cmd)) { + fprintf(stderr, "%s: Command failed: %s %s %s\n", progname, + WHATEVER_TO_MPX, INERROR, MPXFILE); + mvfile(INFILE, INERROR); + if (mode == TROFFMODE) + mvfile(mpxi, TROFF_INERR); + /* rm -f $MPXFILE : done in our exit code */ + output_file(stderr, ERRLOG); + mt_exit(3); + } + mt_exit(0); +} diff --git a/Build/source/texk/contrib/makempx.rc b/Build/source/texk/contrib/makempx.rc new file mode 100644 index 00000000000..f93b9e930da --- /dev/null +++ b/Build/source/texk/contrib/makempx.rc @@ -0,0 +1,34 @@ +/* makempx.rc: makempx resources -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " makempx 1.7" + +#define VER_INTERNALNAME_STR "makempx" +#define VER_ORIGINALFILENAME_STR "makempx.exe" + +#define VER_FILEDESCRIPTION_STR "MetaPost label processor" + +#define VER_LEGALCOPYRIGHT_STR "This program is public domain" + +#include <texlive.version> + +/* makempx.rc ends here */ diff --git a/Build/source/texk/contrib/mkloctex.bat b/Build/source/texk/contrib/mkloctex.bat new file mode 100644 index 00000000000..c91f1d102d5 --- /dev/null +++ b/Build/source/texk/contrib/mkloctex.bat @@ -0,0 +1,48 @@ +@echo off
+REM Staszek Wawrykiewicz (staw@gust.org.pl). March 2000
+REM This batch file installs the local TeX tree for running
+REM programs directly from the CD TeX Live 5 (Windows 9x/2000/NT)
+REM It allows changing some parameters (MF mode for dvips and windvi, etc.)
+REM and building local format files.
+REM Run: mkloctex g c
+REM where: %1 - CD ROM drive letter; %2 - HD drive letter for local tree
+if "%1"=="" goto HELPA
+if "%2"=="" goto HELPB
+%2:
+cd \
+md TeX
+md TeX\texmf
+md TeX\texmf\dvips
+md TeX\texmf\dvips\config
+md TeX\texmf\tex
+md TeX\texmf\tex\generic
+md TeX\texmf\tex\generic\config
+md TeX\texmf\web2c
+copy %1:\texmf\dvips\config\config.ps %2:\TeX\texmf\dvips\config\*.*
+copy %1:\texmf\tex\generic\config\language.dat %2:\TeX\texmf\tex\generic\config\*.*
+copy %1:\texmf\web2c\fmtutil.cnf %2:\TeX\texmf\web2c\*.*
+copy %1:\texmf\web2c\mktex.cnf %2:\TeX\texmf\web2c\*.*
+copy %1:\texmf\web2c\texmf.cnf %2:\TeX\texmf\web2c\*.*
+
+goto OKOK
+:HELPA
+echo Missing parameter: should be the letter of your CD-ROM drive
+
+goto FINIS
+:HELPB
+echo Missing parameter: should be the letter of HD drive for local TeX tree
+
+goto FINIS
+:OKOK
+echo.
+echo 1. Add %1:\bin\win32 directory to your environment PATH,
+echo 2. Add: set TEXMFCNF=%2:/TeX/texmf/web2c to your environment
+echo 3. Modify %2:\TeX\texmf\web2c\texmf.cnf accordingly, e.g.,
+echo TEXMFMAIN = %1:/texmf
+echo VARTEXMF = %2:/TeX/texmf
+echo.
+echo 4. Remember to run `mktexlsr' after any changes.
+
+:FINIS
+mktexlsr
+pause
diff --git a/Build/source/texk/contrib/mkocp.c b/Build/source/texk/contrib/mkocp.c new file mode 100644 index 00000000000..f009c2b76de --- /dev/null +++ b/Build/source/texk/contrib/mkocp.c @@ -0,0 +1,46 @@ +#include <kpathsea/kpathsea.h> +#include "stackenv.h" + +char *progname = NULL; + +void +usage() +{ + fprintf(stderr, "usage: %s ocp_filename\n", progname); + exit(1); +} + +int +main (int argc, char *argv[]) +{ + char cmd[4096]; + int newfd[3], ret; + FILE *f = fopen("nul", "r"); + char *basename; + + progname = xbasename(argv[0]); + + if (argc != 2) { + usage(); + } + + SetConsoleCtrlHandler((PHANDLER_ROUTINE)mt_exit, TRUE); + + basename = xbasename(argv[1]); + if (strlen(basename) > strlen(".ocp") + && _stricmp(basename + strlen(basename) - strlen(".ocp"), ".ocp") == 0) { + basename[strlen(basename) - strlen(".ocp")] = '\0'; + } + newfd[0] = fileno(f); + newfd[1] = fileno(stderr); + newfd[2] = fileno(stderr); + push_fd(newfd); + sprintf(cmd, "otp2ocp %s", basename); + ret = system(cmd); + pop_fd(); + fclose(f); + if (ret == 0) { + printf("%s.ocp\n", basename); + } + return ret; +} diff --git a/Build/source/texk/contrib/mkofm.c b/Build/source/texk/contrib/mkofm.c new file mode 100644 index 00000000000..d133a5bd9f8 --- /dev/null +++ b/Build/source/texk/contrib/mkofm.c @@ -0,0 +1,83 @@ +#include <win32lib.h> + +#undef _DEBUG + +#ifdef _DEBUG +#define TRACE(x) x +#else +#define TRACE(x) +#endif + +/* + Return a quoted string if space is found + New string is allocated +*/ +static char * +quote_elt(char *elt) +{ + int len = 2*strlen(elt)*sizeof(char) + 2; + char *to = xmalloc(len); + char *p = to; + BOOL need_quote = FALSE; + + if (strchr(elt, ' ')) { + *to++ = '"'; + need_quote = TRUE; + } + + while (*elt) { + switch (*elt) { + case '"': + case '\'': + /* case '\\': */ + *to++ = '\\'; + default: + *to++ = *elt++; + } + } + if (need_quote) { + *to++ = '"'; + } + + *to = *elt; + to = xstrdup(p); + free(p); + + return to; +} + +/* + Process an array of strings, quote them + an return their catenation +*/ +static char * +quote_args(char **argv) +{ + int i; + char *line = NULL, *new_line; + char *new_argv_i; + + if (!argv) + return line; + + line = quote_elt(argv[0]); + for (i = 1; argv[i]; i++) { + new_argv_i = quote_elt(argv[i]); + new_line = concat3(line, " ", new_argv_i); + TRACE(fprintf(stderr, "quote_args: new_line = %s\n", new_line)); + free(line); + free(new_argv_i); + line = new_line; + } + + return line; +} + +int +main (int argc, char *argv[]) +{ + char *cmd_line; + argv[0] = "mktextfm"; + cmd_line = quote_args(argv); + return system(cmd_line); +} diff --git a/Build/source/texk/contrib/mktex.c b/Build/source/texk/contrib/mktex.c new file mode 100644 index 00000000000..9675ecbfa47 --- /dev/null +++ b/Build/source/texk/contrib/mktex.c @@ -0,0 +1,2610 @@ +/* mktex.c: this program emulates the mktex* shell scripts from web2c. + +Copyright (C) 1997 Fabrice POPINEAU. +Adapted to MS-DOS/DJGPP by Eli Zaretskii <eliz@is.elta.co.il>. + +Time-stamp: <04/03/14 00:12:09 popineau> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Maximum number of lines per usage message. */ +#define MAX_LINES 16 + +#define SEPARATORS " \t\n\"" + +#include <signal.h> + +#include "stackenv.h" +#include "variables.h" +#include "fileutils.h" +#include "mktex.h" + +#ifdef _WIN32 +#define isatty _isatty +#endif + +/* + Global Variables found in the mktex* scripts +*/ + +/* mktex.opt */ +int program_number = -1; +string progname = NULL; + +/* mktex.cnf */ + +char tmpdir[PATH_MAX]; /* Working temporary directory */ +string output = "astdout"; +FILE *fout = NULL; +static boolean downcase_names; + +char empty_str[] = "(empty)"; + +static int errstatus; +extern int mt_append_mask; +void delmulslash(string ); +void read_mktexcnf(void); +void usage(void); + +/* Description of functionality : long name, short name, min args, + max args and pointer to a function to execute. */ +program_description makedesc [] = { + {"mktexpk", 2, 4, mktexpk }, /* 4,7 */ + {"mktextfm", 2, 2, mktextfm }, /* 1,2 */ + {"mktextex", 4, 6, mktextex }, /* ?? */ + {"mktexmf", 2, 2, mktexmf }, /* 1,1 */ + {"mktexlsr", 1, 255, mktexlsr }, /* 0,MANY */ + {"texhash", 1, 255, mktexlsr }, /* 0,MANY */ + {"mktexupd", 3, 3, mktexupdate }, /* 2,2 */ + {"mktexdir", 2, 255, mktexmkdir }, /* 0,MANY */ + {"mktexrmd", 2, 255, mktexrmdir }, /* ?? */ + {"mktexnam", 2, 5, mktexnames }, /* 1,4 */ +#if 0 + {"mktexfmt", 2, 5, mktexfmt }, /* 1,4 */ +#endif + {0, 0, 0} +}; + +#define PROGRAM_IS(p) STREQ (p, makedesc[program_number].name) + +/* Test whether getopt found an option ``A''. + Assumes the option index is in the variable `option_index', and the + option table in a variable `long_options'. */ +#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a) + +static struct option long_options [] = { + { "debug", 1, 0, 0}, + { "help", 0, 0, 0}, + { "version", 0, 0, 0}, + { "dpi", 1, 0, 0}, + { "bdpi", 1, 0, 0}, + { "mag", 1, 0, 0}, + { "mfmode", 1, 0, 0}, + { "destdir", 1, 0, 0}, + {0, 0, 0, 0} +}; + +/* + First argument takes progname; + Other arguments take no arguments. + */ +static string usage_msg[][MAX_LINES] = { + /* MktexPK */ + { + "Usage: %s [OPTIONS] NAME [REDIRECT],\n", + "Create a PK font.\n\n", + + "--dpi DPI use resolution DPI.\n", + "--bdpi BDPI use base resolution BDPI.\n", + "--mag MAG use magnificiation MAG.\n", + "--mfmode MODE use MODE as the METAFONT mode.\n", + "--destdir DESTDIR write fonts in DESTDIR.\n\n", + + "Try to create a PK file for NAME at resolution DPI, with an assumed\n", + "device base resolution of BDPI, and a Metafont `mag' of MAG. Use MODE\n", + "for the METAFONT mode. Use DESTDIR for the root of where to install\n", + "into, either the absolute directory name to use (if it starts with a\n", + "/) or relative to the default DESTDIR (if not). REDIRECT, if supplied,\n", + "is a string of the form '>&n', where n is the number of the file\n", + "descriptor which is to receive, instead of stdout, the name of the\n", + "newly created pk file.\n", + 0 + }, + /* MktexTFM */ + { + "Usage: %s [--destdir DESTDIR] FONT.\n\n", + "Makes a TFM file for FONT, if possible. Use DESTDIR for the root of where\n", + "to install into, either the absolute directory name to use (if it starts\n", + "with a /) or relative to the default DESTDIR (if not).\n", + 0 + }, + /* MktexTeX */ + { + 0 + }, + /* MktexMF */ + { + "Usage : %s FONT.\n\n", + "Makes the Metafont source file for FONT, if possible. For example,\n", + "`ecr12' or `cmr11'.\n", + 0 + }, + /* MktexlsR */ + { + "Usage: %s [DIRS ...]\n\n", + "Rebuild all necessary ls-R filename databases completely. If one or\n", + "more arguments DIRS are given, these are used as texmf directories to\n", + "build ls-R for. Else all directories in the search path for ls-R files\n", + "($TEXMFDBS) are used.\n", + 0 + }, + /* TeXHash */ + { + "Usage: %s [DIRS ...]\n\n", + "Rebuild all necessary ls-R filename databases completely. If one or\n", + "more arguments DIRS are given, these are used as texmf directories to\n", + "build ls-R for. Else all directories in the search path for ls-R files\n", + "($TEXMFDBS) are used.\n", + 0 + }, + /* Mktexupd */ + { + "Usage : %s DIR FILE.\n", + " Update the ls-R file with an entry for FILE in DIR.\n", + 0 + }, + /* Mktexdir */ + { + "Usage : %s DIRS...\n", + " Create each DIR, including any missing leading directories.\n", + 0 + }, + /* Mktexrmd */ + { + "Usage : %s DIRS ...\n", + " Recursively remove each DIR.\n", + 0 + }, + /* Mktexnam */ + { + "Usage : %s NAME [DPI MODE] [DESTDIR].\n", + " Output the PK, TFM and MF names for a font NAME.\n", + 0 + }, +#if 0 + /* Mktexfmt */ + { + "Usage : %s [-all] [FORMAT].\n", + " Rebuild all or specified format.\n", + 0 + } +#endif +}; + +/* + First part: mktex.opt + */ +int mktex_opt(int argc, char *argv[], + program_description * program) +{ + int g; /* getopt return code */ + int i; + int option_index; + string tempenv, cwd, vartexmf; + + for(;;) { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') { + usage(); /* Unknown option. */ + exit(1); + } + + /* assert (g == 0); */ /* We have no short option names. */ + /* + FIXME : try 'mktexpk --mfmode --bdpi 600 ...' + */ + if (ARGUMENT_IS ("debug")) { + kpathsea_debug |= atoi (optarg); + } + else if (ARGUMENT_IS ("help")) { + usage(); + exit(0); + } + else if (ARGUMENT_IS ("version")) { + fprintf(stderr, "%s of %s.\n", progname, kpathsea_version_string); + exit(0); + } + else if (PROGRAM_IS("mktexpk")) { + if (ARGUMENT_IS("dpi")) { + setval("DPI", optarg); + } + else if (ARGUMENT_IS("bdpi")) { + setval("BDPI", optarg); + } + else if (ARGUMENT_IS("mag")) { + setval("MAG", optarg); + } + else if (ARGUMENT_IS("mfmode")) { + if (!STREQ(optarg, DIR_SEP_STRING)) + setval("MODE", optarg); + } + else if (ARGUMENT_IS("destdir")) { + setval("DEST", optarg); + } + } + else if (PROGRAM_IS("mkextfm")) { + if (ARGUMENT_IS("destdir")) { + setval("DEST", optarg); + } + } + } + + /* shifting options from argv[] list */ + for (i = 1; optind < argc; i++, optind++) + argv[i] = argv[optind]; + argv[i] = NULL; + + argc = i; + if (argc < program->arg_min) { + fprintf (stderr, "%s: Missing argument(s).\nTry `%s --help' for more information.\n", progname, kpse_program_name); + exit(1); + } + if (argc > program->arg_max) { + fprintf(stderr, "%s: Extra arguments", progname); + for (i = program->arg_max - 1; i < argc; i++) + fprintf (stderr, " \"%s\"", argv[i]); + fprintf (stderr, "\nTry `%s --help' for more information.\n", + kpse_program_name); + exit(1); + } + + /* Catch signals, so we clean up if the child is interrupted. + This emulates "trap 'whatever' 1 2 15". */ +#ifdef _WIN32 + SetConsoleCtrlHandler((PHANDLER_ROUTINE)sigint_handler, TRUE); +#else +# ifdef SIGHUP + signal (SIGHUP, sigint_handler); +# endif +# ifdef SIGINT + signal (SIGINT, sigint_handler); +# endif +# ifdef SIGQUIT + signal (SIGQUIT, sigint_handler); +# endif +# ifdef SIGEMT + signal (SIGEMT, sigint_handler); +# endif +# ifdef SIGPIPE + signal (SIGPIPE, sigint_handler); +# endif +# ifdef SIGTERM + signal (SIGTERM, sigint_handler); +# endif +#endif + + tempenv = getval("TMPDIR"); + if (test_file ('z', tempenv)) + tempenv = getval("TEMP"); + if (test_file ('z', tempenv)) + tempenv = getval("TMP"); +#ifdef DOSISH + if (test_file ('z', tempenv)) + tempenv = "c:/tmp"; /* "/tmp" is not good if we are on a CD-ROM */ +#else + if (test_file ('z', tempenv)) + tempenv = "/tmp"; +#endif + sprintf(tmpdir, "%s/mtXXXXXX", tempenv); + mktemp(tmpdir); + if (do_makedir(tmpdir)) { + perror(tmpdir); + exit(1); + } + setval("TEMPDIR", tmpdir); + setval("STDOUT", concat_pathes(tmpdir, "astdout")); + setval("KPSE_DOT", cwd = xgetcwd()); + /* export KPSE_DOT */ + xputenv("KPSE_DOT", cwd); + + /*: ${MT_VARTEXFONTS=`kpsewhich --expand-var='$VARTEXFONTS' | sed 's%^!!%%'`} */ + vartexmf = setval_default("MT_VARTEXFONTS", expand_var("$VARTEXFONTS")); + + /* A sanity check. */ + if (test_file('z', vartexmf)) { + fprintf(stderr, + "%s: VARTEXFONTS is not defined. Defaulting to `%s'.\n", + progname, expand_var("$KPSE_DOT")); + setval("MT_VARTEXFONTS", "$KPSE_DOT"); + } + + /* mktex.opt sets the $MT_MKTEX... variables here to point to the supporting + scripts. But we don't need this, since we just call ourselves. */ + setval("ls_R_magic", + "% ls-R -- filename database for kpathsea; do not change this line."); + setval("old_ls_R_magic", + "% ls-R -- maintained by MakeTeXls-R; do not change this line."); + + pushd(tmpdir); + + if ((fout = fopen(getval("STDOUT"), "w")) == NULL) { + perror(output); + mt_exit(1); + } + + read_mktexcnf(); + + /* features by default */ +#ifdef MSDOS + setval_default("MT_FEATURES", "appendonlydir:dosnames"); +#else + setval_default("MT_FEATURES", "appendonlydir"); +#endif + setval_default("MODE", "ljfour"); + setval_default("BDPI", "600"); + setval_default("ps_to_pk", "gsftopk"); + + /* umask = 0 */ + umask(0); /* for those platforms who support it */ + + /* Cache values that may be useful for recursive calls. */ + xputenv("MT_MKTEX_CNF", getval("MT_MKTEX_CNF")); + xputenv("MT_TEXMFMAIN", getval("MT_TEXMFMAIN")); + xputenv("MT_VARTEXFONTS", getval("MT_VARTEXFONTS")); + + return argc; +} + +/* Reading mktex.cnf */ + +void read_mktexcnf() +{ + FILE *f; + string line; + string mtsite; + + mtsite = kpse_find_file ("mktex.cnf", kpse_web2c_format, false); + mtsite = setval_default("MT_MKTEX_CNF", mtsite); + if (test_file('n', mtsite) && test_file('r', mtsite)) { + f = fopen(mtsite, "r"); + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Reading mktex_cnf file: %s\n", mtsite); + } + while ((line = read_line(f)) != NULL) { + /* skip comments */ + if (*line == '#' || *line == '%' || isspace(*line) + || *line == '\0' || *line == '\n') { + free(line); + continue; + } + + if (!parse_variable(line)) + fprintf(stderr, "%s: unsupported keyword: %s\n", mtsite, line); + free(line); + } + fclose(f); + } + +} + +/* If non-negative, records the handle to redirect STDOUT + in `output_and_cleanup'. */ +int redirect_stdout; + +/* Record the handle where STDOUT is to be redirected + for printing the names of the generated files before we exit. */ +void record_output_handle(int fd) +{ + redirect_stdout = fd; /* FIXME: cannot be nested! */ +} + +void usage() +{ + int i; + fprintf(stderr, "%s of %s\n", progname, kpathsea_version_string); + fprintf(stderr, "Mktex version %s\n", mktex_version_string); + fprintf(stderr,usage_msg[program_number][0], progname ); + fputs("\n", stderr); + for(i = 1; usage_msg[program_number][i]; ++i) + fputs(usage_msg[program_number][i], stderr); +} + +void mktexinit(int argc, char **argv) +{ + string mode, bdpi; + string texmfmain; + + program_number = -1; + + if (!progname) + progname = argv[0]; + + kpse_set_program_name (progname, NULL); + + /* initialize the symbol table */ + init_vars(); + /* `kpse_init_prog' will put MODE and DPI into environment as values of + the two variables below. We need to leave these variables as they are. */ + mode = getval("MAKETEX_MODE"); + bdpi = getval("MAKETEX_BASE_DPI"); + + /* NULL for no fallback font. */ + kpse_init_prog (uppercasify (progname), + bdpi && atoi(bdpi) ? atoi(bdpi) : 600, mode, NULL); + + /* Common code for all scripts. + + : ${MT_TEXMFMAIN=`kpsewhich -expand-path='$TEXMFMAIN'`} */ + texmfmain = setval_default("MT_TEXMFMAIN", kpse_path_expand("$TEXMFMAIN")); + + /* FIXME: we don't support edited mktex.opt files, and don't look for + that file along the TEXMF trees. But at least we should fake the + safeguard in case $TEXMFMAIN is not defined at all. */ + if (test_file('z', texmfmain) || !test_file('d', texmfmain)) { + fprintf(stderr, "%s: $TEXMFMAIN is undefined or points to a non-existent directory;\n%s: check your installation.\n$TEXMFMAIN = %s\n", progname, progname, kpse_var_expand("$TEXMFMAIN")); + exit(1); /* not mt_exit, since temporary files were not created yet */ + } + +} + +/* Output the string in lower case or without modification according + to downcase_names. */ +void output_name(string name, FILE *f) +{ + string p; + if (downcase_names) { + for(p = name; *p; p++) + *p = TOLOWER(*p); + } + fputs(name, f); +} + +/* lower casify the string */ +string string_to_lower(string s) +{ + string p = NULL, q; + if (s) { + q = p = xstrdup(s); + while (*q) { + *q = TOLOWER(*q); + q++; + } + } + return p; +} + +/* Info about the temporary file to which we redirect print_path's + stdout. */ +static struct tem_file { + const char *tem_dir; + const char *tem_base; + const char *lsr_base; +} tem_file_info; + +/* Return 1 if DIR is the directory and BASE is the basename of the + temporary file whose info is in tem_file structure. + FIXME: this will break if mktexlsr invokes itself recirsively. */ +int is_db_file_tmp(string dir, int dir_len, char *base) +{ + if (!tem_file_info.tem_dir || !tem_file_info.tem_base) + return 0; + return ((dir_len >= 0 ? FILESTRNCASEEQ(dir, tem_file_info.tem_dir, dir_len) + : FILESTRCASEEQ(dir, tem_file_info.tem_dir)) + && FILESTRCASEEQ(base, tem_file_info.tem_base)); +} + +/* Updates ls-R db for directory pointed to by path. */ +void print_path(string path, struct stat* st) +{ + if ((st->st_mode & S_IFMT) == S_IFDIR) { +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + HANDLE hnd; + string fulldir; + int offset = 0; + int ind = strlen(path); +#else + DIR *dp; + struct dirent *ep; +#endif + + putchar('\n'); /* extra blank line before new directory */ + output_name(path, stdout); + if (path[0] == '.' && path[1] == '\0') + putchar('/'); + putchar(':'); putchar('\n'); + + /* Note that we actually read each directory twice: once + here, to print all its entries, and once in `recurse_dir', + to recurse into its subdirectories. This is so that + `ls-R' file is written in breadth-first manner, like + `ls -R' does in the original script. Caching the entries + from the first read would make this code run faster, but + since it is faster than the script already, why bother? */ + +#ifdef _WIN32 + if (path[0] == '.' && IS_DIR_SEP(path[1])) { + offset = 2; + } + fulldir = concat_pathes(tem_file_info.lsr_base, path + offset); + + strcat(path, "/*"); /* ok since the caller says path[PATH_MAX] */ + hnd = FindFirstFile(path, &ffd); + while (hnd && FindNextFile(hnd, &ffd)) { + if (ffd.cFileName[0] == '.' + && ((ffd.cFileName[1] == '\0') + || (ffd.cFileName[1] == '.' && ffd.cFileName[2] == '\0'))) + continue; + if (!is_db_file_tmp(path, ind, ffd.cFileName) + /* We don't want to report directories ! */ + && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + output_name(ffd.cFileName, stdout); + putchar('\n');/* We do want a \n */ + { + string fullname; + fullname = concat_pathes(fulldir, ffd.cFileName); + kpse_db_insert(fullname); + free(fullname); + } + } + } + path[ind] = '\0'; + FindClose(hnd); + free(fulldir); +#else /* not _WIN32 */ + if ((dp = opendir(path))) { + while ((ep = readdir(dp))) + if (strcmp(ep->d_name, ".") + && strcmp(ep->d_name, "..") + && !is_db_file_tmp(path, -1, ep->d_name)) { + output_name(ep->d_name, stdout); + putchar('\n'); + } + closedir(dp); + } + else + perror(path); +#endif /* not _WIN32 */ + + } +} + +/* return true if the fs on which path lies is case sensitive. + Insufficient. Some people may have copied the complete tree in + upper case from a case insensitive fs. + Second test : look at the texmf name. If GetShortName != + GetLongName it is ok. +*/ +boolean is_casesensitive(string path) +{ + boolean retval = TRUE; /* default for non-DOSISH systems */ + +#ifdef MONOCASE_FILENAMES + char name[PATH_MAX]; +#ifdef _WIN32 + char volname[PATH_MAX]; + DWORD sernum; + DWORD maxcomplen; +#endif +#ifdef __DJGPP__ + int maxnamelen; + DWORD maxpathlen; +#endif + DWORD fsflags; + char fsname[PATH_MAX]; + + /* How should the db be output ? Preserve case or lower case ? + First, determine the root volume : if path has the drive, ok. If + not, get current drive. */ +#ifdef WIN32 + if (IS_UNC_NAME(path)) { + /* UNC pathname : \\server\dir\... + We must find the first 2 components. + */ + char *p; + strcpy(name, path); + name[0] = name[1] = '\\'; + p = strchr(name+2, '/'); + if (p) + *p = '\\'; + else { + p = strchr(name+2, '\\'); + if (!p) { + fprintf(stderr, "Error getting volume info on %s.\n", name); + mt_exit(1); + } + } + p = strchr(p+1, '/'); + if (p) + *p = '\\'; + else { + p = strchr(p+1, '\\'); + if (!p) { + fprintf(stderr, "Error getting volume info on %s.\n", name); + mt_exit(1); + } + } + *(p+1) = '\0'; + } + else { + if (IS_DEVICE_SEP(path[1])) { /* the shortest path is "." and has 2 chars */ + name[0] = path[0]; + } + else + name[0] = _getdrive() + 'A' - 1; + + strcpy(name+1, ":\\"); + } + + if (GetVolumeInformation(name, volname, 256, &sernum, &maxcomplen, + &fsflags, fsname, 256) == FALSE) { + fprintf(stderr, "Error getting volume info on %s (code %d).\n", name, GetLastError()); + mt_exit(1); + } + +#else /* ! WIN32 */ + if (IS_DEVICE_SEP(path[1])) { /* the shortest path is "." and has 2 chars */ + name[0] = path[0]; + } + else + name[0] = _getdrive() + 'A' - 1; + + strcpy(name+1, ":\\"); + +#ifdef __DJGPP__ + fsflags = _get_volume_info(name, &maxnamelen, &maxpathlen, fsname); +#endif + +#endif /* ! WIN32 */ + + /* FIXME: FS_CASE_IS_PRESERVED does not seem sufficient. People + manage to get share/texmf/FONTS/TFM/... under W95. Too bad. + After all, this flag distinguishes NTFS from all FATs */ + retval = (fsflags & FS_CASE_SENSITIVE) != 0; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "FS %s %s case-sensitive\n", name, + (retval ? "is" : "is not")); + } +#endif /* MONOCASE_FILENAMES */ + + return retval; +} + +/* Set FILE to have the same permissions as directory DIR, minus the bits + masked off by MASK. + This emulates "chmod `kpsestat -xst,go-w $DIR` FILE". */ + +int chmod_as_dir(string file, const string dir, mode_t mask) +{ + struct stat st_buf; + + if (stat (dir, &st_buf) == 0) + return chmod (file, st_buf.st_mode & mask); + return -1; +} + +void do_mktexlsr(string path) +{ + static char name[PATH_MAX]; +#ifdef __DJGPP__ + /* `stat' can be very expensive on MS-DOS, and `recurse_dir' + uses it a lot. Make it work as fast as we possibly can afford. */ + unsigned short save_stat_bits = _djstat_flags; + _djstat_flags = (_STAT_WRITEBIT | _STAT_ROOT_TIME | _STAT_DIRSIZE | + _STAT_EXEC_MAGIC | _STAT_EXEC_EXT); +#endif + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Building ls-R database in: %s\n", path); + } + + downcase_names = ! is_casesensitive(path); + + strcpy(name,path); + recurse_dir(name, print_path, NULL); +#ifdef __DJGPP__ + _djstat_flags = save_stat_bits; +#endif +} + +#if !defined(S_IFLNK) && !defined(S_ISLNK) + +/* Dummy version of `readlink' for systems which don't support links. */ +int readlink(const char *path, char *buf, int bufsize) +{ + return -1; +} + +#endif + +int mktexlsr(int argc, char **argv) +{ + /* We have to take multiple root trees into account. */ + + string db_dir, db_file, lsrdir; + char db_dir_tmp[PATH_MAX]; + char db_file_tmp[PATH_MAX]; + FILE* lsrfile; + int newfd[3]; + char **newargv; + int i; + + if (argc == 1) { + newargv = (char **) malloc(2 * sizeof(char *)); + newargv[0] = argv[0]; + /* This should give us the ls-R default path */ + if (!kpse_format_info[kpse_db_format].type) /* needed if arg was numeric */ + kpse_init_format (kpse_db_format); + newargv[1] = xstrdup(kpse_format_info[kpse_db_format].path); + argc = 2; + } + else { + newargv = (char **) malloc(argc * sizeof(char *)); + for (i = 0; i < argc; i++) + newargv[i] = argv[i]; + } + + /* For each argument in the list */ + for (i = 1; i < argc; i++) { + for (lsrdir = kpse_path_element(newargv[i]); + lsrdir; + lsrdir = kpse_path_element(NULL)) { + char symlink[PATH_MAX]; + int symlink_len; + + /* We need to skip !! */ + if (lsrdir && *lsrdir == '!' && *(lsrdir+1) == '!') + lsrdir +=2; + /* Skip empty path components. */ + if (*lsrdir == 0) + continue; + /* FIXME : /local/tex is absolute under win32, but should it really be ? */ + if (!kpse_absolute_p(lsrdir, FALSE)) + lsrdir = concat_pathes(getval("KPSE_DOT"), lsrdir); + + /* Follow a possible symlink to get the right filesystem. */ + db_file = concat_pathes(lsrdir, "ls-R"); + if ((symlink_len = readlink(db_file, symlink, PATH_MAX)) != -1) { + string new_db_file = xmalloc(symlink_len + 1); + + strncpy(new_db_file, symlink, symlink_len); + new_db_file[symlink_len] = '\0'; + if (!kpse_absolute_p(new_db_file, false)) { + string tem = concat_pathes(lsrdir, new_db_file); + free(new_db_file); + new_db_file = tem; + } + } + db_dir = xdirname(db_file); + + if (!test_file('d', db_dir)) { + fprintf(stderr, "%s: %s is not a directory. Skipping...\n", + progname, db_dir); + continue; + } + + if (!test_file('w', db_dir)) { + fprintf(stderr, "%s: %s: directory not writable. Skipping...\n", + progname, db_dir); + continue; + } + + sprintf(db_dir_tmp, "%s/lsXXXXXX", db_dir); + if (mktemp(db_dir_tmp) == NULL) { + perror(db_dir_tmp); + mt_exit(1); + } + if (mkdir(db_dir_tmp, 0777 & ~umask(0)) == -1) { + fprintf(stderr, "%s: could not create directory '%s'. Skipping...\n"); + continue; + } + + sprintf(db_file_tmp, "%s/lsXXXXXX", db_dir_tmp); + if (mktemp(db_file_tmp) == NULL) { + perror(db_file_tmp); + mt_exit(1); + } + + if ((lsrfile = fopen(db_file_tmp, "wb")) == NULL) { + fprintf(stderr, "%s: %s: no write permission. Skipping...\n", + progname, db_file_tmp); + continue; + } + if (!is_writable(db_file) && errno != ENOENT) { + fprintf(stderr, "%s: %s: no write permission. Skipping...\n", + progname, db_file); + continue; + } + + if (isatty(fileno(stdout))) + fprintf(stderr, "%s: Updating %s...\n", progname, db_file); + + newfd[0] = 0; + newfd[1] = fileno(lsrfile); + newfd[2] = 2; + push_fd(newfd); + + puts(getval("ls_R_magic")); + fputs("/dev/null", stdout); /* like `ls -R' does */ + putchar('\n'); + + /* Record the info about the temporary file, so we don't enter + it into the database. */ + tem_file_info.tem_dir = "."; + tem_file_info.tem_base = xbasename(db_file_tmp); + tem_file_info.lsr_base = db_dir; + + pushd(db_dir); + do_mktexlsr("."); + + popd(); /* back to tmpdir */ + /* Restore original stdout */ + pop_fd(); + + fflush(stdout); + fclose(lsrfile); + + /* Use same permissions as parent directory, minus x, s, or t bits, + but plus writeable bits for those who can read it. */ + { + struct stat stbuf; + + if (stat(db_dir, &stbuf) == 0) { + if ((stbuf.st_mode & S_IRUSR) != 0) + stbuf.st_mode |= S_IWUSR; + if ((stbuf.st_mode & S_IRGRP) != 0) + stbuf.st_mode |= S_IWGRP; + if ((stbuf.st_mode & S_IROTH) != 0) + stbuf.st_mode |= S_IWOTH; + chmod (db_file_tmp, stbuf.st_mode & 00666); + } + } + + /* Forget about this temporary file. */ + tem_file_info.tem_dir = 0; + tem_file_info.tem_base = 0; + + if (mvfile(db_file_tmp, db_file) == FALSE) { + mt_exit(1); + } + + do_rmdir(db_dir_tmp); + + free(db_file); + } + } + free(newargv); + + hash_reinit(); + + if (isatty(fileno(stdout))) + fprintf(stderr, "%s: Done.\n", progname); + return 0; +} + +/* Find namepart for font name in the TDS structure. */ +void findmap() +{ + FILE *f; + string line; + string token; + string filename; + string name = getval("NAME"), noraw_name; + + /* Raw font */ + if (name && *name == 'r') + name = name+1; + + filename = getval("MT_SPECIALMAP"); + if (!test_file('r', filename)) + return; + + f = fopen(filename, FOPEN_R_MODE); + if (f == NULL) { + perror(filename); + return; + } + + /* FIXME : there is a seg fault if the font is not found here */ + /* Is it ok ? 03/02/97 ;.. */ + while((line = read_line(f)) != NULL) { + token = strtok(line, SEPARATORS); + if (!token || !*token) + continue; + + if (FILESTRCASEEQ(token, name) + || (FILESTRNCASEEQ(token, name, strlen(token)) + && isdigit(name[strlen(name)-1]) + && !isdigit(token[strlen(token)-1]))) { + setval("SUPPLIER", xstrdup(strtok(NULL, SEPARATORS))); + setval("TYPEFACE", xstrdup(strtok(NULL, SEPARATORS))); + free(line); + break; + } + else + free(line); + } + + if (test_file('z', getval("SUPPLIER"))) { + string s_abbrev = xstrdup(" "); + /* $NAME might be raw */ + noraw_name = (name[0] == 'r' ? name + 1 : name); + s_abbrev[0] = noraw_name[0]; + setval("s_abbrev", s_abbrev); + filename = getval("MT_SUPPLIERMAP"); + if (test_file('z', filename)) { + fprintf(stderr, "%s: %s: No such file or directory\n", + progname, filename ? filename : empty_str); + return; + } + f = freopen(filename, FOPEN_R_MODE, f); + if (f == NULL) { + perror(filename); + return ; + } + + while((line = read_line(f)) != NULL) { + token = strtok(line, SEPARATORS); + if (FILECHARCASEEQ(*token, *s_abbrev) && token[1] == '\0') { + setval("SUPPLIER", xstrdup(strtok(NULL, SEPARATORS))); + free(line); + break; + } + else + free(line); + } + + if (test_file('n', getval("SUPPLIER"))) { + string t_abbrev = xmalloc (3); + + t_abbrev[0] = '\0'; + strncat (t_abbrev, noraw_name + 1, 2); + setval("t_abbrev", t_abbrev); + filename = getval("MT_TYPEFACEMAP"); + if (test_file('z', filename)) { + fprintf(stderr, "%s: %s: No such file or directory\n", + progname, filename ? filename : empty_str); + return; + } + f = freopen(filename, FOPEN_R_MODE, f); + if (f == NULL) { + perror(filename); + return; + } + + while((line = read_line(f)) != NULL) { + token = strtok(line, SEPARATORS); + if ((strlen(token) == 2) + && (t_abbrev[1] == token[0]) && (t_abbrev[2] == token[1])) { + setval("TYPEFACE", xstrdup(strtok(NULL, SEPARATORS))); + free(line); + break; + } + else + free(line); + } + } + } + + free(filename); + fclose(f); + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Font %s has supplier %s and typeface %s.\n", + getval("NAME"), + getval("SUPPLIER") ? getval("SUPPLIER") : empty_str, + getval("TYPEFACE") ? getval("TYPEFACE") : empty_str); + } + +} + + +/* Test if two pathes are equal. Up to the shortest one. */ +boolean path_included(const_string p1, const_string p2) +{ + boolean ret = true; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Path %s included in %s: ", + p1, p2); + } + + for( ; *p1 && *p2 && ret; p1++, p2++) + ret = ret && (IS_DIR_SEP(*p1) ? IS_DIR_SEP(*p2) : + FILECHARCASEEQ(*p1, *p2)); + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "%s\n", (ret ? "true": "false")); + } + + return ret; +} + +/* return the path element in path which can match dir else NULL */ +string path_in_pathes(const_string dir, const_string path) +{ + string ret = NULL; + string elt; + string pathcpy = xstrdup(path); + /* FIXME : why is it necessary to dup it ? */ + string dircpy = xstrdup(dir); + + for (elt = kpse_path_element (pathcpy); + elt && !ret; + elt = kpse_path_element (NULL)) { + /* Not sufficient to have both equal, there should be a DIR_SEP + on the next char of dir */ + if (path_included(elt, dircpy) && + (IS_DIR_SEP(*(dir+strlen(elt))) + || (strlen(dircpy) == strlen(elt)))) + ret = xstrdup(elt); + } + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Path %s searched for %s => %s.\n", + path, dircpy, ret); + } + free(pathcpy); + free(dircpy); + return ret; + +} + + +/* + Split a .mf name into root part and point size part. + Root and point size are optional (may be NULL). + */ +void split_mf_name(string name, string *base, string *root, string *ptsize) +{ + string p, q; + /* name = basename $1 .mf */ + p = my_basename(name, ".mf"); + if (base) + *base = xstrdup(p); + /* rootname = `echo $name | sed 's/[0-9]*$//'` */ + for (q = p + strlen(p); q > p && isdigit(q[-1]); q--); + /* ptsize = `echo $name | sed 's/^$rootname//'` */ + if (ptsize) + *ptsize = xstrdup(q); + *q = '\0'; + if (root) + *root = p; + else + free(p); +} + +string find_sauter(string name, string *rootname) +{ + string root, sauter_name, res; + split_mf_name(name, NULL, &root, NULL); + sauter_name = concat("b-", root); + res = kpse_find_file(sauter_name, kpse_mf_format, false); + if (rootname) + *rootname = root; + else + free(root); + free(sauter_name); + return res; +} + +/* Return non-zero iff FEATURE is included in $MT_FEATURES. */ +int feature_p(const char *feature) +{ + string mt_features = getval("MT_FEATURES"); + char *p = strstr(mt_features, feature); + int next_char = p ? p[strlen(feature)] : 0; + + if (p && (p == mt_features || p[-1] == ':') + && (next_char == ':' || next_char == '\0')) + return 1; + return 0; +} + +void mktexnam_opt() +{ + string mtn_opt; + + /* FIXME: we don't support edited mktexnam.opt files. */ + if (feature_p("dosnames")) + setval("MT_PKBASE", "dpi$DPI/${NAME}.pk"); + + if (feature_p("nomode")) + setval("MODE", ""); + + /* This is to avoid running the code below if $TEXMF and/or + $TEXMFMAIN are set incorrectly. The code below cannot + cope with that situation. (The scripts do not call + mktexnam.opt in such a case, either.) */ + mtn_opt = kpse_find_file ("mktexnam.opt", kpse_web2c_format, false); + if (!mtn_opt || !*mtn_opt) + return; + + if (feature_p("fontmaps")) { + setval("MT_NAMEPART", "$MT_SUPPLIER/$MT_TYPEFACE"); + setval("MT_PKDESTREL", "pk/$MT_MODE/$MT_NAMEPART"); + setval("MT_TFMDESTREL", "tfm/$MT_NAMEPART"); + setval("MT_MFDESTREL", "source/$MT_NAMEPART"); + setval_default("MT_SPECIALMAP", + kpse_find_file("special.map", kpse_fontmap_format, false)); + setval_default("MT_TYPEFACEMAP", + kpse_find_file("typeface.map", kpse_fontmap_format, false)); + setval_default("MT_SUPPLIERMAP", + kpse_find_file("supplier.map", kpse_fontmap_format, false)); + + if (test_file('z', getval("MT_SUPPLIER")) + || test_file('z', getval("MT_TYPEFACE")) + || STREQ(getval("MT_SUPPLIER"), "unknown") + || STREQ(getval("MT_SUPPLIER"), "unknown")) { + + findmap(); + + if (test_file('z', getval("SUPPLIER"))) { + fprintf(stderr, "%s: Could not map source abbreviation %s for %s.\n", + progname, + getval("s_abbrev") ? getval("s_abbrev") : empty_str, + getval("NAME")); + if (test_file('n', getval("MT_SPECIALMAP"))) + fprintf(stderr, "%s: Need to update %s?\n", + progname, getval("MT_SPECIALMAP")); + else + fprintf(stderr, "%s: $MT_SPECIALMAP not found!\n", progname); + /* setval("MT_SUPPLIER", getval("MT_DEFAULT_SUPPLIER")); */ + /* setval("MT_TYPEFACE", getval("MT_DEFAULT_TYPEFACE")); */ + } + else { + setval("MT_SUPPLIER", getval("SUPPLIER")); + if (test_file('z', getval("TYPEFACE"))) { + fprintf(stderr, "%s: Could not map typeface abbreviation %s for %s.\n", + progname, + getval("t_abbrev") ? getval("t_abbrev") : empty_str, + getval("NAME")); + if (test_file('n', getval("MT_SPECIALMAP"))) + fprintf(stderr, "%s: Need to update %s?\n", + progname, getval("MT_SPECIALMAP")); + else + fprintf(stderr, "%s: $MT_SPECIALMAP not found!\n", progname); + /* setval("MT_TYPEFACE", getval("MT_DEFAULT_TYPEFACE")); */ + } + else + setval("MT_TYPEFACE", getval("TYPEFACE")); + } + } + } + + if (feature_p("stripsupplier")) + setval("MT_SUPPLIER", ""); + + if (feature_p("striptypeface")) + setval("MT_TYPEFACE", ""); + + if (feature_p("varfonts")) + /* atoi is undefined for empty arguments, so test explicitly. */ + if (test_file('z', (getval("USE_VARTEXFONTS"))) + || atoi(getval("USE_VARTEXFONTS")) != 0) + setval("USE_VARTEXFONTS", "1"); +} + +void do_mktexnames(string name) +{ + string fullname, rootname, i; + string stdfontpath, relfmt, namepart; + string *vars; + string s_dest; + int use_alternate = 0; + + setval("NAME", name); + setval_default("MT_PKDESTDIR", "$MT_DESTROOT/$MT_PKDESTREL"); + setval_default("MT_TFMDESTDIR", "$MT_DESTROOT/$MT_TFMDESTREL"); + setval_default("MT_MFDESTDIR", "$MT_DESTROOT/$MT_MFDESTREL"); + setval_default("MT_PKBASE", "$NAME.${DPI}pk"); + setval_default("MT_TFMBASE", "$NAME.tfm"); + setval_default("MT_MFBASE", "$NAME.mf"); + setval_default("MT_DEFAULT_SUPPLIER", "unknown"); + setval_default("MT_DEFAULT_TYPEFACE", "unknown"); + setval_default("MT_DEFAULT_NAMEPART", "$MT_SUPPLIER/$MT_TYPEFACE"); + setval_default("MT_DEFAULT_PKDESTREL", "pk/modeless/$MT_NAMEPART"); + setval_default("MT_DEFAULT_TFMDESTREL", "tfm/$MT_NAMEPART"); + setval_default("MT_DEFAULT_MFDESTREL", "source/$MT_NAMEPART"); + setval_default("MT_DEFAULT_DESTROOT", getval("KPSE_DOT")); + + /* Looking for $name.tfm */ + fullname = kpse_find_file(name, kpse_tfm_format, false); + if (test_file('z', fullname)) { + /* If tfm not found, looking for $name.mf */ + fullname = kpse_find_file(name, kpse_mf_format, false); + if (test_file('z', fullname)) { + /* Try Sauter font */ + fullname = find_sauter(name, &rootname); + if (test_file('z', fullname)) { + if (FILESTRNCASEEQ(rootname, "cs", 2) + || FILESTRNCASEEQ(rootname, "lcsss", 5) + || FILESTRNCASEEQ(rootname, "icscsc", 6) + || FILESTRNCASEEQ(rootname, "icstt", 5) + || FILESTRNCASEEQ(rootname, "ilcsss", 6) + ) { + fullname = kpse_find_file("cscode.mf", kpse_mf_format, false); + } + else if (strlen(rootname) >= 3 + && ((FILESTRNCASEEQ(rootname, "wn", 2) + && strchr("bBcCdDfFiIrRsStTuUvV", rootname[2])) + || (FILESTRNCASEEQ(rootname, "rx", 2) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", rootname[2]) + && strlen(rootname) >= 4 + && strchr("bBcCfFhHiIlLmMoOsStTxX", rootname[3])) + || ((rootname[0] == 'l' || rootname[0] == 'L') + && strchr("aAbBcCdDhHlL", rootname[1]) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", rootname[2])))) { + char lhname[64]; + strcpy(lhname, "xxcodes.mf"); + strncpy(lhname, name, 2); + fullname = kpse_find_file(lhname, kpse_mf_format, false); + } + else { + fullname = kpse_find_file(rootname, kpse_mf_format, false); + } + } + } + } + + if (test_file('z', fullname)) { + /* Moved on 99/04/29 + setval("MT_FEATURES", concat(getval("MT_FEATURES"), ":fontmaps")); */ + setval_default("MT_DESTROOT", getval("MT_VARTEXFONTS")); + } + else { + /* Normalize fullname */ + normalize(fullname); + stdfontpath = kpse_path_expand(concat3(("$TEXMF/fonts"), + ENV_SEP_STRING, + "$MT_VARTEXFONTS")); + /* FIXME : what about if fullname is not in stdfontpath ? + For example: fullname is absolute ... */ + if (test_file('n', i = path_in_pathes(fullname, stdfontpath))) { + /* We now have a preliminary value for the destination root. + MT_DESTROOT="$i" + */ + setval_default("MT_DESTROOT", i); + /* + # When we're done, relfmt contains one of these: + # "/source/$MT_NAMEPART/" + # "/$MT_NAMEPART/source/" + # while namepart contains the actual namepart. + */ + relfmt = xstrdup(fullname); + /* should match in lower cases letters if fs is case insensitive */ + if (!is_casesensitive(relfmt)) { + string p = string_to_lower(relfmt); + string q = string_to_lower(i); + /* remove the 'i' part and the name */ + vars = grep(concatn("^", q, "(/.*/)[^/]*$", NULL), p, 1); + } + else { + /* remove the 'i' part and the name */ + vars = grep(concatn("^", i, "(/.*/)[^/]*$", NULL), relfmt, 1); + } + if (vars) { + free(relfmt); + relfmt = xstrdup(vars[1]); + free(vars); + } + else { + /* grep failed. Shouldn't happen. */ + relfmt = xstrdup(""); + } + + { + string res = ""; + size_t l_relfmt = strlen(relfmt); + + namepart = NULL; + + /* sed -e 's%^/tfm/%/source/%' */ + if (FILESTRNCASEEQ(relfmt, "/tfm/", 5)) { + res = concat("/source/", relfmt + 5); + namepart = concat ("/", relfmt+5); + free(relfmt); + relfmt = res; + } + /* sed -e 's%/tfm/$%/source/%' */ + else if (l_relfmt >= 5 + && FILESTRCASEEQ(relfmt + l_relfmt - 5, "/tfm/")) { + relfmt[l_relfmt - 4] = '\0'; + res = concat(relfmt, "/source/"); + namepart = concat(relfmt, "/"); + free(relfmt); + relfmt = res; + } + /* namepart=`echo "$relfmt" | sed -e 's%/source/%/%'` */ + /* + This should be almost done by now. I assume the scripts not + to be strict enough. IE: /tfm/ can occur only once in the name. + That's why the 'else if' instead of 'if'. + */ + else { + /* namepart is unset by now */ + namepart = subst(relfmt, "/source/", "/"); + } + + /* See if namepart is empty. */ + if (test_file('n', namepart) && strcmp(namepart, "/") != 0) { + res = subst(relfmt, namepart, "/$MT_NAMEPART/"); + free(relfmt); + relfmt = res; + } + else { + /* Assume TDS */ + free(relfmt); + relfmt = xstrdup("/source/$MT_NAMEPART/"); + namepart = ""; + } + } + + /* Determine supplier and typeface from namepart. If there is + only one part in the name part, we take it to be the typeface. + */ + vars = grep("^/([^/]*)/([^/]*)[/]?$", namepart, 2); + if (vars) { + if (vars[2] == NULL || *vars[2] == '\0') { + setval("MT_TYPEFACE", xstrdup(vars[1])); + setval("MT_SUPPLIER", ""); + } + else { + setval("MT_TYPEFACE", xstrdup(vars[2])); + setval("MT_SUPPLIER", xstrdup(vars[1])); + } + free(vars[1]); + if (vars[2]) free(vars[2]); + free(vars); + } + else { + setval("MT_TYPEFACE", namepart); + setval("MT_SUPPLIER", namepart); + } + /* + Phew. Now we create the relative paths for pk, tfm and source. + */ + setval_default("MT_NAMEPART", "$MT_SUPPLIER/$MT_TYPEFACE"); + setval_default("MT_PKDESTREL", subst(relfmt, "/source/", "/pk/$MT_MODE/")); + setval_default("MT_TFMDESTREL", subst(relfmt, "/source/", "/tfm/")); + setval_default("MT_MFDESTREL", relfmt); + } + } /* FIXME: if fullname is absolute, path_in_pathes will fail */ + /* + In case some variables remain unset + */ + /* setval_default("MT_DESTROOT", getval("MT_DEFAULT_DESTROOT")); */ + setval_default("MT_SUPPLIER", getval("MT_DEFAULT_SUPPLIER")); + setval_default("MT_TYPEFACE", getval("MT_DEFAULT_TYPEFACE")); + setval_default("MT_NAMEPART", getval("MT_DEFAULT_NAMEPART")); + setval_default("MT_PKDESTREL", getval("MT_DEFAULT_PKDESTREL")); + setval_default("MT_TFMDESTREL", getval("MT_DEFAULT_TFMDESTREL")); + setval_default("MT_MFDESTREL", getval("MT_DEFAULT_MFDESTREL")); + + /* We have found nothing, so force using the fontmaps as a last resort. + This also means mktexnam can be queried for advice on where to + place fonts. */ + if (STREQ(getval("MT_SUPPLIER"), "unknown") + || STREQ(getval("MT_TYPEFACE"), "unknown")) { + setval_default("MT_FEATURES", concat(getval("MT_FEATURES"), ":fontmaps")); + } + + /* Handle the options */ + mktexnam_opt(); + + /* # Adjust MT_DESTROOT, if necessary. */ + if (test_file('n', expand_var("$MT_DESTROOT"))) { + string systexmf; + /* # Do we have write access and permission? */ + if (!test_file('w', expand_var("$MT_DESTROOT"))) + use_alternate = 1; + /* # We distinguish system trees from the rest. */ + systexmf = concat3(kpse_path_expand("{$SYSTEXMF}/fonts"), + ENV_SEP_STRING, + getval("MT_VARTEXFONTS")); + i = path_in_pathes(expand_var("$MT_DESTROOT"), systexmf); + + if (test_file('n', i) && FILESTRCASEEQ(expand_var("$MT_DESTROOT"), i)) { + if ((test_file('n', (getval("USE_VARTEXFONTS"))) + && STREQ(getval("USE_VARTEXFONTS"),"1")) + || use_alternate) { + setval("MT_DESTROOT", getval("MT_VARTEXFONTS")); + } + } + /* else $MT_DESTROOT stays put. */ + else if (use_alternate) + setval("MT_DESTROOT", ""); + } + + if (test_file('z', expand_var("$MT_DESTROOT"))) { + string default_dest_root = expand_var("$MT_DEFAULT_DESTROOT"); + setval("MT_DESTROOT", default_dest_root); + setval("MT_PKDESTDIR", default_dest_root); + setval("MT_TFMDESTDIR", default_dest_root); + setval("MT_MFDESTDIR", default_dest_root); + } + + s_dest = expand_var("$DEST"); + if (test_file('n', s_dest)) + if (kpse_absolute_p(s_dest, false)) { + setval("MT_PKDESTDIR", s_dest); + setval("MT_TFMDESTDIR", s_dest); + setval("MT_MFDESTDIR", s_dest); + setval("MT_NAMEPART", ""); + } + else + setval("MT_NAMEPART", s_dest); + + setval ("MT_MODE", expand_var("$MODE")); + setval ("MT_NAMEPART", expand_var("$MT_NAMEPART")); + setval ("MT_DESTROOT", expand_var("$MT_DESTROOT")); + setval ("MT_PKDESTREL", expand_var("$MT_PKDESTREL")); + setval ("MT_TFMDESTREL", expand_var("$MT_TFMDESTREL")); + setval ("MT_MFDESTREL", expand_var("$MT_MFDESTREL")); + setval ("MT_PKDESTDIR", expand_var("$MT_PKDESTDIR")); + setval ("MT_TFMDESTDIR", expand_var("$MT_TFMDESTDIR")); + setval ("MT_MFDESTDIR", expand_var("$MT_MFDESTDIR")); + s_dest = setval ("MT_PKNAME", expand_var(concat_pathes(getval("MT_PKDESTDIR"), + getval("MT_PKBASE")))); + /* When "dosnames" is in effect, MT_PKDESTDIR should include "/dpiNNN". */ + if (feature_p("dosnames")) { + string p = xdirname(s_dest); + + setval ("MT_PKDESTDIR", p); + } + setval ("MT_TFMNAME", expand_var(concat_pathes(getval("MT_TFMDESTDIR"), + getval("MT_TFMBASE")))); + setval ("MT_MFNAME", expand_var(concat_pathes(getval("MT_MFDESTDIR"), + getval("MT_MFBASE")))); +} + +int mktexnames(int argc, char **argv) +{ + string name = argv[1]; + + argc--; argv++; /* We are eliminating argv[0] */ + if (argc <= 2) { + setval("DPI", getval("BDPI")); + if (argc == 2) + setval("DEST", argv[1]); + } + else if (argc < 5) { + setval("DPI", argv[1]); + setval("MODE", argv[2]); + if (argc == 4) + setval("DEST", argv[3]); + } + + do_mktexnames(name); + + printf("%s%s%s%s%s\n", normalize(getval("MT_PKNAME")), ENV_SEP_STRING, + normalize(getval("MT_TFMNAME")), ENV_SEP_STRING, + normalize(getval("MT_MFNAME"))); + return 0; +} + +int mktexmkdir(int argc, char **argv) +{ + int i; + string path; + + mt_append_mask = 0; + + /* FIXME: we don't support edited mktexdir.opt files! */ + if (feature_p("appendonlydir")) + /* Set append-only bit on created directories. */ + mt_append_mask = 01000; /* MT_APPEND_MASK=+t;; */ + + for(i = 1; i < argc; i++) { + /* We have to concat the original wd if argv[i] is not absolute */ + if (kpse_absolute_p(argv[i], false)) + errstatus = do_makedir(argv[i]) != 0; + else { + /* original dir is the zeroth directory in the env stack */ + path = concat_pathes(peek_dir(0), argv[i]); + errstatus = do_makedir(path) != 0; + free(path); + } + } + return errstatus; +} +int mktexrmdir(int argc, char **argv) +{ + int i; + + for(i = 1; i < argc; i++) { + do_rmdir(argv[i]); + } + return 0; +} + +void do_mktexupdate(string dir, char *name) +{ + string lsrdir, relative_dir, dirname; + string elt, db_file, line; + FILE *f; + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Mktexupd adds %s in %s\n", name, dir); + } + + normalize(dir); + + if (!test_file('d', dir)) { + fprintf(stderr, "%s: %s not a directory.\n", progname, + test_file('n', dir) ? dir : empty_str); + mt_exit(1); + } + if (!test_file('f', lsrdir = concat_pathes(dir, name))) { + fprintf(stderr, "%s: %s not a file.\n", progname, + test_file('n', lsrdir) ? lsrdir : empty_str); + mt_exit(1); + } + + /* update the current db too ! */ + dirname = concat_pathes(dir, name); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Inserting `%s' into current db\n", dirname); + } + kpse_db_insert(dirname); + free(dirname); + + /* This should give us the ls-R default path */ + if (!kpse_format_info[kpse_db_format].type) /* needed if arg was numeric */ + kpse_init_format (kpse_db_format); + + lsrdir = normalize(xstrdup(kpse_format_info[kpse_db_format].path)); + + setval("TEXMFLS_R", ""); + /* For each argument in the list */ + for (elt = kpse_path_element(lsrdir); + elt; + elt = kpse_path_element(NULL)) { + if (*elt + && FILESTRNCASEEQ(dir, elt, strlen(elt))) { + free(lsrdir); + setval("TEXMFLS_R", lsrdir = xstrdup(elt)); + break; + } + } + if (!test_file('n', getval("TEXMFLS_R"))) + /* just return, it is call by other functions than mktexupd() */ + return; + db_file = concat_pathes(lsrdir, "ls-R"); + + if (!test_file('f', db_file)) { + char *mtlsr_argv[3]; + + mtlsr_argv[0] = "mktexlsr"; + mtlsr_argv[1] = lsrdir; + mtlsr_argv[2] = NULL; + mktexlsr(2, mtlsr_argv); + } + if(!test_file('w', db_file)) { + fprintf(stderr, "%s: %s unwritable.\n", progname, db_file); + mt_exit(1); + } + if ((f = fopen(db_file, "r+b")) == NULL) { + fprintf(stderr, "%s: can't open %s.\n", progname, db_file); + mt_exit(1); + } + if ((line = read_line(f)) == NULL + || (strcmp(line, getval("ls_R_magic")) + && strcmp(line, getval("old_ls_R_magic")))) { + fprintf(stderr, "%s: %s lacks magic string `%s'.\n", progname, db_file, + getval("ls_R_magic")); + mt_exit(1); + } + free(line); + + /* does the fs preserve case ? */ + if (!is_casesensitive(dir)) { + string p; + for(p = dir; *p; p++) + *p = TOLOWER(*p); + for(p = name; *p; p++) + *p = TOLOWER(*p); + } + /* Change `$TEXMFLS_R/' to `./'. */ + if (FILESTRNCASEEQ(dir, lsrdir, strlen(lsrdir))) + relative_dir = concat_pathes("./", dir + strlen(lsrdir)); + else + relative_dir = xstrdup(dir); + fseek(f, 0L, SEEK_END); + fprintf(f, "%s:\n%s\n", relative_dir, name); + /* fputs(dir, f); fputs(":\n", f); + fputs(name, f); fputc('\n', f); */ + fclose(f); + free(relative_dir); +} + +int mktexupdate(int argc, char **argv) +{ + do_mktexupdate(argv[1], argv[2]); + return 0; +} + +/* if dirname is a path that can expand into multiple directories, + return the first directory that exists. */ +string expand(const_string dirname) +{ + string path = kpse_path_expand(dirname); + string elt; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "MktexMF (expand) <= %s\n\t <= %s\n", dirname, path); + } + + for(elt = kpse_path_element(path); + elt && !test_file('d', elt); + elt = kpse_path_element(NULL)) { + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "MktexMF (expand) => %s\n", elt); + } + } + return (elt != NULL ? xstrdup(elt) : NULL); +} + +void do_mktexmf(string font) +{ + string rootname, pointsize, realsize; + string name; + string mfname; + string gen, tmpmf, fullname; + string sauterroot, rootfile, destdir; + FILE *f; + size_t ptsz_len; + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "MktexMF:\n\tFONT: %s\n", font); + } + + split_mf_name(font, &name, &rootname, &pointsize); + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "name = %s, rootname = %s, pointsize = %s\n", + name, rootname, pointsize); + } + + sauterroot = kpse_find_file(concat3("b-", rootname, ".mf"), + kpse_mf_format, false); + + if (test_file('n', sauterroot)) { + rootfile = sauterroot; + rootname = concat("b-", rootname); + } + else if (strlen(rootname) == 8 + && FILESTRNCASEEQ(rootname, "csso12", 6) + && isdigit(rootname[6]) /* FIXME: Should be [0-5] actually */ + && isdigit(rootname[7])) { + rootfile = xstrdup(""); + } + else if (FILESTRNCASEEQ(rootname, "cs", 2) + || FILESTRNCASEEQ(rootname, "lcsss", 5) + || FILESTRNCASEEQ(rootname, "icscsc", 6) + || FILESTRNCASEEQ(rootname, "icstt", 5) + || FILESTRNCASEEQ(rootname, "ilcsss", 6) + ) { + rootfile = kpse_find_file("cscode.mf", + kpse_mf_format, false); + } + else if (strlen(rootname) >= 3 + && ((FILESTRNCASEEQ(rootname, "wn", 2) + && strchr("bBcCdDfFiIrRsStTuUvV", rootname[2])) + || (FILESTRNCASEEQ(rootname, "rx", 2) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", rootname[2]) + && strlen(rootname) >= 4 + && strchr("bBcCfFhHiIlLmMoOsStTxX", rootname[3])) + || ((rootname[0] == 'l' || rootname[0] == 'L') + && strchr("aAbBcCdDhHlL", rootname[1]) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", rootname[2])))) { + char lhprefix[64]; + strcpy(lhprefix, "xxcodes.mf"); + strncpy(lhprefix, name, 2); + rootfile = kpse_find_file(lhprefix, + kpse_mf_format, false); + } + else { + string tem; + rootfile = kpse_find_file(tem = concat(rootname, ".mf"), + kpse_mf_format, false); + free(tem); + } + + if (test_file('z', rootfile)) { + fprintf (stderr, "%s: empty or non-existent rootfile!\n", progname); + mt_exit(1); + } + if (!test_file('f', rootfile)) { + fprintf (stderr, "%s: rootfile %s does not exist!\n", progname, rootfile); + mt_exit(1); + } + + do_mktexnames(name); + destdir = xdirname(getval("MT_MFNAME")); + if (!test_file('d', destdir)) + if (do_makedir(destdir)) + mt_exit(1); + + /* Changing directory */ + pushd(destdir); + + ptsz_len = strlen(pointsize); + if (ptsz_len == 0) { + fprintf(stderr, "%s: no pointsize.\n", progname); + mt_exit(1); + } else if (ptsz_len == 2) { + if (pointsize[0] == '1' && pointsize[1] == '1') + realsize = "10.95"; /* \magstephalf */ + else if (pointsize[0] == '1' && pointsize[1] == '4') + realsize = "14.4"; /* \magstep2 */ + else if (pointsize[0] == '1' && pointsize[1] == '7') + realsize = "17.28"; /* \magstep3 */ + else if (pointsize[0] == '2' && pointsize[1] == '0') + realsize = "20.74"; /* \magstep4 */ + else if (pointsize[0] == '2' && pointsize[1] == '5') + realsize = "24.88"; /* \magstep5 */ + else if (pointsize[0] == '3' && pointsize[1] == '0') + realsize = "29.86"; /* \magstep6 */ + else if (pointsize[0] == '3' && pointsize[1] == '6') + realsize = "35.83"; /* \magstep7 */ + else + realsize = pointsize; + } + /* The new convention is to have three or four letters for the + font name and four digits for the pointsize. The number is + pointsize * 100. We effectively divide by 100 by inserting a + dot before the last two digits. */ + else if (ptsz_len == 4 || ptsz_len == 5) { + /* realsize=`echo "$pointsize" | sed 's/\(..\)$/.\1/'` */ + realsize = (string)xmalloc(ptsz_len + 2); + strcpy(realsize, pointsize); + /* The script doesn't check for last chars being digits, but we do! */ + if (isdigit(realsize[ptsz_len-1]) + && isdigit(realsize[ptsz_len-2])) { + realsize[ptsz_len+1] = '\0'; + realsize[ptsz_len] = realsize[ptsz_len-1]; + realsize[ptsz_len-1] = realsize[ptsz_len-2]; + realsize[ptsz_len-2] = '.'; + free(pointsize); + } + } else realsize = pointsize; + + mfname = concat(name, ".mf"); + if (test_file('r', mfname)) { + gen = normalize(concat_pathes(destdir, mfname)); + fprintf(stderr, "%s: %s already exists.\n", progname, gen); + fprintf(fout, "%s\n", gen); + free(gen); + do_mktexupdate(destdir, mfname); + return; /* in case called by others */ + } + + /* FIXME: We have to expand fontdir and restrain it to the first + valid directory. */ + tmpmf = xstrdup("mfXXXXXX"); + if( mktemp(tmpmf) == NULL ) { + fprintf(stderr, "%s: can't create temp filename in %s.\n", progname, + destdir); + mt_exit(1); + } + if ((f = fopen(tmpmf, "w")) == NULL) { + fprintf(stderr, "%s: can't write into temp filename %s/%s.\n", + progname, destdir, tmpmf); + mt_exit(1); + } + + if (FILESTRNCASEEQ(name, "ec", 2) + || FILESTRNCASEEQ(name, "tc", 2)) { + fprintf(f, "if unknown exbase: input exbase fi;\n"); + fprintf(f, "gensize:=%s;\ngenerate %s;\n", realsize, rootname); + } + else if (FILESTRNCASEEQ(name, "dc", 2)) { + fprintf(f, "if unknown dxbase: input dxbase fi;\n"); + fprintf(f, "gensize:=%s;\ngenerate %s;\n", realsize, rootname); + + } + else if (FILESTRNCASEEQ(name, "cs", 2) + || FILESTRNCASEEQ(name, "lcsss", 5) + || FILESTRNCASEEQ(name, "icscsc", 6) + || FILESTRNCASEEQ(name, "icstt", 5) + || FILESTRNCASEEQ(name, "ilcsss", 6) + ) { + fprintf(f, "input cscode\nuse_driver;\n"); + } + else if (strlen(name) >= 3 + && ((FILESTRNCASEEQ(name, "wn", 2) + && strchr("bBcCdDfFiIrRsStTuUvV", name[2])) + || (FILESTRNCASEEQ(name, "rx", 2) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", name[2]) + && strlen(name) >= 4 + && strchr("bBcCfFhHiIlLmMoOsStTxX", name[3])) + || ((name[0] == 'l' || name[0] == 'L') + && strchr("aAbBcCdDhHlL", name[1]) + && strchr("bBcCdDfFiIoOrRsStTuUvVxX", name[2])))) { + fprintf(f, "input fikparm;\n"); + } + else if (strlen(name) >= 4 && strchr("gG", name[0]) + && strchr("oOrRsStTlL", name[1]) + && strchr("iIjJmMtTwWxX", name[2]) + && strchr("cCiInNoOuU", name[3])) { + /* The CB font family; the test matches (case insensitively) the + pattern `g[lorst][ijmtwx][cinou]*'. + This is only slightly more general than the exact set of patterns. */ + fprintf(f, "gensize:=%s;\ninput %s;\n", realsize, rootname); + } + else { + /* FIXME: this was in the previous versions */ + /* fprintf(tmpfile, "if unknown %s: input %s fi;\n", base, base); */ + fprintf(f, "design_size := %s;\ninput %s;\n", + realsize, rootname); + } + fclose(f); + chmod_as_dir(tmpmf, ".", 00644); + unlink(mfname); + if (mvfile(tmpmf, mfname) == FALSE) { + mt_exit(1); + } + setval("destdir", destdir); + setval("mfname", mfname); + fullname = normalize(concat_pathes(destdir, mfname)); + fprintf(fout, "%s\n", fullname); + fprintf(stderr, "%s: %s: successfully generated.\n", progname, fullname); + free(fullname); + do_mktexupdate(destdir, mfname); +} + +int mktexmf(int argc, char **argv) +{ + start_redirection(false); + do_mktexmf(argv[1]); + return 0; +} + +void do_mktextex(const_string texname) +{ + string fullname, destdir; + + /* + We may try to get this file directly from a remote repository. + */ +#if 0 + fprintf(fout, "%s\n", + fullname = normalize(concat_pathes(destdir, texname))); + fprintf(stderr, "%s: %s: successfully generated.\n", progname, fullname); +#endif +} + +int mktextex(int argc, char **argv) +{ + start_redirection(false); + do_mktextex(argv[1]); + return 0; +} + +boolean check_for_strange_path(string name) +{ + FILE *f; + string line; + string strange1 = "! Strange path"; + string strange2 = "! bad pos"; + string strange3 = "! angle(0,0) is taken as zero."; + boolean res = false; /* in case there are no lines which begin with `!' */ + + if ((f = fopen(name, "r")) == NULL) { + fprintf(stderr, "%s: warning: can't open log file %s.\n", progname, name); + return false; + } + while ((line = read_line(f)) != NULL) { + if (*line == '!') { + if (strncmp(line, strange1, strlen(strange1)) + && strncmp(line, strange2, strlen(strange2)) + && strncmp(line, strange3, strlen(strange3)) + ) { + res = false; + break; + } + else if (res == false) + res = true; /* seen at least one ``Strange path'' message */ + } + } + fclose(f); + return res; +} + + +void do_mktextfm(string font, string destdir) +{ + string fullname, name; + char tfmtempname[PATH_MAX]; + char pktempname[PATH_MAX]; + char cmd[256]; + int retcode; + + setval("NAME", name = my_basename(font, ".tfm")); + setval("MAG", "1"); + setval("DEST", destdir); + setval("DPI", getval("BDPI")); + + do_mktexnames(name); + + setval("PKDEST", getval("MT_PKNAME")); + setval("TFMDEST", getval("MT_TFMNAME")); + setval("PKDESTDIR", getval("MT_PKDESTDIR")); + setval("TFMDESTDIR", getval("MT_TFMDESTDIR")); + setval("PKNAME", (string)xbasename(getval("MT_PKNAME"))); + setval("TFMNAME", concat(name, ".tfm")); + /* FIXME: can e.g. cmr10.600gf clash with e.g. cmr10.600whatever on DOS? */ + setval("GFNAME", concatn(name, ".", getval("DPI"), "gf", NULL)); + + fullname = expand_var("$TFMDESTDIR/$TFMNAME"); + if (test_file('r', fullname)) { + fprintf(stderr, "%s: %s already exists.\n", progname, fullname); + fprintf(fout, "%s\n", fullname); + free(fullname); + do_mktexupdate(getval("TFMDESTDIR"), getval("TFMNAME")); + return; + } + free(fullname); + + do_makedir(getval("TFMDESTDIR")); + if (!test_file('d', getval("TFMDESTDIR"))) { + fprintf(stderr, "%s: mktexdir %s failed.\n", + progname, getval("TFMDESTDIR")); + mt_exit(1); + } + + /* Protect the semi-colons from being interpreted by the shell. + (Use double quotes since they are supported on non-Unix platforms.) */ + sprintf(cmd, "mf \"\\mode:=%s; mag:=%s; nonstopmode; input %s\"", + getval("MODE"), getval("MAG"), getval("NAME")); + + fprintf(stderr, "%s: Running %s\n", progname, cmd); + + /* Now run metafont. + Note that stdin has been redirected to "/dev/null" by `main'. */ + retcode = system(cmd); + + if (retcode != 0) { + if (retcode == -1) { + perror(cmd); + mt_exit(1); + } + else if (check_for_strange_path(expand_var("$NAME.log")) == true) { + fprintf(stderr, "%s: warning: `%s' caused strange path errors.\n", + progname, cmd); + } + else { + struct stat statbuf; + fprintf(stderr, "%s: `%s' failed.\n", progname, cmd); + if (stat(expand_var("$NAME.log"), &statbuf) == 0 + && statbuf.st_size > 0) + mvfile(expand_var("$NAME.log"), + concat_pathes(getval("KPSE_DOT"), expand_var("$NAME.log"))); + mt_exit(1); + } + } + + if (!test_file('r', getval("TFMNAME"))) { + fprintf(stderr, "%s: `%s' failed to make %s.\n", + progname, cmd, getval("TFMNAME")); + mt_exit(1); + } + + /* Install the TFM file carefully, since others + may be working simultaneously. */ + sprintf(tfmtempname, "%s/tfXXXXXX", getval("TFMDESTDIR")); + mktemp(tfmtempname); + if (mvfile(getval("TFMNAME"), tfmtempname) == FALSE) { + mt_exit(1); + } + + pushd(getval("TFMDESTDIR")); + chmod_as_dir(tfmtempname, ".", 00644); + if (!test_file('r', getval("TFMNAME"))) { + char *tfmtmp_base = tfmtempname + strlen(getval("TFMDESTDIR")) + 1; + + if (mvfile(tfmtmp_base, getval("TFMNAME")) == FALSE) { + mt_exit(1); + } + } + + /* OK, success with the TFM. */ + do_mktexupdate(getval("TFMDESTDIR"), getval("TFMNAME")); + fullname = normalize(concat_pathes(getval("TFMDESTDIR"), getval("TFMNAME"))); + fprintf(fout, "%s\n", fullname); + + fprintf(stderr, "%s: %s: successfully generated.\n", progname, + fullname); + + /* Since we probably made a GF(->PK) file, too, may as well install + it if it's needed. */ + popd(); /* Back to $TEMPDIR */ + if (test_file('r', getval("GFNAME")) + && !test_file('f', concat_pathes(getval("PKDESTDIR"), + getval("PKNAME")))) { + char *pktmp_base; + + sprintf(cmd, "gftopk ./%s %s", getval("GFNAME"), getval("PKNAME")); + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "Running: %s\n", cmd); + } + retcode = system(cmd); + if (retcode != 0) { + if (retcode == -1) + perror("gftopk"); + else + fprintf(stderr, "%s: gftopk failed to make %s.\n", + progname, getval("PKNAME")); + mt_exit(1); + } + + do_makedir(getval("PKDESTDIR")); + sprintf(pktempname, "%s/pkXXXXXX", getval("PKDESTDIR")); + mktemp(pktempname); + if (mvfile(getval("PKNAME"), pktempname) == FALSE) { + mt_exit(1); + } + pushd(getval("PKDESTDIR")); + pktmp_base = pktempname + strlen(getval("PKDESTDIR")) + 1; + if (test_file('f', getval("PKNAME"))) + remove(pktmp_base); + else { + chmod_as_dir(pktmp_base, ".", 00644); + if (mvfile(pktmp_base, getval("PKNAME")) == FALSE) { + mt_exit(1); + } + do_mktexupdate(getval("PKDESTDIR"), getval("PKNAME")); + } + popd(); + } +} + +/* this is similar to mktexpk ... */ +int mktextfm(int argc, char **argv) +{ + string dest = getval("DEST"); + string font = argv[1]; + + /* Where do potential driver files belong? + case "$MT_FEATURES" in + *nomfdrivers*) + : ${MT_MFDESTDIR=`pwd`} + export MT_MFDESTDIR;; + esac + */ + if (feature_p("nomfdrivers")) { + setval_default("MT_MFDESTDIR", xgetcwd()); + } + + start_redirection(false); + do_mktextfm(font, dest); + return 0; +} + +int get_mode_from_mf(string mode) +{ + FILE *fpipe; + char buf[1024]; + int result = 0; + + sprintf(buf, "mf \"\\mode:=%s;mode_setup;message\\\"BDPI= \\\"&decimal round pixels_per_inch;end.\"", mode); + + /* METAFONT's stdin was redirected to /dev/null by `main'. */ + fpipe = popen(buf, "r"); + if (fpipe == NULL) { + perror("pipe to mf"); + return 0; + } + + /* awk '/DPI=/ {print $2}' */ + while (fgets(buf, sizeof buf, fpipe)) { + char *p = strstr(buf, "DPI= "); + if (p) + result = atoi(p + 5); /* could break here, but AWK script doesn't */ + } + if (pclose(fpipe)) + perror("running mf"); + return result; +} + +/* A common lossage with stock DOS/Windows shells is that `system("foo")' + returns zero even though `foo' doesn't exist as an executable. A better + way is to say `system("foo.exe")', but that is non-portable to Unix. + + Thus the need for this function. It is a no-op (always returning TRUE) + on Unix, but on DOS/Windows actually looks for its argument along the + PATH. It is assumed that on Unix, the call to `system' will fail as God + intended if the program is not accessible via PATH. */ +boolean find_exe(char *progname) +{ + char path[PATH_MAX]; +#ifdef _WIN32 + char *fp; + return (SearchPath(NULL, progname, ".exe", PATH_MAX, path, &fp) != 0); +#else +# ifdef __DJGPP__ + extern char * __dosexec_find_on_path (const char *, char **, char *); + extern char **environ; + return __dosexec_find_on_path (progname, environ, path) != NULL; +# else + return true; +# endif +#endif +} + +/* + We will read the `modes.mf' and gather the various modes. +*/ +#define MAX_MODES 64 + +struct mf_mode +{ + string mnemonic; + string description; + int hor_res; + int vert_res; +}; + +static struct mf_mode *modes; +static int nb_modes; + +#define SKIP_NON_DIGIT(p) while(!isdigit(*p)) p++ +#define SKIP_ALPHA(p) while(isalpha(*p)) p++; +#define SKIP_SPACE(p) while(isspace(*p)) p++; +#define SKIP_LINE(p) while(*p && *p != '\n') p++; + +static boolean __cdecl +cmp_mf_mode(const struct mf_mode *m1, const struct mf_mode *m2) { + return (strcmp(m1->description, m2->description) < 0); +} + +static boolean +read_modes() +{ + string modes_file_name = kpse_find_file("modes.mf", kpse_mf_format, true); + FILE *f; + string line; + boolean in_mode_def = false; + int size_modes = MAX_MODES; + + /* modes will keep this value if modes.mf can't be found or read. */ + modes = (struct mf_mode *)-1; + if (modes_file_name == NULL) + return false; + if((f = fopen(modes_file_name, "r")) == NULL) { + free(modes_file_name); + return false; + } + + modes = xmalloc(size_modes * sizeof(struct mf_mode)); + + while((line = read_line(f)) != NULL) { + if (in_mode_def) { + char * cp; + if (strncmp(line, "enddef;", 7) == 0) { + nb_modes++; + if (nb_modes == MAX_MODES) { + size_modes *= 2; + modes = xrealloc(modes, size_modes * sizeof(struct mf_mode)); + } + in_mode_def = false; + } + else if (modes[nb_modes].hor_res == 0 + && (cp = strstr(line, "pixels_per_inch"))) { + SKIP_NON_DIGIT (cp); + modes[nb_modes].hor_res = atoi(cp); + modes[nb_modes].vert_res = atoi(cp); + } + else if (cp = strstr(line, "aspect_ratio")) { + SKIP_NON_DIGIT (cp); + modes[nb_modes].vert_res = atoi(cp); + } + } + else if (strncmp(line, "mode_def", 8) == 0) { + char *mode_name, *printer_name; + char *cp = line + 8; + while (! isalpha(*cp) && *cp != '\n') + cp++; + if (! isalpha (*cp)) + goto line_done; + mode_name = cp; + SKIP_ALPHA (cp); + if (*cp == 0) + goto line_done; + *cp++ = 0; + if (strcmp(mode_name, "help") == 0) + goto line_done; + cp = strstr(cp, "%\\["); + if (cp == 0) + goto line_done; + cp += 3; + SKIP_SPACE (cp); + if (cp == 0) + goto line_done; + printer_name = cp; + SKIP_LINE (cp); + *cp = 0; + in_mode_def = true; + + modes[nb_modes].mnemonic = xstrdup(mode_name); + modes[nb_modes].description = xstrdup(printer_name); + modes[nb_modes].hor_res = 0; + } + line_done: + free(line); + } + qsort(modes, nb_modes, sizeof(struct mf_mode), cmp_mf_mode); + return true; +} + +string +get_mf_mode(int dpi) +{ + int i; + + if ((modes == NULL && !read_modes()) + || (modes == (struct mf_mode *)-1)) + return NULL; + + for (i = 0; i < nb_modes; i++) { + if (modes[i].hor_res == dpi) + return modes[i].mnemonic; + } + return NULL; +} + +int mktexpk(int argc, char **argv) +{ + FILE *psmapfile; + string psmapfilename, fullname; + string line = NULL, pktempname; + string cmd = "", gfcmd; + string aname, mfname; + string *vars; + int mf_bdpi, ibdpi, retcode; + boolean has_ttf2pk = false, has_hbf2gf = false; + + /* Where do potential driver files belong? + case "$MT_FEATURES" in + *nomfdrivers*) + : ${MT_MFDESTDIR=`pwd`} + export MT_MFDESTDIR;; + esac + */ + if (feature_p("nomfdrivers")) { + setval_default("MT_FEATURES", xgetcwd()); + } + + if (argc == 3) { + char *ep = NULL; + int fd = - 1; + + if (argv[1][0] == '>' && argv[1][1] == '&' && isdigit(argv[1][2])) + fd = strtoul(argv[1] + 2, &ep, 0); + if (!ep || *ep || fd > 255 || fd < 0) + fprintf(stderr, "%s: argument '%s' ignored - bad file number\n", + progname, argv[2]); + else if (fd != 1) + /* The actual redirection happens before we print the names + of generated file(s). */ + record_output_handle(fd); + } + + start_redirection(false); + + setval("NAME", argv[1]); + + has_ttf2pk = find_exe("ttf2pk"); + has_hbf2gf = find_exe("hbf2gf"); + + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + fprintf(stderr, "MktexPK:\n\tName: %s\n\tDpi: %s\n\tBdpi: %s\n\tMag: %s\n\tMode: %s\n\tDest: %s\n", getval("NAME"), getval("DPI"), getval("BDPI"), + getval("MAG"), getval("MODE"), getval("DEST")); + } + + mfname = concat(getval("NAME"), ".mf"); + cmd = expand_var("mktexmf $NAME"); + + if ((kpse_find_file(mfname, kpse_mf_format, false) != NULL) + || (system(cmd) == 0)) { + + cmd = NULL; /* reset cmd */ + if (test_file('n', getval("MODE"))) { + if ((mf_bdpi = get_mode_from_mf(getval("MODE"))) + != atoi(getval("BDPI"))) { + fprintf(stderr, "%s: Mismatched mode %s and resolution %s; ignoring mode.\n", progname, getval("MODE"), getval("BDPI")); + setval("MODE", ""); + } + } + + if (test_file('z', getval("MODE")) + || strcmp(getval("MODE"), "default") == 0) { + ibdpi = atoi(getval("BDPI")); + switch (ibdpi) { + case 85: + setval("MODE", "sun"); + break; + case 100: + setval("MODE", "nextscrn"); + break; + case 180: + setval("MODE", "toshiba"); + break; + case 300: + setval("MODE", "cx"); + break; + case 400: + setval("MODE", "nexthi"); + break; + case 600: + setval("MODE", "ljfour"); + break; + case 720: + setval("MODE", "epshi"); + break; + case 1270: + setval("MODE", "linoone"); + break; + default: { + string mode = get_mf_mode(ibdpi); + if (mode) { + setval("MODE", mode); + } + else { + fprintf (stderr, "%s: Can't guess mode for %s dpi devices.\n", + progname, getval("BDPI")); + fprintf (stderr, "%s: Use a config file, or update me.\n", + progname); + mt_exit(1); + } + } + } + } + /* Run Metafont. Always use plain Metafont, since reading cmbase.mf */ + /* does not noticeably slow things down. */ + cmd=expand_var("mf \"\\mode:=$MODE; mag:=$MAG; nonstopmode; input $NAME\""); + } + else { + cmd = NULL; /* reset cmd */ + setval("MODE", "modeless"); + if (FILESTRCASEEQ(getval("ps_to_pk"), "gsftopk")) { +#if 0 + if (KPSE_DEBUG_P(MKTEX_DEBUG)) { + printf("Test: system -> %d win32_system -> %d\n", + system(expand_var("$ps_to_pk -t $NAME")), + win32_system(expand_var("$ps_to_pk -t $NAME"))); + } +#endif + if (system(expand_var("$ps_to_pk -t $NAME"))==0) { + cmd = expand_var("$ps_to_pk $NAME $DPI"); + } + } + else if (FILESTRCASEEQ(getval("ps_to_pk"), "ps2pk")) { + string pstmp; + /* look for name in psfont.map. + Can't use `kpse_open_file' because it exits if the file doesn't + exits, and we have a special exit procedure which cleans up. */ + pstmp = kpse_find_file("ps2pk.map", kpse_fontmap_format, false); + if (test_file('z', pstmp)) + pstmp = kpse_find_file("psfonts.map", kpse_fontmap_format, false); + psmapfilename = setval_default("PSMAPFILE", pstmp); + if (test_file('n', pstmp)) free(pstmp); + + if (test_file('n', psmapfilename)) { + string pattern = concat3("^", getval("NAME"), "([ \t]|$)"); + + psmapfile = fopen(psmapfilename, "r"); + if (psmapfile == NULL) oops("Cannot open file %s.", psmapfilename); + while ((line = read_line(psmapfile)) != NULL) { + if ((vars = grep(pattern, line, 1)) != NULL) + break; + free(line); + line = NULL; + } + free(pattern); + fclose(psmapfile); + } + else + fprintf(stderr, "%s: no `psfonts.map' file.\n", progname); + + if (line != NULL) { + /* ps_to_pk is set in mktex.opt */ + string encoding, psname, slant, extend; + encoding = psname = slant = extend = ""; + /* FIXME: mktexpk script has a loop here which effectively + looks for the LAST matching string. Is it important? */ + if ((vars = grep("([^ \t<[\"]*.enc)", line, 1))) + encoding = concat ("-e", vars[1]); + if ((vars = grep("([^ \t<[\"]*.pf[ab])", line, 1))) + psname = vars[1]; + if ((vars = grep("\" ([^ \t]+)SlantFont\"", line, 1))) + slant = concat ("-S ", vars[1]); + if ((vars = grep("\" ([^ \t]+)ExtendFont\"", line, 1))) + extend = concat ("-E", vars[1]); + /* This is looking for .pfa *and* .pfb with the 7.2 kpathsea. */ + if (test_file('z', psname)) { + psname = kpse_find_file(getval("NAME"), kpse_type1_format, false); + } + if (test_file('z', psname)) { + aname = xstrdup(getval("NAME")); + if (strlen(aname) >= 2 + && aname[strlen(aname)-2] == '8' + && aname[strlen(aname)-1] == 'r') + /* Guessing the name of the type1 font file as fallback: */ + aname[strlen(aname)-1] = 'a'; + psname = kpse_find_file(aname, kpse_type1_format, false); + free(aname); + } + if (test_file('n', psname)) { + /* In fact, ps2pk can't cope with the full pathname, so : */ + psname = xbasename(psname); + cmd = concatn( expand_var("ps2pk -v -X$DPI -R$BDPI"), + slant, " ", extend, " ", encoding, + " ", psname, " ", expand_var("$NAME.${DPI}pk"), NULL); + } + else { + cmd = expand_var("gsftopk -t $NAME"); + if (system(cmd) == 0) { + cmd = NULL; /* reset cmd */ + fprintf(stderr, + "%s: cannot find %s.pfa or %s.pfb. Trying gsftopk.\n", + progname, getval("NAME"), getval("NAME")); + cmd = expand_var("gsftopk $NAME $DPI"); +#if 0 + /* make sure that gsftopk uses the psline from our mapfile: */ + { + FILE *f; + if ((f = fopen("./psfonts.map", "w")) != NULL) { + fprintf(f, "%s\n", line); + fclose(f); + setval("TEXFONTMAP", expand_var(".;$TEXFONTMAP")); + } + else { + /* Can't write in the current directory ? Strange ... + Anyway, let's go on and home we will find the right + psfonts.map ... */ + } + } +#endif + } + else { + cmd = NULL; /* reset cmd */ + } + } + } + } + + /* unsupported by $ps_to_pk, try other conversions: */ + if (test_file('z', cmd)) { + if (has_ttf2pk && system(expand_var("ttf2pk -t -q $NAME")) == 0) { + cmd = expand_var("ttf2pk -q $NAME $DPI"); + } + else if (has_hbf2gf && system(expand_var("hbf2gf -q -t $NAME")) == 0) { + cmd = expand_var("hbf2gf -g $NAME $DPI"); + } + else { + fprintf(stderr, "%s: don't know how to create bitmap font for %s.", + progname, getval("NAME")); + mt_exit(1); + } + } + } + + /* Put files into proper place */ + do_mktexnames(getval("NAME")); + + setval("PKDEST", getval("MT_PKNAME")); + setval("PKDESTDIR", getval("MT_PKDESTDIR")); + setval("PKNAME", (string)xbasename(getval("PKDEST"))); + setval("GFNAME", expand_var("${NAME}.${DPI}gf")); + + if (test_file('r', fullname = expand_var("$PKDESTDIR/$PKNAME"))) { + fprintf(stderr, "%s: %s already exists.\n", + progname, fullname); + fprintf(fout, "%s\n", fullname); + free(fullname); + do_mktexupdate(getval("PKDESTDIR"), getval("PKNAME")); + return 0; + } + + do_makedir(getval("PKDESTDIR")); + if (!test_file('d', getval("PKDESTDIR"))) { + fprintf(stderr, "%s: mktexdir %s failed.\n", + progname, getval("PKDESTDIR")); + mt_exit(1); + } + + printf("%s: Running %s\n", progname, cmd); + + /* Now run metafont. + Note that stdin has been redirected to "/dev/null" by `main'. */ + retcode = system(cmd); + if (retcode != 0) { + fprintf(stderr, "command %s return %d\n", cmd, retcode); + if (retcode == -1) { + perror("mf"); + mt_exit(1); + } + else if (check_for_strange_path(expand_var("$NAME.log")) == true) { + fprintf(stderr, "%s: warning: `%s' caused strange path errors.\n", + progname, cmd); + } + else { + struct stat statbuf; + fprintf(stderr, "%s: `%s' failed.\n", progname, cmd); + if (stat(expand_var("$NAME.log"), &statbuf) == 0 + && statbuf.st_size > 0) + mvfile(expand_var("$NAME.log"), + concat_pathes(getval("KPSE_DOT"), expand_var("$NAME.log"))); + mt_exit(1); + } + } + + if (test_file('r', getval("GFNAME"))) { + gfcmd = expand_var("gftopk ./$GFNAME $PKNAME"); + retcode = system(gfcmd); + if (retcode == -1) { + perror("gftopk"); + mt_exit(1); + } + else if (retcode != 0) { + fprintf(stderr, "%s: `%s' failed.\n", progname, gfcmd); + mt_exit(1); + } + } + + /* FIXME : What about the file is created in the current directory ? */ + if (!test_file('f', getval("PKNAME")) + && test_file('f', expand_var("$NAME.${DPI}pk"))) + mvfile(expand_var("$NAME.${DPI}pk"), getval("PKNAME")); + + if (!test_file('s', getval("PKNAME"))) { + fprintf(stderr, "%s: `%s' failed to make %s.\n", + progname, cmd, getval("PKNAME")); + mt_exit(1); + } + + pktempname = concat_pathes(getval("PKDESTDIR"), "pkXXXXXX"); + mktemp(pktempname); + if (mvfile(getval("PKNAME"), pktempname) == FALSE) { + mt_exit(1); + } + + pushd(getval("PKDESTDIR")); + chmod_as_dir(pktempname, ".", 00644); + if (!test_file('r', getval("PKNAME"))) + if (mvfile(pktempname, getval("PKNAME")) == FALSE) { + mt_exit(1); + } + + /* OK, success with the PK. */ + do_mktexupdate(getval("PKDESTDIR"), getval("PKNAME")); + fullname = normalize(concat_pathes(getval("PKDESTDIR"), + getval("PKNAME"))); + fprintf(fout, "%s\n", fullname); + fprintf(stderr, "%s: %s: successfully generated.\n", progname, + fullname); + free(fullname); + + popd(); + return 0; +} diff --git a/Build/source/texk/contrib/mktex.h b/Build/source/texk/contrib/mktex.h new file mode 100644 index 00000000000..153598086fe --- /dev/null +++ b/Build/source/texk/contrib/mktex.h @@ -0,0 +1,58 @@ +/* mktex.h: definitions for mktex lib exports. + +Copyright (C) 1997 Fabrice POPINEAU. +Adapted to MS-DOS/DJGPP by Eli Zaretskii <eliz@is.elta.co.il>. + +Time-stamp: <02/12/23 00:33:08 popineau> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _MKTEX_H_ +#define _MKTEX_H_ + +#include "mktexlib.h" + +/* Pointer to functions that accept argc and argv[] */ +typedef int (*fp)(int, string*); + +typedef struct _program_description { + string name; + int arg_min; + int arg_max; + fp prog; +} program_description; + +extern MKTEXDLL int program_number; +extern MKTEXDLL string progname; +extern MKTEXDLL char empty_str[]; +extern MKTEXDLL FILE *fout; +extern MKTEXDLL FILE *fnul; +extern MKTEXDLL string output; +extern MKTEXDLL string progname; +extern MKTEXDLL char tmpdir[]; +extern MKTEXDLL void mktexinit(int, char**); +extern MKTEXDLL int mktexpk(int, char**); +extern MKTEXDLL int mktextfm(int, char**); +extern MKTEXDLL int mktextex(int, char**); +extern MKTEXDLL int mktexmf(int, char**); +extern MKTEXDLL int mktexlsr(int, char**); +extern MKTEXDLL int mktexupdate(int, char**); +extern MKTEXDLL int mktexmkdir(int, char**); +extern MKTEXDLL int mktexrmdir(int, char**); +extern MKTEXDLL int mktexnames(int, char**); +extern MKTEXDLL int mktex_opt(int, char**, program_description *); +extern MKTEXDLL program_description makedesc[]; +#endif /* _MKTEX_H_ */ + diff --git a/Build/source/texk/contrib/mktexlib.h b/Build/source/texk/contrib/mktexlib.h new file mode 100644 index 00000000000..14391ccc18a --- /dev/null +++ b/Build/source/texk/contrib/mktexlib.h @@ -0,0 +1,61 @@ +#ifndef _MKTEXLIB_H_ +#define _MKTEXLIB_H_ + +#if defined(WIN32) +# ifdef MKTEX_DLL +# ifdef MAKE_MKTEX_DLL +# define MKTEXDLL __declspec( dllexport) +# else +# define MKTEXDLL __declspec( dllimport) +# endif +# else +# define MKTEXDLL +# endif +#else /* ! WIN32 */ +# define MKTEXDLL +# define __cdecl +#endif + +#include <assert.h> +#ifdef _WIN32 +#include <direct.h> +#else +#include <unistd.h> +#include <signal.h> +#endif +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <time.h> +#include <sys/stat.h> + +#include <kpathsea/config.h> +#include <kpathsea/kpathsea.h> +extern KPSEDLL char* kpathsea_version_string; + +#ifndef _WIN32 +#include <sys/param.h> +#endif + +#ifdef WIN32 +# ifdef mkdir +# undef mkdir +# endif +# define mkdir(p,m) _mkdir(p) +typedef unsigned long mode_t; +#else +# define _getdrive() (getdisk() + 1) +# define FS_CASE_SENSITIVE _FILESYS_CASE_SENSITIVE +typedef unsigned int DWORD; +#endif + +/* gsftopk defines KPSE_LAST_DEBUG+2, so avoid clashes */ +#define MKTEX_DEBUG (KPSE_LAST_DEBUG + 3) +#define MKTEX_FINE_DEBUG (KPSE_LAST_DEBUG + 4) + + +#define LAST_CHAR(s) (*((s)+strlen(s)-1)) + +extern MKTEXDLL string mktex_version_string; + +#endif /* _MKTEXLIB_H_ */ diff --git a/Build/source/texk/contrib/pdfdde.c b/Build/source/texk/contrib/pdfdde.c new file mode 100644 index 00000000000..b6736e7fd28 --- /dev/null +++ b/Build/source/texk/contrib/pdfdde.c @@ -0,0 +1,564 @@ +/* pdfdde.c -- control Adobe Acrobat under Windows. Written by Fabrice + Popineau many years ago, based on Adobe documentation. Public + domain. */ + +// #include <afx.h> +#include <win32lib.h> +#include <ddeml.h> +#include <dde.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <shellapi.h> + +#include <getopt.h> + +#define ACROBAT_EXE "acrobat.exe" +#define ACROBAT "acroview" +#define EVAL_TOPIC "control" +#define RESULT_ITEM "Result" +#define ERROR_ITEM "Error" + +/* Timeouts & delays */ +#define CONNECT_DELAY 500 /* ms */ +#define TRANSACTION_TIMEOUT 5000 /* ms */ +#define MAX_INPUT_IDLE_WAIT INFINITE /* ms */ + +static DWORD DDEsession; +static HCONV DDEconversation; + +/* The raw base name */ +static char *argv0 = NULL; +static int nPage = 0; +static char *sFileName = NULL; +static int bAll = 0; +static int bServer = 0; +static int iDebug = 0; +static char *sGoto = NULL; +static char sLongFileName[MAXPATHLEN]; + +const char *pdfdde_version_string = "0.2"; + +/* Test whether getopt found an option ``A''. + Assumes the option index is in the variable `option_index', and the + option table in a variable `long_options'. */ +#define ARGUMENT_IS(a) (_stricmp(long_options[option_index].name, a) == 0) +#define PROGRAM_IS(a) (_stricmp(a, argv0) == 0) + +static struct option long_options [] = { + { "debug", 0, 0, 0}, + { "help", 0, 0, 0}, + { "version", 0, 0, 0}, + { "file", 1, 0, 0}, + { "page", 1, 0, 0}, + { "goto", 1, 0, 0}, + { "all", 0, 0, 0}, + {0, 0, 0, 0} +}; + + +char *FindAcrobatModule() +{ + char buf[260]; + char path[260]; + char *program; + HANDLE hFile; + HINSTANCE hInst; + + program = (char *)malloc(MAX_PATH*sizeof(char)); + if (program == NULL) goto exit_1; + + buf[0] = path[0] = program[0] = '\0'; + + if (GetTempPath(sizeof(path), path) != 0) { + strcpy(buf, path); + } + + + strcat(buf, "dummy.pdf"); + + hFile = CreateFile(buf, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + CloseHandle(hFile); + + hInst = FindExecutable("dummy.pdf", path, program); + + DeleteFile(buf); + +#if 0 + switch ((int)hInst) { + case SE_ERR_FNF: + fprintf(stdout, "File not found: %s\n", argv[1]); + break; + case SE_ERR_NOASSOC: + fprintf(stdout, "No association for %s\n", argv[1]); + break; + default: + fprintf(stdout, "File .pdf is opened by %s\n", program); + break; + } +#endif + + if (*program == '\0' || (GetFileAttributes(program) == 0xFFFFFFFF)) { + program = NULL; + } + +exit_1: + return program; + +} + +void CloseConversation (void) +{ + if (DDEconversation) + DdeDisconnect(DDEconversation); + if (DDEsession) + DdeUninitialize(DDEsession); +} + +void error(LPCTSTR fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + + /* Tidy up */ + CloseConversation(); + exit(1); +} + +void *emalloc(size_t len) +{ + void *p = malloc(len); + + if (p == NULL) + error("Out of memory - cannot allocate %d bytes", len); + + return p; +} + +int outstanding_requests; + +HDDEDATA CALLBACK +Callback (UINT uType, UINT uFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, + HDDEDATA hdata, DWORD dwData1, DWORD dwData2) +{ + if (uType == XTYP_ADVDATA) { + DWORD len = DdeGetData(hdata, NULL, 0, 0); + char *buf = _alloca(len + 1); + DdeGetData(hdata, (LPBYTE)buf, len + 1, 0); + + if (--outstanding_requests == 0) + PostQuitMessage(0); + + return (HDDEDATA) DDE_FACK; + } + + return (HDDEDATA) NULL; +} + +int StartServer(LPCTSTR prog) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + + /* To be sure ... */ + if (! prog) + return 1; + + ZeroMemory (&si, sizeof (si)); + si.cb = sizeof (si); + if (!CreateProcess (NULL, (LPTSTR)prog, NULL, NULL, FALSE, 0, + NULL, NULL, &si, &pi)) + { + error("Could not start process %s", prog); + return 1; + } + + /* Wait for the process to enter an idle state */ + WaitForInputIdle (pi.hProcess, MAX_INPUT_IDLE_WAIT); + + /* Close the handles */ + CloseHandle (pi.hThread); + CloseHandle (pi.hProcess); + return 0; +} + +HSZ DDEString(LPCTSTR str) +{ + HSZ hsz = DdeCreateStringHandle(DDEsession, str, CP_WINANSI); + if (hsz == 0) + error("Cannot create string for %s", str); + return hsz; +} + +FreeString(HSZ hsz) +{ + DdeFreeStringHandle(DDEsession, hsz); +} + +void OpenConversation(LPCTSTR topic_name) +{ + UINT ret; + HSZ service; + HSZ topic; + int n; + + ret = DdeInitialize(&DDEsession, Callback, APPCMD_CLIENTONLY, 0); + if (ret != DMLERR_NO_ERROR) + error("Cannot start DDE"); + + service = DDEString(ACROBAT); + topic = DDEString(topic_name); + DDEconversation = DdeConnect(DDEsession, service, topic, 0); + + if (DDEconversation == 0) + { + if (StartServer(FindAcrobatModule()) == 0) + { + /* Try to connect */ + for (n = 0; n < 5; n++) + { + Sleep (CONNECT_DELAY); + DDEconversation = DdeConnect(DDEsession, service, topic, 0); + if (DDEconversation) + break; + } + if (DDEconversation == 0) + error("Cannot contact server %s", ACROBAT); + } + } + FreeString(service); + FreeString(topic); +} + +void __cdecl ExecuteCommand(LPCTSTR command, ...) +{ + HDDEDATA ret; + va_list args; + int len; + char *buffer; + + va_start( args, command ); + len = _vscprintf(command, args) // _vscprintf doesn't count + + 1; // terminating '\0' + buffer = malloc( len * sizeof(char) ); + vsprintf( buffer, command, args ); + + ret = DdeClientTransaction((LPBYTE)buffer, strlen(buffer) + 1, + DDEconversation, 0, 0, XTYP_EXECUTE, + TRANSACTION_TIMEOUT, 0); + if (ret == 0) + error("Cannot execute command \"%s\" (error %ld)", command, DdeGetLastError(DDEsession)); +} + +void StartHotLink(LPCTSTR item_name) +{ + HSZ item = DDEString(item_name); + DdeClientTransaction(0, 0, DDEconversation, item, CF_TEXT, XTYP_ADVSTART, + TRANSACTION_TIMEOUT, 0); + FreeString(item); +} + +LPTSTR RequestData (LPCTSTR item_name) +{ + HSZ item = DDEString(item_name); + DWORD len; + char *buf; + HDDEDATA result; + result = DdeClientTransaction (NULL, 0, DDEconversation, item, CF_TEXT, + XTYP_REQUEST, TRANSACTION_TIMEOUT, 0); + FreeString(item); + if (result == 0) + error("Cannot request item %s\n", item_name); + + len = DdeGetData(result, NULL, 0, 0); + buf = emalloc(len + 1); + DdeGetData(result, (LPBYTE)buf, len + 1, 0); + return buf; +} + +void usage() +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpdfopen --file <filename> [--page <page>]\n"); + fprintf(stderr, "\t\t Opens <filename> (at page <page> if available)\n"); + fprintf(stderr, "\t\t in Acrobat or Acrobat Reader.\n"); + fprintf(stderr, "\tpdfclose --file <filename>\n"); + fprintf(stderr, "\t Closes <filename> in Acrobat or Acrobat Reader.\n"); + fprintf(stderr, "\tpdfclose --all\n"); + fprintf(stderr, "\t Closes all documents in Acrobat or Acrobat Reader.\n"); + fprintf(stderr, "\tpdfdde\n"); + fprintf(stderr, "\t\t Read commands on stdin\n"); + fprintf(stderr, "Beware: only documents opened by `pdfopen' can be closed\n"); + fprintf(stderr, " by `pdfclose'.\n"); + exit(0); +} + +char *CheckFileName(char *p) +{ + char sTmp[MAXPATHLEN]; + char *fp; + + sLongFileName[0] = '\0'; + + if (GetFileAttributes(p) == -1) { + fprintf(stderr, "%s: non existent file %s\n", argv0, p); + return NULL; + } + if (GetFullPathName(p, sizeof(sTmp), sTmp, &fp) == 0) { + fprintf(stderr, "%s: failed to get full path name for %s (Error %d)\n", argv0, p, GetLastError()); + return NULL; + } + if (GetLongPathName(sTmp, sLongFileName, sizeof(sLongFileName)) == 0) { + fprintf(stderr, "%s: failed to get long path name for %s (Error %d)\n", argv0, sTmp, GetLastError()); + return NULL; + } + return sLongFileName; +} + +int pdfopen() +{ + if (sLongFileName[0] == '\0') { + fprintf(stderr, "%s: mandatory `--file' argument not found.\n", argv0); + return EXIT_FAILURE; + } + + OpenConversation(EVAL_TOPIC); + + ExecuteCommand("[DocOpen(\"%s\")]", sLongFileName); + ExecuteCommand("[FileOpen(\"%s\")]", sLongFileName); + + if (nPage > 0) { + ExecuteCommand("[DocGoTo(\"%s\", %d)]", sLongFileName, nPage); + } + + if (sGoto != NULL) { + ExecuteCommand("[DocGoToNameDest(\"%s\", %s)]", sLongFileName, sGoto); + } + + CloseConversation(); +#if 0 + /* Problem : it seems that these calls can put AR into a strange state. + It would have been simpler if Adobe had simply iconified their application. */ + if (stricmp(argv0, "pdfclose") == 0) { + sprintf(buf, "[AppHide()]"); + } + else if (stricmp(argv0, "pdfopen") == 0) { + sprintf(buf, "[AppShow()]"); + } + bRetVal = DdeClientTransaction((unsigned char *)buf, (DWORD)strlen(buf), + (HCONV)hConversation, NULL, + (UINT)CF_TEXT, (UINT)XTYP_EXECUTE, (DWORD)1000, &dwResult); +#endif + + return EXIT_SUCCESS; +} + +int pdfclose() +{ + OpenConversation(EVAL_TOPIC); + + if (bAll) { + ExecuteCommand("[CloseAllDocs()]"); + } + else if (sLongFileName[0] != '\0') { + ExecuteCommand("[DocClose(\"%s\")]", sLongFileName); + } + +#if 0 + fprintf(stderr, "cmd : %s\n", buf); +#endif + + CloseConversation(); + + return EXIT_SUCCESS; +} + +int pdfserver() +{ + char line[1024]; + + OpenConversation(EVAL_TOPIC); + + fprintf(stdout, "Type Ctrl-Z to quit.\n"); + + while (fgets(line, sizeof(line), stdin)) { +#define WHITE_DELIM " \t\n" + char *p = strtok(line, WHITE_DELIM); + if (stricmp(p, "open") == 0) { + p = strtok(NULL, WHITE_DELIM); + if (CheckFileName(p) == NULL) goto next; + + ExecuteCommand("[DocOpen(\"%s\")]", sLongFileName); + } + else if (stricmp(p, "close") == 0) { + p = strtok(NULL, WHITE_DELIM); + if (CheckFileName(p) == NULL) goto next; + ExecuteCommand("[DocClose(\"%s\")]", sLongFileName); + } + else if (stricmp(p, "closeall") == 0) { + ExecuteCommand("[CloseAllDocs()]"); + } + else if (stricmp(p, "goto") == 0) { + p = strtok(NULL, WHITE_DELIM); + if (p == NULL) goto next; + if (CheckFileName(p) == NULL) goto next; + p = strtok(NULL, WHITE_DELIM); + if (p == NULL) goto next; + nPage = atoi(p) - 1; + ExecuteCommand("[DocGoTo(\"%s\", %d)]", sLongFileName, nPage); + } + else if (stricmp(p, "gotoname") == 0) { + p = strtok(NULL, WHITE_DELIM); + if (p == NULL) goto next; + if (CheckFileName(p) == NULL) goto next; + p = strtok(NULL, WHITE_DELIM); + if (p == NULL) goto next; + sGoto = p; + ExecuteCommand("[DocGoToNameDest(\"%s\", %s)]", sLongFileName, sGoto); + } + else if (stricmp(p, "show") == 0) { + ExecuteCommand("[AppShow()]"); + + } + else if (stricmp(p, "hide") == 0) { + ExecuteCommand("[AppHide()]"); + + } + else if (stricmp(p, "exit") == 0) { + ExecuteCommand("[AppExit()]"); + goto exit; + } + else if (stricmp(p, "list") == 0) { + fprintf(stdout, "open <file> open the file\n"); + fprintf(stdout, "close <file> close the file\n"); + fprintf(stdout, "closeall close all files\n"); + fprintf(stdout, "goto <file> <page> goto the given <page> in <file>\n"); + fprintf(stdout, "gotoname <file> <dest> goto the <dest> named destination in <file>\n"); + fprintf(stdout, "show show acroview\n"); + fprintf(stdout, "hide hide acroview\n"); + fprintf(stdout, "exit exit acroview and %s\n", argv0); + } + next: ; + } + +#if 0 + fprintf(stderr, "cmd : %s\n", buf); +#endif +exit: + CloseConversation(); + + return EXIT_SUCCESS; +} + +int main (int argc, char *argv[]) +{ + BOOL bRet = FALSE; + char *p; + int argv0len = 0; + int g; /* getopt return code */ + int option_index; + + /* Make argv0 to point to the raw base name */ + argv0 = argv[0]; + if ((p = strrchr(argv0, '/')) + || (p = strrchr(argv0, '\\'))) { + argv0 = _strdup(p+1); + } + if ((argv0len = strlen(argv0)) > 4 + && _strnicmp(argv0 + argv0len - 4, ".exe", 4) == 0) + argv0[argv0len - 4] = '\0'; + + for(;;) { + g = getopt_long_only (argc, argv, "", long_options, &option_index); + + if (g == EOF) + break; + + if (g == '?') { + usage(); /* Unknown option. */ + exit(EXIT_FAILURE); + } + + /* assert (g == 0); */ /* We have no short option names. */ + /* + FIXME : try 'mktexpk --mfmode --bdpi 600 ...' + */ + + if (ARGUMENT_IS ("debug")) { +#if 0 + if (! isalnum(*optarg)) { + fprintf(stderr, "%s: warning, `%s' bad debug argument.\n", argv0, optarg); + } + iDebug |= atoi (optarg); +#endif + iDebug = TRUE; + } + else if (ARGUMENT_IS ("help")) { + usage(); + exit(EXIT_SUCCESS); + } + else if (ARGUMENT_IS ("version")) { + fprintf(stderr, "%s of %s.\n", argv0, pdfdde_version_string); + exit(EXIT_SUCCESS); + } + else if (PROGRAM_IS("pdfopen")) { + if (ARGUMENT_IS("file")) { + CheckFileName(optarg); + } + else if (ARGUMENT_IS("page")) { + nPage = atoi(optarg) - 1; + } + else if (ARGUMENT_IS("goto")) { + sGoto = optarg; + } + } + else if (PROGRAM_IS("pdfclose")) { + if (ARGUMENT_IS("file")) { + CheckFileName(optarg); + } + else if (ARGUMENT_IS("all")) { + bAll = TRUE; + } + } + } + +#if 0 + /* shifting options from argv[] list */ + for (i = 0; i < argc - optind; i++) + argv[i] = argv[optind+i]; + argv[i] = NULL; + + argc = i; +#endif + + if (PROGRAM_IS("pdfopen")) { + bRet = pdfopen(); + } + else if (PROGRAM_IS("pdfclose")) { + bRet = pdfclose(); + } + else if (PROGRAM_IS("pdfdde")) { + bRet = pdfserver(); + } + else { + fprintf(stderr, "This program has been incorrectly copied to the name %s.\n", argv[0]); + bRet = EXIT_FAILURE; + } + return bRet; +} + + + + + + diff --git a/Build/source/texk/contrib/regex/regex.c b/Build/source/texk/contrib/regex/regex.c new file mode 100644 index 00000000000..8169880d7e4 --- /dev/null +++ b/Build/source/texk/contrib/regex/regex.c @@ -0,0 +1,4948 @@ +/* Extended regular expression matching and search library, + version 0.12. + (Implements POSIX draft P10003.2/D11.2, except for + internationalization features.) + + Copyright (C) 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (REGEX_MALLOC) + #pragma alloca +#endif + +#define _GNU_SOURCE + +/* We need this for `regex.h', and perhaps for the Emacs include files. */ +#include <sys/types.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* The `emacs' switch turns on certain matching commands + that make sense only in Emacs. */ +#ifdef emacs + +#include "lisp.h" +#include "buffer.h" +#include "syntax.h" + +/* Emacs uses `NULL' as a predicate. */ +#undef NULL + +#else /* not emacs */ + +/* We used to test for `BSTRING' here, but only GCC and Emacs define + `BSTRING', as far as I know, and neither of them use this code. */ +#if HAVE_STRING_H || STDC_HEADERS +#include <string.h> +#ifndef bcmp +#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) +#endif +#ifndef bcopy +#define bcopy(s, d, n) memcpy ((d), (s), (n)) +#endif +#ifndef bzero +#define bzero(s, n) memset ((s), 0, (n)) +#endif +#else +#include <strings.h> +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#else +char *malloc (); +char *realloc (); +#endif + + +/* Define the syntax stuff for \<, \>, etc. */ + +/* This must be nonzero for the wordchar and notwordchar pattern + commands in re_match_2. */ +#ifndef Sword +#define Sword 1 +#endif + +#ifdef SYNTAX_TABLE + +extern char *re_syntax_table; + +#else /* not SYNTAX_TABLE */ + +/* How many characters in the character set. */ +#define CHAR_SET_SIZE 256 + +static char re_syntax_table[CHAR_SET_SIZE]; + +static void +init_syntax_once () +{ + register int c; + static int done = 0; + + if (done) + return; + + bzero (re_syntax_table, sizeof re_syntax_table); + + for (c = 'a'; c <= 'z'; c++) + re_syntax_table[c] = Sword; + + for (c = 'A'; c <= 'Z'; c++) + re_syntax_table[c] = Sword; + + for (c = '0'; c <= '9'; c++) + re_syntax_table[c] = Sword; + + re_syntax_table['_'] = Sword; + + done = 1; +} + +#endif /* not SYNTAX_TABLE */ + +#define SYNTAX(c) re_syntax_table[c] + +#endif /* not emacs */ + +/* Get the interface, including the syntax bits. */ +#include "regex.h" + +/* isalpha etc. are used for the character classes. */ +#include <ctype.h> + +#ifndef isascii +#define isascii(c) 1 +#endif + +#ifdef isblank +#define ISBLANK(c) (isascii (c) && isblank (c)) +#else +#define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +#define ISGRAPH(c) (isascii (c) && isgraph (c)) +#else +#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (isascii (c) && isprint (c)) +#define ISDIGIT(c) (isascii (c) && isdigit (c)) +#define ISALNUM(c) (isascii (c) && isalnum (c)) +#define ISALPHA(c) (isascii (c) && isalpha (c)) +#define ISCNTRL(c) (isascii (c) && iscntrl (c)) +#define ISLOWER(c) (isascii (c) && islower (c)) +#define ISPUNCT(c) (isascii (c) && ispunct (c)) +#define ISSPACE(c) (isascii (c) && isspace (c)) +#define ISUPPER(c) (isascii (c) && isupper (c)) +#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) + +#ifndef NULL +#define NULL 0 +#endif + +/* We remove any previous definition of `SIGN_EXTEND_CHAR', + since ours (we hope) works properly with all combinations of + machines, compilers, `char' and `unsigned char' argument types. + (Per Bothner suggested the basic approach.) */ +#undef SIGN_EXTEND_CHAR +#if __STDC__ +#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) +#else /* not __STDC__ */ +/* As in Harbison and Steele. */ +#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) +#endif + +/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we + use `alloca' instead of `malloc'. This is because using malloc in + re_search* or re_match* could cause memory leaks when C-g is used in + Emacs; also, malloc is slower and causes storage fragmentation. On + the other hand, malloc is more portable, and easier to debug. + + Because we sometimes use alloca, some routines have to be macros, + not functions -- `alloca'-allocated space disappears at the end of the + function it is called in. */ + +#ifdef REGEX_MALLOC + +#define REGEX_ALLOCATE malloc +#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) + +#else /* not REGEX_MALLOC */ + +/* Emacs already defines alloca, sometimes. */ +#ifndef alloca + +/* Make alloca work the best possible way. */ +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include <alloca.h> +#else /* not __GNUC__ or HAVE_ALLOCA_H */ +#ifndef _AIX /* Already did AIX, up at the top. */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +#endif /* not alloca */ + +#define REGEX_ALLOCATE alloca + +/* Assumes a `char *destination' variable. */ +#define REGEX_REALLOCATE(source, osize, nsize) \ + (destination = (char *) alloca (nsize), \ + bcopy (source, destination, osize), \ + destination) + +#endif /* not REGEX_MALLOC */ + + +/* True if `size1' is non-NULL and PTR is pointing anywhere inside + `string1' or just past its end. This works if PTR is NULL, which is + a good thing. */ +#define FIRST_STRING_P(ptr) \ + (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) + +/* (Re)Allocate N items of type T using malloc, or fail. */ +#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) +#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) +#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) + +#define BYTEWIDTH 8 /* In bits. */ + +#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +typedef char boolean; +#define false 0 +#define true 1 + +/* These are the command codes that appear in compiled regular + expressions. Some opcodes are followed by argument bytes. A + command code can specify any interpretation whatsoever for its + arguments. Zero bytes may appear in the compiled regular expression. + + The value of `exactn' is needed in search.c (search_buffer) in Emacs. + So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of + `exactn' we use here must also be 1. */ + +typedef enum +{ + no_op = 0, + + /* Followed by one byte giving n, then by n literal bytes. */ + exactn = 1, + + /* Matches any (more or less) character. */ + anychar, + + /* Matches any one char belonging to specified set. First + following byte is number of bitmap bytes. Then come bytes + for a bitmap saying which chars are in. Bits in each byte + are ordered low-bit-first. A character is in the set if its + bit is 1. A character too large to have a bit in the map is + automatically not in the set. */ + charset, + + /* Same parameters as charset, but match any character that is + not one of those specified. */ + charset_not, + + /* Start remembering the text that is matched, for storing in a + register. Followed by one byte with the register number, in + the range 0 to one less than the pattern buffer's re_nsub + field. Then followed by one byte with the number of groups + inner to this one. (This last has to be part of the + start_memory only because we need it in the on_failure_jump + of re_match_2.) */ + start_memory, + + /* Stop remembering the text that is matched and store it in a + memory register. Followed by one byte with the register + number, in the range 0 to one less than `re_nsub' in the + pattern buffer, and one byte with the number of inner groups, + just like `start_memory'. (We need the number of inner + groups here because we don't have any easy way of finding the + corresponding start_memory when we're at a stop_memory.) */ + stop_memory, + + /* Match a duplicate of something remembered. Followed by one + byte containing the register number. */ + duplicate, + + /* Fail unless at beginning of line. */ + begline, + + /* Fail unless at end of line. */ + endline, + + /* Succeeds if at beginning of buffer (if emacs) or at beginning + of string to be matched (if not). */ + begbuf, + + /* Analogously, for end of buffer/string. */ + endbuf, + + /* Followed by two byte relative address to which to jump. */ + jump, + + /* Same as jump, but marks the end of an alternative. */ + jump_past_alt, + + /* Followed by two-byte relative address of place to resume at + in case of failure. */ + on_failure_jump, + + /* Like on_failure_jump, but pushes a placeholder instead of the + current string position when executed. */ + on_failure_keep_string_jump, + + /* Throw away latest failure point and then jump to following + two-byte relative address. */ + pop_failure_jump, + + /* Change to pop_failure_jump if know won't have to backtrack to + match; otherwise change to jump. This is used to jump + back to the beginning of a repeat. If what follows this jump + clearly won't match what the repeat does, such that we can be + sure that there is no use backtracking out of repetitions + already matched, then we change it to a pop_failure_jump. + Followed by two-byte address. */ + maybe_pop_jump, + + /* Jump to following two-byte address, and push a dummy failure + point. This failure point will be thrown away if an attempt + is made to use it for a failure. A `+' construct makes this + before the first repeat. Also used as an intermediary kind + of jump when compiling an alternative. */ + dummy_failure_jump, + + /* Push a dummy failure point and continue. Used at the end of + alternatives. */ + push_dummy_failure, + + /* Followed by two-byte relative address and two-byte number n. + After matching N times, jump to the address upon failure. */ + succeed_n, + + /* Followed by two-byte relative address, and two-byte number n. + Jump to the address N times, then fail. */ + jump_n, + + /* Set the following two-byte relative address to the + subsequent two-byte number. The address *includes* the two + bytes of number. */ + set_number_at, + + wordchar, /* Matches any word-constituent character. */ + notwordchar, /* Matches any char that is not a word-constituent. */ + + wordbeg, /* Succeeds if at word beginning. */ + wordend, /* Succeeds if at word end. */ + + wordbound, /* Succeeds if at a word boundary. */ + notwordbound /* Succeeds if not at a word boundary. */ + +#ifdef emacs + ,before_dot, /* Succeeds if before point. */ + at_dot, /* Succeeds if at point. */ + after_dot, /* Succeeds if after point. */ + + /* Matches any character whose syntax is specified. Followed by + a byte which contains a syntax code, e.g., Sword. */ + syntaxspec, + + /* Matches any character whose syntax is not that specified. */ + notsyntaxspec +#endif /* emacs */ +} re_opcode_t; + +/* Common operations on the compiled pattern. */ + +/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ + +#define STORE_NUMBER(destination, number) \ + do { \ + (destination)[0] = (number) & 0377; \ + (destination)[1] = (number) >> 8; \ + } while (0) + +/* Same as STORE_NUMBER, except increment DESTINATION to + the byte after where the number is stored. Therefore, DESTINATION + must be an lvalue. */ + +#define STORE_NUMBER_AND_INCR(destination, number) \ + do { \ + STORE_NUMBER (destination, number); \ + (destination) += 2; \ + } while (0) + +/* Put into DESTINATION a number stored in two contiguous bytes starting + at SOURCE. */ + +#define EXTRACT_NUMBER(destination, source) \ + do { \ + (destination) = *(source) & 0377; \ + (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ + } while (0) + +#ifdef DEBUG +static void +extract_number (dest, source) + int *dest; + unsigned char *source; +{ + int temp = SIGN_EXTEND_CHAR (*(source + 1)); + *dest = *source & 0377; + *dest += temp << 8; +} + +#ifndef EXTRACT_MACROS /* To debug the macros. */ +#undef EXTRACT_NUMBER +#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. + SOURCE must be an lvalue. */ + +#define EXTRACT_NUMBER_AND_INCR(destination, source) \ + do { \ + EXTRACT_NUMBER (destination, source); \ + (source) += 2; \ + } while (0) + +#ifdef DEBUG +static void +extract_number_and_incr (destination, source) + int *destination; + unsigned char **source; +{ + extract_number (destination, *source); + *source += 2; +} + +#ifndef EXTRACT_MACROS +#undef EXTRACT_NUMBER_AND_INCR +#define EXTRACT_NUMBER_AND_INCR(dest, src) \ + extract_number_and_incr (&dest, &src) +#endif /* not EXTRACT_MACROS */ + +#endif /* DEBUG */ + +/* If DEBUG is defined, Regex prints many voluminous messages about what + it is doing (if the variable `debug' is nonzero). If linked with the + main program in `iregex.c', you can enter patterns and strings + interactively. And if linked with the main program in `main.c' and + the other test files, you can run the already-written tests. */ + +#ifdef DEBUG + +/* We use standard I/O for debugging. */ +#include <stdio.h> + +/* It is useful to test things that ``must'' be true when debugging. */ +#include <assert.h> + +static int debug = 0; + +#define DEBUG_STATEMENT(e) e +#define DEBUG_PRINT1(x) if (debug) printf (x) +#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ + if (debug) print_partial_compiled_pattern (s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ + if (debug) print_double_string (w, s1, sz1, s2, sz2) + + +extern void printchar (); + +/* Print the fastmap in human-readable form. */ + +void +print_fastmap (fastmap) + char *fastmap; +{ + unsigned was_a_range = 0; + unsigned i = 0; + + while (i < (1 << BYTEWIDTH)) + { + if (fastmap[i++]) + { + was_a_range = 0; + printchar (i - 1); + while (i < (1 << BYTEWIDTH) && fastmap[i]) + { + was_a_range = 1; + i++; + } + if (was_a_range) + { + printf ("-"); + printchar (i - 1); + } + } + } + putchar ('\n'); +} + + +/* Print a compiled pattern string in human-readable form, starting at + the START pointer into it and ending just before the pointer END. */ + +void +print_partial_compiled_pattern (start, end) + unsigned char *start; + unsigned char *end; +{ + int mcnt, mcnt2; + unsigned char *p = start; + unsigned char *pend = end; + + if (start == NULL) + { + printf ("(null)\n"); + return; + } + + /* Loop over pattern commands. */ + while (p < pend) + { + switch ((re_opcode_t) *p++) + { + case no_op: + printf ("/no_op"); + break; + + case exactn: + mcnt = *p++; + printf ("/exactn/%d", mcnt); + do + { + putchar ('/'); + printchar (*p++); + } + while (--mcnt); + break; + + case start_memory: + mcnt = *p++; + printf ("/start_memory/%d/%d", mcnt, *p++); + break; + + case stop_memory: + mcnt = *p++; + printf ("/stop_memory/%d/%d", mcnt, *p++); + break; + + case duplicate: + printf ("/duplicate/%d", *p++); + break; + + case anychar: + printf ("/anychar"); + break; + + case charset: + case charset_not: + { + register int c; + + printf ("/charset%s", + (re_opcode_t) *(p - 1) == charset_not ? "_not" : ""); + + assert (p + *p < pend); + + for (c = 0; c < *p; c++) + { + unsigned bit; + unsigned char map_byte = p[1 + c]; + + putchar ('/'); + + for (bit = 0; bit < BYTEWIDTH; bit++) + if (map_byte & (1 << bit)) + printchar (c * BYTEWIDTH + bit); + } + p += 1 + *p; + break; + } + + case begline: + printf ("/begline"); + break; + + case endline: + printf ("/endline"); + break; + + case on_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_jump/0/%d", mcnt); + break; + + case on_failure_keep_string_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/on_failure_keep_string_jump/0/%d", mcnt); + break; + + case dummy_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/dummy_failure_jump/0/%d", mcnt); + break; + + case push_dummy_failure: + printf ("/push_dummy_failure"); + break; + + case maybe_pop_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/maybe_pop_jump/0/%d", mcnt); + break; + + case pop_failure_jump: + extract_number_and_incr (&mcnt, &p); + printf ("/pop_failure_jump/0/%d", mcnt); + break; + + case jump_past_alt: + extract_number_and_incr (&mcnt, &p); + printf ("/jump_past_alt/0/%d", mcnt); + break; + + case jump: + extract_number_and_incr (&mcnt, &p); + printf ("/jump/0/%d", mcnt); + break; + + case succeed_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case jump_n: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2); + break; + + case set_number_at: + extract_number_and_incr (&mcnt, &p); + extract_number_and_incr (&mcnt2, &p); + printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2); + break; + + case wordbound: + printf ("/wordbound"); + break; + + case notwordbound: + printf ("/notwordbound"); + break; + + case wordbeg: + printf ("/wordbeg"); + break; + + case wordend: + printf ("/wordend"); + +#ifdef emacs + case before_dot: + printf ("/before_dot"); + break; + + case at_dot: + printf ("/at_dot"); + break; + + case after_dot: + printf ("/after_dot"); + break; + + case syntaxspec: + printf ("/syntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; + + case notsyntaxspec: + printf ("/notsyntaxspec"); + mcnt = *p++; + printf ("/%d", mcnt); + break; +#endif /* emacs */ + + case wordchar: + printf ("/wordchar"); + break; + + case notwordchar: + printf ("/notwordchar"); + break; + + case begbuf: + printf ("/begbuf"); + break; + + case endbuf: + printf ("/endbuf"); + break; + + default: + printf ("?%d", *(p-1)); + } + } + printf ("/\n"); +} + + +void +print_compiled_pattern (bufp) + struct re_pattern_buffer *bufp; +{ + unsigned char *buffer = bufp->buffer; + + print_partial_compiled_pattern (buffer, buffer + bufp->used); + printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); + + if (bufp->fastmap_accurate && bufp->fastmap) + { + printf ("fastmap: "); + print_fastmap (bufp->fastmap); + } + + printf ("re_nsub: %d\t", bufp->re_nsub); + printf ("regs_alloc: %d\t", bufp->regs_allocated); + printf ("can_be_null: %d\t", bufp->can_be_null); + printf ("newline_anchor: %d\n", bufp->newline_anchor); + printf ("no_sub: %d\t", bufp->no_sub); + printf ("not_bol: %d\t", bufp->not_bol); + printf ("not_eol: %d\t", bufp->not_eol); + printf ("syntax: %d\n", bufp->syntax); + /* Perhaps we should print the translate table? */ +} + + +void +print_double_string (where, string1, size1, string2, size2) + const char *where; + const char *string1; + const char *string2; + int size1; + int size2; +{ + unsigned this_char; + + if (where == NULL) + printf ("(null)"); + else + { + if (FIRST_STRING_P (where)) + { + for (this_char = where - string1; this_char < size1; this_char++) + printchar (string1[this_char]); + + where = string2; + } + + for (this_char = where - string2; this_char < size2; this_char++) + printchar (string2[this_char]); + } +} + +#else /* not DEBUG */ + +#undef assert +#define assert(e) + +#define DEBUG_STATEMENT(e) +#define DEBUG_PRINT1(x) +#define DEBUG_PRINT2(x1, x2) +#define DEBUG_PRINT3(x1, x2, x3) +#define DEBUG_PRINT4(x1, x2, x3, x4) +#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) +#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) + +#endif /* not DEBUG */ + +/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax (syntax) + reg_syntax_t syntax; +{ + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. */ + +static const char *re_error_msg[] = + { NULL, /* REG_NOERROR */ + "No match", /* REG_NOMATCH */ + "Invalid regular expression", /* REG_BADPAT */ + "Invalid collation character", /* REG_ECOLLATE */ + "Invalid character class name", /* REG_ECTYPE */ + "Trailing backslash", /* REG_EESCAPE */ + "Invalid back reference", /* REG_ESUBREG */ + "Unmatched [ or [^", /* REG_EBRACK */ + "Unmatched ( or \\(", /* REG_EPAREN */ + "Unmatched \\{", /* REG_EBRACE */ + "Invalid content of \\{\\}", /* REG_BADBR */ + "Invalid range end", /* REG_ERANGE */ + "Memory exhausted", /* REG_ESPACE */ + "Invalid preceding regular expression", /* REG_BADRPT */ + "Premature end of regular expression", /* REG_EEND */ + "Regular expression too big", /* REG_ESIZE */ + "Unmatched ) or \\)", /* REG_ERPAREN */ + }; + +/* Subroutine declarations and macros for regex_compile. */ + +static void store_op1 (), store_op2 (); +static void insert_op1 (), insert_op2 (); +static boolean at_begline_loc_p (), at_endline_loc_p (); +static boolean group_in_compile_stack (); +static reg_errcode_t compile_range (); + +/* Fetch the next character in the uncompiled pattern---translating it + if necessary. Also cast from a signed character in the constant + string passed to us by the user to an unsigned char that we can use + as an array index (in, e.g., `translate'). */ +#define PATFETCH(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + if (translate) c = translate[c]; \ + } while (0) + +/* Fetch the next character in the uncompiled pattern, with no + translation. */ +#define PATFETCH_RAW(c) \ + do {if (p == pend) return REG_EEND; \ + c = (unsigned char) *p++; \ + } while (0) + +/* Go backwards one character in the pattern. */ +#define PATUNFETCH p-- + + +/* If `translate' is non-null, return translate[D], else just D. We + cast the subscript to translate because some data is declared as + `char *', to avoid warnings when a string constant is passed. But + when we use a character as a subscript we must make it unsigned. */ +#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) + + +/* Macros for outputting the compiled pattern into `buffer'. */ + +/* If the buffer isn't allocated when it comes in, use this. */ +#define INIT_BUF_SIZE 32 + +/* Make sure we have at least N more bytes of space in buffer. */ +#define GET_BUFFER_SPACE(n) \ + while (b - bufp->buffer + (n) > bufp->allocated) \ + EXTEND_BUFFER () + +/* Make sure we have one more byte of buffer space and then add C to it. */ +#define BUF_PUSH(c) \ + do { \ + GET_BUFFER_SPACE (1); \ + *b++ = (unsigned char) (c); \ + } while (0) + + +/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ +#define BUF_PUSH_2(c1, c2) \ + do { \ + GET_BUFFER_SPACE (2); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + } while (0) + + +/* As with BUF_PUSH_2, except for three bytes. */ +#define BUF_PUSH_3(c1, c2, c3) \ + do { \ + GET_BUFFER_SPACE (3); \ + *b++ = (unsigned char) (c1); \ + *b++ = (unsigned char) (c2); \ + *b++ = (unsigned char) (c3); \ + } while (0) + + +/* Store a jump with opcode OP at LOC to location TO. We store a + relative address offset by the three bytes the jump itself occupies. */ +#define STORE_JUMP(op, loc, to) \ + store_op1 (op, loc, (to) - (loc) - 3) + +/* Likewise, for a two-argument jump. */ +#define STORE_JUMP2(op, loc, to, arg) \ + store_op2 (op, loc, (to) - (loc) - 3, arg) + +/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP(op, loc, to) \ + insert_op1 (op, loc, (to) - (loc) - 3, b) + +/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ +#define INSERT_JUMP2(op, loc, to, arg) \ + insert_op2 (op, loc, (to) - (loc) - 3, arg, b) + + +/* This is not an arbitrary limit: the arguments which represent offsets + into the pattern are two bytes long. So if 2^16 bytes turns out to + be too small, many things would have to change. */ +#define MAX_BUF_SIZE (1L << 16) + + +/* Extend the buffer by twice its current size via realloc and + reset the pointers that pointed into the old block to point to the + correct places in the new one. If extending the buffer results in it + being larger than MAX_BUF_SIZE, then flag memory exhausted. */ +#define EXTEND_BUFFER() \ + do { \ + unsigned char *old_buffer = bufp->buffer; \ + if (bufp->allocated == MAX_BUF_SIZE) \ + return REG_ESIZE; \ + bufp->allocated <<= 1; \ + if (bufp->allocated > MAX_BUF_SIZE) \ + bufp->allocated = MAX_BUF_SIZE; \ + bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ + if (bufp->buffer == NULL) \ + return REG_ESPACE; \ + /* If the buffer moved, move all the pointers into it. */ \ + if (old_buffer != bufp->buffer) \ + { \ + b = (b - old_buffer) + bufp->buffer; \ + begalt = (begalt - old_buffer) + bufp->buffer; \ + if (fixup_alt_jump) \ + fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ + if (laststart) \ + laststart = (laststart - old_buffer) + bufp->buffer; \ + if (pending_exact) \ + pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ + } \ + } while (0) + + +/* Since we have one byte reserved for the register number argument to + {start,stop}_memory, the maximum number of groups we can report + things about is what fits in that byte. */ +#define MAX_REGNUM 255 + +/* But patterns can have more than `MAX_REGNUM' registers. We just + ignore the excess. */ +typedef unsigned regnum_t; + + +/* Macros for the compile stack. */ + +/* Since offsets can go either forwards or backwards, this type needs to + be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ +typedef int pattern_offset_t; + +typedef struct +{ + pattern_offset_t begalt_offset; + pattern_offset_t fixup_alt_jump; + pattern_offset_t inner_group_offset; + pattern_offset_t laststart_offset; + regnum_t regnum; +} compile_stack_elt_t; + + +typedef struct +{ + compile_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} compile_stack_type; + + +#define INIT_COMPILE_STACK_SIZE 32 + +#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) +#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) + +/* The next available element. */ +#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) + + +/* Set the bit for character C in a list. */ +#define SET_LIST_BIT(c) \ + (b[((unsigned char) (c)) / BYTEWIDTH] \ + |= 1 << (((unsigned char) c) % BYTEWIDTH)) + + +/* Get the next unsigned number in the uncompiled pattern. */ +#define GET_UNSIGNED_NUMBER(num) \ + { if (p != pend) \ + { \ + PATFETCH (c); \ + while (ISDIGIT (c)) \ + { \ + if (num < 0) \ + num = 0; \ + num = num * 10 + c - '0'; \ + if (p == pend) \ + break; \ + PATFETCH (c); \ + } \ + } \ + } + +#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +#define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) + +/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. + Returns one of error codes defined in `regex.h', or zero for success. + + Assumes the `allocated' (and perhaps `buffer') and `translate' + fields are set in BUFP on entry. + + If it succeeds, results are put in BUFP (if it returns an error, the + contents of BUFP are undefined): + `buffer' is the compiled pattern; + `syntax' is set to SYNTAX; + `used' is set to the length of the compiled pattern; + `fastmap_accurate' is zero; + `re_nsub' is the number of subexpressions in PATTERN; + `not_bol' and `not_eol' are zero; + + The `fastmap' and `newline_anchor' fields are neither + examined nor set. */ + +static reg_errcode_t +regex_compile (pattern, size, syntax, bufp) + const char *pattern; + int size; + reg_syntax_t syntax; + struct re_pattern_buffer *bufp; +{ + /* We fetch characters from PATTERN here. Even though PATTERN is + `char *' (i.e., signed), we declare these variables as unsigned, so + they can be reliably used as array indices. */ + register unsigned char c, c1; + + /* A random tempory spot in PATTERN. */ + const char *p1; + + /* Points to the end of the buffer, where we should append. */ + register unsigned char *b; + + /* Keeps track of unclosed groups. */ + compile_stack_type compile_stack; + + /* Points to the current (ending) position in the pattern. */ + const char *p = pattern; + const char *pend = pattern + size; + + /* How to translate the characters in the pattern. */ + char *translate = bufp->translate; + + /* Address of the count-byte of the most recently inserted `exactn' + command. This makes it possible to tell if a new exact-match + character can be added to that command or if the character requires + a new `exactn' command. */ + unsigned char *pending_exact = 0; + + /* Address of start of the most recently finished expression. + This tells, e.g., postfix * where to find the start of its + operand. Reset at the beginning of groups and alternatives. */ + unsigned char *laststart = 0; + + /* Address of beginning of regexp, or inside of last group. */ + unsigned char *begalt; + + /* Place in the uncompiled pattern (i.e., the {) to + which to go back if the interval is invalid. */ + const char *beg_interval; + + /* Address of the place where a forward jump should go to the end of + the containing expression. Each alternative of an `or' -- except the + last -- ends with a forward jump of this sort. */ + unsigned char *fixup_alt_jump = 0; + + /* Counts open-groups as they are encountered. Remembered for the + matching close-group on the compile stack, so the same register + number is put in the stop_memory as the start_memory. */ + regnum_t regnum = 0; + +#ifdef DEBUG + DEBUG_PRINT1 ("\nCompiling pattern: "); + if (debug) + { + unsigned debug_count; + + for (debug_count = 0; debug_count < size; debug_count++) + printchar (pattern[debug_count]); + putchar ('\n'); + } +#endif /* DEBUG */ + + /* Initialize the compile stack. */ + compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); + if (compile_stack.stack == NULL) + return REG_ESPACE; + + compile_stack.size = INIT_COMPILE_STACK_SIZE; + compile_stack.avail = 0; + + /* Initialize the pattern buffer. */ + bufp->syntax = syntax; + bufp->fastmap_accurate = 0; + bufp->not_bol = bufp->not_eol = 0; + + /* Set `used' to zero, so that if we return an error, the pattern + printer (for debugging) will think there's no pattern. We reset it + at the end. */ + bufp->used = 0; + + /* Always count groups, whether or not bufp->no_sub is set. */ + bufp->re_nsub = 0; + +#if !defined (emacs) && !defined (SYNTAX_TABLE) + /* Initialize the syntax table. */ + init_syntax_once (); +#endif + + if (bufp->allocated == 0) + { + if (bufp->buffer) + { /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. */ + RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); + } + else + { /* Caller did not allocate a buffer. Do it for them. */ + bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); + } + if (!bufp->buffer) return REG_ESPACE; + + bufp->allocated = INIT_BUF_SIZE; + } + + begalt = b = bufp->buffer; + + /* Loop through the uncompiled pattern until we're at the end. */ + while (p != pend) + { + PATFETCH (c); + + switch (c) + { + case '^': + { + if ( /* If at start of pattern, it's an operator. */ + p == pattern + 1 + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's come before. */ + || at_begline_loc_p (pattern, p, syntax)) + BUF_PUSH (begline); + else + goto normal_char; + } + break; + + + case '$': + { + if ( /* If at end of pattern, it's an operator. */ + p == pend + /* If context independent, it's an operator. */ + || syntax & RE_CONTEXT_INDEP_ANCHORS + /* Otherwise, depends on what's next. */ + || at_endline_loc_p (p, pend, syntax)) + BUF_PUSH (endline); + else + goto normal_char; + } + break; + + + case '+': + case '?': + if ((syntax & RE_BK_PLUS_QM) + || (syntax & RE_LIMITED_OPS)) + goto normal_char; + handle_plus: + case '*': + /* If there is no previous pattern... */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (!(syntax & RE_CONTEXT_INDEP_OPS)) + goto normal_char; + } + + { + /* Are we optimizing this jump? */ + boolean keep_string_p = false; + + /* 1 means zero (many) matches is allowed. */ + char zero_times_ok = 0, many_times_ok = 0; + + /* If there is a sequence of repetition chars, collapse it + down to just one (the right one). We can't combine + interval operators with these because of, e.g., `a{2}*', + which should only match an even number of `a's. */ + + for (;;) + { + zero_times_ok |= c != '+'; + many_times_ok |= c != '?'; + + if (p == pend) + break; + + PATFETCH (c); + + if (c == '*' + || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) + ; + + else if (syntax & RE_BK_PLUS_QM && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + if (!(c1 == '+' || c1 == '?')) + { + PATUNFETCH; + PATUNFETCH; + break; + } + + c = c1; + } + else + { + PATUNFETCH; + break; + } + + /* If we get here, we found another repeat character. */ + } + + /* Star, etc. applied to an empty pattern is equivalent + to an empty pattern. */ + if (!laststart) + break; + + /* Now we know whether or not zero matches is allowed + and also whether or not two or more matches is allowed. */ + if (many_times_ok) + { /* More than one repetition is allowed, so put in at the + end a backward relative jump from `b' to before the next + jump we're going to put in below (which jumps from + laststart to after this jump). + + But if we are at the `*' in the exact sequence `.*\n', + insert an unconditional jump backwards to the ., + instead of the beginning of the loop. This way we only + push a failure point once, instead of every time + through the loop. */ + assert (p - 1 > pattern); + + /* Allocate the space for the jump. */ + GET_BUFFER_SPACE (3); + + /* We know we are not at the first character of the pattern, + because laststart was nonzero. And we've already + incremented `p', by the way, to be the character after + the `*'. Do we have to do something analogous here + for null bytes, because of RE_DOT_NOT_NULL? */ + if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') + && zero_times_ok + && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') + && !(syntax & RE_DOT_NEWLINE)) + { /* We have .*\n. */ + STORE_JUMP (jump, b, laststart); + keep_string_p = true; + } + else + /* Anything else. */ + STORE_JUMP (maybe_pop_jump, b, laststart - 3); + + /* We've added more stuff to the buffer. */ + b += 3; + } + + /* On failure, jump from laststart to b + 3, which will be the + end of the buffer after this jump is inserted. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump + : on_failure_jump, + laststart, b + 3); + pending_exact = 0; + b += 3; + + if (!zero_times_ok) + { + /* At least one repetition is required, so insert a + `dummy_failure_jump' before the initial + `on_failure_jump' instruction of the loop. This + effects a skip over that instruction the first time + we hit that loop. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); + b += 3; + } + } + break; + + + case '.': + laststart = b; + BUF_PUSH (anychar); + break; + + + case '[': + { + boolean had_char_class = false; + + if (p == pend) return REG_EBRACK; + + /* Ensure that we have enough space to push a charset: the + opcode, the length count, and the bitset; 34 bytes in all. */ + GET_BUFFER_SPACE (34); + + laststart = b; + + /* We test `*p == '^' twice, instead of using an if + statement, so we only need one BUF_PUSH. */ + BUF_PUSH (*p == '^' ? charset_not : charset); + if (*p == '^') + p++; + + /* Remember the first position in the bracket expression. */ + p1 = p; + + /* Push the number of bytes in the bitmap. */ + BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); + + /* Clear the whole map. */ + bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); + + /* charset_not matches newline according to a syntax bit. */ + if ((re_opcode_t) b[-2] == charset_not + && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) + SET_LIST_BIT ('\n'); + + /* Read in characters and ranges, setting map bits. */ + for (;;) + { + if (p == pend) return REG_EBRACK; + + PATFETCH (c); + + /* \ might escape characters inside [...] and [^...]. */ + if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') + { + if (p == pend) return REG_EESCAPE; + + PATFETCH (c1); + SET_LIST_BIT (c1); + continue; + } + + /* Could be the end of the bracket expression. If it's + not (i.e., when the bracket expression is `[]' so + far), the ']' character bit gets set way below. */ + if (c == ']' && p != p1 + 1) + break; + + /* Look ahead to see if it's a range when the last thing + was a character class. */ + if (had_char_class && c == '-' && *p != ']') + return REG_ERANGE; + + /* Look ahead to see if it's a range when the last thing + was a character: if this is a hyphen not at the + beginning or the end of a list, then it's the range + operator. */ + if (c == '-' + && !(p - 2 >= pattern && p[-2] == '[') + && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') + && *p != ']') + { + reg_errcode_t ret + = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + else if (p[0] == '-' && p[1] != ']') + { /* This handles ranges made up of characters only. */ + reg_errcode_t ret; + + /* Move past the `-'. */ + PATFETCH (c1); + + ret = compile_range (&p, pend, translate, syntax, b); + if (ret != REG_NOERROR) return ret; + } + + /* See if we're at the beginning of a possible character + class. */ + + else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') + { /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + + PATFETCH (c); + c1 = 0; + + /* If pattern is `[[:'. */ + if (p == pend) return REG_EBRACK; + + for (;;) + { + PATFETCH (c); + if (c == ':' || c == ']' || p == pend + || c1 == CHAR_CLASS_MAX_LENGTH) + break; + str[c1++] = c; + } + str[c1] = '\0'; + + /* If isn't a word bracketed by `[:' and:`]': + undo the ending character, the letters, and leave + the leading `:' and `[' (but set bits for them). */ + if (c == ':' && *p == ']') + { + int ch; + boolean is_alnum = STREQ (str, "alnum"); + boolean is_alpha = STREQ (str, "alpha"); + boolean is_blank = STREQ (str, "blank"); + boolean is_cntrl = STREQ (str, "cntrl"); + boolean is_digit = STREQ (str, "digit"); + boolean is_graph = STREQ (str, "graph"); + boolean is_lower = STREQ (str, "lower"); + boolean is_print = STREQ (str, "print"); + boolean is_punct = STREQ (str, "punct"); + boolean is_space = STREQ (str, "space"); + boolean is_upper = STREQ (str, "upper"); + boolean is_xdigit = STREQ (str, "xdigit"); + + if (!IS_CHAR_CLASS (str)) return REG_ECTYPE; + + /* Throw away the ] at the end of the character + class. */ + PATFETCH (c); + + if (p == pend) return REG_EBRACK; + + for (ch = 0; ch < 1 << BYTEWIDTH; ch++) + { + if ( (is_alnum && ISALNUM (ch)) + || (is_alpha && ISALPHA (ch)) + || (is_blank && ISBLANK (ch)) + || (is_cntrl && ISCNTRL (ch)) + || (is_digit && ISDIGIT (ch)) + || (is_graph && ISGRAPH (ch)) + || (is_lower && ISLOWER (ch)) + || (is_print && ISPRINT (ch)) + || (is_punct && ISPUNCT (ch)) + || (is_space && ISSPACE (ch)) + || (is_upper && ISUPPER (ch)) + || (is_xdigit && ISXDIGIT (ch))) + SET_LIST_BIT (ch); + } + had_char_class = true; + } + else + { + c1++; + while (c1--) + PATUNFETCH; + SET_LIST_BIT ('['); + SET_LIST_BIT (':'); + had_char_class = false; + } + } + else + { + had_char_class = false; + SET_LIST_BIT (c); + } + } + + /* Discard any (non)matching list bytes that are all 0 at the + end of the map. Decrease the map-length byte too. */ + while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) + b[-1]--; + b += b[-1]; + } + break; + + + case '(': + if (syntax & RE_NO_BK_PARENS) + goto handle_open; + else + goto normal_char; + + + case ')': + if (syntax & RE_NO_BK_PARENS) + goto handle_close; + else + goto normal_char; + + + case '\n': + if (syntax & RE_NEWLINE_ALT) + goto handle_alt; + else + goto normal_char; + + + case '|': + if (syntax & RE_NO_BK_VBAR) + goto handle_alt; + else + goto normal_char; + + + case '{': + if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) + goto handle_interval; + else + goto normal_char; + + + case '\\': + if (p == pend) return REG_EESCAPE; + + /* Do not translate the character after the \, so that we can + distinguish, e.g., \B from \b, even if we normally would + translate, e.g., B to b. */ + PATFETCH_RAW (c); + + switch (c) + { + case '(': + if (syntax & RE_NO_BK_PARENS) + goto normal_backslash; + + handle_open: + bufp->re_nsub++; + regnum++; + + if (COMPILE_STACK_FULL) + { + RETALLOC (compile_stack.stack, compile_stack.size << 1, + compile_stack_elt_t); + if (compile_stack.stack == NULL) return REG_ESPACE; + + compile_stack.size <<= 1; + } + + /* These are the values to restore when we hit end of this + group. They are all relative offsets, so that if the + whole pattern moves because of realloc, they will still + be valid. */ + COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; + COMPILE_STACK_TOP.fixup_alt_jump + = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; + COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; + COMPILE_STACK_TOP.regnum = regnum; + + /* We will eventually replace the 0 with the number of + groups inner to this one. But do not push a + start_memory for groups beyond the last one we can + represent in the compiled pattern. */ + if (regnum <= MAX_REGNUM) + { + COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; + BUF_PUSH_3 (start_memory, regnum, 0); + } + + compile_stack.avail++; + + fixup_alt_jump = 0; + laststart = 0; + begalt = b; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + break; + + + case ')': + if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_backslash; + else + return REG_ERPAREN; + + handle_close: + if (fixup_alt_jump) + { /* Push a dummy failure point at the end of the + alternative for a possible future + `pop_failure_jump' to pop. See comments at + `push_dummy_failure' in `re_match_2'. */ + BUF_PUSH (push_dummy_failure); + + /* We allocated space for this jump when we assigned + to `fixup_alt_jump', in the `handle_alt' case below. */ + STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); + } + + /* See similar code for backslashed left paren above. */ + if (COMPILE_STACK_EMPTY) + if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) + goto normal_char; + else + return REG_ERPAREN; + + /* Since we just checked for an empty stack above, this + ``can't happen''. */ + assert (compile_stack.avail != 0); + { + /* We don't just want to restore into `regnum', because + later groups should continue to be numbered higher, + as in `(ab)c(de)' -- the second group is #2. */ + regnum_t this_group_regnum; + + compile_stack.avail--; + begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; + fixup_alt_jump + = COMPILE_STACK_TOP.fixup_alt_jump + ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 + : 0; + laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; + this_group_regnum = COMPILE_STACK_TOP.regnum; + /* If we've reached MAX_REGNUM groups, then this open + won't actually generate any code, so we'll have to + clear pending_exact explicitly. */ + pending_exact = 0; + + /* We're at the end of the group, so now we know how many + groups were inside this one. */ + if (this_group_regnum <= MAX_REGNUM) + { + unsigned char *inner_group_loc + = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; + + *inner_group_loc = regnum - this_group_regnum; + BUF_PUSH_3 (stop_memory, this_group_regnum, + regnum - this_group_regnum); + } + } + break; + + + case '|': /* `\|'. */ + if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) + goto normal_backslash; + handle_alt: + if (syntax & RE_LIMITED_OPS) + goto normal_char; + + /* Insert before the previous alternative a jump which + jumps to this alternative if the former fails. */ + GET_BUFFER_SPACE (3); + INSERT_JUMP (on_failure_jump, begalt, b + 6); + pending_exact = 0; + b += 3; + + /* The alternative before this one has a jump after it + which gets executed if it gets matched. Adjust that + jump so it will jump to this alternative's analogous + jump (put in below, which in turn will jump to the next + (if any) alternative's such jump, etc.). The last such + jump jumps to the correct final destination. A picture: + _____ _____ + | | | | + | v | v + a | b | c + + If we are at `b', then fixup_alt_jump right now points to a + three-byte space after `a'. We'll put in the jump, set + fixup_alt_jump to right after `b', and leave behind three + bytes which we'll fill in when we get to after `c'. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + /* Mark and leave space for a jump after this alternative, + to be filled in later either by next alternative or + when know we're at the end of a series of alternatives. */ + fixup_alt_jump = b; + GET_BUFFER_SPACE (3); + b += 3; + + laststart = 0; + begalt = b; + break; + + + case '{': + /* If \{ is a literal. */ + if (!(syntax & RE_INTERVALS) + /* If we're at `\{' and it's not the open-interval + operator. */ + || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + || (p - 2 == pattern && p == pend)) + goto normal_backslash; + + handle_interval: + { + /* If got here, then the syntax allows intervals. */ + + /* At least (most) this many matches must be made. */ + int lower_bound = -1, upper_bound = -1; + + beg_interval = p - 1; + + if (p == pend) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_EBRACE; + } + + GET_UNSIGNED_NUMBER (lower_bound); + + if (c == ',') + { + GET_UNSIGNED_NUMBER (upper_bound); + if (upper_bound < 0) upper_bound = RE_DUP_MAX; + } + else + /* Interval such as `{1}' => match exactly once. */ + upper_bound = lower_bound; + + if (lower_bound < 0 || upper_bound > RE_DUP_MAX + || lower_bound > upper_bound) + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (c != '\\') return REG_EBRACE; + + PATFETCH (c); + } + + if (c != '}') + { + if (syntax & RE_NO_BK_BRACES) + goto unfetch_interval; + else + return REG_BADBR; + } + + /* We just parsed a valid interval. */ + + /* If it's invalid to have no preceding re. */ + if (!laststart) + { + if (syntax & RE_CONTEXT_INVALID_OPS) + return REG_BADRPT; + else if (syntax & RE_CONTEXT_INDEP_OPS) + laststart = b; + else + goto unfetch_interval; + } + + /* If the upper bound is zero, don't want to succeed at + all; jump from `laststart' to `b + 3', which will be + the end of the buffer after we insert the jump. */ + if (upper_bound == 0) + { + GET_BUFFER_SPACE (3); + INSERT_JUMP (jump, laststart, b + 3); + b += 3; + } + + /* Otherwise, we have a nontrivial interval. When + we're all done, the pattern will look like: + set_number_at <jump count> <upper bound> + set_number_at <succeed_n count> <lower bound> + succeed_n <after jump addr> <succed_n count> + <body of loop> + jump_n <succeed_n addr> <jump count> + (The upper bound and `jump_n' are omitted if + `upper_bound' is 1, though.) */ + else + { /* If the upper bound is > 1, we need to insert + more at the end of the loop. */ + unsigned nbytes = 10 + (upper_bound > 1) * 10; + + GET_BUFFER_SPACE (nbytes); + + /* Initialize lower bound of the `succeed_n', even + though it will be set during matching by its + attendant `set_number_at' (inserted next), + because `re_compile_fastmap' needs to know. + Jump to the `jump_n' we might insert below. */ + INSERT_JUMP2 (succeed_n, laststart, + b + 5 + (upper_bound > 1) * 5, + lower_bound); + b += 5; + + /* Code to initialize the lower bound. Insert + before the `succeed_n'. The `5' is the last two + bytes of this `set_number_at', plus 3 bytes of + the following `succeed_n'. */ + insert_op2 (set_number_at, laststart, 5, lower_bound, b); + b += 5; + + if (upper_bound > 1) + { /* More than one repetition is allowed, so + append a backward jump to the `succeed_n' + that starts this interval. + + When we've reached this during matching, + we'll have matched the interval once, so + jump back only `upper_bound - 1' times. */ + STORE_JUMP2 (jump_n, b, laststart + 5, + upper_bound - 1); + b += 5; + + /* The location we want to set is the second + parameter of the `jump_n'; that is `b-2' as + an absolute address. `laststart' will be + the `set_number_at' we're about to insert; + `laststart+3' the number to set, the source + for the relative address. But we are + inserting into the middle of the pattern -- + so everything is getting moved up by 5. + Conclusion: (b - 2) - (laststart + 3) + 5, + i.e., b - laststart. + + We insert this at the beginning of the loop + so that if we fail during matching, we'll + reinitialize the bounds. */ + insert_op2 (set_number_at, laststart, b - laststart, + upper_bound - 1, b); + b += 5; + } + } + pending_exact = 0; + beg_interval = NULL; + } + break; + + unfetch_interval: + /* If an invalid interval, match the characters as literals. */ + assert (beg_interval); + p = beg_interval; + beg_interval = NULL; + + /* normal_char and normal_backslash need `c'. */ + PATFETCH (c); + + if (!(syntax & RE_NO_BK_BRACES)) + { + if (p > pattern && p[-1] == '\\') + goto normal_backslash; + } + goto normal_char; + +#ifdef emacs + /* There is no way to specify the before_dot and after_dot + operators. rms says this is ok. --karl */ + case '=': + BUF_PUSH (at_dot); + break; + + case 's': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); + break; + + case 'S': + laststart = b; + PATFETCH (c); + BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); + break; +#endif /* emacs */ + + + case 'w': + laststart = b; + BUF_PUSH (wordchar); + break; + + + case 'W': + laststart = b; + BUF_PUSH (notwordchar); + break; + + + case '<': + BUF_PUSH (wordbeg); + break; + + case '>': + BUF_PUSH (wordend); + break; + + case 'b': + BUF_PUSH (wordbound); + break; + + case 'B': + BUF_PUSH (notwordbound); + break; + + case '`': + BUF_PUSH (begbuf); + break; + + case '\'': + BUF_PUSH (endbuf); + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + if (syntax & RE_NO_BK_REFS) + goto normal_char; + + c1 = c - '0'; + + if (c1 > regnum) + return REG_ESUBREG; + + /* Can't back reference to a subexpression if inside of it. */ + if (group_in_compile_stack (compile_stack, c1)) + goto normal_char; + + laststart = b; + BUF_PUSH_2 (duplicate, c1); + break; + + + case '+': + case '?': + if (syntax & RE_BK_PLUS_QM) + goto handle_plus; + else + goto normal_backslash; + + default: + normal_backslash: + /* You might think it would be useful for \ to mean + not to translate; but if we don't translate it + it will never match anything. */ + c = TRANSLATE (c); + goto normal_char; + } + break; + + + default: + /* Expects the character in `c'. */ + normal_char: + /* If no exactn currently being built. */ + if (!pending_exact + + /* If last exactn not at current position. */ + || pending_exact + *pending_exact + 1 != b + + /* We have only one byte following the exactn for the count. */ + || *pending_exact == (1 << BYTEWIDTH) - 1 + + /* If followed by a repetition operator. */ + || *p == '*' || *p == '^' + || ((syntax & RE_BK_PLUS_QM) + ? *p == '\\' && (p[1] == '+' || p[1] == '?') + : (*p == '+' || *p == '?')) + || ((syntax & RE_INTERVALS) + && ((syntax & RE_NO_BK_BRACES) + ? *p == '{' + : (p[0] == '\\' && p[1] == '{')))) + { + /* Start building a new exactn. */ + + laststart = b; + + BUF_PUSH_2 (exactn, 0); + pending_exact = b - 1; + } + + BUF_PUSH (c); + (*pending_exact)++; + break; + } /* switch (c) */ + } /* while p != pend */ + + + /* Through the pattern now. */ + + if (fixup_alt_jump) + STORE_JUMP (jump_past_alt, fixup_alt_jump, b); + + if (!COMPILE_STACK_EMPTY) + return REG_EPAREN; + + free (compile_stack.stack); + + /* We have succeeded; set the length of the buffer. */ + bufp->used = b - bufp->buffer; + +#ifdef DEBUG + if (debug) + { + DEBUG_PRINT1 ("\nCompiled pattern: "); + print_compiled_pattern (bufp); + } +#endif /* DEBUG */ + + return REG_NOERROR; +} /* regex_compile */ + +/* Subroutines for `regex_compile'. */ + +/* Store OP at LOC followed by two-byte integer parameter ARG. */ + +static void +store_op1 (op, loc, arg) + re_opcode_t op; + unsigned char *loc; + int arg; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg); +} + + +/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +store_op2 (op, loc, arg1, arg2) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; +{ + *loc = (unsigned char) op; + STORE_NUMBER (loc + 1, arg1); + STORE_NUMBER (loc + 3, arg2); +} + + +/* Copy the bytes from LOC to END to open up three bytes of space at LOC + for OP followed by two-byte integer parameter ARG. */ + +static void +insert_op1 (op, loc, arg, end) + re_opcode_t op; + unsigned char *loc; + int arg; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 3; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op1 (op, loc, arg); +} + + +/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ + +static void +insert_op2 (op, loc, arg1, arg2, end) + re_opcode_t op; + unsigned char *loc; + int arg1, arg2; + unsigned char *end; +{ + register unsigned char *pfrom = end; + register unsigned char *pto = end + 5; + + while (pfrom != loc) + *--pto = *--pfrom; + + store_op2 (op, loc, arg1, arg2); +} + + +/* P points to just after a ^ in PATTERN. Return true if that ^ comes + after an alternative or a begin-subexpression. We assume there is at + least one character before the ^. */ + +static boolean +at_begline_loc_p (pattern, p, syntax) + const char *pattern, *p; + reg_syntax_t syntax; +{ + const char *prev = p - 2; + boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; + + return + /* After a subexpression? */ + (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) + /* After an alternative? */ + || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); +} + + +/* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + +static boolean +at_endline_loc_p (p, pend, syntax) + const char *p, *pend; + int syntax; +{ + const char *next = p; + boolean next_backslash = *next == '\\'; + const char *next_next = p + 1 < pend ? p + 1 : NULL; + + return + /* Before a subexpression? */ + (syntax & RE_NO_BK_PARENS ? *next == ')' + : next_backslash && next_next && *next_next == ')') + /* Before an alternative? */ + || (syntax & RE_NO_BK_VBAR ? *next == '|' + : next_backslash && next_next && *next_next == '|'); +} + + +/* Returns true if REGNUM is in one of COMPILE_STACK's elements and + false if it's not. */ + +static boolean +group_in_compile_stack (compile_stack, regnum) + compile_stack_type compile_stack; + regnum_t regnum; +{ + int this_element; + + for (this_element = compile_stack.avail - 1; + this_element >= 0; + this_element--) + if (compile_stack.stack[this_element].regnum == regnum) + return true; + + return false; +} + + +/* Read the ending character of a range (in a bracket expression) from the + uncompiled pattern *P_PTR (which ends at PEND). We assume the + starting character is in `P[-2]'. (`P[-1]' is the character `-'.) + Then we set the translation of all bits between the starting and + ending characters (inclusive) in the compiled pattern B. + + Return an error code. + + We use these short variable names so we can use the same macros as + `regex_compile' itself. */ + +static reg_errcode_t +compile_range (p_ptr, pend, translate, syntax, b) + const char **p_ptr, *pend; + char *translate; + reg_syntax_t syntax; + unsigned char *b; +{ + unsigned this_char; + + const char *p = *p_ptr; + int range_start, range_end; + + if (p == pend) + return REG_ERANGE; + + /* Even though the pattern is a signed `char *', we need to fetch + with unsigned char *'s; if the high bit of the pattern character + is set, the range endpoints will be negative if we fetch using a + signed char *. + + We also want to fetch the endpoints without translating them; the + appropriate translation is done in the bit-setting loop below. */ + range_start = ((unsigned char *) p)[-2]; + range_end = ((unsigned char *) p)[0]; + + /* Have to increment the pointer into the pattern string, so the + caller isn't still at the ending character. */ + (*p_ptr)++; + + /* If the start is after the end, the range is empty. */ + if (range_start > range_end) + return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; + + /* Here we see why `this_char' has to be larger than an `unsigned + char' -- the range is inclusive, so if `range_end' == 0xff + (assuming 8-bit characters), we would otherwise go into an infinite + loop, since all characters <= 0xff. */ + for (this_char = range_start; this_char <= range_end; this_char++) + { + SET_LIST_BIT (TRANSLATE (this_char)); + } + + return REG_NOERROR; +} + +/* Failure stack declarations and macros; both re_compile_fastmap and + re_match_2 use a failure stack. These have to be macros because of + REGEX_ALLOCATE. */ + + +/* Number of failure points for which to initially allocate space + when matching. If this number is exceeded, we allocate more + space, so it is not a hard limit. */ +#ifndef INIT_FAILURE_ALLOC +#define INIT_FAILURE_ALLOC 5 +#endif + +/* Roughly the maximum number of failure points on the stack. Would be + exactly that if always used MAX_FAILURE_SPACE each time we failed. + This is a variable only so users of regex can assign to it; we never + change it ourselves. */ +int re_max_failures = 2000; + +typedef const unsigned char *fail_stack_elt_t; + +typedef struct +{ + fail_stack_elt_t *stack; + unsigned size; + unsigned avail; /* Offset of next open position. */ +} fail_stack_type; + +#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) +#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) +#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) +#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) + + +/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ + +#define INIT_FAIL_STACK() \ + do { \ + fail_stack.stack = (fail_stack_elt_t *) \ + REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ + \ + if (fail_stack.stack == NULL) \ + return -2; \ + \ + fail_stack.size = INIT_FAILURE_ALLOC; \ + fail_stack.avail = 0; \ + } while (0) + + +/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. + + Return 1 if succeeds, and 0 if either ran out of memory + allocating space for it or it was already too large. + + REGEX_REALLOCATE requires `destination' be declared. */ + +#define DOUBLE_FAIL_STACK(fail_stack) \ + ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ + ? 0 \ + : ((fail_stack).stack = (fail_stack_elt_t *) \ + REGEX_REALLOCATE ((fail_stack).stack, \ + (fail_stack).size * sizeof (fail_stack_elt_t), \ + ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ + \ + (fail_stack).stack == NULL \ + ? 0 \ + : ((fail_stack).size <<= 1, \ + 1))) + + +/* Push PATTERN_OP on FAIL_STACK. + + Return 1 if was able to do so and 0 if ran out of memory allocating + space to do so. */ +#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ + ((FAIL_STACK_FULL () \ + && !DOUBLE_FAIL_STACK (fail_stack)) \ + ? 0 \ + : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ + 1)) + +/* This pushes an item onto the failure stack. Must be a four-byte + value. Assumes the variable `fail_stack'. Probably should only + be called from within `PUSH_FAILURE_POINT'. */ +#define PUSH_FAILURE_ITEM(item) \ + fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item + +/* The complement operation. Assumes `fail_stack' is nonempty. */ +#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] + +/* Used to omit pushing failure point id's when we're not debugging. */ +#ifdef DEBUG +#define DEBUG_PUSH PUSH_FAILURE_ITEM +#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () +#else +#define DEBUG_PUSH(item) +#define DEBUG_POP(item_addr) +#endif + + +/* Push the information about the state we will need + if we ever fail back to it. + + Requires variables fail_stack, regstart, regend, reg_info, and + num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be + declared. + + Does `return FAILURE_CODE' if runs out of memory. */ + +#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ + do { \ + char *destination; \ + /* Must be int, so when we don't save any registers, the arithmetic \ + of 0 + -1 isn't done as unsigned. */ \ + int this_reg; \ + \ + DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ + DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ + DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ + DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ + \ + DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ + DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ + \ + /* Ensure we have enough space allocated for what we will push. */ \ + while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ + { \ + if (!DOUBLE_FAIL_STACK (fail_stack)) \ + return failure_code; \ + \ + DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ + (fail_stack).size); \ + DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ + } \ + \ + /* Push the info, starting with the registers. */ \ + DEBUG_PRINT1 ("\n"); \ + \ + for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ + this_reg++) \ + { \ + DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ + DEBUG_STATEMENT (num_regs_pushed++); \ + \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + PUSH_FAILURE_ITEM (regstart[this_reg]); \ + \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + PUSH_FAILURE_ITEM (regend[this_reg]); \ + \ + DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ + DEBUG_PRINT2 (" match_null=%d", \ + REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ + DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ + DEBUG_PRINT2 (" matched_something=%d", \ + MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT2 (" ever_matched=%d", \ + EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ + DEBUG_PRINT1 ("\n"); \ + PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ + } \ + \ + DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ + PUSH_FAILURE_ITEM (lowest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ + PUSH_FAILURE_ITEM (highest_active_reg); \ + \ + DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ + PUSH_FAILURE_ITEM (pattern_place); \ + \ + DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ + DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ + size2); \ + DEBUG_PRINT1 ("'\n"); \ + PUSH_FAILURE_ITEM (string_place); \ + \ + DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ + DEBUG_PUSH (failure_id); \ + } while (0) + +/* This is the number of items that are pushed and popped on the stack + for each register. */ +#define NUM_REG_ITEMS 3 + +/* Individual items aside from the registers. */ +#ifdef DEBUG +#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ +#else +#define NUM_NONREG_ITEMS 4 +#endif + +/* We push at most this many items on the stack. */ +#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) + +/* We actually push this many items. */ +#define NUM_FAILURE_ITEMS \ + ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ + + NUM_NONREG_ITEMS) + +/* How many items can still be added to the stack without overflowing it. */ +#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + +/* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + +#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ +{ \ + DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ + int this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_ITEM (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ + \ + low_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ + \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + } \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ +} /* POP_FAILURE_POINT */ + +/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in + BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible + characters can start a string that matches the pattern. This fastmap + is used by re_search to skip quickly over impossible starting points. + + The caller must supply the address of a (1 << BYTEWIDTH)-byte data + area as BUFP->fastmap. + + We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in + the pattern buffer. + + Returns 0 if we succeed, -2 if an internal error. */ + +int +re_compile_fastmap (bufp) + struct re_pattern_buffer *bufp; +{ + int j, k; + fail_stack_type fail_stack; +#ifndef REGEX_MALLOC + char *destination; +#endif + /* We don't push any register information onto the failure stack. */ + unsigned num_regs = 0; + + register char *fastmap = bufp->fastmap; + unsigned char *pattern = bufp->buffer; + unsigned long size = bufp->used; + const unsigned char *p = pattern; + register unsigned char *pend = pattern + size; + + /* Assume that each path through the pattern can be null until + proven otherwise. We set this false at the bottom of switch + statement, to which we get only if a particular path doesn't + match the empty string. */ + boolean path_can_be_null = true; + + /* We aren't doing a `succeed_n' to begin with. */ + boolean succeed_n_p = false; + + assert (fastmap != NULL && p != NULL); + + INIT_FAIL_STACK (); + bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ + bufp->fastmap_accurate = 1; /* It will be when we're done. */ + bufp->can_be_null = 0; + + while (p != pend || !FAIL_STACK_EMPTY ()) + { + if (p == pend) + { + bufp->can_be_null |= path_can_be_null; + + /* Reset for next path. */ + path_can_be_null = true; + + p = fail_stack.stack[--fail_stack.avail]; + } + + /* We should never be about to go beyond the end of the pattern. */ + assert (p < pend); + +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + + /* I guess the idea here is to simply not bother with a fastmap + if a backreference is used, since it's too hard to figure out + the fastmap for the corresponding group. Setting + `can_be_null' stops `re_search_2' from using the fastmap, so + that is all we do. */ + case duplicate: + bufp->can_be_null = 1; + return 0; + + + /* Following are the cases which match a character. These end + with `break'. */ + + case exactn: + fastmap[p[1]] = 1; + break; + + + case charset: + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) + fastmap[j] = 1; + break; + + + case charset_not: + /* Chars beyond end of map must be allowed. */ + for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) + if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) + fastmap[j] = 1; + break; + + + case wordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == Sword) + fastmap[j] = 1; + break; + + + case notwordchar: + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != Sword) + fastmap[j] = 1; + break; + + + case anychar: + /* `.' matches anything ... */ + for (j = 0; j < (1 << BYTEWIDTH); j++) + fastmap[j] = 1; + + /* ... except perhaps newline. */ + if (!(bufp->syntax & RE_DOT_NEWLINE)) + fastmap['\n'] = 0; + + /* Return if we have already set `can_be_null'; if we have, + then the fastmap is irrelevant. Something's wrong here. */ + else if (bufp->can_be_null) + return 0; + + /* Otherwise, have to check alternative paths. */ + break; + + +#ifdef emacs + case syntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) == (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + case notsyntaxspec: + k = *p++; + for (j = 0; j < (1 << BYTEWIDTH); j++) + if (SYNTAX (j) != (enum syntaxcode) k) + fastmap[j] = 1; + break; + + + /* All cases after this match the empty string. These end with + `continue'. */ + + + case before_dot: + case at_dot: + case after_dot: + continue; +#endif /* not emacs */ + + + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbound: + case notwordbound: + case wordbeg: + case wordend: + case push_dummy_failure: + continue; + + + case jump_n: + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case jump_past_alt: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + if (j > 0) + continue; + + /* Jump backward implies we just went through the body of a + loop and matched nothing. Opcode jumped to should be + `on_failure_jump' or `succeed_n'. Just treat it like an + ordinary jump. For a * loop, it has pushed its failure + point already; if so, discard that as redundant. */ + if ((re_opcode_t) *p != on_failure_jump + && (re_opcode_t) *p != succeed_n) + continue; + + p++; + EXTRACT_NUMBER_AND_INCR (j, p); + p += j; + + /* If what's on the stack is where we are now, pop it. */ + if (!FAIL_STACK_EMPTY () + && fail_stack.stack[fail_stack.avail - 1] == p) + fail_stack.avail--; + + continue; + + + case on_failure_jump: + case on_failure_keep_string_jump: + handle_on_failure_jump: + EXTRACT_NUMBER_AND_INCR (j, p); + + /* For some patterns, e.g., `(a?)?', `p+j' here points to the + end of the pattern. We don't want to push such a point, + since when we restore it above, entering the switch will + increment `p' past the end of the pattern. We don't need + to push such a point since we obviously won't find any more + fastmap entries beyond `pend'. Such a pattern can match + the null string, though. */ + if (p + j < pend) + { + if (!PUSH_PATTERN_OP (p + j, fail_stack)) + return -2; + } + else + bufp->can_be_null = 1; + + if (succeed_n_p) + { + EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ + succeed_n_p = false; + } + + continue; + + + case succeed_n: + /* Get to the number of times to succeed. */ + p += 2; + + /* Increment p past the n for when k != 0. */ + EXTRACT_NUMBER_AND_INCR (k, p); + if (k == 0) + { + p -= 4; + succeed_n_p = true; /* Spaghetti code alert. */ + goto handle_on_failure_jump; + } + continue; + + + case set_number_at: + p += 4; + continue; + + + case start_memory: + case stop_memory: + p += 2; + continue; + + + default: + abort (); /* We have listed all the cases. */ + } /* switch *p++ */ + + /* Getting here means we have found the possible starting + characters for one path of the pattern -- and that the empty + string does not match. We need not follow this path further. + Instead, look at the next alternative (remembered on the + stack), or quit if no more. The test at the top of the loop + does these things. */ + path_can_be_null = false; + p = pend; + } /* while p */ + + /* Set `can_be_null' for the last path (also the first path, if the + pattern is empty). */ + bufp->can_be_null |= path_can_be_null; + return 0; +} /* re_compile_fastmap */ + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use + this memory for recording register information. STARTS and ENDS + must be allocated using the malloc library routine, and must each + be at least NUM_REGS * sizeof (regoff_t) bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ + +void +re_set_registers (bufp, regs, num_regs, starts, ends) + struct re_pattern_buffer *bufp; + struct re_registers *regs; + unsigned num_regs; + regoff_t *starts, *ends; +{ + if (num_regs) + { + bufp->regs_allocated = REGS_REALLOCATE; + regs->num_regs = num_regs; + regs->start = starts; + regs->end = ends; + } + else + { + bufp->regs_allocated = REGS_UNALLOCATED; + regs->num_regs = 0; + regs->start = regs->end = (regoff_t) 0; + } +} + +/* Searching routines. */ + +/* Like re_search_2, below, but only one string is specified, and + doesn't let you say where to stop matching. */ + +int +re_search (bufp, string, size, startpos, range, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, startpos, range; + struct re_registers *regs; +{ + return re_search_2 (bufp, NULL, 0, string, size, startpos, range, + regs, size); +} + + +/* Using the compiled pattern in BUFP->buffer, first tries to match the + virtual concatenation of STRING1 and STRING2, starting first at index + STARTPOS, then at STARTPOS + 1, and so on. + + STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. + + RANGE is how far to scan while trying to match. RANGE = 0 means try + only at STARTPOS; in general, the last start tried is STARTPOS + + RANGE. + + In REGS, return the indices of the virtual concatenation of STRING1 + and STRING2 that matched the entire BUFP->buffer and its contained + subexpressions. + + Do not consider matching one past the index STOP in the virtual + concatenation of STRING1 and STRING2. + + We return either the position in the strings at which the match was + found, -1 if no match, or -2 if error (such as failure + stack overflow). */ + +int +re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int startpos; + int range; + struct re_registers *regs; + int stop; +{ + int val; + register char *fastmap = bufp->fastmap; + register char *translate = bufp->translate; + int total_size = size1 + size2; + int endpos = startpos + range; + + /* Check for out-of-range STARTPOS. */ + if (startpos < 0 || startpos > total_size) + return -1; + + /* Fix up RANGE if it might eventually take us outside + the virtual concatenation of STRING1 and STRING2. */ + if (endpos < -1) + range = -1 - startpos; + else if (endpos > total_size) + range = total_size - startpos; + + /* If the search isn't to be a backwards one, don't waste time in a + search for a pattern that must be anchored. */ + if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) + { + if (startpos > 0) + return -1; + else + range = 1; + } + + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ + for (;;) + { + /* If a fastmap is supplied, skip quickly over characters that + cannot be the start of a match. If the pattern can match the + null string, however, we don't need to skip characters; we want + the first null string. */ + if (fastmap && startpos < total_size && !bufp->can_be_null) + { + if (range > 0) /* Searching forwards. */ + { + register const char *d; + register int lim = 0; + int irange = range; + + if (startpos < size1 && startpos + range >= size1) + lim = range - (size1 - startpos); + + d = (startpos >= size1 ? string2 - size1 : string1) + startpos; + + /* Written out as an if-else to avoid testing `translate' + inside the loop. */ + if (translate) + while (range > lim + && !fastmap[(unsigned char) + translate[(unsigned char) *d++]]) + range--; + else + while (range > lim && !fastmap[(unsigned char) *d++]) + range--; + + startpos += irange - range; + } + else /* Searching backwards. */ + { + register char c = (size1 == 0 || startpos >= size1 + ? string2[startpos - size1] + : string1[startpos]); + + if (!fastmap[(unsigned char) TRANSLATE (c)]) + goto advance; + } + } + + /* If can't match the null string, and that's all we have left, fail. */ + if (range >= 0 && startpos == total_size && fastmap + && !bufp->can_be_null) + return -1; + + val = re_match_2 (bufp, string1, size1, string2, size2, + startpos, regs, stop); + if (val >= 0) + return startpos; + + if (val == -2) + return -2; + + advance: + if (!range) + break; + else if (range > 0) + { + range--; + startpos++; + } + else + { + range++; + startpos--; + } + } + return -1; +} /* re_search_2 */ + +/* Declarations and macros for re_match_2. */ + +static int bcmp_translate (); +static boolean alt_match_null_string_p (), + common_op_match_null_string_p (), + group_match_null_string_p (); + +/* Structure for per-register (a.k.a. per-group) information. + This must not be longer than one word, because we push this value + onto the failure stack. Other register information, such as the + starting and ending positions (which are addresses), and the list of + inner groups (which is a bits list) are maintained in separate + variables. + + We are making a (strictly speaking) nonportable assumption here: that + the compiler will pack our bit fields into something that fits into + the type of `word', i.e., is something that fits into one item on the + failure stack. */ +typedef union +{ + fail_stack_elt_t word; + struct + { + /* This field is one if this group can match the empty string, + zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ +#define MATCH_NULL_UNSET_VALUE 3 + unsigned match_null_string_p : 2; + unsigned is_active : 1; + unsigned matched_something : 1; + unsigned ever_matched_something : 1; + } bits; +} register_info_type; + +#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) +#define IS_ACTIVE(R) ((R).bits.is_active) +#define MATCHED_SOMETHING(R) ((R).bits.matched_something) +#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) + + +/* Call this when have matched a real character; it sets `matched' flags + for the subexpressions which we are currently inside. Also records + that those subexprs have matched. */ +#define SET_REGS_MATCHED() \ + do \ + { \ + unsigned r; \ + for (r = lowest_active_reg; r <= highest_active_reg; r++) \ + { \ + MATCHED_SOMETHING (reg_info[r]) \ + = EVER_MATCHED_SOMETHING (reg_info[r]) \ + = 1; \ + } \ + } \ + while (0) + + +/* This converts PTR, a pointer into one of the search strings `string1' + and `string2' into an offset from the beginning of that string. */ +#define POINTER_TO_OFFSET(ptr) \ + (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1) + +/* Registers are set to a sentinel when they haven't yet matched. */ +#define REG_UNSET_VALUE ((char *) -1) +#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) + + +/* Macros for dealing with the split strings in re_match_2. */ + +#define MATCHING_IN_FIRST_STRING (dend == end_match_1) + +/* Call before fetching a character with *d. This switches over to + string2 if necessary. */ +#define PREFETCH() \ + while (d == dend) \ + { \ + /* End of string2 => fail. */ \ + if (dend == end_match_2) \ + goto fail; \ + /* End of string1 => advance to string2. */ \ + d = string2; \ + dend = end_match_2; \ + } + + +/* Test if at very beginning or at very end of the virtual concatenation + of `string1' and `string2'. If only one string, it's `string2'. */ +#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) +#define AT_STRINGS_END(d) ((d) == end2) + + +/* Test if D points to a character which is word-constituent. We have + two special cases to check for: if past the end of string1, look at + the first character in string2; and if before the beginning of + string2, look at the last character in string1. */ +#define WORDCHAR_P(d) \ + (SYNTAX ((d) == end1 ? *string2 \ + : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ + == Sword) + +/* Test if the character before D and the one at D differ with respect + to being word-constituent. */ +#define AT_WORD_BOUNDARY(d) \ + (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ + || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) + + +/* Free everything we malloc. */ +#ifdef REGEX_MALLOC +#define FREE_VAR(var) if (var) free (var); var = NULL +#define FREE_VARIABLES() \ + do { \ + FREE_VAR (fail_stack.stack); \ + FREE_VAR (regstart); \ + FREE_VAR (regend); \ + FREE_VAR (old_regstart); \ + FREE_VAR (old_regend); \ + FREE_VAR (best_regstart); \ + FREE_VAR (best_regend); \ + FREE_VAR (reg_info); \ + FREE_VAR (reg_dummy); \ + FREE_VAR (reg_info_dummy); \ + } while (0) +#else /* not REGEX_MALLOC */ +/* Some MIPS systems (at least) want this to free alloca'd storage. */ +#define FREE_VARIABLES() alloca (0) +#endif /* not REGEX_MALLOC */ + + +/* These values must meet several constraints. They must not be valid + register values; since we have a limit of 255 registers (because + we use only one byte in the pattern for the register number), we can + use numbers larger than 255. They must differ by 1, because of + NUM_FAILURE_ITEMS above. And the value for the lowest register must + be larger than the value for the highest register, so we do not try + to actually save any registers when none are active. */ +#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) +#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) + +/* Matching routines. */ + +#ifndef emacs /* Emacs never uses this. */ +/* re_match is like re_match_2 except it takes only a single string. */ + +int +re_match (bufp, string, size, pos, regs) + struct re_pattern_buffer *bufp; + const char *string; + int size, pos; + struct re_registers *regs; + { + return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); +} +#endif /* not emacs */ + + +/* re_match_2 matches the compiled pattern in BUFP against the + the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 + and SIZE2, respectively). We start matching at POS, and stop + matching at STOP. + + If REGS is non-null and the `no_sub' field of BUFP is nonzero, we + store offsets for the substring each group matched in REGS. See the + documentation for exactly how many groups we fill. + + We return -1 if no match, -2 if an internal error (such as the + failure stack overflowing). Otherwise, we return the length of the + matched substring. */ + +int +re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) + struct re_pattern_buffer *bufp; + const char *string1, *string2; + int size1, size2; + int pos; + struct re_registers *regs; + int stop; +{ + /* General temporaries. */ + int mcnt; + unsigned char *p1; + + /* Just past the end of the corresponding string. */ + const char *end1, *end2; + + /* Pointers into string1 and string2, just past the last characters in + each to consider matching. */ + const char *end_match_1, *end_match_2; + + /* Where we are in the data, and the end of the current string. */ + const char *d, *dend; + + /* Where we are in the pattern, and the end of the pattern. */ + unsigned char *p = bufp->buffer; + register unsigned char *pend = p + bufp->used; + + /* We use this to map every character in the string. */ + char *translate = bufp->translate; + + /* Failure point stack. Each place that can handle a failure further + down the line pushes a failure point on this stack. It consists of + restart, regend, and reg_info for all registers corresponding to + the subexpressions we're currently inside, plus the number of such + registers, and, finally, two char *'s. The first char * is where + to resume scanning the pattern; the second one is where to resume + scanning the strings. If the latter is zero, the failure point is + a ``dummy''; if a failure happens and the failure point is a dummy, + it gets discarded and the next next one is tried. */ + fail_stack_type fail_stack; +#ifdef DEBUG + static unsigned failure_id = 0; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; +#endif + + /* We fill all the registers internally, independent of what we + return, for use in backreferences. The number here includes + an element for register zero. */ + unsigned num_regs = bufp->re_nsub + 1; + + /* The currently active registers. */ + unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; + unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; + + /* Information on the contents of registers. These are pointers into + the input strings; they record just what was matched (on this + attempt) by a subexpression part of the pattern, that is, the + regnum-th regstart pointer points to where in the pattern we began + matching and the regnum-th regend points to right after where we + stopped matching the regnum-th subexpression. (The zeroth register + keeps track of what the whole pattern matches.) */ + const char **regstart, **regend; + + /* If a group that's operated upon by a repetition operator fails to + match anything, then the register for its start will need to be + restored because it will have been set to wherever in the string we + are when we last see its open-group operator. Similarly for a + register's end. */ + const char **old_regstart, **old_regend; + + /* The is_active field of reg_info helps us keep track of which (possibly + nested) subexpressions we are currently in. The matched_something + field of reg_info[reg_num] helps us tell whether or not we have + matched any of the pattern so far this time through the reg_num-th + subexpression. These two fields get reset each time through any + loop their register is in. */ + register_info_type *reg_info; + + /* The following record the register info as found in the above + variables when we find a match better than any we've seen before. + This happens as we backtrack through the failure points, which in + turn happens only if we have not yet matched the entire string. */ + unsigned best_regs_set = false; + const char **best_regstart, **best_regend; + + /* Logically, this is `best_regend[0]'. But we don't want to have to + allocate space for that if we're not allocating space for anything + else (see below). Also, we never need info about register 0 for + any of the other register vectors, and it seems rather a kludge to + treat `best_regend' differently than the rest. So we keep track of + the end of the best match so far in a separate variable. We + initialize this to NULL so that when we backtrack the first time + and need to test it, it's not garbage. */ + const char *match_end = NULL; + + /* Used when we pop values we don't care about. */ + const char **reg_dummy; + register_info_type *reg_info_dummy; + +#ifdef DEBUG + /* Counts the total number of registers pushed. */ + unsigned num_regs_pushed = 0; +#endif + + DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); + + INIT_FAIL_STACK (); + + /* Do not bother to initialize all the register variables if there are + no groups in the pattern, as it takes a fair amount of time. If + there are groups, we include space for register 0 (the whole + pattern), even though we never use it, since it simplifies the + array indexing. We should fix this. */ + if (bufp->re_nsub) + { + regstart = REGEX_TALLOC (num_regs, const char *); + regend = REGEX_TALLOC (num_regs, const char *); + old_regstart = REGEX_TALLOC (num_regs, const char *); + old_regend = REGEX_TALLOC (num_regs, const char *); + best_regstart = REGEX_TALLOC (num_regs, const char *); + best_regend = REGEX_TALLOC (num_regs, const char *); + reg_info = REGEX_TALLOC (num_regs, register_info_type); + reg_dummy = REGEX_TALLOC (num_regs, const char *); + reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); + + if (!(regstart && regend && old_regstart && old_regend && reg_info + && best_regstart && best_regend && reg_dummy && reg_info_dummy)) + { + FREE_VARIABLES (); + return -2; + } + } +#ifdef REGEX_MALLOC + else + { + /* We must initialize all our variables to NULL, so that + `FREE_VARIABLES' doesn't try to free them. */ + regstart = regend = old_regstart = old_regend = best_regstart + = best_regend = reg_dummy = NULL; + reg_info = reg_info_dummy = (register_info_type *) NULL; + } +#endif /* REGEX_MALLOC */ + + /* The starting position is bogus. */ + if (pos < 0 || pos > size1 + size2) + { + FREE_VARIABLES (); + return -1; + } + + /* Initialize subexpression text positions to -1 to mark ones that no + start_memory/stop_memory has been seen for. Also initialize the + register information struct. */ + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = regend[mcnt] + = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; + + REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; + IS_ACTIVE (reg_info[mcnt]) = 0; + MATCHED_SOMETHING (reg_info[mcnt]) = 0; + EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; + } + + /* We move `string1' into `string2' if the latter's empty -- but not if + `string1' is null. */ + if (size2 == 0 && string1 != NULL) + { + string2 = string1; + size2 = size1; + string1 = 0; + size1 = 0; + } + end1 = string1 + size1; + end2 = string2 + size2; + + /* Compute where to stop matching, within the two strings. */ + if (stop <= size1) + { + end_match_1 = string1 + stop; + end_match_2 = string2; + } + else + { + end_match_1 = end1; + end_match_2 = string2 + stop - size1; + } + + /* `p' scans through the pattern as `d' scans through the data. + `dend' is the end of the input string that `d' points within. `d' + is advanced into the following input string whenever necessary, but + this happens before fetching; therefore, at the beginning of the + loop, `d' can be pointing at the end of a string, but it cannot + equal `string2'. */ + if (size1 > 0 && pos <= size1) + { + d = string1 + pos; + dend = end_match_1; + } + else + { + d = string2 + pos - size1; + dend = end_match_2; + } + + DEBUG_PRINT1 ("The compiled pattern is: "); + DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); + DEBUG_PRINT1 ("The string to match is: `"); + DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); + DEBUG_PRINT1 ("'\n"); + + /* This loops over pattern commands. It exits by returning from the + function if the match is complete, or it drops through if the match + fails at this starting point in the input data. */ + for (;;) + { + DEBUG_PRINT2 ("\n0x%x: ", p); + + if (p == pend) + { /* End of pattern means we might have succeeded. */ + DEBUG_PRINT1 ("end of pattern ... "); + + /* If we haven't matched the entire string, and we want the + longest match, try backtracking. */ + if (d != end_match_2) + { + DEBUG_PRINT1 ("backtracking.\n"); + + if (!FAIL_STACK_EMPTY ()) + { /* More failure points to try. */ + boolean same_str_p = (FIRST_STRING_P (match_end) + == MATCHING_IN_FIRST_STRING); + + /* If exceeds best match so far, save it. */ + if (!best_regs_set + || (same_str_p && d > match_end) + || (!same_str_p && !MATCHING_IN_FIRST_STRING)) + { + best_regs_set = true; + match_end = d; + + DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + best_regstart[mcnt] = regstart[mcnt]; + best_regend[mcnt] = regend[mcnt]; + } + } + goto fail; + } + + /* If no failure points, don't restore garbage. */ + else if (best_regs_set) + { + restore_best_regs: + /* Restore best match. It may happen that `dend == + end_match_1' while the restored d is in string2. + For example, the pattern `x.*y.*z' against the + strings `x-' and `y-z-', if the two strings are + not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + + d = match_end; + dend = ((d >= string1 && d <= end1) + ? end_match_1 : end_match_2); + + for (mcnt = 1; mcnt < num_regs; mcnt++) + { + regstart[mcnt] = best_regstart[mcnt]; + regend[mcnt] = best_regend[mcnt]; + } + } + } /* d != end_match_2 */ + + DEBUG_PRINT1 ("Accepting match.\n"); + + /* If caller wants register contents data back, do it. */ + if (regs && !bufp->no_sub) + { + /* Have the register data arrays been allocated? */ + if (bufp->regs_allocated == REGS_UNALLOCATED) + { /* No. So allocate them with malloc. We need one + extra element beyond `num_regs' for the `-1' marker + GNU code uses. */ + regs->num_regs = MAX (RE_NREGS, num_regs + 1); + regs->start = TALLOC (regs->num_regs, regoff_t); + regs->end = TALLOC (regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + bufp->regs_allocated = REGS_REALLOCATE; + } + else if (bufp->regs_allocated == REGS_REALLOCATE) + { /* Yes. If we need more elements than were already + allocated, reallocate them. If we need fewer, just + leave it alone. */ + if (regs->num_regs < num_regs + 1) + { + regs->num_regs = num_regs + 1; + RETALLOC (regs->start, regs->num_regs, regoff_t); + RETALLOC (regs->end, regs->num_regs, regoff_t); + if (regs->start == NULL || regs->end == NULL) + return -2; + } + } + else + assert (bufp->regs_allocated == REGS_FIXED); + + /* Convert the pointer data in `regstart' and `regend' to + indices. Register zero has to be set differently, + since we haven't kept track of any info for it. */ + if (regs->num_regs > 0) + { + regs->start[0] = pos; + regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1 + : d - string2 + size1); + } + + /* Go through the first `min (num_regs, regs->num_regs)' + registers, since that is all we initialized. */ + for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) + { + if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) + regs->start[mcnt] = regs->end[mcnt] = -1; + else + { + regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]); + regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]); + } + } + + /* If the regs structure we return has more elements than + were in the pattern, set the extra elements to -1. If + we (re)allocated the registers, this is the case, + because we always allocate enough to have at least one + -1 at the end. */ + for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) + regs->start[mcnt] = regs->end[mcnt] = -1; + } /* regs && !bufp->no_sub */ + + FREE_VARIABLES (); + DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", + nfailure_points_pushed, nfailure_points_popped, + nfailure_points_pushed - nfailure_points_popped); + DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); + + mcnt = d - pos - (MATCHING_IN_FIRST_STRING + ? string1 + : string2 - size1); + + DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); + + return mcnt; + } + + /* Otherwise match next pattern command. */ +#ifdef SWITCH_ENUM_BUG + switch ((int) ((re_opcode_t) *p++)) +#else + switch ((re_opcode_t) *p++) +#endif + { + /* Ignore these. Used to ignore the n of succeed_n's which + currently have n == 0. */ + case no_op: + DEBUG_PRINT1 ("EXECUTING no_op.\n"); + break; + + + /* Match the next n pattern characters exactly. The following + byte in the pattern defines n, and the n bytes after that + are the characters to match. */ + case exactn: + mcnt = *p++; + DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); + + /* This is written out as an if-else so we don't waste time + testing `translate' inside the loop. */ + if (translate) + { + do + { + PREFETCH (); + if (translate[(unsigned char) *d++] != (char) *p++) + goto fail; + } + while (--mcnt); + } + else + { + do + { + PREFETCH (); + if (*d++ != (char) *p++) goto fail; + } + while (--mcnt); + } + SET_REGS_MATCHED (); + break; + + + /* Match any character except possibly a newline or a null. */ + case anychar: + DEBUG_PRINT1 ("EXECUTING anychar.\n"); + + PREFETCH (); + + if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') + || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) + goto fail; + + SET_REGS_MATCHED (); + DEBUG_PRINT2 (" Matched `%d'.\n", *d); + d++; + break; + + + case charset: + case charset_not: + { + register unsigned char c; + boolean not = (re_opcode_t) *(p - 1) == charset_not; + + DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); + + PREFETCH (); + c = TRANSLATE (*d); /* The character to match. */ + + /* Cast to `unsigned' instead of `unsigned char' in case the + bit list is a full 32 bytes long. */ + if (c < (unsigned) (*p * BYTEWIDTH) + && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + p += 1 + *p; + + if (!not) goto fail; + + SET_REGS_MATCHED (); + d++; + break; + } + + + /* The beginning of a group is represented by start_memory. + The arguments are the register number in the next byte, and the + number of groups inner to this one in the next. The text + matched within the group is recorded (in the internal + registers data structure) under the register number. */ + case start_memory: + DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); + + /* Find out if this group can match the empty string. */ + p1 = p; /* To send to group_match_null_string_p. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[*p]) + = group_match_null_string_p (&p1, pend, reg_info); + + /* Save the position in the string where we were the last time + we were at this open-group operator in case the group is + operated upon by a repetition operator, e.g., with `(a*)*b' + against `ab'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regstart[*p]) ? d : regstart[*p] + : regstart[*p]; + DEBUG_PRINT2 (" old_regstart: %d\n", + POINTER_TO_OFFSET (old_regstart[*p])); + + regstart[*p] = d; + DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); + + IS_ACTIVE (reg_info[*p]) = 1; + MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* This is the new highest active register. */ + highest_active_reg = *p; + + /* If nothing was active before, this is the new lowest active + register. */ + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *p; + + /* Move past the register number and inner group count. */ + p += 2; + break; + + + /* The stop_memory opcode represents the end of a group. Its + arguments are the same as start_memory's: the register + number, and the number of inner groups. */ + case stop_memory: + DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); + + /* We need to save the string position the last time we were at + this close-group operator in case the group is operated + upon by a repetition operator, e.g., with `((a*)*(b*)*)*' + against `aba'; then we want to ignore where we are now in + the string in case this attempt to match fails. */ + old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) + ? REG_UNSET (regend[*p]) ? d : regend[*p] + : regend[*p]; + DEBUG_PRINT2 (" old_regend: %d\n", + POINTER_TO_OFFSET (old_regend[*p])); + + regend[*p] = d; + DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); + + /* This register isn't active anymore. */ + IS_ACTIVE (reg_info[*p]) = 0; + + /* If this was the only register active, nothing is active + anymore. */ + if (lowest_active_reg == highest_active_reg) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + { /* We must scan for the new highest active register, since + it isn't necessarily one less than now: consider + (a(b)c(d(e)f)g). When group 3 ends, after the f), the + new highest active register is 1. */ + unsigned char r = *p - 1; + while (r > 0 && !IS_ACTIVE (reg_info[r])) + r--; + + /* If we end up at register zero, that means that we saved + the registers as the result of an `on_failure_jump', not + a `start_memory', and we jumped to past the innermost + `stop_memory'. For example, in ((.)*) we save + registers 1 and 2 as a result of the *, but when we pop + back to the second ), we are at the stop_memory 1. + Thus, nothing is active. */ + if (r == 0) + { + lowest_active_reg = NO_LOWEST_ACTIVE_REG; + highest_active_reg = NO_HIGHEST_ACTIVE_REG; + } + else + highest_active_reg = r; + } + + /* If just failed to match something this time around with a + group that's operated on by a repetition operator, try to + force exit from the ``loop'', and restore the register + information for this group that we had before trying this + last match. */ + if ((!MATCHED_SOMETHING (reg_info[*p]) + || (re_opcode_t) p[-3] == start_memory) + && (p + 2) < pend) + { + boolean is_a_jump_n = false; + + p1 = p + 2; + mcnt = 0; + switch ((re_opcode_t) *p1++) + { + case jump_n: + is_a_jump_n = true; + case pop_failure_jump: + case maybe_pop_jump: + case jump: + case dummy_failure_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (is_a_jump_n) + p1 += 2; + break; + + default: + /* do nothing */ ; + } + p1 += mcnt; + + /* If the next operation is a jump backwards in the pattern + to an on_failure_jump right before the start_memory + corresponding to this stop_memory, exit from the loop + by forcing a failure after pushing on the stack the + on_failure_jump's jump in the pattern, and d. */ + if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump + && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) + { + /* If this group ever matched anything, then restore + what its registers were before trying this last + failed match, e.g., with `(a*)*b' against `ab' for + regstart[1], and, e.g., with `((a*)*(b*)*)*' + against `aba' for regend[3]. + + Also restore the registers for inner groups for, + e.g., `((a*)(b*))*' against `aba' (register 3 would + otherwise get trashed). */ + + if (EVER_MATCHED_SOMETHING (reg_info[*p])) + { + unsigned r; + + EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; + + /* Restore this and inner groups' (if any) registers. */ + for (r = *p; r < *p + *(p + 1); r++) + { + regstart[r] = old_regstart[r]; + + /* xx why this test? */ + if ((int) old_regend[r] >= (int) regstart[r]) + regend[r] = old_regend[r]; + } + } + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + PUSH_FAILURE_POINT (p1 + mcnt, d, -2); + + goto fail; + } + } + + /* Move past the register number and the inner group count. */ + p += 2; + break; + + + /* \<digit> has been turned into a `duplicate' command which is + followed by the numeric value of <digit> as the register number. */ + case duplicate: + { + register const char *d2, *dend2; + int regno = *p++; /* Get which register to match against. */ + DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); + + /* Can't back reference a group which we've never matched. */ + if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) + goto fail; + + /* Where in input to try to start matching. */ + d2 = regstart[regno]; + + /* Where to stop matching; if both the place to start and + the place to stop matching are in the same string, then + set to the place to stop, otherwise, for now have to use + the end of the first string. */ + + dend2 = ((FIRST_STRING_P (regstart[regno]) + == FIRST_STRING_P (regend[regno])) + ? regend[regno] : end_match_1); + for (;;) + { + /* If necessary, advance to next segment in register + contents. */ + while (d2 == dend2) + { + if (dend2 == end_match_2) break; + if (dend2 == regend[regno]) break; + + /* End of string1 => advance to string2. */ + d2 = string2; + dend2 = regend[regno]; + } + /* At end of register contents => success */ + if (d2 == dend2) break; + + /* If necessary, advance to next segment in data. */ + PREFETCH (); + + /* How many characters left in this segment to match. */ + mcnt = dend - d; + + /* Want how many consecutive characters we can match in + one shot, so, if necessary, adjust the count. */ + if (mcnt > dend2 - d2) + mcnt = dend2 - d2; + + /* Compare that many; failure if mismatch, else move + past them. */ + if (translate + ? bcmp_translate (d, d2, mcnt, translate) + : bcmp (d, d2, mcnt)) + goto fail; + d += mcnt, d2 += mcnt; + } + } + break; + + + /* begline matches the empty string at the beginning of the string + (unless `not_bol' is set in `bufp'), and, if + `newline_anchor' is set, after newlines. */ + case begline: + DEBUG_PRINT1 ("EXECUTING begline.\n"); + + if (AT_STRINGS_BEG (d)) + { + if (!bufp->not_bol) break; + } + else if (d[-1] == '\n' && bufp->newline_anchor) + { + break; + } + /* In all other cases, we fail. */ + goto fail; + + + /* endline is the dual of begline. */ + case endline: + DEBUG_PRINT1 ("EXECUTING endline.\n"); + + if (AT_STRINGS_END (d)) + { + if (!bufp->not_eol) break; + } + + /* We have to ``prefetch'' the next character. */ + else if ((d == end1 ? *string2 : *d) == '\n' + && bufp->newline_anchor) + { + break; + } + goto fail; + + + /* Match at the very beginning of the data. */ + case begbuf: + DEBUG_PRINT1 ("EXECUTING begbuf.\n"); + if (AT_STRINGS_BEG (d)) + break; + goto fail; + + + /* Match at the very end of the data. */ + case endbuf: + DEBUG_PRINT1 ("EXECUTING endbuf.\n"); + if (AT_STRINGS_END (d)) + break; + goto fail; + + + /* on_failure_keep_string_jump is used to optimize `.*\n'. It + pushes NULL as the value for the string on the stack. Then + `pop_failure_point' will keep the current value for the + string, instead of restoring it. To see why, consider + matching `foo\nbar' against `.*\n'. The .* matches the foo; + then the . fails against the \n. But the next thing we want + to do is match the \n against the \n; if we restored the + string value, we would be back at the foo. + + Because this is used only in specific cases, we don't need to + check all the things that `on_failure_jump' does, to make + sure the right things get saved on the stack. Hence we don't + share its code. The only reason to push anything on the + stack at all is that otherwise we would have to change + `anychar's code to do something besides goto fail in this + case; that seems worse than this. */ + case on_failure_keep_string_jump: + DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); + + PUSH_FAILURE_POINT (p + mcnt, NULL, -2); + break; + + + /* Uses of on_failure_jump: + + Each alternative starts with an on_failure_jump that points + to the beginning of the next alternative. Each alternative + except the last ends with a jump that in effect jumps past + the rest of the alternatives. (They really jump to the + ending jump of the following alternative, because tensioning + these jumps is a hassle.) + + Repeats start with an on_failure_jump that points past both + the repetition text and either the following jump or + pop_failure_jump back to this on_failure_jump. */ + case on_failure_jump: + on_failure: + DEBUG_PRINT1 ("EXECUTING on_failure_jump"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); + + /* If this on_failure_jump comes right before a group (i.e., + the original * applied to a group), save the information + for that group and all inner ones, so that if we fail back + to this point, the group's information will be correct. + For example, in \(a*\)*\1, we need the preceding group, + and in \(\(a*\)b*\)\2, we need the inner group. */ + + /* We can't use `p' to check ahead because we push + a failure point to `p + mcnt' after we do this. */ + p1 = p; + + /* We need to skip no_op's before we look for the + start_memory in case this on_failure_jump is happening as + the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 + against aba. */ + while (p1 < pend && (re_opcode_t) *p1 == no_op) + p1++; + + if (p1 < pend && (re_opcode_t) *p1 == start_memory) + { + /* We have a new highest active register now. This will + get reset at the start_memory we are about to get to, + but we will have saved all the registers relevant to + this repetition op, as described above. */ + highest_active_reg = *(p1 + 1) + *(p1 + 2); + if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) + lowest_active_reg = *(p1 + 1); + } + + DEBUG_PRINT1 (":\n"); + PUSH_FAILURE_POINT (p + mcnt, d, -2); + break; + + + /* A smart repeat ends with `maybe_pop_jump'. + We change it to either `pop_failure_jump' or `jump'. */ + case maybe_pop_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); + { + register unsigned char *p2 = p; + + /* Compare the beginning of the repeat with what in the + pattern follows its end. If we can establish that there + is nothing that they would both match, i.e., that we + would have to backtrack because of (as in, e.g., `a*a') + then we can change to pop_failure_jump, because we'll + never have to backtrack. + + This is not true in the case of alternatives: in + `(a|ab)*' we do need to backtrack to the `ab' alternative + (e.g., if the string was `ab'). But instead of trying to + detect that here, the alternative has put on a dummy + failure point which is what we will end up popping. */ + + /* Skip over open/close-group commands. */ + while (p2 + 2 < pend + && ((re_opcode_t) *p2 == stop_memory + || (re_opcode_t) *p2 == start_memory)) + p2 += 3; /* Skip over args, too. */ + + /* If we're at the end of the pattern, we can change. */ + if (p2 == pend) + { + /* Consider what happens when matching ":\(.*\)" + against ":/". I don't really understand this code + yet. */ + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 + (" End of pattern: change to `pop_failure_jump'.\n"); + } + + else if ((re_opcode_t) *p2 == exactn + || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) + { + register unsigned char c + = *p2 == (unsigned char) endline ? '\n' : p2[2]; + p1 = p + mcnt; + + /* p1[0] ... p1[2] are the `on_failure_jump' corresponding + to the `maybe_finalize_jump' of this case. Examine what + follows. */ + if ((re_opcode_t) p1[3] == exactn && p1[5] != c) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", + c, p1[5]); + } + + else if ((re_opcode_t) p1[3] == charset + || (re_opcode_t) p1[3] == charset_not) + { + int not = (re_opcode_t) p1[3] == charset_not; + + if (c < (unsigned char) (p1[4] * BYTEWIDTH) + && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) + not = !not; + + /* `not' is equal to 1 if c would match, which means + that we can't change to pop_failure_jump. */ + if (!not) + { + p[-3] = (unsigned char) pop_failure_jump; + DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); + } + } + } + } + p -= 2; /* Point at relative address again. */ + if ((re_opcode_t) p[-1] != pop_failure_jump) + { + p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); + goto unconditional_jump; + } + /* Note fall through. */ + + + /* The end of a simple repeat has a pop_failure_jump back to + its matching on_failure_jump, where the latter will push a + failure point. The pop_failure_jump takes off failure + points put on by this pop_failure_jump's matching + on_failure_jump; we got through the pattern to here from the + matching on_failure_jump, so didn't fail. */ + case pop_failure_jump: + { + /* We need to pass separate storage for the lowest and + highest registers, even though we don't care about the + actual values. Otherwise, we will restore only one + register from the stack, since lowest will == highest in + `pop_failure_point'. */ + unsigned dummy_low_reg, dummy_high_reg; + unsigned char *pdummy; + const char *sdummy; + + DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); + POP_FAILURE_POINT (sdummy, pdummy, + dummy_low_reg, dummy_high_reg, + reg_dummy, reg_dummy, reg_info_dummy); + } + /* Note fall through. */ + + + /* Unconditionally jump (without popping any failure points). */ + case jump: + unconditional_jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ + DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); + p += mcnt; /* Do the jump. */ + DEBUG_PRINT2 ("(to 0x%x).\n", p); + break; + + + /* We need this opcode so we can detect where alternatives end + in `group_match_null_string_p' et al. */ + case jump_past_alt: + DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); + goto unconditional_jump; + + + /* Normally, the on_failure_jump pushes a failure point, which + then gets popped at pop_failure_jump. We will end up at + pop_failure_jump, also, and with a pattern of, say, `a+', we + are skipping over the on_failure_jump, so we have to push + something meaningless for pop_failure_jump to pop. */ + case dummy_failure_jump: + DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); + /* It doesn't matter what we push for the string here. What + the code at `fail' tests is the value for the pattern. */ + PUSH_FAILURE_POINT (0, 0, -2); + goto unconditional_jump; + + + /* At the end of an alternative, we need to push a dummy failure + point in case we are followed by a `pop_failure_jump', because + we don't want the failure point for the alternative to be + popped. For example, matching `(a|ab)*' against `aab' + requires that we match the `ab' alternative. */ + case push_dummy_failure: + DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); + /* See comments just above at `dummy_failure_jump' about the + two zeroes. */ + PUSH_FAILURE_POINT (0, 0, -2); + break; + + /* Have to succeed matching what follows at least n times. + After that, handle like `on_failure_jump'. */ + case succeed_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); + + assert (mcnt >= 0); + /* Originally, this is how many times we HAVE to succeed. */ + if (mcnt > 0) + { + mcnt--; + p += 2; + STORE_NUMBER_AND_INCR (p, mcnt); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); + } + else if (mcnt == 0) + { + DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); + p[2] = (unsigned char) no_op; + p[3] = (unsigned char) no_op; + goto on_failure; + } + break; + + case jump_n: + EXTRACT_NUMBER (mcnt, p + 2); + DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); + + /* Originally, this is how many times we CAN jump. */ + if (mcnt) + { + mcnt--; + STORE_NUMBER (p + 2, mcnt); + goto unconditional_jump; + } + /* If don't have to jump any more, skip over the rest of command. */ + else + p += 4; + break; + + case set_number_at: + { + DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); + + EXTRACT_NUMBER_AND_INCR (mcnt, p); + p1 = p + mcnt; + EXTRACT_NUMBER_AND_INCR (mcnt, p); + DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); + STORE_NUMBER (p1, mcnt); + break; + } + + case wordbound: + DEBUG_PRINT1 ("EXECUTING wordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + break; + goto fail; + + case notwordbound: + DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); + if (AT_WORD_BOUNDARY (d)) + goto fail; + break; + + case wordbeg: + DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); + if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) + break; + goto fail; + + case wordend: + DEBUG_PRINT1 ("EXECUTING wordend.\n"); + if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) + && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) + break; + goto fail; + +#ifdef emacs +#ifdef emacs19 + case before_dot: + DEBUG_PRINT1 ("EXECUTING before_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) >= point) + goto fail; + break; + + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) != point) + goto fail; + break; + + case after_dot: + DEBUG_PRINT1 ("EXECUTING after_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) <= point) + goto fail; + break; +#else /* not emacs19 */ + case at_dot: + DEBUG_PRINT1 ("EXECUTING at_dot.\n"); + if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) + goto fail; + break; +#endif /* not emacs19 */ + + case syntaxspec: + DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchsyntax; + + case wordchar: + DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); + mcnt = (int) Sword; + matchsyntax: + PREFETCH (); + if (SYNTAX (*d++) != (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + + case notsyntaxspec: + DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); + mcnt = *p++; + goto matchnotsyntax; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); + mcnt = (int) Sword; + matchnotsyntax: + PREFETCH (); + if (SYNTAX (*d++) == (enum syntaxcode) mcnt) + goto fail; + SET_REGS_MATCHED (); + break; + +#else /* not emacs */ + case wordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); + PREFETCH (); + if (!WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; + + case notwordchar: + DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); + PREFETCH (); + if (WORDCHAR_P (d)) + goto fail; + SET_REGS_MATCHED (); + d++; + break; +#endif /* not emacs */ + + default: + abort (); + } + continue; /* Successfully executed one pattern command; keep going. */ + + + /* We goto here if a matching operation fails. */ + fail: + if (!FAIL_STACK_EMPTY ()) + { /* A restart point is known. Restore to that state. */ + DEBUG_PRINT1 ("\nFAIL:\n"); + POP_FAILURE_POINT (d, p, + lowest_active_reg, highest_active_reg, + regstart, regend, reg_info); + + /* If this failure point is a dummy, try the next one. */ + if (!p) + goto fail; + + /* If we failed to the end of the pattern, don't examine *p. */ + assert (p <= pend); + if (p < pend) + { + boolean is_a_jump_n = false; + + /* If failed to a backwards jump that's part of a repetition + loop, need to pop this failure point and use the next one. */ + switch ((re_opcode_t) *p) + { + case jump_n: + is_a_jump_n = true; + case maybe_pop_jump: + case pop_failure_jump: + case jump: + p1 = p + 1; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + + if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) + || (!is_a_jump_n + && (re_opcode_t) *p1 == on_failure_jump)) + goto fail; + break; + default: + /* do nothing */ ; + } + } + + if (d >= string1 && d <= end1) + dend = end_match_1; + } + else + break; /* Matching at this starting point really fails. */ + } /* for (;;) */ + + if (best_regs_set) + goto restore_best_regs; + + FREE_VARIABLES (); + + return -1; /* Failure to match. */ +} /* re_match_2 */ + +/* Subroutine definitions for re_match_2. */ + + +/* We are passed P pointing to a register number after a start_memory. + + Return true if the pattern up to the corresponding stop_memory can + match the empty string, and false otherwise. + + If we find the matching stop_memory, sets P to point to one past its number. + Otherwise, sets P to an undefined byte less than or equal to END. + + We don't handle duplicates properly (yet). */ + +static boolean +group_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + /* Point to after the args to the start_memory. */ + unsigned char *p1 = *p + 2; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and return true or + false, as appropriate, when we get to one that can't, or to the + matching stop_memory. */ + + switch ((re_opcode_t) *p1) + { + /* Could be either a loop or a series of alternatives. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + /* If the next operation is not a jump backwards in the + pattern. */ + + if (mcnt >= 0) + { + /* Go through the on_failure_jumps of the alternatives, + seeing if any of the alternatives cannot match nothing. + The last alternative starts with only a jump, + whereas the rest start with on_failure_jump and end + with a jump, e.g., here is the pattern for `a|b|c': + + /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 + /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 + /exactn/1/c + + So, we have to first go through the first (n-1) + alternatives and then deal with the last one separately. */ + + + /* Deal with the first (n-1) alternatives, which start + with an on_failure_jump (see above) that jumps to right + past a jump_past_alt. */ + + while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) + { + /* `mcnt' holds how many bytes long the alternative + is, including the ending `jump_past_alt' and + its number. */ + + if (!alt_match_null_string_p (p1, p1 + mcnt - 3, + reg_info)) + return false; + + /* Move to right after this alternative, including the + jump_past_alt. */ + p1 += mcnt; + + /* Break if it's the beginning of an n-th alternative + that doesn't begin with an on_failure_jump. */ + if ((re_opcode_t) *p1 != on_failure_jump) + break; + + /* Still have to check that it's not an n-th + alternative that starts with an on_failure_jump. */ + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) + { + /* Get to the beginning of the n-th alternative. */ + p1 -= 3; + break; + } + } + + /* Deal with the last alternative: go back and get number + of the `jump_past_alt' just before it. `mcnt' contains + the length of the alternative. */ + EXTRACT_NUMBER (mcnt, p1 - 2); + + if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) + return false; + + p1 += mcnt; /* Get past the n-th alternative. */ + } /* if mcnt > 0 */ + break; + + + case stop_memory: + assert (p1[1] == **p); + *p = p1 + 2; + return true; + + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return false; +} /* group_match_null_string_p */ + + +/* Similar to group_match_null_string_p, but doesn't deal with alternatives: + It expects P to be the first byte of a single alternative and END one + byte past the last. The alternative can contain groups. */ + +static boolean +alt_match_null_string_p (p, end, reg_info) + unsigned char *p, *end; + register_info_type *reg_info; +{ + int mcnt; + unsigned char *p1 = p; + + while (p1 < end) + { + /* Skip over opcodes that can match nothing, and break when we get + to one that can't. */ + + switch ((re_opcode_t) *p1) + { + /* It's a loop. */ + case on_failure_jump: + p1++; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + break; + + default: + if (!common_op_match_null_string_p (&p1, end, reg_info)) + return false; + } + } /* while p1 < end */ + + return true; +} /* alt_match_null_string_p */ + + +/* Deals with the ops common to group_match_null_string_p and + alt_match_null_string_p. + + Sets P to one after the op and its arguments, if any. */ + +static boolean +common_op_match_null_string_p (p, end, reg_info) + unsigned char **p, *end; + register_info_type *reg_info; +{ + int mcnt; + boolean ret; + int reg_no; + unsigned char *p1 = *p; + + switch ((re_opcode_t) *p1++) + { + case no_op: + case begline: + case endline: + case begbuf: + case endbuf: + case wordbeg: + case wordend: + case wordbound: + case notwordbound: +#ifdef emacs + case before_dot: + case at_dot: + case after_dot: +#endif + break; + + case start_memory: + reg_no = *p1; + assert (reg_no > 0 && reg_no <= MAX_REGNUM); + ret = group_match_null_string_p (&p1, end, reg_info); + + /* Have to set this here in case we're checking a group which + contains a group and a back reference to it. */ + + if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) + REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; + + if (!ret) + return false; + break; + + /* If this is an optimized succeed_n for zero times, make the jump. */ + case jump: + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + if (mcnt >= 0) + p1 += mcnt; + else + return false; + break; + + case succeed_n: + /* Get to the number of times to succeed. */ + p1 += 2; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + + if (mcnt == 0) + { + p1 -= 4; + EXTRACT_NUMBER_AND_INCR (mcnt, p1); + p1 += mcnt; + } + else + return false; + break; + + case duplicate: + if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) + return false; + break; + + case set_number_at: + p1 += 4; + + default: + /* All other opcodes mean we cannot match the empty string. */ + return false; + } + + *p = p1; + return true; +} /* common_op_match_null_string_p */ + + +/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN + bytes; nonzero otherwise. */ + +static int +bcmp_translate (s1, s2, len, translate) + unsigned char *s1, *s2; + register int len; + char *translate; +{ + register unsigned char *p1 = s1, *p2 = s2; + while (len) + { + if (translate[*p1++] != translate[*p2++]) return 1; + len--; + } + return 0; +} + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length SIZE) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the `allocated' (and perhaps `buffer') and `translate' fields + are set in BUFP on entry. + + We call regex_compile to do the actual compilation. */ + +const char * +re_compile_pattern (pattern, length, bufp) + const char *pattern; + int length; + struct re_pattern_buffer *bufp; +{ + reg_errcode_t ret; + + /* GNU code is written to assume at least RE_NREGS registers will be set + (and at least one extra will be -1). */ + bufp->regs_allocated = REGS_UNALLOCATED; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub. */ + bufp->no_sub = 0; + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = regex_compile (pattern, length, re_syntax_options, bufp); + + return re_error_msg[(int) ret]; +} + +/* Entry points compatible with 4.2 BSD regex library. We don't define + them if this is an Emacs or POSIX compilation. */ + +#if !defined (emacs) && !defined (_POSIX_SOURCE) + +/* BSD has one and only one pattern buffer. */ +static struct re_pattern_buffer re_comp_buf; + +char * +re_comp (s) + const char *s; +{ + reg_errcode_t ret; + + if (!s) + { + if (!re_comp_buf.buffer) + return "No previous regular expression"; + return 0; + } + + if (!re_comp_buf.buffer) + { + re_comp_buf.buffer = (unsigned char *) malloc (200); + if (re_comp_buf.buffer == NULL) + return "Memory exhausted"; + re_comp_buf.allocated = 200; + + re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); + if (re_comp_buf.fastmap == NULL) + return "Memory exhausted"; + } + + /* Since `re_exec' always passes NULL for the `regs' argument, we + don't need to initialize the pattern buffer fields which affect it. */ + + /* Match anchors at newlines. */ + re_comp_buf.newline_anchor = 1; + + ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); + + /* Yes, we're discarding `const' here. */ + return (char *) re_error_msg[(int) ret]; +} + + +int +re_exec (s) + const char *s; +{ + const int len = strlen (s); + return + 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); +} +#endif /* not emacs and not _POSIX_SOURCE */ + +/* POSIX.2 functions. Don't define these for Emacs. */ + +#ifndef emacs + +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + `buffer' to the compiled pattern; + `used' to the length of the compiled pattern; + `syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + `newline_anchor' to REG_NEWLINE being set in CFLAGS; + `fastmap' and `fastmap_accurate' to zero; + `re_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp (preg, pattern, cflags) + regex_t *preg; + const char *pattern; + int cflags; +{ + reg_errcode_t ret; + unsigned syntax + = (cflags & REG_EXTENDED) ? + RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; + + /* regex_compile will allocate the space for the compiled pattern. */ + preg->buffer = 0; + preg->allocated = 0; + + /* Don't bother to use a fastmap when searching. This simplifies the + REG_NEWLINE case: if we used a fastmap, we'd have to put all the + characters after newlines into the fastmap. This way, we just try + every character. */ + preg->fastmap = 0; + + if (cflags & REG_ICASE) + { + unsigned i; + + preg->translate = (char *) malloc (CHAR_SET_SIZE); + if (preg->translate == NULL) + return (int) REG_ESPACE; + + /* Map uppercase characters to corresponding lowercase ones. */ + for (i = 0; i < CHAR_SET_SIZE; i++) + preg->translate[i] = ISUPPER (i) ? tolower (i) : i; + } + else + preg->translate = NULL; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) + { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } + else + preg->newline_anchor = 0; + + preg->no_sub = !!(cflags & REG_NOSUB); + + /* POSIX says a null character in the pattern terminates it, so we + can use strlen here in compiling the pattern. */ + ret = regex_compile (pattern, strlen (pattern), syntax, preg); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) ret = REG_EPAREN; + + return (int) ret; +} + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies `execution flags' which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec (preg, string, nmatch, pmatch, eflags) + const regex_t *preg; + const char *string; + size_t nmatch; + regmatch_t pmatch[]; + int eflags; +{ + int ret; + struct re_registers regs; + regex_t private_preg; + int len = strlen (string); + boolean want_reg_info = !preg->no_sub && nmatch > 0; + + private_preg = *preg; + + private_preg.not_bol = !!(eflags & REG_NOTBOL); + private_preg.not_eol = !!(eflags & REG_NOTEOL); + + /* The user has told us exactly how many registers to return + information about, via `nmatch'. We have to pass that on to the + matching routines. */ + private_preg.regs_allocated = REGS_FIXED; + + if (want_reg_info) + { + regs.num_regs = nmatch; + regs.start = TALLOC (nmatch, regoff_t); + regs.end = TALLOC (nmatch, regoff_t); + if (regs.start == NULL || regs.end == NULL) + return (int) REG_NOMATCH; + } + + /* Perform the searching operation. */ + ret = re_search (&private_preg, string, len, + /* start: */ 0, /* range: */ len, + want_reg_info ? ®s : (struct re_registers *) 0); + + /* Copy the register information to the POSIX structure. */ + if (want_reg_info) + { + if (ret >= 0) + { + unsigned r; + + for (r = 0; r < nmatch; r++) + { + pmatch[r].rm_so = regs.start[r]; + pmatch[r].rm_eo = regs.end[r]; + } + } + + /* If we needed the temporary register info, free the space now. */ + free (regs.start); + free (regs.end); + } + + /* We want zero return to mean success, unlike `re_search'. */ + return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; +} + + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror (errcode, preg, errbuf, errbuf_size) + int errcode; + const regex_t *preg; + char *errbuf; + size_t errbuf_size; +{ + const char *msg; + size_t msg_size; + + if (errcode < 0 + || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort (); + + msg = re_error_msg[errcode]; + + /* POSIX doesn't require that we do anything in this case, but why + not be nice. */ + if (! msg) + msg = "Success"; + + msg_size = strlen (msg) + 1; /* Includes the null. */ + + if (errbuf_size != 0) + { + if (msg_size > errbuf_size) + { + strncpy (errbuf, msg, errbuf_size - 1); + errbuf[errbuf_size - 1] = 0; + } + else + strcpy (errbuf, msg); + } + + return msg_size; +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree (preg) + regex_t *preg; +{ + if (preg->buffer != NULL) + free (preg->buffer); + preg->buffer = NULL; + + preg->allocated = 0; + preg->used = 0; + + if (preg->fastmap != NULL) + free (preg->fastmap); + preg->fastmap = NULL; + preg->fastmap_accurate = 0; + + if (preg->translate != NULL) + free (preg->translate); + preg->translate = NULL; +} + +#endif /* not emacs */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/Build/source/texk/contrib/regex/regex.h b/Build/source/texk/contrib/regex/regex.h new file mode 100644 index 00000000000..7aa88be9f18 --- /dev/null +++ b/Build/source/texk/contrib/regex/regex.h @@ -0,0 +1,505 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + + Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __REGEXP_LIBRARY_H__ +#define __REGEXP_LIBRARY_H__ + +/* POSIX says that <sys/types.h> must be included (by the caller) before + <regex.h>. */ + +#ifdef VMS +/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it + should be there. */ +#include <stddef.h> +#endif + +#if defined(WIN32) +#pragma warning(disable : 4018) +#include <malloc.h> +#ifdef _DLL +#ifdef MAKE_REGEX_DLL +#define REGEXDLL __declspec( dllexport) +#else +#define REGEXDLL __declspec( dllimport) +#endif +#else +#define REGEXDLL +#endif +#else /* ! WIN32 */ +#define REGEXDLL +#endif + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +#define RE_BACKSLASH_ESCAPE_IN_LISTS (1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +#define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then `{...}' defines an interval, and \{ and \} + are literals. + If not set, then `\{...\}' defines an interval. */ +#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \<digit> matches <digit>. + If not set, then \<digit> is a back-reference. */ +#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern REGEXDLL reg_syntax_t re_syntax_options; + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +#define RE_SYNTAX_EMACS 0 + +#define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +#define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) + +#define RE_SYNTAX_GREP \ + (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ + | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ + | RE_NEWLINE_ALT) + +#define RE_SYNTAX_EGREP \ + (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ + | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ + | RE_NO_BK_VBAR) + +#define RE_SYNTAX_POSIX_EGREP \ + (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +#define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +#define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +#define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ +#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + +/* Maximum number of duplicates an interval can allow. Some systems + (erroneously) define this in other header files, but we want our + value, so remove any previous define. */ +#ifdef RE_DUP_MAX +#undef RE_DUP_MAX +#endif +#define RE_DUP_MAX ((1 << 15) - 1) + + +/* POSIX `cflags' bits (i.e., information for `regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (REG_EXTENDED << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (REG_ICASE << 1) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (REG_NEWLINE << 1) + + +/* POSIX `eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + + +/* If any error codes are removed, changed, or added, update the + `re_error_msg' table in regex.c. */ +typedef enum +{ + REG_NOERROR = 0, /* Success. */ + REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + REG_BADPAT, /* Invalid pattern. */ + REG_ECOLLATE, /* Not implemented. */ + REG_ECTYPE, /* Invalid character class name. */ + REG_EESCAPE, /* Trailing backslash. */ + REG_ESUBREG, /* Invalid back reference. */ + REG_EBRACK, /* Unmatched left bracket. */ + REG_EPAREN, /* Parenthesis imbalance. */ + REG_EBRACE, /* Unmatched \{. */ + REG_BADBR, /* Invalid contents of \{\}. */ + REG_ERANGE, /* Invalid range end. */ + REG_ESPACE, /* Ran out of memory. */ + REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + REG_EEND, /* Premature end. */ + REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ + REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields `buffer', `allocated', `fastmap', + `translate', and `no_sub' can be set. After the pattern has been + compiled, the `re_nsub' field is available. All other fields are + private to the regex routines. */ + +struct re_pattern_buffer +{ +/* [[[begin pattern_buffer]]] */ + /* Space that holds the compiled pattern. It is declared as + `unsigned char *' because its elements are + sometimes used as array indexes. */ + unsigned char *buffer; + + /* Number of bytes to which `buffer' points. */ + unsigned long allocated; + + /* Number of bytes actually used in `buffer'. */ + unsigned long used; + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t syntax; + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses + the fastmap, if there is one, to skip over impossible + starting points for matches. */ + char *fastmap; + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation + is applied to a pattern when it is compiled and to a string + when it is matched. */ + char *translate; + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in `re_search_2', to see + whether or not we should use the fastmap, so we don't set + this absolutely perfectly; see `re_compile_fastmap' (the + `duplicate' case). */ + unsigned can_be_null : 1; + + /* If REGS_UNALLOCATED, allocate space in the `regs' structure + for `max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ +#define REGS_UNALLOCATED 0 +#define REGS_REALLOCATE 1 +#define REGS_FIXED 2 + unsigned regs_allocated : 2; + + /* Set to zero when `regex_compile' compiles a pattern; set to one + by `re_compile_fastmap' if it updates the fastmap. */ + unsigned fastmap_accurate : 1; + + /* If set, `re_match_2' does not return information about + subexpressions. */ + unsigned no_sub : 1; + + /* If set, a beginning-of-line anchor doesn't match at the + beginning of the string. */ + unsigned not_bol : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned not_eol : 1; + + /* If true, an anchor at a newline matches. */ + unsigned newline_anchor : 1; + +/* [[[end pattern_buffer]]] */ +}; + +typedef struct re_pattern_buffer regex_t; + + +/* search.c (search_buffer) in Emacs needs this one opcode value. It is + defined both in `regex.c' and here. */ +#define RE_EXACTN_VALUE 1 + +/* Type for byte offsets within the string. POSIX mandates this. */ +typedef int regoff_t; + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + unsigned num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + `re_match_2' returns information about at least this many registers + the first time a `regs' structure is passed. */ +#ifndef RE_NREGS +#define RE_NREGS 30 +#endif + + +/* POSIX specification for registers. Aside from the different names than + `re_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + +/* To avoid duplicating every routine declaration -- once with a + prototype (if we are ANSI), and once without (if we aren't) -- we + use the following macro to declare argument types. This + unfortunately clutters up the declarations a bit, but I think it's + worth it. */ + +#if __STDC__ + +#define _RE_ARGS(args) args + +#else /* not __STDC__ */ + +#define _RE_ARGS(args) () + +#endif /* not __STDC__ */ + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the `re_syntax_options' variable. */ +extern REGEXDLL reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global `re_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. */ +extern REGEXDLL const char *re_compile_pattern + _RE_ARGS ((const char *pattern, int length, + struct re_pattern_buffer *buffer)); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern REGEXDLL int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern REGEXDLL int re_search + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, int range, struct re_registers *regs)); + + +/* Like `re_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern REGEXDLL int re_search_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, int range, struct re_registers *regs, int stop)); + + +/* Like `re_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern REGEXDLL int re_match + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, + int length, int start, struct re_registers *regs)); + + +/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ +extern REGEXDLL int re_match_2 + _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, + int length1, const char *string2, int length2, + int start, struct re_registers *regs, int stop)); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least `NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + PATTERN_BUFFER will allocate its own register data, without + freeing the old data. */ +extern REGEXDLL void re_set_registers + _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, + unsigned num_regs, regoff_t *starts, regoff_t *ends)); + +/* 4.2 bsd compatibility. */ +extern REGEXDLL char *re_comp _RE_ARGS ((const char *)); +extern REGEXDLL int re_exec _RE_ARGS ((const char *)); + +/* POSIX compatibility. */ +extern REGEXDLL int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); +extern REGEXDLL int regexec + _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, + regmatch_t pmatch[], int eflags)); +extern REGEXDLL size_t regerror + _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, + size_t errbuf_size)); +extern REGEXDLL void regfree _RE_ARGS ((regex_t *preg)); + +#endif /* not __REGEXP_LIBRARY_H__ */ + +/* +Local variables: +make-backup-files: t +version-control: t +trim-versions-without-asking: nil +End: +*/ diff --git a/Build/source/texk/contrib/stackenv.c b/Build/source/texk/contrib/stackenv.c new file mode 100644 index 00000000000..a4a831e5f5d --- /dev/null +++ b/Build/source/texk/contrib/stackenv.c @@ -0,0 +1,343 @@ +/* stackenv.c: routines that help to mimic shell scripts. + +Copyright (C) 1997 Fabrice POPINEAU. + +Adapted to DJGPP by Eli Zaretskii. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "stackenv.h" +#include "variables.h" + +string mktex_version_string = "2.0"; + +extern char *output; +extern char tmpdir[]; +extern char *progname; + +/* The global stack. */ +static mod_env stack_env[256]; +static int index_env = 0; + +void mt_exit(int); + +static FILE *fnul = NULL; + +pfnOutputAndCleanup output_and_cleanup_function; + +#ifndef _WIN32 +#include <unistd.h> + +void flushall (void) +{ + /* Simulate `flushall' by only flushing standard streams. + This should be enough, since the non-standard are going + to be closed in a moment, and will be flushed then. */ + fflush (stdout); + fsync (fileno (stdout)); + fflush (stderr); + fsync (fileno (stderr)); +} +#endif + +#ifndef _WIN32 +#ifdef __DJGPP__ + +/* DJGPP-specific emulation of functions which aren't in the library + and aren't ANSI/POSIX. */ + +#include <errno.h> +#include <libc/file.h> + +static void fcloseall_func (FILE *f) +{ + fflush (f); + if (fileno (f) > 2) + fclose(f); + else + fsync (fileno (f)); +} + +void fcloseall (void) +{ + _fwalk (fcloseall_func); +} + +#else /* not __DJGPP__ */ + +/* FIXME: is this enough on Unix? */ +static void fcloseall (void) +{ + flushall (); +} + +#endif /* not __DJGPP__ */ +#endif /* not _WIN32 */ + +void +oops(const char *message, ...) +{ + va_list args; + + va_start(args, message); + vfprintf(stderr, message, args); + va_end(args); + fputc('\n', stderr); + mt_exit(1); +} + +/* pushd */ +void pushd(char *p) +{ + if (index_env >= sizeof(stack_env)/sizeof(stack_env[0])) { + fprintf(stderr, "%s: stack overflow in pushd\n", progname); + mt_exit(1); + } + if ((stack_env[index_env].data.path = malloc(MAXPATHLEN)) == NULL + || getcwd(stack_env[index_env].data.path, MAXPATHLEN) == NULL) { + fprintf(stderr, "pushd error!\n"); + mt_exit(1); + } + stack_env[index_env].op = CHDIR; + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "At %d, pushing from %s to %s\n", index_env, + stack_env[index_env].data.path, p); + } + + index_env++; + if (chdir(p) == -1) { + perror(p); + mt_exit(1); + } +} +/* popd */ +void popd() +{ + if (index_env == 0) + return; + index_env--; + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "At %d, popping %s\n", index_env, stack_env[index_env].data.path); + } + assert(stack_env[index_env].op == CHDIR); + if (chdir(stack_env[index_env].data.path) == -1) { + perror(stack_env[index_env].data.path); + mt_exit(1); + } + free(stack_env[index_env].data.path); + return; +} + +/* random access to directories' stack */ +char *peek_dir(int n) +{ + int i; + int level = n; + + /* The stack holds both directories pushed by `pushd' and file + handles pushed by `push_fd'. When they say "peek_dir(n)", they + mean the n'th DIRECTORY entry, not the n'th entry counting from + the stack bottom. + + For example, if the stack looks like this: + + idx type + + 0 handles + 1 handles + 2 directory + 3 handles <--- top of the stack + 4 <empty> <--- index_env + + then "peek_dir(0)" should return the entry with the index 2, not + the one with the index 0. + + The following loop looks for the index i of a stack slot which + holds the n'th directory pushed on to the stack. */ + + do { + for (i = 0; i < index_env && stack_env[i].op != CHDIR; i++) + ; + } while (i < index_env && n--); + + if (i < index_env) + return stack_env[i].data.path; + else { + fprintf (stderr, "%s: attempt to peek at invalid stack level %d\n", + progname, level); + mt_exit(1); + } +} + +/* redirect */ +void push_fd(int newfd[3]) +{ + int i; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "At %d, pushing fds %d %d %d\n", index_env, newfd[0], + newfd[1], newfd[2]); + } + flushall(); + if (index_env >= sizeof(stack_env)/sizeof(stack_env[0])) { + fprintf(stderr, "%s: stack overflow in push_fd\n", progname); + mt_exit(1); + } + stack_env[index_env].op = REDIRECT; + for(i = 0; i < 3; i++) { + if (i == newfd[i]) + stack_env[index_env].data.oldfd[i] = i; + else { + if ((stack_env[index_env].data.oldfd[i] = dup(i)) == -1) { + perror("push_fd: dup"); + mt_exit(1); + } + if (dup2(newfd[i], i) == -1) { + perror("push_fd : dup2"); + mt_exit(1); + } + } + } + index_env++; +} + +void pop_fd() +{ + int i; + index_env--; + assert(stack_env[index_env].op == REDIRECT); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "At %d; popping fds %d %d %d\n", + index_env, + stack_env[index_env].data.oldfd[0], + stack_env[index_env].data.oldfd[1], + stack_env[index_env].data.oldfd[2]); + } + flushall(); + for(i = 0; i < 3; i++) + if (i != stack_env[index_env].data.oldfd[i]) { + if (fnul && i != fileno(fnul)) close(i); + if (dup2(stack_env[index_env].data.oldfd[i], i) == -1) { + perror("pop_fd : dup2"); + mt_exit(1); + } + if (fnul && stack_env[index_env].data.oldfd[i] != fileno(fnul)) + close(stack_env[index_env].data.oldfd[i]); + } +} + +/* popenv */ +void popenv() +{ + if (index_env <= 0) { + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) + fprintf(stderr, "Trying to popenv() from empty stack!\n"); + return; + } + + switch(stack_env[index_env-1].op) { + case CHDIR: + popd(); + break; + case REDIRECT: + pop_fd(); + break; + default: + fprintf(stderr, "popenv : unknown op %d.\n", stack_env[index_env-1].op); + break; + } +} + +#ifdef _WIN32 +BOOL sigint_handler(DWORD dwCtrlType) +{ + /* Fix me : there is a problem if a system() command is running. + We should wait for the son process to be interrupted. + Only way I can think of to do that : rewrite system() based on + spawn() with parsing of the command line and set a global pid + Next cwait(pid) in the HandlerRoutine. + */ + + /* This is not that good, but else we would need to wait for + the child processes to finish ! */ + Sleep(250); + + mt_exit(3); + return FALSE; /* return value obligatory */ +} +#else +void sigint_handler (int sig) +{ + mt_exit(3); +} +#endif + +void mt_exit(int code) +{ + /* rétablir les 0, 1 et 2 d'origine avant de tenter quoi que ce soit ! */ + fcloseall(); + + /* unstack all env from main) */ + for( ; index_env > 0; popenv()); + + /* output the result and rm any unneeded file */ + if (output_and_cleanup_function != 0) + (*output_and_cleanup_function)(code); + + exit(code); +} + +void +dump_stack() +{ + int i; + for (i = 0; i < index_env; i++) + switch (stack_env[i].op) { + case CHDIR: + fprintf(stderr, "Env %d : chdir %s\n", i, stack_env[i].data.path); + break; + case REDIRECT: + fprintf(stderr, "Env %d : redirect %d %d %d\n", i, + stack_env[i].data.oldfd[0], + stack_env[i].data.oldfd[1], + stack_env[i].data.oldfd[2]); + break; + } + +} + +/* + This is used by mktex{mf,tfm,pk} + if the argument is true, stdout is redirected to fnul + else to stderr. + */ +void start_redirection(boolean discard_stdout) +{ + int newfd[3]; + if (fnul == NULL) +#ifdef _WIN32 + fnul = fopen("nul", "r"); /* fopen /dev/null */ +#else + fnul = fopen("/dev/null", "r"); +#endif + + newfd[0] = fileno(fnul); + newfd[1] = (discard_stdout ? fileno(fnul) : fileno(stderr)); + newfd[2] = fileno(stderr); + + push_fd(newfd); +} + + diff --git a/Build/source/texk/contrib/stackenv.h b/Build/source/texk/contrib/stackenv.h new file mode 100644 index 00000000000..58df686b3eb --- /dev/null +++ b/Build/source/texk/contrib/stackenv.h @@ -0,0 +1,46 @@ +#ifndef _STACKENV_H_ + +#define _STACKENV_H_ + +#include "mktexlib.h" + +/* + We are keeping trace of the environment (ie: cwd, file redirections) + with the help of these ops and structures. There is a global stack + inidcating wich actions have been taken. + */ +typedef enum { CHDIR = 1, REDIRECT } op_env; +typedef struct mod_env { + op_env op; + union { + char *path; + int oldfd[3]; + } data; +} mod_env; + +/* from stackenv.c */ +extern void oops(const char *, ...); +#ifdef __GNUC__ +extern void mt_exit(int) __attribute__((noreturn)); +#else +extern MKTEXDLL void mt_exit(int); +#endif +extern MKTEXDLL void pushd(char *); +extern MKTEXDLL void popd(void); +extern MKTEXDLL void popenv(void); +extern char *peek_dir(int); +extern MKTEXDLL void push_fd(int [3]); +extern MKTEXDLL void pop_fd(void); +extern MKTEXDLL void start_redirection(boolean); +#ifdef _WIN32 +/* extern void mt_exit(int); */ +extern MKTEXDLL BOOL sigint_handler(DWORD); +#else +extern void sigint_handler(int); +#endif + +typedef void (__cdecl * pfnOutputAndCleanup)(int); +extern MKTEXDLL pfnOutputAndCleanup output_and_cleanup_function; + +extern MKTEXDLL int redirect_stdout; +#endif /* _STACKENV_H_ */ diff --git a/Build/source/texk/contrib/variables.c b/Build/source/texk/contrib/variables.c new file mode 100644 index 00000000000..d1837bd6b4b --- /dev/null +++ b/Build/source/texk/contrib/variables.c @@ -0,0 +1,472 @@ +/* variables.c: this package provides symbols and dynamic strings + +Copyright (C) 1997 Fabrice POPINEAU. + +Time-stamp: <03/02/21 11:54:23 popineau> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "stackenv.h" +#include "fileutils.h" +#include "variables.h" +#include <regex.h> + +/* + We will use kpathsea's hash tables + */ + +/* The symbol table */ +hash_table_type *symtab = NULL; + +/* Initialize a symbol table to store all the vars used by + the various shell scripts. */ +void init_vars() +{ + + symtab = hash_create(719, hashtable_symtab); + +} + +void +hash_remove_all (hash_table_type *table, string key) +{ + string *val; + while ((val = hash_lookup(table, key))) { + hash_remove(table, key, *val); + free (val); + } +} + +string getval(string name) +{ + string *lookup = NULL; + string res = NULL; + + /* + Either the name is already in the symbol table ... + */ + if ((lookup = hash_lookup(symtab, name)) != NULL) { + /* FIXME: we return the first value ... */ + res = lookup[0]; + free(lookup); + } +#if 0 + else if ((lookup = hash_lookup(symtab, vname)) != NULL) { + /* FIXME: we return the first value ... */ + res = lookup[0]; + free(lookup); + } + else { + string dollar_name = concat("$", vname); + res = kpse_cnf_get(vname); + free(dollar_name); + } +#endif + if (!res) { +#if 0 + /* + ... Either it is known from kpathsea, in which case we put it + in the symbol table. + */ + string dollar_name = concat("$", vname); + res = expand_var(dollar_name); + + if (test_file('n', res)) { + setval(vname, res); + } + else { + /* res = "", so return NULL */ + res = NULL; + } + free (dollar_name); +#endif + res = getenv(name); + } + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "GetVal %s => %s\n", name, res); + } + + /* In any case ... */ + return res; +} + +string setval(string name, string value) +{ + /* Be safe ... */ + if (!value) value = ""; + hash_remove_all(symtab, name); + hash_insert(symtab, name, value); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "SetVal %s <= %s\n", name, value); + } + + return value; +} + +string setval_default(string name, string value) +{ + string old_value; + /* Be safe ... */ + if (!value) { + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "setval_default: inserting NULL value for %s!\n", name); + } + value = ""; + } + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "SetVal default %s ... ", name); + } + + /* The mktex... scripts NEVER use ${foo:=bar}, always ${foo=bar}. + So we only need to set NAME=VALUE if $NAME is unset. */ + if ((old_value = getval(name)) == NULL) { + hash_insert(symtab, name, value); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "SetVal %s <= %s\n", name, value); + } + } + else + value = old_value; + + return value; +} + +string *grep(char *regexp, char *line, int num_vars) +{ + struct re_pattern_buffer *rc; + struct re_registers *p; + const_string ok; + string *vars = NULL; + string *lookup; + int i; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Grep\n\t%s\n\tin\n\t%s\n", regexp, line); + } + + if (test_file('z', line)) + return NULL; + + /* This will retrieve the precompiled regexp or compile it and + remember it. vars contains the strings matched, num_vars the number + of these strings. */ +#if 0 + if ((lookup = hash_lookup(symtab, regexp))) + rc = (struct re_pattern_buffer *)lookup[0]; + else + rc = NULL; + if (rc == NULL) { +#endif + /* Compile the regexp and stores the result */ + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "\tCompiling the regexp\n"); + } + + re_syntax_options = RE_SYNTAX_POSIX_EGREP; + rc = (struct re_pattern_buffer *) calloc(1, sizeof(struct re_pattern_buffer)); + rc->regs_allocated = REGS_UNALLOCATED; + if ((ok = re_compile_pattern(regexp, strlen(regexp), rc)) != 0) + FATAL1("Can't compile regex %s\n", regexp); +#if 0 + hash_remove_all(symtab, regexp); + hash_insert(symtab, regexp, (char *)rc); + } + else if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "\tAlready compiled\n"); + } +#endif + + p = (struct re_registers *) calloc(1, sizeof(struct re_registers)); + p->num_regs = num_vars; + if ((re_match(rc, line, strlen(line), 0, p)) > 0) { + vars = (char **) xmalloc ((num_vars+1) * sizeof(char *)); + for (i = 0; i <= num_vars; i++) { + vars[i] = malloc((p->end[i] - p->start[i] + 1)*sizeof(char)); + strncpy(vars[i], line+p->start[i], p->end[i] - p->start[i]); + vars[i][p->end[i] - p->start[i]] = '\0'; + } + } + free (p); + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + if (vars) + for(i = 0; i <= num_vars; i++) + fprintf(stderr, "String %d matches %s\n", i, vars[i]); + } + return vars; +} + +/* read a line, trying to find 'variable = value' + Currently groks two constructs: + VAR=value + : {VAR=value} + using regex to analyze them. + The variable is added to the symbol table. In the first case, it + overrides an old value, not in the second case. + */ +boolean parse_variable(string line) +{ + char **vars; + + static char *r1 = "^[[:space:]]*([[:alnum:]_]+)=[[:space:]]*([^[:space:]]*)[[:space:]]*.*$"; + static char *r2 = "^:[[:space:]]+\\$\\{([[:alnum:]_]+)=([^\\}]*)\\}[[:space:]]*.*$"; + + if ((vars = grep(r1, line, 2))) { + setval(vars[1], vars[2]); + return true; + } + else if ((vars = grep(r2, line, 2))) { + setval_default(vars[1], vars[2]); + return true; + } + else + WARNING1("The following line has not been parsed:\n%s\n", line); + return false; +} + +/* Substitute from by to in line */ +string subst(string line, string from, string to) +{ + string before, after, p; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Substituting %s by %s in %s\n", from, to, line); + } + + if ((p = strstr(line, from))) { + before = xstrdup(line); + before[p-line] = '\0'; + after = p+strlen(from); + p = concat3(before, to , after); + free (before); + } + else + p = xstrdup(line); + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "=> gives %s\n", p); + } + + return p; +} + +/* kpse_expand_var does not remove leading !!, but we do not need + them in mktex* + (Parts of code shamelessly stolen from remove_dbonly on tex-file.c.) + */ +string expand_var(const_string s) +{ + string p, q; + string res = NULL; + + if (s) { + boolean new_elt = true; + + res = mktex_var_expand(s); + + for (p = q = res; *p; ) { + if (new_elt && *p == '!' && p[1] == '!') + p += 2; + else { + new_elt = *p == ENV_SEP; + *q++ = *p++; + } + } + *q = '\0'; + + if (KPSE_DEBUG_P(MKTEX_FINE_DEBUG)) { + fprintf(stderr, "Expanding variable %s into %s\n", s, res); + } + } + + return res; +} + +/* + This is shamelessly stolen from kpathsea/variable.c . + We want to do expansion without having to put variables in the + environment. + */ + +/* We have to keep track of variables being expanded, otherwise + constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop. + (Or indirectly recursive variables, etc.) Our simple solution is to + add to a list each time an expansion is started, and check the list + before expanding. */ + +typedef struct { + const_string var; + boolean expanding; +} expansion_type; +static expansion_type *expansions; /* The sole variable of this type. */ +static unsigned expansion_len = 0; + +static void +expanding P2C(const_string, var, boolean, xp) +{ + unsigned e; + for (e = 0; e < expansion_len; e++) { + if (STREQ (expansions[e].var, var)) { + expansions[e].expanding = xp; + return; + } + } + + /* New variable, add it to the list. */ + expansion_len++; + XRETALLOC (expansions, expansion_len, expansion_type); + expansions[expansion_len - 1].var = xstrdup (var); + expansions[expansion_len - 1].expanding = xp; +} + + +/* Return whether VAR is currently being expanding. */ + +static boolean +expanding_p P1C(const_string, var) +{ + unsigned e; + for (e = 0; e < expansion_len; e++) { + if (STREQ (expansions[e].var, var)) + return expansions[e].expanding; + } + + return false; +} + +/* Append the result of value of `var' to EXPANSION, where `var' begins + at START and ends at END. If `var' is not set, do not complain. + This is a subroutine for the more complicated expansion function. */ + +static void +expand P3C(fn_type *, expansion, const_string, start, const_string, end) +{ + string value; + unsigned len = end - start + 1; + string var = xmalloc (len + 1); + strncpy (var, start, len); + var[len] = 0; + + if (expanding_p (var)) { + WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var); + } else { +#if 1 + /* The mktex.c replacement for shell scripts needs a more sophisticated + lookup for variables */ + value = getval(var); +#else + /* Check for an environment variable. */ + value = getenv (var); +#endif + /* If no envvar, check the config files. */ + if (!value) + value = kpse_cnf_get (var); + + if (value) { + expanding (var, true); + value = mktex_var_expand (value); + expanding (var, false); + fn_grow (expansion, value, strlen (value)); + free (value); + } + + free (var); + } +} + +/* Can't think of when it would be useful to change these (and the + diagnostic messages assume them), but ... */ +#ifndef IS_VAR_START /* starts all variable references */ +#define IS_VAR_START(c) ((c) == '$') +#endif +#ifndef IS_VAR_CHAR /* variable name constituent */ +#define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_') +#endif +#ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */ +#define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{') +#endif +#ifndef IS_VAR_END_DELIMITER +#define IS_VAR_END_DELIMITER(c) ((c) == '}') +#endif + + +/* Maybe we should support some or all of the various shell ${...} + constructs, especially ${var-value}. */ + +string +mktex_var_expand P1C(const_string, src) +{ + const_string s; + string ret; + fn_type expansion; + expansion = fn_init (); + + /* Copy everything but variable constructs. */ + for (s = src; *s; s++) { + if (IS_VAR_START (*s)) { + s++; + + /* Three cases: `$VAR', `${VAR}', `$<anything-else>'. */ + if (IS_VAR_CHAR (*s)) { + /* $V: collect name constituents, then expand. */ + const_string var_end = s; + + do { + var_end++; + } while (IS_VAR_CHAR (*var_end)); + + var_end--; /* had to go one past */ + expand (&expansion, s, var_end); + s = var_end; + + } else if (IS_VAR_BEGIN_DELIMITER (*s)) { + /* ${: scan ahead for matching delimiter, then expand. */ + const_string var_end = ++s; + + while (*var_end && !IS_VAR_END_DELIMITER (*var_end)) + var_end++; + + if (! *var_end) { + WARNING1 ("%s: No matching } for ${", src); + s = var_end - 1; /* will incr to null at top of loop */ + } else { + expand (&expansion, s, var_end - 1); + s = var_end; /* will incr past } at top of loop*/ + } + + } else { + /* $<something-else>: error. */ + WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s); + /* Just ignore those chars and keep going. */ + } + } else + fn_1grow (&expansion, *s); + } + fn_1grow (&expansion, 0); + + ret = FN_STRING (expansion); + return ret; +} + +#ifdef TEST + +main() +{ + char buf[256]; + while (gets(buf)) parse_variable(buf); +} +#endif diff --git a/Build/source/texk/contrib/variables.h b/Build/source/texk/contrib/variables.h new file mode 100644 index 00000000000..2488866c6f4 --- /dev/null +++ b/Build/source/texk/contrib/variables.h @@ -0,0 +1,23 @@ +#ifndef _MKTEX_VARIABLES_H_ + +#define _MKTEX_VARIABLES_H_ + +#include <kpathsea/cnf.h> +#include <kpathsea/db.h> +#include <kpathsea/fn.h> +#include <kpathsea/hash.h> + +extern MKTEXDLL void init_vars(void); +extern MKTEXDLL char *getval(char *name); +extern MKTEXDLL char *setval(char *name,char *value); +extern MKTEXDLL char *setval_default(char *name,char *value); +extern MKTEXDLL char **grep(char *regexp,char *line,int num_vars) ; + +extern MKTEXDLL boolean parse_variable(char *line); + +extern char *strcasestr(char *s1,char *s2); + +extern char *subst(char *line, char *from, char *to); +extern MKTEXDLL string expand_var(const_string); +extern MKTEXDLL string mktex_var_expand (const_string src); +#endif /* _MKTEX_VARIABLES_H_ */ diff --git a/Build/source/texk/contrib/win32.mak b/Build/source/texk/contrib/win32.mak new file mode 100644 index 00000000000..65f9f633e8b --- /dev/null +++ b/Build/source/texk/contrib/win32.mak @@ -0,0 +1,166 @@ +################################################################################ +# +# Makefile : TeXk / contrib +# Author : Fabrice Popineau <Fabrice.Popineau@supelec.fr> +# Platform : Win32, Microsoft VC++ 6.0, depends upon fpTeX 0.5 sources +# Time-stamp: <03/09/18 11:26:01 popineau> +# +################################################################################ +root_srcdir=..\.. +!ifdef DEVELOPMENT +INCLUDE=$(INCLUDE);$(root_srcdir)\texk.development +!else +INCLUDE=$(INCLUDE);$(root_srcdir)\texk +!endif + +USE_KPATHSEA=1 +USE_MKTEX=1 +MAKE_MKTEX = 1 +USE_REGEX=1 +USE_GNUW32=1 + +# FIXME: delay load kpathsea for irun !!! + +!include <msvc/common.mak> + +DEFS = $(DEFS) -DHAVE_CONFIG_H -DKPATHSEA_DLL=\"$(kpathseaname).dll\" + +mktex_objs = $(objdir)\fileutils.obj \ + $(objdir)\mktex.obj \ + $(objdir)\variables.obj \ + $(objdir)\stackenv.obj + +mktex_progs = $(objdir)\mktexlsr.exe \ + $(objdir)\mktexnam.exe \ + $(objdir)\mktexupd.exe \ + $(objdir)\mktexpk.exe \ + $(objdir)\mktexdir.exe \ + $(objdir)\mktexmf.exe \ + $(objdir)\mktextfm.exe \ +# $(objdir)\mkofm.exe \ +# $(objdir)\mktextex.exe + +programs = \ + $(mktexdll) \ + $(objdir)\dvihp.exe \ + $(objdir)\makempx.exe \ + $(objdir)\mktex.exe \ + $(objdir)\fmtutil.exe \ + $(objdir)\mkocp.exe \ + $(objdir)\mkofm.exe \ + $(objdir)\irun.exe \ + $(objdir)\pdfdde.exe + +pdfddechilds = $(objdir)\pdfopen.exe $(objdir)\pdfclose.exe + +libfiles = $(mktexlib) + +default: all + +all: $(objdir) $(mktex) $(programs) + +lib: $(objdir) $(mktexlib) + +!ifdef MKTEX_DLL +DEFS = -DMAKE_MKTEX_DLL $(DEFS) + +$(mktexlib): $(mktex_objs) + $(archive) /DEF $(mktex_objs) + +$(mktexdll): $(mktex_objs) $(objdir)\libmktex.res $(regexlib) $(kpathsealib) + $(link_dll) $(**) $(mktexlib:.lib=.exp) $(conlibs) +!else +$(mktexlib): $(mktex_objs) $(regexlib) + $(archive) $(**) +!endif + +mktex_progs: $(objdir)\mktex.exe + for %%i in ($(mktex_progs)) \ + do $(copy) $(objdir)\mktex.exe $(objdir)\%%~nxi + +$(objdir)\makempx.exe: $(objdir)\makempx.obj $(mktexlib) $(objdir)\makempx.res $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\fmtutil.exe: $(objdir)\fmtutil.obj $(mktexlib) $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\dvihp.exe: $(objdir)\dvihp.obj $(mktexlib) $(objdir)\dvihp.res $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\mktex.exe: $(objdir)\main.obj $(mktexlib) $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\mkocp.exe: $(objdir)\mkocp.obj $(mktexlib) $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\mkofm.exe: $(objdir)\mkofm.obj $(gnuw32lib) + $(link) $(**) $(conlibs) + +$(objdir)\makempx.obj: makempx.c + $(compile) -UMAKE_MKTEX_DLL makempx.c + +$(objdir)\fmtutil.obj: fmtutil.c + $(compile) -UMAKE_MKTEX_DLL fmtutil.c + +$(objdir)\main.obj: main.c + $(compile) -UMAKE_MKTEX_DLL main.c + +$(objdir)\dvihp.obj: dvihp.c + $(compile) -UMAKE_MKTEX_DLL dvihp.c + +$(objdir)\mkocp.obj: mkocp.c + $(compile) -UMAKE_MKTEX_DLL mkocp.c + +$(objdir)\mkofm.obj: mkofm.c + $(compile) -UKPSE_DLL -UMAKE_MKTEX_DLL mkofm.c + +$(objdir)\irun-tmp.obj: $(srcdir)\irun.c + echo define RDATA 0x3D000 | sed "s/define/#define/" > $(srcdir)\irun.h + $(compile) $(srcdir)\irun.c + +$(objdir)\irun-tmp.exe: $(objdir)\irun-tmp.obj $(kpathsealib) + $(link) $(**) $(conlibs) + +$(objdir)\irun.obj: $(srcdir)\irun.c $(objdir)\irun-tmp.exe + dumpbin /headers $(objdir)\irun-tmp.exe \ + | sed -n -e "/^[ \t]*FOOBAR/,/^[ \t]*FOOBAR/p" \ + | sed -n -e "/file pointer/p" \ + | sed -e "/raw data/s/^[ \t]*\([0-9A-Z]*\).*$$/#define RDATA 0x\1/" \ + | sed -e "/file pointer/d" \ + > $(srcdir)\irun.h + $(compile) $(srcdir)\irun.c +# -$(RM) $(objdir)\irun-tmp.* + +$(objdir)\irun.exe: $(objdir)\irun.obj $(objdir)\irun.res $(kpathsealib) + $(link) $(**) $(conlibs) $(kpathsealib) + +$(objdir)\pdfdde.exe: $(objdir)\pdfdde.obj $(gnuw32lib) + $(link) $(**) $(conlibs) shell32.lib + +$(objdir)\pdfdde.obj: pdfdde.c + $(compile) -UKPSE_DLL pdfdde.c + +!include <msvc/config.mak> +!include <msvc/install.mak> + +install:: install-exec + +install-exec:: + -@echo $(verbose) & ( \ + echo "Installing mktex program files in $(MAKEDIR)" & \ + ( for %%i in ($(mktex_progs)) do \ + $(copy) $(objdir)\mktex.exe $(bindir)\%%~nxi $(redir_stdout) ) & \ + $(copy) $(objdir)\fmtutil.exe $(bindir)\mktexfmt.exe $(redir_stdout) \ + ) + -@echo $(verbose) & ( \ + for %%i in ($(pdfddechilds)) \ + do $(copy) $(objdir)\pdfdde.exe $(bindir)\%%~nxi $(redir_stdout) ) + +!include <msvc/clean.mak> + +!include <msvc/rdepend.mak> +!include "./depend.mak" + +#Local Variables: +#mode: Makefile +#End: |