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