/*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 #include #include #include #include #if NOT defined( _WIN32 ) #define i386 #endif #include #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; }