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

Last change on this file since 4667 was 4667, checked in by phaller, 25 years ago

Major move towards WINE CRTDLL, mixture between both code branches

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