[CRT]
[reactos.git] / reactos / lib / sdk / crt / stdio / file.c
index 299e2dd..4bb99da 100644 (file)
@@ -110,6 +110,8 @@ static char utf16_bom[2] = { 0xff, 0xfe };
 #define MAX_FILES 2048
 #define FD_BLOCK_SIZE 64
 
+#define MSVCRT_INTERNAL_BUFSIZ 4096
+
 /* ioinfo structure size is different in msvcrXX.dll's */
 typedef struct {
     HANDLE              handle;
@@ -373,9 +375,11 @@ static int init_fp(FILE* file, int fd, unsigned stream_flags)
     *_errno() = EBADF;
     return -1;
   }
-  memset(file, 0, sizeof(*file));
+  file->_ptr = file->_base = NULL;
+  file->_cnt = 0;
   file->_file = fd;
   file->_flag = stream_flags;
+  file->_tmpfname = NULL;
 
   if(file<_iob || file>=_iob+_IOB_ENTRIES)
       InitializeCriticalSection(&((file_crit*)file)->crit);
@@ -506,14 +510,14 @@ void msvcrt_init_io(void)
 /* INTERNAL: Flush stdio file buffer */
 static int flush_buffer(FILE* file)
 {
-  if(file->_bufsiz) {
+  if(file->_flag & (_IOMYBUF | _USERBUF)) {
         int cnt=file->_ptr-file->_base;
         if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
             file->_flag |= _IOERR;
             return EOF;
         }
         file->_ptr=file->_base;
-        file->_cnt=file->_bufsiz;
+        file->_cnt=0;
   }
   return 0;
 }
@@ -539,20 +543,43 @@ int CDECL _isatty(int fd)
             && _isatty(file->_file))
         return FALSE;
 
-    file->_base = calloc(BUFSIZ,1);
+    file->_base = calloc(MSVCRT_INTERNAL_BUFSIZ,1);
     if(file->_base) {
-        file->_bufsiz = BUFSIZ;
+        file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
         file->_flag |= _IOMYBUF;
     } else {
         file->_base = (char*)(&file->_charbuf);
-        /* put here 2 ??? */
-        file->_bufsiz = sizeof(file->_charbuf);
+        file->_bufsiz = 2;
+        file->_flag |= _IONBF;
     }
     file->_ptr = file->_base;
     file->_cnt = 0;
     return TRUE;
 }
 
