advapi32: Remove a useless macro.
[wine] / dlls / msvcrt / tests / file.c
1 /*
2  * Unit test suite for file functions
3  *
4  * Copyright 2002 Bill Currie
5  * Copyright 2005 Paul Rupe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "wine/test.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <share.h>
28 #include <sys/stat.h>
29 #include <io.h>
30 #include <windef.h>
31 #include <winbase.h>
32 #include <winnls.h>
33 #include <process.h>
34 #include <errno.h>
35
36 static void test_fdopen( void )
37 {
38     static const char buffer[] = {0,1,2,3,4,5,6,7,8,9};
39     char ibuf[10];
40     int fd;
41     FILE *file;
42
43     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
44     write (fd, buffer, sizeof (buffer));
45     close (fd);
46
47     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
48     lseek (fd, 5, SEEK_SET);
49     file = fdopen (fd, "rb");
50     ok (fread (ibuf, 1, sizeof (buffer), file) == 5, "read wrong byte count\n");
51     ok (memcmp (ibuf, buffer + 5, 5) == 0, "read wrong bytes\n");
52     fclose (file);
53     unlink ("fdopen.tst");
54 }
55
56 static void test_fileops( void )
57 {
58     static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9";
59     char buffer[256];
60     WCHAR wbuffer[256];
61     int fd;
62     FILE *file;
63     fpos_t pos;
64     int i, c;
65
66     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
67     write (fd, outbuffer, sizeof (outbuffer));
68     close (fd);
69
70     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
71     file = fdopen (fd, "rb");
72     ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error\n");
73     ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected\n");
74     ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF\n");
75     ok(feof(file) !=0,"feof doesn't signal EOF\n");
76     rewind(file);
77     ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected\n");
78     ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size\n");
79     ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
80     ok(strlen(buffer) == 1,"fgets dropped chars\n");
81     ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars\n");
82
83     rewind(file);
84     for (i = 0, c = EOF; i < sizeof(outbuffer); i++)
85     {
86         ok((c = fgetc(file)) == outbuffer[i], "fgetc returned wrong data\n");
87     }
88     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
89     ok(feof(file), "feof did not return EOF\n");
90     ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF\n");
91     ok(feof(file), "feof after ungetc(EOF) did not return EOF\n");
92     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
93     c = outbuffer[sizeof(outbuffer) - 1];
94     ok(ungetc(c, file) == c, "ungetc did not return its input\n");
95     ok(!feof(file), "feof after ungetc returned EOF\n");
96     ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF\n");
97     ok(c == outbuffer[sizeof(outbuffer) - 1],
98        "getc did not return ungetc'd data\n");
99     ok(!feof(file), "feof after getc returned EOF prematurely\n");
100     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
101     ok(feof(file), "feof after getc did not return EOF\n");
102
103     rewind(file);
104     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
105     ok(pos == 0, "Unexpected result of fgetpos 0x%Lx\n", pos);
106     pos = (ULONGLONG)sizeof (outbuffer);
107     ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected\n");
108     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
109     ok(pos == (ULONGLONG)sizeof (outbuffer), "Unexpected result of fgetpos 0x%Lx\n", pos);
110
111     fclose (file);
112     fd = open ("fdopen.tst", O_RDONLY | O_TEXT);
113     file = fdopen (fd, "rt"); /* open in TEXT mode */
114     ok(fgetws(wbuffer,sizeof(wbuffer),file) !=0,"fgetws failed unexpected\n");
115     ok(fgetws(wbuffer,sizeof(wbuffer),file) ==0,"fgetws didn't signal EOF\n");
116     ok(feof(file) !=0,"feof doesn't signal EOF\n");
117     rewind(file);
118     ok(fgetws(wbuffer,strlen(outbuffer),file) !=0,"fgetws failed unexpected\n");
119     ok(lstrlenW(wbuffer) == (lstrlenA(outbuffer) -1),"fgetws didn't read right size\n");
120     ok(fgetws(wbuffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
121     ok(lstrlenW(wbuffer) == 1,"fgets dropped chars\n");
122     fclose (file);
123
124     file = fopen("fdopen.tst", "rb");
125     ok( file != NULL, "fopen failed\n");
126     /* sizeof(buffer) > content of file */
127     ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n");
128     /* feof should be set now */
129     ok(feof(file), "feof after fread failed\n");
130     fclose (file);
131
132     unlink ("fdopen.tst");
133 }
134
135 #define IOMODE (ao?"ascii mode":"binary mode")
136 static void test_readmode( BOOL ascii_mode )
137 {
138     static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9\r\n\r\nA,B,C,D,E\r\nX,Y,Z";
139     static const char padbuffer[] = "ghjghjghjghj";
140     static const char nlbuffer[] = "\r\n";
141     char buffer[2*BUFSIZ+256];
142     const char *optr;
143     int fd;
144     FILE *file;
145     const int *ip;
146     int i, j, m, fp, ao, pl;
147     long l;
148
149     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
150     /* an internal buffer of BUFSIZ is maintained, so make a file big
151      * enough to test operations that cross the buffer boundary 
152      */
153     j = (2*BUFSIZ-4)/strlen(padbuffer);
154     for (i=0; i<j; i++)
155         write (fd, padbuffer, strlen(padbuffer));
156     j = (2*BUFSIZ-4)%strlen(padbuffer);
157     for (i=0; i<j; i++)
158         write (fd, &padbuffer[i], 1);
159     write (fd, nlbuffer, strlen(nlbuffer));
160     write (fd, outbuffer, sizeof (outbuffer));
161     close (fd);
162     
163     if (ascii_mode) {
164         /* Open file in ascii mode */
165         fd = open ("fdopen.tst", O_RDONLY);
166         file = fdopen (fd, "r");
167         ao = -1; /* on offset to account for carriage returns */
168     }
169     else {
170         fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
171         file = fdopen (fd, "rb");
172         ao = 0;
173     }
174     
175     /* first is a test of fgets, ftell, fseek */
176     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
177     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
178     l = ftell(file);
179     pl = 2*BUFSIZ-2;
180     ok(l == pl,"padding line ftell got %ld should be %d in %s\n", l, pl, IOMODE);
181     ok(lstrlenA(buffer) == pl+ao,"padding line fgets got size %d should be %d in %s\n",
182      lstrlenA(buffer), pl+ao, IOMODE);
183     for (fp=0; fp<strlen(outbuffer); fp++)
184         if (outbuffer[fp] == '\n') break;
185     fp++;
186     ok(fgets(buffer,256,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
187     l = ftell(file);
188     ok(l == pl+fp,"line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
189     ok(lstrlenA(buffer) == fp+ao,"line 1 fgets got size %d should be %d in %s\n",
190      lstrlenA(buffer), fp+ao, IOMODE);
191     /* test a seek back across the buffer boundary */
192     l = pl;
193     ok(fseek(file,l,SEEK_SET)==0,"seek failure in %s\n", IOMODE);
194     l = ftell(file);
195     ok(l == pl,"ftell after seek got %ld should be %d in %s\n", l, pl, IOMODE);
196     ok(fgets(buffer,256,file) !=0,"second read of line 1 fgets failed unexpected in %s\n", IOMODE);
197     l = ftell(file);
198     ok(l == pl+fp,"second read of line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
199     ok(lstrlenA(buffer) == fp+ao,"second read of line 1 fgets got size %d should be %d in %s\n",
200      lstrlenA(buffer), fp+ao, IOMODE);
201     ok(fgets(buffer,256,file) !=0,"line 2 fgets failed unexpected in %s\n", IOMODE);
202     fp += 2;
203     l = ftell(file);
204     ok(l == pl+fp,"line 2 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
205     ok(lstrlenA(buffer) == 2+ao,"line 2 fgets got size %d should be %d in %s\n",
206      lstrlenA(buffer), 2+ao, IOMODE);
207     
208     /* test fread across buffer boundary */
209     rewind(file);
210     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
211     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
212     j=strlen(outbuffer);
213     i=fread(buffer,1,BUFSIZ+strlen(outbuffer),file);
214     ok(i==BUFSIZ+j,"fread failed, expected %d got %d in %s\n", BUFSIZ+j, i, IOMODE);
215     l = ftell(file);
216     ok(l == pl+j-(ao*4)-5,"ftell after fread got %ld should be %d in %s\n", l, pl+j-(ao*4)-5, IOMODE);
217     for (m=0; m<3; m++)
218         ok(buffer[m]==padbuffer[m+(BUFSIZ-4)%strlen(padbuffer)],"expected %c got %c\n", padbuffer[m], buffer[m]);
219     m+=BUFSIZ+2+ao;
220     optr = outbuffer;
221     for (; m<i; m++) {
222         ok(buffer[m]==*optr,"char %d expected %c got %c in %s\n", m, *optr, buffer[m], IOMODE);
223         optr++;
224         if (ao && (*optr == '\r'))
225             optr++;
226     }
227     /* fread should return the requested number of bytes if available */
228     rewind(file);
229     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
230     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
231     j = fp+10;
232     i=fread(buffer,1,j,file);
233     ok(i==j,"fread failed, expected %d got %d in %s\n", j, i, IOMODE);
234     /* test fread eof */
235     ok(fseek(file,0,SEEK_END)==0,"seek failure in %s\n", IOMODE);
236     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
237     ok(fread(buffer,1,1,file)==0,"fread failure in %s\n", IOMODE);
238     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
239     ok(fseek(file,-3,SEEK_CUR)==0,"seek failure in %s\n", IOMODE);
240     todo_wine ok(feof(file)==0,"feof failure in %s\n", IOMODE);
241     ok(fread(buffer,2,1,file)==1,"fread failed in %s\n", IOMODE);
242     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
243     ok(fread(buffer,2,1,file)==0,"fread failure in %s\n",IOMODE);
244     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
245     
246     /* test some additional functions */
247     rewind(file);
248     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
249     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
250     i = _getw(file);
251     ip = (const int *)outbuffer;
252     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
253     for (fp=0; fp<strlen(outbuffer); fp++)
254         if (outbuffer[fp] == '\n') break;
255     fp++;
256     /* this will cause the next _getw to cross carriage return characters */
257     ok(fgets(buffer,fp-6,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
258     for (i=0, j=0; i<6; i++) {
259         if (ao==0 || outbuffer[fp-3+i] != '\r')
260             buffer[j++] = outbuffer[fp-3+i];
261     }
262     i = _getw(file);
263     ip = (int *)buffer;
264     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
265
266     fclose (file);
267     unlink ("fdopen.tst");
268 }
269
270
271 static WCHAR* AtoW( const char* p )
272 {
273     WCHAR* buffer;
274     DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
275     buffer = malloc( len * sizeof(WCHAR) );
276     MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
277     return buffer;
278 }
279
280 static void test_fgetc( void )
281 {
282   char* tempf;
283   FILE *tempfh;
284   int  ich=0xe0, ret;
285
286   tempf=_tempnam(".","wne");
287   tempfh = fopen(tempf,"w+");
288   fputc(ich, tempfh);
289   fputc(ich, tempfh);
290   rewind(tempfh);
291   ret = fgetc(tempfh);
292   ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
293   ret = fgetc(tempfh);
294   ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
295   fclose(tempfh);
296   unlink(tempf);
297 }
298
299 static void test_fgetwc( void )
300 {
301 #define LLEN 512
302
303   char* tempf;
304   FILE *tempfh;
305   static const char mytext[]= "This is test_fgetwc\r\n";
306   WCHAR wtextW[BUFSIZ+LLEN+1];
307   WCHAR *mytextW = NULL, *aptr, *wptr;
308   BOOL diff_found = FALSE;
309   int i, j;
310   long l;
311
312   tempf=_tempnam(".","wne");
313   tempfh = fopen(tempf,"wb");
314   j = 'a';
315   /* pad to almost the length of the internal buffer */
316   for (i=0; i<BUFSIZ-4; i++)
317     fputc(j,tempfh);
318   j = '\r';
319   fputc(j,tempfh);
320   j = '\n';
321   fputc(j,tempfh);
322   fputs(mytext,tempfh);
323   fclose(tempfh);
324   /* in text mode, getws/c expects multibyte characters */
325   /*currently Wine only supports plain ascii, and that is all that is tested here */
326   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
327   fgetws(wtextW,LLEN,tempfh);
328   l=ftell(tempfh);
329   ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l);
330   fgetws(wtextW,LLEN,tempfh);
331   l=ftell(tempfh);
332   ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n",
333    BUFSIZ-2+strlen(mytext), l);
334   mytextW = AtoW (mytext);
335   aptr = mytextW;
336   wptr = wtextW;
337   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
338     {
339       diff_found |= (*aptr != *wptr);
340     }
341   ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
342   ok(*wptr == '\n', "Carriage return was not skipped\n");
343   fclose(tempfh);
344   unlink(tempf);
345   
346   tempfh = fopen(tempf,"wb");
347   j = 'a';
348   /* pad to almost the length of the internal buffer. Use an odd number of bytes
349      to test that we can read wchars that are split across the internal buffer
350      boundary */
351   for (i=0; i<BUFSIZ-3-strlen(mytext)*sizeof(WCHAR); i++)
352     fputc(j,tempfh);
353   j = '\r';
354   fputwc(j,tempfh);
355   j = '\n';
356   fputwc(j,tempfh);
357   fputws(wtextW,tempfh);
358   fputws(wtextW,tempfh);
359   fclose(tempfh);
360   /* in binary mode, getws/c expects wide characters */
361   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
362   j=(BUFSIZ-2)/sizeof(WCHAR)-strlen(mytext);
363   fgetws(wtextW,j,tempfh);
364   l=ftell(tempfh);
365   j=(j-1)*sizeof(WCHAR);
366   ok(l==j, "ftell expected %d got %ld\n", j, l);
367   i=fgetc(tempfh);
368   ok(i=='a', "fgetc expected %d got %d\n", 0x61, i);
369   l=ftell(tempfh);
370   j++;
371   ok(l==j, "ftell expected %d got %ld\n", j, l);
372   fgetws(wtextW,3,tempfh);
373   ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]);
374   ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]);
375   l=ftell(tempfh);
376   j += 4;
377   ok(l==j, "ftell expected %d got %ld\n", j, l);
378   for(i=0; i<strlen(mytext); i++)
379     wtextW[i] = 0;
380   /* the first time we get the string, it should be entirely within the local buffer */
381   fgetws(wtextW,LLEN,tempfh);
382   l=ftell(tempfh);
383   j += (strlen(mytext)-1)*sizeof(WCHAR);
384   ok(l==j, "ftell expected %d got %ld\n", j, l);
385   diff_found = FALSE;
386   aptr = mytextW;
387   wptr = wtextW;
388   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
389     {
390       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
391       diff_found |= (*aptr != *wptr);
392     }
393   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
394   ok(*wptr == '\n', "Should get newline\n");
395   for(i=0; i<strlen(mytext); i++)
396     wtextW[i] = 0;
397   /* the second time we get the string, it should cross the local buffer boundary.
398      One of the wchars should be split across the boundary */
399   fgetws(wtextW,LLEN,tempfh);
400   diff_found = FALSE;
401   aptr = mytextW;
402   wptr = wtextW;
403   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
404     {
405       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
406       diff_found |= (*aptr != *wptr);
407     }
408   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
409   ok(*wptr == '\n', "Should get newline\n");
410
411   free(mytextW);
412   fclose(tempfh);
413   unlink(tempf);
414 }
415
416 static void test_ctrlz( void )
417 {
418   char* tempf;
419   FILE *tempfh;
420   static const char mytext[]= "This is test_ctrlz";
421   char buffer[256];
422   int i, j;
423   long l;
424
425   tempf=_tempnam(".","wne");
426   tempfh = fopen(tempf,"wb");
427   fputs(mytext,tempfh);
428   j = 0x1a; /* a ctrl-z character signals EOF in text mode */
429   fputc(j,tempfh);
430   j = '\r';
431   fputc(j,tempfh);
432   j = '\n';
433   fputc(j,tempfh);
434   j = 'a';
435   fputc(j,tempfh);
436   fclose(tempfh);
437   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
438   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
439   i=strlen(buffer);
440   j=strlen(mytext);
441   ok(i==j, "returned string length expected %d got %d\n", j, i);
442   j+=4; /* ftell should indicate the true end of file */
443   l=ftell(tempfh);
444   ok(l==j, "ftell expected %d got %ld\n", j, l);
445   ok(feof(tempfh), "did not get EOF\n");
446   fclose(tempfh);
447   
448   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
449   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
450   i=strlen(buffer);
451   j=strlen(mytext)+3; /* should get through newline */
452   ok(i==j, "returned string length expected %d got %d\n", j, i);
453   l=ftell(tempfh);
454   ok(l==j, "ftell expected %d got %ld\n", j, l);
455   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
456   i=strlen(buffer);
457   ok(i==1, "returned string length expected %d got %d\n", 1, i);
458   ok(feof(tempfh), "did not get EOF\n");
459   fclose(tempfh);
460   unlink(tempf);
461 }
462
463 static void test_file_put_get( void )
464 {
465   char* tempf;
466   FILE *tempfh;
467   static const char mytext[]=  "This is a test_file_put_get\n";
468   static const char dostext[]= "This is a test_file_put_get\r\n";
469   char btext[LLEN];
470   WCHAR wtextW[LLEN+1];
471   WCHAR *mytextW = NULL, *aptr, *wptr;
472   BOOL diff_found = FALSE;
473   unsigned int i;
474
475   tempf=_tempnam(".","wne");
476   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
477   fputs(mytext,tempfh);
478   fclose(tempfh);
479   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
480   fgets(btext,LLEN,tempfh);
481   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
482   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
483   fclose(tempfh);
484   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
485   fputs(dostext,tempfh);
486   fclose(tempfh);
487   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
488   fgets(btext,LLEN,tempfh);
489   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
490   fclose(tempfh);
491   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
492   fgets(btext,LLEN,tempfh);
493   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
494
495   fclose(tempfh);
496   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
497   fgetws(wtextW,LLEN,tempfh);
498   mytextW = AtoW (mytext);
499   aptr = mytextW;
500   wptr = wtextW;
501
502   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
503     {
504       diff_found |= (*aptr != *wptr);
505     }
506   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
507   free(mytextW);
508   fclose(tempfh);
509   unlink(tempf);
510 }
511
512 static void test_file_write_read( void )
513 {
514   char* tempf;
515   int tempfd;
516   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
517   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
518   char btext[LLEN];
519   int ret, i;
520
521   tempf=_tempnam(".","wne");
522   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
523                      _S_IREAD | _S_IWRITE);
524   ok( tempfd != -1,
525      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
526   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
527      "_write _O_BINARY bad return value\n");
528   _close(tempfd);
529   i = lstrlenA(mytext);
530   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
531   ok(_read(tempfd,btext,i) == i,
532      "_read _O_BINARY got bad length\n");
533   ok( memcmp(dostext,btext,i) == 0,
534       "problems with _O_BINARY  _write / _read\n");
535   _close(tempfd);
536   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
537   ok(_read(tempfd,btext,i) == i-1,
538      "_read _O_TEXT got bad length\n");
539   ok( memcmp(mytext,btext,i-1) == 0,
540       "problems with _O_BINARY _write / _O_TEXT _read\n");
541   _close(tempfd);
542   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
543                      _S_IREAD | _S_IWRITE);
544   ok( tempfd != -1,
545      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
546   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
547      "_write _O_TEXT bad return value\n");
548   _close(tempfd);
549   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
550   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
551      "_read _O_BINARY got bad length\n");
552   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
553       "problems with _O_TEXT _write / _O_BINARY _read\n");
554   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
555   _close(tempfd);
556   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
557   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
558      "_read _O_TEXT got bad length\n");
559   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
560       "problems with _O_TEXT _write / _read\n");
561   _close(tempfd);
562
563   memset(btext, 0, LLEN);
564   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
565   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
566   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
567   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
568   _close(tempfd);
569
570   /* Test reading only \n or \r */
571   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
572   _lseek(tempfd, -1, FILE_END);
573   ret = _read(tempfd,btext,LLEN);
574   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
575   _lseek(tempfd, -2, FILE_END);
576   ret = _read(tempfd,btext,LLEN);
577   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
578   _lseek(tempfd, -3, FILE_END);
579   ret = _read(tempfd,btext,2);
580   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
581   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
582   _close(tempfd);
583
584   ret = unlink(tempf);
585   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
586
587   tempf=_tempnam(".","wne");
588   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
589   ok( tempfd != -1,
590      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
591   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
592      "_write _O_BINARY bad return value\n");
593   _close(tempfd);
594   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
595   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
596      "_read _O_BINARY got bad length\n");
597   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
598       "problems with _O_BINARY _write / _read\n");
599   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
600   _close(tempfd);
601   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
602   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
603      "_read _O_TEXT got bad length\n");
604   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
605       "problems with _O_BINARY _write / _O_TEXT _read\n");
606   _close(tempfd);
607
608    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
609   ok( ret == 0,
610      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
611   ret = unlink(tempf);
612   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
613 }
614
615 static void test_file_inherit_child(const char* fd_s)
616 {
617     int fd = atoi(fd_s);
618     char buffer[32];
619     int ret;
620
621     ret =write(fd, "Success", 8);
622     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
623     lseek(fd, 0, SEEK_SET);
624     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
625     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
626 }
627
628 static void test_file_inherit_child_no(const char* fd_s)
629 {
630     int fd = atoi(fd_s);
631     int ret;
632
633     ret = write(fd, "Success", 8);
634     ok( ret == -1 && errno == EBADF, 
635        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
636 }
637  
638 static void test_file_inherit( const char* selfname )
639 {
640     int                 fd;
641     const char*         arg_v[5];
642     char                buffer[16];
643
644     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
645     ok(fd != -1, "Couldn't create test file\n");
646     arg_v[0] = selfname;
647     arg_v[1] = "tests/file.c";
648     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
649     arg_v[3] = 0;
650     _spawnvp(_P_WAIT, selfname, arg_v);
651     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
652     lseek(fd, 0, SEEK_SET);
653     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
654     close (fd);
655     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
656     
657     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
658     ok(fd != -1, "Couldn't create test file\n");
659     arg_v[0] = selfname;
660     arg_v[1] = "tests/file.c";
661     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
662     arg_v[3] = buffer;
663     arg_v[4] = 0;
664     _spawnvp(_P_WAIT, selfname, arg_v);
665     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
666     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
667     close (fd);
668     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
669 }
670
671 static void test_tmpnam( void )
672 {
673   char name[MAX_PATH] = "abc";
674   char *res;
675
676   res = tmpnam(NULL);
677   ok(res != NULL, "tmpnam returned NULL\n");
678   ok(res[0] == '\\', "first character is not a backslash\n");
679   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
680   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
681
682   res = tmpnam(name);
683   ok(res != NULL, "tmpnam returned NULL\n");
684   ok(res == name, "supplied buffer was not used\n");
685   ok(res[0] == '\\', "first character is not a backslash\n");
686   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
687   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
688 }
689
690 static void test_chsize( void )
691 {
692     int fd;
693     long cur, pos, count;
694     char temptext[] = "012345678";
695     char *tempfile = _tempnam( ".", "tst" );
696     
697     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
698
699     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
700     ok( fd > 0, "Couldn't open test file\n" );
701
702     count = _write( fd, temptext, sizeof(temptext) );
703     ok( count > 0, "Couldn't write to test file\n" );
704
705     /* get current file pointer */
706     cur = _lseek( fd, 0, SEEK_CUR );
707
708     /* make the file smaller */
709     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
710
711     pos = _lseek( fd, 0, SEEK_CUR );
712     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
713     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
714
715     /* enlarge the file */
716     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
717
718     pos = _lseek( fd, 0, SEEK_CUR );
719     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
720     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
721
722     _close( fd );
723     _unlink( tempfile );
724 }
725
726 static void test_fopen_fclose_fcloseall( void )
727 {
728     char fname1[] = "empty1";
729     char fname2[] = "empty2";
730     char fname3[] = "empty3";
731     FILE *stream1, *stream2, *stream3, *stream4;
732     int ret, numclosed;
733
734     /* testing fopen() */
735     stream1 = fopen(fname1, "w+");
736     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
737     stream2 = fopen(fname2, "w ");
738     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
739     _unlink(fname3);
740     stream3 = fopen(fname3, "r");
741     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
742     stream3 = fopen(fname3, "w+");
743     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
744     errno = 0xfaceabad;
745     stream4 = fopen("", "w+");
746     ok(stream4 == NULL && errno == ENOENT, 
747        "filename is empty, errno = %d (expected 2)\n", errno);
748     errno = 0xfaceabad;
749     stream4 = fopen(NULL, "w+");
750     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
751        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
752
753     /* testing fclose() */
754     ret = fclose(stream2);
755     ok(ret == 0, "The file '%s' was not closed\n", fname2);
756     ret = fclose(stream3);
757     ok(ret == 0, "The file '%s' was not closed\n", fname3);
758     ret = fclose(stream2);
759     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
760     ret = fclose(stream3);
761     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
762
763     /* testing fcloseall() */
764     numclosed = _fcloseall();
765     /* fname1 should be closed here */
766     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
767     numclosed = _fcloseall();
768     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
769
770     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
771     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
772     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
773 }
774
775 static void test_get_osfhandle(void)
776 {
777     int fd;
778     char fname[] = "t_get_osfhanle";
779     DWORD bytes_written;
780     HANDLE handle;
781
782     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
783     handle = (HANDLE)_get_osfhandle(fd);
784     WriteFile(handle, "bar", 3, &bytes_written, NULL);
785     _close(fd);
786     fd = _open(fname, _O_RDONLY, 0);
787     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
788
789     _close(fd);
790     _unlink(fname);
791 }
792
793 static void test_setmaxstdio(void)
794 {
795     ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048));
796     ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
797 }
798
799 START_TEST(file)
800 {
801     int arg_c;
802     char** arg_v;
803
804     arg_c = winetest_get_mainargs( &arg_v );
805
806     /* testing low-level I/O */
807     if (arg_c >= 3)
808     {
809         if (arg_c == 3) test_file_inherit_child(arg_v[2]); 
810         else test_file_inherit_child_no(arg_v[2]);
811         return;
812     }
813     test_file_inherit(arg_v[0]);
814     test_file_write_read();
815     test_chsize();
816
817     /* testing stream I/O */
818     test_fdopen();
819     test_fopen_fclose_fcloseall();
820     test_fileops();
821     test_readmode(FALSE); /* binary mode */
822     test_readmode(TRUE);  /* ascii mode */
823     test_fgetc();
824     test_fgetwc();
825     test_ctrlz();
826     test_file_put_get();
827     test_tmpnam();
828     test_get_osfhandle();
829     test_setmaxstdio();
830 }