1 /* 2 * PROJECT: ReactOS CRT library 3 * LICENSE: LGPL - See COPYING in the top level directory 4 * FILE: lib/sdk/crt/stdio/file.c 5 * PURPOSE: File CRT functions 6 * PROGRAMMERS: Wine team 7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org) 8 */ 9 10 /********************************************* 11 * This file contains ReactOS changes!! 12 * Don't blindly sync it with Wine code! 13 * 14 * If you break Unicode output on the console again, please update this counter: 15 * int hours_wasted_on_this = 42; 16 *********************************************/ 17 18 /* 19 * msvcrt.dll file functions 20 * 21 * Copyright 1996,1998 Marcus Meissner 22 * Copyright 1996 Jukka Iivonen 23 * Copyright 1997,2000 Uwe Bonnes 24 * Copyright 2000 Jon Griffiths 25 * Copyright 2004 Eric Pouech 26 * Copyright 2004 Juan Lang 27 * 28 * This library is free software; you can redistribute it and/or 29 * modify it under the terms of the GNU Lesser General Public 30 * License as published by the Free Software Foundation; either 31 * version 2.1 of the License, or (at your option) any later version. 32 * 33 * This library is distributed in the hope that it will be useful, 34 * but WITHOUT ANY WARRANTY; without even the implied warranty of 35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 36 * Lesser General Public License for more details. 37 * 38 * You should have received a copy of the GNU Lesser General Public 39 * License along with this library; if not, write to the Free Software 40 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 41 * 42 * TODO 43 * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED 44 */ 45 46 #include <precomp.h> 47 #include "wine/unicode.h" 48 #include "internal/wine/msvcrt.h" 49 50 #include <sys/utime.h> 51 #include <direct.h> 52 53 int *__p__fmode(void); 54 int *__p___mb_cur_max(void); 55 56 extern int _commode; 57 58 #ifndef _IOCOMMIT 59 #define _IOCOMMIT 0x4000 60 #endif 61 62 #ifdef feof 63 #undef feof 64 #endif 65 #ifdef _fileno 66 #undef _fileno 67 #endif 68 #ifdef ferror 69 #undef ferror 70 #endif 71 #ifdef clearerr 72 #undef clearerr 73 #endif 74 75 #undef getc 76 #undef getwc 77 #undef getchar 78 #undef getwchar 79 #undef putc 80 #undef putwc 81 #undef putchar 82 #undef putwchar 83 84 #undef vprintf 85 #undef vwprintf 86 87 /* _access() bit flags FIXME: incomplete */ 88 /* defined in crt/io.h */ 89 90 /* values for wxflag in file descriptor */ 91 #define WX_OPEN 0x01 92 #define WX_ATEOF 0x02 93 #define WX_READNL 0x04 /* read started with \n */ 94 #define WX_READEOF 0x04 /* like ATEOF, but for underlying file rather than buffer */ 95 #define WX_PIPE 0x08 96 #define WX_READCR 0x08 /* underlying file is at \r */ 97 #define WX_DONTINHERIT 0x10 98 #define WX_APPEND 0x20 99 #define WX_TTY 0x40 100 #define WX_TEXT 0x80 101 102 /* values for exflag - it's used differently in msvcr90.dll*/ 103 #define EF_UTF8 0x01 104 #define EF_UTF16 0x02 105 #define EF_CRIT_INIT 0x04 106 #define EF_UNK_UNICODE 0x08 107 108 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf }; 109 static char utf16_bom[2] = { 0xff, 0xfe }; 110 111 /* FIXME: this should be allocated dynamically */ 112 #define MSVCRT_MAX_FILES 2048 113 #define MSVCRT_FD_BLOCK_SIZE 32 114 115 #define MSVCRT_INTERNAL_BUFSIZ 4096 116 117 /********************************************************************* 118 * __pioinfo (MSVCRT.@) 119 * array of pointers to ioinfo arrays [32] 120 */ 121 ioinfo * __pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 }; 122 123 /********************************************************************* 124 * __badioinfo (MSVCRT.@) 125 */ 126 ioinfo __badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT }; 127 128 typedef struct { 129 FILE file; 130 CRITICAL_SECTION crit; 131 } file_crit; 132 133 FILE _iob[_IOB_ENTRIES] = { { 0 } }; 134 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { NULL }; 135 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx; 136 137 /* INTERNAL: process umask */ 138 static int MSVCRT_umask = 0; 139 140 /* INTERNAL: static data for tmpnam and _wtmpname functions */ 141 static int tmpnam_unique; 142 143 /* This critical section protects the MSVCRT_fstreams table 144 * and MSVCRT_stream_idx from race conditions. It also 145 * protects fd critical sections creation code. 146 */ 147 static CRITICAL_SECTION MSVCRT_file_cs; 148 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug = 149 { 150 0, 0, &MSVCRT_file_cs, 151 { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList }, 152 0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") } 153 }; 154 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 }; 155 #define LOCK_FILES() do { EnterCriticalSection(&MSVCRT_file_cs); } while (0) 156 #define UNLOCK_FILES() do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0) 157 158 static inline ioinfo* get_ioinfo_nolock(int fd) 159 { 160 ioinfo *ret = NULL; 161 if(fd>=0 && fd<MSVCRT_MAX_FILES) 162 ret = __pioinfo[fd/MSVCRT_FD_BLOCK_SIZE]; 163 if(!ret) 164 return &__badioinfo; 165 166 return ret + (fd%MSVCRT_FD_BLOCK_SIZE); 167 } 168 169 static inline void init_ioinfo_cs(ioinfo *info) 170 { 171 if(!(info->exflag & EF_CRIT_INIT)) { 172 LOCK_FILES(); 173 if(!(info->exflag & EF_CRIT_INIT)) { 174 InitializeCriticalSection(&info->crit); 175 info->exflag |= EF_CRIT_INIT; 176 } 177 UNLOCK_FILES(); 178 } 179 } 180 181 ioinfo* get_ioinfo(int fd) 182 { 183 ioinfo *ret = get_ioinfo_nolock(fd); 184 if(ret == &__badioinfo) 185 return ret; 186 init_ioinfo_cs(ret); 187 EnterCriticalSection(&ret->crit); 188 return ret; 189 } 190 191 static inline BOOL alloc_pioinfo_block(int fd) 192 { 193 ioinfo *block; 194 int i; 195 196 if(fd<0 || fd>=MSVCRT_MAX_FILES) 197 { 198 *_errno() = ENFILE; 199 return FALSE; 200 } 201 202 block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo)); 203 if(!block) 204 { 205 WARN(":out of memory!\n"); 206 *_errno() = ENOMEM; 207 return FALSE; 208 } 209 for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++) 210 block[i].handle = INVALID_HANDLE_VALUE; 211 if(InterlockedCompareExchangePointer((void**)&__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL)) 212 free(block); 213 return TRUE; 214 } 215 216 static inline ioinfo* get_ioinfo_alloc_fd(int fd) 217 { 218 ioinfo *ret; 219 220 ret = get_ioinfo(fd); 221 if(ret != &__badioinfo) 222 return ret; 223 224 if(!alloc_pioinfo_block(fd)) 225 return &__badioinfo; 226 227 return get_ioinfo(fd); 228 } 229 230 static inline ioinfo* get_ioinfo_alloc(int *fd) 231 { 232 int i; 233 234 *fd = -1; 235 for(i=0; i<MSVCRT_MAX_FILES; i++) 236 { 237 ioinfo *info = get_ioinfo_nolock(i); 238 239 if(info == &__badioinfo) 240 { 241 if(!alloc_pioinfo_block(i)) 242 return &__badioinfo; 243 info = get_ioinfo_nolock(i); 244 } 245 246 init_ioinfo_cs(info); 247 if(TryEnterCriticalSection(&info->crit)) 248 { 249 if(info->handle == INVALID_HANDLE_VALUE) 250 { 251 *fd = i; 252 return info; 253 } 254 LeaveCriticalSection(&info->crit); 255 } 256 } 257 258 WARN(":files exhausted!\n"); 259 *_errno() = ENFILE; 260 return &__badioinfo; 261 } 262 263 void release_ioinfo(ioinfo *info) 264 { 265 if(info!=&__badioinfo && info->exflag & EF_CRIT_INIT) 266 LeaveCriticalSection(&info->crit); 267 } 268 269 static inline FILE* msvcrt_get_file(int i) 270 { 271 file_crit *ret; 272 273 if(i >= MSVCRT_max_streams) 274 return NULL; 275 276 if(i < _IOB_ENTRIES) 277 return &_iob[i]; 278 279 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]; 280 if(!ret) { 281 MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit)); 282 if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) { 283 ERR("out of memory\n"); 284 *_errno() = ENOMEM; 285 return NULL; 286 } 287 288 ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE); 289 } else 290 ret += i%MSVCRT_FD_BLOCK_SIZE; 291 292 return &ret->file; 293 } 294 295 /* INTERNAL: free a file entry fd */ 296 static void msvcrt_free_fd(int fd) 297 { 298 ioinfo *fdinfo = get_ioinfo(fd); 299 300 if(fdinfo != &__badioinfo) 301 { 302 fdinfo->handle = INVALID_HANDLE_VALUE; 303 fdinfo->wxflag = 0; 304 } 305 TRACE(":fd (%d) freed\n",fd); 306 307 if (fd < 3) 308 { 309 switch (fd) 310 { 311 case 0: 312 SetStdHandle(STD_INPUT_HANDLE, 0); 313 break; 314 case 1: 315 SetStdHandle(STD_OUTPUT_HANDLE, 0); 316 break; 317 case 2: 318 SetStdHandle(STD_ERROR_HANDLE, 0); 319 break; 320 } 321 } 322 release_ioinfo(fdinfo); 323 } 324 325 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag) 326 { 327 fdinfo->handle = hand; 328 fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY)); 329 fdinfo->lookahead[0] = '\n'; 330 fdinfo->lookahead[1] = '\n'; 331 fdinfo->lookahead[2] = '\n'; 332 fdinfo->exflag &= EF_CRIT_INIT; 333 334 switch (fdinfo-__pioinfo[0]) 335 { 336 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break; 337 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break; 338 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break; 339 } 340 } 341 342 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */ 343 /*static*/ int msvcrt_alloc_fd(HANDLE hand, int flag) 344 { 345 int fd; 346 ioinfo *info = get_ioinfo_alloc(&fd); 347 348 TRACE(":handle (%p) allocating fd (%d)\n", hand, fd); 349 350 if(info == &__badioinfo) 351 return -1; 352 353 msvcrt_set_fd(info, hand, flag); 354 release_ioinfo(info); 355 return fd; 356 } 357 358 /* INTERNAL: Allocate a FILE* for an fd slot */ 359 /* caller must hold the files lock */ 360 static FILE* msvcrt_alloc_fp(void) 361 { 362 int i; 363 FILE *file; 364 365 for (i = 3; i < MSVCRT_max_streams; i++) 366 { 367 file = msvcrt_get_file(i); 368 if (!file) 369 return NULL; 370 371 if (file->_flag == 0) 372 { 373 if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++; 374 return file; 375 } 376 } 377 378 return NULL; 379 } 380 381 /* INTERNAL: initialize a FILE* from an open fd */ 382 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags) 383 { 384 TRACE(":fd (%d) allocating FILE*\n",fd); 385 if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN)) 386 { 387 WARN(":invalid fd %d\n",fd); 388 *__doserrno() = 0; 389 *_errno() = EBADF; 390 return -1; 391 } 392 file->_ptr = file->_base = NULL; 393 file->_cnt = 0; 394 file->_file = fd; 395 file->_flag = stream_flags; 396 file->_tmpfname = NULL; 397 398 if(file<_iob || file>=_iob+_IOB_ENTRIES) 399 InitializeCriticalSection(&((file_crit*)file)->crit); 400 401 TRACE(":got FILE* (%p)\n",file); 402 return 0; 403 } 404 405 /* INTERNAL: Create an inheritance data block (for spawned process) 406 * The inheritance block is made of: 407 * 00 int nb of file descriptor (NBFD) 408 * 04 char file flags (wxflag): repeated for each fd 409 * 4+NBFD HANDLE file handle: repeated for each fd 410 */ 411 unsigned create_io_inherit_block(WORD *size, BYTE **block) 412 { 413 int fd, last_fd; 414 char* wxflag_ptr; 415 HANDLE* handle_ptr; 416 ioinfo* fdinfo; 417 418 for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--) 419 if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE) 420 break; 421 last_fd++; 422 423 *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd; 424 *block = calloc(1, *size); 425 if (!*block) 426 { 427 *size = 0; 428 return FALSE; 429 } 430 wxflag_ptr = (char*)*block + sizeof(unsigned); 431 handle_ptr = (HANDLE*)(wxflag_ptr + last_fd); 432 433 *(unsigned*)*block = last_fd; 434 for (fd = 0; fd < last_fd; fd++) 435 { 436 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */ 437 fdinfo = get_ioinfo_nolock(fd); 438 if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN) 439 { 440 *wxflag_ptr = fdinfo->wxflag; 441 *handle_ptr = fdinfo->handle; 442 } 443 else 444 { 445 *wxflag_ptr = 0; 446 *handle_ptr = INVALID_HANDLE_VALUE; 447 } 448 wxflag_ptr++; handle_ptr++; 449 } 450 return TRUE; 451 } 452 453 /* INTERNAL: Set up all file descriptors, 454 * as well as default streams (stdin, stderr and stdout) 455 */ 456 void msvcrt_init_io(void) 457 { 458 STARTUPINFOA si; 459 unsigned int i; 460 ioinfo *fdinfo; 461 462 GetStartupInfoA(&si); 463 if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL) 464 { 465 BYTE* wxflag_ptr; 466 HANDLE* handle_ptr; 467 unsigned int count; 468 469 count = *(unsigned*)si.lpReserved2; 470 wxflag_ptr = si.lpReserved2 + sizeof(unsigned); 471 handle_ptr = (HANDLE*)(wxflag_ptr + count); 472 473 count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1)); 474 count = min(count, MSVCRT_MAX_FILES); 475 for (i = 0; i < count; i++) 476 { 477 if ((*wxflag_ptr & WX_OPEN) && GetFileType(*handle_ptr) != FILE_TYPE_UNKNOWN) 478 { 479 fdinfo = get_ioinfo_alloc_fd(i); 480 if(fdinfo != &__badioinfo) 481 msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr); 482 release_ioinfo(fdinfo); 483 } 484 485 wxflag_ptr++; handle_ptr++; 486 } 487 } 488 489 fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO); 490 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { 491 HANDLE h = GetStdHandle(STD_INPUT_HANDLE); 492 DWORD type = GetFileType(h); 493 494 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0) 495 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0)); 496 } 497 release_ioinfo(fdinfo); 498 499 fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO); 500 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { 501 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 502 DWORD type = GetFileType(h); 503 504 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0) 505 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0)); 506 } 507 release_ioinfo(fdinfo); 508 509 fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO); 510 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { 511 HANDLE h = GetStdHandle(STD_ERROR_HANDLE); 512 DWORD type = GetFileType(h); 513 514 msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0) 515 |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0)); 516 } 517 release_ioinfo(fdinfo); 518 519 TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle, 520 get_ioinfo_nolock(STDOUT_FILENO)->handle, 521 get_ioinfo_nolock(STDERR_FILENO)->handle); 522 523 memset(_iob,0,3*sizeof(FILE)); 524 for (i = 0; i < 3; i++) 525 { 526 /* FILE structs for stdin/out/err are static and never deleted */ 527 _iob[i]._file = i; 528 _iob[i]._tmpfname = NULL; 529 _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT; 530 } 531 MSVCRT_stream_idx = 3; 532 } 533 534 /* INTERNAL: Flush stdio file buffer */ 535 static int msvcrt_flush_buffer(FILE* file) 536 { 537 if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT && 538 file->_flag & (_IOMYBUF|_USERBUF)) { 539 int cnt=file->_ptr-file->_base; 540 if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) { 541 file->_flag |= _IOERR; 542 return EOF; 543 } 544 545 if(file->_flag & _IORW) 546 file->_flag &= ~_IOWRT; 547 548 #ifdef __REACTOS__ /* CORE-11949 */ 549 file->_ptr=file->_base; 550 file->_cnt=0; 551 #endif 552 } 553 554 #ifndef __REACTOS__ /* CORE-11949 */ 555 file->_ptr=file->_base; 556 file->_cnt=0; 557 #endif 558 return 0; 559 } 560 561 /********************************************************************* 562 * _isatty (MSVCRT.@) 563 */ 564 int CDECL _isatty(int fd) 565 { 566 TRACE(":fd (%d)\n",fd); 567 568 return get_ioinfo_nolock(fd)->wxflag & WX_TTY; 569 } 570 571 /* INTERNAL: Allocate stdio file buffer */ 572 /*static*/ BOOL msvcrt_alloc_buffer(FILE* file) 573 { 574 if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO) 575 && _isatty(file->_file)) 576 return FALSE; 577 578 file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ); 579 if(file->_base) { 580 file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ; 581 file->_flag |= _IOMYBUF; 582 } else { 583 file->_base = (char*)(&file->_charbuf); 584 file->_bufsiz = 2; 585 file->_flag |= _IONBF; 586 } 587 file->_ptr = file->_base; 588 file->_cnt = 0; 589 return TRUE; 590 } 591 592 /* INTERNAL: Allocate temporary buffer for stdout and stderr */ 593 static BOOL add_std_buffer(FILE *file) 594 { 595 static char buffers[2][BUFSIZ]; 596 597 if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO) 598 || (file->_flag & (_IONBF | _IOMYBUF | _USERBUF)) 599 || !_isatty(file->_file)) 600 return FALSE; 601 602 file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1]; 603 file->_bufsiz = file->_cnt = BUFSIZ; 604 file->_flag |= _USERBUF; 605 return TRUE; 606 } 607 608 /* INTERNAL: Removes temporary buffer from stdout or stderr */ 609 /* Only call this function when add_std_buffer returned TRUE */ 610 static void remove_std_buffer(FILE *file) 611 { 612 msvcrt_flush_buffer(file); 613 file->_ptr = file->_base = NULL; 614 file->_bufsiz = file->_cnt = 0; 615 file->_flag &= ~_USERBUF; 616 } 617 618 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */ 619 static int msvcrt_int_to_base32(int num, char *str) 620 { 621 char *p; 622 int n = num; 623 int digits = 0; 624 625 while (n != 0) 626 { 627 n >>= 5; 628 digits++; 629 } 630 p = str + digits; 631 *p = 0; 632 while (--p >= str) 633 { 634 *p = (num & 31) + '0'; 635 if (*p > '9') 636 *p += ('a' - '0' - 10); 637 num >>= 5; 638 } 639 640 return digits; 641 } 642 643 /* INTERNAL: wide character version of msvcrt_int_to_base32 */ 644 static int msvcrt_int_to_base32_w(int num, wchar_t *str) 645 { 646 wchar_t *p; 647 int n = num; 648 int digits = 0; 649 650 while (n != 0) 651 { 652 n >>= 5; 653 digits++; 654 } 655 p = str + digits; 656 *p = 0; 657 while (--p >= str) 658 { 659 *p = (num & 31) + '0'; 660 if (*p > '9') 661 *p += ('a' - '0' - 10); 662 num >>= 5; 663 } 664 665 return digits; 666 } 667 668 /* INTERNAL: Create a wide string from an ascii string */ 669 wchar_t *msvcrt_wstrdupa(const char *str) 670 { 671 const unsigned int len = strlen(str) + 1 ; 672 wchar_t *wstr = malloc(len* sizeof (wchar_t)); 673 if (!wstr) 674 return NULL; 675 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len); 676 return wstr; 677 } 678 679 /********************************************************************* 680 * __iob_func(MSVCRT.@) 681 */ 682 FILE * CDECL __iob_func(void) 683 { 684 return &_iob[0]; 685 } 686 687 /********************************************************************* 688 * _access (MSVCRT.@) 689 */ 690 int CDECL _access(const char *filename, int mode) 691 { 692 DWORD attr = GetFileAttributesA(filename); 693 694 TRACE("(%s,%d) %d\n",filename,mode,attr); 695 696 if (!filename || attr == INVALID_FILE_ATTRIBUTES) 697 { 698 _dosmaperr(GetLastError()); 699 return -1; 700 } 701 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) 702 { 703 _set_errno(ERROR_ACCESS_DENIED); 704 return -1; 705 } 706 return 0; 707 } 708 709 /********************************************************************* 710 * _access_s (MSVCRT.@) 711 */ 712 int CDECL _access_s(const char *filename, int mode) 713 { 714 if (!MSVCRT_CHECK_PMT(filename != NULL) || 715 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0)) 716 { 717 _set_errno(EINVAL); 718 return -1; 719 } 720 721 return _access(filename, mode); 722 } 723 724 /********************************************************************* 725 * _waccess (MSVCRT.@) 726 */ 727 int CDECL _waccess(const wchar_t *filename, int mode) 728 { 729 DWORD attr = GetFileAttributesW(filename); 730 731 TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr); 732 733 if (!filename || attr == INVALID_FILE_ATTRIBUTES) 734 { 735 _dosmaperr(GetLastError()); 736 return -1; 737 } 738 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK)) 739 { 740 _set_errno(ERROR_ACCESS_DENIED); 741 return -1; 742 } 743 return 0; 744 } 745 746 /********************************************************************* 747 * _waccess_s (MSVCRT.@) 748 */ 749 int CDECL _waccess_s(const wchar_t *filename, int mode) 750 { 751 if (!MSVCRT_CHECK_PMT(filename != NULL) || 752 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0)) 753 { 754 *_errno() = EINVAL; 755 return -1; 756 } 757 758 return _waccess(filename, mode); 759 } 760 761 /********************************************************************* 762 * _chmod (MSVCRT.@) 763 */ 764 int CDECL _chmod(const char *path, int flags) 765 { 766 DWORD oldFlags = GetFileAttributesA(path); 767 768 if (oldFlags != INVALID_FILE_ATTRIBUTES) 769 { 770 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY: 771 oldFlags | FILE_ATTRIBUTE_READONLY; 772 773 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags)) 774 return 0; 775 } 776 _dosmaperr(GetLastError()); 777 return -1; 778 } 779 780 /********************************************************************* 781 * _wchmod (MSVCRT.@) 782 */ 783 int CDECL _wchmod(const wchar_t *path, int flags) 784 { 785 DWORD oldFlags = GetFileAttributesW(path); 786 787 if (oldFlags != INVALID_FILE_ATTRIBUTES) 788 { 789 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY: 790 oldFlags | FILE_ATTRIBUTE_READONLY; 791 792 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags)) 793 return 0; 794 } 795 _dosmaperr(GetLastError()); 796 return -1; 797 } 798 799 /********************************************************************* 800 * _unlink (MSVCRT.@) 801 */ 802 int CDECL _unlink(const char *path) 803 { 804 TRACE("%s\n",debugstr_a(path)); 805 if(DeleteFileA(path)) 806 return 0; 807 TRACE("failed (%d)\n",GetLastError()); 808 _dosmaperr(GetLastError()); 809 return -1; 810 } 811 812 /********************************************************************* 813 * _wunlink (MSVCRT.@) 814 */ 815 int CDECL _wunlink(const wchar_t *path) 816 { 817 TRACE("(%s)\n",debugstr_w(path)); 818 if(DeleteFileW(path)) 819 return 0; 820 TRACE("failed (%d)\n",GetLastError()); 821 _dosmaperr(GetLastError()); 822 return -1; 823 } 824 825 /********************************************************************* 826 * _commit (MSVCRT.@) 827 */ 828 int CDECL _commit(int fd) 829 { 830 ioinfo *info = get_ioinfo(fd); 831 int ret; 832 833 TRACE(":fd (%d) handle (%p)\n", fd, info->handle); 834 835 if (info->handle == INVALID_HANDLE_VALUE) 836 ret = -1; 837 else if (!FlushFileBuffers(info->handle)) 838 { 839 if (GetLastError() == ERROR_INVALID_HANDLE) 840 { 841 /* FlushFileBuffers fails for console handles 842 * so we ignore this error. 843 */ 844 ret = 0; 845 } 846 else 847 { 848 TRACE(":failed-last error (%d)\n",GetLastError()); 849 _dosmaperr(GetLastError()); 850 ret = -1; 851 } 852 } 853 else 854 { 855 TRACE(":ok\n"); 856 ret = 0; 857 } 858 859 release_ioinfo(info); 860 return ret; 861 } 862 863 /* _flushall calls fflush which calls _flushall */ 864 int CDECL fflush(FILE* file); 865 866 /* INTERNAL: Flush all stream buffer */ 867 static int msvcrt_flush_all_buffers(int mask) 868 { 869 int i, num_flushed = 0; 870 FILE *file; 871 872 LOCK_FILES(); 873 for (i = 0; i < MSVCRT_stream_idx; i++) { 874 file = msvcrt_get_file(i); 875 876 if (file->_flag) 877 { 878 if(file->_flag & mask) { 879 fflush(file); 880 num_flushed++; 881 } 882 } 883 } 884 UNLOCK_FILES(); 885 886 TRACE(":flushed (%d) handles\n",num_flushed); 887 return num_flushed; 888 } 889 890 /********************************************************************* 891 * _flushall (MSVCRT.@) 892 */ 893 int CDECL _flushall(void) 894 { 895 return msvcrt_flush_all_buffers(_IOWRT | _IOREAD); 896 } 897 898 /********************************************************************* 899 * fflush (MSVCRT.@) 900 */ 901 int CDECL fflush(FILE* file) 902 { 903 if(!file) { 904 msvcrt_flush_all_buffers(_IOWRT); 905 } else if(file->_flag & _IOWRT) { 906 int res; 907 908 _lock_file(file); 909 res = msvcrt_flush_buffer(file); 910 /* FIXME 911 if(!res && (file->_flag & _IOCOMMIT)) 912 res = _commit(file->_file) ? EOF : 0; 913 */ 914 _unlock_file(file); 915 916 return res; 917 } else if(file->_flag & _IOREAD) { 918 _lock_file(file); 919 file->_cnt = 0; 920 file->_ptr = file->_base; 921 _unlock_file(file); 922 923 return 0; 924 } 925 return 0; 926 } 927 928 /********************************************************************* 929 * _close (MSVCRT.@) 930 */ 931 int CDECL _close(int fd) 932 { 933 ioinfo *info = get_ioinfo(fd); 934 int ret; 935 936 TRACE(":fd (%d) handle (%p)\n", fd, info->handle); 937 if (!(info->wxflag & WX_OPEN)) { 938 ret = -1; 939 } else if (fd == STDOUT_FILENO && 940 info->handle == get_ioinfo_nolock(STDERR_FILENO)->handle) { 941 msvcrt_free_fd(fd); 942 ret = 0; 943 } else if (fd == STDERR_FILENO && 944 info->handle == get_ioinfo_nolock(STDOUT_FILENO)->handle) { 945 msvcrt_free_fd(fd); 946 ret = 0; 947 } else { 948 ret = CloseHandle(info->handle) ? 0 : -1; 949 msvcrt_free_fd(fd); 950 if (ret) { 951 WARN(":failed-last error (%d)\n",GetLastError()); 952 _dosmaperr(GetLastError()); 953 ret = -1; 954 } 955 } 956 release_ioinfo(info); 957 return ret; 958 } 959 960 /********************************************************************* 961 * _dup2 (MSVCRT.@) 962 * NOTES 963 * MSDN isn't clear on this point, but the remarks for _pipe 964 * indicate file descriptors duplicated with _dup and _dup2 are always 965 * inheritable. 966 */ 967 int CDECL _dup2(int od, int nd) 968 { 969 ioinfo *info_od, *info_nd; 970 int ret; 971 972 TRACE("(od=%d, nd=%d)\n", od, nd); 973 974 if (od < nd) 975 { 976 info_od = get_ioinfo(od); 977 info_nd = get_ioinfo_alloc_fd(nd); 978 } 979 else 980 { 981 info_nd = get_ioinfo_alloc_fd(nd); 982 info_od = get_ioinfo(od); 983 } 984 985 if (info_nd == &__badioinfo) 986 { 987 ret = -1; 988 } 989 else if (info_od->wxflag & WX_OPEN) 990 { 991 HANDLE handle; 992 993 if (DuplicateHandle(GetCurrentProcess(), info_od->handle, 994 GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) 995 { 996 int wxflag = info_od->wxflag & ~WX_DONTINHERIT; 997 998 if (info_nd->wxflag & WX_OPEN) 999 _close(nd); 1000 1001 msvcrt_set_fd(info_nd, handle, wxflag); 1002 /* _dup2 returns 0, not nd, on success */ 1003 ret = 0; 1004 } 1005 else 1006 { 1007 ret = -1; 1008 _dosmaperr(GetLastError()); 1009 } 1010 } 1011 else 1012 { 1013 *_errno() = EBADF; 1014 ret = -1; 1015 } 1016 1017 release_ioinfo(info_od); 1018 release_ioinfo(info_nd); 1019 return ret; 1020 } 1021 1022 /********************************************************************* 1023 * _dup (MSVCRT.@) 1024 */ 1025 int CDECL _dup(int od) 1026 { 1027 int fd, ret; 1028 ioinfo *info = get_ioinfo_alloc(&fd); 1029 1030 if (_dup2(od, fd) == 0) 1031 ret = fd; 1032 else 1033 ret = -1; 1034 release_ioinfo(info); 1035 return ret; 1036 } 1037 1038 /********************************************************************* 1039 * _eof (MSVCRT.@) 1040 */ 1041 int CDECL _eof(int fd) 1042 { 1043 ioinfo *info = get_ioinfo(fd); 1044 DWORD curpos,endpos; 1045 LONG hcurpos,hendpos; 1046 1047 TRACE(":fd (%d) handle (%p)\n", fd, info->handle); 1048 1049 if (info->handle == INVALID_HANDLE_VALUE) 1050 { 1051 release_ioinfo(info); 1052 return -1; 1053 } 1054 1055 if (info->wxflag & WX_ATEOF) 1056 { 1057 release_ioinfo(info); 1058 return TRUE; 1059 } 1060 1061 /* Otherwise we do it the hard way */ 1062 hcurpos = hendpos = 0; 1063 curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT); 1064 endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END); 1065 1066 if (curpos == endpos && hcurpos == hendpos) 1067 { 1068 /* FIXME: shouldn't WX_ATEOF be set here? */ 1069 release_ioinfo(info); 1070 return TRUE; 1071 } 1072 1073 SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN); 1074 release_ioinfo(info); 1075 return FALSE; 1076 } 1077 1078 /********************************************************************* 1079 * _fcloseall (MSVCRT.@) 1080 */ 1081 int CDECL _fcloseall(void) 1082 { 1083 int num_closed = 0, i; 1084 FILE *file; 1085 1086 LOCK_FILES(); 1087 for (i = 3; i < MSVCRT_stream_idx; i++) { 1088 file = msvcrt_get_file(i); 1089 1090 if (file->_flag && !fclose(file)) 1091 num_closed++; 1092 } 1093 UNLOCK_FILES(); 1094 1095 TRACE(":closed (%d) handles\n",num_closed); 1096 return num_closed; 1097 } 1098 1099 /* free everything on process exit */ 1100 void msvcrt_free_io(void) 1101 { 1102 unsigned int i; 1103 int j; 1104 1105 _flushall(); 1106 _fcloseall(); 1107 1108 for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++) 1109 { 1110 if(!__pioinfo[i]) 1111 continue; 1112 1113 for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++) 1114 { 1115 if(__pioinfo[i][j].exflag & EF_CRIT_INIT) 1116 DeleteCriticalSection(&__pioinfo[i][j].crit); 1117 } 1118 free(__pioinfo[i]); 1119 } 1120 1121 for(j=0; j<MSVCRT_stream_idx; j++) 1122 { 1123 FILE *file = msvcrt_get_file(j); 1124 if(file<_iob || file>=_iob+_IOB_ENTRIES) 1125 { 1126 ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0; 1127 DeleteCriticalSection(&((file_crit*)file)->crit); 1128 } 1129 } 1130 1131 for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++) 1132 free(MSVCRT_fstream[i]); 1133 } 1134 1135 /********************************************************************* 1136 * _lseeki64 (MSVCRT.@) 1137 */ 1138 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence) 1139 { 1140 ioinfo *info = get_ioinfo(fd); 1141 LARGE_INTEGER ofs; 1142 1143 TRACE(":fd (%d) handle (%p)\n", fd, info->handle); 1144 1145 if (info->handle == INVALID_HANDLE_VALUE) 1146 { 1147 release_ioinfo(info); 1148 return -1; 1149 } 1150 1151 if (whence < 0 || whence > 2) 1152 { 1153 release_ioinfo(info); 1154 *_errno() = EINVAL; 1155 return -1; 1156 } 1157 1158 TRACE(":fd (%d) to %s pos %s\n", 1159 fd,wine_dbgstr_longlong(offset), 1160 (whence==SEEK_SET)?"SEEK_SET": 1161 (whence==SEEK_CUR)?"SEEK_CUR": 1162 (whence==SEEK_END)?"SEEK_END":"UNKNOWN"); 1163 1164 /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only, 1165 * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */ 1166 ofs.QuadPart = offset; 1167 if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER || 1168 GetLastError() == ERROR_SUCCESS) 1169 { 1170 info->wxflag &= ~(WX_ATEOF|WX_READEOF); 1171 /* FIXME: What if we seek _to_ EOF - is EOF set? */ 1172 1173 release_ioinfo(info); 1174 return ofs.QuadPart; 1175 } 1176 release_ioinfo(info); 1177 TRACE(":error-last error (%d)\n",GetLastError()); 1178 _dosmaperr(GetLastError()); 1179 return -1; 1180 } 1181 1182 /********************************************************************* 1183 * _lseek (MSVCRT.@) 1184 */ 1185 LONG CDECL _lseek(int fd, LONG offset, int whence) 1186 { 1187 return (LONG)_lseeki64(fd, offset, whence); 1188 } 1189 1190 /********************************************************************* 1191 * _lock_file (MSVCRT.@) 1192 */ 1193 void CDECL _lock_file(FILE *file) 1194 { 1195 if(file>=_iob && file<_iob+_IOB_ENTRIES) 1196 _lock(_STREAM_LOCKS+(file-_iob)); 1197 /* ReactOS: string streams dont need to be locked */ 1198 else if(!(file->_flag & _IOSTRG)) 1199 EnterCriticalSection(&((file_crit*)file)->crit); 1200 } 1201 1202 /********************************************************************* 1203 * _unlock_file (MSVCRT.@) 1204 */ 1205 void CDECL _unlock_file(FILE *file) 1206 { 1207 if(file>=_iob && file<_iob+_IOB_ENTRIES) 1208 _unlock(_STREAM_LOCKS+(file-_iob)); 1209 /* ReactOS: string streams dont need to be locked */ 1210 else if(!(file->_flag & _IOSTRG)) 1211 LeaveCriticalSection(&((file_crit*)file)->crit); 1212 1213 } 1214 1215 /********************************************************************* 1216 * _locking (MSVCRT.@) 1217 * 1218 * This is untested; the underlying LockFile doesn't work yet. 1219 */ 1220 int CDECL _locking(int fd, int mode, LONG nbytes) 1221 { 1222 ioinfo *info = get_ioinfo(fd); 1223 BOOL ret; 1224 DWORD cur_locn; 1225 1226 TRACE(":fd (%d) handle (%p)\n", fd, info->handle); 1227 if (info->handle == INVALID_HANDLE_VALUE) 1228 { 1229 release_ioinfo(info); 1230 return -1; 1231 } 1232 1233 if (mode < 0 || mode > 4) 1234 { 1235 release_ioinfo(info); 1236 *_errno() = EINVAL; 1237 return -1; 1238 } 1239 1240 TRACE(":fd (%d) by 0x%08x mode %s\n", 1241 fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK": 1242 (mode==_LK_LOCK)?"_LK_LOCK": 1243 (mode==_LK_NBLCK)?"_LK_NBLCK": 1244 (mode==_LK_RLCK)?"_LK_RLCK": 1245 (mode==_LK_NBRLCK)?"_LK_NBRLCK": 1246 "UNKNOWN"); 1247 1248 if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, FILE_CURRENT)) == INVALID_SET_FILE_POINTER) 1249 { 1250 release_ioinfo(info); 1251 FIXME ("Seek failed\n"); 1252 *_errno() = EINVAL; /* FIXME */ 1253 return -1; 1254 } 1255 if (mode == _LK_LOCK || mode == _LK_RLCK) 1256 { 1257 int nretry = 10; 1258 ret = 1; /* just to satisfy gcc */ 1259 while (nretry--) 1260 { 1261 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L); 1262 if (ret) break; 1263 Sleep(1); 1264 } 1265 } 1266 else if (mode == _LK_UNLCK) 1267 ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L); 1268 else 1269 ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L); 1270 /* FIXME - what about error settings? */ 1271 release_ioinfo(info); 1272 return ret ? 0 : -1; 1273 } 1274 1275 /********************************************************************* 1276 * _fseeki64 (MSVCRT.@) 1277 */ 1278 int CDECL _fseeki64(FILE* file, __int64 offset, int whence) 1279 { 1280 int ret; 1281 1282 _lock_file(file); 1283 /* Flush output if needed */ 1284 if(file->_flag & _IOWRT) 1285 msvcrt_flush_buffer(file); 1286 1287 if(whence == SEEK_CUR && file->_flag & _IOREAD ) { 1288 whence = SEEK_SET; 1289 offset += _ftelli64(file); 1290 } 1291 1292 /* Discard buffered input */ 1293 file->_cnt = 0; 1294 file->_ptr = file->_base; 1295 /* Reset direction of i/o */ 1296 if(file->_flag & _IORW) { 1297 file->_flag &= ~(_IOREAD|_IOWRT); 1298 } 1299 /* Clear end of file flag */ 1300 file->_flag &= ~_IOEOF; 1301 ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0; 1302 1303 _unlock_file(file); 1304 return ret; 1305 } 1306 1307 /********************************************************************* 1308 * fseek (MSVCRT.@) 1309 */ 1310 int CDECL fseek(FILE* file, long offset, int whence) 1311 { 1312 return _fseeki64( file, offset, whence ); 1313 } 1314 1315 /********************************************************************* 1316 * _chsize_s (MSVCRT.@) 1317 */ 1318 int CDECL _chsize_s(int fd, __int64 size) 1319 { 1320 ioinfo *info; 1321 __int64 cur, pos; 1322 BOOL ret = FALSE; 1323 1324 TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size)); 1325 1326 if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL; 1327 1328 info = get_ioinfo(fd); 1329 if (info->handle != INVALID_HANDLE_VALUE) 1330 { 1331 /* save the current file pointer */ 1332 cur = _lseeki64(fd, 0, SEEK_CUR); 1333 if (cur >= 0) 1334 { 1335 pos = _lseeki64(fd, size, SEEK_SET); 1336 if (pos >= 0) 1337 { 1338 ret = SetEndOfFile(info->handle); 1339 if (!ret) _dosmaperr(GetLastError()); 1340 } 1341 1342 /* restore the file pointer */ 1343 _lseeki64(fd, cur, SEEK_SET); 1344 } 1345 } 1346 1347 release_ioinfo(info); 1348 return ret ? 0 : *_errno(); 1349 } 1350 1351 /********************************************************************* 1352 * _chsize (MSVCRT.@) 1353 */ 1354 int CDECL _chsize(int fd, long size) 1355 { 1356 /* _chsize_s returns errno on failure but _chsize should return -1 */ 1357 return _chsize_s( fd, size ) == 0 ? 0 : -1; 1358 } 1359 1360 /********************************************************************* 1361 * clearerr (MSVCRT.@) 1362 */ 1363 void CDECL clearerr(FILE* file) 1364 { 1365 TRACE(":file (%p) fd (%d)\n",file,file->_file); 1366 1367 _lock_file(file); 1368 file->_flag &= ~(_IOERR | _IOEOF); 1369 _unlock_file(file); 1370 } 1371 1372 /********************************************************************* 1373 * rewind (MSVCRT.@) 1374 */ 1375 void CDECL rewind(FILE* file) 1376 { 1377 TRACE(":file (%p) fd (%d)\n",file,file->_file); 1378 1379 _lock_file(file); 1380 fseek(file, 0L, SEEK_SET); 1381 clearerr(file); 1382 _unlock_file(file); 1383 } 1384 1385 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags) 1386 { 1387 int plus = strchrW(mode, '+') != NULL; 1388 1389 TRACE("%s\n", debugstr_w(mode)); 1390 1391 while(*mode == ' ') mode++; 1392 1393 switch(*mode++) 1394 { 1395 case 'R': case 'r': 1396 *open_flags = plus ? _O_RDWR : _O_RDONLY; 1397 *stream_flags = plus ? _IORW : _IOREAD; 1398 break; 1399 case 'W': case 'w': 1400 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY); 1401 *stream_flags = plus ? _IORW : _IOWRT; 1402 break; 1403 case 'A': case 'a': 1404 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY); 1405 *stream_flags = plus ? _IORW : _IOWRT; 1406 break; 1407 default: 1408 MSVCRT_INVALID_PMT(0, EINVAL); 1409 return -1; 1410 } 1411 1412 *stream_flags |= _commode; 1413 1414 while (*mode && *mode!=',') 1415 switch (*mode++) 1416 { 1417 case 'B': case 'b': 1418 *open_flags |= _O_BINARY; 1419 *open_flags &= ~_O_TEXT; 1420 break; 1421 case 't': 1422 *open_flags |= _O_TEXT; 1423 *open_flags &= ~_O_BINARY; 1424 break; 1425 case 'D': 1426 *open_flags |= _O_TEMPORARY; 1427 break; 1428 case 'T': 1429 *open_flags |= _O_SHORT_LIVED; 1430 break; 1431 case 'c': 1432 *stream_flags |= _IOCOMMIT; 1433 break; 1434 case 'n': 1435 *stream_flags &= ~_IOCOMMIT; 1436 break; 1437 case 'N': 1438 *open_flags |= _O_NOINHERIT; 1439 break; 1440 case '+': 1441 case ' ': 1442 case 'a': 1443 case 'w': 1444 break; 1445 case 'S': 1446 case 'R': 1447 FIXME("ignoring cache optimization flag: %c\n", mode[-1]); 1448 break; 1449 default: 1450 ERR("incorrect mode flag: %c\n", mode[-1]); 1451 break; 1452 } 1453 1454 if(*mode == ',') 1455 { 1456 static const WCHAR ccs[] = {'c','c','s'}; 1457 static const WCHAR utf8[] = {'u','t','f','-','8'}; 1458 static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'}; 1459 static const WCHAR unicode[] = {'u','n','i','c','o','d','e'}; 1460 1461 mode++; 1462 while(*mode == ' ') mode++; 1463 if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0])))) 1464 return -1; 1465 mode += sizeof(ccs)/sizeof(ccs[0]); 1466 while(*mode == ' ') mode++; 1467 if(!MSVCRT_CHECK_PMT(*mode == '=')) 1468 return -1; 1469 mode++; 1470 while(*mode == ' ') mode++; 1471 1472 if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0]))) 1473 { 1474 *open_flags |= _O_U8TEXT; 1475 mode += sizeof(utf8)/sizeof(utf8[0]); 1476 } 1477 else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0]))) 1478 { 1479 *open_flags |= _O_U16TEXT; 1480 mode += sizeof(utf16le)/sizeof(utf16le[0]); 1481 } 1482 else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0]))) 1483 { 1484 *open_flags |= _O_WTEXT; 1485 mode += sizeof(unicode)/sizeof(unicode[0]); 1486 } 1487 else 1488 { 1489 MSVCRT_INVALID_PMT(0, EINVAL); 1490 return -1; 1491 } 1492 1493 while(*mode == ' ') mode++; 1494 } 1495 1496 if(!MSVCRT_CHECK_PMT(*mode == 0)) 1497 return -1; 1498 return 0; 1499 } 1500 1501 /********************************************************************* 1502 * _fdopen (MSVCRT.@) 1503 */ 1504 FILE* CDECL _fdopen(int fd, const char *mode) 1505 { 1506 FILE *ret; 1507 wchar_t *modeW = NULL; 1508 1509 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL; 1510 1511 ret = _wfdopen(fd, modeW); 1512 1513 free(modeW); 1514 return ret; 1515 } 1516 1517 /********************************************************************* 1518 * _wfdopen (MSVCRT.@) 1519 */ 1520 FILE* CDECL _wfdopen(int fd, const wchar_t *mode) 1521 { 1522 int open_flags, stream_flags; 1523 FILE* file; 1524 1525 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL; 1526 1527 LOCK_FILES(); 1528 if (!(file = msvcrt_alloc_fp())) 1529 file = NULL; 1530 else if (msvcrt_init_fp(file, fd, stream_flags) == -1) 1531 { 1532 file->_flag = 0; 1533 file = NULL; 1534 } 1535 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file); 1536 UNLOCK_FILES(); 1537 1538 return file; 1539 } 1540 1541 /********************************************************************* 1542 * _filelength (MSVCRT.@) 1543 */ 1544 LONG CDECL _filelength(int fd) 1545 { 1546 LONG curPos = _lseek(fd, 0, SEEK_CUR); 1547 if (curPos != -1) 1548 { 1549 LONG endPos = _lseek(fd, 0, SEEK_END); 1550 if (endPos != -1) 1551 { 1552 if (endPos != curPos) 1553 _lseek(fd, curPos, SEEK_SET); 1554 return endPos; 1555 } 1556 } 1557 return -1; 1558 } 1559 1560 /********************************************************************* 1561 * _filelengthi64 (MSVCRT.@) 1562 */ 1563 __int64 CDECL _filelengthi64(int fd) 1564 { 1565 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR); 1566 if (curPos != -1) 1567 { 1568 __int64 endPos = _lseeki64(fd, 0, SEEK_END); 1569 if (endPos != -1) 1570 { 1571 if (endPos != curPos) 1572 _lseeki64(fd, curPos, SEEK_SET); 1573 return endPos; 1574 } 1575 } 1576 return -1; 1577 } 1578 1579 /********************************************************************* 1580 * _fileno (MSVCRT.@) 1581 */ 1582 int CDECL _fileno(FILE* file) 1583 { 1584 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file); 1585 return file->_file; 1586 } 1587 1588 /********************************************************************* 1589 * _get_osfhandle (MSVCRT.@) 1590 */ 1591 intptr_t CDECL _get_osfhandle(int fd) 1592 { 1593 HANDLE hand = get_ioinfo_nolock(fd)->handle; 1594 TRACE(":fd (%d) handle (%p)\n",fd,hand); 1595 1596 if(hand == INVALID_HANDLE_VALUE) 1597 *_errno() = EBADF; 1598 return (intptr_t)hand; 1599 } 1600 1601 /********************************************************************* 1602 * _mktemp (MSVCRT.@) 1603 */ 1604 char * CDECL _mktemp(char *pattern) 1605 { 1606 int numX = 0; 1607 char *retVal = pattern; 1608 int id; 1609 char letter = 'a'; 1610 1611 if(!pattern) 1612 return NULL; 1613 1614 while(*pattern) 1615 numX = (*pattern++ == 'X')? numX + 1 : 0; 1616 if (numX < 6) 1617 return NULL; 1618 pattern--; 1619 id = GetCurrentProcessId(); 1620 numX = 6; 1621 while(numX--) 1622 { 1623 int tempNum = id / 10; 1624 *pattern-- = id - (tempNum * 10) + '0'; 1625 id = tempNum; 1626 } 1627 pattern++; 1628 do 1629 { 1630 *pattern = letter++; 1631 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES) 1632 return retVal; 1633 } while(letter <= 'z'); 1634 return NULL; 1635 } 1636 1637 /********************************************************************* 1638 * _wmktemp (MSVCRT.@) 1639 */ 1640 wchar_t * CDECL _wmktemp(wchar_t *pattern) 1641 { 1642 int numX = 0; 1643 wchar_t *retVal = pattern; 1644 int id; 1645 wchar_t letter = 'a'; 1646 1647 while(*pattern) 1648 numX = (*pattern++ == 'X')? numX + 1 : 0; 1649 if (numX < 5) 1650 return NULL; 1651 pattern--; 1652 id = GetCurrentProcessId(); 1653 numX = 6; 1654 while(numX--) 1655 { 1656 int tempNum = id / 10; 1657 *pattern-- = id - (tempNum * 10) + '0'; 1658 id = tempNum; 1659 } 1660 pattern++; 1661 do 1662 { 1663 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES && 1664 GetLastError() == ERROR_FILE_NOT_FOUND) 1665 return retVal; 1666 *pattern = letter++; 1667 } while(letter != '|'); 1668 return NULL; 1669 } 1670 1671 /*static*/ unsigned split_oflags(unsigned oflags) 1672 { 1673 int wxflags = 0; 1674 unsigned unsupp; /* until we support everything */ 1675 1676 if (oflags & _O_APPEND) wxflags |= WX_APPEND; 1677 if (oflags & _O_BINARY) {/* Nothing to do */} 1678 else if (oflags & _O_TEXT) wxflags |= WX_TEXT; 1679 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT; 1680 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT; 1681 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT; 1682 else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */} 1683 else wxflags |= WX_TEXT; /* default to TEXT*/ 1684 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT; 1685 1686 if ((unsupp = oflags & ~( 1687 _O_BINARY|_O_TEXT|_O_APPEND| 1688 _O_TRUNC|_O_EXCL|_O_CREAT| 1689 _O_RDWR|_O_WRONLY|_O_TEMPORARY| 1690 _O_NOINHERIT| 1691 _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED| 1692 _O_WTEXT|_O_U16TEXT|_O_U8TEXT 1693 ))) 1694 ERR(":unsupported oflags 0x%04x\n",unsupp); 1695 1696 return wxflags; 1697 } 1698 1699 /********************************************************************* 1700 * _pipe (MSVCRT.@) 1701 */ 1702 int CDECL _pipe(int *pfds, unsigned int psize, int textmode) 1703 { 1704 int ret = -1; 1705 SECURITY_ATTRIBUTES sa; 1706 HANDLE readHandle, writeHandle; 1707 1708 if (!pfds) 1709 { 1710 *_errno() = EINVAL; 1711 return -1; 1712 } 1713 1714 sa.nLength = sizeof(SECURITY_ATTRIBUTES); 1715 sa.bInheritHandle = !(textmode & _O_NOINHERIT); 1716 sa.lpSecurityDescriptor = NULL; 1717 if (CreatePipe(&readHandle, &writeHandle, &sa, psize)) 1718 { 1719 unsigned int wxflags = split_oflags(textmode); 1720 int fd; 1721 1722 fd = msvcrt_alloc_fd(readHandle, wxflags); 1723 if (fd != -1) 1724 { 1725 pfds[0] = fd; 1726 fd = msvcrt_alloc_fd(writeHandle, wxflags); 1727 if (fd != -1) 1728 { 1729 pfds[1] = fd; 1730 ret = 0; 1731 } 1732 else 1733 { 1734 _close(pfds[0]); 1735 CloseHandle(writeHandle); 1736 *_errno() = EMFILE; 1737 } 1738 } 1739 else 1740 { 1741 CloseHandle(readHandle); 1742 CloseHandle(writeHandle); 1743 *_errno() = EMFILE; 1744 } 1745 } 1746 else 1747 _dosmaperr(GetLastError()); 1748 1749 return ret; 1750 } 1751 1752 static int check_bom(HANDLE h, int oflags, BOOL seek) 1753 { 1754 char bom[sizeof(utf8_bom)]; 1755 DWORD r; 1756 1757 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT); 1758 1759 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL)) 1760 return oflags; 1761 1762 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) { 1763 oflags |= _O_U8TEXT; 1764 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) { 1765 if (seek && r>2) 1766 SetFilePointer(h, 2, NULL, FILE_BEGIN); 1767 oflags |= _O_U16TEXT; 1768 }else if (seek) { 1769 SetFilePointer(h, 0, NULL, FILE_BEGIN); 1770 } 1771 1772 return oflags; 1773 } 1774 1775 /********************************************************************* 1776 * _wsopen_s (MSVCRT.@) 1777 */ 1778 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode ) 1779 { 1780 DWORD access = 0, creation = 0, attrib; 1781 SECURITY_ATTRIBUTES sa; 1782 DWORD sharing, type; 1783 int wxflag; 1784 HANDLE hand; 1785 1786 TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n", 1787 fd, debugstr_w(path), oflags, shflags, pmode); 1788 1789 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL; 1790 1791 *fd = -1; 1792 wxflag = split_oflags(oflags); 1793 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) 1794 { 1795 case _O_RDONLY: access |= GENERIC_READ; break; 1796 case _O_WRONLY: access |= GENERIC_WRITE; break; 1797 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break; 1798 } 1799 1800 if (oflags & _O_CREAT) 1801 { 1802 if(pmode & ~(_S_IREAD | _S_IWRITE)) 1803 FIXME(": pmode 0x%04x ignored\n", pmode); 1804 else 1805 WARN(": pmode 0x%04x ignored\n", pmode); 1806 1807 if (oflags & _O_EXCL) 1808 creation = CREATE_NEW; 1809 else if (oflags & _O_TRUNC) 1810 creation = CREATE_ALWAYS; 1811 else 1812 creation = OPEN_ALWAYS; 1813 } 1814 else /* no _O_CREAT */ 1815 { 1816 if (oflags & _O_TRUNC) 1817 creation = TRUNCATE_EXISTING; 1818 else 1819 creation = OPEN_EXISTING; 1820 } 1821 1822 switch( shflags ) 1823 { 1824 case _SH_DENYRW: 1825 sharing = 0L; 1826 break; 1827 case _SH_DENYWR: 1828 sharing = FILE_SHARE_READ; 1829 break; 1830 case _SH_DENYRD: 1831 sharing = FILE_SHARE_WRITE; 1832 break; 1833 case _SH_DENYNO: 1834 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 1835 break; 1836 default: 1837 ERR( "Unhandled shflags 0x%x\n", shflags ); 1838 return EINVAL; 1839 } 1840 attrib = FILE_ATTRIBUTE_NORMAL; 1841 1842 if (oflags & _O_TEMPORARY) 1843 { 1844 attrib |= FILE_FLAG_DELETE_ON_CLOSE; 1845 access |= DELETE; 1846 sharing |= FILE_SHARE_DELETE; 1847 } 1848 1849 sa.nLength = sizeof( SECURITY_ATTRIBUTES ); 1850 sa.lpSecurityDescriptor = NULL; 1851 sa.bInheritHandle = !(oflags & _O_NOINHERIT); 1852 1853 if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT)) 1854 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING) 1855 && !(access&GENERIC_READ)) 1856 { 1857 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 1858 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 1859 if (hand != INVALID_HANDLE_VALUE) 1860 { 1861 oflags = check_bom(hand, oflags, FALSE); 1862 CloseHandle(hand); 1863 } 1864 else 1865 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT); 1866 } 1867 1868 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0); 1869 if (hand == INVALID_HANDLE_VALUE) { 1870 WARN(":failed-last error (%d)\n",GetLastError()); 1871 _dosmaperr(GetLastError()); 1872 return *_errno(); 1873 } 1874 1875 if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT)) 1876 { 1877 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW 1878 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING 1879 || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS))) 1880 { 1881 if (oflags & _O_U8TEXT) 1882 { 1883 DWORD written = 0, tmp; 1884 1885 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written, 1886 sizeof(utf8_bom)-written, &tmp, NULL)) 1887 written += tmp; 1888 if (written != sizeof(utf8_bom)) { 1889 WARN("error writing BOM\n"); 1890 CloseHandle(hand); 1891 _dosmaperr(GetLastError()); 1892 return *_errno(); 1893 } 1894 } 1895 else 1896 { 1897 DWORD written = 0, tmp; 1898 1899 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written, 1900 sizeof(utf16_bom)-written, &tmp, NULL)) 1901 written += tmp; 1902 if (written != sizeof(utf16_bom)) 1903 { 1904 WARN("error writing BOM\n"); 1905 CloseHandle(hand); 1906 _dosmaperr(GetLastError()); 1907 return *_errno(); 1908 } 1909 } 1910 } 1911 else if (access & GENERIC_READ) 1912 oflags = check_bom(hand, oflags, TRUE); 1913 } 1914 1915 type = GetFileType(hand); 1916 if (type == FILE_TYPE_CHAR) 1917 wxflag |= WX_TTY; 1918 else if (type == FILE_TYPE_PIPE) 1919 wxflag |= WX_PIPE; 1920 1921 *fd = msvcrt_alloc_fd(hand, wxflag); 1922 if (*fd == -1) 1923 return *_errno(); 1924 1925 if (oflags & _O_WTEXT) 1926 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE; 1927 else if (oflags & _O_U16TEXT) 1928 get_ioinfo_nolock(*fd)->exflag |= EF_UTF16; 1929 else if (oflags & _O_U8TEXT) 1930 get_ioinfo_nolock(*fd)->exflag |= EF_UTF8; 1931 1932 TRACE(":fd (%d) handle (%p)\n", *fd, hand); 1933 return 0; 1934 } 1935 1936 /********************************************************************* 1937 * _wsopen (MSVCRT.@) 1938 */ 1939 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... ) 1940 { 1941 int pmode; 1942 int fd; 1943 1944 if (oflags & _O_CREAT) 1945 { 1946 __ms_va_list ap; 1947 1948 __ms_va_start(ap, shflags); 1949 pmode = va_arg(ap, int); 1950 __ms_va_end(ap); 1951 } 1952 else 1953 pmode = 0; 1954 1955 _wsopen_s(&fd, path, oflags, shflags, pmode); 1956 return fd; 1957 } 1958 1959 /********************************************************************* 1960 * _sopen_s (MSVCRT.@) 1961 */ 1962 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode ) 1963 { 1964 wchar_t *pathW; 1965 int ret; 1966 1967 if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path)))) 1968 return EINVAL; 1969 1970 ret = _wsopen_s(fd, pathW, oflags, shflags, pmode); 1971 free(pathW); 1972 return ret; 1973 } 1974 1975 /********************************************************************* 1976 * _sopen (MSVCRT.@) 1977 */ 1978 int CDECL _sopen( const char *path, int oflags, int shflags, ... ) 1979 { 1980 int pmode; 1981 int fd; 1982 1983 if (oflags & _O_CREAT) 1984 { 1985 va_list ap; 1986 1987 va_start(ap, shflags); 1988 pmode = va_arg(ap, int); 1989 va_end(ap); 1990 } 1991 else 1992 pmode = 0; 1993 1994 _sopen_s(&fd, path, oflags, shflags, pmode); 1995 return fd; 1996 } 1997 1998 /********************************************************************* 1999 * _open (MSVCRT.@) 2000 */ 2001 int CDECL _open( const char *path, int flags, ... ) 2002 { 2003 va_list ap; 2004 2005 if (flags & _O_CREAT) 2006 { 2007 int pmode; 2008 va_start(ap, flags); 2009 pmode = va_arg(ap, int); 2010 va_end(ap); 2011 return _sopen( path, flags, _SH_DENYNO, pmode ); 2012 } 2013 else 2014 return _sopen( path, flags, _SH_DENYNO); 2015 } 2016 2017 /********************************************************************* 2018 * _wopen (MSVCRT.@) 2019 */ 2020 int CDECL _wopen(const wchar_t *path,int flags,...) 2021 { 2022 va_list ap; 2023 2024 if (flags & _O_CREAT) 2025 { 2026 int pmode; 2027 va_start(ap, flags); 2028 pmode = va_arg(ap, int); 2029 va_end(ap); 2030 return _wsopen( path, flags, _SH_DENYNO, pmode ); 2031 } 2032 else 2033 return _wsopen( path, flags, _SH_DENYNO); 2034 } 2035 2036 /********************************************************************* 2037 * _creat (MSVCRT.@) 2038 */ 2039 int CDECL _creat(const char *path, int flags) 2040 { 2041 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC; 2042 return _open(path, usedFlags); 2043 } 2044 2045 /********************************************************************* 2046 * _wcreat (MSVCRT.@) 2047 */ 2048 int CDECL _wcreat(const wchar_t *path, int flags) 2049 { 2050 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC; 2051 return _wopen(path, usedFlags); 2052 } 2053 2054 /********************************************************************* 2055 * _open_osfhandle (MSVCRT.@) 2056 */ 2057 int CDECL _open_osfhandle(intptr_t handle, int oflags) 2058 { 2059 DWORD flags; 2060 int fd; 2061 2062 /* _O_RDONLY (0) always matches, so set the read flag 2063 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the 2064 * file, so set the write flag. It also only sets _O_TEXT if it wants 2065 * text - it never sets _O_BINARY. 2066 */ 2067 /* don't let split_oflags() decide the mode if no mode is passed */ 2068 if (!(oflags & (_O_BINARY | _O_TEXT))) 2069 oflags |= _O_BINARY; 2070 2071 flags = GetFileType((HANDLE)handle); 2072 if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR) 2073 { 2074 _dosmaperr(GetLastError()); 2075 return -1; 2076 } 2077 2078 if (flags == FILE_TYPE_CHAR) 2079 flags = WX_TTY; 2080 else if (flags == FILE_TYPE_PIPE) 2081 flags = WX_PIPE; 2082 else 2083 flags = 0; 2084 flags |= split_oflags(oflags); 2085 2086 fd = msvcrt_alloc_fd((HANDLE)handle, flags); 2087 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags); 2088 return fd; 2089 } 2090 2091 /********************************************************************* 2092 * _rmtmp (MSVCRT.@) 2093 */ 2094 int CDECL _rmtmp(void) 2095 { 2096 int num_removed = 0, i; 2097 FILE *file; 2098 2099 LOCK_FILES(); 2100 for (i = 3; i < MSVCRT_stream_idx; i++) { 2101 file = msvcrt_get_file(i); 2102 2103 if (file->_tmpfname) 2104 { 2105 fclose(file); 2106 num_removed++; 2107 } 2108 } 2109 UNLOCK_FILES(); 2110 2111 if (num_removed) 2112 TRACE(":removed (%d) temp files\n",num_removed); 2113 return num_removed; 2114 } 2115 2116 static inline int get_utf8_char_len(char ch) 2117 { 2118 if((ch&0xf8) == 0xf0) 2119 return 4; 2120 else if((ch&0xf0) == 0xe0) 2121 return 3; 2122 else if((ch&0xe0) == 0xc0) 2123 return 2; 2124 return 1; 2125 } 2126 2127 /********************************************************************* 2128 * (internal) read_utf8 2129 */ 2130 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count) 2131 { 2132 HANDLE hand = fdinfo->handle; 2133 char min_buf[4], *readbuf, lookahead; 2134 DWORD readbuf_size, pos=0, num_read=1, char_len, i, j; 2135 2136 /* make the buffer big enough to hold at least one character */ 2137 /* read bytes have to fit to output and lookahead buffers */ 2138 count /= 2; 2139 readbuf_size = count < 4 ? 4 : count; 2140 if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) { 2141 readbuf_size = 4; 2142 readbuf = min_buf; 2143 } 2144 2145 if(fdinfo->lookahead[0] != '\n') { 2146 readbuf[pos++] = fdinfo->lookahead[0]; 2147 fdinfo->lookahead[0] = '\n'; 2148 2149 if(fdinfo->lookahead[1] != '\n') { 2150 readbuf[pos++] = fdinfo->lookahead[1]; 2151 fdinfo->lookahead[1] = '\n'; 2152 2153 if(fdinfo->lookahead[2] != '\n') { 2154 readbuf[pos++] = fdinfo->lookahead[2]; 2155 fdinfo->lookahead[2] = '\n'; 2156 } 2157 } 2158 } 2159 2160 /* NOTE: this case is broken in native dll, reading 2161 * sometimes fails when small buffer is passed 2162 */ 2163 if(count < 4) { 2164 if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) { 2165 if (GetLastError() == ERROR_BROKEN_PIPE) { 2166 fdinfo->wxflag |= WX_ATEOF; 2167 return 0; 2168 }else { 2169 _dosmaperr(GetLastError()); 2170 return -1; 2171 } 2172 }else if(!num_read) { 2173 fdinfo->wxflag |= WX_ATEOF; 2174 return 0; 2175 }else { 2176 pos++; 2177 } 2178 2179 char_len = get_utf8_char_len(readbuf[0]); 2180 if(char_len>pos) { 2181 if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL)) 2182 pos += num_read; 2183 } 2184 2185 if(readbuf[0] == '\n') 2186 fdinfo->wxflag |= WX_READNL; 2187 else 2188 fdinfo->wxflag &= ~WX_READNL; 2189 2190 if(readbuf[0] == 0x1a) { 2191 fdinfo->wxflag |= WX_ATEOF; 2192 return 0; 2193 } 2194 2195 if(readbuf[0] == '\r') { 2196 if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1) 2197 buf[0] = '\r'; 2198 else if(lookahead == '\n') 2199 buf[0] = '\n'; 2200 else { 2201 buf[0] = '\r'; 2202 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) 2203 fdinfo->lookahead[0] = lookahead; 2204 else 2205 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT); 2206 } 2207 return 2; 2208 } 2209 2210 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) { 2211 _dosmaperr(GetLastError()); 2212 return -1; 2213 } 2214 2215 return num_read*2; 2216 } 2217 2218 if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) { 2219 if(pos) { 2220 num_read = 0; 2221 }else if(GetLastError() == ERROR_BROKEN_PIPE) { 2222 fdinfo->wxflag |= WX_ATEOF; 2223 if (readbuf != min_buf) free(readbuf); 2224 return 0; 2225 }else { 2226 _dosmaperr(GetLastError()); 2227 if (readbuf != min_buf) free(readbuf); 2228 return -1; 2229 } 2230 }else if(!pos && !num_read) { 2231 fdinfo->wxflag |= WX_ATEOF; 2232 if (readbuf != min_buf) free(readbuf); 2233 return 0; 2234 } 2235 2236 pos += num_read; 2237 if(readbuf[0] == '\n') 2238 fdinfo->wxflag |= WX_READNL; 2239 else 2240 fdinfo->wxflag &= ~WX_READNL; 2241 2242 /* Find first byte of last character (may be incomplete) */ 2243 for(i=pos-1; i>0 && i>pos-4; i--) 2244 if((readbuf[i]&0xc0) != 0x80) 2245 break; 2246 char_len = get_utf8_char_len(readbuf[i]); 2247 if(char_len+i <= pos) 2248 i += char_len; 2249 2250 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) { 2251 if(i < pos) 2252 fdinfo->lookahead[0] = readbuf[i]; 2253 if(i+1 < pos) 2254 fdinfo->lookahead[1] = readbuf[i+1]; 2255 if(i+2 < pos) 2256 fdinfo->lookahead[2] = readbuf[i+2]; 2257 }else if(i < pos) { 2258 SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT); 2259 } 2260 pos = i; 2261 2262 for(i=0, j=0; i<pos; i++) { 2263 if(readbuf[i] == 0x1a) { 2264 fdinfo->wxflag |= WX_ATEOF; 2265 break; 2266 } 2267 2268 /* strip '\r' if followed by '\n' */ 2269 if(readbuf[i] == '\r' && i+1==pos) { 2270 if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) { 2271 readbuf[j++] = '\r'; 2272 }else if(lookahead == '\n' && j==0) { 2273 readbuf[j++] = '\n'; 2274 }else { 2275 if(lookahead != '\n') 2276 readbuf[j++] = '\r'; 2277 2278 if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) 2279 fdinfo->lookahead[0] = lookahead; 2280 else 2281 SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT); 2282 } 2283 }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') { 2284 readbuf[j++] = readbuf[i]; 2285 } 2286 } 2287 pos = j; 2288 2289 if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) { 2290 _dosmaperr(GetLastError()); 2291 if (readbuf != min_buf) free(readbuf); 2292 return -1; 2293 } 2294 2295 if (readbuf != min_buf) free(readbuf); 2296 return num_read*2; 2297 } 2298 2299 /********************************************************************* 2300 * (internal) read_i 2301 * 2302 * When reading \r as last character in text mode, read() positions 2303 * the file pointer on the \r character while getc() goes on to 2304 * the following \n 2305 */ 2306 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count) 2307 { 2308 DWORD num_read, utf16; 2309 char *bufstart = buf; 2310 2311 if (count == 0) 2312 return 0; 2313 2314 if (fdinfo->wxflag & WX_ATEOF) { 2315 TRACE("already at EOF, returning 0\n"); 2316 return 0; 2317 } 2318 /* Don't trace small reads, it gets *very* annoying */ 2319 if (count > 4) 2320 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count); 2321 if (fdinfo->handle == INVALID_HANDLE_VALUE) 2322 { 2323 *_errno() = EBADF; 2324 return -1; 2325 } 2326 2327 utf16 = (fdinfo->exflag & EF_UTF16) != 0; 2328 if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1) 2329 { 2330 *_errno() = EINVAL; 2331 return -1; 2332 } 2333 2334 if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8)) 2335 return read_utf8(fdinfo, buf, count); 2336 2337 if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL)) 2338 { 2339 if (fdinfo->lookahead[0] != '\n') 2340 { 2341 bufstart[0] = fdinfo->lookahead[0]; 2342 fdinfo->lookahead[0] = '\n'; 2343 2344 if (utf16) 2345 { 2346 bufstart[1] = fdinfo->lookahead[1]; 2347 fdinfo->lookahead[1] = '\n'; 2348 } 2349 2350 if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL)) 2351 num_read += 1+utf16; 2352 else 2353 num_read = 1+utf16; 2354 } 2355 2356 if(utf16 && (num_read&1)) 2357 { 2358 /* msvcr90 uses uninitialized value from the buffer in this case */ 2359 /* msvcrt ignores additional data */ 2360 ERR("got odd number of bytes in UTF16 mode\n"); 2361 num_read--; 2362 } 2363 2364 if (count != 0 && num_read == 0) 2365 { 2366 fdinfo->wxflag |= WX_ATEOF; 2367 TRACE(":EOF %s\n",debugstr_an(buf,num_read)); 2368 } 2369 else if (fdinfo->wxflag & WX_TEXT) 2370 { 2371 DWORD i, j; 2372 2373 if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0)) 2374 fdinfo->wxflag |= WX_READNL; 2375 else 2376 fdinfo->wxflag &= ~WX_READNL; 2377 2378 for (i=0, j=0; i<num_read; i+=1+utf16) 2379 { 2380 /* in text mode, a ctrl-z signals EOF */ 2381 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0)) 2382 { 2383 fdinfo->wxflag |= WX_ATEOF; 2384 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read)); 2385 break; 2386 } 2387 2388 /* in text mode, strip \r if followed by \n */ 2389 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read) 2390 { 2391 char lookahead[2]; 2392 DWORD len; 2393 2394 lookahead[1] = '\n'; 2395 if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len) 2396 { 2397 if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0) 2398 { 2399 bufstart[j++] = '\n'; 2400 if(utf16) bufstart[j++] = 0; 2401 } 2402 else 2403 { 2404 if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0)) 2405 { 2406 bufstart[j++] = '\r'; 2407 if(utf16) bufstart[j++] = 0; 2408 } 2409 2410 if (fdinfo->wxflag & (WX_PIPE | WX_TTY)) 2411 { 2412 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1])) 2413 { 2414 bufstart[j++] = '\n'; 2415 if (utf16) bufstart[j++] = 0; 2416 } 2417 else 2418 { 2419 fdinfo->lookahead[0] = lookahead[0]; 2420 fdinfo->lookahead[1] = lookahead[1]; 2421 } 2422 } 2423 else 2424 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT); 2425 } 2426 } 2427 else 2428 { 2429 bufstart[j++] = '\r'; 2430 if(utf16) bufstart[j++] = 0; 2431 } 2432 } 2433 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0)) 2434 || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0))) 2435 { 2436 bufstart[j++] = bufstart[i]; 2437 if(utf16) bufstart[j++] = bufstart[i+1]; 2438 } 2439 } 2440 num_read = j; 2441 } 2442 } 2443 else 2444 { 2445 if (GetLastError() == ERROR_BROKEN_PIPE) 2446 { 2447 TRACE(":end-of-pipe\n"); 2448 fdinfo->wxflag |= WX_ATEOF; 2449 return 0; 2450 } 2451 else 2452 { 2453 TRACE(":failed-last error (%d)\n",GetLastError()); 2454 return -1; 2455 } 2456 } 2457 2458 if (count > 4) 2459 TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read)); 2460 return num_read; 2461 } 2462 2463 /********************************************************************* 2464 * _read (MSVCRT.@) 2465 */ 2466 int CDECL _read(int fd, void *buf, unsigned int count) 2467 { 2468 ioinfo *info = get_ioinfo(fd); 2469 int num_read = read_i(fd, info, buf, count); 2470 release_ioinfo(info); 2471 return num_read; 2472 } 2473 2474 /********************************************************************* 2475 * _setmode (MSVCRT.@) 2476 */ 2477 int CDECL _setmode(int fd,int mode) 2478 { 2479 ioinfo *info = get_ioinfo(fd); 2480 int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY; 2481 if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16))) 2482 ret = _O_WTEXT; 2483 2484 if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT 2485 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) { 2486 *_errno() = EINVAL; 2487 release_ioinfo(info); 2488 return -1; 2489 } 2490 2491 if(info == &__badioinfo) { 2492 *_errno() = EBADF; 2493 return EOF; 2494 } 2495 2496 if(mode == _O_BINARY) { 2497 info->wxflag &= ~WX_TEXT; 2498 info->exflag &= ~(EF_UTF8|EF_UTF16); 2499 release_ioinfo(info); 2500 return ret; 2501 } 2502 2503 info->wxflag |= WX_TEXT; 2504 if(mode == _O_TEXT) 2505 info->exflag &= ~(EF_UTF8|EF_UTF16); 2506 else if(mode == _O_U8TEXT) 2507 info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8; 2508 else 2509 info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16; 2510 2511 release_ioinfo(info); 2512 return ret; 2513 2514 } 2515 2516 /********************************************************************* 2517 * _tell (MSVCRT.@) 2518 */ 2519 long CDECL _tell(int fd) 2520 { 2521 return _lseek(fd, 0, SEEK_CUR); 2522 } 2523 2524 /********************************************************************* 2525 * _telli64 (MSVCRT.@) 2526 */ 2527 __int64 CDECL _telli64(int fd) 2528 { 2529 return _lseeki64(fd, 0, SEEK_CUR); 2530 } 2531 2532 /********************************************************************* 2533 * _tempnam (MSVCRT.@) 2534 */ 2535 char * CDECL _tempnam(const char *dir, const char *prefix) 2536 { 2537 char tmpbuf[MAX_PATH]; 2538 const char *tmp_dir = getenv("TMP"); 2539 2540 if (tmp_dir) dir = tmp_dir; 2541 2542 TRACE("dir (%s) prefix (%s)\n",dir,prefix); 2543 if (GetTempFileNameA(dir,prefix,0,tmpbuf)) 2544 { 2545 TRACE("got name (%s)\n",tmpbuf); 2546 DeleteFileA(tmpbuf); 2547 return _strdup(tmpbuf); 2548 } 2549 TRACE("failed (%d)\n",GetLastError()); 2550 return NULL; 2551 } 2552 2553 /********************************************************************* 2554 * _wtempnam (MSVCRT.@) 2555 */ 2556 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix) 2557 { 2558 wchar_t tmpbuf[MAX_PATH]; 2559 2560 TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix)); 2561 if (GetTempFileNameW(dir,prefix,0,tmpbuf)) 2562 { 2563 TRACE("got name (%s)\n",debugstr_w(tmpbuf)); 2564 DeleteFileW(tmpbuf); 2565 return _wcsdup(tmpbuf); 2566 } 2567 TRACE("failed (%d)\n",GetLastError()); 2568 return NULL; 2569 } 2570 2571 /********************************************************************* 2572 * _umask (MSVCRT.@) 2573 */ 2574 int CDECL _umask(int umask) 2575 { 2576 int old_umask = MSVCRT_umask; 2577 TRACE("(%d)\n",umask); 2578 MSVCRT_umask = umask; 2579 return old_umask; 2580 } 2581 2582 /********************************************************************* 2583 * _write (MSVCRT.@) 2584 */ 2585 int CDECL _write(int fd, const void* buf, unsigned int count) 2586 { 2587 DWORD num_written; 2588 ioinfo *info = get_ioinfo(fd); 2589 HANDLE hand = info->handle; 2590 2591 /* Don't trace small writes, it gets *very* annoying */ 2592 #if 0 2593 if (count > 32) 2594 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count); 2595 #endif 2596 if (hand == INVALID_HANDLE_VALUE) 2597 { 2598 *_errno() = EBADF; 2599 release_ioinfo(info); 2600 return -1; 2601 } 2602 2603 if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1) 2604 { 2605 *_errno() = EINVAL; 2606 release_ioinfo(info); 2607 return -1; 2608 } 2609 2610 /* If appending, go to EOF */ 2611 if (info->wxflag & WX_APPEND) 2612 _lseek(fd, 0, FILE_END); 2613 2614 if (!(info->wxflag & WX_TEXT)) 2615 { 2616 if (WriteFile(hand, buf, count, &num_written, NULL) 2617 && (num_written == count)) 2618 { 2619 release_ioinfo(info); 2620 return num_written; 2621 } 2622 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd, 2623 hand, GetLastError()); 2624 *_errno() = ENOSPC; 2625 } 2626 else 2627 { 2628 unsigned int i, j, nr_lf, size; 2629 char *p = NULL; 2630 const char *q; 2631 const char *s = buf, *buf_start = buf; 2632 2633 if (!(info->exflag & (EF_UTF8|EF_UTF16))) 2634 { 2635 /* find number of \n */ 2636 for (nr_lf=0, i=0; i<count; i++) 2637 if (s[i] == '\n') 2638 nr_lf++; 2639 if (nr_lf) 2640 { 2641 size = count+nr_lf; 2642 if ((q = p = malloc(size))) 2643 { 2644 for (s = buf, i = 0, j = 0; i < count; i++) 2645 { 2646 if (s[i] == '\n') 2647 p[j++] = '\r'; 2648 p[j++] = s[i]; 2649 } 2650 } 2651 else 2652 { 2653 FIXME("Malloc failed\n"); 2654 nr_lf = 0; 2655 size = count; 2656 q = buf; 2657 } 2658 } 2659 else 2660 { 2661 size = count; 2662 q = buf; 2663 } 2664 } 2665 else if (info->exflag & EF_UTF16) 2666 { 2667 for (nr_lf=0, i=0; i<count; i+=2) 2668 if (s[i]=='\n' && s[i+1]==0) 2669 nr_lf += 2; 2670 if (nr_lf) 2671 { 2672 size = count+nr_lf; 2673 if ((q = p = malloc(size))) 2674 { 2675 for (s=buf, i=0, j=0; i<count; i++) 2676 { 2677 if (s[i]=='\n' && s[i+1]==0) 2678 { 2679 p[j++] = '\r'; 2680 p[j++] = 0; 2681 } 2682 p[j++] = s[i++]; 2683 p[j++] = s[i]; 2684 } 2685 } 2686 else 2687 { 2688 FIXME("Malloc failed\n"); 2689 nr_lf = 0; 2690 size = count; 2691 q = buf; 2692 } 2693 } 2694 else 2695 { 2696 size = count; 2697 q = buf; 2698 } 2699 } 2700 else 2701 { 2702 DWORD conv_len; 2703 2704 for(nr_lf=0, i=0; i<count; i+=2) 2705 if (s[i]=='\n' && s[i+1]==0) 2706 nr_lf++; 2707 2708 conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL); 2709 if(!conv_len) { 2710 _dosmaperr(GetLastError()); 2711 free(p); 2712 release_ioinfo(info); 2713 return -1; 2714 } 2715 2716 size = conv_len+nr_lf; 2717 if((p = malloc(count+nr_lf*2+size))) 2718 { 2719 for (s=buf, i=0, j=0; i<count; i++) 2720 { 2721 if (s[i]=='\n' && s[i+1]==0) 2722 { 2723 p[j++] = '\r'; 2724 p[j++] = 0; 2725 } 2726 p[j++] = s[i++]; 2727 p[j++] = s[i]; 2728 } 2729 q = p+count+nr_lf*2; 2730 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf, 2731 p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL); 2732 } 2733 else 2734 { 2735 FIXME("Malloc failed\n"); 2736 nr_lf = 0; 2737 size = count; 2738 q = buf; 2739 } 2740 } 2741 2742 if (!WriteFile(hand, q, size, &num_written, NULL)) 2743 num_written = -1; 2744 release_ioinfo(info); 2745 if(p) 2746 free(p); 2747 if (num_written != size) 2748 { 2749 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n", 2750 fd, hand, GetLastError(), num_written); 2751 *_errno() = ENOSPC; 2752 return s - buf_start; 2753 } 2754 return count; 2755 } 2756 2757 release_ioinfo(info); 2758 return -1; 2759 } 2760 2761 /********************************************************************* 2762 * _putw (MSVCRT.@) 2763 */ 2764 int CDECL _putw(int val, FILE* file) 2765 { 2766 int len; 2767 2768 _lock_file(file); 2769 len = _write(file->_file, &val, sizeof(val)); 2770 if (len == sizeof(val)) { 2771 _unlock_file(file); 2772 return val; 2773 } 2774 2775 file->_flag |= _IOERR; 2776 _unlock_file(file); 2777 return EOF; 2778 } 2779 2780 /********************************************************************* 2781 * fclose (MSVCRT.@) 2782 */ 2783 int CDECL fclose(FILE* file) 2784 { 2785 int r, flag; 2786 2787 _lock_file(file); 2788 flag = file->_flag; 2789 free(file->_tmpfname); 2790 file->_tmpfname = NULL; 2791 /* flush stdio buffers */ 2792 if(file->_flag & _IOWRT) 2793 fflush(file); 2794 if(file->_flag & _IOMYBUF) 2795 free(file->_base); 2796 2797 r=_close(file->_file); 2798 2799 file->_flag = 0; 2800 _unlock_file(file); 2801 if(file<_iob || file>=_iob+_IOB_ENTRIES) 2802 DeleteCriticalSection(&((file_crit*)file)->crit); 2803 2804 if(file == msvcrt_get_file(MSVCRT_stream_idx-1)) { 2805 while(MSVCRT_stream_idx>3 && !file->_flag) { 2806 MSVCRT_stream_idx--; 2807 file = msvcrt_get_file(MSVCRT_stream_idx-1); 2808 } 2809 } 2810 2811 return ((r == -1) || (flag & _IOERR) ? EOF : 0); 2812 } 2813 2814 /********************************************************************* 2815 * feof (MSVCRT.@) 2816 */ 2817 int CDECL feof(FILE* file) 2818 { 2819 return file->_flag & _IOEOF; 2820 } 2821 2822 /********************************************************************* 2823 * ferror (MSVCRT.@) 2824 */ 2825 int CDECL ferror(FILE* file) 2826 { 2827 return file->_flag & _IOERR; 2828 } 2829 2830 /********************************************************************* 2831 * _filbuf (MSVCRT.@) 2832 */ 2833 int CDECL _filbuf(FILE* file) 2834 { 2835 unsigned char c; 2836 _lock_file(file); 2837 2838 if(file->_flag & _IOSTRG) { 2839 _unlock_file(file); 2840 return EOF; 2841 } 2842 2843 /* Allocate buffer if needed */ 2844 if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF))) 2845 msvcrt_alloc_buffer(file); 2846 2847 if(!(file->_flag & _IOREAD)) { 2848 if(file->_flag & _IORW) 2849 file->_flag |= _IOREAD; 2850 else { 2851 _unlock_file(file); 2852 return EOF; 2853 } 2854 } 2855 2856 if(!(file->_flag & (_IOMYBUF | _USERBUF))) { 2857 int r; 2858 if ((r = _read(file->_file,&c,1)) != 1) { 2859 file->_flag |= (r == 0) ? _IOEOF : _IOERR; 2860 _unlock_file(file); 2861 return EOF; 2862 } 2863 2864 _unlock_file(file); 2865 return c; 2866 } else { 2867 file->_cnt = _read(file->_file, file->_base, file->_bufsiz); 2868 if(file->_cnt<=0) { 2869 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR; 2870 file->_cnt = 0; 2871 _unlock_file(file); 2872 return EOF; 2873 } 2874 2875 file->_cnt--; 2876 file->_ptr = file->_base+1; 2877 c = *(unsigned char *)file->_base; 2878 _unlock_file(file); 2879 return c; 2880 } 2881 } 2882 2883 /********************************************************************* 2884 * fgetc (MSVCRT.@) 2885 */ 2886 int CDECL fgetc(FILE* file) 2887 { 2888 unsigned char *i; 2889 unsigned int j; 2890 2891 _lock_file(file); 2892 if (file->_cnt>0) { 2893 file->_cnt--; 2894 i = (unsigned char *)file->_ptr++; 2895 j = *i; 2896 } else 2897 j = _filbuf(file); 2898 2899 _unlock_file(file); 2900 return j; 2901 } 2902 2903 /********************************************************************* 2904 * _fgetchar (MSVCRT.@) 2905 */ 2906 int CDECL _fgetchar(void) 2907 { 2908 return fgetc(stdin); 2909 } 2910 2911 /********************************************************************* 2912 * fgets (MSVCRT.@) 2913 */ 2914 char * CDECL fgets(char *s, int size, FILE* file) 2915 { 2916 int cc = EOF; 2917 char * buf_start = s; 2918 2919 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n", 2920 file,file->_file,s,size); 2921 2922 _lock_file(file); 2923 2924 while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n') 2925 { 2926 *s++ = (char)cc; 2927 size --; 2928 } 2929 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/ 2930 { 2931 TRACE(":nothing read\n"); 2932 _unlock_file(file); 2933 return NULL; 2934 } 2935 if ((cc != EOF) && (size > 1)) 2936 *s++ = cc; 2937 *s = '\0'; 2938 TRACE(":got %s\n", debugstr_a(buf_start)); 2939 _unlock_file(file); 2940 return buf_start; 2941 } 2942 2943 /********************************************************************* 2944 * fgetwc (MSVCRT.@) 2945 */ 2946 wint_t CDECL fgetwc(FILE* file) 2947 { 2948 wint_t ret; 2949 int ch; 2950 2951 _lock_file(file); 2952 2953 if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16)) 2954 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) { 2955 char *p; 2956 2957 for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) { 2958 ch = fgetc(file); 2959 if(ch == EOF) { 2960 ret = WEOF; 2961 break; 2962 } 2963 *p = (char)ch; 2964 } 2965 }else { 2966 char mbs[MB_LEN_MAX]; 2967 int len = 0; 2968 2969 ch = fgetc(file); 2970 if(ch != EOF) { 2971 mbs[0] = (char)ch; 2972 if(isleadbyte((unsigned char)mbs[0])) { 2973 ch = fgetc(file); 2974 if(ch != EOF) { 2975 mbs[1] = (char)ch; 2976 len = 2; 2977 } 2978 }else { 2979 len = 1; 2980 } 2981 } 2982 2983 if(!len || mbtowc(&ret, mbs, len)==-1) 2984 ret = WEOF; 2985 } 2986 2987 _unlock_file(file); 2988 return ret; 2989 } 2990 2991 /********************************************************************* 2992 * _getw (MSVCRT.@) 2993 */ 2994 int CDECL _getw(FILE* file) 2995 { 2996 char *ch; 2997 int i, k; 2998 unsigned int j; 2999 ch = (char *)&i; 3000 3001 _lock_file(file); 3002 for (j=0; j<sizeof(int); j++) { 3003 k = fgetc(file); 3004 if (k == EOF) { 3005 file->_flag |= _IOEOF; 3006 _unlock_file(file); 3007 return EOF; 3008 } 3009 ch[j] = k; 3010 } 3011 3012 _unlock_file(file); 3013 return i; 3014 } 3015 3016 /********************************************************************* 3017 * getwc (MSVCRT.@) 3018 */ 3019 wint_t CDECL getwc(FILE* file) 3020 { 3021 return fgetwc(file); 3022 } 3023 3024 /********************************************************************* 3025 * _fgetwchar (MSVCRT.@) 3026 */ 3027 wint_t CDECL _fgetwchar(void) 3028 { 3029 return fgetwc(stdin); 3030 } 3031 3032 /********************************************************************* 3033 * getwchar (MSVCRT.@) 3034 */ 3035 wint_t CDECL getwchar(void) 3036 { 3037 return _fgetwchar(); 3038 } 3039 3040 /********************************************************************* 3041 * fgetws (MSVCRT.@) 3042 */ 3043 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file) 3044 { 3045 int cc = WEOF; 3046 wchar_t * buf_start = s; 3047 3048 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n", 3049 file,file->_file,s,size); 3050 3051 _lock_file(file); 3052 3053 while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n') 3054 { 3055 *s++ = (char)cc; 3056 size --; 3057 } 3058 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/ 3059 { 3060 TRACE(":nothing read\n"); 3061 _unlock_file(file); 3062 return NULL; 3063 } 3064 if ((cc != WEOF) && (size > 1)) 3065 *s++ = cc; 3066 *s = 0; 3067 TRACE(":got %s\n", debugstr_w(buf_start)); 3068 _unlock_file(file); 3069 return buf_start; 3070 } 3071 3072 /********************************************************************* 3073 * fwrite (MSVCRT.@) 3074 */ 3075 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file) 3076 { 3077 size_t wrcnt=size * nmemb; 3078 int written = 0; 3079 if (size == 0) 3080 return 0; 3081 3082 _lock_file(file); 3083 3084 while(wrcnt) { 3085 #ifndef __REACTOS__ 3086 if(file->_cnt < 0) { 3087 WARN("negative file->_cnt value in %p\n", file); 3088 file->_flag |= MSVCRT__IOERR; 3089 break; 3090 } else 3091 #endif 3092 if(file->_cnt) { 3093 int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt; 3094 memcpy(file->_ptr, ptr, pcnt); 3095 file->_cnt -= pcnt; 3096 file->_ptr += pcnt; 3097 written += pcnt; 3098 wrcnt -= pcnt; 3099 ptr = (const char*)ptr + pcnt; 3100 } else if((file->_flag & _IONBF) 3101 || ((file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= file->_bufsiz) 3102 || (!(file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) { 3103 size_t pcnt; 3104 int bufsiz; 3105 3106 if(file->_flag & _IONBF) 3107 bufsiz = 1; 3108 else if(!(file->_flag & (_IOMYBUF | _USERBUF))) 3109 bufsiz = MSVCRT_INTERNAL_BUFSIZ; 3110 else 3111 bufsiz = file->_bufsiz; 3112 3113 pcnt = (wrcnt / bufsiz) * bufsiz; 3114 3115 if(msvcrt_flush_buffer(file) == EOF) 3116 break; 3117 3118 if(_write(file->_file, ptr, pcnt) <= 0) { 3119 file->_flag |= _IOERR; 3120 break; 3121 } 3122 written += pcnt; 3123 wrcnt -= pcnt; 3124 ptr = (const char*)ptr + pcnt; 3125 } else { 3126 if(_flsbuf(*(const char*)ptr, file) == EOF) 3127 break; 3128 written++; 3129 wrcnt--; 3130 ptr = (const char*)ptr + 1; 3131 } 3132 } 3133 3134 _unlock_file(file); 3135 return written / size; 3136 } 3137 3138 /********************************************************************* 3139 * fputwc (MSVCRT.@) 3140 * FORKED for ReactOS, don't sync with Wine! 3141 * References: 3142 * - http://jira.reactos.org/browse/CORE-6495 3143 * - http://bugs.winehq.org/show_bug.cgi?id=8598 3144 */ 3145 wint_t CDECL fputwc(wchar_t c, FILE* stream) 3146 { 3147 /* If this is a real file stream (and not some temporary one for 3148 sprintf-like functions), check whether it is opened in text mode. 3149 In this case, we have to perform an implicit conversion to ANSI. */ 3150 if (!(stream->_flag & _IOSTRG) && get_ioinfo_nolock(stream->_file)->wxflag & WX_TEXT) 3151 { 3152 /* Convert to multibyte in text mode */ 3153 char mbc[MB_LEN_MAX]; 3154 int mb_return; 3155 3156 mb_return = wctomb(mbc, c); 3157 3158 if(mb_return == -1) 3159 return WEOF; 3160 3161 /* Output all characters */ 3162 if (fwrite(mbc, mb_return, 1, stream) != 1) 3163 return WEOF; 3164 } 3165 else 3166 { 3167 if (fwrite(&c, sizeof(c), 1, stream) != 1) 3168 return WEOF; 3169 } 3170 3171 return c; 3172 } 3173 3174 /********************************************************************* 3175 * _fputwchar (MSVCRT.@) 3176 */ 3177 wint_t CDECL _fputwchar(wint_t wc) 3178 { 3179 return fputwc(wc, stdout); 3180 } 3181 3182 /********************************************************************* 3183 * _wfsopen (MSVCRT.@) 3184 */ 3185 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share) 3186 { 3187 FILE* file; 3188 int open_flags, stream_flags, fd; 3189 3190 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode)); 3191 3192 /* map mode string to open() flags. "man fopen" for possibilities. */ 3193 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) 3194 return NULL; 3195 3196 LOCK_FILES(); 3197 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE); 3198 if (fd < 0) 3199 file = NULL; 3200 else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags) 3201 != -1) 3202 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file); 3203 else if (file) 3204 { 3205 file->_flag = 0; 3206 file = NULL; 3207 } 3208 3209 TRACE(":got (%p)\n",file); 3210 if (fd >= 0 && !file) 3211 _close(fd); 3212 UNLOCK_FILES(); 3213 return file; 3214 } 3215 3216 /********************************************************************* 3217 * _fsopen (MSVCRT.@) 3218 */ 3219 FILE * CDECL _fsopen(const char *path, const char *mode, int share) 3220 { 3221 FILE *ret; 3222 wchar_t *pathW = NULL, *modeW = NULL; 3223 3224 if (path && !(pathW = msvcrt_wstrdupa(path))) { 3225 _invalid_parameter(NULL, NULL, NULL, 0, 0); 3226 *_errno() = EINVAL; 3227 return NULL; 3228 } 3229 if (mode && !(modeW = msvcrt_wstrdupa(mode))) 3230 { 3231 free(pathW); 3232 _invalid_parameter(NULL, NULL, NULL, 0, 0); 3233 *_errno() = EINVAL; 3234 return NULL; 3235 } 3236 3237 ret = _wfsopen(pathW, modeW, share); 3238 3239 free(pathW); 3240 free(modeW); 3241 return ret; 3242 } 3243 3244 /********************************************************************* 3245 * fopen (MSVCRT.@) 3246 */ 3247 FILE * CDECL fopen(const char *path, const char *mode) 3248 { 3249 return _fsopen( path, mode, _SH_DENYNO ); 3250 } 3251 3252 /********************************************************************* 3253 * fopen_s (MSVCRT.@) 3254 */ 3255 int CDECL fopen_s(FILE** pFile, 3256 const char *filename, const char *mode) 3257 { 3258 if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL; 3259 if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL; 3260 if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL; 3261 3262 *pFile = fopen(filename, mode); 3263 3264 if(!*pFile) 3265 return *_errno(); 3266 return 0; 3267 } 3268 3269 /********************************************************************* 3270 * _wfopen (MSVCRT.@) 3271 */ 3272 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode) 3273 { 3274 return _wfsopen( path, mode, _SH_DENYNO ); 3275 } 3276 3277 /********************************************************************* 3278 * _wfopen_s (MSVCRT.@) 3279 */ 3280 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename, 3281 const wchar_t *mode) 3282 { 3283 if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) || 3284 !MSVCRT_CHECK_PMT(mode != NULL)) { 3285 *_errno() = EINVAL; 3286 return EINVAL; 3287 } 3288 3289 *pFile = _wfopen(filename, mode); 3290 3291 if(!*pFile) 3292 return *_errno(); 3293 return 0; 3294 } 3295 3296 /* fputc calls _flsbuf which calls fputc */ 3297 int CDECL _flsbuf(int c, FILE* file); 3298 3299 /********************************************************************* 3300 * fputc (MSVCRT.@) 3301 */ 3302 int CDECL fputc(int c, FILE* file) 3303 { 3304 int res; 3305 3306 _lock_file(file); 3307 if(file->_cnt>0) { 3308 *file->_ptr++=c; 3309 file->_cnt--; 3310 if (c == '\n') 3311 { 3312 res = msvcrt_flush_buffer(file); 3313 _unlock_file(file); 3314 return res ? res : c; 3315 } 3316 else { 3317 _unlock_file(file); 3318 return c & 0xff; 3319 } 3320 } else { 3321 res = _flsbuf(c, file); 3322 _unlock_file(file); 3323 return res; 3324 } 3325 } 3326 3327 /********************************************************************* 3328 * _fputchar (MSVCRT.@) 3329 */ 3330 int CDECL _fputchar(int c) 3331 { 3332 return fputc(c, stdout); 3333 } 3334 3335 /********************************************************************* 3336 * fread (MSVCRT.@) 3337 */ 3338 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file) 3339 { 3340 size_t rcnt=size * nmemb; 3341 size_t read=0; 3342 size_t pread=0; 3343 3344 if(!rcnt) 3345 return 0; 3346 3347 _lock_file(file); 3348 3349 /* first buffered data */ 3350 if(file->_cnt>0) { 3351 int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt; 3352 memcpy(ptr, file->_ptr, pcnt); 3353 file->_cnt -= pcnt; 3354 file->_ptr += pcnt; 3355 read += pcnt ; 3356 rcnt -= pcnt ; 3357 ptr = (char*)ptr + pcnt; 3358 } else if(!(file->_flag & _IOREAD )) { 3359 if(file->_flag & _IORW) { 3360 file->_flag |= _IOREAD; 3361 } else { 3362 _unlock_file(file); 3363 return 0; 3364 } 3365 } 3366 3367 if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF))) 3368 msvcrt_alloc_buffer(file); 3369 3370 while(rcnt>0) 3371 { 3372 int i; 3373 if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) { 3374 file->_cnt = _read(file->_file, file->_base, file->_bufsiz); 3375 file->_ptr = file->_base; 3376 i = (file->_cnt<rcnt) ? file->_cnt : rcnt; 3377 /* If the buffer fill reaches eof but fread wouldn't, clear eof. */ 3378 if (i > 0 && i < file->_cnt) { 3379 get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF; 3380 file->_flag &= ~_IOEOF; 3381 } 3382 if (i > 0) { 3383 memcpy(ptr, file->_ptr, i); 3384 file->_cnt -= i; 3385 file->_ptr += i; 3386 } 3387 } else if (rcnt > INT_MAX) { 3388 i = _read(file->_file, ptr, INT_MAX); 3389 } else if (rcnt < BUFSIZ) { 3390 i = _read(file->_file, ptr, rcnt); 3391 } else { 3392 i = _read(file->_file, ptr, rcnt - BUFSIZ/2); 3393 } 3394 pread += i; 3395 rcnt -= i; 3396 ptr = (char *)ptr+i; 3397 /* expose feof condition in the flags 3398 * MFC tests file->_flag for feof, and doesn't call feof()) 3399 */ 3400 if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF) 3401 file->_flag |= _IOEOF; 3402 else if (i == -1) 3403 { 3404 file->_flag |= _IOERR; 3405 pread = 0; 3406 rcnt = 0; 3407 } 3408 if (i < 1) break; 3409 } 3410 read+=pread; 3411 _unlock_file(file); 3412 return read / size; 3413 } 3414 3415 /********************************************************************* 3416 * _wfreopen (MSVCRT.@) 3417 * 3418 */ 3419 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file) 3420 { 3421 int open_flags, stream_flags, fd; 3422 3423 TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1); 3424 3425 LOCK_FILES(); 3426 if (!file || ((fd = file->_file) < 0)) 3427 file = NULL; 3428 else 3429 { 3430 fclose(file); 3431 /* map mode string to open() flags. "man fopen" for possibilities. */ 3432 if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) 3433 file = NULL; 3434 else 3435 { 3436 fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE); 3437 if (fd < 0) 3438 file = NULL; 3439 else if (msvcrt_init_fp(file, fd, stream_flags) == -1) 3440 { 3441 file->_flag = 0; 3442 WARN(":failed-last error (%d)\n",GetLastError()); 3443 _dosmaperr(GetLastError()); 3444 file = NULL; 3445 } 3446 } 3447 } 3448 UNLOCK_FILES(); 3449 return file; 3450 } 3451 3452 /********************************************************************* 3453 * freopen (MSVCRT.@) 3454 * 3455 */ 3456 FILE* CDECL freopen(const char *path, const char *mode, FILE* file) 3457 { 3458 FILE *ret; 3459 wchar_t *pathW = NULL, *modeW = NULL; 3460 3461 if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL; 3462 if (mode && !(modeW = msvcrt_wstrdupa(mode))) 3463 { 3464 free(pathW); 3465 return NULL; 3466 } 3467 3468 ret = _wfreopen(pathW, modeW, file); 3469 3470 free(pathW); 3471 free(modeW); 3472 return ret; 3473 } 3474 3475 /********************************************************************* 3476 * fsetpos (MSVCRT.@) 3477 */ 3478 int CDECL fsetpos(FILE* file, const fpos_t *pos) 3479 { 3480 int ret; 3481 3482 _lock_file(file); 3483 /* Note that all this has been lifted 'as is' from fseek */ 3484 if(file->_flag & _IOWRT) 3485 msvcrt_flush_buffer(file); 3486 3487 /* Discard buffered input */ 3488 file->_cnt = 0; 3489 file->_ptr = file->_base; 3490 3491 /* Reset direction of i/o */ 3492 if(file->_flag & _IORW) { 3493 file->_flag &= ~(_IOREAD|_IOWRT); 3494 } 3495 3496 ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0; 3497 _unlock_file(file); 3498 return ret; 3499 } 3500 3501 /********************************************************************* 3502 * _ftelli64 (MSVCRT.@) 3503 */ 3504 __int64 CDECL _ftelli64(FILE* file) 3505 { 3506 __int64 pos; 3507 3508 _lock_file(file); 3509 pos = _telli64(file->_file); 3510 if(pos == -1) { 3511 _unlock_file(file); 3512 return -1; 3513 } 3514 if(file->_flag & (_IOMYBUF | _USERBUF)) { 3515 if(file->_flag & _IOWRT) { 3516 pos += file->_ptr - file->_base; 3517 3518 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) { 3519 char *p; 3520 3521 for(p=file->_base; p<file->_ptr; p++) 3522 if(*p == '\n') 3523 pos++; 3524 } 3525 } else if(!file->_cnt) { /* nothing to do */ 3526 } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) { 3527 int i; 3528 3529 pos -= file->_cnt; 3530 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) { 3531 for(i=0; i<file->_cnt; i++) 3532 if(file->_ptr[i] == '\n') 3533 pos--; 3534 } 3535 } else { 3536 char *p; 3537 3538 if(_lseeki64(file->_file, pos, SEEK_SET) != pos) { 3539 _unlock_file(file); 3540 return -1; 3541 } 3542 3543 pos -= file->_bufsiz; 3544 pos += file->_ptr - file->_base; 3545 3546 if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) { 3547 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL) 3548 pos--; 3549 3550 for(p=file->_base; p<file->_ptr; p++) 3551 if(*p == '\n') 3552 pos++; 3553 } 3554 } 3555 } 3556 3557 _unlock_file(file); 3558 return pos; 3559 } 3560 3561 /********************************************************************* 3562 * ftell (MSVCRT.@) 3563 */ 3564 LONG CDECL ftell(FILE* file) 3565 { 3566 return (LONG)_ftelli64(file); 3567 } 3568 3569 /********************************************************************* 3570 * fgetpos (MSVCRT.@) 3571 */ 3572 int CDECL fgetpos(FILE* file, fpos_t *pos) 3573 { 3574 *pos = _ftelli64(file); 3575 if(*pos == -1) 3576 return -1; 3577 return 0; 3578 } 3579 3580 /********************************************************************* 3581 * fputs (MSVCRT.@) 3582 */ 3583 int CDECL fputs(const char *s, FILE* file) 3584 { 3585 size_t len = strlen(s); 3586 int ret; 3587 3588 _lock_file(file); 3589 ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF; 3590 _unlock_file(file); 3591 return ret; 3592 } 3593 3594 /********************************************************************* 3595 * fputws (MSVCRT.@) 3596 */ 3597 int CDECL fputws(const wchar_t *s, FILE* file) 3598 { 3599 size_t i, len = strlenW(s); 3600 BOOL tmp_buf; 3601 int ret; 3602 3603 _lock_file(file); 3604 if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) { 3605 ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF; 3606 _unlock_file(file); 3607 return ret; 3608 } 3609 3610 tmp_buf = add_std_buffer(file); 3611 for (i=0; i<len; i++) { 3612 if(fputwc(s[i], file) == WEOF) { 3613 if(tmp_buf) remove_std_buffer(file); 3614 _unlock_file(file); 3615 return WEOF; 3616 } 3617 } 3618 3619 if(tmp_buf) remove_std_buffer(file); 3620 _unlock_file(file); 3621 return 0; 3622 } 3623 3624 /********************************************************************* 3625 * getchar (MSVCRT.@) 3626 */ 3627 int CDECL getchar(void) 3628 { 3629 return fgetc(stdin); 3630 } 3631 3632 /********************************************************************* 3633 * getc (MSVCRT.@) 3634 */ 3635 int CDECL getc(FILE* file) 3636 { 3637 return fgetc(file); 3638 } 3639 3640 /********************************************************************* 3641 * gets (MSVCRT.@) 3642 */ 3643 char * CDECL gets(char *buf) 3644 { 3645 int cc; 3646 char * buf_start = buf; 3647 3648 _lock_file(stdin); 3649 for(cc = fgetc(stdin); cc != EOF && cc != '\n'; 3650 cc = fgetc(stdin)) 3651 if(cc != '\r') *buf++ = (char)cc; 3652 3653 *buf = '\0'; 3654 3655 TRACE("got '%s'\n", buf_start); 3656 _unlock_file(stdin); 3657 return buf_start; 3658 } 3659 3660 /********************************************************************* 3661 * _getws (MSVCRT.@) 3662 */ 3663 wchar_t* CDECL _getws(wchar_t* buf) 3664 { 3665 wint_t cc; 3666 wchar_t* ws = buf; 3667 3668 _lock_file(stdin); 3669 for (cc = fgetwc(stdin); cc != WEOF && cc != '\n'; 3670 cc = fgetwc(stdin)) 3671 { 3672 if (cc != '\r') 3673 *buf++ = (wchar_t)cc; 3674 } 3675 *buf = '\0'; 3676 3677 TRACE("got %s\n", debugstr_w(ws)); 3678 _unlock_file(stdin); 3679 return ws; 3680 } 3681 3682 /********************************************************************* 3683 * putc (MSVCRT.@) 3684 */ 3685 int CDECL putc(int c, FILE* file) 3686 { 3687 return fputc(c, file); 3688 } 3689 3690 /********************************************************************* 3691 * putchar (MSVCRT.@) 3692 */ 3693 int CDECL putchar(int c) 3694 { 3695 return fputc(c, stdout); 3696 } 3697 3698 /********************************************************************* 3699 * _putwch (MSVCRT.@) 3700 */ 3701 wint_t CDECL _putwch(wchar_t c) 3702 { 3703 return fputwc(c, stdout); 3704 } 3705 3706 /********************************************************************* 3707 * puts (MSVCRT.@) 3708 */ 3709 int CDECL puts(const char *s) 3710 { 3711 size_t len = strlen(s); 3712 int ret; 3713 3714 _lock_file(stdout); 3715 if(fwrite(s, sizeof(*s), len, stdout) != len) { 3716 _unlock_file(stdout); 3717 return EOF; 3718 } 3719 3720 ret = fwrite("\n",1,1,stdout) == 1 ? 0 : EOF; 3721 _unlock_file(stdout); 3722 return ret; 3723 } 3724 3725 /********************************************************************* 3726 * _putws (MSVCRT.@) 3727 */ 3728 int CDECL _putws(const wchar_t *s) 3729 { 3730 static const wchar_t nl = '\n'; 3731 size_t len = strlenW(s); 3732 int ret; 3733 3734 _lock_file(stdout); 3735 if(fwrite(s, sizeof(*s), len, stdout) != len) { 3736 _unlock_file(stdout); 3737 return EOF; 3738 } 3739 3740 ret = fwrite(&nl,sizeof(nl),1,stdout) == 1 ? 0 : EOF; 3741 _unlock_file(stdout); 3742 return ret; 3743 } 3744 3745 /********************************************************************* 3746 * remove (MSVCRT.@) 3747 */ 3748 int CDECL remove(const char *path) 3749 { 3750 TRACE("(%s)\n",path); 3751 if (DeleteFileA(path)) 3752 return 0; 3753 TRACE(":failed (%d)\n",GetLastError()); 3754 _dosmaperr(GetLastError()); 3755 return -1; 3756 } 3757 3758 /********************************************************************* 3759 * _wremove (MSVCRT.@) 3760 */ 3761 int CDECL _wremove(const wchar_t *path) 3762 { 3763 TRACE("(%s)\n",debugstr_w(path)); 3764 if (DeleteFileW(path)) 3765 return 0; 3766 TRACE(":failed (%d)\n",GetLastError()); 3767 _dosmaperr(GetLastError()); 3768 return -1; 3769 } 3770 3771 /********************************************************************* 3772 * rename (MSVCRT.@) 3773 */ 3774 int CDECL rename(const char *oldpath,const char *newpath) 3775 { 3776 TRACE(":from %s to %s\n",oldpath,newpath); 3777 if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED)) 3778 return 0; 3779 TRACE(":failed (%d)\n",GetLastError()); 3780 _dosmaperr(GetLastError()); 3781 return -1; 3782 } 3783 3784 /********************************************************************* 3785 * _wrename (MSVCRT.@) 3786 */ 3787 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath) 3788 { 3789 TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath)); 3790 if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED)) 3791 return 0; 3792 TRACE(":failed (%d)\n",GetLastError()); 3793 _dosmaperr(GetLastError()); 3794 return -1; 3795 } 3796 3797 /********************************************************************* 3798 * setvbuf (MSVCRT.@) 3799 */ 3800 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size) 3801 { 3802 if(!MSVCRT_CHECK_PMT(file != NULL)) return -1; 3803 if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1; 3804 if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1; 3805 3806 _lock_file(file); 3807 3808 fflush(file); 3809 if(file->_flag & _IOMYBUF) 3810 free(file->_base); 3811 file->_flag &= ~(_IONBF | _IOMYBUF | _USERBUF); 3812 file->_cnt = 0; 3813 3814 if(mode == _IONBF) { 3815 file->_flag |= _IONBF; 3816 file->_base = file->_ptr = (char*)&file->_charbuf; 3817 file->_bufsiz = 2; 3818 }else if(buf) { 3819 file->_base = file->_ptr = buf; 3820 file->_flag |= _USERBUF; 3821 file->_bufsiz = size; 3822 }else { 3823 file->_base = file->_ptr = malloc(size); 3824 if(!file->_base) { 3825 file->_bufsiz = 0; 3826 _unlock_file(file); 3827 return -1; 3828 } 3829 3830 file->_flag |= _IOMYBUF; 3831 file->_bufsiz = size; 3832 } 3833 _unlock_file(file); 3834 return 0; 3835 } 3836 3837 /********************************************************************* 3838 * setbuf (MSVCRT.@) 3839 */ 3840 void CDECL setbuf(FILE* file, char *buf) 3841 { 3842 setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ); 3843 } 3844 3845 /********************************************************************* 3846 * tmpnam (MSVCRT.@) 3847 */ 3848 char * CDECL tmpnam(char *s) 3849 { 3850 char tmpstr[16]; 3851 char *p; 3852 int count, size; 3853 3854 if (!s) { 3855 thread_data_t *data = msvcrt_get_thread_data(); 3856 3857 if(!data->tmpnam_buffer) 3858 data->tmpnam_buffer = malloc(MAX_PATH); 3859 3860 s = data->tmpnam_buffer; 3861 } 3862 3863 msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr); 3864 p = s + sprintf(s, "\\s%s.", tmpstr); 3865 for (count = 0; count < TMP_MAX; count++) 3866 { 3867 size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr); 3868 memcpy(p, tmpstr, size); 3869 p[size] = '\0'; 3870 if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES && 3871 GetLastError() == ERROR_FILE_NOT_FOUND) 3872 break; 3873 } 3874 return s; 3875 } 3876 3877 /********************************************************************* 3878 * _wtmpnam (MSVCRT.@) 3879 */ 3880 wchar_t * CDECL _wtmpnam(wchar_t *s) 3881 { 3882 static const wchar_t format[] = {'\\','s','%','s','.',0}; 3883 wchar_t tmpstr[16]; 3884 wchar_t *p; 3885 int count, size; 3886 if (!s) { 3887 thread_data_t *data = msvcrt_get_thread_data(); 3888 3889 if(!data->wtmpnam_buffer) 3890 data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH])); 3891 3892 s = data->wtmpnam_buffer; 3893 } 3894 3895 msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr); 3896 p = s + _snwprintf(s, MAX_PATH, format, tmpstr); 3897 for (count = 0; count < TMP_MAX; count++) 3898 { 3899 size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr); 3900 memcpy(p, tmpstr, size*sizeof(wchar_t)); 3901 p[size] = '\0'; 3902 if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES && 3903 GetLastError() == ERROR_FILE_NOT_FOUND) 3904 break; 3905 } 3906 return s; 3907 } 3908 3909 /********************************************************************* 3910 * tmpfile (MSVCRT.@) 3911 */ 3912 FILE* CDECL tmpfile(void) 3913 { 3914 char *filename = tmpnam(NULL); 3915 int fd; 3916 FILE* file = NULL; 3917 3918 LOCK_FILES(); 3919 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY, 3920 _S_IREAD | _S_IWRITE); 3921 if (fd != -1 && (file = msvcrt_alloc_fp())) 3922 { 3923 if (msvcrt_init_fp(file, fd, _IORW) == -1) 3924 { 3925 file->_flag = 0; 3926 file = NULL; 3927 } 3928 else file->_tmpfname = _strdup(filename); 3929 } 3930 3931 if(fd != -1 && !file) 3932 _close(fd); 3933 UNLOCK_FILES(); 3934 return file; 3935 } 3936 3937 /********************************************************************* 3938 * ungetc (MSVCRT.@) 3939 */ 3940 int CDECL ungetc(int c, FILE * file) 3941 { 3942 if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF; 3943 3944 if (c == EOF || !(file->_flag&_IOREAD || 3945 (file->_flag&_IORW && !(file->_flag&_IOWRT)))) 3946 return EOF; 3947 3948 _lock_file(file); 3949 if((!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)) 3950 && msvcrt_alloc_buffer(file)) 3951 || (!file->_cnt && file->_ptr==file->_base)) 3952 file->_ptr++; 3953 3954 if(file->_ptr>file->_base) { 3955 file->_ptr--; 3956 if(file->_flag & _IOSTRG) { 3957 if(*file->_ptr != c) { 3958 file->_ptr++; 3959 _unlock_file(file); 3960 return EOF; 3961 } 3962 }else { 3963 *file->_ptr = c; 3964 } 3965 file->_cnt++; 3966 clearerr(file); 3967 file->_flag |= _IOREAD; 3968 _unlock_file(file); 3969 return c; 3970 } 3971 3972 _unlock_file(file); 3973 return EOF; 3974 } 3975 3976 /********************************************************************* 3977 * ungetwc (MSVCRT.@) 3978 */ 3979 wint_t CDECL ungetwc(wint_t wc, FILE * file) 3980 { 3981 wchar_t mwc = wc; 3982 3983 if (wc == WEOF) 3984 return WEOF; 3985 3986 _lock_file(file); 3987 3988 if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16)) 3989 || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) { 3990 unsigned char * pp = (unsigned char *)&mwc; 3991 int i; 3992 3993 for(i=sizeof(wchar_t)-1;i>=0;i--) { 3994 if(pp[i] != ungetc(pp[i],file)) { 3995 _unlock_file(file); 3996 return WEOF; 3997 } 3998 } 3999 }else { 4000 char mbs[MB_LEN_MAX]; 4001 int len; 4002 4003 len = wctomb(mbs, mwc); 4004 if(len == -1) { 4005 _unlock_file(file); 4006 return WEOF; 4007 } 4008 4009 for(len--; len>=0; len--) { 4010 if(mbs[len] != ungetc(mbs[len], file)) { 4011 _unlock_file(file); 4012 return WEOF; 4013 } 4014 } 4015 } 4016 4017 _unlock_file(file); 4018 return mwc; 4019 } 4020 4021 4022 4023 /********************************************************************* 4024 * _getmaxstdio (MSVCRT.@) 4025 */ 4026 int CDECL _getmaxstdio(void) 4027 { 4028 return MSVCRT_max_streams; 4029 } 4030 4031 /********************************************************************* 4032 * _setmaxstdio (MSVCRT.@) 4033 */ 4034 int CDECL _setmaxstdio(int newmax) 4035 { 4036 TRACE("%d\n", newmax); 4037 4038 if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx) 4039 return -1; 4040 4041 MSVCRT_max_streams = newmax; 4042 return MSVCRT_max_streams; 4043 } 4044