/* Release 3.00 */
/*-------------------------------------------------------------------------*
*                                                                          *
*  cio2.c - common I/O			         			   *
*                                                                          *
*  COPYRIGHT (C) 1989 Jensen and Partners. All Rights Reserved             *
*  Written by Simon Knight.                                                *
*                                                                          *
*  COPYRIGHT (C) 1991 Psion PLC. All Rights Reserved                       *
*  Modified by NSM.                                                        *
*                                                                          *
*--------------------------------------------------------------------------*/

#define _USE_TIME
#define _USE_CONIO
#include "clib.h"

/****************************************************************************
*  buffer flushing functions.						    *
****************************************************************************/

int _flsbuf(int  ch, FILE *st) {

  int flag;

  ch&=0xFF;
  flag=st->_flag;
  if( (!flag) || (flag&_F_ERR))
    return(-1);
  if((flag&_F_EOF) && (flag&_F_IN)) {
    lseek(st->_file, 0L, SEEK_END);
    st->_flag|=_F_RST;
    st->_flag&=(~(_F_IN|_F_EOF));
    if(st->_size) {
      _flusher(st);	
      --st->_cnt;			
      *st->_ptr++= (char) ch;
      return(ch);
    }
  }
  else {
    if((!(flag&_F_WRIT)) || (flag&_F_IN)
                	 || ((!(flag&_F_BIN)) && ((char) ch == EOF))) {
      st->_flag|=_F_ERR;
      return(-1);
    }					      /* return error */
    if(st->_size) {			      /* buffered */
      if(_flusher(st)== -1 )		      /* flush buffer */
	return(-1);
      --st->_cnt;			      /* put overflow char in buffer */
      *st->_ptr++= (char) ch;
      return(ch);
    }
    st->_flag&=~_F_RST;  		      /* clear reset flag */
    if(flag&_F_APP)
      lseek(st->_file, 0L, SEEK_END);         /* unbuffered - write data */
  }	
  st->_cnt=0;                               /* set buffer pointers */
  st->_ptr=NULL;
  st->_flag|=_F_OUT;			      /* set output flag */
  if(_write(st->_file,&ch,1) != 1) {
    st->_flag|=_F_ERR;
    return(-1);
  }
  if((ch == _CTLZ) && (!(flag&(_F_BIN|_F_DEV))))
					      /* ctl z - set EOF flag if */
    st->_flag|=_F_EOF;		      /* text mode and not device */
  return(ch);
}

int _flusher(FILE *st)                     /* empties output buffer */

{
    unsigned wnum, flag;
    char zbuf[128];
    long pos;
    int nr, sr;

    flag=st->_flag;
    if(flag&(_F_IN|_F_EOF))
	return(-1);
    if(flag&_F_RST)			   /* set up reset buffer for output */
    {
	st->_flag&=(~_F_RST);
	st->_flag|=_F_OUT;
	st->_cnt=st->_size;
	st->_ptr=st->_base;
	return(0);			   /* return - buffer wasn't full */
    }
    if(st->_cnt<0)
       st->_cnt=0;
    wnum=st->_size-st->_cnt;
    if(wnum == 0)			   /* nothing to do - return */
	return(0);			   /* buffer empty */
    if(flag&_F_BIN)			   /* binary mode */
    {
	if(flag&_F_APP)
	    lseek(st->_file, 0L, SEEK_END);    /* append */
	if(_write(st->_file, st->_base, wnum) != wnum)
	    goto error;
    }
    else				   /* text mode */
    {
	if(flag&_F_APP) {
	    pos = lseek(st->_file, -128L, SEEK_END);
	    if(pos < 0)
	      lseek(st->_file, 0, SEEK_SET);
	    nr = _read(st->_file, zbuf, 128);
	    sr = nr;
	    if (nr == -1)
	      goto error;
	    while(--sr >= 0) {
	        if(zbuf[sr] != _CTLZ)
	          break;
	    }
            pos = sr - nr + 1;
	    lseek(st->_file, pos, SEEK_END);    /* append after last cltZ */
        }
	if(_write(st->_file, st->_base, wnum) == -1)
	    goto error;
	if(st->_flag&_F_CTZ) {
            st->_flag|=_F_EOF;
            st->_cnt=0;
            st->_ptr=st->_base;
            return(0);
        }
    }
    st->_cnt=st->_size; 		    /* set buffer pointers */
    st->_ptr=st->_base;
    st->_flag|=_F_OUT;			    /* set output flag */
    return(0);
error:
    st->_flag|=_F_ERR;
    st->_cnt=0;
    return(-1);
}

/****************************************************************************
*  buffer filling functions						    *
****************************************************************************/

int _filbuf(FILE *st)
{
    int  ch, n, flag;

    flag=st->_flag;
    if((!flag)||(flag&(_F_EOF|_F_ERR)))
	return(-1);
    if((flag&_F_OUT) || (!(flag&_F_READ)))
    {
	st->_flag|=_F_ERR;
	return(-1);			/* return error */
    }
    if(st->_size)			/* buffered */
    {
        if(_filler(st) <= 0 )       /* fill buffer */
            return(-1);
	--st->_cnt; 		/* get first char from buffer */
	ch=*st->_ptr++;
	return(ch&0xFF);		/* return first character in buffer */
    }
    st->_cnt=0;                         /* reset pointers */
    st->_flag|=_F_IN;                   /* set input flag */
    st->_ptr=NULL;
    st->_flag&=~_F_RST;
    for(n=0; n<2; n++)			/* unbuffered - read character */
    {
	if(_read(st->_file, &ch, 1) != 1)
	{
	    st->_flag|=_F_EOF;
            return(-1);
	}
	ch&=0xFF;
	if((flag&_F_BIN)||(ch != '\r')) /* dont translate if binary mode */
	    break;
    }
    if((!(flag&(_F_BIN|_F_DEV))) && (ch == _CTLZ))
	st->_flag|=_F_EOF;		/* ctl z end of file */
    return(ch);
}

