/*
 * nuetc.c - extra stuff; mostly system-dependent subroutines.
 *
 * NuLib v3.2  March 1992  Freeware (distribute, don't sell)
 * By Andy McFadden (fadden@netcom.com)
 *
 * $Id: nuetc.c,v 1.5 1996/11/28 07:48:29 gdr Exp $
 */

#define SEGMENT_NAME "NuMain____"

#include "nudefs.h"
#include <stdio.h>
#include <stdlib.h>	   /* exit(), etc. */
#include <string.h>
#include <fcntl.h>
#include <errno.h>	  /* errno declarations */
#include <ctype.h>	  /* for tolower(), isupper() */

#ifdef UNIX
# include <time.h>	  /* need localtime() */
# include <sys/types.h>   /* defn of time_t */
# include <sys/time.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
#ifdef __ORCAC__
# include <time.h>
# include <gsos.h>
# include <shell.h>
#endif
#ifdef APW
# include <types.h>	   /* has _toolErr in it */
# include <prodos.h>
# include "apwerr.h"	   /* APW/ProDOS error codes */
#endif
#ifdef MSDOS
# include <process.h>
# include <io.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <time.h>
#endif

#ifdef __ORCAC__
#include <orca.h>
#endif

#if defined(__sun__) && !defined(__SVR4)
#include "sunos4.h"
#endif

#include "nuetc.h"
/* note "nuread.h" is not included... none of the routines here assume */
/* any knowledge of NuFX archives.                                     */

#ifdef APW
extern Time ReadTimeHex();  /* should be TimeRec, from misctool.h */
#endif

#if defined(__GNUC__) || defined(SUNOS4) || defined(hal) || defined(__SUNPRO_C)
extern char *mktemp __P((char *));
#endif

/* This is a generally available TEMPORARY filename buffer */
char tmpNameBuf[MAXFILENAME];


/******************** general misc routines ********************/

/*
 * Fatal error handler
 */
void
#ifdef __STDC__
Fatal (char *deathstr, char *procName)
#else
Fatal(deathstr, procName)
char *deathstr, *procName;
#endif
{
    fflush(stdout);
    fprintf(stderr, "\n%s: fatal error: %s\n--- ", prgName, deathstr);
    perror(procName);
    QuitNulib (-1);
}


/*
 * QuitNulib can be used to perform cleanup operations before exiting.
 */
void
#ifdef __STDC__
QuitNulib (int val)
#else
QuitNulib (val)
int val;
#endif
{
    exit(val);
}


/*
 * Safe malloc()... checks return value
 */
char *

#ifdef __STDC__
Malloc __P((size_t size))
#else
Malloc (size)
     size_t size;
#endif
{
    char *ptr = (char *) malloc(size);

    if (ptr != (char *) NULL) {
	return(ptr);
    } else {
	/* 8910.31 - RBH: report byte size that failed */
	printf("Malloc: memory alloc error [%lu : bytes]\n", 
	       (unsigned long) size);
#ifdef MSDOS
	/* (this doesn't work under Turbo C - MSC only) */
	printf("(Largest Available Block: %u)\n", _memmax());
#endif
	QuitNulib (-1);
	/*NOTREACHED*/
    }
#ifdef __lint
    return NULL;
#endif
    /*NOTREACHED*/
}

/******************** UNIX compatibility routines ********************/

#ifdef UNIX
/*
 * Convert expanded date to a number of seconds for UNIX systems.
 *
 * Remember that *atime follows the NuFX docs for time values, which
 * don't necessarily match those in UNIX manual pages.
 * Adapted from _Advanced UNIX Programming_ by Marc J. Rochkind.
 *
 * Returns 0 if date/time is invalid.
 */
