/*dopen.c,v 1.3 1994/01/06 14:32:26 mcr Exp*/

/* dopen() is a massively system-dependent function, so I've placed
 * it in a separate file.
 */

/* Macros used...
 *
 *  IS_ABS   -- a macro that returns nonzero if the string argument is an
 *              absolute path, or 0 if it is a relative path.
 *  PATH_STR -- a string of characters which separate directory components.
 *  SUF_STR  -- suffix for configuration files
 *  PATH_SEP -- character to separate directory from filename.
 *  LIST_SEP -- character that separates pathnames in a list.
 *  exists(f) -- returns nonzero if the file f exists.
 *		if not defined, then use fopen to determine existence.
 *  HAS_ENV  -- if defined, environment variables are searched.
 *
 */

/*
 *  Our algorithm is to try the following in sequence, until one works.
 *
 *  The filename as-is.
 *  The filename with SUF_STR appended.
 *
 *  If IS_ABS returns nonzero, then fail.
 *
 *  Else, we call the system-dependent get_dir() function.  Each call
 *  provides a directory to look in.
 *
 *  For each directory, append the filename (perhaps inserting the
 *  PATH_SEP).  If that fails, try again after appending SUF_STR.
 *
 *  When we run out of directories, we fail.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>

#ifdef UNIX
#define HAS_ENV
#define exists(f) (access(f, 0) == 0)
#define IS_ABS(f) (*f == '/')
#define SUF_STR ".cfg"
#define PATH_SEP '/'
#define PATH_STR "/"
#define LIST_SEP ':'
#endif

#ifdef MSDOS
#define HAS_ENV
#include <io.h>
#define exists(f) (access(f, 0) == 0)
#define IS_ABS(f) (f[1] == ':' || strchr(PATH_STR, *f))
#define SUF_STR ".cfg"
#define PATH_SEP '/'
#define PATH_STR "/\\:"
#define LIST_SEP ';'
#endif

#ifdef VMS				/* VMS is really different */
#define IS_ABS(f) (strchr(f, ':') || strchr(PATH_STR, *f))
#define SUF_STR ".cfg"
#define PATH_SEP '.'
#define PATH_STR "[.]"
#endif

#ifdef AMIGA
#define IS_ABS(f) (strchr(f, ':') || *f == '/')
#define SUF_STR ".cfg"
#define PATH_SEP '/'
#define PATH_STR "/"
#endif

/* If user specified no operating system, be very pessimistic.
 * Don't do anything beyond adding the `.cfg. suffix.
 */
#ifndef SUF_STR
#define IS_ABS 1
#define SUF_STR ".cfg"
#undef PATH_SEP
#undef PATH_STR
#undef HAS_ENV
#endif

/* If we don't have an exists(), then we'll just use fopen. */
#ifndef exists
#define exists(f) (descriptor = fopen(f, "rt"))
#endif

#ifdef HAS_ENV
/* We search a handful of environment variables */
const char *envlist[] = { "PATH", "DPATH", "WP2XDIR", NULL };

char *get_dir(void)
{
    static const char **nextenv = envlist;
    static char *nextpath = NULL;
    char *s;

    /* get the next environment variable */
    while (nextpath == NULL || *nextpath == '\0') {
	if (*nextenv == NULL) return NULL;  /* out of ideas */
	nextpath = getenv(*nextenv++);
	if(nextpath) {
	  nextpath=strdup(nextpath);
	}
    }
    
    s=nextpath;
    while (*nextpath && *nextpath != LIST_SEP) nextpath++;
    if (*nextpath) {
      *nextpath='\0';
      nextpath++;
    }

    return s;	/* return pointer to start of string */
}
#else
/* On non-UNIX systems, we don't have environment variables. */
/* We might have other things, though, so insert your local version here */
char *get_dir(void) { return NULL; }
#endif

/* s is where to copy the filename, and f is the filename to try. */
FILE *try_directory(char *dir, const char *f)
{
  int  dirlen;
  char *buf;
  FILE *d;

  dirlen=strlen(dir);
  buf=alloca(dirlen+strlen(f)+9);	/* need SUF_STR too */

  strcpy(buf,dir);
  if(buf[dirlen-1]!=PATH_SEP) {
    buf[dirlen++]=PATH_SEP;
    buf[dirlen]='\0';
  }
  strcat(buf, f);

  if(exists(buf)) {
    d = fopen(buf, "r");
    return d;
  }
  strcat(buf, SUF_STR);
  if(exists(buf)) {
    d = fopen(buf, "r");
    return d;
  }
  return NULL;
}

FILE *dopen(const char *f)
{
    char *s;
    FILE *d;

    /* First, try it as-is */
    if ((d=try_directory("", f))!=NULL) return d;

#ifdef WP2X_DIR
    if ((d=try_directory(WP2X_DIR, f))!=NULL) return d;
#endif

    /* Skip if an absolute path */
    if (!IS_ABS(f)) {
      /* Iterate through the possible directories */
      while (s = get_dir()) {
	if ((d=try_directory(s, f))!=NULL) return d;
      }
    }
    error(NULL, "Cannot find file %s\n", f);
    return NULL;
}
