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

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

.

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