int _filler(FILE *st)		      /* fills buffer */
{
    int  flag, num;

    flag=st->_flag;
    if(flag&(_F_OUT|_F_EOF))
	return(-1);
    if(flag&_F_RST)
	st->_flag&=~_F_RST;
    num =_read(st->_file, st->_base, st->_size);
    st->_ptr=st->_base;
    if(( num == -1) && (num != st->_size))
	 goto error;
    st->_cnt=num;			  /* reset pointers */
    st->_flag|=_F_IN;                     /* set input flag */
    if(num == 0)
    {
        st->_flag|=_F_EOF;                /* end of file */
        return(-1);
    }
    return(num);
error:					  /* read error */
    st->_flag|=_F_ERR;
    st->_cnt=0;
    return(-1);
}

int fputchar(int ch)
{
    return(fputc(ch, stdout));
}

int fgetchar()
{
    return(fgetc(stdin));
}

/****************************************************************************
*  ungetc - put character back onto input stream			    *
****************************************************************************/

int ungetc(int ch, FILE *st)
{
    int flag;

    flag=st->_flag;
    if((!flag) || (flag&_F_ERR))
	return(EOF);
    if(ch == EOF)
	return(EOF);		     /* return EOF if error, EOF or not read mode */
    if(flag&_F_OUT)
    {
	st->_flag|=_F_ERR;
	return(EOF);		     /* return EOF if error, EOF or not read mode */
    }
    ch&=0xFF;
    st->_flag&=(~_F_EOF);		/* clear EOF */
    if((flag&_F_RST) || (st->_size == 0))
    {
        st->_flag&=(~_F_RST);		
        st->_flag|=_F_IN;
        if(st->_size)
            st->_ptr=st->_base;
        else
            st->_ptr= (char *) &st->_pback;
        if((ch == 0xA) && (!(st->_flag&_F_BIN))) {
          st->_cnt=2;
          *((unsigned *)st->_ptr)=0xA0D;
        }
        else {
          st->_cnt=1;
          *st->_ptr=ch;
        }
        return(ch);
    }
    if((ch == 0xA) && (!(st->_flag&_F_BIN)) && (st->_cnt < st->_size-2)) {
        *--st->_ptr= (char) 0xD;
	st->_cnt++;
    }
    *--st->_ptr= (char) ch; 	/* buffer not full - put it in buffer */
    st->_cnt++;
    return(ch);
}

/****************************************************************************
* rewind - rewind and clear error flag					    *
****************************************************************************/

void rewind(FILE *st)
{
    if(st->_flag)
    {
	st->_flag&=(~_F_ERR);
	fseek(st, 0L, SEEK_SET);
    }
    return;
}

/****************************************************************************
*  flushall - flush all open streams					    *
****************************************************************************/

int  flushall()
{
    int n, count;

    count=0;
    for(n=0; n< _open_max; n++)
    {
	if(_iob[n]._flag)	      /* inc count if open file */
	{
	    fflush(&_iob[n]);	      /* flush buffer */
	    count++;
	}
    }
    return(count);		      /* return number of open streams */
}

void  _flushall()
{
    int n;

    for(n=0; n<_open_max; n++)
    {
	if((_iob[n]._flag) && (_iob[n]._size))
	    _flusher(&_iob[n]);	      /* flush buffer */
    }
    return;	                      /* return number of open streams */
}

/****************************************************************************
*  fopen  - open stream 						    *
****************************************************************************/

#define _WRITE	  2
#define NODEFMODE 4
#define _READ	  8

FILE *fopen(const char *path, const char *type)
{
    int  num;
    int handle, flag, mode;

    flag=_F_RST;
    mode=0;
    if(_scan_type(type, &flag, &mode) < 0)	   /* get access mode */
	return(NULL);
    handle=_open_stream(path, &flag, mode);	   /* open the file */
    if(handle < 0)
	return(NULL);
    num=_free_stream(); 			   /* find a free stream */
    if(num < 0)
    {
        close(handle);
	return(NULL);
    }	
    return(_alloc_stream(&_iob[num], handle, flag));
}						   /* allocate the stream */

int _scan_type(const char *type, int *fptr, int *mptr)
{					      /* evaluate file mode */
    int  c, n;

    switch(type[0])
    {
	case 'r':
	    *mptr|=(_READ|O_EXCL);
	    break;
	case 'w':
	    *mptr|=(O_TRUNC|O_CREAT|_WRITE);
	    break;
	case 'a':
	    *fptr|=_F_APP;
	    *mptr|=(_WRITE|O_APPEND|O_CREAT);
	    break;
	default:
	    return(-1);
    }
    n=0;
    do
    {
	c=type[++n];
	switch(c)
	{
	    case'+':
		*mptr|=(_READ|_WRITE);
		break;
	    case'b':
		*fptr|=_F_BIN;
		*mptr|=NODEFMODE|O_BINARY;
		break;
	    case't':
		*mptr|=NODEFMODE|O_TEXT;
		break;
	    default:
		break;
	}
    } while((n < 3) && (c));
    return(0);
}

