1 /*
2 * Copyright (c) 2009 Philip Guenther
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * Test whether the various stdio functions set the stream orientation
32 * ("width") as they should
33 */
34
35 #include <sys/types.h>
36 #include <err.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <wchar.h>
43
44 char filename[] = "/tmp/fwide.XXXXXXXXXX";
45
46 FILE *dup_stdout = NULL;
47 int failures = 0;
48
49 void
fail(int line,int r,char const * expect,char const * test)50 fail(int line, int r, char const *expect, char const *test)
51 {
52 failures++;
53 fprintf(dup_stdout,
54 "FAIL: %d: fwide returned %d, expected %s 0 after %s\n",
55 line, r, expect, test);
56 }
57
58 FILE *
setup(int line)59 setup(int line)
60 {
61 FILE *f;
62 int r;
63
64 if ((f = fopen(filename, "r+")) == NULL)
65 err(2, "fopen");
66 if ((r = fwide(f, 0)) != 0)
67 fail(line, r, "==", "fopen");
68 return (f);
69 }
70
71 FILE *
setup_std(FILE * std,int line)72 setup_std(FILE *std, int line)
73 {
74 int r;
75
76 if (freopen(filename, "r+", std) == NULL)
77 err(2, "freopen");
78 if ((r = fwide(std, 0)) != 0)
79 fail(line, r, "==", "freopen");
80 return (std);
81 }
82
83 #define TEST_(x, op) \
84 do { \
85 f = setup(__LINE__); \
86 x; \
87 if (!((r = fwide(f, 0)) op 0)) \
88 fail(__LINE__, r, #op, #x); \
89 fclose(f); \
90 } while (0)
91
92 #define TEST_STD_(std, x, op) \
93 do { \
94 f = setup_std(std, __LINE__); \
95 x; \
96 if (!((r = fwide(f, 0)) op 0)) \
97 fail(__LINE__, r, #op, #x); \
98 } while (0)
99
100 #define TEST_UNCHANGED(x) TEST_(x, ==)
101 #define TEST_NARROW(x) TEST_(x, <)
102 #define TEST_WIDE(x) TEST_(x, >)
103 #define TEST_UNCHANGED_STD(std, x) TEST_STD_(std, x, ==)
104 #define TEST_NARROW_STD(std, x) TEST_STD_(std, x, <)
105 #define TEST_WIDE_STD(std, x) TEST_STD_(std, x, >)
106
107 int
main(int argc,char * argv[])108 main(int argc, char *argv[])
109 {
110 char buffer[BUFSIZ];
111 wchar_t wbuffer[BUFSIZ];
112 char *buf;
113 wchar_t *wbuf;
114 FILE *f;
115 fpos_t pos;
116 size_t size;
117 int fd, r;
118 char c;
119 wchar_t wc;
120
121 if ((fd = dup(1)) == -1)
122 err(2, "dup");
123 if ((dup_stdout = fdopen(fd, "w")) == NULL)
124 err(2, "fdopen");
125 if ((fd = mkstemp(filename)) == -1)
126 err(2, "mkstemp");
127 if (write(fd, "0123456789\n\n", 12) != 12 || close(fd))
128 err(2, "write + close");
129
130 /* status */
131 TEST_UNCHANGED(fwide(f, 0));
132 TEST_NARROW(fwide(f, -1));
133 TEST_WIDE(fwide(f, 1));
134 TEST_UNCHANGED(feof(f));
135 TEST_UNCHANGED(ferror(f));
136 TEST_UNCHANGED(fileno(f));
137 TEST_UNCHANGED(clearerr(f));
138
139 /* flush and purge */
140 TEST_UNCHANGED(fflush(f));
141
142 /* positioning */
143 TEST_UNCHANGED(fgetpos(f, &pos));
144 TEST_UNCHANGED(fgetpos(f, &pos); fsetpos(f, &pos));
145 TEST_UNCHANGED(ftell(f));
146 TEST_UNCHANGED(ftello(f));
147 TEST_UNCHANGED(fseek(f, 1, SEEK_CUR));
148 TEST_UNCHANGED(fseek(f, 1, SEEK_SET));
149 TEST_UNCHANGED(fseek(f, 1, SEEK_END));
150 TEST_UNCHANGED(fseeko(f, 1, SEEK_CUR));
151 TEST_UNCHANGED(fseeko(f, 1, SEEK_SET));
152 TEST_UNCHANGED(fseeko(f, 1, SEEK_END));
153 TEST_UNCHANGED(rewind(f));
154
155 /* buffering */
156 TEST_UNCHANGED(setbuf(f, NULL));
157 TEST_UNCHANGED(setbuf(f, buffer));
158 TEST_UNCHANGED(setvbuf(f, buffer, _IONBF, BUFSIZ));
159 TEST_UNCHANGED(setvbuf(f, buffer, _IOLBF, BUFSIZ));
160 TEST_UNCHANGED(setvbuf(f, buffer, _IOFBF, BUFSIZ));
161 TEST_UNCHANGED(setvbuf(f, NULL, _IONBF, 0));
162 TEST_UNCHANGED(setvbuf(f, NULL, _IOLBF, 0));
163 TEST_UNCHANGED(setvbuf(f, NULL, _IOFBF, 0));
164 TEST_UNCHANGED(setbuffer(f, NULL, 0));
165 TEST_UNCHANGED(setbuffer(f, buffer, BUFSIZ));
166 TEST_UNCHANGED(setlinebuf(f));
167
168 /* locking */
169 TEST_UNCHANGED(flockfile(f);funlockfile(f));
170 TEST_UNCHANGED(ftrylockfile(f);funlockfile(f));
171
172 /* input */
173 TEST_NARROW(getc(f));
174 TEST_NARROW(getc_unlocked(f));
175 TEST_NARROW(fgetc(f));
176 TEST_NARROW(c = fgetc(f); ungetc(c, f));
177 TEST_NARROW(fgets(buffer, BUFSIZ, f));
178 TEST_NARROW(fscanf(f, "%s\n", buffer));
179
180 /* output */
181 TEST_NARROW(putc('c', f));
182 TEST_NARROW(putc_unlocked('c', f));
183 TEST_NARROW(fputc('c', f));
184 TEST_NARROW(fputs("foo", f));
185 TEST_NARROW(fprintf(f, "%s\n", "foo"));
186
187 /* input from stdin */
188 TEST_NARROW_STD(stdin, getchar());
189 TEST_NARROW_STD(stdin, getchar_unlocked());
190 TEST_NARROW_STD(stdin, scanf("%s\n", buffer));
191
192 /* output to stdout */
193 TEST_NARROW_STD(stdout, putchar('c'));
194 TEST_NARROW_STD(stdout, putchar_unlocked('c'));
195 TEST_NARROW_STD(stdout, puts("foo"));
196 TEST_NARROW_STD(stdout, printf("foo"));
197
198 /* word-size ops */
199 /*
200 * fread and fwrite are specified as being implemented in
201 * terms of fgetc() and fputc() and therefore must set the
202 * stream orientation to narrow.
203 */
204 TEST_NARROW(fread(buffer, 4, BUFSIZ / 4, f));
205 TEST_NARROW(fwrite(buffer, 4, BUFSIZ / 4, f));
206
207 /*
208 * getw() and putw() aren't specified anywhere but logically
209 * should behave the same as fread/fwrite. Not all OSes agree:
210 * Solaris 10 has them not changing the orientation.
211 */
212 TEST_NARROW(getw(f));
213 TEST_NARROW(putw(1234, f));
214
215
216 /* WIDE CHAR TIME! */
217
218 /* input */
219 TEST_WIDE(getwc(f));
220 TEST_WIDE(fgetwc(f));
221 TEST_WIDE(wc = fgetwc(f); ungetwc(wc, f));
222 TEST_WIDE(fgetws(wbuffer, BUFSIZ, f));
223 TEST_WIDE(fwscanf(f, L"%s\n", wbuffer));
224
225 /* output */
226 TEST_WIDE(putwc(L'c', f));
227 TEST_WIDE(fputwc(L'c', f));
228 TEST_WIDE(fputws(L"foo", f));
229 TEST_WIDE(fwprintf(f, L"%s\n", L"foo"));
230
231 /* input from stdin */
232 TEST_WIDE_STD(stdin, getwchar());
233 TEST_WIDE_STD(stdin, wscanf(L"%s\n", wbuffer));
234
235 /* output to stdout */
236 TEST_WIDE_STD(stdout, putwchar(L'c'));
237 TEST_WIDE_STD(stdout, wprintf(L"foo"));
238
239
240 /* memory streams */
241 f = open_memstream(&buf, &size);
242 if (!((r = fwide(f, 0)) < 0))
243 fail(__LINE__, r, "<", "open_memstream()");
244 fclose(f);
245 f = open_wmemstream(&wbuf, &size);
246 if (f != NULL && !((r = fwide(f, 0)) > 0))
247 fail(__LINE__, r, ">", "open_wmemstream()");
248 fclose(f);
249
250
251 /* random stuff? */
252 TEST_UNCHANGED_STD(stderr, perror("foo"));
253
254 remove(filename);
255 if (failures)
256 exit(1);
257 exit(0);
258 }
259