long
#ifdef __STDC__
timecvt (Time *atime)
#else
timecvt (atime)
Time *atime;
#endif
{
#ifdef __STDC__
    time_t tm;
#else
    long tm;
#endif
    int days;
    BOOLEAN isleapyear;
    int tzone;
    char *tz;

    if ((tz = getenv("TZ")) == NULL)
	tzone = 8;  /* pacific std time */
    else
	tzone = atoi(&tz[3]);

    isleapyear = (atime->year != 0) && (atime->year%4 == 0);  /* 2000 isn't */
    if (atime->year < 70)
	atime->year += 100;  /* years after 2000 */
    days = (atime->year - 70) * 365L;
    days += ((atime->year - 69L) / 4);  /* previous years' leap days */

    switch (atime->month +1) {  /* month is 0-11 */
    case 12:
	days += 30;  /* Nov */
    case 11:
	days += 31;  /* Oct */
    case 10:
	days += 30;  /* Sep */
    case 9:
	days += 31;  /* Aug */
    case 8:
	days += 31;  /* Jul */
    case 7:
	days += 30;  /* Jun */
    case 6:
	days += 31;  /* May */
    case 5:
	days += 30;  /* Apr */
    case 4:
	days += 31;  /* Mar */
    case 3:
	days += (isleapyear ? 29 : 28);  /* Feb */
    case 2:
	days += 31;  /* Jan */
    case 1:
	break;
    default:
	/*printf("Invalid month\n");*/
	return (0L);
    }

    if (atime->day > 31) {
	/*printf("Invalid day\n");*/
	return (0L);
    }
    tm = (days + atime->day) * 24L * 60L * 60L;

    if (atime->hour > 23) {
	/*printf("Invalid hour\n");*/
	return (0L);
    }
    atime->hour += tzone;  /* correct for time zone */
    tm += atime->hour * 60L * 60L;

    if (atime->minute > 59) {
	/*printf("Invalid minute\n");*/
	return (0L);
    }
    tm += atime->minute * 60L;

    if (atime->second > 59) {
	/*printf("Invalid second\n");*/
	return (0L);
    }
    tm += atime->second;

    if (localtime(&tm)->tm_isdst)  /* was that day in dst? */
	tm -= 60L * 60L;  /* adjust for daylight savings */
    return (tm);
}
#endif /* UNIX */

/******************** APW compatibility routines ********************/

#ifdef APW
/*
 * Normally a C library function to print out a description of the most
 * recent system (non-toolbox, non-ProDOS) error.  Exists under UNIX and
 * MS C 5.1, so I'm assuming it exists most everywhere else...
 */
void
#ifdef __STDC__
perror(const char *errstr)
#else
perror(errstr)
const char *errstr;
#endif
{
    fflush(stdout);
    if ( (errno > 0) && (errno < sys_nerr) ) {	/* known APW error? */
	fprintf(stderr, "%s: %s\n", errstr, sys_errlist[errno]);
    } else {
	fprintf(stderr, "%s: ", errstr);
	fflush(stderr);
	ERROR( errno );
    }
    QuitNulib (-1);
}
#endif /* APW */

#if defined(APW)
/* Check for //gs toolbox errors; all are fatal */
void
#ifdef __STDC__
ToolErrChk (void)
#else
ToolErrChk()
#endif
{
    int err = _toolErr;

    if (err) {
	if (err < MPErr) {  /* was a ProDOS error? */
	    fprintf(stderr, "Error: $%.2x %s\n", (char) err,
		ProDOSErr[err]);
	} else {
	    fprintf(stderr, "Tool err ($%.4x): ", err);
	    fflush(stderr);
	    ERROR( err );
	}
	QuitNulib (-1);
    }
}

#endif /* APW */

/******************** miscellaneous string routines ********************/

/*
 * Compare strings, ignoring case (may be in standard C lib; stricmp()?)
 */
int
#ifdef __STDC__
strcasecmp (register const char *str1, register const char *str2)
#else
strcasecmp(str1, str2)
register const char *str1, *str2;
#endif
{
    register char one, two;
    register int val;

    for ( ; *str1 && *str2; str1++, str2++) {
	one = (isupper(*str1) ? tolower(*str1) : *str1);
	two = (isupper(*str2) ? tolower(*str2) : *str2);
	if ((val = two - one))
	    return (val);
    }
    if (!(*str1) && !(*str2))  /* both zero -> equivalent */
	return (0);
    else {  /* one is shorter; return result */
	one = (isupper(*str1) ? tolower(*str1) : *str1);
	two = (isupper(*str2) ? tolower(*str2) : *str2);
	return (two - one);
    }
}

