/* $Id$ */
/* openclose.c: open and close files for TeX, Metafont, and BibTeX.

   Written 1995, 96 Karl Berry.  Public domain.

   Large portions rewritten for RISC OS by Jakob Stoklund Olesen.
 */

#include "config.h"
#include "kpathsea:absolute.h"
#include "kpathsea:c-pathch.h"
#include "kpathsea:tex-file.h"
#include "kpathsea:variable.h"
#include "kpathsea:riscos.h"
#include "OS:osfile.h"

/* The globals we use to communicate.  */
extern string nameoffile;
extern unsigned namelength;

/*
   Set the Pascal variables nameoffile and namelength from fname and free fname.
   riscos_prefix is stripped from the front if strip is set
 */
static void
set_nameoffile (string fname, boolean strip)
{
  /* Discard the old name */
  free (nameoffile);

  /* Strip riscos_prefix from fname if simple file requested */
  if (strip && riscos_prefix_length > 0
      && FILESTRNCASEEQ (riscos_prefix, fname, riscos_prefix_length))
    {
      /* OK, remove prefix_length characters from fname */
      namelength = strlen (fname + riscos_prefix_length);
      memmove (fname + 1, fname + riscos_prefix_length, namelength + 1);
      nameoffile = xrealloc (fname, namelength + 2);
    }
  else
    {
      namelength = strlen (fname);
      nameoffile = xrealloc (fname, namelength + 2);
      memmove (nameoffile + 1, nameoffile, namelength + 1);
    }
}

/* 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;

/* File opening functions */
typedef void *(*openin_func) (const char *name);
typedef void *(*openout_func) (const char *name, int filetype);

static void *
openin_stdio (const char *name)
{
  return fopen (name, "r");
}

static void *
openout_stdio (const char *name, int filetype)
{
  os_error *erp;

  /* Since we're going to do fopen("w") we might as well create the file */
  erp = xosfile_create_stamped (name, filetype, 0);
  if (erp)
    {
      errno_swi (erp);
      return NULL;
    }

  return fopen (name, "w");
}

/* Open an input file F, 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
generic_open_input (void **f_ptr, kpse_file_format_type filefmt,
		    openin_func open)
{
  string fname;
  boolean absolute_p = kpse_absolute_p (nameoffile + 1, true);

  /* A negative FILEFMT means don't use a path.  */
  if ((int) filefmt < 0)
    {
      /* no_file_path, for BibTeX .aux files and MetaPost things.  */
      fname = riscos_translate_input (nameoffile + 1);
    }
  else
    {
      /* The only exception to `must_exist' being true is \openin, for which
         we set `tex_input_type' to 1 in the change file.  */
      boolean must_exist = filefmt != kpse_tex_format || texinputtype;

      fname = kpse_find_file (nameoffile + 1, filefmt, must_exist);
    }

  if (fname)
    {
      /* We must use the given filename */
      *f_ptr = open (fname);

      /* set nameoffile and free fname */
      set_nameoffile (fname, !absolute_p);

    }
  else
    *f_ptr = NULL;

  return *f_ptr != NULL;
}

/* Open a stdio file for input */
boolean
open_input (FILE ** f_ptr, kpse_file_format_type filefmt)
{
  boolean ret = generic_open_input ((void **) f_ptr, filefmt, openin_stdio);

  /* 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 (ret)
    {
      if (filefmt == kpse_tfm_format || filefmt == kpse_ofm_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);
	}
    }
  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
generic_open_output (void **f_ptr, int filetype, openout_func open)
{
  string tname;
  boolean absolute_p = kpse_absolute_p (nameoffile + 1, true);

  /* Is the filename openable as given?  */
  tname = riscos_translate_output (nameoffile + 1);
  if (tname != NULL)
    *f_ptr = open (tname, filetype);
  else
    *f_ptr = NULL;

  if (!*f_ptr)
    {
      /* Can't open as given.  Try the envvar.  */
      string texmfoutput = kpse_var_value ("TEXMFOUTPUT");

      if (tname != NULL)
	{
	  /* Hmm, translate works but fopen didn't, trouble! */
	  free (tname);
	  tname = NULL;
	}
      if (texmfoutput && *texmfoutput)
	{
	  string fname = concat3 (texmfoutput, DIR_SEP_STRING, nameoffile + 1);
	  tname = riscos_translate_output (fname);
	  free (fname);
	  if (tname != NULL)
	    *f_ptr = open (tname, filetype);
	}
    }

  /* If this succeeded, change nameoffile accordingly.  */
  if (*f_ptr)
    set_nameoffile (tname, !absolute_p);
  else if (tname != NULL)
    free (tname);

  return *f_ptr != NULL;
}

/* Openout a stdio file */
boolean
open_output (FILE ** f_ptr, int filetype)
{
  return generic_open_output ((void **) f_ptr, filetype, openout_stdio);
}


/* Close F.  */

void
aclose (FILE * f)
{
  /* If F is null, just return.  bad_pool might close a file that has never
     been opened.  */
  if (!f)
    return;

  if (fclose (f) == EOF)
    {
/* 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");
    }
}

