source: trunk/src/crtdll/file.c@ 6645

Last change on this file since 6645 was 6645, checked in by bird, 24 years ago

Added $Id:$ keyword.

File size: 41.5 KB
Line 
1/* $Id: file.c,v 1.3 2001-09-05 12:14:24 bird Exp $ */
2/*
3 * CRTDLL file functions
4 *
5 * Copyright 1996,1998 Marcus Meissner
6 * Copyright 1996 Jukka Iivonen
7 * Copyright 1997,2000 Uwe Bonnes
8 * Copyright 2000 Jon Griffiths
9 *
10 * Implementation Notes:
11 * Mapping is performed between FILE*, fd and HANDLE's. This allows us to
12 * implement all calls using the Win32 API, support remapping fd's to
13 * FILES and do some other tricks as well (like closeall, _get_osfhandle).
14 * For mix and matching with the host libc, processes can use the Win32 HANDLE
15 * to get a real unix fd from the wineserver. Or we could do this once
16 * on create, and provide a function to return it quickly (store it
17 * in the mapping table). Note that If you actuall _do_ this, you should
18 * call rewind() before using any other crt functions on the file. To avoid
19 * the confusion I got when reading the API docs, fd is always refered
20 * to as a file descriptor here. In the API docs its called a file handle
21 * which is confusing with Win32 HANDLES.
22 * M$ CRT includes inline versions of some of these functions (like feof()).
23 * These inlines check/modify bitfields in the FILE structure, so we set
24 * _flags/_file/_cnt in the FILE* to be binary compatable with the win dll.
25 * lcc defines _IOAPPEND as one of the flags for a FILE*, but testing shows
26 * that M$ CRT never sets it. So we keep the flag in our mapping table but
27 * mask it out when we populate a FILE* with it. Then when we write we seek
28 * to EOF if _IOAPPEND is set for the underlying fd.
29 *
30 * FIXME:
31 * Not MT safe. Need locking around file access and allocation for this.
32 * NT has no effective limit on files - neither should we. This will be fixed
33 * with dynamic allocation of the file mapping array.
34 * Buffering is handled differently. Have to investigate a) how much control
35 * we have over buffering in win32, and b) if we care ;-)
36 */
37
38#include <odin.h>
39
40#include "crtdll.h"
41#include <stdarg.h>
42#include <string.h>
43#include <ctype.h>
44#include <errno.h>
45#include "ntddk.h"
46
47DEFAULT_DEBUG_CHANNEL(crtdll);
48
49/* FIXME: Make this dynamic */
50#define CRTDLL_MAX_FILES 257
51
52HANDLE __CRTDLL_handles[CRTDLL_MAX_FILES];
53CRTDLL_FILE* __CRTDLL_files[CRTDLL_MAX_FILES];
54INT __CRTDLL_flags[CRTDLL_MAX_FILES];
55CRTDLL_FILE __CRTDLL_iob[3];
56
57static int __CRTDLL_fdstart = 3; /* first unallocated fd */
58static int __CRTDLL_fdend = 3; /* highest allocated fd */
59
60/* INTERNAL: process umask */
61static INT __CRTDLL_umask = 0;
62
63/* INTERNAL: Static buffer for temp file name */
64static char CRTDLL_tmpname[MAX_PATH];
65
66/* file extentions recognised as executables */
67static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
68static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
69static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
70static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
71
72/* for stat mode, permissions apply to all,owner and group */
73#define CRTDLL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
74#define CRTDLL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
75#define CRTDLL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
76
77
78/* INTERNAL: Get the HANDLE for a fd */
79static HANDLE __CRTDLL__fdtoh(INT fd);
80static HANDLE __CRTDLL__fdtoh(INT fd)
81{
82 if (fd < 0 || fd >= __CRTDLL_fdend ||
83 __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE)
84 {
85 WARN(":fd (%d) - no handle!\n",fd);
86 CRTDLL_doserrno = 0;
87 CRTDLL_errno = EBADF;
88 return INVALID_HANDLE_VALUE;
89 }
90 return __CRTDLL_handles[fd];
91}
92
93
94/* INTERNAL: free a file entry fd */
95static void __CRTDLL__free_fd(INT fd);
96static void __CRTDLL__free_fd(INT fd)
97{
98 __CRTDLL_handles[fd] = INVALID_HANDLE_VALUE;
99 __CRTDLL_files[fd] = 0;
100 __CRTDLL_flags[fd] = 0;
101 TRACE(":fd (%d) freed\n",fd);
102 if (fd < 3)
103 return; /* dont use 0,1,2 for user files */
104 if (fd == __CRTDLL_fdend - 1)
105 __CRTDLL_fdend--;
106 if (fd < __CRTDLL_fdstart)
107 __CRTDLL_fdstart = fd;
108}
109
110
111/* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
112static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag);
113static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag)
114{
115 INT fd = __CRTDLL_fdstart;
116
117 TRACE(":handle (%d) allocating fd (%d)\n",hand,fd);
118 if (fd >= CRTDLL_MAX_FILES)
119 {
120 WARN(":files exhausted!\n");
121 return -1;
122 }
123 __CRTDLL_handles[fd] = hand;
124 __CRTDLL_flags[fd] = flag;
125
126 /* locate next free slot */
127 if (fd == __CRTDLL_fdend)
128 __CRTDLL_fdstart = ++__CRTDLL_fdend;
129 else
130 while(__CRTDLL_fdstart < __CRTDLL_fdend &&
131 __CRTDLL_handles[__CRTDLL_fdstart] != INVALID_HANDLE_VALUE)
132 __CRTDLL_fdstart++;
133
134 return fd;
135}
136
137
138/* INTERNAL: Allocate a FILE* for an fd slot
139 * This is done lazily to avoid memory wastage for low level open/write
140 * usage when a FILE* is not requested (but may be later).
141 */
142static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd);
143static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd)
144{
145 TRACE(":fd (%d) allocating FILE*\n",fd);
146 if (fd < 0 || fd >= __CRTDLL_fdend ||
147 __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE)
148 {
149 WARN(":invalid fd %d\n",fd);
150 CRTDLL_doserrno = 0;
151 CRTDLL_errno = EBADF;
152 return NULL;
153 }
154 if (!__CRTDLL_files[fd])
155 {
156 if ((__CRTDLL_files[fd] = CRTDLL_calloc(sizeof(CRTDLL_FILE),1)))
157 {
158 __CRTDLL_files[fd]->_file = fd;
159 __CRTDLL_files[fd]->_flag = __CRTDLL_flags[fd];
160 __CRTDLL_files[fd]->_flag &= ~_IOAPPEND; /* mask out, see above */
161 }
162 }
163 TRACE(":got FILE* (%p)\n",__CRTDLL_files[fd]);
164 return __CRTDLL_files[fd];
165}
166
167
168/* INTERNAL: Set up stdin, stderr and stdout */
169VOID __CRTDLL__init_io(VOID)
170{
171 int i;
172 memset(__CRTDLL_iob,0,3*sizeof(CRTDLL_FILE));
173 __CRTDLL_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
174 __CRTDLL_flags[0] = __CRTDLL_iob[0]._flag = _IOREAD;
175 __CRTDLL_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
176 __CRTDLL_flags[1] = __CRTDLL_iob[1]._flag = _IOWRT;
177 __CRTDLL_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
178 __CRTDLL_flags[2] = __CRTDLL_iob[2]._flag = _IOWRT;
179
180 TRACE(":handles (%d)(%d)(%d)\n",__CRTDLL_handles[0],
181 __CRTDLL_handles[1],__CRTDLL_handles[2]);
182
183 for (i = 0; i < 3; i++)
184 {
185 /* FILE structs for stdin/out/err are static and never deleted */
186 __CRTDLL_files[i] = &__CRTDLL_iob[i];
187 __CRTDLL_iob[i]._file = i;
188 }
189}
190
191
192/*********************************************************************
193 * _access (CRTDLL.37)
194 */
195INT CDECL CRTDLL__access(LPCSTR filename, INT mode)
196{
197 // return (_access(path, mode));
198
199 DWORD attr = GetFileAttributesA(filename);
200
201 if (attr == -1)
202 {
203 if (!filename)
204 {
205 /* FIXME: Should GetFileAttributesA() return this? */
206 __CRTDLL__set_errno(ERROR_INVALID_DATA);
207 return -1;
208 }
209 __CRTDLL__set_errno(GetLastError());
210 return -1;
211 }
212 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
213 {
214 __CRTDLL__set_errno(ERROR_ACCESS_DENIED);
215 return -1;
216 }
217 TRACE(":file %s, mode (%d) ok\n",filename,mode);
218 return 0;
219}
220
221
222/*********************************************************************
223 * _close (CRTDLL.57)
224 *
225 * Close an open file descriptor.
226 */
227INT CDECL CRTDLL__close(INT fd)
228{
229 HANDLE hand = __CRTDLL__fdtoh(fd);
230
231 TRACE(":fd (%d) handle (%d)\n",fd,hand);
232 if (hand == INVALID_HANDLE_VALUE)
233 return -1;
234
235 /* Dont free std FILE*'s, they are not dynamic */
236 if (fd > 2 && __CRTDLL_files[fd])
237 CRTDLL_free(__CRTDLL_files[fd]);
238
239 __CRTDLL__free_fd(fd);
240
241 if (!CloseHandle(hand))
242 {
243 WARN(":failed-last error (%ld)\n",GetLastError());
244 __CRTDLL__set_errno(GetLastError());
245 return -1;
246 }
247 TRACE(":ok\n");
248 return 0;
249}
250
251
252/*********************************************************************
253 * _commit (CRTDLL.58)
254 *
255 * Ensure all file operations have been flushed to the drive.
256 */
257INT CDECL CRTDLL__commit(INT fd)
258{
259 HANDLE hand = __CRTDLL__fdtoh(fd);
260
261 TRACE(":fd (%d) handle (%d)\n",fd,hand);
262 if (hand == INVALID_HANDLE_VALUE)
263 return -1;
264
265 if (!FlushFileBuffers(hand))
266 {
267 if (GetLastError() == ERROR_INVALID_HANDLE)
268 {
269 /* FlushFileBuffers fails for console handles
270 * so we ignore this error.
271 */
272 return 0;
273 }
274 TRACE(":failed-last error (%ld)\n",GetLastError());
275 __CRTDLL__set_errno(GetLastError());
276 return -1;
277 }
278 TRACE(":ok\n");
279 return 0;
280}
281
282
283/*********************************************************************
284 * _creat (CRTDLL.066)
285 *
286 * Open a file, creating it if it is not present.
287 */
288INT CDECL CRTDLL__creat(LPCSTR path, INT flags)
289{
290 // return (_creat(s, i));
291
292 INT usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
293 return CRTDLL__open(path, usedFlags);
294}
295
296
297/*********************************************************************
298 * _eof (CRTDLL.076)
299 *
300 * Determine if the file pointer is at the end of a file.
301 */
302/* FIXME: Care for large files */
303INT CDECL CRTDLL__eof( INT fd )
304{
305 // return (__eof(_fd));
306
307 DWORD curpos,endpos;
308 HANDLE hand = __CRTDLL__fdtoh(fd);
309
310 TRACE(":fd (%d) handle (%d)\n",fd,hand);
311
312 if (hand == INVALID_HANDLE_VALUE)
313 return -1;
314
315 /* If we have a FILE* for this file, the EOF flag
316 * will be set by the read()/write() functions.
317 */
318 if (__CRTDLL_files[fd])
319 return __CRTDLL_files[fd]->_flag & _IOEOF;
320
321 /* Otherwise we do it the hard way */
322 curpos = SetFilePointer( hand, 0, NULL, SEEK_CUR );
323 endpos = SetFilePointer( hand, 0, NULL, FILE_END );
324
325 if (curpos == endpos)
326 return TRUE;
327
328 SetFilePointer( hand, curpos, 0, FILE_BEGIN);
329 return FALSE;
330}
331
332
333/*********************************************************************
334 * _fcloseall (CRTDLL.089)
335 *
336 * Close all open files except stdin/stdout/stderr.
337 */
338INT CDECL CRTDLL__fcloseall(VOID)
339{
340 // return (_fcloseall());
341
342 int num_closed = 0, i = 3;
343
344 while(i < __CRTDLL_fdend)
345 if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE)
346 {
347 CRTDLL__close(i);
348 num_closed++;
349 }
350
351 TRACE(":closed (%d) handles\n",num_closed);
352 return num_closed;
353}
354
355
356/*********************************************************************
357 * _fdopen (CRTDLL.091)
358 *
359 * Get a FILE* from a low level file descriptor.
360 */
361CRTDLL_FILE* CDECL CRTDLL__fdopen(INT fd, LPCSTR mode)
362{
363 // return (_fdopen(handle, mode));
364
365 CRTDLL_FILE* file = __CRTDLL__alloc_fp(fd);
366
367 TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file);
368 if (file)
369 CRTDLL_rewind(file);
370
371 return file;
372}
373
374
375/*********************************************************************
376 * _fgetchar (CRTDLL.092)
377 */
378INT CDECL CRTDLL__fgetchar( VOID )
379{
380 // return (_fgetchar());
381
382 return CRTDLL_fgetc(CRTDLL_stdin);
383}
384
385
386/*********************************************************************
387 * _filbuf (CRTDLL.094)
388 *
389 * NOTES
390 * The macro version of getc calls this function whenever FILE->_cnt
391 * becomes negative. We ensure that _cnt is always 0 after any read
392 * so this function is always called. Our implementation simply calls
393 * fgetc as all the underlying buffering is handled by Wines
394 * implementation of the Win32 file I/O calls.
395 */
396INT CDECL CRTDLL__filbuf(CRTDLL_FILE* file)
397{
398 return CRTDLL_fgetc(file);
399}
400
401
402/*********************************************************************
403 * _fileno (CRTDLL.097)
404 *
405 * Get the file descriptor from a FILE*.
406 *
407 * NOTES
408 * This returns the CRTDLL fd, _not_ the underlying *nix fd.
409 */
410INT CDECL CRTDLL__fileno(CRTDLL_FILE* file)
411{
412 // return (_fileno(f));
413
414 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
415 return file->_file;
416}
417
418
419/*********************************************************************
420 * _flsbuf (CRTDLL.102)
421 *
422 * NOTES
423 * The macro version of putc calls this function whenever FILE->_cnt
424 * becomes negative. We ensure that _cnt is always 0 after any write
425 * so this function is always called. Our implementation simply calls
426 * fputc as all the underlying buffering is handled by Wines
427 * implementation of the Win32 file I/O calls.
428 */
429INT CDECL CRTDLL__flsbuf(INT c, CRTDLL_FILE* file)
430{
431 return CRTDLL_fputc(c,file);
432}
433
434
435/*********************************************************************
436 * _flushall (CRTDLL.103)
437 *
438 * Flush all open files.
439 */
440INT CDECL CRTDLL__flushall(VOID)
441{
442 // return (_flushall());
443
444 int num_flushed = 0, i = 3;
445
446 while(i < __CRTDLL_fdend)
447 if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE)
448 {
449 if (CRTDLL__commit(i) == -1)
450 if (__CRTDLL_files[i])
451 __CRTDLL_files[i]->_flag |= _IOERR;
452 num_flushed++;
453 }
454
455 TRACE(":flushed (%d) handles\n",num_flushed);
456 return num_flushed;
457}
458
459
460/*********************************************************************
461 * _fputchar (CRTDLL.108)
462 *
463 * Put a character to a file.
464 */
465INT CDECL CRTDLL__fputchar(INT c)
466{
467 // return(_fputchar(c));
468
469 return CRTDLL_fputc(c, CRTDLL_stdout);
470}
471
472
473/*********************************************************************
474 * _fsopen (CRTDLL.110)
475 *
476 * Open a FILE* with sharing.
477 */
478CRTDLL_FILE* CDECL CRTDLL__fsopen(LPCSTR path, LPCSTR mode, INT share)
479{
480 FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share);
481 return CRTDLL_fopen(path,mode);
482}
483
484
485/*********************************************************************
486 * _fstat (CRTDLL.111)
487 *
488 * Get information about an open file.
489 */
490int CDECL CRTDLL__fstat(int fd, struct _stat* buf)
491{
492 // return (_fstat(file, buf));
493
494 DWORD dw;
495 BY_HANDLE_FILE_INFORMATION hfi;
496 HANDLE hand = __CRTDLL__fdtoh(fd);
497
498 TRACE(":fd (%d) stat (%p)\n",fd,buf);
499 if (hand == INVALID_HANDLE_VALUE)
500 return -1;
501
502 if (!buf)
503 {
504 WARN(":failed-NULL buf\n");
505 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER);
506 return -1;
507 }
508
509 memset(&hfi, 0, sizeof(hfi));
510 memset(buf, 0, sizeof(struct _stat));
511 if (!GetFileInformationByHandle(hand, &hfi))
512 {
513 WARN(":failed-last error (%ld)\n",GetLastError());
514 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER);
515 return -1;
516 }
517 FIXME(":dwFileAttributes = %d, mode set to 0",hfi.dwFileAttributes);
518 buf->st_nlink = hfi.nNumberOfLinks;
519 buf->st_size = hfi.nFileSizeLow;
520 RtlTimeToSecondsSince1970( &hfi.ftLastAccessTime, &dw );
521 buf->st_atime = dw;
522 RtlTimeToSecondsSince1970( &hfi.ftLastWriteTime, &dw );
523 buf->st_mtime = buf->st_ctime = dw;
524 return 0;
525}
526
527
528/*********************************************************************
529 * _get_osfhandle (CRTDLL.117)
530 *
531 * Return a Win32 HANDLE from a file descriptor.
532 *
533 * PARAMS
534 * fd [in] A valid file descriptor
535 *
536 * RETURNS
537 * Success: A Win32 HANDLE
538 *
539 * Failure: INVALID_HANDLE_VALUE.
540 *
541 */
542HANDLE CRTDLL__get_osfhandle(INT fd)
543{
544 HANDLE hand = __CRTDLL__fdtoh(fd);
545 HANDLE newhand = hand;
546 TRACE(":fd (%d) handle (%d)\n",fd,hand);
547
548 if (hand != INVALID_HANDLE_VALUE)
549 {
550 /* FIXME: I'm not convinced that I should be copying the
551 * handle here - it may be leaked if the app doesn't
552 * close it (and the API docs dont say that it should)
553 * Not duplicating it means that it can't be inherited
554 * and so lcc's wedit doesn't cope when it passes it to
555 * child processes. I've an idea that it should either
556 * be copied by CreateProcess, or marked as inheritable
557 * when initialised, or maybe both? JG 21-9-00.
558 */
559 DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(),
560 &newhand,0,TRUE,DUPLICATE_SAME_ACCESS );
561 }
562 return newhand;
563}
564
565
566/*********************************************************************
567 * _isatty (CRTDLL.137)
568 *
569 * Return non zero if fd is a character device (e.g console).
570 */
571INT CDECL CRTDLL__isatty(INT fd)
572{
573 HANDLE hand = __CRTDLL__fdtoh(fd);
574
575 TRACE(":fd (%d) handle (%d)\n",fd,hand);
576 if (hand == INVALID_HANDLE_VALUE)
577 return 0;
578
579 return GetFileType(fd) == FILE_TYPE_CHAR? 1 : 0;
580}
581
582
583/*********************************************************************
584 * _lseek (CRTDLL.179)
585 *
586 * Move the file pointer within a file.
587 */
588LONG CDECL CRTDLL__lseek( INT fd, LONG offset, INT whence)
589{
590 // return (_lseek(handle, offset, origin));
591
592 LONG ret;
593 HANDLE hand = __CRTDLL__fdtoh(fd);
594
595 TRACE(":fd (%d) handle (%d)\n",fd,hand);
596 if (hand == INVALID_HANDLE_VALUE)
597 return -1;
598
599 if (whence < 0 || whence > 2)
600 {
601 CRTDLL_errno = EINVAL;
602 return -1;
603 }
604
605 TRACE(":fd (%d) to 0x%08lx pos %s\n",
606 fd,offset,(whence==SEEK_SET)?"SEEK_SET":
607 (whence==SEEK_CUR)?"SEEK_CUR":
608 (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
609
610 if ((ret = SetFilePointer( hand, offset, NULL, whence )) != 0xffffffff)
611 {
612 if ( __CRTDLL_files[fd])
613 __CRTDLL_files[fd]->_flag &= ~_IOEOF;
614 /* FIXME: What if we seek _to_ EOF - is EOF set? */
615 return ret;
616 }
617 TRACE(":error-last error (%ld)\n",GetLastError());
618 if ( __CRTDLL_files[fd])
619 switch(GetLastError())
620 {
621 case ERROR_NEGATIVE_SEEK:
622 case ERROR_SEEK_ON_DEVICE:
623 __CRTDLL__set_errno(GetLastError());
624 __CRTDLL_files[fd]->_flag |= _IOERR;
625 break;
626 default:
627 break;
628 }
629 return -1;
630}
631
632
633/*********************************************************************
634 * _open (CRTDLL.239)
635 * Open a file.
636 */
637INT CDECL CRTDLL__open(LPCSTR path,INT flags)
638{
639 DWORD access = 0, creation = 0;
640 INT ioflag = 0, fd;
641 HANDLE hand;
642
643 TRACE(":file (%s) mode 0x%04x\n",path,flags);
644
645 switch(flags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
646 {
647 case _O_RDONLY:
648 access |= GENERIC_READ;
649 ioflag |= _IOREAD;
650 break;
651 case _O_WRONLY:
652 access |= GENERIC_WRITE;
653 ioflag |= _IOWRT;
654 break;
655 case _O_RDWR:
656 access |= GENERIC_WRITE | GENERIC_READ;
657 ioflag |= _IORW;
658 break;
659 }
660
661 if (flags & _O_CREAT)
662 {
663 if (flags & _O_EXCL)
664 creation = CREATE_NEW;
665 else if (flags & _O_TRUNC)
666 creation = CREATE_ALWAYS;
667 else
668 creation = OPEN_ALWAYS;
669 }
670 else /* no _O_CREAT */
671 {
672 if (flags & _O_TRUNC)
673 creation = TRUNCATE_EXISTING;
674 else
675 creation = OPEN_EXISTING;
676 }
677 if (flags & _O_APPEND)
678 ioflag |= _IOAPPEND;
679
680
681 flags |= _O_BINARY; /* FIXME: Default to text */
682
683 if (flags & _O_TEXT)
684 {
685 /* Dont warn when writing */
686 if (ioflag & GENERIC_READ)
687 FIXME(":TEXT node not implemented\n");
688 flags &= ~_O_TEXT;
689 }
690
691 if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL|_O_CREAT|_O_RDWR))
692 TRACE(":unsupported flags 0x%04x\n",flags);
693
694 /* clear those pesky flags ;-) */
695 flags &= (_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL|_O_CREAT|_O_RDWR);
696
697 hand = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
698 NULL, creation, FILE_ATTRIBUTE_NORMAL, -1);
699
700 if (hand == INVALID_HANDLE_VALUE)
701 {
702 WARN(":failed-last error (%ld)\n",GetLastError());
703 __CRTDLL__set_errno(GetLastError());
704 return -1;
705 }
706
707 fd = __CRTDLL__alloc_fd(hand,ioflag);
708
709 TRACE(":fd (%d) handle (%d)\n",fd, hand);
710
711 if (flags & _IOAPPEND && fd > 0)
712 CRTDLL__lseek(fd, 0, FILE_END );
713
714 return fd;
715}
716
717
718/*********************************************************************
719 * _open_osfhandle (CRTDLL.240)
720 *
721 * Create a file descriptor for a file HANDLE.
722 */
723INT CDECL CRTDLL__open_osfhandle(HANDLE hand, INT flags)
724{
725 INT fd = __CRTDLL__alloc_fd(hand,flags);
726 TRACE(":handle (%d) fd (%d)\n",hand,fd);
727 return fd;
728}
729
730
731/*********************************************************************
732 * _read (CRTDLL.256)
733 *
734 * Read data from a file.
735 */
736INT CDECL CRTDLL__read(INT fd, LPVOID buf, UINT count)
737{
738 DWORD num_read;
739 HANDLE hand = __CRTDLL__fdtoh(fd);
740
741 /* Dont trace small reads, it gets *very* annoying */
742 if (count > 4)
743 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
744 if (hand == INVALID_HANDLE_VALUE)
745 return -1;
746
747 /* Set _cnt to 0 so optimised binaries will call our implementation
748 * of putc/getc. See _filbuf/_flsbuf comments.
749 */
750 if (__CRTDLL_files[fd])
751 __CRTDLL_files[fd]->_cnt = 0;
752
753 if (ReadFile(hand, buf, count, &num_read, NULL))
754 {
755 if (num_read != count && __CRTDLL_files[fd])
756 {
757 TRACE(":EOF\n");
758 __CRTDLL_files[fd]->_flag |= _IOEOF;
759 }
760 return num_read;
761 }
762 TRACE(":failed-last error (%ld)\n",GetLastError());
763 if ( __CRTDLL_files[fd])
764 __CRTDLL_files[fd]->_flag |= _IOERR;
765 return -1;
766}
767
768
769/*********************************************************************
770 * _setmode (CRTDLL.265)
771 *
772 * FIXME: At present we ignore the request to translate CR/LF to LF.
773 *
774 * We always translate when we read with fgets, we never do with fread
775 *
776 */
777INT CDECL CRTDLL__setmode(INT fd,INT mode)
778{
779 // return (_setmode(fh, mode));
780
781 if (mode & _O_TEXT)
782 FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode);
783 return 0;
784}
785
786
787/*********************************************************************
788 * _stat (CRTDLL.280)
789 */
790INT CDECL CRTDLL__stat(const char* path, struct _stat * buf)
791{
792 // return(_stat(s1, n));
793
794 DWORD dw;
795 WIN32_FILE_ATTRIBUTE_DATA hfi;
796 unsigned short mode = CRTDLL_S_IREAD;
797 int plen;
798
799 TRACE(":file (%s) buf(%p)\n",path,buf);
800
801 if (!GetFileAttributesExA( path, GetFileExInfoStandard, &hfi ))
802 {
803 TRACE("failed-last error (%ld)\n",GetLastError());
804 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
805 return -1;
806 }
807
808 memset(buf,0,sizeof(struct _stat));
809
810 /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */
811 if (isalpha(*path))
812 buf->st_dev = buf->st_rdev = toupper(*path - 'A'); /* drive num */
813 else
814 buf->st_dev = buf->st_rdev = CRTDLL__getdrive() - 1;
815
816 plen = strlen(path);
817
818 /* Dir, or regular file? */
819 if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
820 (path[plen-1] == '\\'))
821 mode |= (_S_IFDIR | CRTDLL_S_IEXEC);
822 else
823 {
824 mode |= _S_IFREG;
825 /* executable? */
826 if (plen > 6 && path[plen-4] == '.') /* shortest exe: "\x.exe" */
827 {
828 unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8)
829 | (tolower(path[plen-3]) << 16);
830 if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
831 mode |= CRTDLL_S_IEXEC;
832 }
833 }
834
835 if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
836 mode |= CRTDLL_S_IWRITE;
837
838 buf->st_mode = mode;
839 buf->st_nlink = 1;
840 buf->st_size = hfi.nFileSizeLow;
841 RtlTimeToSecondsSince1970( &hfi.ftLastAccessTime, &dw );
842 buf->st_atime = dw;
843 RtlTimeToSecondsSince1970( &hfi.ftLastWriteTime, &dw );
844 buf->st_mtime = buf->st_ctime = dw;
845 TRACE("\n%d %d %d %d %d %d\n", buf->st_mode,buf->st_nlink,buf->st_size,
846 buf->st_atime,buf->st_mtime, buf->st_ctime);
847 return 0;
848}
849
850
851/*********************************************************************
852 * _tell (CRTDLL.302)
853 *
854 * Get current file position.
855 */
856LONG CDECL CRTDLL__tell(INT fd)
857{
858 // return (_tell(i));
859
860 return CRTDLL__lseek(fd, 0, SEEK_CUR);
861}
862
863
864/*********************************************************************
865 * _tempnam (CRTDLL.305)
866 *
867 */
868LPSTR CDECL CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix)
869{
870 // return (_tempnam(dir, prefix));
871
872 char tmpbuf[MAX_PATH];
873
874 TRACE("dir (%s) prefix (%s)\n",dir,prefix);
875 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
876 {
877 TRACE("got name (%s)\n",tmpbuf);
878 return CRTDLL__strdup(tmpbuf);
879 }
880 TRACE("failed-last error (%ld)\n",GetLastError());
881 return NULL;
882}
883
884
885/*********************************************************************
886 * _umask (CRTDLL.310)
887 *
888 * Set the process-wide umask.
889 */
890INT CDECL CRTDLL__umask(INT umask)
891{
892 // return (_umask(i));
893
894 INT old_umask = __CRTDLL_umask;
895 TRACE("umask (%d)\n",umask);
896 __CRTDLL_umask = umask;
897 return old_umask;
898}
899
900
901/*********************************************************************
902 * _unlink (CRTDLL.315)
903 *
904 * Delete a file.
905 */
906INT CDECL CRTDLL__unlink(LPCSTR path)
907{
908 TRACE("path (%s)\n",path);
909 if(DeleteFileA( path ))
910 return 0;
911
912 TRACE("failed-last error (%ld)\n",GetLastError());
913 __CRTDLL__set_errno(GetLastError());
914 return -1;
915}
916
917
918/*********************************************************************
919 * _write (CRTDLL.332)
920 *
921 * Write data to a file.
922 */
923UINT CDECL CRTDLL__write(INT fd, LPCVOID buf, UINT count)
924{
925 DWORD num_written;
926 HANDLE hand = __CRTDLL__fdtoh(fd);
927
928 /* Dont trace small writes, it gets *very* annoying */
929 if (count > 4)
930 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
931 if (hand == INVALID_HANDLE_VALUE)
932 return -1;
933
934 /* If appending, go to EOF */
935 /** @@@PH this seems to be slow and wrong. Only seek at opening the file? */
936 if (__CRTDLL_flags[fd] & _IOAPPEND)
937 CRTDLL__lseek(fd, 0, FILE_END );
938
939 /* Set _cnt to 0 so optimised binaries will call our implementation
940 * of putc/getc. See _filbuf/_flsbuf comments.
941 */
942 if (__CRTDLL_files[fd])
943 __CRTDLL_files[fd]->_cnt = 0;
944
945 if (WriteFile(hand, buf, count, &num_written, NULL)
946 && (num_written == count))
947 return num_written;
948
949 TRACE(":failed-last error (%ld)\n",GetLastError());
950 if ( __CRTDLL_files[fd])
951 __CRTDLL_files[fd]->_flag |= _IOERR;
952
953 return -1;
954}
955
956
957/*********************************************************************
958 * clearerr (CRTDLL.349)
959 *
960 * Clear a FILE's error indicator.
961 */
962VOID CDECL CRTDLL_clearerr(CRTDLL_FILE* file)
963{
964 // clearerr(fp);
965
966 TRACE(":file (%p) fd (%d)\n",file,file->_file);
967 file->_flag &= ~(_IOERR | _IOEOF);
968}
969
970
971/*********************************************************************
972 * fclose (CRTDLL.362)
973 *
974 * Close an open file.
975 */
976INT CDECL CRTDLL_fclose( CRTDLL_FILE* file )
977{
978 // return (fclose(fp));
979
980 return CRTDLL__close(file->_file);
981}
982
983
984/*********************************************************************
985 * feof (CRTDLL.363)
986 *
987 * Check the eof indicator on a file.
988 */
989INT CDECL CRTDLL_feof( CRTDLL_FILE* file )
990{
991 // return (feof(fp));
992
993 return file->_flag & _IOEOF;
994}
995
996
997/*********************************************************************
998 * ferror (CRTDLL.361)
999 *
1000 * Check the error indicator on a file.
1001 */
1002INT CDECL CRTDLL_ferror( CRTDLL_FILE* file )
1003{
1004 // return (ferror(fp));
1005
1006 return file->_flag & _IOERR;
1007}
1008
1009
1010/*********************************************************************
1011 * fflush (CRTDLL.362)
1012 */
1013INT CDECL CRTDLL_fflush( CRTDLL_FILE* file )
1014{
1015 // return (fflush(fp));
1016
1017 return CRTDLL__commit(file->_file);
1018}
1019
1020
1021/*********************************************************************
1022 * fgetc (CRTDLL.363)
1023 */
1024INT CDECL CRTDLL_fgetc( CRTDLL_FILE* file )
1025{
1026 // return (fgetc(fp));
1027
1028 char c;
1029 if (CRTDLL__read(file->_file,&c,1) != 1)
1030 return EOF;
1031 return c;
1032}
1033
1034
1035/*********************************************************************
1036 * fgetpos (CRTDLL.364)
1037 */
1038INT CDECL CRTDLL_fgetpos( CRTDLL_FILE* file, __CRTDLL_fpos_t *pos)
1039{
1040 // return (fgetpos(fp, pos));
1041
1042 *pos = CRTDLL__tell(file->_file);
1043 return (*pos == -1? -1 : 0);
1044}
1045
1046
1047/*********************************************************************
1048 * fgets (CRTDLL.365)
1049 */
1050CHAR* CDECL CRTDLL_fgets(LPSTR s, INT size, CRTDLL_FILE* file)
1051{
1052 // return (fgets(s, n, fp));
1053
1054 int cc;
1055 LPSTR buf_start = s;
1056
1057 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1058 file,file->_file,s,size);
1059
1060 /* BAD, for the whole WINE process blocks... just done this way to test
1061 * windows95's ftp.exe.
1062 * JG - Is this true now we use ReadFile() on stdin too?
1063 */
1064 for(cc = CRTDLL_fgetc(file); cc != EOF && cc != '\n';
1065 cc = CRTDLL_fgetc(file))
1066 if (cc != '\r')
1067 {
1068 if (--size <= 0) break;
1069 *s++ = (char)cc;
1070 }
1071 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
1072 {
1073 TRACE(":nothing read\n");
1074 return 0;
1075 }
1076 if (cc == '\n')
1077 if (--size > 0)
1078 *s++ = '\n';
1079 *s = '\0';
1080 TRACE(":got '%s'\n", buf_start);
1081 return buf_start;
1082}
1083
1084
1085/*********************************************************************
1086 * fputs (CRTDLL.375)
1087 */
1088INT CDECL CRTDLL_fputs( LPCSTR s, CRTDLL_FILE* file )
1089{
1090 // return (fputs(s, fp));
1091
1092 return CRTDLL_fwrite(s,strlen(s),1,file);
1093}
1094
1095
1096/*********************************************************************
1097 * fprintf (CRTDLL.370)
1098 */
1099INT CDECL CRTDLL_fprintf( CRTDLL_FILE* file, LPCSTR format, ... )
1100{
1101 // return (fprintf(file, format, arg));
1102
1103 va_list valist;
1104 INT res;
1105
1106 va_start( valist, format );
1107 res = CRTDLL_vfprintf( file, format, valist );
1108 va_end( valist );
1109 return res;
1110}
1111
1112
1113/*********************************************************************
1114 * fopen (CRTDLL.372)
1115 *
1116 * Open a file.
1117 */
1118CRTDLL_FILE* CDECL CRTDLL_fopen(LPCSTR path, LPCSTR mode)
1119{
1120 // return (fopen( filename, mode));
1121
1122 CRTDLL_FILE* file;
1123 INT flags = 0, plus = 0, fd;
1124 const char* search = mode;
1125
1126 TRACE(":path (%s) mode (%s)\n",path,mode);
1127
1128 while (*search)
1129 if (*search++ == '+')
1130 plus = 1;
1131
1132 /* map mode string to open() flags. "man fopen" for possibilities. */
1133 switch(*mode++)
1134 {
1135 case 'R': case 'r':
1136 flags = (plus ? _O_RDWR : _O_RDONLY);
1137 break;
1138 case 'W': case 'w':
1139 flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1140 break;
1141 case 'A': case 'a':
1142 flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1143 break;
1144 default:
1145 return NULL;
1146 }
1147
1148 while (*mode)
1149 switch (*mode++)
1150 {
1151 case 'B': case 'b':
1152 flags |= _O_BINARY;
1153 flags &= ~_O_TEXT;
1154 break;
1155 case 'T': case 't':
1156 flags |= _O_TEXT;
1157 flags &= ~_O_BINARY;
1158 break;
1159 case '+':
1160 break;
1161 default:
1162 FIXME(":unknown flag %c not supported\n",mode[-1]);
1163 }
1164
1165 fd = CRTDLL__open(path, flags);
1166
1167 if (fd < 0)
1168 return NULL;
1169
1170 file = __CRTDLL__alloc_fp(fd);
1171 TRACE(":get file (%p)\n",file);
1172 if (!file)
1173 CRTDLL__close(fd);
1174
1175 return file;
1176}
1177
1178
1179/*********************************************************************
1180 * fputc (CRTDLL.374)
1181 */
1182INT CDECL CRTDLL_fputc( INT c, CRTDLL_FILE* file )
1183{
1184 // return (fputc(c, fp));
1185
1186 return CRTDLL__write(file->_file, &c, 1) == 1? c : EOF;
1187}
1188
1189
1190/*********************************************************************
1191 * fread (CRTDLL.377)
1192 */
1193DWORD CDECL CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file)
1194{
1195 // return (fread(ptr, size, n, fp));
1196
1197 DWORD read = CRTDLL__read(file->_file,ptr, size * nmemb);
1198 if (read <= 0)
1199 return 0;
1200 return read / size;
1201}
1202
1203
1204/*********************************************************************
1205 * freopen (CRTDLL.379)
1206 *
1207 */
1208CRTDLL_FILE* CDECL CRTDLL_freopen(LPCSTR path, LPCSTR mode,CRTDLL_FILE* file)
1209{
1210 // return (freopen(filename, mode, fp));
1211
1212 CRTDLL_FILE* newfile;
1213 INT fd;
1214
1215 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file);
1216 if (!file || ((fd = file->_file) < 0) || fd > __CRTDLL_fdend)
1217 return NULL;
1218
1219 if (fd > 2)
1220 {
1221 FIXME(":reopen on user file not implemented!\n");
1222 __CRTDLL__set_errno(ERROR_CALL_NOT_IMPLEMENTED);
1223 return NULL;
1224 }
1225
1226 /* first, create the new file */
1227 if ((newfile = CRTDLL_fopen(path,mode)) == NULL)
1228 return NULL;
1229
1230 if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE :
1231 (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE),
1232 __CRTDLL_handles[newfile->_file]))
1233 {
1234 /* Redirecting std handle to file , copy over.. */
1235 __CRTDLL_handles[fd] = __CRTDLL_handles[newfile->_file];
1236 __CRTDLL_flags[fd] = __CRTDLL_flags[newfile->_file];
1237 memcpy(&__CRTDLL_iob[fd], newfile, sizeof (CRTDLL_FILE));
1238 __CRTDLL_iob[fd]._file = fd;
1239 /* And free up the resources allocated by fopen, but
1240 * not the HANDLE we copied. */
1241 CRTDLL_free(__CRTDLL_files[fd]);
1242 __CRTDLL__free_fd(newfile->_file);
1243 return &__CRTDLL_iob[fd];
1244 }
1245
1246 WARN(":failed-last error (%ld)\n",GetLastError());
1247 CRTDLL_fclose(newfile);
1248 __CRTDLL__set_errno(GetLastError());
1249 return NULL;
1250}
1251
1252
1253/*********************************************************************
1254 * fsetpos (CRTDLL.380)
1255 */
1256INT CDECL CRTDLL_fsetpos( CRTDLL_FILE* file, __CRTDLL_fpos_t *pos)
1257{
1258 // return (fsetpos(fp, pos));
1259
1260 return CRTDLL__lseek(file->_file,*pos,SEEK_SET);
1261}
1262
1263
1264/*********************************************************************
1265 * fscanf (CRTDLL.381)
1266 */
1267INT CDECL CRTDLL_fscanf( CRTDLL_FILE* file, LPSTR format, ... )
1268{
1269 // return (fscanf(fp, format, arg));
1270
1271 INT rd = 0;
1272 int nch;
1273 va_list ap;
1274 if (!*format) return 0;
1275 WARN("%p (\"%s\"): semi-stub\n", file, format);
1276 nch = CRTDLL_fgetc(file);
1277 va_start(ap, format);
1278 while (*format) {
1279 if (*format == ' ') {
1280 /* skip whitespace */
1281 while ((nch!=EOF) && isspace(nch))
1282 nch = CRTDLL_fgetc(file);
1283 }
1284 else if (*format == '%') {
1285 int st = 0;
1286 format++;
1287 switch(*format) {
1288 case 'd': { /* read an integer */
1289 int*val = va_arg(ap, int*);
1290 int cur = 0;
1291 /* skip initial whitespace */
1292 while ((nch!=EOF) && isspace(nch))
1293 nch = CRTDLL_fgetc(file);
1294 /* get sign and first digit */
1295 if (nch == '-') {
1296 nch = CRTDLL_fgetc(file);
1297 if (isdigit(nch))
1298 cur = -(nch - '0');
1299 else break;
1300 } else {
1301 if (isdigit(nch))
1302 cur = nch - '0';
1303 else break;
1304 }
1305 nch = CRTDLL_fgetc(file);
1306 /* read until no more digits */
1307 while ((nch!=EOF) && isdigit(nch)) {
1308 cur = cur*10 + (nch - '0');
1309 nch = CRTDLL_fgetc(file);
1310 }
1311 st = 1;
1312 *val = cur;
1313 }
1314 break;
1315 case 'f': { /* read a float */
1316 float*val = va_arg(ap, float*);
1317 float cur = 0;
1318 /* skip initial whitespace */
1319 while ((nch!=EOF) && isspace(nch))
1320 nch = CRTDLL_fgetc(file);
1321 /* get sign and first digit */
1322 if (nch == '-') {
1323 nch = CRTDLL_fgetc(file);
1324 if (isdigit(nch))
1325 cur = -(nch - '0');
1326 else break;
1327 } else {
1328 if (isdigit(nch))
1329 cur = nch - '0';
1330 else break;
1331 }
1332 /* read until no more digits */
1333 while ((nch!=EOF) && isdigit(nch)) {
1334 cur = cur*10 + (nch - '0');
1335 nch = CRTDLL_fgetc(file);
1336 }
1337 if (nch == '.') {
1338 /* handle decimals */
1339 float dec = 1;
1340 nch = CRTDLL_fgetc(file);
1341 while ((nch!=EOF) && isdigit(nch)) {
1342 dec /= 10;
1343 cur += dec * (nch - '0');
1344 nch = CRTDLL_fgetc(file);
1345 }
1346 }
1347 st = 1;
1348 *val = cur;
1349 }
1350 break;
1351 case 's': { /* read a word */
1352 char*str = va_arg(ap, char*);
1353 char*sptr = str;
1354 /* skip initial whitespace */
1355 while ((nch!=EOF) && isspace(nch))
1356 nch = CRTDLL_fgetc(file);
1357 /* read until whitespace */
1358 while ((nch!=EOF) && !isspace(nch)) {
1359 *sptr++ = nch; st++;
1360 nch = CRTDLL_fgetc(file);
1361 }
1362 /* terminate */
1363 *sptr = 0;
1364 TRACE("read word: %s\n", str);
1365 }
1366 break;
1367 default: FIXME("unhandled: %%%c\n", *format);
1368 }
1369 if (st) rd++;
1370 else break;
1371 }
1372 else {
1373 /* check for character match */
1374 if (nch == *format)
1375 nch = CRTDLL_fgetc(file);
1376 else break;
1377 }
1378 format++;
1379 }
1380 va_end(ap);
1381 if (nch!=EOF) {
1382 WARN("need ungetch\n");
1383 }
1384 TRACE("returning %d\n", rd);
1385 return rd;
1386}
1387
1388
1389/*********************************************************************
1390 * fseek (CRTDLL.382)
1391 */
1392LONG CDECL CRTDLL_fseek( CRTDLL_FILE* file, LONG offset, INT whence)
1393{
1394 // return (fseek(file, offset, whence));
1395
1396 return CRTDLL__lseek(file->_file,offset,whence);
1397}
1398
1399
1400/*********************************************************************
1401 * ftell (CRTDLL.381)
1402 */
1403LONG CDECL CRTDLL_ftell( CRTDLL_FILE* file )
1404{
1405 // return (ftell(fp));
1406
1407 return CRTDLL__tell(file->_file);
1408}
1409
1410
1411/*********************************************************************
1412 * fwrite (CRTDLL.383)
1413 */
1414UINT CDECL CRTDLL_fwrite( LPCVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file )
1415{
1416 // return (fwrite( ptr, size, nmemb, file));
1417
1418 UINT written = CRTDLL__write(file->_file, ptr, size * nmemb);
1419 if (written <= 0)
1420 return 0;
1421 return written / size;
1422}
1423
1424
1425/*********************************************************************
1426 * getchar (CRTDLL.386)
1427 */
1428INT CDECL CRTDLL_getchar( VOID )
1429{
1430 // return (getchar());
1431
1432 return CRTDLL_fgetc(CRTDLL_stdin);
1433}
1434
1435
1436/*********************************************************************
1437 * getc (CRTDLL.388)
1438 */
1439INT CDECL CRTDLL_getc( CRTDLL_FILE* file )
1440{
1441 // return (getc(fp));
1442
1443 return CRTDLL_fgetc( file );
1444}
1445
1446
1447/*********************************************************************
1448 * gets (CRTDLL.391)
1449 */
1450LPSTR CDECL CRTDLL_gets(LPSTR buf)
1451{
1452 // return (gets(s));
1453
1454 int cc;
1455 LPSTR buf_start = buf;
1456
1457 /* BAD, for the whole WINE process blocks... just done this way to test
1458 * windows95's ftp.exe.
1459 * JG 19/9/00: Is this still true, now we are using ReadFile?
1460 */
1461 for(cc = CRTDLL_fgetc(CRTDLL_stdin); cc != EOF && cc != '\n';
1462 cc = CRTDLL_fgetc(CRTDLL_stdin))
1463 if(cc != '\r') *buf++ = (char)cc;
1464
1465 *buf = '\0';
1466
1467 TRACE("got '%s'\n", buf_start);
1468 return buf_start;
1469}
1470
1471
1472/*********************************************************************
1473 * putc (CRTDLL.441)
1474 */
1475INT CDECL CRTDLL_putc( INT c, CRTDLL_FILE* file )
1476{
1477 // return putc( c, fp );
1478
1479 return CRTDLL_fputc( c, file );
1480}
1481
1482
1483/*********************************************************************
1484 * putchar (CRTDLL.442)
1485 */
1486void CDECL CRTDLL_putchar( INT c )
1487{
1488 // return putchar( c );
1489
1490 CRTDLL_fputc(c, CRTDLL_stdout);
1491}
1492
1493
1494/*********************************************************************
1495 * puts (CRTDLL.443)
1496 */
1497INT CDECL CRTDLL_puts(LPCSTR s)
1498{
1499 // return puts( s );
1500
1501 return CRTDLL_fputs(s, CRTDLL_stdout);
1502}
1503
1504
1505/*********************************************************************
1506 * rewind (CRTDLL.447)
1507 *
1508 * Set the file pointer to the start of a file and clear any error
1509 * indicators.
1510 */
1511VOID CDECL CRTDLL_rewind(CRTDLL_FILE* file)
1512{
1513 // rewind(fp);
1514
1515 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1516 CRTDLL__lseek(file->_file,0,SEEK_SET);
1517 file->_flag &= ~(_IOEOF | _IOERR);
1518}
1519
1520
1521/*********************************************************************
1522 * remove (CRTDLL.448)
1523 */
1524INT CDECL CRTDLL_remove(LPCSTR path)
1525{
1526 // return (remove(file));
1527
1528 TRACE(":path (%s)\n",path);
1529 if (DeleteFileA(path))
1530 return 0;
1531 TRACE(":failed-last error (%ld)\n",GetLastError());
1532 __CRTDLL__set_errno(GetLastError());
1533 return -1;
1534}
1535
1536
1537/*********************************************************************
1538 * rename (CRTDLL.449)
1539 */
1540INT CDECL CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath)
1541{
1542 // return (rename(old, new2));
1543
1544 TRACE(":from %s to %s\n",oldpath,newpath);
1545 if (MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
1546 return 0;
1547 TRACE(":failed-last error (%ld)\n",GetLastError());
1548 __CRTDLL__set_errno(GetLastError());
1549 return -1;
1550}
1551
1552
1553/*********************************************************************
1554 * setbuf (CRTDLL.452)
1555 */
1556INT CDECL CRTDLL_setbuf(CRTDLL_FILE* file, LPSTR buf)
1557{
1558 // setbuf(fp, buf);
1559
1560 TRACE(":file (%p) fd (%d) buf (%p)\n", file, file->_file,buf);
1561 if (buf)
1562 WARN(":user buffer will not be used!\n");
1563 /* FIXME: no buffering for now */
1564 return 0;
1565}
1566
1567
1568/*********************************************************************
1569 * tmpnam (CRTDLL.490)
1570 *
1571 * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1572 *
1573 */
1574LPSTR CDECL CRTDLL_tmpnam(LPSTR s)
1575{
1576 // return (tmpnam(s));
1577
1578 char tmpbuf[MAX_PATH];
1579 char* prefix = "TMP";
1580 if (!GetTempPathA(MAX_PATH,tmpbuf) ||
1581 !GetTempFileNameA(tmpbuf,prefix,0,CRTDLL_tmpname))
1582 {
1583 TRACE(":failed-last error (%ld)\n",GetLastError());
1584 return NULL;
1585 }
1586 TRACE(":got tmpnam %s\n",CRTDLL_tmpname);
1587 return CRTDLL_tmpname;
1588}
1589
1590
1591/*********************************************************************
1592 * vfprintf (CRTDLL.494)
1593 *
1594 * Write formatted output to a file.
1595 */
1596/* we have avoided libc stdio.h so far, lets not start now */
1597/* @@@PH extern int vsprintf(void *, const void *, va_list); */
1598
1599INT CDECL CRTDLL_vfprintf( CRTDLL_FILE* file, LPCSTR format, va_list args )
1600{
1601 // return (vfprintf(file, format, args));
1602
1603 /* FIXME: We should parse the format string, calculate the maximum,
1604 * length of each arg, malloc a buffer, print to it, and fwrite that.
1605 * Yes this sucks, but not as much as crashing 1/2 way through an
1606 * app writing to a file :-(
1607 */
1608 char buffer[2048];
1609 TRACE(":file (%p) fd (%d) fmt (%s)\n",file,file->_file,format);
1610
1611 vsprintf( buffer, format, args );
1612 return CRTDLL_fwrite( buffer, 1, strlen(buffer), file );
1613}
1614
Note: See TracBrowser for help on using the repository browser.