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
46char filename[] = "/tmp/fwide.XXXXXXXXXX";
47
48FILE *dup_stdout = NULL;
49int failures = 0;
50
51void
52fail(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
60FILE *
61setup(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
73FILE *
74setup_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
109int
110main(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