int
#ifdef __STDC__
strncasecmp (register const char *str1, register const char *str2, size_t num)
#else
strncasecmp (str1, str2, num)
register const char *str1, *str2;
int num;
#endif
{
    register int i;
    register char one, two;
    register int val;  /* keep going 'til no more registers... */

    for (i = 0; (i < num) && (*str1) && (*str2); i++, str1++, str2++) {
	one = (isupper(*str1) ? tolower(*str1) : *str1);
	two = (isupper(*str2) ? tolower(*str2) : *str2);
	if ((val = two - one))
	    return (val);
    }
    if (i == num)  /* first num characters are equal, so return zero */
	return (0);
    else {  /* one ended early; return result */
	one = (isupper(*str1) ? tolower(*str1) : *str1);
	two = (isupper(*str2) ? tolower(*str2) : *str2);
	return (two - one);
    }
}

/******************* file-related routines ********************/

/*
 * Do operating system-dependent CREATE stuff
 *
 * Creates a NuFX archive file, with type info where necessary.
 * Does not leave file open.
 */
void
#ifdef __STDC__
ArcfiCreate(char *filename)
#else
ArcfiCreate(filename)
char *filename;
#endif
{
    static char *procName = "ArcfiCreate";
#ifdef __ORCAC__
    static CreateRecPtrGS crec;

    if ((crec = malloc(sizeof(CreateRecGS))) == NULL) {
      perror("ArcfiCreate failed");
      QuitNulib(-1);
    }
    if ((crec->pathname = __C2GSMALLOC(filename)) == NULL) {
      perror("ArcfiCreate failed");
      QuitNulib(-1);
    }
    crec->pCount   = 4;
    crec->access   = 0x00e3;  /* unlocked, visible */
    crec->fileType = 0x00e0;  /* LBR */
    crec->auxType  = 0x8002;  /* SHK */

    CreateGS(crec);
    if (_toolErr) {
      errno = _mapErr(_toolErr);
      Fatal("Unable to create file", procName);
    }
#elif defined(UNIX) /* && !defined(__GNO__) */
    int fd;

    if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0)
	Fatal("Unable to create file", procName);
    close(fd);
#elif defined(APW)
    FileRec create_p;

    c2pstr(filename);
    create_p.pathname = filename;
    create_p.fAccess = 0x00e3;
    create_p.fileType = 0x00e0;  /* LBR */
    create_p.auxType = 0x8002;	 /* SHK */
    create_p.storageType = 0x0001;
    create_p.createDate = 0x0000;  /* let ProDOS fill in the blanks */
    create_p.createTime = 0x0000;
    CREATE( &create_p );
    ToolErrChk();
    p2cstr(filename);

#elif defined(MSDOS)
    int fd;

    if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0)
	Fatal("Unable to create file", procName);
    close(fd);

#else
    int fd;

    if ((fd = open(filename, O_CREAT|O_RDWR, (mode_t) WPERMS)) < 0)
	Fatal("Unable to create file", procName);
    close(fd);
#endif
}


/*
 * Determine if a file already exists.
 */