int _open_stream(const char *path, int *fptr, int mode)
{
    unsigned access, permission;

    access=0;					 /* translates level 2	    */
    permission=0;				 /* access and permission   */
    if(!(mode&NODEFMODE))			 /* flags to level 1 and    */
    {						 /* uses open to get handle */
	if(_fmode==O_BINARY)
	{
	*fptr|=_F_BIN;
	access= O_BINARY;
	}
	else
	    access=O_TEXT;
    }
    if(mode&_WRITE)
    {
	permission|=S_IWRITE;
	if(mode&_READ)
	{
	    *fptr|=_F_RDWR;
	    permission|=S_IREAD;
	    access|=O_RDWR;
	}
	else
	{
	    *fptr|=_F_WRIT;
	    access|=O_WRONLY;
	}
    }
    else
    {
	access|=O_RDONLY;
	permission=S_IREAD;
	*fptr|=_F_READ;
    }
    access|= (mode&(O_TEXT|O_BINARY|O_CREAT|O_TRUNC|O_EXCL|O_APPEND));
    return(open(path, access, permission));
}

int _valid_stream(FILE *st)           /* checks stream pointer is valid */
{
    if((st > &_iob[_open_max-1]) || (st < _iob) || (st->_flag==0) )
	return(FALSE);
    return(TRUE);
}

/****************************************************************************
*  fgetpos - get current stream position                                    *
****************************************************************************/

int fgetpos(FILE *st, fpos_t *fp)
{
    long pos;

    pos=ftell(st);
    if(pos == -1)
        return(-1);
    *fp= (fpos_t) pos;
    return(0);
}

/****************************************************************************
*  fsetpos - set current stream position                                    *
****************************************************************************/

int fsetpos(FILE *st, const fpos_t *fp)
{
    return fseek(st, *fp, SEEK_SET);
}

/*-------------------------------------------------------------------------*
*  close.c - level 1 I/O - close file.                                     *
*--------------------------------------------------------------------------*/

int close(int handle)
{
    int  n;

    n=_close(handle);                 /* close file */
    if(n < 0)
        return(-1);                   /* return -1 if error */
    _openfd[handle]=0;	              /* zero file descriptor */
    return(0);                        /* success - return 0 */
}

/*-------------------------------------------------------------------------*
*  eof.c - level 1 I/O - test for eof.                                     *
*--------------------------------------------------------------------------*/

int eof(int handle)
{
    if( (_openfd[handle]&O_TEXT) && (_openfd[handle]&_O_EOF))
        return(1);           /* text file ctl z eof */
    if(_openfd[handle]&O_DEVICE)
        return(0);           /* device - no eof unless text mode */
    return(_eof(handle));
}

/*-------------------------------------------------------------------------*
*  umask.c - level 1 I/O - set file permission mask.			   *
*--------------------------------------------------------------------------*/

unsigned umask(unsigned permission)
{
    unsigned  ret;

    ret=_fmask;
    _fmask=permission;
    return(ret);
}

/*-------------------------------------------------------------------------*
*  filelength.c - returns file length.					   *
*--------------------------------------------------------------------------*/

long filelength(int handle)
{
    long pos, size;

    pos=tell(handle);			    /* save file position */
    if(pos == -1)
	return(pos);
    size=lseek(handle, 0L, SEEK_END);	    /* get file length */
    lseek(handle, pos, SEEK_SET);	    /* restore original file position */
    return(size);
}

int rmtmp(void)
{
    int n, files;

    n=0;
    files=0;
    while(n < _open_max)
    {
        if (_tmpfiles[n])
        {
            fclose(_tmpfptrs[n]);
            unlink(_tmpfiles[n]);
            _tmpfiles[n]=NULL;
            ++files;
        }
        ++n;
    }
    _exit_tmp=NULL;
    return(files);
}

FILE *tmpfile(void)
{
    int handle,i;
    FILE *ret;
    char *e,*p,name[0x128];

    name[0]=0;
    if ((e=getenv("TMP"))!=NULL && (i=strlen(e))!=0)
	{
	strcpy(&name[0],e);
	p=(&name[i-1]);
	if (*p!='\\')
	    {
	    *p++='\\';
	    *p=0;
	    }
	}
    if ((handle=_creat_temp(&name[0],FA_NORMAL))==(-1))
	return(NULL);
    _openfd[handle]=O_BINARY|O_RDWR;
    i=strlen(&name[0])+1;
    if ((p=malloc(i))==NULL)
	goto failed1;
    strcpy(p,&name[0]);
    _tmpfiles[handle]=p;
    if ((ret=fdopen(handle,"w+b"))==NULL)
	goto failed2;
    _tmpfptrs[handle]=ret;
    _exit_tmp=_exit2;
    return(ret);
failed2:
    free(_tmpfiles[handle]);
    _tmpfiles[handle]=NULL;
failed1:
    _openfd[handle]=0;
    _close(handle);
    return(NULL);
}

/*-------------------------------------------------------------------------*
*  console I/O section.	                  				   *
*--------------------------------------------------------------------------*/

char *cgets(char *s)
{
    extern void *winHandle;
    extern void p_xwind(void);

    if(!_p_init)
    {
        _i_putch=_d_putch;
        _i_cgets=_d_cgets;
        _p_init=-1;
	if (winHandle==NULL)
	    p_xwind();
    }
    return(_i_cgets(s));
}

int sopen(const char *path, int access, int shflag, ...)
{
    va_list _v_argptr;

    va_start(_v_argptr, shflag);
    return(open(path, access|shflag, va_arg(_v_argptr, int)));
}

