Dan Kegel : msvcrt: Remove CRs earlier in ascii mode.

Alexandre Julliard julliard at winehq.org
Mon Jan 19 08:58:49 CST 2009


Module: wine
Branch: master
Commit: ebe4a9e321800fbe6d2004a640cd276a28d15c38
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ebe4a9e321800fbe6d2004a640cd276a28d15c38

Author: Dan Kegel <dank at kegel.com>
Date:   Sun Jan 18 19:19:46 2009 -0800

msvcrt: Remove CRs earlier in ascii mode.

---

 dlls/msvcrt/file.c       |   90 +++++++++++++++++++--------------------------
 dlls/msvcrt/tests/file.c |   34 +++++++++++++++++-
 2 files changed, 71 insertions(+), 53 deletions(-)

diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c
index 8945044..e3bc6c4 100644
--- a/dlls/msvcrt/file.c
+++ b/dlls/msvcrt/file.c
@@ -1639,27 +1639,6 @@ int CDECL _rmtmp(void)
 }
 
 /*********************************************************************
- * (internal) remove_cr
- *
- * Translate all \r\n to \n inplace.
- * return the number of \r removed
- * Corner cases required by some apps:
- *   \r\r\n -> \r\n
- * BUG: should save state across calls somehow, so CR LF that
- * straddles buffer boundary gets recognized properly?
- */
-static unsigned int remove_cr(char *buf, unsigned int count)
-{
-    unsigned int i, j;
-
-    for (i=0, j=0; j < count; j++)
-        if ((buf[j] != '\r') || ((j+1) < count && buf[j+1] != '\n'))
-	    buf[i++] = buf[j];
-
-    return count - i;
-}
-
-/*********************************************************************
  * (internal) read_i
  */
 static int read_i(int fd, void *buf, unsigned int count)
