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