/*-------------------------------------------------------------------------*
*  macro equivalents.	                  				   *
*--------------------------------------------------------------------------*/

int ferror(FILE *st)
{
    return((st)->_flag & _F_ERR);
}

int feof(FILE *st)
{
    return((st)->_flag & _F_EOF);
}

int fileno(FILE *st)
{
    return((st)->_file);
}

int remove(const char *path)
{
    return(unlink(path));
}

int getc(FILE *st)
{
    return(fgetc(st));
}

int putc(int c, FILE *st)
{
    return(fputc(c, st));
}

int getchar()
{
    return(fgetc(stdin));
}

int putchar(int c)
{
    return(fputc(c, stdout));
}

/****************************************************************************
*  puts - send string to stdout 					    *
****************************************************************************/

int puts(const char  *s)
{
    int n, c, ret;

    n=0;
    while((c=s[n++]) != 0)
    {
	if(putchar(c) == EOF)
	{
	    ret=-1;
	    goto puts_error;
	}
    }
    if(putchar('\n') == EOF)
    {
        ret=-1;
	goto puts_error;
    }
    ret=fflush(stdout);
puts_error:
    return(ret);
}

/****************************************************************************
*  gets - get string from stdin 					    *
****************************************************************************/

char *gets(char  *s)
{
    int n, c;
    char *ret;

    n=0;
    while((c=getchar()) != '\n')
    {
	if(c < 0)
	{
	    if((feof(stdin)) && (n))
	        break;
	    ret=NULL;
	    goto gets_error;
	}
	s[n++]= (char) c;
    }
    s[n]=0;
    ret=s;
gets_error:
    return(ret);
}

/****************************************************************************
*  fputs - put string on stream 					    *
****************************************************************************/

int fputs(const char  *s, FILE *st)
{
    int n, c, ret;

    ret=0;
    n=0;
    while((c=s[n++]) != 0)
    {
	if(fputc(c, st) == EOF )
	{
	    ret=-1;
	    break;
	}
    }
    if(st->_flag&_F_DEV)
        fflush(st);
    return(ret);
}

/****************************************************************************
*  fgets - get string from stream					    *
****************************************************************************/

char  *fgets(char  *s, int num, FILE *st)
{
    int n, c;
    char *ret;

    n=0;
    ret=s;
    while( n < num-1)
    {
	c=fgetc(st);
	if(c == -1)
	{
	    if((feof(st)) && (n))
	        break;
	    ret=NULL;
	    goto fgets_end;
	}
        s[n++]= (char) c;
	if(c == '\n')
	    break;
    }
    s[n]=0;
fgets_end:
    return(ret);
}

/****************************************************************************
*  getw - get word from stream						    *
*  putw - put word on stream						    *
****************************************************************************/

int getw(FILE *st)
{
    unsigned hibyte, lobyte;

    lobyte=fgetc(st);
    hibyte=fgetc(st);
    return( (hibyte*0x100)+lobyte);
}

int putw(int num, FILE *st)
{
    int ret;

    fputc(num&0xFF, st);
    ret=fputc((num&0xFF00)>>8, st);
    return(ret);
}

/****************************************************************************
*  clearerr - clear error and EOF flags and reset buffer status 	    *
****************************************************************************/

void clearerr(FILE *st)

{
    if(st->_flag)
    {
        st->_flag&=~(_F_ERR|_F_EOF|_F_CTZ);
        _openfd[st->_file]&= (~_O_EOF);
    }
    return;
}

/****************************************************************************
* fseek - position stream pointer					    *
****************************************************************************/

int fseek(FILE *st, long offset, int orig)
{
    long ret, temp, pos;
    int flag;

    flag=st->_flag;
    if((!flag) || (flag&_F_ERR))
    {
	errno=EBADF;
	ret=-1;
	goto fseek_end;
    }
    if(orig == SEEK_CUR)
    {
        if((!(flag&(_F_WRIT|_F_RST))) && (st->_size)) {
          if(offset == 0) {
            ret=0;
            goto fseek_end;
          }
          else if(offset < 0)
            pos=st->_ptr-st->_base;
          else
            pos=st->_cnt;
          if(pos > labs(offset)) {
            st->_cnt-=(short)offset;
            st->_ptr+=(short)offset;
            ret=0;
            goto fseek_end;
          }
        }
        temp=ftell(st);
        ret=fseek(st, temp+offset, SEEK_SET);
        if(ret)
          ret = -1L;
        goto fseek_end;
    }
    if((st->_size) && (flag&_F_OUT))	      /* flush output buffer */
	_flusher(st);
    st->_pback=0;			      /* reset buffer */
    st->_cnt=0;
    st->_flag|=_F_RST;
    ret=lseek(st->_file, offset, orig);
    st->_flag&=~(_F_IN|_F_OUT|_F_EOF|_F_CTZ); /* clear direction flag and EOF */
    _openfd[st->_file]&=~(_O_EOF);
fseek_end:
    if(ret < 0)
	return(1);
    return(0);
}

/****************************************************************************
*  ftell - return stream pointer					    *
****************************************************************************/

long ftell(FILE *st)
{
    long pos, ret;
    int flag;

    flag=st->_flag;
    if((!flag) || (flag&_F_ERR))
    {
        errno=EINVAL;
	ret=-1L;
	goto ftell_error;
    }
    if((flag&_F_RST) || (!st->_size))      /* unbuffered or reset stream */
    {
        st->_cnt=0;
        ret=tell(st->_file);
    }
    else if(flag&_F_OUT)                   /* output stream */
    {
        _flusher(st);                      /* flush stream  */
        ret=tell(st->_file);
    }
    else
    {
        pos=tell(st->_file);                   /* input stream */
        if(st->_pback != 0)
            --pos;
        if((flag&_F_BIN) && (st->_pback == 0xA0D))
            --pos;
        ret=pos-st->_cnt;
    }
ftell_error:
    return(ret);
}