@@ -1686,18 +1665,25 @@ static int read_i(int fd, void *buf, unsigned int count)
     {
         if (MSVCRT_fdesc[fd].wxflag & WX_TEXT)
         {
-            DWORD i;
-            /* in text mode, a ctrl-z signals EOF */
-            for (i=0; i<num_read; i++)
+            DWORD i, j;
+            for (i=0, j=0; i<num_read; i++)
             {
+                /* in text mode, a ctrl-z signals EOF */
                 if (bufstart[i] == 0x1a)
                 {
-                    num_read = i;
                     MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
                     break;
                 }
+                /* in text mode, strip \r if followed by \n.
+                 * BUG: should save state across calls somehow, so CR LF that
+                 * straddles buffer boundary gets recognized properly?
+                 */
+		if ((bufstart[i] != '\r')
+                ||  ((i+1) < num_read && bufstart[i+1] != '\n'))
+		    bufstart[j++] = bufstart[i];
             }
+            num_read = j;
         }
         if (count != 0 && num_read == 0)
         {
@@ -1732,10 +1718,6 @@ int CDECL MSVCRT__read(int fd, void *buf, unsigned int count)
 {
   int num_read;
   num_read = read_i(fd, buf, count);
-  if (num_read>0 && MSVCRT_fdesc[fd].wxflag & WX_TEXT)
-  {
-      num_read -= remove_cr(buf,num_read);
-  }
   return num_read;
 }
 
@@ -2219,17 +2201,13 @@ int CDECL MSVCRT_fgetc(MSVCRT_FILE* file)
 {
   unsigned char *i;
   unsigned int j;
-  do {
-    if (file->_cnt>0) {
-      file->_cnt--;
-      i = (unsigned char *)file->_ptr++;
-      j = *i;
-    } else
-      j = MSVCRT__filbuf(file);
-    if (!(MSVCRT_fdesc[file->_file].wxflag & WX_TEXT)
-    || ((j != '\r') || (file->_cnt && file->_ptr[0] != '\n')))
-        return j;
-  } while(1);
+  if (file->_cnt>0) {
+    file->_cnt--;
+    i = (unsigned char *)file->_ptr++;
+    j = *i;
+  } else
+    j = MSVCRT__filbuf(file);
+  return j;
 }
 
 /*********************************************************************
@@ -2597,17 +2575,13 @@ MSVCRT_size_t CDECL MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nm
 
   /* first buffered data */
   if(file->_cnt>0) {
-     while (file->_cnt>0 && rcnt > 0) {
 	int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
 	memcpy(ptr, file->_ptr, pcnt);
 	file->_cnt -= pcnt;
 	file->_ptr += pcnt;
-	if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT)
-            pcnt -= remove_cr(ptr,pcnt);
 	read += pcnt ;
 	rcnt -= pcnt ;
         ptr = (char*)ptr + pcnt;
-     }
   } else if(!(file->_flag & MSVCRT__IOREAD )) {
 	if(file->_flag & MSVCRT__IORW) {
 		file->_flag |= MSVCRT__IOREAD;
@@ -2723,17 +2697,26 @@ int CDECL MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
  */
 LONG CDECL MSVCRT_ftell(MSVCRT_FILE* file)
 {
+  /* TODO: just call fgetpos and return lower half of result */
   int off=0;
   long pos;
+  pos = _tell(file->_file);
+  if(pos == -1) return -1;
   if(file->_bufsiz)  {
 	if( file->_flag & MSVCRT__IOWRT ) {
 		off = file->_ptr - file->_base;
 	} else {
 		off = -file->_cnt;
+		if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT) {
+			/* Black magic correction for CR removal */
+			int i;
+			for (i=0; i<file->_cnt; i++) {
+				if (file->_ptr[i] == '\n')
+					off--;
+			}
+		}
 	}
   }
-  pos = _tell(file->_file);
-  if(pos == -1) return pos;
   return off + pos;
 }
 
@@ -2742,22 +2725,25 @@ LONG CDECL MSVCRT_ftell(MSVCRT_FILE* file)
  */
 int CDECL MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
 {
-  /* This code has been lifted form the MSVCRT_ftell function */
   int off=0;
-
   *pos = MSVCRT__lseeki64(file->_file,0,SEEK_CUR);
-
-  if (*pos == -1) return -1;
-  
+  if(*pos == -1) return -1;
   if(file->_bufsiz)  {
 	if( file->_flag & MSVCRT__IOWRT ) {
 		off = file->_ptr - file->_base;
 	} else {
 		off = -file->_cnt;
+		if (MSVCRT_fdesc[file->_file].wxflag & WX_TEXT) {
+			/* Black magic correction for CR removal */
+			int i;
+			for (i=0; i<file->_cnt; i++) {
+				if (file->_ptr[i] == '\n')
+					off--;
+			}
+		}
 	}
   }
   *pos += off;
-  
   return 0;
 }
 
diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c
index 91effe9..44ca961 100644
--- a/dlls/msvcrt/tests/file.c
+++ b/dlls/msvcrt/tests/file.c
@@ -36,6 +36,37 @@
 
 static HANDLE proc_handles[2];
 
+static void test_filbuf( void )
+{
+    FILE *fp;
+    int c;
+    fpos_t pos;
+
+    fp = fopen("filbuf.tst", "wb");
+    fwrite("\n\n\n\n", 1, 4, fp);
+    fclose(fp);
+
+    fp = fopen("filbuf.tst", "rt");
+    c = _filbuf(fp);
+    ok(c == '\n', "read wrong byte\n");
+    /* See bug 16970 for why we care about _filbuf.
+     * ftell returns screwy values on files with lots
+     * of bare LFs in ascii mode because it assumes
+     * that ascii files contain only CRLFs, removes
+     * the CR's early in _filbuf, and adjusts the return
+     * value of ftell to compensate.
+     * native _filbuf will read the whole file, then consume and return
+     * the first one.  That leaves fp->_fd at offset 4, and fp->_ptr
+     * pointing to a buffer of three bare LFs, so
+     * ftell will return 4 - 3 - 3 = -2.
+     */
+    ok(ftell(fp) == -2, "ascii crlf removal does not match native\n");
+    ok(fgetpos(fp, &pos) == 0, "fgetpos fail\n");
+    ok(pos == -2, "ftell does not match fgetpos\n");
+    fclose(fp);
+    unlink("filbuf.tst");
+}
+
 static void test_fdopen( void )
 {
     static const char buffer[] = {0,1,2,3,4,5,6,7,8,9};
@@ -463,7 +494,7 @@ static void test_fgetwc( void )
   ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l);
   fgetws(wtextW,LLEN,tempfh);
   l=ftell(tempfh);
-  ok(l==BUFSIZ-2+strlen(mytext), "ftell got %ld\n", l);
+  ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n", BUFSIZ-2+strlen(mytext), l);
   mytextW = AtoW (mytext);
   aptr = mytextW;
   wptr = wtextW;
@@ -1146,6 +1177,7 @@ START_TEST(file)
     test_unlink();
 
     /* testing stream I/O */
+    test_filbuf();
     test_fdopen();
     test_fopen_fclose_fcloseall();
     test_fileops();




More information about the wine-cvs mailing list