home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / read.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  12KB  |  365 lines

  1. /***
  2. *read.c - read from a file handle
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _read() - read from a file handle
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifndef _MAC
  12.  
  13.  
  14. #include <cruntime.h>
  15. #include <oscalls.h>
  16. #include <mtdll.h>
  17. #include <io.h>
  18. #include <internal.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <msdos.h>
  22.  
  23. #define LF 10           /* line feed */
  24. #define CR 13           /* carriage return */
  25. #define CTRLZ 26        /* ctrl-z means eof for text */
  26.  
  27. /***
  28. *int _read(fh, buf, cnt) - read bytes from a file handle
  29. *
  30. *Purpose:
  31. *       Attempts to read cnt bytes from fh into a buffer.
  32. *       If the file is in text mode, CR-LF's are mapped to LF's, thus
  33. *       affecting the number of characters read.  This does not
  34. *       affect the file pointer.
  35. *
  36. *       NOTE:  The stdio _IOCTRLZ flag is tied to the use of FEOFLAG.
  37. *       Cross-reference the two symbols before changing FEOFLAG's use.
  38. *
  39. *Entry:
  40. *       int fh - file handle to read from
  41. *       char *buf - buffer to read into
  42. *       int cnt - number of bytes to read
  43. *
  44. *Exit:
  45. *       Returns number of bytes read (may be less than the number requested
  46. *       if the EOF was reached or the file is in text mode).
  47. *       returns -1 (and sets errno) if fails.
  48. *
  49. *Exceptions:
  50. *
  51. *******************************************************************************/
  52.  
  53. #ifdef _MT
  54.  
  55. /* define normal version that locks/unlocks, validates fh */
  56. int __cdecl _read (
  57.         int fh,
  58.         void *buf,
  59.         unsigned cnt
  60.         )
  61. {
  62.         int r;                          /* return value */
  63.  
  64.         /* validate handle */
  65.         if ( ((unsigned)fh >= (unsigned)_nhandle) ||
  66.              !(_osfile(fh) & FOPEN) )
  67.         {
  68.             /* out of range -- return error */
  69.             errno = EBADF;
  70.             _doserrno = 0;  /* not o.s. error */
  71.             return -1;
  72.         }
  73.  
  74.         _lock_fh(fh);                   /* lock file */
  75.         r = _read_lk(fh, buf, cnt);     /* read bytes */
  76.         _unlock_fh(fh);                 /* unlock file */
  77.  
  78.         return r;
  79. }
  80.  
  81. /* now define version that doesn't lock/unlock, validate fh */
  82. int __cdecl _read_lk (
  83.         int fh,
  84.         void *buf,
  85.         unsigned cnt
  86.         )
  87. {
  88.         int bytes_read;                 /* number of bytes read */
  89.         char *buffer;                   /* buffer to read to */
  90.         int os_read;                    /* bytes read on OS call */
  91.         char *p, *q;                    /* pointers into buffer */
  92.         char peekchr;                   /* peek-ahead character */
  93.         ULONG filepos;                  /* file position after seek */
  94.         ULONG dosretval;                /* o.s. return value */
  95.  
  96.  
  97. #else  /* _MT */
  98.  
  99. /* now define normal version */
  100. int __cdecl _read (
  101.         int fh,
  102.         void *buf,
  103.         unsigned cnt
  104.         )
  105. {
  106.         int bytes_read;                 /* number of bytes read */
  107.         char *buffer;                   /* buffer to read to */
  108.         int os_read;                    /* bytes read on OS call */
  109.         char *p, *q;                    /* pointers into buffer */
  110.         char peekchr;                   /* peek-ahead character */
  111.         ULONG filepos;                  /* file position after seek */
  112.         ULONG dosretval;                /* o.s. return value */
  113.  
  114.         /* validate fh */
  115.         if ( ((unsigned)fh >= (unsigned)_nhandle) ||
  116.              !(_osfile(fh) & FOPEN) )
  117.         {
  118.             /* bad file handle */
  119.             errno = EBADF;
  120.             _doserrno = 0;              /* not o.s. error */
  121.             return -1;
  122.         }
  123.  
  124. #endif  /* _MT */
  125.  
  126.         bytes_read = 0;                 /* nothing read yet */
  127.         buffer = buf;
  128.  
  129.         if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
  130.             /* nothing to read or at EOF, so return 0 read */
  131.             return 0;
  132.         }
  133.  
  134.         if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
  135.             /* a pipe/device and pipe lookahead non-empty: read the lookahead
  136.              * char */
  137.             *buffer++ = _pipech(fh);
  138.             ++bytes_read;
  139.             --cnt;
  140.             _pipech(fh) = LF;           /* mark as empty */
  141.         }
  142.  
  143.         /* read the data */
  144.  
  145.         if ( !ReadFile( (HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read,
  146.                         NULL ) )
  147.         {
  148.             /* ReadFile has reported an error. recognize two special cases.
  149.              *
  150.              *      1. map ERROR_ACCESS_DENIED to EBADF
  151.              *
  152.              *      2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
  153.              *         means the handle is a read-handle on a pipe for which
  154.              *         all write-handles have been closed and all data has been
  155.              *         read. */
  156.  
  157.             if ( (dosretval = GetLastError()) == ERROR_ACCESS_DENIED ) {
  158.                 /* wrong read/write mode should return EBADF, not EACCES */
  159.                 errno = EBADF;
  160.                 _doserrno = dosretval;
  161.                 return -1;
  162.             }
  163.             else if ( dosretval == ERROR_BROKEN_PIPE ) {
  164.                 return 0;
  165.             }
  166.             else {
  167.                 _dosmaperr(dosretval);
  168.                 return -1;
  169.             }
  170.         }
  171.  
  172.         bytes_read += os_read;          /* update bytes read */
  173.  
  174.         if (_osfile(fh) & FTEXT) {
  175.             /* now must translate CR-LFs to LFs in the buffer */
  176.  
  177.             /* set CRLF flag to indicate LF at beginning of buffer */
  178.             if ( (os_read != 0) && (*(char *)buf == LF) )
  179.                 _osfile(fh) |= FCRLF;
  180.             else
  181.                 _osfile(fh) &= ~FCRLF;
  182.  
  183.             /* convert chars in the buffer: p is src, q is dest */
  184.             p = q = buf;
  185.             while (p < (char *)buf + bytes_read) {
  186.                 if (*p == CTRLZ) {
  187.                     /* if fh is not a device, set ctrl-z flag */
  188.                     if ( !(_osfile(fh) & FDEV) )
  189.                         _osfile(fh) |= FEOFLAG;
  190.                     break;              /* stop translating */
  191.                 }
  192.                 else if (*p != CR)
  193.                     *q++ = *p++;
  194.                 else {
  195.                     /* *p is CR, so must check next char for LF */
  196.                     if (p < (char *)buf + bytes_read - 1) {
  197.                         if (*(p+1) == LF) {
  198.                             p += 2;
  199.                             *q++ = LF;  /* convert CR-LF to LF */
  200.                         }
  201.                         else
  202.                             *q++ = *p++;    /* store char normally */
  203.                     }
  204.                     else {
  205.                         /* This is the hard part.  We found a CR at end of
  206.                            buffer.  We must peek ahead to see if next char
  207.                            is an LF. */
  208.                         ++p;
  209.  
  210.                         dosretval = 0;
  211.                         if ( !ReadFile( (HANDLE)_osfhnd(fh), &peekchr, 1,
  212.                                         (LPDWORD)&os_read, NULL ) )
  213.                             dosretval = GetLastError();
  214.  
  215.                         if (dosretval != 0 || os_read == 0) {
  216.                             /* couldn't read ahead, store CR */
  217.                             *q++ = CR;
  218.                         }
  219.                         else {
  220.                             /* peekchr now has the extra character -- we now
  221.                                have several possibilities:
  222.                                1. disk file and char is not LF; just seek back
  223.                                   and copy CR
  224.                                2. disk file and char is LF; seek back and
  225.                                   discard CR
  226.                                3. disk file, char is LF but this is a one-byte
  227.                                   read: store LF, don't seek back
  228.                                4. pipe/device and char is LF; store LF.
  229.                                5. pipe/device and char isn't LF, store CR and
  230.                                   put char in pipe lookahead buffer. */
  231.                             if (_osfile(fh) & (FDEV|FPIPE)) {
  232.                                 /* non-seekable device */
  233.                                 if (peekchr == LF)
  234.                                     *q++ = LF;
  235.                                 else {
  236.                                     *q++ = CR;
  237.                                     _pipech(fh) = peekchr;
  238.                                 }
  239.                             }
  240.                             else {
  241.                                 /* disk file */
  242.                                 if (q == buf && peekchr == LF) {
  243.                                     /* nothing read yet; must make some
  244.                                        progress */
  245.                                     *q++ = LF;
  246.                                 }
  247.                                 else {
  248.                                     /* seek back */
  249.                                     filepos = _lseek_lk(fh, -1, FILE_CURRENT);
  250.                                     if (peekchr != LF)
  251.                                         *q++ = CR;
  252.                                 }
  253.                             }
  254.                         }
  255.                     }
  256.                 }
  257.             }
  258.  
  259.             /* we now change bytes_read to reflect the true number of chars
  260.                in the buffer */
  261.             bytes_read = q - (char *)buf;
  262.         }
  263.  
  264.         return bytes_read;              /* and return */
  265. }
  266.  
  267.  
  268. #else  /* _MAC */
  269.  
  270.  
  271. #include <cruntime.h>
  272. #include <io.h>
  273. #include <internal.h>
  274. #include <stdlib.h>
  275. #include <errno.h>
  276. #include <msdos.h>
  277. #include <macos\files.h>
  278. #include <macos\errors.h>
  279. #include <mpw.h>
  280.  
  281. /***
  282. *int _read(fh, buf, cnt) - read bytes from a file handle
  283. *
  284. *Purpose:
  285. *       Attempts to read cnt bytes from fh into a buffer.
  286. *
  287. *Entry:
  288. *       int fh - file handle to read from
  289. *       char *buf - buffer to read into
  290. *       int cnt - number of bytes to read
  291. *
  292. *Exit:
  293. *       Returns number of bytes read (may be less than the number requested
  294. *       if the EOF was reached or the file is in text mode).
  295. *       returns -1 (and sets errno) if fails.
  296. *
  297. *Exceptions:
  298. *
  299. *******************************************************************************/
  300.  
  301.  
  302. int __cdecl _read (
  303.         int fh,
  304.         const void *buf,
  305.         unsigned cnt
  306.         )
  307. {
  308.         OSErr osErr;
  309.         int cbReturn;
  310.         /* validate handle */
  311.         if ( ((unsigned)fh >= (unsigned)_nfile) || !(_osfile[fh] & FOPEN) ||
  312.              (_osfile[fh] & FWRONLY) )
  313.         {
  314.             /* out of range -- return error */
  315.             errno = EBADF;
  316.             _macerrno = 0;
  317.             return -1;
  318.         }
  319.  
  320.         if (_osfile[fh] & FDEV)
  321.         {
  322.             MPWFILE *pparm;
  323.  
  324.             /* MPW console */
  325.             pparm = (MPWFILE *)_osfhnd[fh];
  326.             pparm->count = cnt;
  327.             (const void *)(pparm->pBuff) = buf;
  328.             osErr = (*((pparm->pDevice)->read))(pparm);
  329.             if (osErr)
  330.             {
  331.                 osErr = pparm->err;
  332.             }
  333.             cbReturn = cnt - pparm->count;
  334.         }
  335.         else
  336.         {
  337.             ParamBlockRec parm;
  338.  
  339.             /* File */
  340.  
  341.             parm.ioParam.ioRefNum = _osfhnd[fh];
  342.             (const void *)parm.ioParam.ioBuffer = buf;
  343.             parm.ioParam.ioReqCount = cnt;
  344.             parm.ioParam.ioPosOffset = 0;
  345.             parm.ioParam.ioPosMode = fsAtMark;
  346.             osErr = PBReadSync(&parm);
  347.  
  348.             cbReturn = parm.ioParam.ioActCount;
  349.         }
  350.  
  351.         if (!osErr || osErr == eofErr)
  352.         {
  353.             return cbReturn;
  354.         }
  355.         else
  356.         {
  357.             _dosmaperr(osErr);
  358.             return -1;
  359.         }
  360.  
  361. }
  362.  
  363.  
  364. #endif  /* _MAC */
  365.