/****************************************************************************
*  fflush - flush stream						    *
****************************************************************************/

int  fflush(FILE  *st)
{
    int flag, ret;

    if(st == NULL)
    {
        flushall();
        return(0);
    }
    flag=st->_flag;
    if((!flag)||(flag&(_F_EOF|_F_ERR)))
    {
    	ret=EOF;			  /* error EOF or not open */
        goto fflush_end;
    }
    if(!st->_size)
    {
	st->_cnt=0;
        st->_flag|=_F_RST;
        st->_flag&=~(_F_OUT|_F_IN);
	ret=0;			  /* no buffer */
	goto fflush_end;
    }
    if(flag&_F_OUT)
        ret=_flusher(st);                 /* flush output buffer */
    else
    {
        fseek(st, ftell(st), SEEK_SET);
        ret=0;
	goto fflush_end;
    }
    st->_pback=0;                         /* reset buffer */
    st->_cnt=0;
    st->_flag|=_F_RST;
    st->_flag&=~(_F_OUT|_F_IN);
fflush_end:
    return(ret);
}

/****************************************************************************
*  fdopen - assign stream to handle					    *
****************************************************************************/

#define _WRITE	  2
#define NODEFMODE 4
#define _READ	  8

FILE *fdopen(int handle, char *type)
{
    int  num;
    int  flag, mode;

    flag=_F_RST;
    mode=0;
    if(handle < 0)			/* bad handle */
    {
	 errno=EBADF;
	 return(NULL);
    }
    if(_scan_type(type, &flag, &mode) < 0)	  /* get the access mode */
	return(NULL);
    if((!(mode&NODEFMODE))&&(_fmode==O_BINARY))
	flag|=_F_BIN;
    if(mode&_WRITE)
    {
	if(mode&_READ)
	    flag|=_F_RDWR;
	else
	    flag|=_F_WRIT;
    }
    else
	flag|=_F_READ;
    num=_free_stream(); 			  /* find a free stream */
    if(num < 0)
    {
        close(handle);
	return(NULL);
    }	
    return(_alloc_stream(&_iob[num], handle, flag));
}						  /* allocate the stream */

FILE *  _alloc_stream(FILE *stream, int handle, int flag)
{
    stream->_file=handle;		   /* allocates buffer and sets flags */
    stream->_flag=flag;
    stream->_cnt=0;
    stream->_pback=0;
    stream->_size=BUFSIZ;
    if(_openfd[handle]&O_DEVICE)
	stream->_flag|=_F_DEV;
    if((stream->_base= (char *) malloc(BUFSIZ)) == NULL)
    {
	stream->_size=0;		   /* no memory for buffer */
	stream->_ptr=NULL;
	errno=ENOMEM;
    }
    else
    {
	stream->_size=BUFSIZ;
	stream->_ptr=stream->_base;
    }
    return(stream);
}

int _free_stream()                               /* find a free stream */
{
    int n;

    for(n=0; n < _open_max; n++)
    {
	if(_iob[n]._flag == 0)
	    return(n);
    }
    return(-1);
}

/****************************************************************************
*  freopen - close existing stream and assign new file			    *
****************************************************************************/

FILE *freopen(const char *path, const char *type, FILE *st)
{
    int handle, flag, mode;

    if(fclose(st) == EOF)		     /* close old stream */
	return(NULL);
    flag=_F_RST;
    mode=0;
    if(_scan_type(type, &flag, &mode) < 0)   /* get file mode */
	goto fr_error;
    handle=_open_stream(path, &flag, mode);  /* open new */
    if(handle < 0)
	goto fr_error;
    return(_alloc_stream(st, handle, flag)); /* assign to stream */
fr_error:
    return(NULL);
}

/****************************************************************************
*  fclose - close stream						    *
****************************************************************************/

int fclose(FILE *st)
{
     int ret;

     ret=0;
     if(!_valid_stream(st))
     {
     	 ret=-1;
     	 goto fclose_error;
     }	
     if(st->_size)
         _flusher(st);			    /* flush buffer if any */
     if(close(st->_file) < 0)		    /* close file */
	 ret=-1;
     if((st->_base != NULL) && (!(st->_flag&_F_UBUF)))
	 free(st->_base);		    /* free system allocated buffer */
     st->_flag=0;                           /* free stream */
     if(_tmpfiles[st->_file])
     {
         unlink(_tmpfiles[st->_file]);
         free(_tmpfiles[st->_file]);
         _tmpfiles[st->_file]=NULL;
     }
fclose_error:
     return(ret);
}

/****************************************************************************
*  fcloseall - closes all streams except standards			    *
****************************************************************************/

int fcloseall(void)
{
    int n, count;

    count=0;
    for(n=3; n < _open_max; n++)
    {
	if(fclose(&_iob[n]) == 0)
	    count++;
    }
    return(count);
}

/****************************************************************************
*  setbuf - allocates user buffer to stream				    *
****************************************************************************/