+/* INTERNAL: Allocate temporary buffer for stdout and stderr */
+static BOOL add_std_buffer(FILE *file)
+{
+    static char buffers[2][BUFSIZ];
+
+    if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
+            || !_isatty(file->_file) || file->_bufsiz)
+        return FALSE;
+
+    file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
+    file->_bufsiz = file->_cnt = BUFSIZ;
+    return TRUE;
+}
+
+/* INTERNAL: Removes temporary buffer from stdout or stderr */
+/* Only call this function when add_std_buffer returned TRUE */
+static void remove_std_buffer(FILE *file)
+{
+    flush_buffer(file);
+    file->_ptr = file->_base = NULL;
+    file->_bufsiz = file->_cnt = 0;
+}
+
 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
 static int int_to_base32(int num, char *str)
 {
@@ -770,13 +797,13 @@ static int flush_all_buffers(int mask)
   FILE *file;
 
   LOCK_FILES();
-  for (i = 3; i < stream_idx; i++) {
+  for (i = 0; i < stream_idx; i++) {
     file = get_file(i);
 
     if (file->_flag)
     {
       if(file->_flag & mask) {
-        fflush(file);
+       fflush(file);
         num_flushed++;
       }
     }
@@ -2707,7 +2734,7 @@ int CDECL _filbuf(FILE* file)
     }
 
     /* Allocate buffer if needed */
-    if(file->_bufsiz == 0 && !(file->_flag & _IONBF))
+    if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
         alloc_buffer(file);
 
     if(!(file->_flag & _IOREAD)) {
@@ -2719,7 +2746,7 @@ int CDECL _filbuf(FILE* file)
         }
     }
 
-    if(file->_flag & _IONBF) {
+    if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
         int r;
         if ((r = read_i(file->_file,&c,1)) != 1) {
             file->_flag |= (r == 0) ? _IOEOF : _IOERR;
@@ -3187,7 +3214,7 @@ size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
 {
   size_t rcnt=size * nmemb;
   size_t read=0;
-  int pread=0;
+  size_t pread=0;
 
   if(!rcnt)
        return 0;
@@ -3196,7 +3223,7 @@ size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
 
   /* first buffered data */
   if(file->_cnt>0) {
-       int pcnt= (rcnt>(unsigned int)file->_cnt)? file->_cnt:rcnt;
+       int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
        memcpy(ptr, file->_ptr, pcnt);
        file->_cnt -= pcnt;
        file->_ptr += pcnt;
@@ -3211,14 +3238,17 @@ size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
         return 0;
     }
   }
+
+  if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
+      alloc_buffer(file);
+
   while(rcnt>0)
   {
     int i;
-    if (!file->_cnt && rcnt<BUFSIZ && !(file->_flag & _IONBF)
-            && (file->_bufsiz != 0 || alloc_buffer(file))) {
+    if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) {
       file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
       file->_ptr = file->_base;
-      i = ((unsigned int)file->_cnt<rcnt) ? file->_cnt : rcnt;
+      i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
       if (i > 0 && i < file->_cnt) {
         get_ioinfo(file->_file)->wxflag &= ~WX_ATEOF;
@@ -3229,8 +3259,8 @@ size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
         file->_cnt -= i;
         file->_ptr += i;
       }
-    } else if (rcnt > UINT_MAX) {
-      i = _read(file->_file, ptr, UINT_MAX);
+    } else if (rcnt > INT_MAX) {
+      i = _read(file->_file, ptr, INT_MAX);
     } else if (rcnt < BUFSIZ) {
       i = _read(file->_file, ptr, rcnt);
     } else {
@@ -3356,7 +3386,7 @@ __int64 CDECL _ftelli64(FILE* file)
         _unlock_file(file);
         return -1;
     }
-    if(file->_bufsiz)  {
+    if(file->_flag & (_IOMYBUF | _USERBUF))  {
         if(file->_flag & _IOWRT) {
             pos += file->_ptr - file->_base;
 
@@ -3416,34 +3446,9 @@ LONG CDECL ftell(FILE* file)
  */
 int CDECL fgetpos(FILE* file, fpos_t *pos)
 {
-    int off=0;
-
-    _lock_file(file);
-    *pos = _lseeki64(file->_file,0,SEEK_CUR);
-    if(*pos == -1) {
-        _unlock_file(file);
+    *pos = _ftelli64(file);
+    if(*pos == -1)
         return -1;
-    }
-    if(file->_bufsiz)  {
-        if( file->_flag & _IOWRT ) {
-            off = file->_ptr - file->_base;
-        } else {
-            off = -file->_cnt;
-            if (get_ioinfo(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--;
-                }
-                /* Black magic when reading CR at buffer boundary*/
-                if(get_ioinfo(file->_file)->wxflag & WX_READCR)
-                    off--;
-            }
-        }
-    }
-    *pos += off;
-    _unlock_file(file);
     return 0;
 }
 
@@ -3452,23 +3457,13 @@ int CDECL fgetpos(FILE* file, fpos_t *pos)
  */
 int CDECL fputs(const char *s, FILE* file)
 {
-    size_t i, len = strlen(s);
+    size_t len = strlen(s);
     int ret;
 
     _lock_file(file);
-    if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
-      ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
-      _unlock_file(file);
-      return ret;
-    }
-    for (i=0; i<len; i++)
-      if (fputc(s[i], file) == EOF)  {
-        _unlock_file(file);
-        return EOF;
-      }
-
+    ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF;
     _unlock_file(file);
-    return 0;
+    return ret;
 }
 
 /*********************************************************************
@@ -3477,6 +3472,7 @@ int CDECL fputs(const char *s, FILE* file)
 int CDECL fputws(const wchar_t *s, FILE* file)
 {
     size_t i, len = strlenW(s);
+    BOOL tmp_buf;
     int ret;
 
     _lock_file(file);
@@ -3485,14 +3481,17 @@ int CDECL fputws(const wchar_t *s, FILE* file)
         _unlock_file(file);
         return ret;
     }
+
+    tmp_buf = add_std_buffer(file);
     for (i=0; i<len; i++) {
-        if (((s[i] == '\n') && (fputc('\r', file) == EOF))
-                || fputwc(s[i], file) == WEOF) {
+        if(fputwc(s[i], file) == WEOF) {
+            if(tmp_buf) remove_std_buffer(file);
             _unlock_file(file);
             return WEOF;
         }
     }
 
+    if(tmp_buf) remove_std_buffer(file);
     _unlock_file(file);
     return 0;
 }
@@ -3726,6 +3725,7 @@ char * CDECL tmpnam(char *s)
   {
     size = int_to_base32(tmpnam_unique++, tmpstr);
     memcpy(p, tmpstr, size);
+    p[size] = '\0';
     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
         GetLastError() == ERROR_FILE_NOT_FOUND)
       break;
@@ -3757,6 +3757,7 @@ wchar_t * CDECL _wtmpnam(wchar_t *s)
     {
         size = int_to_base32_w(tmpnam_unique++, tmpstr);
         memcpy(p, tmpstr, size*sizeof(wchar_t));
+        p[size] = '\0';
         if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
                 GetLastError() == ERROR_FILE_NOT_FOUND)
             break;
@@ -3830,15 +3831,39 @@ int CDECL ungetc(int c, FILE * file)
 wint_t CDECL ungetwc(wint_t wc, FILE * file)
 {
     wchar_t mwc = wc;
-    char * pp = (char *)&mwc;
-    int i;
+
+    if (wc == WEOF)
+        return WEOF;
 
     _lock_file(file);
-    for(i=sizeof(wchar_t)-1;i>=0;i--) {
-        if(pp[i] != ungetc(pp[i],file)) {
+
+    if((get_ioinfo(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
+            || !(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
+        unsigned char * pp = (unsigned char *)&mwc;
+        int i;
+
+        for(i=sizeof(wchar_t)-1;i>=0;i--) {
+            if(pp[i] != ungetc(pp[i],file)) {
+                _unlock_file(file);
+                return WEOF;
+            }
+        }
+    }else {
+        char mbs[MB_LEN_MAX];
+        int len;
+
+        len = wctomb(mbs, mwc);
+        if(len == -1) {
             _unlock_file(file);
             return WEOF;
         }
+
+        for(len--; len>=0; len--) {
+            if(mbs[len] != ungetc(mbs[len], file)) {
+                _unlock_file(file);
+                return WEOF;
+            }
+        }
     }
 
     _unlock_file(file);