BOOLEAN
#ifdef __STDC__
Exists(char *filename)
#else
Exists(filename)
char *filename;
#endif
{
#if defined(MSDOS) || (defined(__ORCAC__) && !defined(__GNO__))
    static char *procName = "Exists";
#endif

#if defined(UNIX) && !defined(__GNO__)
    return (access(filename, F_OK) == 0) ? TRUE : FALSE;

#elif defined(__ORCAC__) /* && !defined(__GNO__) */
    static FileInfoRecGS frec;
    static GSString255 rbuf;
    int result;

    frec.pCount = 2;
    frec.pathname = __C2GSMALLOC(filename);
    
    GetFileInfoGS(&frec);
    switch (_toolErr) {
    case 0:
      result = TRUE;
      break;

    case devNotFound:
    case pathNotFound:
    case volNotFound:
      result = FALSE;
      break;

    default:
      printf("%s: GetFileInfoGS failed for %s: %s\n", procName,
	     filename, strerror(_mapErr(_toolErr)));
      QuitNulib(-1);
    }
    free(frec.pathname);
    return result;

#elif defined(APW)
    FileRec info_p;  /* check if file exists, is dir */
    int err;

    c2pstr(filename);
    info_p.pathname = filename;
    GET_FILE_INFO( &info_p );
    err = _toolErr;
    p2cstr(filename);
    if (err == pathNotFound || err == fileNotFound)
	return (FALSE);
    else if (!err)
	return (TRUE);
    else {
	_toolErr = err;
	ToolErrChk();
	return (TRUE);
    }
#elif defined(MSDOS)
    struct stat sm;

    if (stat(filename, &sm) < 0) {
       if (errno == ENOENT)  /* if doesn't exist, then okay */
           return (FALSE);
       else  /* some other problem killed stat(), probably serious */
           fprintf(stderr, "Unable to stat() '%s'\n", filename);
           Fatal("Bad stat()", procName); /*serious prob*/
    } else  /* successful call - file exists */
       return (TRUE);
#else
    printf("Need [other] Exists()\n");  /* +PORT+ */
    return (FALSE);
#endif
}


/*
 * Generate a temporary file name (system dependent).
 * Assumes space is allocated for buffer.
 */
char *
#ifdef __STDC__
MakeTemp(char *buffer)
#else
MakeTemp(buffer)
char *buffer;
#endif
{
#if 0
    static char *procName = "MakeTemp";
#endif

#ifdef UNIX
    strcpy(buffer, "nulb.tmpXXXXXX");
    return mktemp(buffer);

#elif defined(__ORCAC__)
    return tmpnam(NULL);

#elif defined(APW)
    int idx = 0;

    do {
        sprintf(buffer, "nulb.tmp%d", idx++);
    } while (Exists(buffer));
    return (buffer);

#elif defined(MSDOS)
    extern char *mktemp();

    strcpy(buffer, "nulbXXXX.tmp");
    return (mktemp(buffer));

#else
    strcpy(buffer, "nulb.tmp");  /* +PORT+ */
    return (buffer);
#endif
}

#ifdef NO_RENAME
/*
 * This is a replacement for the library call, in case somebody's C library
 * doesn't have it.
 */
int
#ifdef __STDC__
rename(char *fromname, char *toname)
#else
rename(fromname, toname)
     char *fromname;
     char *toname;
#endif
{
    if (link(fromname, toname) < 0)
	return (-1);
    if (unlink(fromname) < 0)
	return (-1);
}
#endif


/*
 * Rename a file.
 */
void
#ifdef __STDC__
Rename(char *fromname, char *toname)
#else
Rename(fromname, toname)
char *fromname, *toname;
#endif
{
    static char *procName = "Rename";
#ifdef __ORCAC__
    if (rename(fromname, toname) != 0) {
      fprintf(stderr,
	      "\n%s: WARNING: Unable to rename '%s' as '%s'\n",
	      prgName, fromname, toname);
      Fatal("Bad rename()", procName);
    }
#elif defined(UNIX)
    if (Exists(toname)) {
	fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n",
	    prgName, fromname, toname);
	fflush(stderr);
    }
# ifdef AOSVS					/* BAK 04/30/90 */
    printf("Work on AOS/VS rename command\n");	/* BAK 04/30/90 */
# else						/* BAK 04/30/90 */
    else {
	if (rename(fromname, toname) < 0) {  /* this should "never" fail */
	    fprintf(stderr,
		"\n%s: WARNING: Unable to rename '%s' as '%s'\n",
		prgName, fromname, toname);
	    Fatal("Bad rename()", procName); /*serious prob*/
	}
    }