void setbuf(FILE *st, char *buffer)
{
    if((!_valid_stream(st))||(!(st->_flag&_F_RST))||(st->_flag&_F_UBUF))
	return;
    if(st->_base != NULL)	    /* free any system buffer */
	free(st->_base);
    st->_base=buffer;		    /* use user buffer */
    st->_ptr=buffer;
    if(buffer != NULL)
    {
	st->_size=BUFSIZ;
	st->_flag|=_F_UBUF;
    }
    else
    {
	st->_size=0;
        st->_flag&=~_F_LBUF;
    }
    return;
}

/****************************************************************************
*  setvbuf - allocates user or system buffer to stream			    *
****************************************************************************/

int setvbuf(FILE *st, char *buffer, int type, size_t size)
{
    int flag;

    if((type < _IOFBF) || (type > _IONBF) || ((int) size < 0))
        return(1);
    flag=st->_flag;
    if((!_valid_stream(st))||(!(flag&_F_RST))||(size < 0))
    {
    	return(1);
    }	
    if((st->_base != NULL) || (!(st->_flag&_F_UBUF)))	   /* free old buffer */
	free(st->_base);
    st->_flag&=(~_F_LBUF|_F_IN|_F_OUT);
    if(type != _IONBF)
    {
	if(buffer==NULL)
	{			   /* allocate new system buffer */
	    buffer=malloc(size);
	    if(buffer==NULL)
	    {
		errno=ENOMEM;
		return(1);
	    }
	}
	else			  /* user buffer */
	    st->_flag|=_F_UBUF;
	st->_base=buffer;
	st->_ptr=buffer;
	st->_size=size;
	if(type == _IOLBF)	  /* line buffered */
	    st->_flag|=_F_LBUF;
    }
    else			  /* no buffer */
    {
	st->_size=0;
	st->_base=NULL;
        st->_ptr=NULL;
        st->_cnt=0;
    }
setvbuf_error:
    return(0);
}

/****************************************************************************
*  fread - get a number of data blocks from stream			    *
****************************************************************************/

size_t fread(void *buf, size_t size, size_t count, FILE *st)
{
    unsigned numtoread;
    unsigned pos;
    int flag;
    char *buffer;
    long total, numleft, p;
    size_t ret;

    flag=st->_flag;
    if((!flag) || (size == 0) || (count==0) || (flag&(_F_ERR|_F_EOF)))
    {
    	ret=0;
    	goto fread_error;
    }	
    if((flag&_F_OUT) || (!(st->_flag&_F_READ)))
    {
	st->_flag|=_F_ERR;
    	ret=0;
    	goto fread_error;
    }
    st->_flag|=_F_IN;
    buffer=(char *)buf;
    total=size*count;			/* how many bytes are there to read */
    pos=0;
    if((st->_size == 0) || (!(st->_flag&_F_BIN)))
    {
	for(p=0; p < total; p++)	/* unbuffered */
	{
	    ret=getc(st);
	    if(ret == EOF )
		break;
	    buffer[pos]= (char) ret;
	    pos++;
	}
    }
    else
    {
	numleft=total;
	p=0;
	do
	{
	    if(st->_cnt == 0)	       /* fill empty buffer */
	    {
		if(_filler(st) <= 0)
		    break;	       /* error or EOF */
	    }
	    if( (long) (unsigned) st->_cnt >= numleft)	  /* read entire item */
		numtoread = (unsigned) numleft;
	    else
		numtoread=st->_cnt;    /* read entire buffer */
	    memcpy(buffer, st->_ptr, numtoread);
	    st->_cnt-=numtoread;
	    buffer+=numtoread;
	    st->_ptr+=numtoread;
	    numleft-=numtoread;
	    p+=numtoread;
	}while(numleft);
    }
    ret=(int) p/size;
fread_error:
    return(ret);	     /* return number of complete items read */
}

/****************************************************************************
*  fwrite - put a number of data blocks on stream			    *
****************************************************************************/

size_t fwrite(const void *buf, size_t size, size_t count, FILE *st)
{
    unsigned numtowrite;
    unsigned pos;
    char *buffer;
    long total, numleft, p;
    int flag;
    size_t ret;

    flag=st->_flag;
    if((!flag) || (size == 0) || (count==0) || (flag&(_F_ERR|_F_EOF)))
    {
    	ret=0;
    	goto fwrite_error;
    }	
    if((flag&_F_IN) || (!(st->_flag&_F_WRIT)))
    {
	st->_flag|=_F_ERR;
    	ret=0;
    	goto fwrite_error;
    }
    st->_flag|=_F_OUT;
    buffer=(char *)buf;
    pos=0;
    total=size*count;
    if((st->_size == 0) || (!(st->_flag&_F_BIN)))
    {
	for(p=0; p < total; p++)	/* unbuffered */
	{
	    if(putc(buffer[pos], st) == -1)
		break;
	    pos++;
	}
    }
    else
    {
	numleft=total;
	p=0;
	do
	{
	    if( (long) (unsigned) st->_cnt >= numleft)	  /* write entire item */
		numtowrite= (unsigned) numleft;
	    else
		numtowrite=st->_cnt;			  /* write entire buffer */
	    memcpy(st->_ptr, buffer, numtowrite);
	    st->_cnt-=numtowrite;
	    buffer+=numtowrite;
	    st->_ptr+=numtowrite;
	    numleft-= (long) numtowrite;
	    if(st->_cnt == 0)
	    {
		if(_flusher(st) < 0)
		    break;				  /* error */
	    }
	    p+=numtowrite;
	}while(numleft);
    }
    ret=(int) p/size;
fwrite_error:
    return(ret);     /* return number of complete items written */
}

/*--------------------------------------------------------------------------*
*	      creat.c - creates a file. 				
*---------------------------------------------------------------------------*/

