diff -ru wine-20011226.orig/dlls/msvcrt/file.c wine-20011226/dlls/msvcrt/file.c --- wine-20011226.orig/dlls/msvcrt/file.c Wed Dec 26 20:50:58 2001 +++ wine-20011226/dlls/msvcrt/file.c Mon Jan 7 14:18:42 2002 @@ -180,6 +180,36 @@ } } +/* INTERNAL: Flush stdio file buffer */ +static int msvcrt_flush_buffer(MSVCRT_FILE* file) +{ + if(file->_bufsiz) { + int cnt=file->_ptr-file->_base; + if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) { + return MSVCRT_EOF; + } + file->_ptr=file->_base; + file->_cnt=file->_bufsiz; + } + return 0; +} + +/* INTERNAL: Allocate stdio file buffer */ +static void msvcrt_alloc_buffer(MSVCRT_FILE* file) +{ + file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1); + if(file->_base) { + file->_bufsiz = MSVCRT_BUFSIZ; + file->_flag |= MSVCRT__IOMYBUF; + } else { + file->_base = (unsigned char *)(&file->_charbuf); + /* put here 2 ??? */ + file->_bufsiz = sizeof(file->_charbuf); + } + file->_ptr = file->_base; + file->_cnt = 0; +} + /********************************************************************* * __p__iob(MSVCRT.@) */ @@ -306,6 +336,14 @@ TRACE(":fd (%d) handle (%d)\n",fd,hand); if (hand == INVALID_HANDLE_VALUE) return -1; + /* flush stdio buffers */ + if(MSVCRT_files[fd]) { + if(MSVCRT_files[fd]->_flag & MSVCRT__IOWRT) + MSVCRT_fflush(MSVCRT_files[fd]); + + if(MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF) + MSVCRT_free(MSVCRT_files[fd]->_base); + } /* Dont free std FILE*'s, they are not dynamic */ if (fd > 2 && MSVCRT_files[fd]) @@ -376,7 +414,7 @@ * will be set by the read()/write() functions. */ if (MSVCRT_files[fd]) - return MSVCRT_files[fd]->_flag & MSVCRT__IOEOF; + return MSVCRT_flags[fd] & MSVCRT__IOEOF; /* Otherwise we do it the hard way */ curpos = SetFilePointer(hand, 0, NULL, SEEK_CUR); @@ -458,8 +496,8 @@ void MSVCRT_rewind(MSVCRT_FILE* file) { TRACE(":file (%p) fd (%d)\n",file,file->_file); - _lseek(file->_file,0,SEEK_SET); - file->_flag &= ~(MSVCRT__IOEOF | MSVCRT__IOERR); + MSVCRT_fseek(file, 0L, SEEK_SET); + MSVCRT_clearerr(file); } /********************************************************************* @@ -528,10 +566,16 @@ while(i < MSVCRT_fdend) if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE) { +#if 0 + /* FIXME: flush, do not commit */ if (_commit(i) == -1) if (MSVCRT_files[i]) MSVCRT_files[i]->_flag |= MSVCRT__IOERR; - num_flushed++; +#endif + if(MSVCRT_files[i] && MSVCRT_files[i]->_flag & MSVCRT__IOWRT) { + MSVCRT_fflush(MSVCRT_files[i]); + num_flushed++; + } } TRACE(":flushed (%d) handles\n",num_flushed); @@ -905,7 +949,10 @@ if (num_read != count && MSVCRT_files[fd]) { TRACE(":EOF\n"); + MSVCRT_flags[fd] |= MSVCRT__IOEOF; +/* MSVCRT_files[fd]->_flag |= MSVCRT__IOEOF; +*/ } return num_read; } @@ -1161,12 +1208,6 @@ if (MSVCRT_flags[fd] & MSVCRT__IOAPPEND) _lseek(fd, 0, FILE_END); - /* Set _cnt to 0 so optimised binaries will call our implementation - * of putc/getc. - */ - if (MSVCRT_files[fd]) - MSVCRT_files[fd]->_cnt = 0; - if (WriteFile(hand, buf, count, &num_written, NULL) && (num_written == count)) return num_written; @@ -1226,7 +1267,13 @@ */ int MSVCRT_fflush(MSVCRT_FILE* file) { - return _commit(file->_file); + if(!file) { + _flushall(); + return 0; + } else { + int res=msvcrt_flush_buffer(file); + return res; + } } /********************************************************************* @@ -1234,10 +1281,12 @@ */ int MSVCRT_fgetc(MSVCRT_FILE* file) { - char c; - if (_read(file->_file,&c,1) != 1) - return MSVCRT_EOF; - return c; + if (file->_cnt>0) { + file->_cnt--; + return *(unsigned char *)file->_ptr++; + } else { + return _filbuf(file); + } } /********************************************************************* @@ -1253,7 +1302,36 @@ */ int _filbuf(MSVCRT_FILE* file) { - return MSVCRT_fgetc(file); + + /* Allocate buffer if needed */ + if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF) ) { + msvcrt_alloc_buffer(file); + } + if(!(file->_flag & MSVCRT__IOREAD)) { + if(file->_flag & MSVCRT__IORW) { + file->_flag |= MSVCRT__IOREAD; + } else { + return MSVCRT_EOF; + } + } + if(file->_flag & MSVCRT__IONBF) { + unsigned char c; + if (_read(file->_file,&c,1) != 1) { + file->_flag |= MSVCRT__IOEOF; + return MSVCRT_EOF; + } + return c; + } else { + file->_cnt = _read(file->_file, file->_base, file->_bufsiz); + if(file->_cnt<0) file->_cnt = 0; + if(!file->_cnt) { + file->_flag |= MSVCRT__IOEOF; + return MSVCRT_EOF; + } + file->_cnt--; + file->_ptr = file->_base+1; + return *(unsigned char *)file->_base; + } } /********************************************************************* @@ -1261,7 +1339,7 @@ */ int MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos) { - *pos = _tell(file->_file); + *pos = MSVCRT_ftell(file); return (*pos == -1? -1 : 0); } @@ -1305,7 +1383,7 @@ */ MSVCRT_wint_t MSVCRT_fgetwc(MSVCRT_FILE* file) { - MSVCRT_wint_t wc; + WCHAR wc; if (_read(file->_file, &wc, sizeof(wc)) != sizeof(wc)) return MSVCRT_WEOF; return wc; @@ -1336,11 +1414,48 @@ } /********************************************************************* + * fgetws (MSVCRT.@) + */ +WCHAR *MSVCRT_fgetws(WCHAR *s, int size, MSVCRT_FILE* file) +{ + int cc; + WCHAR * buf_start = s; + + TRACE(":file(%p) fd (%d) str (%p) len (%d)\n", + file,file->_file,s,size); + + /* BAD, for the whole WINE process blocks... just done this way to test + * windows95's ftp.exe. + * JG - Is this true now we use ReadFile() on stdin too? + */ + for(cc = MSVCRT_fgetwc(file); cc != MSVCRT_WEOF && cc != L'\n'; + cc = MSVCRT_fgetwc(file)) + if (cc != L'\r') + { + if (--size <= 0) break; + *s++ = cc; + } + if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/ + { + TRACE(":nothing read\n"); + return 0; + } + if (cc == L'\n') + if (--size > 0) + *s++ = '\n'; + *s = '\0'; +/* TRACE(":got '%s'\n", buf_start); */ + return buf_start; +} + + +/********************************************************************* * fputwc (MSVCRT.@) */ MSVCRT_wint_t MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file) { - if (_write(file->_file, &wc, sizeof(wc)) != sizeof(wc)) + WCHAR mwc=wc; + if (MSVCRT_fwrite( &mwc, 1, sizeof(mwc), file) != sizeof(mwc)) return MSVCRT_WEOF; return wc; } @@ -1463,7 +1578,13 @@ */ int MSVCRT_fputc(int c, MSVCRT_FILE* file) { - return _write(file->_file, &c, 1) == 1? c : MSVCRT_EOF; + if(file->_cnt>0) { + *file->_ptr++=c; + file->_cnt--; + return c; + } else { + return _flsbuf(c, file); + } } /********************************************************************* @@ -1471,7 +1592,24 @@ */ int _flsbuf(int c, MSVCRT_FILE* file) { - return MSVCRT_fputc(c,file); + /* Flush output buffer */ + if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) { + msvcrt_alloc_buffer(file); + } + if(!(file->_flag & MSVCRT__IOWRT)) { + if(file->_flag & MSVCRT__IORW) { + file->_flag |= MSVCRT__IOWRT; + } else { + return MSVCRT_EOF; + } + } + if(file->_bufsiz) { + int res=msvcrt_flush_buffer(file); + return res?res : MSVCRT_fputc(c, file); + } else { + unsigned char cc=c; + return _write(file->_file, &cc, 1) == 1? c : MSVCRT_EOF; + } } /********************************************************************* @@ -1486,10 +1624,28 @@ * fread (MSVCRT.@) */ MSVCRT_size_t MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file) -{ - int read = _read(file->_file,ptr, size * nmemb); - if (read <= 0) - return 0; +{ MSVCRT_size_t rcnt=size * nmemb; + MSVCRT_size_t read=0; + int pread=0; + /* first buffered data */ + if(file->_cnt>0) { + int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt; + memcpy(ptr, file->_ptr, pcnt); + file->_cnt -= pcnt; + file->_ptr += pcnt; + read += pcnt ; + rcnt -= pcnt ; + ptr += pcnt; + } else if(!(file->_flag & MSVCRT__IOREAD )) { + if(file->_flag & MSVCRT__IORW) { + file->_flag |= MSVCRT__IOREAD; + } else + return 0; + } + if(rcnt) pread = _read(file->_file,ptr, rcnt); + if (pread <= 0) + pread = 0; + read+=pread; return read / size; } @@ -1508,9 +1664,14 @@ if (fd > 2) { +#if 0 FIXME(":reopen on user file not implemented!\n"); MSVCRT__set_errno(ERROR_CALL_NOT_IMPLEMENTED); return NULL; +#endif + if(MSVCRT_fclose(file)) + return NULL; + return MSVCRT_fopen(path, mode); } /* first, create the new file */ @@ -1675,6 +1836,20 @@ */ int MSVCRT_fseek(MSVCRT_FILE* file, long offset, int whence) { + /* Flush output if needed */ + if(file->_flag & MSVCRT__IOWRT) + msvcrt_flush_buffer(file); + + if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) { + offset -= file->_cnt; + } + /* Discard buffered input */ + file->_cnt = 0; + file->_ptr = file->_base; + /* Reset direction of i/o */ + if(file->_flag & MSVCRT__IORW) { + file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT); + } return _lseek(file->_file,offset,whence); } @@ -1683,7 +1858,18 @@ */ LONG MSVCRT_ftell(MSVCRT_FILE* file) { - return _tell(file->_file); + int off=0; + long pos; + if(file->_bufsiz) { + if( file->_flag & MSVCRT__IOWRT ) { + off = file->_ptr - file->_base; + } else { + off = -file->_cnt; + } + } + pos = _tell(file->_file); + if(pos == -1) return pos; + return off + pos; } /********************************************************************* @@ -1691,9 +1877,31 @@ */ MSVCRT_size_t MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file) { - int written = _write(file->_file, ptr, size * nmemb); - if (written <= 0) - return 0; + MSVCRT_size_t wrcnt=size * nmemb; + int written = 0; + if(file->_cnt) { + int pcnt=(file->_cnt>wrcnt)? file->_cnt: wrcnt; + memcpy(file->_ptr, ptr, pcnt); + file->_cnt -= pcnt; + file->_ptr += pcnt; + written = pcnt; + wrcnt -= pcnt; + ptr += pcnt; + } else if(!(file->_flag & MSVCRT__IOWRT)) { + if(file->_flag & MSVCRT__IORW) { + file->_flag |= MSVCRT__IOWRT; + } else + return 0; + } + if(wrcnt) { + /* Flush buffer */ + int res=msvcrt_flush_buffer(file); + if(!res) { + int pwritten = _write(file->_file, ptr, wrcnt); + if (pwritten <= 0) pwritten=0; + written += pwritten; + } + } return written / size; } @@ -1860,8 +2068,22 @@ */ int MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size) { - FIXME("(%p,%p,%d,%d)stub\n",file, buf, mode, size); - return -1; + /* TODO: Check if file busy */ + if(file->_bufsiz) { + MSVCRT_free(file->_base); + file->_bufsiz = 0; + file->_cnt = 0; + } + if(mode == MSVCRT__IOFBF) { + file->_flag &= ~MSVCRT__IONBF; + file->_base = file->_ptr = buf; + if(buf) { + file->_bufsiz = size; + } + } else { + file->_flag |= MSVCRT__IONBF; + } + return 0; } /********************************************************************* @@ -1869,7 +2091,7 @@ */ void MSVCRT_setbuf(MSVCRT_FILE* file, char *buf) { - MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, BUFSIZ); + MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ); } /********************************************************************* @@ -1932,6 +2154,9 @@ /********************************************************************* * vfwprintf (MSVCRT.@) + * FIXME: + * Is final char included in written (then resize is too big) or not + * (then we must test for equality too)? */ int MSVCRT_vfwprintf(MSVCRT_FILE* file, const WCHAR *format, va_list valist) { @@ -1944,7 +2169,7 @@ resize = (written == -1 ? resize * 2 : written + sizeof(WCHAR)); if (mem != buf) MSVCRT_free (mem); - if (!(mem = (WCHAR *)MSVCRT_malloc(resize))) + if (!(mem = (WCHAR *)MSVCRT_malloc(resize*sizeof(*mem)))) return MSVCRT_EOF; } retval = MSVCRT_fwrite(mem, 1, written * sizeof (WCHAR), file); @@ -2006,6 +2231,39 @@ res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist); va_end(valist); return res; +} + +/********************************************************************* + * ungetc (MSVCRT.@) + */ +int MSVCRT_ungetc(int c, MSVCRT_FILE * file) +{ + if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) { + msvcrt_alloc_buffer(file); + file->_ptr++; + } + if(file->_ptr>file->_base) { + file->_ptr--; + *file->_ptr=c; + file->_cnt++; + return c; + } + return MSVCRT_EOF; +} + +/********************************************************************* + * ungetwc (MSVCRT.@) + */ +MSVCRT_wint_t MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file) +{ + WCHAR mwc = wc; + char * pp = &mwc; + int i; + for(i=sizeof(WCHAR)-1;i>=0;i--) { + if(pp[i] != MSVCRT_ungetc(pp[i],file)) + return MSVCRT_WEOF; + } + return mwc; } /********************************************************************* diff -ru wine-20011226.orig/dlls/msvcrt/msvcrt.spec wine-20011226/dlls/msvcrt/msvcrt.spec --- wine-20011226.orig/dlls/msvcrt/msvcrt.spec Fri Dec 21 21:27:39 2001 +++ wine-20011226/dlls/msvcrt/msvcrt.spec Mon Jan 7 14:18:55 2002 @@ -605,7 +605,7 @@ @ cdecl fgetpos(ptr ptr) MSVCRT_fgetpos @ cdecl fgets(str long ptr) MSVCRT_fgets @ cdecl fgetwc(ptr) MSVCRT_fgetwc -@ stub fgetws #(wstr long ptr) +@ cdecl fgetws(wstr long ptr) MSVCRT_fgetws @ forward -noimport floor ntdll.floor @ cdecl fmod(double double) fmod @ cdecl fopen(str str) MSVCRT_fopen @@ -736,8 +736,8 @@ @ cdecl toupper(long) toupper @ forward -noimport towlower ntdll.towlower @ forward -noimport towupper ntdll.towupper -@ stub ungetc #(long ptr) -@ stub ungetwc #(long ptr) +@ cdecl ungetc(long ptr) MSVCRT_ungetc +@ cdecl ungetwc(long ptr) MSVCRT_ungetwc @ cdecl vfprintf(ptr str long) MSVCRT_vfprintf @ cdecl vfwprintf(ptr wstr long) MSVCRT_vfwprintf @ cdecl vprintf(str long) MSVCRT_vprintf diff -ru wine-20011226.orig/include/msvcrt/stdio.h wine-20011226/include/msvcrt/stdio.h --- wine-20011226.orig/include/msvcrt/stdio.h Mon Oct 22 20:59:23 2001 +++ wine-20011226/include/msvcrt/stdio.h Mon Jan 7 14:19:21 2002 @@ -72,6 +72,8 @@ #define MSVCRT_EOF (-1) +#define MSVCRT_BUFSIZ 512 + #endif /* USE_MSVCRT_PREFIX */ typedef struct MSVCRT(_iobuf)