#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
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];
*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)
{
{
#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);
{
#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);
{
#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);
}
/* INTERNAL: Allocate stdio file buffer */
-static void alloc_buffer(FILE* file)
+void alloc_buffer(FILE* file)
{
file->_base = calloc(BUFSIZ,1);
if(file->_base) {
int CDECL _dup(int od)
{
int fd, ret;
-
+
LOCK_FILES();
fd = fdstart;
if (_dup2(od, fd) == 0)
{
/* 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;
else
creation = OPEN_EXISTING;
}
-
+
switch( shflags )
{
case _SH_DENYRW:
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
*/
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");
*/
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
{
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;
}
{
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;
}
/*********************************************************************
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);
}
return wc;
}
-
+
c = fgetc(file);
if ((*__p___mb_cur_max() > 1) && isleadbyte(c))
{
/*********************************************************************
* 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;
}
/*********************************************************************
}
}
-/*********************************************************************
- * _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.@)
*/
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;
/* Discard buffered input */
file->_cnt = 0;
file->_ptr = file->_base;
-
+
/* Reset direction of i/o */
if(file->_flag & _IORW) {
file->_flag &= ~(_IOREAD|_IOWRT);
*/
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;
}
*/
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;
}
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;
}
if ((s[i] == '\n') && (fputc('\r', file) == EOF))
return WEOF;
if (fputwc(s[i], file) == WEOF)
- return WEOF;
+ return WEOF;
}
return 0;
}
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.@)
*/
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.@)
*/