int creat(const char *path, int permission)
{
    int  fh, fdesc;

    fdesc=_fmode;			  /* set RTL I/O flags */
    permission^=_fmask;
    if(permission == S_IREAD)
    {
	    permission=FA_RDONLY;
    }
    else
    {
	    fdesc|=O_RDWR;
	    permission=FA_NORMAL;
    }
    if(_fmode&O_TEXT)
	    permission=FA_TEXT;
    fh=_creat_trunc(path, permission);	 /* truncate if exists and !readonly */
    if((fh < 0) || (fh >= _open_max))
       return(-1);
    if(isatty(fh))
        fdesc|=O_DEVICE;
    _openfd[fh]=fdesc;                   /* store file descriptor */
    return(fh);                          /* return handle */
}

/*-------------------------------------------------------------------------*
*  open.c - opens a file.						   *
*  This function opens a file, setting DOS access and permision modes,     *
*  and stores access and translation modes in the file descriptor array    *
*  _openfd.								   *
*--------------------------------------------------------------------------*/

#pragma warn(wvnu => off)

int open(const char *path, int access, ...)
{
    va_list  varg;
    int  fh, fdesc;
    unsigned permission;

    fdesc=0;
    if(access&O_TEXT)		    /* defaults to _fmode */
        fdesc|=O_TEXT;
    else if(access&O_BINARY)
	fdesc|=O_BINARY;
    else if( (_fmode == O_BINARY) || (_fmode == O_TEXT))
	fdesc|=_fmode;
    else
	fdesc|=O_BINARY;
    if(access&(O_CREAT|O_APPEND|O_TRUNC))  /* create append or truncate */
    {
	if(access&O_CREAT)
	{
	    va_start(varg, access);
	    permission=va_arg(varg, unsigned);	  /* get permission */
	}
	else
	{
	    if(!(access&(O_RDWR|O_WRONLY)))
		permission=S_IREAD;
	    else
		permission=S_IREAD|S_IWRITE;
	}
	permission^=_fmask;			  /* exclusive or with fmask */
	if(permission == S_IREAD)		  /* set DOS access modes */
	{
	    permission=FA_RDONLY;
	}
	else
	{
	    fdesc|=O_RDWR;
	    permission=FA_NORMAL;
	}
	if (fdesc&O_TEXT)
	    permission|=FA_TEXT;
        if(_exists(path))        /* does file exist ? */
	{
	    if(access&O_EXCL)
	    {
		errno=EEXIST;
		return(-1);		    /* if exclusive flag return error */
	    }
            if(!(access&O_TRUNC))
                goto open_file;             /* if not truncate open file */
	}
        else if(!(access&O_CREAT))          /* create only if flag set */
        {
            errno=ENOENT;
            return(-1);		
        }
        fh=_creat_trunc(path, permission);
    }
    else
    {
open_file:				    /* open file */
	if(!(access&(O_RDWR|O_WRONLY)))
	    fdesc|=O_RDONLY;		    /* write access given */
	else
	{
	    access&=~(O_RDONLY|O_WRONLY);
	    access|=O_RDWR;
	    fdesc|=O_RDWR;
	}
	access&=~(O_TEXT|O_BINARY);
	if (fdesc&O_TEXT)
	    access|=O_TEXT;
	fh=_open(path, access);
    }
    if((fh < 0)	|| (fh >= _open_max)) /* invalid handle from _open or _creat */
        return(-1);
    if(access&O_APPEND) 		 /* if O_APPEND set flag */
        fdesc|=O_APPEND;
    if(isatty(fh))			 /* check for character device */
        fdesc|=O_DEVICE;
    _openfd[fh]=fdesc;                   /* store file descriptor */
    return(fh);                          /* return handle */
}

/*-------------------------------------------------------------------------*
*  dup.c - level 1 I/O - force duplicate file handle.			   *
*--------------------------------------------------------------------------*/

int dup(int handle)
{
    int nh;

    if(((nh=_dup(handle)) == -1) || (nh >= _open_max))
        return(-1);                     /* duplication failed */
    _openfd[nh]=_openfd[handle];        /* copy file desc */
    return(nh);                         /* success - return new handle */
}

#pragma warn(wvnu => on)

/*-------------------------------------------------------------------------*
*  dup2.c - level 1 I/O - force duplicate file handle.                     *
*--------------------------------------------------------------------------*/

int dup2(int oldhandle, int newhandle)
{
    if(_openfd[newhandle])	       /* close new handle if open */
	close(newhandle);		       /* at level 1 */
    if(_dup2(oldhandle, newhandle) < 0)
        return(-1);                            /* duplication failed */
    _openfd[newhandle]=_openfd[oldhandle];     /* copy file desc */
    return(0);                                 /* success - return 0 */
}

/*-------------------------------------------------------------------------*
*  setmode.c - set file translation mode .				   *
*--------------------------------------------------------------------------*/


int setmode(int handle, unsigned mode)
{
    int ret, n;
    char name[P_FNAMESIZE];

    if((mode != O_BINARY) && (mode != O_TEXT))
    {
invalid:
	errno=EINVAL;
	return(-1);
    }
    ret=-1;
    if(_openfd[handle])
    {
	_FsChanToName(getRealHandle(handle),&name[0]);
	if (memcmp("LOC",&name[0],3)!=0)
	    goto invalid;
	ret=_openfd[handle]&(O_BINARY|O_TEXT);	   /* save old mode */
	_openfd[handle]&= ~(O_BINARY|O_TEXT);	   /* mask out old mode */
	_openfd[handle]|=mode;			   /* set new mode */
	n=-1;
	while(++n < _open_max)			   /* look for level 2 stream */
	{
	    if(_iob[n]._file == handle)
	    {
		if(mode == O_BINARY)		   /* Binary - set flag */
		    _iob[n]._flag|=_F_BIN;
		else
		    _iob[n]._flag&=~(_F_BIN);	   /* Text - clear flag */
		break;
	    }
	}
    }
    else
	errno=EBADF;			   /* file wasn't open */
    return(ret);
}

