Improved unicode fileio support.
[reactos.git] / reactos / apps / testsets / msvcrt / fileio / _tfileio.c
1 /*
2 * ReactOS test program -
3 *
4 * _tfileio.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #define WIN32_LEAN_AND_MEAN
24 #include <windows.h>
25 #include <tchar.h>
26 #include <wchar.h>
27 #include <stdio.h>
28
29
30 #ifdef UNICODE
31 #define _tfopen _wfopen
32 #define _tunlink _wunlink
33 #define _TEOF WEOF
34 #define _gettchar getwchar
35 #define _puttchar putwchar
36 #define _THEX_FORMAT _T("0x%04x ")
37 #else /*UNICODE*/
38 #define _tfopen fopen
39 #define _tunlink _unlink
40 #define _TEOF EOF
41 #define _gettchar getchar
42 #define _puttchar putchar
43 #define _THEX_FORMAT "0x%02x "
44 #endif /*UNICODE*/
45
46
47 #define TEST_BUFFER_SIZE 200
48 #define TEST_FILE_LINES 4
49
50 extern BOOL verbose_flagged;
51 extern BOOL status_flagged;
52 //extern TCHAR test_buffer[TEST_BUFFER_SIZE];
53
54 static TCHAR test_buffer[TEST_BUFFER_SIZE];
55
56 static TCHAR dos_data[] = _T("line1: this is a bunch of readable text.\r\n")\
57 _T("line2: some more printable text and punctuation !@#$%^&*()\r\n")\
58 _T("line3: followed up with some numerals 1234567890\r\n")\
59 _T("line4: done.\r\n");
60
61 static TCHAR nix_data[] = _T("line1: this is a bunch of readable text.\n")\
62 _T("line2: some more printable text and punctuation !@#$%^&*()\n")\
63 _T("line3: followed up with some numerals 1234567890\n")\
64 _T("line4: done.\n");
65
66 #ifdef UNICODE
67 #define TEST_B1_FILE_SIZE ((((sizeof(dos_data)/2)-1)+TEST_FILE_LINES)/2) // (166+4)/2=85
68 #define TEST_B2_FILE_SIZE (((sizeof(dos_data)/2)-1)*2) // (166*2) =332
69 #define TEST_B3_FILE_SIZE ((((sizeof(nix_data)/2)-1)+TEST_FILE_LINES)/2) // (162+4)/2=83
70 #define TEST_B4_FILE_SIZE (((sizeof(nix_data)/2)-1)*2) // (162*2) =324
71 #else /*UNICODE*/
72 #define TEST_B1_FILE_SIZE (sizeof(dos_data)-1+TEST_FILE_LINES) // (166+4)=170
73 #define TEST_B2_FILE_SIZE (sizeof(dos_data)-1-TEST_FILE_LINES) // (166-4)=162
74 #define TEST_B3_FILE_SIZE (sizeof(nix_data)-1+TEST_FILE_LINES) // (162+4)=166
75 #define TEST_B4_FILE_SIZE (sizeof(nix_data)-1) // (162) =162
76 #endif /*UNICODE*/
77
78
79
80
81
82 static BOOL create_output_file(TCHAR* file_name, TCHAR* file_mode, TCHAR* file_data)
83 {
84 BOOL result = FALSE;
85 FILE *file = _tfopen(file_name, file_mode);
86 if (file != NULL) {
87 #ifndef _NO_NEW_DEPENDS_
88 if (_fputts(file_data, file) != _TEOF) {
89 result = TRUE;
90 } else {
91 _tprintf(_T("ERROR: failed to write data to file \"%s\"\n"), file_name);
92 _tprintf(_T("ERROR: ferror returned %d\n"), ferror(file));
93 }
94 #endif
95 fclose(file);
96 } else {
97 _tprintf(_T("ERROR: failed to open/create file \"%s\" for output\n"), file_name);
98 _tprintf(_T("ERROR: ferror returned %d\n"), ferror(file));
99 }
100 return result;
101 }
102
103 static BOOL verify_output_file(TCHAR* file_name, TCHAR* file_mode, TCHAR* file_data)
104 {
105 int error_code;
106 int offset = 0;
107 int line_num = 0;
108 BOOL result = FALSE;
109 BOOL error_flagged = FALSE;
110 FILE* file = _tfopen(file_name, file_mode);
111 if (file == NULL) {
112 _tprintf(_T("ERROR: (%s) Can't open file for reading\n"), file_name);
113 _tprintf(_T("ERROR: ferror returned %d\n"), ferror(file));
114 return FALSE;
115 } else if (status_flagged) {
116 _tprintf(_T("STATUS: (%s) opened file for reading\n"), file_name);
117 }
118 #ifndef _NO_NEW_DEPENDS_
119 while (_fgetts(test_buffer, TEST_BUFFER_SIZE, file)) {
120 int length = _tcslen(test_buffer);
121 int req_len = _tcschr(file_data+offset, _T('\n')) - (file_data+offset) + 1;
122
123 ++line_num;
124 if (length > req_len) {
125 _tprintf(_T("ERROR: read excess bytes from line %d, length %d, but expected %d\n"), line_num, length, req_len);
126 error_flagged = TRUE;
127 break;
128 }
129 if (status_flagged) {
130 _tprintf(_T("STATUS: Verifying %d bytes read from line %d\n"), length, line_num);
131 }
132 if (_tcsncmp(test_buffer, file_data+offset, length - 1) == 0) {
133 result = TRUE;
134 } else {
135 if (status_flagged) {
136 int i;
137 _tprintf(_T("WARNING: (%s) failed to verify file\n"), file_name);
138 for (i = 0; i < length; i++) {
139 if (file_data[offset+i] != test_buffer[i]) {
140 _tprintf(_T("line %d, offset %d expected: 0x%04x found: 0x%04x\n"), line_num, i, (int)file_data[offset+i], (int)test_buffer[i]);
141 }
142 }
143 _tprintf(_T("\n"));
144 } else {
145 error_flagged = TRUE;
146 }
147 }
148 offset += length;
149 }
150 error_code = ferror(file);
151 if (error_code) {
152 _tprintf(_T("ERROR: (%s) ferror returned %d after reading\n"), file_name, error_code);
153 perror("Read error");
154 }
155 if (!line_num) {
156 _tprintf(_T("ERROR: (%s) failed to read from file\n"), file_name);
157 }
158 if (error_flagged == TRUE) {
159 _tprintf(_T("ERROR: (%s) failed to verify file\n"), file_name);
160 result = FALSE;
161 }
162 #endif
163 fclose(file);
164 return result;
165 }
166
167 static int create_test_file(TCHAR* file_name, TCHAR* write_mode, TCHAR* read_mode, TCHAR* file_data)
168 {
169 if (status_flagged) {
170 _tprintf(_T("STATUS: Attempting to create output file %s\n"), file_name);
171 }
172 if (create_output_file(file_name, write_mode, file_data)) {
173 if (status_flagged) {
174 _tprintf(_T("STATUS: Attempting to verify output file %s\n"), file_name);
175 }
176 if (verify_output_file(file_name, read_mode, file_data)) {
177 if (status_flagged) {
178 _tprintf(_T("SUCCESS: %s verified ok\n"), file_name);
179 }
180 } else {
181 //_tprintf(_T("ERROR: failed to verify file %s\n"), file_name);
182 return 2;
183 }
184 } else {
185 _tprintf(_T("ERROR: failed to create file %s\n"), file_name);
186 return 1;
187 }
188 return 0;
189 }
190
191 static int check_file_size(TCHAR* file_name, TCHAR* file_mode, int expected)
192 {
193 int count = 0;
194 FILE* file;
195 TCHAR ch;
196 int error_code;
197
198 if (status_flagged) {
199 //_tprintf(_T("STATUS: (%s) checking for %d bytes in %s mode\n"), file_name, expected, _tcschr(file_mode, _T('b')) ? _T("binary") : _T("text"));
200 _tprintf(_T("STATUS: (%s) checking for %d bytes with mode %s\n"), file_name, expected, file_mode);
201 }
202 file = _tfopen(file_name, file_mode);
203 if (file == NULL) {
204 _tprintf(_T("ERROR: (%s) failed to open file for reading\n"), file_name);
205 return 1;
206 }
207 while ((ch = _fgettc(file)) != _TEOF) {
208 if (verbose_flagged) {
209 _tprintf(_THEX_FORMAT, ch);
210 }
211 ++count;
212 }
213 error_code = ferror(file);
214 if (error_code) {
215 _tprintf(_T("ERROR: (%s) ferror returned %d after reading\n"), file_name, error_code);
216 perror("Read error");
217 }
218
219 if (verbose_flagged) {
220 // _puttc(_T('\n'), stdout);
221 }
222 fclose(file);
223 if (count == expected) {
224 if (status_flagged) {
225 _tprintf(_T("PASSED: (%s) read %d bytes\n"), file_name, count);
226 }
227 } else {
228 _tprintf(_T("FAILED: (%s) read %d bytes but expected %d using mode \"%s\"\n"), file_name, count, expected, file_mode);
229 }
230 return (count == expected) ? 0 : -1;
231 }
232
233 static int test_console_io(void)
234 {
235 #ifndef _NO_NEW_DEPENDS_
236 TCHAR buffer[81];
237 TCHAR ch;
238 int i, j;
239
240 //printf("Enter a line for echoing:\n");
241 _tprintf(_T("Enter a line for echoing:\n"));
242
243 //for (i = 0; (i < 80) && ((ch = _gettchar()) != _TEOF) && (ch != _T('\n')); i++) {
244 for (i = 0; (i < 80) && ((ch = _gettc(stdin)) != _TEOF) && (ch != _T('\n')); i++) {
245 buffer[i] = (TCHAR)ch;
246 }
247 buffer[i] = _T('\0');
248 for (j = 0; j < i; j++) {
249 _puttc(buffer[j], stdout);
250 }
251 _puttc(_T('\n'), stdout);
252 _tprintf(_T("%s\n"), buffer);
253 #endif
254 return 0;
255 }
256
257 static int test_console_getchar(void)
258 {
259 int result = 0;
260 #ifndef _NO_NEW_DEPENDS_
261 TCHAR ch;
262
263 //printf("Enter lines for dumping or <ctrl-z><nl> to finish:\n");
264 _tprintf(_T("Enter lines for dumping or <ctrl-z><nl> to finish:\n"));
265
266 //while ((ch = _gettchar()) != _TEOF) {
267 while ((ch = _gettc(stdin)) != _TEOF) {
268 _tprintf(_THEX_FORMAT, ch);
269 //printf("0x%04x ", ch);
270 }
271 #endif
272 return result;
273 }
274
275 static int test_console_putch(void)
276 {
277 int result = 0;
278 //TCHAR ch;
279
280 _putch('1');
281 _putch('@');
282 _putch('3');
283 _putch(':');
284 _putch('\n');
285 _putch('a');
286 _putch('B');
287 _putch('c');
288 _putch(':');
289 _putch('\n');
290
291
292 return result;
293 }
294
295 static int test_unlink_files(void)
296 {
297 int result = 0;
298
299 //printf("sizeof dos_data: %d\n", sizeof(dos_data));
300 //printf("sizeof nix_data: %d\n", sizeof(nix_data));
301
302 result |= _tunlink(_T("binary.dos"));
303 result |= _tunlink(_T("binary.nix"));
304 result |= _tunlink(_T("text.dos"));
305 result |= _tunlink(_T("text.nix"));
306 return result;
307 }
308
309 static int test_text_fileio(TCHAR* file_name, TCHAR* file_data, int tsize, int bsize)
310 {
311 int result = 0;
312
313 result = create_test_file(file_name, _T("w"), _T("r"), file_data);
314 result = check_file_size(file_name, _T("r"), tsize);
315 result = check_file_size(file_name, _T("rb"), bsize);
316 return result;
317 }
318
319 static int test_binary_fileio(TCHAR* file_name, TCHAR* file_data, int tsize, int bsize)
320 {
321 int result = 0;
322
323 result = create_test_file(file_name, _T("wb"), _T("rb"), file_data);
324 result = check_file_size(file_name, _T("r"), tsize);
325 result = check_file_size(file_name, _T("rb"), bsize);
326 return result;
327 }
328
329 static int test_files(int test_num, char* type)
330 {
331 int result = 0;
332
333 printf("performing test: %d (%s)\n", test_num, type);
334
335 switch (test_num) {
336 case 1:
337 result = test_text_fileio(_T("text.dos"), dos_data, 166, TEST_B1_FILE_SIZE);
338 break;
339 case 2:
340 result = test_binary_fileio(_T("binary.dos"), dos_data, TEST_B2_FILE_SIZE, 166);
341 break;
342 case 3:
343 result = test_text_fileio(_T("text.nix"), nix_data, 162, TEST_B3_FILE_SIZE);
344 break;
345 case 4:
346 result = test_binary_fileio(_T("binary.nix"), nix_data, TEST_B4_FILE_SIZE, 162);
347 break;
348 case 5:
349 result = test_console_io();
350 break;
351 case 6:
352 result = test_console_getchar();
353 break;
354 case 7:
355 result = test_console_putch();
356 break;
357 case -1:
358 result = test_unlink_files();
359 break;
360 default:
361 _tprintf(_T("no test number selected\n"));
362 break;
363 }
364 return result;
365 }
366
367 #if 1
368
369 #else
370
371 static int test_files(int test_num, char* type)
372 {
373 int result = 0;
374
375 printf("performing test: %d (%s)\n", test_num, type);
376
377 switch (test_num) {
378 case 1:
379 result = create_test_file(_T("text.dos"), _T("w"), _T("r"), dos_data);
380 break;
381 case 2:
382 result = create_test_file(_T("binary.dos"), _T("wb"), _T("rb"), dos_data);
383 break;
384 case 3:
385 result = create_test_file(_T("text.nix"), _T("w"), _T("r"), nix_data);
386 break;
387 case 4:
388 result = create_test_file(_T("binary.nix"), _T("wb"), _T("rb"), nix_data);
389 break;
390
391 case 5:
392 result = check_file_size(_T("text.dos"), _T("r"), 166);
393 result = check_file_size(_T("text.dos"), _T("rb"), TEST_B1_FILE_SIZE);
394 break;
395 case 6:
396 result = check_file_size(_T("binary.dos"), _T("r"), TEST_B2_FILE_SIZE);
397 result = check_file_size(_T("binary.dos"), _T("rb"), 166);
398 break;
399 case 7:
400 result = check_file_size(_T("text.nix"), _T("r"), 162);
401 result = check_file_size(_T("text.nix"), _T("rb"), TEST_B3_FILE_SIZE);
402 break;
403 case 8:
404 result = check_file_size(_T("binary.nix"), _T("r"), TEST_B4_FILE_SIZE);
405 result = check_file_size(_T("binary.nix"), _T("rb"), 162);
406 break;
407
408 case 9:
409 result = test_console_io();
410 break;
411 case 0:
412 result = test_console_getchar();
413 break;
414 case -1:
415 result = test_unlink_files();
416 break;
417 default:
418 _tprintf(_T("no test number selected\n"));
419 break;
420 }
421 return result;
422 }
423
424 #endif