summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/lib/openclose.c
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/lib/openclose.c
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/lib/openclose.c')
-rw-r--r--Build/source/texk/web2c/lib/openclose.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/lib/openclose.c b/Build/source/texk/web2c/lib/openclose.c
new file mode 100644
index 00000000000..63fa0393528
--- /dev/null
+++ b/Build/source/texk/web2c/lib/openclose.c
@@ -0,0 +1,471 @@
+/* openclose.c: open and close files for TeX, Metafont, and BibTeX.
+
+ Written 1995 Karl Berry. Public domain. */
+
+#include <w2c/config.h>
+#include "lib.h"
+#include <kpathsea/c-pathch.h>
+#include <kpathsea/tex-file.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/absolute.h>
+#ifdef PTEX
+#include <ptexenc/ptexenc.h>
+#endif
+
+#ifdef _WIN32
+static int fsyscp_remove(char *s)
+{
+ wchar_t *sw = NULL;
+ int ret;
+
+ if(!file_system_codepage)
+ return remove(s);
+
+ sw = get_wstring_from_fsyscp(s, sw);
+ ret = _wremove(sw);
+ if(sw) free(sw);
+ return ret;
+}
+
+static int fsyscp_rename(char *s1, char *s2)
+{
+ wchar_t *sw1 = NULL, *sw2 = NULL;
+ int ret;
+
+ if(!file_system_codepage)
+ return rename(s1, s2);
+
+ sw1 = get_wstring_from_fsyscp(s1, sw1);
+ sw2 = get_wstring_from_fsyscp(s2, sw2);
+ ret = _wrename(sw1, sw2);
+ if(sw1) free(sw1);
+ if(sw2) free(sw2);
+ return ret;
+}
+
+FILE *f_fsyscp_fopen(const char *filename, const char *mode)
+{
+ if(!file_system_codepage)
+ return fopen(filename, mode);
+
+ return fsyscp_fopen(filename, mode);
+}
+
+FILE *f_fsyscp_xfopen(const char *filename, const char *mode)
+{
+ if(!file_system_codepage)
+ return xfopen(filename, mode);
+
+ return fsyscp_xfopen(filename, mode);
+}
+#undef fopen
+#undef xfopen
+#define fopen f_fsyscp_fopen
+#define xfopen f_fsyscp_xfopen
+#define rename fsyscp_rename
+#define remove fsyscp_remove
+#endif /* _WIN32 */
+
+/* The globals we use to communicate. */
+extern string nameoffile;
+extern unsigned namelength;
+
+/* Define some variables. */
+/* For "file:line:error" style error messages. */
+string fullnameoffile; /* Defaults to NULL. */
+static string recorder_name; /* Defaults to NULL. */
+static FILE *recorder_file; /* Defaults to NULL. */
+/* For the filename recorder. */
+boolean recorder_enabled; /* Defaults to false. */
+/* For the output-dir option. */
+string output_directory; /* Defaults to NULL. */
+
+/* For TeX and MetaPost. See below. Always defined so we don't have to
+ #ifdef, and thus this file can be compiled once and go in lib.a. */
+int tfmtemp;
+int ocptemp;
+int texinputtype;
+
+/* Helpers for the filename recorder... */
+/* Start the recorder */
+static void
+recorder_start(void)
+{
+ /* Alas, while we'd like to use mkstemp it is not portable,
+ and doing the autoconfiscation (and providing fallbacks) is more
+ than we want to cope with. So we have to be content with using a
+ default name. Throw in the pid so at least parallel builds might
+ work (Debian bug 575731). */
+ string cwd;
+ char pid_str[MAX_INT_LENGTH];
+
+ /* Windows (MSVC) seems to have no pid_t, so instead of storing the
+ value returned by getpid() we immediately consume it. */
+ sprintf (pid_str, "%ld", (long) getpid());
+ recorder_name = concat3(kpse_program_name, pid_str, ".fls");
+
+ /* If an output directory was specified, use it instead of cwd. */
+ if (output_directory) {
+ string temp = concat3(output_directory, DIR_SEP_STRING, recorder_name);
+ free(recorder_name);
+ recorder_name = temp;
+ }
+
+ recorder_file = xfopen(recorder_name, FOPEN_W_MODE);
+
+ cwd = xgetcwd();
+ fprintf(recorder_file, "PWD %s\n", cwd);
+ free(cwd);
+}
+
+/* Change the name of the recorder file after we know the log file to
+ the usual thing -- no pid integer and the document file name instead
+ of the program name. Unfortunately, we have to explicitly take
+ -output-directory into account (again), since the NEW_NAME we are
+ called with does not; it is just the log file name with .log replaced
+ by .fls. */
+
+void
+recorder_change_filename (string new_name)
+{
+ string temp = NULL;
+
+ if (!recorder_file)
+ return;
+
+ /* On windows, an opened file cannot be renamed. */
+#if defined(_WIN32)
+ fclose (recorder_file);
+#endif /* _WIN32 */
+
+ /* If an output directory was specified, use it. */
+ if (output_directory) {
+ temp = concat3(output_directory, DIR_SEP_STRING, new_name);
+ new_name = temp;
+ }
+
+ /* On windows, renaming fails if a file with new_name exists. */
+#if defined(_WIN32)
+ remove (new_name);
+#endif /* _WIN32 */
+
+ rename(recorder_name, new_name);
+ free(recorder_name);
+ recorder_name = xstrdup(new_name);
+
+ /* reopen the recorder file by FOPEN_A_MODE. */
+#if defined(_WIN32)
+ recorder_file = xfopen (recorder_name, FOPEN_A_MODE);
+#endif /* _WIN32 */
+
+ if (temp)
+ free (temp);
+}
+
+/* helper for recorder_record_* */
+static void
+recorder_record_name (const_string prefix, const_string name)
+{
+ if (recorder_enabled) {
+ if (!recorder_file)
+ recorder_start();
+ fprintf(recorder_file, "%s %s\n", prefix, name);
+ fflush(recorder_file);
+ }
+}
+
+/* record an input file name */
+void
+recorder_record_input (const_string name)
+{
+ recorder_record_name ("INPUT", name);
+}
+
+/* record an output file name */
+void
+recorder_record_output (const_string name)
+{
+ recorder_record_name ("OUTPUT", name);
+}
+
+/* Open input file *F_PTR, using the kpathsea format FILEFMT and passing
+ FOPEN_MODE to fopen. The filename is in `nameoffile+1'. We return
+ whether or not the open succeeded. If it did, `nameoffile' is set to
+ the full filename opened, and `namelength' to its length. */
+
+boolean
+open_input (FILE **f_ptr, int filefmt, const_string fopen_mode)
+{
+ string fname = NULL;
+#if defined(PTEX) && !defined(WIN32)
+ string fname0;
+#endif
+#ifdef FUNNY_CORE_DUMP
+ /* This only applies if a preloaded TeX/Metafont is being made;
+ it allows automatic creation of the core dump (typing ^\ loses
+ since that requires manual intervention). */
+ if ((filefmt == kpse_tex_format || filefmt == kpse_mf_format
+ || filefmt == kpse_mp_format)
+ && STREQ (nameoffile + 1, "HackyInputFileNameForCoreDump.tex"))
+ funny_core_dump ();
+#endif
+
+ /* We havent found anything yet. */
+ *f_ptr = NULL;
+ if (fullnameoffile)
+ free(fullnameoffile);
+ fullnameoffile = NULL;
+
+ /* Look in -output-directory first, if the filename is not
+ absolute. This is because .aux and other such files will get
+ written to the output directory, and we have to be able to read
+ them from there. We only look for the name as-is. */
+
+#if defined(PTEX) && !defined(WIN32)
+ fname0 = ptenc_from_internal_enc_string_to_utf8(nameoffile + 1);
+ if (fname0) {
+ free (nameoffile);
+ namelength = strlen (fname0);
+ nameoffile = xmalloc (namelength + 2);
+ strcpy (nameoffile + 1, fname0);
+ free (fname0);
+ }
+#endif
+ if (output_directory && !kpse_absolute_p (nameoffile+1, false)) {
+ fname = concat3 (output_directory, DIR_SEP_STRING, nameoffile + 1);
+ *f_ptr = fopen (fname, fopen_mode);
+#if !defined(_WIN32)
+/*
+ if fname is a directory, discard it.
+*/
+ if (*f_ptr && dir_p (fname)) {
+ fclose (*f_ptr);
+ *f_ptr = NULL;
+ }
+#endif
+ if (*f_ptr) {
+#if defined(PTEX) && !defined(WIN32)
+ fname0 = ptenc_from_utf8_string_to_internal_enc(fname);
+ if (fname0) {
+ free (fname);
+ fname = fname0;
+ }
+#endif
+ free (nameoffile);
+ namelength = strlen (fname);
+ nameoffile = xmalloc (namelength + 2);
+ strcpy (nameoffile + 1, fname);
+ fullnameoffile = fname;
+ } else {
+ free (fname);
+ }
+ }
+
+ /* No file means do the normal search. */
+ if (*f_ptr == NULL) {
+ /* A negative FILEFMT means don't use a path. */
+ if (filefmt < 0) {
+ /* no_file_path, for BibTeX .aux files and MetaPost things. */
+ *f_ptr = fopen(nameoffile + 1, fopen_mode);
+ /* FIXME... fullnameoffile = xstrdup(nameoffile + 1); */
+ } else {
+ /* The only exception to `must_exist' being true is \openin, for
+ which we set `tex_input_type' to 0 in the change file. */
+ /* According to the pdfTeX people, pounding the disk for .vf files
+ is overkill as well. A more general solution would be nice. */
+ boolean must_exist;
+ must_exist = (filefmt != kpse_tex_format || texinputtype)
+ && (filefmt != kpse_vf_format);
+ fname = kpse_find_file (nameoffile + 1,
+ (kpse_file_format_type)filefmt,
+ must_exist);
+ if (fname) {
+ fullnameoffile = xstrdup(fname);
+ /* If we found the file in the current directory, don't leave
+ the `./' at the beginning of `nameoffile', since it looks
+ dumb when `tex foo' says `(./foo.tex ... )'. On the other
+ hand, if the user said `tex ./foo', and that's what we
+ opened, then keep it -- the user specified it, so we
+ shouldn't remove it. */
+ if (fname[0] == '.' && IS_DIR_SEP (fname[1])
+ && (nameoffile[1] != '.' || !IS_DIR_SEP (nameoffile[2])))
+ {
+ unsigned i = 0;
+ while (fname[i + 2] != 0) {
+ fname[i] = fname[i + 2];
+ i++;
+ }
+ fname[i] = 0;
+ }
+
+ /* This fopen is not allowed to fail. */
+#if defined(PTEX) && !defined(WIN32)
+ if (filefmt == kpse_tex_format ||
+ filefmt == kpse_bib_format) {
+ *f_ptr = nkf_open (fname, fopen_mode);
+ } else
+#endif
+ *f_ptr = xfopen (fname, fopen_mode);
+
+ /* kpse_find_file always returns a new string. */
+#if defined(PTEX) && !defined(WIN32)
+ fname0 = ptenc_from_utf8_string_to_internal_enc(fname);
+ if (fname0) {
+ free (fname);
+ fname = fname0;
+ }
+#endif
+ free (nameoffile);
+ namelength = strlen (fname);
+ nameoffile = xmalloc (namelength + 2);
+ strcpy (nameoffile + 1, fname);
+ free (fname);
+ }
+ }
+ }
+
+ if (*f_ptr) {
+ recorder_record_input (nameoffile + 1);
+
+ /* If we just opened a TFM file, we have to read the first
+ byte, to pretend we're Pascal. See tex.ch and mp.ch.
+ Ditto for the ocp/ofm Omega file formats. */
+ if (filefmt == kpse_tfm_format) {
+ tfmtemp = getc (*f_ptr);
+ /* We intentionally do not check for EOF here, i.e., an
+ empty TFM file. TeX will see the 255 byte and complain
+ about a bad TFM file, which is what we want. */
+ } else if (filefmt == kpse_ocp_format) {
+ ocptemp = getc (*f_ptr);
+ } else if (filefmt == kpse_ofm_format) {
+ tfmtemp = getc (*f_ptr);
+ }
+ }
+
+ return *f_ptr != NULL;
+}
+
+
+/* Open input file *F_PTR (of type FILEFMT), prepending the directory
+ part of the string FNAME to `nameoffile'+1, unless that is already
+ kpse_absolute_p. This is called from BibTeX, to open subsidiary .aux
+ files, with FNAME set to the top-level aux file. The idea is that if
+ we're invoked as bibtex somedir/foo.aux, and foo.aux has an
+ \@input{bar} statement, we should look for somedir/bar.aux too. (See
+ bibtex-auxinclude.test.) */
+
+boolean
+open_input_with_dirname (FILE **f_ptr, int filefmt, const char *fname)
+{
+ boolean ret = false;
+ char *top_dir = xdirname (fname);
+
+ if (top_dir && *top_dir && !STREQ (top_dir, ".")
+ && !kpse_absolute_p (nameoffile+1, true)) {
+ char *newname = concat3 (top_dir, DIR_SEP_STRING, nameoffile+1);
+ free (nameoffile);
+ nameoffile = xmalloc (strlen (newname) + 2);
+ strcpy (nameoffile + 1, newname);
+ ret = open_input (f_ptr, filefmt, FOPEN_RBIN_MODE);
+ free (newname);
+ }
+
+ free (top_dir);
+ return ret;
+}
+
+
+/* Open an output file F either in the current directory or in
+ $TEXMFOUTPUT/F, if the environment variable `TEXMFOUTPUT' exists.
+ (Actually, this also applies to the BibTeX and MetaPost output files,
+ but `TEXMFMPBIBOUTPUT' was just too long.) The filename is in the
+ global `nameoffile' + 1. We return whether or not the open
+ succeeded. If it did, `nameoffile' is reset to the name opened if
+ necessary, and `namelength' to its length. */
+
+boolean
+open_output (FILE **f_ptr, const_string fopen_mode)
+{
+ string fname;
+#if defined(PTEX) && !defined(WIN32)
+ string fname0;
+#endif
+ boolean absolute = kpse_absolute_p(nameoffile+1, false);
+
+ /* If we have an explicit output directory, use it. */
+ if (output_directory && !absolute) {
+ fname = concat3(output_directory, DIR_SEP_STRING, nameoffile + 1);
+ } else {
+ fname = nameoffile + 1;
+ }
+#if defined(PTEX) && !defined(WIN32)
+ fname0 = ptenc_from_internal_enc_string_to_utf8(fname);
+ if (fname0) {
+ if (fname != nameoffile + 1) free(fname);
+ fname = fname0;
+ }
+#endif
+
+ /* Is the filename openable as given? */
+ *f_ptr = fopen (fname, fopen_mode);
+
+ if (!*f_ptr) {
+ /* Can't open as given. Try the envvar. */
+ string texmfoutput = kpse_var_value("TEXMFOUTPUT");
+
+ if (texmfoutput && *texmfoutput && !absolute) {
+ if (fname != nameoffile + 1)
+ free(fname);
+ fname = concat3(texmfoutput, DIR_SEP_STRING, nameoffile+1);
+ *f_ptr = fopen(fname, fopen_mode);
+ }
+ }
+ /* If this succeeded, change nameoffile accordingly. */
+ if (*f_ptr) {
+ if (fname != nameoffile + 1) {
+#if defined(PTEX) && !defined(WIN32)
+ fname0 = ptenc_from_utf8_string_to_internal_enc(fname);
+ if (fname0) {
+ free(fname);
+ fname = fname0;
+ }
+#endif
+ free (nameoffile);
+ namelength = strlen (fname);
+ nameoffile = xmalloc (namelength + 2);
+ strcpy (nameoffile + 1, fname);
+ }
+ recorder_record_output (fname);
+ }
+ if (fname != nameoffile +1)
+ free(fname);
+ return *f_ptr != NULL;
+}
+
+/* Close F. */
+
+void
+close_file (FILE *f)
+{
+ /* If F is null, just return. bad_pool might close a file that has
+ never been opened. */
+ if (!f)
+ return;
+
+#ifdef PTEX
+#ifdef WIN32
+ clear_infile_enc (f);
+ if (fclose (f) == EOF) {
+#else
+ if (nkf_close (f) == EOF) {
+#endif
+#else
+ if (fclose (f) == EOF) {
+#endif
+ /* It's not always nameoffile, we might have opened something else
+ in the meantime. And it's not easy to extract the filenames out
+ of the pool array. So just punt on the filename. Sigh. This
+ probably doesn't need to be a fatal error. */
+ perror ("fclose");
+ }
+}