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 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 * 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 * 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 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