[CRT]
[reactos.git] / reactos / lib / sdk / crt / stdio / file.c
index 1545816..cb5f5ae 100644 (file)
@@ -76,6 +76,7 @@ int *__p___mb_cur_max(void);
 #define WX_OPEN           0x01
 #define WX_ATEOF          0x02
 #define WX_READEOF        0x04  /* like ATEOF, but for underlying file rather than buffer */
+#define WX_READCR         0x08  /* underlying file is at \r */
 #define WX_DONTINHERIT    0x10
 #define WX_APPEND         0x20
 #define WX_TEXT           0x80
@@ -87,7 +88,7 @@ int *__p___mb_cur_max(void);
 typedef struct {
     HANDLE              handle;
     unsigned char       wxflag;
-    DWORD               unkn[7]; /* critical section and init flag */       
+    DWORD               unkn[7]; /* critical section and init flag */
 } ioinfo;
 
 ioinfo fdesc[MAX_FILES];
@@ -291,12 +292,12 @@ unsigned create_io_inherit_block(WORD *size, BYTE **block)
       *handle_ptr = INVALID_HANDLE_VALUE;
     }
     wxflag_ptr++; handle_ptr++;
-  } 
+  }
   return TRUE;
 }
 
-/* INTERNAL: Set up all file descriptors, 
- * as well as default streams (stdin, stderr and stdout) 
+/* INTERNAL: Set up all file descriptors,
+ * as well as default streams (stdin, stderr and stdout)
  */
 void msvcrt_init_io(void)
 {
@@ -341,7 +342,7 @@ void msvcrt_init_io(void)
   {
 #ifndef __REACTOS__
     DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
-                    GetCurrentProcess(), &fdesc[0].handle, 0, TRUE, 
+                    GetCurrentProcess(), &fdesc[0].handle, 0, TRUE,
                     DUPLICATE_SAME_ACCESS);
 #else
       fdesc[0].handle = GetStdHandle(STD_INPUT_HANDLE);
@@ -354,7 +355,7 @@ void msvcrt_init_io(void)
   {
 #ifndef __REACTOS__
       DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE),
-                    GetCurrentProcess(), &fdesc[1].handle, 0, TRUE, 
+                    GetCurrentProcess(), &fdesc[1].handle, 0, TRUE,
                     DUPLICATE_SAME_ACCESS);
 #else
       fdesc[1].handle = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -367,7 +368,7 @@ void msvcrt_init_io(void)
   {
 #ifndef __REACTOS__
       DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
-                    GetCurrentProcess(), &fdesc[2].handle, 0, TRUE, 
+                    GetCurrentProcess(), &fdesc[2].handle, 0, TRUE,
                     DUPLICATE_SAME_ACCESS);
 #else
       fdesc[2].handle = GetStdHandle(STD_ERROR_HANDLE);
@@ -408,7 +409,7 @@ static int flush_buffer(FILE* file)
 }
 
 /* INTERNAL: Allocate stdio file buffer */