# endif
#elif defined(APW)
    PathNameRec cpath_p;

    if (Exists(toname)) {
	fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n",
	    prgName, fromname, toname);
	fflush(stderr);
	return;
    }

    cpath_p.pathname = fromname;
    cpath_p.newPathname = toname;
    c2pstr(fromname);
    c2pstr(toname);
    CHANGE_PATH( &cpath_p );
    ToolErrChk();
    p2cstr(fromname);
    p2cstr(toname);
#elif defined(MSDOS)
    if (Exists(toname)) {
	fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n",
	    prgName, fromname, toname);
	fflush(stderr);
	return;
    }
    printf("Work on MSDOS rename command\n");
#else
    if (Exists(toname)) {
	fprintf(stderr, "\n%s: WARNING: Unable to rename '%s' as '%s'\n",
	    prgName, fromname, toname);
	fflush(stderr);
	return;
    }
    printf("Need [other] rename command\n");  /* +PORT+ */
#endif
}

/******************** date/time routines ********************/

/*
 * Expand date/time from file-sys dependent format to eight byte NuFX format.
 * tptr is filesys format, TimePtr is NuFX format
 */
void
#ifdef __STDC__
ExpandTime(void *tptr, Time *TimePtr)
#else
ExpandTime(tptr, TimePtr)	   /* (BSD) UNIX version */
onebyt *tptr;  /* usually points to a time_t (long) */
Time *TimePtr;
#endif
{
#if defined(UNIX) || defined(__ORCAC__)
    time_t *tp = (time_t *) tptr;
    struct tm *unixt;

    unixt = localtime(tp);  /* expand time_t into components */
    TimePtr->second = unixt->tm_sec;
    TimePtr->minute = unixt->tm_min;
    TimePtr->hour = unixt->tm_hour;
    TimePtr->year = unixt->tm_year;
    TimePtr->day = unixt->tm_mday -1;  /* want 0-xx, not 1-xx */
    TimePtr->month = unixt->tm_mon;
    TimePtr->extra = 0;
    TimePtr->weekDay = unixt->tm_wday +1;  /* Sunday = 1, not 0 like UNIX */
#else
# ifdef APW			    /* APW version */
    twobyt date, time;

    date = (twobyt)tptr[0] + ((twobyt)tptr[1] << 8);
    time = (twobyt)tptr[2] + ((twobyt)tptr[3] << 8);
    TimePtr->second = 0;  /* not stored in ProDOS file info */
    TimePtr->minute = (char) time;  /* truncated to char */
    TimePtr->hour = time >> 8;
    TimePtr->year = date >> 9;
    TimePtr->day = (date & 0x1f) - 1;
    TimePtr->month = ((date & 0x01e0) >> 5) - 1;
    TimePtr->extra = 0;
    TimePtr->weekDay = 0;
# endif /* APW */
# ifdef MSDOS
    struct tm *newtime;
    time_t *tp = (time_t *) tptr;

    newtime = localtime (tp);
    TimePtr->second = (onebyt)newtime->tm_sec;
    TimePtr->minute = (onebyt)newtime->tm_min;
    TimePtr->hour   = (onebyt)newtime->tm_hour;
    TimePtr->year   = (onebyt)newtime->tm_year;
    TimePtr->day    = (onebyt)newtime->tm_mday - 1;
    TimePtr->month  = (onebyt)newtime->tm_mon;
    TimePtr->extra  = 0;
    TimePtr->weekDay= (onebyt)newtime->tm_wday + 1;
# endif /* MSDOS */

# ifndef APW
# ifndef MSDOS
    printf("Need [other] time-expander\n");  /* +PORT+ */
    TimePtr->second = 0;
    TimePtr->minute = 0;
    TimePtr->hour = 0;
    TimePtr->year = 0;
    TimePtr->day = 0;
    TimePtr->month = 0;
    TimePtr->extra = 0;
    TimePtr->weekDay = 0;
# endif /* none1 */
# endif /* none2 */
#endif /* UNIX */
}

#ifdef SUNOS4
time_t time __P((time_t *));
#endif

/*
 * Get current time, put in struct
 */
