mshtml: Print wine_gecko version in load_wine_gecko.
[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[2*MSVCRT_BUFSIZ+256], *optr;
143     int fd;
144     FILE *file;
145     int i, j, m, 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 = (2*MSVCRT_BUFSIZ-4)/strlen(padbuffer);
153     for (i=0; i<j; i++)
154         write (fd, padbuffer, strlen(padbuffer));
155     j = (2*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,2*MSVCRT_BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
177     l = ftell(file);
178     pl = 2*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,MSVCRT_BUFSIZ+strlen(outbuffer),file);
213     ok(i==MSVCRT_BUFSIZ+j,"fread failed, expected %d got %d in %s\n", MSVCRT_BUFSIZ+j, i, IOMODE);
214     l = ftell(file);
215     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);
216     for (m=0; m<3; m++)
217         ok(buffer[m]==padbuffer[m+(MSVCRT_BUFSIZ-4)%strlen(padbuffer)],"expected %c got %c\n", padbuffer[m], buffer[m]);
218     m+=MSVCRT_BUFSIZ+2+ao;
219     optr = (char *)outbuffer;
220     for (; m<i; m++) {
221         ok(buffer[m]==*optr,"char %d expected %c got %c in %s\n", m, *optr, buffer[m], IOMODE);
222         optr++;
223         if (ao && (*optr == '\r'))
224             optr++;
225     }
226     /* fread should return the requested number of bytes if available */
227     rewind(file);
228     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
229     ok(fgets(buffer,MSVCRT_BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
230     j = fp+10;
231     i=fread(buffer,1,j,file);
232     ok(i==j,"fread failed, expected %d got %d in %s\n", j, i, IOMODE);
233     /* test fread eof */
234     ok(fseek(file,0,SEEK_END)==0,"seek failure in %s\n", IOMODE);
235     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
236     ok(fread(buffer,1,1,file)==0,"fread failure in %s\n", IOMODE);
237     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
238     ok(fseek(file,-3,SEEK_CUR)==0,"seek failure in %s\n", IOMODE);
239     todo_wine ok(feof(file)==0,"feof failure in %s\n", IOMODE);
240     ok(fread(buffer,2,1,file)==1,"fread failed in %s\n", IOMODE);
241     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
242     ok(fread(buffer,2,1,file)==0,"fread failure in %s\n",IOMODE);
243     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
244     
245     /* test some additional functions */
246     rewind(file);
247     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
248     ok(fgets(buffer,2*MSVCRT_BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
249     i = _getw(file);
250     ip = (int *)outbuffer;
251     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
252     for (fp=0; fp<strlen(outbuffer); fp++)
253         if (outbuffer[fp] == '\n') break;
254     fp++;
255     /* this will cause the next _getw to cross carriage return characters */
256     ok(fgets(buffer,fp-6,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
257     for (i=0, j=0; i<6; i++) {
258         if (ao==0 || outbuffer[fp-3+i] != '\r')
259             buffer[j++] = outbuffer[fp-3+i];
260     }
261     i = _getw(file);
262     ip = (int *)buffer;
263     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
264
265     fclose (file);
266     unlink ("fdopen.tst");
267 }
268
269
270 static WCHAR* AtoW( char* p )
271 {
272     WCHAR* buffer;
273     DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
274     buffer = malloc( len * sizeof(WCHAR) );
275     MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
276     return buffer;
277 }
278
279 static void test_fgetc( void )
280 {
281   char* tempf;
282   FILE *tempfh;
283   int  ich=0xe0, ret;
284
285   tempf=_tempnam(".","wne");
286   tempfh = fopen(tempf,"w+");
287   fputc(ich, tempfh);
288   fputc(ich, tempfh);
289   rewind(tempfh);
290   ret = fgetc(tempfh);
291   ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
292   ret = fgetc(tempfh);
293   ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
294   fclose(tempfh);
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[MSVCRT_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<MSVCRT_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==MSVCRT_BUFSIZ-2, "ftell expected %d got %ld\n", MSVCRT_BUFSIZ-2, l);
328   fgetws(wtextW,LLEN,tempfh);
329   l=ftell(tempfh);
330   ok(l==MSVCRT_BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n",
331    MSVCRT_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<MSVCRT_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=(MSVCRT_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 START_TEST(file)
792 {
793     int arg_c;
794     char** arg_v;
795
796     arg_c = winetest_get_mainargs( &arg_v );
797
798     /* testing low-level I/O */
799     if (arg_c >= 3)
800     {
801         if (arg_c == 3) test_file_inherit_child(arg_v[2]); 
802         else test_file_inherit_child_no(arg_v[2]);
803         return;
804     }
805     test_file_inherit(arg_v[0]);
806     test_file_write_read();
807     test_chsize();
808
809     /* testing stream I/O */
810     test_fdopen();
811     test_fopen_fclose_fcloseall();
812     test_fileops();
813     test_readmode(FALSE); /* binary mode */
814     test_readmode(TRUE);  /* ascii mode */
815     test_fgetc();
816     test_fgetwc();
817     test_ctrlz();
818     test_file_put_get();
819     test_tmpnam();
820     test_get_osfhandle();
821 }