manual: glob: document the gl_flags field
[jlayton/glibc.git] / libio / tst-widetext.c
1 /* Test program for the wide character stream functions handling larger
2    amounts of text.
3    Copyright (C) 2000-2013 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Ulrich Drepper <drepper@cygnus.com>.
6
7    The GNU C 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    The GNU C 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 the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <assert.h>
22 #include <iconv.h>
23 #include <locale.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <wchar.h>
29
30 /* Approximate size of the file (must be larger).  */
31 #define SIZE 210000
32
33
34 int
35 main (void)
36 {
37   char name[] = "/tmp/widetext.out.XXXXXX";
38   char mbbuf[SIZE];
39   char mb2buf[SIZE];
40   wchar_t wcbuf[SIZE];
41   wchar_t wc2buf[SIZE];
42   size_t mbsize;
43   size_t wcsize;
44   int fd;
45   FILE *fp;
46   size_t n;
47   int res;
48   int status = 0;
49   wchar_t *wcp;
50
51   setlocale (LC_ALL, "de_DE.UTF-8");
52   printf ("locale used: %s\n\n", setlocale (LC_ALL, NULL));
53
54   /* Read the file into memory.  */
55   mbsize = fread (mbbuf, 1, SIZE, stdin);
56   if (mbsize == 0)
57     {
58       printf ("%u: cannot read input file from standard input: %m\n",
59               __LINE__);
60       exit (1);
61     }
62
63    printf ("INFO: input file has %Zd bytes\n", mbsize);
64
65   /* First convert the text to wide characters.  We use iconv here.  */
66   {
67     iconv_t cd;
68     char *inbuf = mbbuf;
69     size_t inleft = mbsize;
70     char *outbuf = (char *) wcbuf;
71     size_t outleft = sizeof (wcbuf);
72     size_t nonr;
73
74     cd = iconv_open ("WCHAR_T", "UTF-8");
75     if (cd == (iconv_t) -1)
76       {
77         printf ("%u: cannot get iconv descriptor for conversion to UCS4\n",
78                 __LINE__);
79         exit (1);
80       }
81
82     /* We must need only one call and there must be no losses.  */
83     nonr = iconv (cd, &inbuf, &inleft, &outbuf, &outleft);
84     if (nonr != 0 && nonr != (size_t) -1)
85       {
86         printf ("%u: iconv performed %Zd nonreversible conversions\n",
87                 __LINE__, nonr);
88         exit (1);
89       }
90
91     if  (nonr == (size_t) -1)
92       {
93         printf ("\
94 %u: iconv returned with %Zd and errno = %m (inleft: %Zd, outleft: %Zd)\n",
95                 __LINE__, nonr, inleft, outleft);
96         exit (1);
97       }
98
99     if (inleft != 0)
100       {
101         printf ("%u: iconv didn't convert all input\n", __LINE__);
102         exit (1);
103       }
104
105     iconv_close (cd);
106
107     if ((sizeof (wcbuf) - outleft) % sizeof (wchar_t) != 0)
108       {
109         printf ("%u: iconv converted not complete wchar_t\n", __LINE__);
110         exit (1);
111       }
112
113     wcsize = (sizeof (wcbuf) - outleft) / sizeof (wchar_t);
114     assert (wcsize + 1 <= SIZE);
115   }
116
117   /* Now that we finished the preparations, run the first test.  We
118      are writing the wide char data out and read it back in.  We write
119      and read single characters.  */
120
121   fd = mkstemp (name);
122   if (fd == -1)
123     {
124       printf ("%u: cannot open temporary file: %m\n", __LINE__);
125       exit (1);
126     }
127
128   unlink (name);
129
130   fp = fdopen (dup (fd), "w");
131   if (fp == NULL)
132     {
133       printf ("%u: fdopen of temp file for writing failed: %m\n", __LINE__);
134       exit (1);
135     }
136
137   for (n = 0; n < wcsize; ++n)
138     {
139       if (fputwc (wcbuf[n], fp) == WEOF)
140         {
141           printf ("%u: fputwc failed: %m\n", __LINE__);
142           exit (1);
143         }
144     }
145
146   res = fclose (fp);
147   if (res != 0)
148     {
149       printf ("%u: fclose after single-character writing failed (%d): %m\n",
150               __LINE__, res);
151       exit (1);
152     }
153
154   lseek (fd, SEEK_SET, 0);
155   fp = fdopen (dup (fd), "r");
156   if (fp == NULL)
157     {
158       printf ("%u: fdopen of temp file for reading failed: %m\n", __LINE__);
159       exit (1);
160     }
161
162   for (n = 0; n < wcsize; ++n)
163     {
164       wint_t wch = fgetwc (fp);
165       if (wch == WEOF)
166         {
167           printf ("%u: fgetwc failed (idx %Zd): %m\n", __LINE__, n);
168           exit (1);
169         }
170       wc2buf[n] = wch;
171     }
172
173   /* There should be nothing else.  */
174   if (fgetwc (fp) != WEOF)
175     {
176       printf ("%u: too many characters available with fgetwc\n", __LINE__);
177       status = 1;
178     }
179   else if (wmemcmp (wcbuf, wc2buf, wcsize) != 0)
180     {
181       printf ("%u: buffer read with fgetwc differs\n", __LINE__);
182       status = 1;
183     }
184
185   res = fclose (fp);
186   if (res != 0)
187     {
188       printf ("%u: fclose after single-character reading failed (%d): %m\n",
189               __LINE__, res);
190       exit (1);
191     }
192
193   /* Just make sure there are no two errors which hide each other, read the
194      file using the `char' functions.  */
195
196   lseek (fd, SEEK_SET, 0);
197   fp = fdopen (fd, "r");
198   if (fp == NULL)
199     {
200       printf ("%u: fdopen of temp file for reading failed: %m\n", __LINE__);
201       exit (1);
202     }
203
204   if (fread (mb2buf, 1, mbsize, fp) != mbsize)
205     {
206       printf ("%u: cannot read all of the temp file\n", __LINE__);
207       status = 1;
208     }
209   else
210     {
211       /* Make sure there is nothing left.  */
212       if (fgetc (fp) != EOF)
213         {
214           printf ("%u: more input available\n", __LINE__);
215           status = 1;
216         }
217
218       if (memcmp (mb2buf, mbbuf, mbsize) != 0)
219         {
220           printf ("%u: buffer written with fputwc differs\n", __LINE__);
221           status = 1;
222         }
223     }
224
225   res = fclose (fp);
226   if (res != 0)
227     {
228       printf ("%u: fclose after single-character reading failed (%d): %m\n",
229               __LINE__, res);
230       exit (1);
231     }
232
233   /* Now to reading and writing line-wise.  */
234
235   fd = mkstemp (strcpy (name, "/tmp/widetext.out.XXXXXX"));
236   if (fd == -1)
237     {
238       printf ("%u: cannot open temporary file: %m\n", __LINE__);
239       exit (1);
240     }
241
242   unlink (name);
243
244   fp = fdopen (dup (fd), "w");
245   if (fp == NULL)
246     {
247       printf ("%u: fdopen of temp file for writing failed: %m\n", __LINE__);
248       exit (1);
249     }
250
251   for (wcp = wcbuf; wcp < &wcbuf[wcsize]; )
252     {
253       wchar_t *wendp = wcschr (wcp, L'\n');
254
255       if (wendp != NULL)
256         {
257           /* Temporarily NUL terminate the line.  */
258           wchar_t save = wendp[1];
259           wendp[1] = L'\0';
260
261           fputws (wcp, fp);
262
263           wendp[1] = save;
264           wcp = &wendp[1];
265         }
266       else
267         {
268           fputws (wcp, fp);
269           wcp = wcschr (wcp, L'\0');
270           assert (wcp == &wcbuf[wcsize]);
271         }
272     }
273
274   res = fclose (fp);
275   if (res != 0)
276     {
277       printf ("%u: fclose after line-wise writing failed (%d): %m\n",
278               __LINE__, res);
279       exit (1);
280     }
281
282   lseek (fd, SEEK_SET, 0);
283   fp = fdopen (dup (fd), "r");
284   if (fp == NULL)
285     {
286       printf ("%u: fdopen of temp file for reading failed: %m\n", __LINE__);
287       exit (1);
288     }
289
290   for (wcp = wc2buf; wcp < &wc2buf[wcsize]; )
291     {
292       if (fgetws (wcp, &wc2buf[wcsize] - wcp + 1, fp) == NULL)
293         {
294           printf ("%u: short read using fgetws (only %Zd of %Zd)\n",
295                   __LINE__, wcp - wc2buf, wcsize);
296           status = 1;
297           break;
298         }
299       wcp = wcschr (wcp, L'\0');
300     }
301
302   if (wcp > &wc2buf[wcsize])
303     {
304       printf ("%u: fgetws read too much\n", __LINE__);
305       status = 1;
306     }
307   else if (fgetwc (fp) != WEOF)
308     {
309       /* There should be nothing else.  */
310       printf ("%u: too many characters available with fgetws\n", __LINE__);
311       status = 1;
312     }
313
314   if (wcp >= &wc2buf[wcsize] && wmemcmp (wcbuf, wc2buf, wcsize) != 0)
315     {
316       printf ("%u: buffer read with fgetws differs\n", __LINE__);
317       status = 1;
318     }
319
320   res = fclose (fp);
321   if (res != 0)
322     {
323       printf ("%u: fclose after single-character reading failed (%d): %m\n",
324               __LINE__, res);
325       exit (1);
326     }
327
328   /* Just make sure there are no two errors which hide each other, read the
329      file using the `char' functions.  */
330
331   lseek (fd, SEEK_SET, 0);
332   fp = fdopen (fd, "r");
333   if (fp == NULL)
334     {
335       printf ("%u: fdopen of temp file for reading failed: %m\n", __LINE__);
336       exit (1);
337     }
338
339   if (fread (mb2buf, 1, mbsize, fp) != mbsize)
340     {
341       printf ("%u: cannot read all of the temp file\n", __LINE__);
342       status = 1;
343     }
344   else
345     {
346       /* Make sure there is nothing left.  */
347       if (fgetc (fp) != EOF)
348         {
349           printf ("%u: more input available\n", __LINE__);
350           status = 1;
351         }
352
353       if (memcmp (mb2buf, mbbuf, mbsize) != 0)
354         {
355           printf ("%u: buffer written with fputws differs\n", __LINE__);
356           status = 1;
357         }
358     }
359
360   res = fclose (fp);
361   if (res != 0)
362     {
363       printf ("%u: fclose after single-character reading failed (%d): %m\n",
364               __LINE__, res);
365       exit (1);
366     }
367
368   return status;
369 }