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