/*-------------------------------------------------------------------------*
*    stat and fstat - return file status information in stat structure.    *
*--------------------------------------------------------------------------*/

#define MAX_EXTS 4
static char exec_exts[MAX_EXTS][5]={ ".BTF", ".OPO", ".APP",".IMG"};

int stat(const char *path, struct stat *statbuf)

{
    int fmode, temp, drive, fh, n;
    long time;

    if (!_isloc(path))
    {
	errno=EINVAL;
	return(-1);
    }
    temp=0;
    fmode=_chmod(path, 0, 0);	      /* get access mode and file type */
    if(fmode == -1)
    {
	errno=ENOENT;
	return(-1);
    }
    statbuf->st_nlink=1;	       /* nlink is always one */
    if(fmode&0x18)
    {
	statbuf->st_mode=S_IFDIR;
	return(0);
    }	
    else
	temp|=S_IFREG;
    if(fmode&1)
	temp|=S_IREAD;
    else
	temp|=S_IREAD|S_IWRITE;
    fh=_open(path, O_RDONLY);	      /* open the file */
    if(fh < 0)
	return(-1);
    if(isatty(fh))		      /* is it a device */
	temp|=S_IFCHR;
    else			      /* if it is a file get drive, length */
				      /* and time info plus exec status    */
    {
	drive=_filedrive(fh);
	statbuf->st_dev=drive;
	statbuf->st_rdev=drive;
	n=0;
	while(n < MAX_EXTS)
	{
	    if(strstr(path, exec_exts[n]))
	    {
                temp|=S_IEXEC;
                break;
            }
            ++n;
	}
	statbuf->st_size=filelength(fh);
	time=get_utime(fh);
	statbuf->st_atime=time;
	statbuf->st_mtime=time;
	statbuf->st_ctime=time;
    }
    statbuf->st_mode=temp;
    _close(fh); 		       /* close the file */
    return(0);
}

int fstat(int handle, struct stat *statbuf)
{
    int fmode, temp, drive;
    long time;

    temp=0;
    fmode=_openfd[handle];
    if(fmode == 0)
    {
	errno=EBADF;
	return(-1);
    }
    temp|=S_IFREG;		       /* get access etc from file descriptor */
    if(fmode&O_RDWR)
	temp|=S_IREAD|S_IWRITE;
    else if(fmode&O_WRONLY)
	temp|=S_IWRITE;
    else
	temp|=S_IREAD;
    if(fmode&O_DEVICE)
    {
	temp|=S_IFCHR;
	drive=handle;
    }
    else			       /* if it is a file get length, drive */
    {				       /* and time info */
	statbuf->st_size=filelength(handle);
	time=get_utime(handle);
	statbuf->st_atime=time;
	statbuf->st_mtime=time;
	statbuf->st_ctime=time;
	drive=_filedrive(handle);
    }
    statbuf->st_dev=drive;
    statbuf->st_rdev=drive;
    statbuf->st_mode=temp;
    statbuf->st_nlink=1;	       /* nlink is always one */
    return(0);
}

/*-------------------------------------------------------------------------*
*    chsize - change size of file .					   *
*--------------------------------------------------------------------------*/

#define SECSIZE 2024L

int chsize(int handle, long size)
{
    char *h;
    int ret,mode;

    if ((h=getRealHandle(handle))==NULL)
	return(-1);
    if ((ret=_iow3(h,P_FSETEOF,&size))<0)
	{
	_ioerr(ret);
	return(-1);
	}
    mode=P_FABS;
    _iow4(h,P_FSEEK,&mode,&size);
    return(0);
}

/*-------------------------------------------------------------------------*
*  getcwd.c - returns pointer to buffer containing current directory.      *
*--------------------------------------------------------------------------*/

char *getcwd(char *buf, int maxlen)
{
    char temp[P_FNAMESIZE];
    int  n,p,aflag;

    aflag=0;
    _getPath(&temp[0]);
    if(buf == NULL)
    {
        buf=(char *) malloc(maxlen);     /* if buffer is null allocate memory */
        if(buf == NULL)
        {
            errno=ENOMEM;       /* no memory - error */
            return(NULL);
	}
	aflag=1;
    }
    n=0;
    p=P_FSYSNAMESIZE;
    while(n < maxlen)    /* copy maxlen bytes to buffer */
    {
	if((buf[n++]=temp[p++]) == 0)
	{
	    if ((n=strlen(&buf[0]))!=3)
		buf[n-1]=0;
            return(buf);
	}
    }
    errno=ERANGE;		 /* string too long */
    if(aflag)			 /* free heap alocated buffer */
	free(buf);
    return(NULL);
}

/*-------------------------------------------------------------------------*
*    console I/O                         				   *
*--------------------------------------------------------------------------*/

void cputs(const char *s)
{
    int n, c;

    n=0;
    if(_ungotchar!=(-1))
    {
        putch(_ungotchar);
        _ungotchar=(-1);
    }
    while((c=s[n++]) != 0)
    {
        putch(c);
    }
    return;
}

