diff options
Diffstat (limited to 'private/crt32/lowio/read.c')
-rw-r--r-- | private/crt32/lowio/read.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/private/crt32/lowio/read.c b/private/crt32/lowio/read.c new file mode 100644 index 000000000..d11805761 --- /dev/null +++ b/private/crt32/lowio/read.c @@ -0,0 +1,349 @@ +/*** +*read.c - OS/2 read from a file handle +* +* Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _read() - read from a file handle +* +*Revision History: +* 06-19-89 PHG Module created, based on asm version +* 03-13-90 GJF Made calling type _CALLTYPE2 (for now), added #include +* <cruntime.h> and fixed compiler warnings. Also, fixed +* the copyright. +* 04-03-90 GJF Now _CALLTYPE1. +* 07-24-90 SBM Removed '32' from API names +* 08-14-90 SBM Compiles cleanly with -W3 +* 10-01-90 GJF New-style function declarator. +* 12-04-90 GJF Appended Win32 version onto the source with #ifdef-s. +* It is enough different that there is little point in +* trying to more closely merge the two versions. +* 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h> +* 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo +* 12-28-90 SRW Added cast of void * to char * for Mips C Compiler +* 01-16-91 GJF ANSI naming. +* 01-29-91 SRW Changed to not read ahead on char devices [_WIN32_] +* 02-01-91 SRW Changed to use ERROR_HANDLE_EOF error code (_WIN32_) +* 02-25-91 MHL Adapt to ReadFile/WriteFile changes (_WIN32_) +* 04-09-91 PNT Added _MAC_ conditional +* 04-16-91 SRW Character device bug fix [_WIN32_] +* 05-23-91 GJF Don't set FEOFLAG if handle corresponds to a device. +* 10-24-91 GJF Added LPDWORD casts to make MIPS compiler happy. +* ASSUMES THAT sizeof(int) == sizeof(DWORD). +* 02-13-92 GJF Replaced _nfile by _nhandle for Win32. +* 06-16-92 GJF Bug fix - if CR was the very last char read, and the +* last char in the file, CRLF was getting written to +* user's buffer. +* 12-18-93 GJF Don't treat ERROR_BROKEN_PIPE as an error. Instead, +* just return 0. +* +*******************************************************************************/ + +#include <cruntime.h> +#include <oscalls.h> +#include <os2dll.h> +#include <io.h> +#include <internal.h> +#include <stdlib.h> +#include <errno.h> +#include <msdos.h> + +#define LF 10 /* line feed */ +#define CR 13 /* carriage return */ +#define CTRLZ 26 /* ctrl-z means eof for text */ + +/*** +*int _read(fh, buf, cnt) - read bytes from a file handle +* +*Purpose: +* Attempts to read cnt bytes from fh into a buffer. +* If the file is in text mode, CR-LF's are mapped to LF's, thus +* affecting the number of characters read. This does not +* affect the file pointer. +* +* NOTE: The stdio _IOCTRLZ flag is tied to the use of FEOFLAG. +* Cross-reference the two symbols before changing FEOFLAG's use. +* +*Entry: +* int fh - file handle to read from +* char *buf - buffer to read into +* int cnt - number of bytes to read +* +*Exit: +* Returns number of bytes read (may be less than the number requested +* if the EOF was reached or the file is in text mode). +* returns -1 (and sets errno) if fails. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef MTHREAD + +/* define normal version that locks/unlocks, validates fh */ +int _CALLTYPE1 _read ( + int fh, + void *buf, + unsigned cnt + ) +{ + int r; /* return value */ + + /* validate handle */ +#ifdef _WIN32_ + if ( (unsigned)fh >= (unsigned)_nhandle ) { +#else + if ((unsigned)fh >= (unsigned)_nfile) { +#endif + /* out of range -- return error */ + errno = EBADF; + _doserrno = 0; /* not OS/2 error */ + return -1; + } + + _lock_fh(fh); /* lock file */ + r = _read_lk(fh, buf, cnt); /* read bytes */ + _unlock_fh(fh); /* unlock file */ + + return r; +} + +/* now define version that doesn't lock/unlock, validate fh */ +int _CALLTYPE1 _read_lk ( + int fh, + void *buf, + unsigned cnt + ) +{ + int bytes_read; /* number of bytes read */ + char *buffer; /* buffer to read to */ + int os_read; /* bytes read on OS call */ + char *p, *q; /* pointers into buffer */ + char peekchr; /* peek-ahead character */ + ULONG filepos; /* file position after seek */ + ULONG dosretval; /* OS/2 return value */ + + +#else + +/* now define normal version */ +int _CALLTYPE1 _read ( + int fh, + void *buf, + unsigned cnt + ) +{ + int bytes_read; /* number of bytes read */ + char *buffer; /* buffer to read to */ + int os_read; /* bytes read on OS call */ + char *p, *q; /* pointers into buffer */ + char peekchr; /* peek-ahead character */ + ULONG filepos; /* file position after seek */ + ULONG dosretval; /* OS/2 return value */ + + /* validate fh */ +#ifdef _WIN32_ + if ( (unsigned)fh >= (unsigned)_nhandle ) { +#else + if ((unsigned)fh >= (unsigned)_nfile) { +#endif + /* bad file handle */ + errno = EBADF; + _doserrno = 0; /* not OS/2 error */ + return -1; + } + +#endif + + bytes_read = 0; /* nothing read yet */ + buffer = buf; + + if (cnt == 0 || (_osfile[fh] & FEOFLAG)) { + /* nothing to read or at EOF, so return 0 read */ + return 0; + } + + if ((_osfile[fh] & (FPIPE|FDEV)) && _pipech[fh] != LF) { + /* a pipe/device and pipe lookahead non-empty: read the lookahead char */ + *buffer++ = _pipech[fh]; + ++bytes_read; + --cnt; + _pipech[fh] = LF; /* mark as empty */ + } + + /* read the data */ +#ifdef _CRUISER_ + + if ( dosretval = DOSREAD(fh, buffer, cnt, &os_read) ) { + /* OS error, map it and return */ + if (dosretval == ERROR_ACCESS_DENIED) { + /* wrong read/write mode should return EBADF, not EACCES */ + errno = EBADF; + _doserrno = dosretval; + } + else + _dosmaperr(dosretval); + return -1; + } + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + if ( !ReadFile((HANDLE)_osfhnd[fh], buffer, cnt, (LPDWORD)&os_read, + NULL) ) { + + /* ReadFile has reported an error. recognize two special cases. + * + * 1. map ERROR_ACCESS_DENIED to EBADF + * + * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it + * means the handle is a read-handle on a pipe for which + * all write-handles have been closed and all data has been + * read. */ + + if ( (dosretval = GetLastError()) == ERROR_ACCESS_DENIED ) { + /* wrong read/write mode should return EBADF, not EACCES */ + errno = EBADF; + _doserrno = dosretval; + return -1; + } + else if ( dosretval == ERROR_BROKEN_PIPE ) { + return 0; + } + else { + _dosmaperr(dosretval); + return -1; + } + } + +#else /* ndef _WIN32_ */ + +#ifdef _MAC_ + + TBD(); + +#else /* ndef _MAC_ */ + +#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED! + +#endif /* _MAC_ */ + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + + bytes_read += os_read; /* update bytes read */ + + if (_osfile[fh] & FTEXT) { + /* now must translate CR-LFs to LFs in the buffer */ + + /* set CRLF flag to indicate LF at beginning of buffer */ + if (*(char *)buf == LF) + _osfile[fh] |= FCRLF; + else + _osfile[fh] &= ~FCRLF; + + /* convert chars in the buffer: p is src, q is dest */ + p = q = buf; + while (p < (char *)buf + bytes_read) { + if (*p == CTRLZ) { + /* if fh is not a device, set ctrl-z flag */ + if ( !(_osfile[fh] & FDEV) ) + _osfile[fh] |= FEOFLAG; + break; /* stop translating */ + } + else if (*p != CR) + *q++ = *p++; + else { + /* *p is CR, so must check next char for LF */ + if (p < (char *)buf + bytes_read - 1) { + if (*(p+1) == LF) { + p += 2; + *q++ = LF; /* convert CR-LF to LF */ + } + else + *q++ = *p++; /* store char normally */ + } + else { + /* This is the hard part. We found a CR at end of + buffer. We must peek ahead to see if next char + is an LF. */ + ++p; +#ifdef _CRUISER_ + + dosretval = DOSREAD(fh, &peekchr, 1, &os_read); + +#else /* ndef _CRUISER_ */ + +#ifdef _WIN32_ + + dosretval = 0; + if ( !ReadFile((HANDLE)_osfhnd[fh], &peekchr, 1, + (LPDWORD)&os_read, NULL) ) + dosretval = GetLastError(); + +#else /* ndef _WIN32_ */ + +#ifdef _MAC_ + + TBD(); + +#else /* ndef _MAC_ */ + +#error ERROR - ONLY CRUISER, WIN32, OR MAC TARGET SUPPORTED! + +#endif /* _MAC_ */ + +#endif /* _WIN32_ */ + +#endif /* _CRUISER_ */ + if (dosretval != 0 || os_read == 0) { + /* couldn't read ahead, store CR */ + *q++ = CR; + } + else { + /* peekchr now has the extra character -- we now have + several possibilities: + 1. disk file and char is not LF; just seek back + and copy CR + 2. disk file and char is LF; seek back and discard CR + 3. disk file, char is LF but this is a one-byte read: + store LF, don't seek back + 4. pipe/device and char is LF; store LF. + 5. pipe/device and char isn't LF, store CR and put + char in pipe lookahead buffer. */ + if (_osfile[fh] & (FDEV|FPIPE)) { + /* non-seekable device */ + if (peekchr == LF) + *q++ = LF; + else { + *q++ = CR; + _pipech[fh] = peekchr; + } + } + else { + /* disk file */ + if (q == buf && peekchr == LF) { + /* nothing read yet; must make some progress */ + *q++ = LF; + } + else { + /* seek back */ + filepos = _lseek_lk(fh, -1, FILE_CURRENT); + if (peekchr != LF) + *q++ = CR; + } + } + } + } + } + } + + /* we now change bytes_read to reflect the true number of chars + in the buffer */ + bytes_read = q - (char *)buf; + } + + return bytes_read; /* and return */ +} |