Time *
#ifdef __STDC__
GetTime(void)
#else
GetTime()
#endif
{
    static Time t;
#if defined(UNIX) || defined(__ORCAC__)
    struct tm *unixt;
    time_t now = time(NULL);

    unixt = localtime(&now);
    t.second = unixt->tm_sec;
    t.minute = unixt->tm_min;
    t.hour = unixt->tm_hour;
    t.year = unixt->tm_year;
    t.day = unixt->tm_mday -1;	/* want 0-xx, not 1-xx */
    t.month = unixt->tm_mon;
    t.extra = 0;
    t.weekDay = unixt->tm_wday +1;  /* Sunday = 1, not 0 like UNIX */
    /* return (&t) */
#else
# ifdef APW
    t = ReadTimeHex(t);
    /* return (&t) */
# endif /* APW */
# ifdef MSDOS
    struct tm *pctime;
    time_t now = time(NULL);

    pctime = localtime(&now);
    t.second = (onebyt)pctime->tm_sec;
    t.minute = (onebyt)pctime->tm_min;
    t.hour   = (onebyt)pctime->tm_hour;
    t.year   = (onebyt)pctime->tm_year;
    t.day    = (onebyt)pctime->tm_mday -1; /* want 0-xx, not 1-xx */
    t.month  = (onebyt)pctime->tm_mon;
    t.extra  = 0;
    t.weekDay= (onebyt)pctime->tm_wday +1;  /* Sunday = 1, not 0 */
    /* return (&t) */
# endif /* MSDOS */

# ifndef APW
# ifndef MSDOS
    printf("\nNeed [other] GetTime\n");  /* +PORT+ */
    t->second = 0;
    t->minute = 0;
    t->hour = 0;
    t->year = 0;
    t->day = 0;
    t->month = 0;
    t->filler = 0;
    t->weekDay = 0;
    /* return (&t) */
# endif /* none1 */
# endif /* none2 */
#endif /* UNIX */
    return (&t);
}


/*
 * Convert a NuFX Time struct to a compact system-dependent format
 *
 * This is used to set a file's date when extracting.  Most systems don't
 * dedicate 8 bytes to storing the date; this reduces it to the format
 * used by a "set_file_date" command.
 */
long
#ifdef __STDC__
ReduceTime(Time *tptr)
#else
ReduceTime(tptr)
Time *tptr;
#endif
{
#ifdef UNIX
    long t = timecvt(tptr);

    return (t ? t : time(NULL));	/* if stored time is invalid, */
					/* return current time */
#else
# ifdef APW
    twobyt date, time;
    long val;

    date = ((twobyt)tptr->year << 9) | ((((twobyt)tptr->month)+1) << 5) |
   	(((twobyt)tptr->day)+1);
    time = ((twobyt)tptr->hour << 8) | ((twobyt)tptr->minute);

    val = (long) date + ((long) time << 16);
    return (val);
# endif /* APW */
# ifdef MSDOS
    return (time(NULL)); /* not sure what to do, return current : RBH */
# endif /* MSDOS */

#ifndef APW
#ifndef MSDOS
    printf("Need [other] ReduceTime\n");  /* +PORT+ */
# endif /* none2 */
# endif /* none1 */
#endif /* UNIX */
}

#ifdef __ORCAC__
int
keyboardStop(void) {
   StopGSPB sblock = { 1, 0 };

   StopGS(&sblock);
   TOOL_CHECK("get stop info", "", 1);
   return sblock.flag;
}

#ifndef __GNO__

GSString255Ptr
__C2GSMALLOC(char *s)
{
  GSString255Ptr result;
  size_t len;
  
  if (s == NULL || (len = strlen(s)) > 255) {
    errno = EINVAL;
    return NULL;
  }
  result = malloc(sizeof(GSString255));
  if (result != NULL) {
    result->length = len;
    strncpy(result->text, s, len); /* don't null-terminate iff len == 255 */
  }
  return result;
}

#ifndef __GNO__
#define EPERM   EIO
#define ENOTBLK EIO
#define ENOEXEC EIO
#define EAGAIN  EIO
#endif

