/* openinout.c: open input and output files.  These routines used by
   TeX, Metafont, and BibTeX.  */

#include "config.h"
#include "c-namemx.h"
#include "c-pathch.h"

#ifdef BibTeX
/* See comments in bibtex.ch for why we need these.  */
FILE *standardinput = stdin;
FILE *standardoutput = stdout;

/* Because we don't generate a .h file with all the global definitions
   for BibTeX, as we do with TeX and Metafont, we must declare these
   variables.  */
extern char nameoffile[];
extern integer namelength;

#else /* not BibTeX */

#define EXTERN extern /* Don't instantiate data here.  */

#ifdef TeX
#include "texd.h"
#else /* Metafont */
#include "mfd.h"
#endif

#ifdef FUNNY_CORE_DUMP
/* This is defined in ./texmf.c.  */
extern void funny_core_dump ();
#endif /* FUNNY_CORE_DUMP */

#endif /* not BibTeX */

/* Open an input file F, using the path PATHSPEC and passing
   FOPEN_MODE to fopen.  The filename is in `nameoffile', as a Pascal
   string. We return whether or not the open succeeded.  If it did, we
   also set `namelength' to the length of the full pathname that we
   opened.  */

boolean
open_input (f, path_index, fopen_mode)
  FILE **f;
  path_constant_type path_index;
  char *fopen_mode;
{
  boolean openable = false;

#if defined (FUNNY_CORE_DUMP) && !defined (BibTeX)
  /* This only applies if a preloaded TeX (or Metafont) is being made;
     it allows for automatic creation of the core dump (typing ^\
     requires manual intervention).  */
  if (path_index == TEXINPUTPATH
      && strncmp (nameoffile+1, "HackyInputFileNameForCoreDump.tex", 33) == 0)
    funny_core_dump ();
#endif /* FUNNY_CORE_DUMP and not BibTeX */

#ifdef BibTeX
  if (path_index == NO_FILE_PATH)
    {
      unsigned temp_length;

      null_terminate (nameoffile + 1);
      *f = fopen (nameoffile + 1, fopen_mode);
      temp_length = strlen (nameoffile + 1);
      space_terminate (nameoffile + 1);
      if (*f != NULL)
        {
          namelength = temp_length;
          openable = true;
        }
    }

  else
#endif /* BibTeX */
  
  if (testreadaccess (nameoffile, path_index))
    {
      /* We can assume `nameoffile' is openable, since
         `testreadaccess' just returned true.  */
      *f = xfopen_pas (nameoffile, fopen_mode);
      
      /* If we found the file in the current directory, don't leave the
         `./' at the beginning of `nameoffile', since it looks dumb when
         TeX says `(./foo.tex ... )', and analogously for Metafont.  */
      if (nameoffile[1] == '.' && nameoffile[2] == PATH_SEP)
        {
          unsigned i = 1;
          while (nameoffile[i + 2] != ' ')
            {
              nameoffile[i] = nameoffile[i + 2];
              i++;
            }
          nameoffile[i] = ' ';
          namelength = i - 1;
        }
      else
        namelength = strchr (nameoffile + 1, ' ') - nameoffile - 1;
      
#ifdef TeX
      /* If we just opened a TFM file, we have to read the first byte,
         since TeX wants to look at it.  What a kludge.  */
      if (path_index == TFMFILEPATH)
        { /* See comments in ctex.ch for why we need this.  */
          extern integer tfmtemp;
          tfmtemp = getc (*f);
        }
#endif /* TeX */  

      openable = true;
    }

  return openable;
}


/* Call the external program PROGRAM, passing it `nameoffile'.  */

static boolean
make_tex_file (program)
    string program;
{
#ifdef NO_MAKETEX
  return 0;
#else
  char cmd[NAME_MAX + 1 + PATH_MAX + 1];
  unsigned cmd_len;
  int ret;
  unsigned i = 1; /* For copying from `nameoffile'.  */

  /* Wrap another sh around the invocation of the MakeTeX program, so we
     can avoid `sh: MakeTeXTFM: not found' errors confusing the user.
     We don't use fork/exec ourselves, since we'd have to call sh anyway
     to interpret the script.  */
  strcpy (cmd, "sh -c \"");
  
  strcat (cmd, program);
  cmd_len = strlen (cmd);
  cmd[cmd_len++] = ' ';

  while (nameoffile[i] != ' ')
    cmd[cmd_len++] = nameoffile[i++];

  /* Add terminating null.  */
  cmd[cmd_len] = 0;

  /* Don't show any output.  */
  strcat (cmd, "\">/dev/null 2>&1");

  /* Run the command, and return whether or not it succeeded.  */
  ret = system (cmd);
  return ret == EXIT_SUCCESS_CODE;
#endif /* not NO_MAKE_TEX */
}


/* This is called by TeX if an \input resp. TFM file can't be opened.  */

boolean
maketextex ()
{
  return make_tex_file ("MakeTeXTeX");
}

boolean
maketextfm ()
{
  return make_tex_file ("MakeTeXTFM");
}

boolean
maketexmf ()
{
  return make_tex_file ("MakeTeXMF");
}

/* Open an output file F either in the current directory or in
   $TEXMFOUTPUT/F, if the environment variable `TEXMFOUTPUT' exists.
   (Actually, this applies to the BibTeX output files, also, but
   `TEXMFBIBOUTPUT' was just too long.)  The filename is in the global
   `nameoffile', as a Pascal string.  We return whether or not the open
   succeeded.  If it did, the global `namelength' is set to the length
   of the actual filename.  */

boolean
open_output (f, fopen_mode)
  FILE **f;
  char *fopen_mode;
{
  unsigned temp_length;

  /* Make the filename into a C string.  */
  null_terminate (nameoffile + 1);
  
  /* Is the filename openable as given?  */
  *f = fopen (nameoffile + 1, fopen_mode);

  if (*f == NULL)
    { /* Can't open as given.  Try the envvar.  */
      string temp_dir = getenv ("TEXMFOUTPUT");

      if (temp_dir != NULL)
        {
          string temp_name = concat3 (temp_dir, "/", nameoffile + 1);
          *f = fopen (temp_name, fopen_mode);
          
          /* If this succeeded, change nameoffile accordingly.  */
          if (*f)
            strcpy (nameoffile + 1, temp_name);
          
          free (temp_name);
        }
    }

  /* Back into a Pascal string, but first get its length.  */
  temp_length = strlen (nameoffile + 1);
  space_terminate (nameoffile + 1);

  /* Only set `namelength' if we succeeded.  I'm not sure why.  */
  if (*f)
    namelength = temp_length;
  
  return *f != NULL;
}

/* Test if the Pascal string BASE concatenated with the extension
   `.SUFFIX' is the same file as just BASE.  SUFFIX is a C string.  */

boolean
extensionirrelevantp (base, suffix)
  char *base;
  char *suffix;
{
  boolean ret;
  char temp[PATH_MAX];
  
  make_c_string (&base);
  strcpy (temp, base);
  strcat (temp, ".");
  strcat (temp, suffix);
  
  ret = same_file_p (base, temp);
  make_pascal_string (&base);
  
  return ret;
}