-static void alloc_buffer(FILE* file)
+void alloc_buffer(FILE* file)
 {
        file->_base = calloc(BUFSIZ,1);
        if(file->_base) {
@@ -721,7 +722,7 @@ int CDECL _dup2(int od, int nd)
 int CDECL _dup(int od)
 {
   int fd, ret;
+
   LOCK_FILES();
   fd = fdstart;
   if (_dup2(od, fd) == 0)
@@ -902,10 +903,21 @@ int CDECL fseek(FILE* file, long offset, int whence)
 {
   /* Flush output if needed */
   if(file->_flag & _IOWRT)
-       flush_buffer(file);
+    flush_buffer(file);
 
   if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
-       offset -= file->_cnt;
+    offset -= file->_cnt;
+    if (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')
+                offset--;
+        }
+        /* Black magic when reading CR at buffer boundary*/
+        if(fdesc[file->_file].wxflag & WX_READCR)
+            offset--;
+    }
   }
   /* Discard buffered input */
   file->_cnt = 0;
@@ -1381,7 +1393,7 @@ int CDECL _sopen( const char *path, int oflags, int shflags, ... )
     else
       creation = OPEN_EXISTING;
   }
-  
+
   switch( shflags )
   {
     case _SH_DENYRW:
@@ -1556,27 +1568,6 @@ int CDECL _rmtmp(void)
   return num_removed;
 }
 
-/*********************************************************************
- * (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
  */
@@ -1586,6 +1577,9 @@ static int read_i(int fd, void *buf, unsigned int count)
   char *bufstart = buf;
   HANDLE hand = fdtoh(fd);
 
+  if (count == 0)
+    return 0;
+
   if (fdesc[fd].wxflag & WX_READEOF) {
      fdesc[fd].wxflag |= WX_ATEOF;
      TRACE("already at EOF, returning 0\n");
@@ -1602,25 +1596,47 @@ static int read_i(int fd, void *buf, unsigned int count)
    */
     if (ReadFile(hand, bufstart, count, &num_read, NULL))
     {
-        if (fdesc[fd].wxflag & WX_TEXT)
+        if (count != 0 && num_read == 0)
         {
-            int i;
-            /* in text mode, a ctrl-z signals EOF */
-            for (i=0; i<num_read; i++)
+            fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
+            TRACE(":EOF %s\n",debugstr_an(buf,num_read));
+        }
+        else if (fdesc[fd].wxflag & WX_TEXT)
+        {
+              DWORD i, j;
+            if (bufstart[num_read-1] == '\r')
+            {
+                if(count == 1)
+                {
+                    fdesc[fd].wxflag  &=  ~WX_READCR;
+                    ReadFile(hand, bufstart, 1, &num_read, NULL);
+                }
+                else
+                {
+                    fdesc[fd].wxflag  |= WX_READCR;
+                    num_read--;
+                }
+            }
+           else
+            fdesc[fd].wxflag  &=  ~WX_READCR;
+            for (i=0, j=0; i<num_read; i++)
             {
+                /* in text mode, a ctrl-z signals EOF */
                 if (bufstart[i] == 0x1a)
                 {
-                    num_read = i;
                     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];
             }
-        }
-        if (count != 0 && num_read == 0)
-        {
-            fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
-            TRACE(":EOF %s\n",debugstr_an(buf,num_read));
+            num_read = j;
         }
     }
     else
@@ -1650,10 +1666,6 @@ int CDECL _read(int fd, void *buf, unsigned int count)
 {
   int num_read;
   num_read = read_i(fd, buf, count);
-  if (num_read>0 && fdesc[fd].wxflag & WX_TEXT)
-  {
-      num_read -= remove_cr(buf,num_read);
-  }
   return num_read;
 }
 
@@ -1955,17 +1967,13 @@ int CDECL fgetc(FILE* file)
 {
   unsigned char *i;
   unsigned int j;
-  do {
-    if (file->_cnt>0) {
-      file->_cnt--;
-      i = (unsigned char *)file->_ptr++;
-      j = *i;
-    } else
-      j = _filbuf(file);
-    if (!(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 = _filbuf(file);
+  return j;
 }
 
 /*********************************************************************
@@ -2022,12 +2030,12 @@ wint_t CDECL fgetwc(FILE* file)
       wcp = (char *)&wc;
       for(i=0; i<sizeof(wc); i++)
       {
-        if (file->_cnt>0) 
+        if (file->_cnt>0)
         {
           file->_cnt--;
           chp = file->_ptr++;
           wcp[i] = *chp;
-        } 
+        }
         else
         {
           j = _filbuf(file);
@@ -2042,7 +2050,7 @@ wint_t CDECL fgetwc(FILE* file)
       }
       return wc;
     }
-    
+
   c = fgetc(file);
   if ((*__p___mb_cur_max() > 1) && isleadbyte(c))
     {
@@ -2167,12 +2175,33 @@ size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
 /*********************************************************************
  *             fputwc (MSVCRT.@)
  */
-wint_t CDECL fputwc(wint_t wc, FILE* file)
+wint_t CDECL fputwc(wchar_t c, FILE* stream)
 {
-  wchar_t mwc=wc;
-  if (fwrite( &mwc, sizeof(mwc), 1, file) != 1)
-    return WEOF;
-  return wc;
+    /* If this is a real file stream (and not some temporary one for
+       sprintf-like functions), check whether it is opened in text mode.
+       In this case, we have to perform an implicit conversion to ANSI. */
+    if (!(stream->_flag & _IOSTRG) && fdesc[stream->_file].wxflag & WX_TEXT)
+    {
+        /* Convert to multibyte in text mode */
+        char mbc[MB_LEN_MAX];
+        int mb_return;
+
+        mb_return = wctomb(mbc, c);
+
+        if(mb_return == -1)
+            return WEOF;
+
+        /* Output all characters */
+        if (fwrite(mbc, mb_return, 1, stream) != 1)
+            return WEOF;
+    }
+    else
+    {
+        if (fwrite(&c, sizeof(c), 1, stream) != 1)
+            return WEOF;
+    }
+
+    return c;
 }
 
 /*********************************************************************
@@ -2282,35 +2311,6 @@ int CDECL fputc(int c, FILE* file)
   }
 }
 
-/*********************************************************************
- *             _flsbuf (MSVCRT.@)
- */
-int CDECL _flsbuf(int c, FILE* file)
-{
-  /* Flush output buffer */
-  if(file->_bufsiz == 0 && !(file->_flag & _IONBF)) {
-       alloc_buffer(file);
-  }
-  if(!(file->_flag & _IOWRT)) {
-       if(file->_flag & _IORW) {
-               file->_flag |= _IOWRT;
-       } else {
-               return EOF;
-       }
-  }
-  if(file->_bufsiz) {
-        int res=flush_buffer(file);
-       return res?res : fputc(c, file);
-  } else {
-       unsigned char cc=c;
-        int len;
-       len = _write(file->_file, &cc, 1);
-        if (len == 1) return c & 0xff;
-        file->_flag |= _IOERR;
-        return EOF;
-  }
-}
-
 /*********************************************************************
  *             _fputchar (MSVCRT.@)
  */
@@ -2336,8 +2336,6 @@ size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
        memcpy(ptr, file->_ptr, pcnt);
        file->_cnt -= pcnt;
        file->_ptr += pcnt;
-       if (fdesc[file->_file].wxflag & WX_TEXT)
-            pcnt -= remove_cr(ptr,pcnt);
        read += pcnt ;
        rcnt -= pcnt ;
         ptr = (char*)ptr + pcnt;
@@ -2479,7 +2477,7 @@ int CDECL fsetpos(FILE* file, const fpos_t *pos)
   /* Discard buffered input */
   file->_cnt = 0;
   file->_ptr = file->_base;
-  
+
   /* Reset direction of i/o */
   if(file->_flag & _IORW) {
         file->_flag &= ~(_IOREAD|_IOWRT);
@@ -2493,17 +2491,26 @@ int CDECL fsetpos(FILE* file, const fpos_t *pos)
  */
 LONG CDECL ftell(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 & _IOWRT ) {
-               off = file->_ptr - file->_base;
-       } else {
-               off = -file->_cnt;
-       }
+    if( file->_flag & _IOWRT ) {
+        off = file->_ptr - file->_base;
+    } else {
+        off = -file->_cnt;
+        if (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;
 }
 
@@ -2512,22 +2519,25 @@ LONG CDECL ftell(FILE* file)
  */
 int CDECL fgetpos(FILE* file, fpos_t *pos)
 {
-  /* This code has been lifted form the ftell function */
   int off=0;
-
   *pos = _lseeki64(file->_file,0,SEEK_CUR);
-
-  if (*pos == -1) return -1;
-  
+  if(*pos == -1) return -1;
   if(file->_bufsiz)  {
-       if( file->_flag & _IOWRT ) {
-               off = file->_ptr - file->_base;
-       } else {
-               off = -file->_cnt;
-       }
+    if( file->_flag & _IOWRT ) {
+        off = file->_ptr - file->_base;
+    } else {
+        off = -file->_cnt;
+        if (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;
 }
 
@@ -2540,7 +2550,7 @@ int CDECL fputs(const char *s, FILE* file)
     if (!(fdesc[file->_file].wxflag & WX_TEXT))
       return fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
     for (i=0; i<len; i++)
-      if (fputc(s[i], file) == EOF) 
+      if (fputc(s[i], file) == EOF)
        return EOF;
     return 0;
 }
@@ -2558,7 +2568,7 @@ int CDECL fputws(const wchar_t *s, FILE* file)
         if ((s[i] == '\n') && (fputc('\r', file) == EOF))
          return WEOF;
        if (fputwc(s[i], file) == WEOF)
-         return WEOF; 
+         return WEOF;
       }
     return 0;
 }
@@ -2794,140 +2804,6 @@ FILE* CDECL tmpfile(void)
   return file;
 }
 
-/*********************************************************************
- *             vfprintf (MSVCRT.@)
- */
-int CDECL vfprintf(FILE* file, const char *format, va_list valist)
-{
-  char buf[2048], *mem = buf;
-  int written, resize = sizeof(buf), retval;
-  /* There are two conventions for vsnprintf failing:
-   * Return -1 if we truncated, or
-   * Return the number of bytes that would have been written
-   * The code below handles both cases
-   */
-  while ((written = _vsnprintf(mem, resize, format, valist)) == -1 ||
-          written > resize)
-  {
-    resize = (written == -1 ? resize * 2 : written + 1);
-    if (mem != buf)
-      free (mem);
-    if (!(mem = malloc(resize)))
-      return EOF;
-  }
-  retval = fwrite(mem, sizeof(*mem), written, file);
-  if (mem != buf)
-    free (mem);
-  return retval;
-}
-
-/*********************************************************************
- *             vfwprintf (MSVCRT.@)
- * FIXME:
- * Is final char included in written (then resize is too big) or not
- * (then we must test for equality too)?
- */
-int CDECL vfwprintf(FILE* file, const wchar_t *format, va_list valist)
-{
-  wchar_t buf[2048], *mem = buf;
-  int written, resize = sizeof(buf) / sizeof(wchar_t), retval;
-  /* See vfprintf comments */
-  while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
-          written > resize)
-  {
-    resize = (written == -1 ? resize * 2 : written + sizeof(wchar_t));
-    if (mem != buf)
-      free (mem);
-    if (!(mem = malloc(resize*sizeof(*mem))))
-      return EOF;
-  }
-
-  /* Check if outputting to a text-file */
-  if (fdesc[file->_file].wxflag & WX_TEXT)
-  {
-      /* Convert each character and stop at the first invalid character. Behavior verified by tests under WinXP SP2 */
-      char chMultiByte[MB_LEN_MAX];
-      int nReturn;
-      wchar_t *p;
-
-      retval = 0;
-
-      for (p = mem; *p; p++)
-      {
-          nReturn = wctomb(chMultiByte, *p);
-
-          if(nReturn == -1)
-              break;
-
-          retval += fwrite(chMultiByte, 1, nReturn, file);
-      }
-  }
-  else
-  {
-    retval = fwrite(mem, sizeof(*mem), written, file);
-  }
-
-  if (mem != buf)
-    free (mem);
-
-  return retval;
-}
-
-/*********************************************************************
- *             vprintf (MSVCRT.@)
- */
-int CDECL vprintf(const char *format, va_list valist)
-{
-  return vfprintf(stdout,format,valist);
-}
-
-/*********************************************************************
- *             vwprintf (MSVCRT.@)
- */
-int CDECL vwprintf(const wchar_t *format, va_list valist)
-{
-  return vfwprintf(stdout,format,valist);
-}
-
-/*********************************************************************
- *             fprintf (MSVCRT.@)
- */
-int CDECL fprintf(FILE* file, const char *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = vfprintf(file, format, valist);
-    va_end(valist);
-    return res;
-}
-
-/*********************************************************************
- *             fwprintf (MSVCRT.@)
- */
-int CDECL fwprintf(FILE* file, const wchar_t *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = vfwprintf(file, format, valist);
-    va_end(valist);
-    return res;
-}
-
-/*********************************************************************
- *             printf (MSVCRT.@)
- */
-int CDECL printf(const char *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = vfprintf(stdout, format, valist);
-    va_end(valist);
-    return res;
-}
-
 /*********************************************************************
  *             ungetc (MSVCRT.@)
  */
@@ -2964,19 +2840,6 @@ wint_t CDECL ungetwc(wint_t wc, FILE * file)
        return mwc;
 }
 
-/*********************************************************************
- *             wprintf (MSVCRT.@)
- */
-int CDECL wprintf(const wchar_t *format, ...)
-{
-    va_list valist;
-    int res;
-    va_start(valist, format);
-    res = vwprintf(format, valist);
-    va_end(valist);
-    return res;
-}
-
 /*********************************************************************
  *             _getmaxstdio (MSVCRT.@)
  */