int
_mapErr (int gserrnum) {
  switch (gserrnum) {
  case invalidRefNum:	/* invalid reference number */
    return EBADF;	/* bad file descriptor */

  case outOfMem:	/* out of memory */
    return ENOMEM;	/* Not enough memory */

  case drvrPriorOpen:	/* character device already open */
  case drvrBusy:	/* call aborted; driver is busy */
  case drvrWrtProt:	/* device is write protected */
    return EACCESS;	/* access bits prevent the operation */

  case devNotFound:	/* device not found */
  case pathNotFound:	/* subdirectory does not exist */
  case volNotFound:	/* volume not found */
  case fileNotFound:	/* file not found */
    return ENOENT;	/* No such file or directory */

  case tooManyFilesOpen:/* too many files open on server volume */
  case defListFull:	/* device list is full */
  case fileBusy:	/* file is already open */
    return EMFILE;	/* too many files are open */

  case gsosActive:	/* GS/OS already active */
    return EDOM;	/* domain error */

  case invalidAccess:	/* access not allowed */
  case dataUnavail:	/* Data unavailable */
    return EPERM;	/* Not owner */

  case notBlockDev:	/* not a block device */
    return ENOTBLK;	/* not a block device */

  case notSystemFile:	/* not an executable file */
    return ENOEXEC;	/* Exec format error */

  case volumeFull:	/* volume full error */
  case volDirFull:	/* volume directory full */
    return ENOSPC;	/* the file is too large */

  case dupPathname:	/* create or rename with existing name */
  case devNameErr:	/* device exists with same name as replacement name */
    return EEXIST;	/* the file exists */

  case outOfRange:	/* position out of range */
    return ERANGE;	/* # too large, too small, or illegal */

  case irqTableFull:	/* interrupt table full */
  case drvrNoResrc:	/* resources not available */
  case stackOverflow:	/* too many applications on stack */
    return EAGAIN;	/* No more processes */

  case endOfDir:	/* end of directory has been reached */
  case eofEncountered:	/* end-of-file encountered */
    return 0;		/* no error ... */

  case badSystemCall:	/* bad system call number */
  case invalidPcount:	/* invalid parameter count */
  case invalidDevNum:	/* invalid device number */
  case drvrBadReq:	/* bad request or command */
  case drvrBadCode:	/* bad control or status code */
  case drvrBadParm:	/* bad call parameter */
  case drvrBadCount:	/* invalid byte count */
  case drvrBadBlock:	/* invalid block address */
  case badPathSyntax:	/* invalid pathname syntax */
  case badFileFormat:	/* version error (incompatible file format) */
  case badStoreType:	/* unsupported (or incorrect) storage type */
  case buffTooSmall:	/* buffer too small */
  case paramRangeErr:	/* parameter out of range */
  case invalidClass:	/* invalid FST call class */
  case invalidFSTID:	/* error - FST ID is invalid */
  case invalidFSTop:	/* invalid FST operation */
  case unknownVol:	/* unknown volume type */
  case dupVolume:	/* duplicate volume name */
  case badPathNames:	/* invalid pathnames for ChangePath */
  case osUnsupported:	/* Operating System not supported */
  case invalidLevel:	/* specifield level outside legal range */
    return EINVAL;	/* Invalid argument */

  case drvrIOError:	/* I/O error */
  case resForkNotFound:	/* file does not contain required resource */
  case supListFull:	/* supervisor list is full */
  case fstError:	/* generic FST error */
  case resExistsErr:	/* cannot expand file, resource already exists */
  case resAddErr:	/* cannot add resource fork to this type file */
  case networkError:	/* generic network error */
  case drvrNotOpen:	/* character device not open */
  case drvrNoDevice:	/* device not connected */
  case drvrDiskSwitch:	/* disk has been switched */
  case drvrOffLine:	/* device off line/ no media present */
  case dirError:	/* directory error */
  case damagedBitMap:	/* block number too large */
  case fstCaution:	/* FST handled call, but result is weird */
  default:
    return EIO;		/* I/O error */
  }
}

#endif /* !__GNO__ */
#endif /* __ORCAC__ */
