Windows-Server-2003/sdktools/link16/stdio20.c

617 lines
14 KiB
C

/*static char *SCCSID = "%W% %E%";*/
/*
* Copyright Microsoft Corporation, 1983-1987
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/*
* STANDARD I/O:
*
* Standard (buffered) I/O package which is smaller and faster
* than the MS C runtime stdio.
*/
#include <fcntl.h>
#include <minlit.h>
#include <memory.h>
#include <io.h>
#include <string.h>
#if NOT defined( _WIN32 )
#define i386
#endif
#include <stdarg.h>
#if OWNSTDIO
#define STDSIZ 128 /* Size for stdin, stdout */
#define BUFSIZ 1024 /* Size for other files */
typedef char IOEBUF[STDSIZ]; /* For stdin, stdout */
#define _NFILE 10
#define _NSTD 2 /* # automatic stdio buffers */
LOCAL IOEBUF _buf0;
LOCAL IOEBUF _buf1;
LOCAL int cffree = _NFILE - _NSTD;
#if DOSX32 // hack needed untill the libc.lib is fixed
int _cflush;
#endif
/*
* typedef struct file
* {
* char *_ptr;
* int _cnt;
* char *_base;
* char _flag;
* char _file;
* int _bsize;
* }
* FILE;
*/
FILE _iob[_NFILE] =
{
{ NULL, NULL, _buf0, _IOREAD, 0, STDSIZ },
{ _buf1, STDSIZ, _buf1, _IOWRT, 1, STDSIZ },
};
typedef struct file2
{
char _flag2;
char _charbuf;
int _bufsiz;
int __tmpnum;
char _padding[2]; /* pad out to size of FILE structure */
}
FILE2;
FILE2 _iob2[_NFILE] =
{
{0x01, '\0', STDSIZ },
{0x00, '\0', 0 }
};
#if (_MSC_VER >= 700)
// 23-Jun-1993 HV Kill the near keyword to make the compiler happy
#define near
/* pointer to end of descriptors */
FILE * near _lastiob = &_iob[ _NFILE -1];
#endif
/*
* LOCAL FUNCTION PROTOTYPES
*/
int cdecl _filbuf(f)
REGISTER FILE *f;
{
if((f->_cnt = _read(f->_file,f->_base,f->_bsize)) <= 0)
{
if(!f->_cnt) f->_flag |= _IOEOF;
else f->_flag |= _IOERR;
return(EOF);
}
f->_ptr = f->_base;
--f->_cnt;
return((int) *f->_ptr++ & 0xff);
}
/* Just like _filbuf but don't return 1st char */
void cdecl _xfilbuf(f)
REGISTER FILE *f;
{
if((f->_cnt = _read(f->_file,f->_base,f->_bsize)) <= 0)
{
if(!f->_cnt) f->_flag |= _IOEOF;
else f->_flag |= _IOERR;
}
f->_ptr = f->_base;
}
int cdecl _flsbuf(c,f)
unsigned c;
REGISTER FILE *f;
{
unsigned b;
if(f->_flag & _IONBF)
{
b = c;
if(_write(f->_file,&b,1) != 1)
{
f->_flag |= _IOERR;
return(EOF);
}
f->_cnt = 0;
return((int) c);
}
f->_cnt = f->_bsize - 1;
if(_write(f->_file,f->_base,f->_bsize) != f->_bsize)
{
f->_flag |= _IOERR;
return(EOF);
}
f->_ptr = f->_base;
*f->_ptr++ = (char) c;
return((int) c);
}
#if (_MSC_VER >= 700)
int cdecl _flush(f)
REGISTER FILE *f;
{
return(fflush(f));
}
#endif
int cdecl fflush(f)
REGISTER FILE *f;
{
REGISTER int i;
if(f->_flag & _IONBF) return(0);
if(f->_flag & _IOWRT)
{
i = f->_bsize - f->_cnt;
f->_cnt = f->_bsize;
if(i && _write(f->_file,f->_base,i) != i)
{
f->_flag |= _IOERR;
return(EOF);
}
f->_ptr = f->_base;
return(0);
}
if(f->_flag & _IOREAD)
{
f->_cnt = 0;
return(0);
}
return(EOF);
}
int cdecl fclose(f)
REGISTER FILE *f;
{
int rc; /* Return code from close() */
if(!(f->_flag & _IOPEN))
return(EOF);
fflush(f);
if(f->_file > 2)
{
rc = _close(f->_file);
/* Free the file stream pointer regardless of close() return
* value, since code elsewhere may be intentionally calling
* fclose() on a file whose handle has already been closed.
*/
f->_flag = 0;
++cffree;
return(rc);
}
return(0);
}
long cdecl ftell(f)
REGISTER FILE *f;
{
if(f->_flag & _IONBF) return(_lseek(f->_file,0L,1));
if(f->_flag & _IOREAD) return(_lseek(f->_file,0L,1) - f->_cnt);
if(f->_flag & _IOWRT) return(_lseek(f->_file,0L,1) + f->_bsize - f->_cnt);
return(-1L);
}
int cdecl fseek(f,lfa,mode)
REGISTER FILE *f;
long lfa;
int mode;
{
REGISTER int ilfa;
f->_flag &= ~_IOEOF;
if(f->_flag & _IONBF)
{
if(_lseek(f->_file,lfa,mode) != -1L) return(0);
f->_flag |= _IOERR;
return(EOF);
}
if(mode == 1)
{
if(f->_flag & _IOREAD)
{
if(((long) f->_cnt > lfa && lfa >= 0) ||
(lfa < 0 && (long)(f->_base - f->_ptr) <= lfa))
{ /* If we won't go beyond the buffer */
ilfa = (int) lfa;
f->_cnt -= ilfa;
f->_ptr += ilfa;
return(0);
}
lfa -= f->_cnt;
}
}
if(fflush(f)) return(EOF);
if (mode != 2 && (f->_flag & _IOREAD))
{
/*
* If absolute mode, or relative mode AND forward, seek to the
* est preceding 512-byte boundary to optimize disk I/O.
* It could be done for backward relative seeks as well, but we
* would have to check whether the current file pointer (FP) is
* on a 512-byte boundary. If FP were not on a 512-byte boundary,
* we might attempt to seek before the beginning of the file.
* (Example: FP = 0x2445, destination address = 0x0010, lfa = -0x2435,
* mode = 1. Rounding of lfa to 512-boundary yields -0x2600
* which is bogus.) FP will usually not be on a 512 boundary
* at the end of file, for example. Solution is to keep track of
* current FP. This is not worth the effort, especially since
* seeks are rare because of the extended dictionary.
* Use "lfa >= 0" as test, since if mode is 0 this will always be
* true, and it also filters out backward relative seeks.
*/
if(lfa >= 0)
{
/*
* Optimization: eliminate relative seeks of 0.
*/
if(mode == 0 || lfa & ~0x1ff)
if (_lseek(f->_file, lfa & ~0x1ff, mode) == -1L)
{
f->_flag |= _IOERR;
return(EOF);
}
_xfilbuf(f);
f->_cnt -= lfa & 0x1ff; /* adjust _iobuf fields */
f->_ptr += lfa & 0x1ff;
return(0);
}
}
if(_lseek(f->_file,lfa,mode) == -1L)
{
f->_flag |= _IOERR;
return(EOF);
}
return(0);
}
int cdecl fgetc(f)
REGISTER FILE *f;
{
return(getc(f));
}
int cdecl fputc(c,f)
unsigned c;
REGISTER FILE *f;
{
unsigned b;
if(f->_flag & _IONBF)
{
b = c;
if(_write(f->_file,&b,1) == 1) return((int) c);
f->_flag |= _IOERR;
return(EOF);
}
return(putc(c,f));
}
int cdecl fputs(s,f)
REGISTER char *s;
REGISTER FILE *f;
{
int i;
if(f->_flag & _IONBF)
{
i = strlen(s);
if(_write(f->_file,s,i) == i) return(0);
f->_flag |= _IOERR;
return(EOF);
}
for(; *s; ++s)
if(putc(*s,f) == EOF) return(EOF);
return(0);
}
int cdecl fread(pobj,cbobj,nobj,f)
char *pobj;
unsigned cbobj;
unsigned nobj;
FILE *f;
{
REGISTER int i; /* # bytes left to read */
REGISTER unsigned j; /* # bytes to transfer to buffer */
// special case for one block -- try to avoid all this junk
if (cbobj == 1 && nobj <= (unsigned)f->_cnt)
{
memcpy(pobj, f->_ptr, nobj);
f->_cnt -= nobj;
f->_ptr += nobj;
return nobj;
}
i = nobj*cbobj; /* Initial request ==> bytes */
do
{
j = (i <= f->_cnt)? i: f->_cnt; /* Determine how much we can move */
memcpy( pobj,f->_ptr,j); /* Move it */
f->_cnt -= j; /* Update file count */
f->_ptr += j; /* Update file pointer */
i -= j; /* Update request count */
pobj += j; /* Update buffer pointer */
if (i && !f->_cnt) _xfilbuf(f); /* Fill buffer if necessary */
} while (i && !(f->_flag & (_IOEOF|_IOERR)));
return(nobj - i/cbobj);
}
/*
* fwrite : standard library routine
*/
int cdecl fwrite(pobj,cbobj,nobj,f)
char *pobj; /* Pointer to buffer */
int cbobj; /* # bytes per object */
int nobj; /* # objects */
register FILE *f; /* File stream */
{
register int cb; /* # bytes remaining to write */
/* Check for error initially so we don't trash data unnecessarily. */
if(ferror(f))
return(0);
/* Initialize count of bytes remaining to write. */
cb = nobj * cbobj;
if (cb > f->_cnt) // doesn't fit -- must flush
if (fflush(f))
return 0;
if (cb > f->_cnt) // bigger than the buffer... don't bother copying
{
if (_write(f->_file, pobj, cb) != cb)
return 0;
}
else
{
memcpy(f->_ptr, pobj, cb);
f->_cnt -= cb;
f->_ptr += cb;
}
return nobj;
}
int cdecl ungetc(c,f)
int c;
FILE *f;
{
if(!(f->_flag & _IONBF) && f->_cnt < f->_bsize && c != EOF)
{
++f->_cnt;
*--f->_ptr = (char) c;
return(c);
}
return(EOF);
}
void cdecl flushall ()
{
FlsStdio();
}
#if (_MSC_VER >= 700)
void cdecl _flushall ()
{
FlsStdio();
}
#endif
void cdecl FlsStdio()
{
FILE *p;
for(p = _iob; p < &_iob[_NSTD]; p++)
if(p->_flag & _IOPEN) fclose(p);
}
/*
* makestream
*
* Makes a file stream structure for a possibly already-opened file.
* Does common work for fopen, fdopen.
* If name parameter is NULL, then file has been opened, else use the
* name.
* RETURNS pointer to stream or NULL.
*/
LOCAL FILE * NEAR cdecl makestream(mode,name,fh)
char *mode;
char *name;
int fh;
{
REGISTER int i;
REGISTER FILE *f;
int openmode;
int iOpenRet;
if(!cffree--)
{
cffree = 0;
return(NULL);
}
for(i = _NSTD; _iob[i]._flag & _IOPEN; ++i);
f = &_iob[i];
f->_base = NULL;
f->_bsize = 0;
f->_flag = _IONBF;
if(name == NULL)
f->_file = (char) fh;
if(*mode == 'r')
{
openmode = O_RDONLY;
if(mode[1] == 't')
openmode |= O_TEXT;
else if(mode[1] == 'b')
openmode |= O_BINARY;
if(name != NULL)
{
iOpenRet = _open(name,openmode);
if (iOpenRet == -1)
{
++cffree;
return(NULL);
}
else
{
f->_file = (char) iOpenRet;
}
}
f->_cnt = 0;
f->_flag |= _IOREAD;
return(f);
}
f->_cnt = f->_bsize;
f->_ptr = f->_base;
openmode = O_CREAT | O_TRUNC | O_WRONLY;
if(mode[1] == 't')
openmode |= O_TEXT;
else if(mode[1] == 'b')
openmode |= O_BINARY;
if(name != NULL)
{
iOpenRet = _open(name,openmode, 0600);
if (iOpenRet == -1)
{
++cffree;
return(NULL);
}
else
{
f->_file = (char) iOpenRet;
}
}
f->_flag |= _IOWRT;
return(f);
}
/*
* fopen : (standard library routine)
*
* WARNING: This is a LIMITED version of fopen(). Only "r" and
* "w" modes are supported.
*/
FILE * cdecl fopen(name,mode)
char *name;
char *mode;
{
return(makestream(mode,name,0));
}
/*
* fdopen : (standard library routine)
*
* WARNING: This is a LIMITED version of fdopen(). Only "r" and
* "w" modes are supported.
*/
FILE * cdecl fdopen(fh,mode)
int fh;
char *mode;
{
return(makestream(mode,NULL,fh));
}
/*
* setvbuf : standard library routine
*
* WARNING: This is a LIMITED version of setvbuf(). Only
* type _IOFBF is supported.
*/
int cdecl setvbuf (fh, buf, type, size)
FILE *fh;
char *buf;
int type;
int size;
{
if(fflush(fh) || type != _IOFBF)
return(EOF);
fh->_base = buf;
fh->_flag &= ~_IONBF;
fh->_bsize = size;
if(fh->_flag & _IOWRT)
{
fh->_cnt = size;
fh->_ptr = buf;
}
return(0);
}
#endif
int
__cdecl
printf(char *fmt, ...)
{
va_list marker;
int ret;
va_start(marker, fmt);
ret = vfprintf(stdout, fmt, marker);
fflush(stdout);
va_end(marker);
return ret;
}
//
// DLH Can't use fprintf or vfprintf from MSVCRT.DLL, since the FILE structure
// is too different.
//
int cdecl fprintf(struct file *f, const char *fmt, ...)
{
va_list marker;
int ret;
va_start(marker, fmt);
ret = vfprintf(f, fmt, marker);
fflush(f);
va_end(marker);
return ret;
}
int cdecl vfprintf(struct file *f, const char *fmt, va_list pArgs)
{
int cb;
static char szBuf[4096];
cb = vsprintf(szBuf, fmt, pArgs);
fwrite(szBuf, 1, cb, f);
return cb;
}