Back to index

tetex-bin  3.0
openclose.c
Go to the documentation of this file.
00001 /* openclose.c: open and close files for TeX, Metafont, and BibTeX.
00002 
00003    Written 1995, 96 Karl Berry.  Public domain.  */
00004 
00005 #include "config.h"
00006 #include <kpathsea/c-pathch.h>
00007 #include <kpathsea/tex-file.h>
00008 #include <kpathsea/variable.h>
00009 #include <kpathsea/absolute.h>
00010 
00011 /* The globals we use to communicate.  */
00012 extern string nameoffile;
00013 extern unsigned namelength;
00014 /* For "file:line:error style error messages. */
00015 extern string fullnameoffile;
00016 /* For the filename recorder. */
00017 extern boolean recorder_enabled;
00018 /* For the output-dir option. */
00019 extern string output_directory;
00020 
00021 /* Define some variables. */
00022 string fullnameoffile;       /* Defaults to NULL.  */
00023 static string recorder_name; /* Defaults to NULL.  */
00024 static FILE *recorder_file;  /* Defaults to NULL.  */
00025 boolean recorder_enabled;    /* Defaults to false. */
00026 string output_directory;     /* Defaults to NULL.  */
00027 
00028 /* For TeX and MetaPost.  See below.  Always defined so we don't have to
00029    #ifdef, and thus this file can be compiled once and go in lib.a.  */
00030 int tfmtemp;
00031 int ocptemp;
00032 int texinputtype;
00033 
00034 /* Helpers for the filename recorder... */
00035 /* Start the recorder */
00036 static void
00037 recorder_start()
00038 {
00039     /* Alas, while we might want to use mkstemp it is not portable.
00040        So we have to be content with using a default name... */
00041     string cwd;
00042     recorder_name = (string)xmalloc(strlen(kpse_program_name)+5);
00043     strcpy(recorder_name, kpse_program_name);
00044     strcat(recorder_name, ".fls");
00045     recorder_file = xfopen(recorder_name, FOPEN_W_MODE);
00046     cwd = xgetcwd();
00047     fprintf(recorder_file, "PWD %s\n", cwd);
00048     free(cwd);
00049 }
00050 
00051 /* Change the name of the recorder file. */
00052 void
00053 recorder_change_filename P1C(string, new_name)
00054 {
00055    if (!recorder_file)
00056      return;
00057    rename(recorder_name, new_name);
00058    free(recorder_name);
00059    recorder_name = xstrdup(new_name);
00060 }
00061 
00062 /* Open an input file F, using the kpathsea format FILEFMT and passing
00063    FOPEN_MODE to fopen.  The filename is in `nameoffile+1'.  We return
00064    whether or not the open succeeded.  If it did, `nameoffile' is set to
00065    the full filename opened, and `namelength' to its length.  */
00066 
00067 boolean
00068 open_input P3C(FILE **, f_ptr,  int, filefmt,  const_string, fopen_mode)
00069 {
00070     string fname = NULL;
00071 #ifdef FUNNY_CORE_DUMP
00072     /* This only applies if a preloaded TeX/Metafont is being made;
00073        it allows automatic creation of the core dump (typing ^\ loses
00074        since that requires manual intervention).  */
00075     if ((filefmt == kpse_tex_format || filefmt == kpse_mf_format
00076          || filefmt == kpse_mp_format)
00077         && STREQ (nameoffile + 1, "HackyInputFileNameForCoreDump.tex"))
00078         funny_core_dump ();
00079 #endif
00080 
00081     /* We havent found anything yet. */
00082     *f_ptr = NULL;
00083     if (fullnameoffile)
00084         free(fullnameoffile);
00085     fullnameoffile = NULL;
00086     
00087     /* Handle -output-directory.
00088        FIXME: We assume that it is OK to look here first.  Possibly it
00089        would be better to replace lookups in "." with lookups in the
00090        output_directory followed by "." but to do this requires much more
00091        invasive surgery in libkpathsea.  */
00092     if (output_directory) {
00093         fname = concat3(output_directory, DIR_SEP_STRING, nameoffile + 1);
00094         *f_ptr = fopen(fname, fopen_mode);
00095         if (*f_ptr) {
00096             free(nameoffile);
00097             namelength = strlen (fname);
00098             nameoffile = (string)xmalloc (namelength + 2);
00099             strcpy (nameoffile + 1, fname);
00100             fullnameoffile = fname;
00101         } else {
00102             free(fname);
00103         }
00104     }
00105 
00106     /* No file means do the normal search. */
00107     if (*f_ptr == NULL) {
00108         /* A negative FILEFMT means don't use a path.  */
00109         if (filefmt < 0) {
00110             /* no_file_path, for BibTeX .aux files and MetaPost things.  */
00111             *f_ptr = fopen(nameoffile + 1, fopen_mode);
00112             /* FIXME... fullnameoffile = xstrdup(nameoffile + 1); */
00113         } else {
00114             /* The only exception to `must_exist' being true is \openin, for
00115                which we set `tex_input_type' to 0 in the change file.  */
00116             /* According to the pdfTeX people, pounding the disk for .vf files
00117                is overkill as well.  A more general solution would be nice. */
00118             boolean must_exist = (filefmt != kpse_tex_format || texinputtype)
00119                     && (filefmt != kpse_vf_format);
00120             fname = kpse_find_file (nameoffile + 1,
00121                                     (kpse_file_format_type)filefmt,
00122                                     must_exist);
00123             if (fname) {
00124                 fullnameoffile = xstrdup(fname);
00125                 /* If we found the file in the current directory, don't leave
00126                    the `./' at the beginning of `nameoffile', since it looks
00127                    dumb when `tex foo' says `(./foo.tex ... )'.  On the other
00128                    hand, if the user said `tex ./foo', and that's what we
00129                    opened, then keep it -- the user specified it, so we
00130                    shouldn't remove it.  */
00131                 if (fname[0] == '.' && IS_DIR_SEP (fname[1])
00132                     && (nameoffile[1] != '.' || !IS_DIR_SEP (nameoffile[2])))
00133                 {
00134                     unsigned i = 0;
00135                     while (fname[i + 2] != 0) {
00136                         fname[i] = fname[i + 2];
00137                         i++;
00138                     }
00139                     fname[i] = 0;
00140                 }
00141 
00142                 /* FIXME: Can kpse_find_file ever return the name it was
00143                    given?  Otherwise the following can be unconditional. */
00144                 if (nameoffile + 1 != fname) {
00145                     free (nameoffile);
00146                     namelength = strlen (fname);
00147                     nameoffile = (string)xmalloc (namelength + 2);
00148                     strcpy (nameoffile + 1, fname);
00149                     free (fname);
00150                 }
00151 
00152                 /* This fopen is not allowed to fail. */
00153                 *f_ptr = xfopen (nameoffile + 1, fopen_mode);
00154             }
00155         }
00156     }
00157 
00158     if (*f_ptr) {
00159         if (recorder_enabled) {
00160             if (!recorder_file)
00161                 recorder_start();
00162             fprintf(recorder_file, "INPUT %s\n", nameoffile + 1);
00163         }
00164 
00165         /* If we just opened a TFM file, we have to read the first
00166            byte, to pretend we're Pascal.  See tex.ch and mp.ch.
00167            Ditto for the ocp/ofm Omega file formats.  */
00168         if (filefmt == kpse_tfm_format) {
00169             tfmtemp = getc (*f_ptr);
00170             /* We intentionally do not check for EOF here, i.e., an
00171                empty TFM file.  TeX will see the 255 byte and complain
00172                about a bad TFM file, which is what we want.  */
00173         } else if (filefmt == kpse_ocp_format) {
00174             ocptemp = getc (*f_ptr);
00175         } else if (filefmt == kpse_ofm_format) {
00176             tfmtemp = getc (*f_ptr);
00177         }
00178     }            
00179 
00180     return *f_ptr != NULL;
00181 }
00182 
00183 /* Open an output file F either in the current directory or in
00184    $TEXMFOUTPUT/F, if the environment variable `TEXMFOUTPUT' exists.
00185    (Actually, this also applies to the BibTeX and MetaPost output files,
00186    but `TEXMFMPBIBOUTPUT' was just too long.)  The filename is in the
00187    global `nameoffile' + 1.  We return whether or not the open
00188    succeeded.  If it did, `nameoffile' is reset to the name opened if
00189    necessary, and `namelength' to its length.  */
00190 
00191 boolean
00192 open_output P2C(FILE **, f_ptr,  const_string, fopen_mode)
00193 {
00194     string fname;
00195     boolean absolute = kpse_absolute_p(nameoffile+1, false);
00196 
00197     /* If we have an explicit output directory, use it. */
00198     if (output_directory && !absolute) {
00199         fname = concat3(output_directory, DIR_SEP_STRING, nameoffile + 1);
00200     } else {
00201         fname = nameoffile + 1;
00202     }
00203 
00204     /* Is the filename openable as given?  */
00205     *f_ptr = fopen (fname, fopen_mode);
00206 
00207     if (!*f_ptr) {
00208         /* Can't open as given.  Try the envvar.  */
00209         string texmfoutput = kpse_var_value("TEXMFOUTPUT");
00210 
00211         if (texmfoutput && *texmfoutput && !absolute) {
00212             string fname = concat3(texmfoutput, DIR_SEP_STRING, nameoffile+1);
00213             *f_ptr = fopen(fname, fopen_mode);
00214         }
00215     }
00216     /* If this succeeded, change nameoffile accordingly.  */
00217     if (*f_ptr) {
00218         if (fname != nameoffile + 1) {
00219             free (nameoffile);
00220             namelength = strlen (fname);
00221             nameoffile = (string)xmalloc (namelength + 2);
00222             strcpy (nameoffile + 1, fname);
00223         }
00224         if (recorder_enabled) {
00225             if (!recorder_file)
00226                 recorder_start();
00227             fprintf(recorder_file, "OUTPUT %s\n", fname);
00228         }
00229     }
00230     if (fname != nameoffile +1)
00231         free(fname);
00232     return *f_ptr != NULL;
00233 }
00234 
00235 /* Close F.  */
00236 
00237 void
00238 aclose P1C(FILE *, f)
00239 {
00240   /* If F is null, just return.  bad_pool might close a file that has
00241      never been opened.  */
00242   if (!f)
00243     return;
00244     
00245   if (fclose (f) == EOF) {
00246     /* It's not always nameoffile, we might have opened something else
00247        in the meantime.  And it's not easy to extract the filenames out
00248        of the pool array.  So just punt on the filename.  Sigh.  This
00249        probably doesn't need to be a fatal error.  */
00250     perror ("fclose");
00251   }
00252 }