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