]>
Commit | Line | Data |
---|---|---|
fdb7d390 | 1 | /* fmemopen tests for append and read mode. |
dff8da6b | 2 | Copyright (C) 2015-2024 Free Software Foundation, Inc. |
fdb7d390 AZ |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
fdb7d390 AZ |
18 | |
19 | #include <assert.h> | |
20 | #include <stdio.h> | |
21 | #include <string.h> | |
22 | #include <sys/types.h> | |
23 | ||
a84dcb4b FB |
24 | #include <support/xstdio.h> |
25 | ||
fdb7d390 AZ |
26 | static void |
27 | print_buffer (const char *s, size_t n) | |
28 | { | |
29 | size_t i; | |
b65b205f | 30 | printf ("{"); |
fdb7d390 | 31 | for (i=0; i<n; ++i) |
b65b205f AZ |
32 | { |
33 | printf ("0x%02X (%c)", s[i], s[i]); | |
34 | if (i != n) | |
35 | printf (", "); | |
36 | } | |
fdb7d390 AZ |
37 | } |
38 | ||
7f0d9e61 | 39 | /* This test check append mode initial position (a/a+) based on POSIX definition |
fdb7d390 AZ |
40 | (BZ#6544 and BZ#13151). */ |
41 | static int | |
42 | do_test_write_append (const char *mode) | |
43 | { | |
44 | char buf[32] = "testing buffer"; | |
45 | char exp[32] = "testing bufferXX"; | |
46 | ||
47 | FILE *fp = fmemopen (buf, sizeof (buf), mode); | |
48 | ||
49 | fflush (fp); | |
50 | fprintf (fp, "X"); | |
51 | fseek (fp, 0, SEEK_SET); | |
52 | fprintf (fp, "X"); | |
53 | fclose (fp); | |
54 | ||
55 | if (strcmp (buf, exp) != 0) | |
56 | { | |
57 | printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp); | |
58 | return 1; | |
59 | } | |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
7f0d9e61 | 64 | /* This test check append mode initial position (a/a+) based on POSIX definition |
fdb7d390 AZ |
65 | (BZ#6544 and BZ#13151) for buffer without null byte end. */ |
66 | static int | |
67 | do_test_write_append_without_null (const char *mode) | |
68 | { | |
69 | char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; | |
70 | char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; | |
71 | ||
72 | /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be | |
73 | the size argument. */ | |
74 | FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a"); | |
75 | ||
76 | fflush (fp); | |
77 | fputc (0x70, fp); | |
78 | fseek (fp, 0, SEEK_SET); | |
79 | fputc (0x70, fp); | |
80 | fputc (0x70, fp); | |
81 | fclose (fp); | |
82 | ||
83 | /* POSIX also states that a write operation on the stream shall not advance | |
84 | the current buffer size beyond the size given in fmemopen, so the string | |
85 | should be same. */ | |
86 | if (memcmp (buf, exp, sizeof (buf)) != 0) | |
87 | { | |
88 | printf ("%s: check failed: ", __FUNCTION__); | |
89 | print_buffer (buf, sizeof (buf)); | |
90 | printf ("!= "); | |
91 | print_buffer (exp, sizeof (exp)); | |
92 | printf ("\n"); | |
93 | return 1; | |
94 | } | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
7f0d9e61 | 99 | /* This test check for initial position and seek value for fmemopen objects |
fdb7d390 AZ |
100 | opened with append mode. */ |
101 | static int | |
102 | do_test_read_append (void) | |
103 | { | |
104 | char buf[32] = "testing buffer"; | |
105 | size_t buflen = strlen (buf); | |
106 | long fpos; | |
107 | ||
108 | /* POSIX defines for 'a+' the initial position is the first null byte. */ | |
109 | FILE *fp = fmemopen (buf, sizeof (buf), "a+"); | |
110 | ||
111 | fpos = ftell (fp); | |
112 | if (fpos != buflen) | |
113 | { | |
114 | printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %zu\n", | |
115 | __FUNCTION__, fpos, buf, buflen); | |
116 | fclose (fp); | |
117 | return 1; | |
118 | } | |
119 | ||
120 | fseek (fp, 0, SEEK_END); | |
121 | ||
122 | if (fpos != buflen) | |
123 | { | |
124 | printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %zu\n", | |
125 | __FUNCTION__, fpos, buf, buflen); | |
126 | fclose (fp); | |
127 | return 1; | |
128 | } | |
129 | fclose (fp); | |
130 | ||
131 | /* Check if attempting to read past the current size, defined as strlen (buf) | |
132 | yield an EOF. */ | |
133 | fp = fmemopen (buf, sizeof (buf), "a+"); | |
134 | if (getc(fp) != EOF) | |
135 | { | |
136 | printf ("%s: getc(fp) != EOF\n", __FUNCTION__); | |
137 | fclose (fp); | |
138 | return -1; | |
139 | } | |
140 | ||
141 | fclose (fp); | |
142 | ||
143 | return 0; | |
144 | } | |
145 | ||
146 | /* This test check for fseek (SEEK_END) using negative offsets (BZ#14292). The | |
147 | starting position of descriptor is different base on the opening mode. */ | |
148 | static int | |
149 | do_test_read_seek_neg (const char *mode, const char *expected) | |
150 | { | |
151 | char buf[] = "abcdefghijklmnopqrstuvxz0123456789"; | |
152 | char tmp[10]; | |
153 | size_t tmps = sizeof (tmps); | |
154 | long offset = -11; | |
155 | ||
156 | FILE *fp = fmemopen (buf, sizeof (buf), mode); | |
157 | fseek (fp, offset, SEEK_END); | |
a84dcb4b | 158 | xfread (tmp, tmps, 1, fp); |
fdb7d390 AZ |
159 | |
160 | if (memcmp (tmp, expected, tmps) != 0) | |
161 | { | |
162 | printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n", | |
163 | __FUNCTION__, mode, offset); | |
164 | printf (" returned: "); | |
165 | print_buffer (tmp, tmps); | |
166 | printf ("\n"); | |
167 | printf (" expected: "); | |
168 | print_buffer (expected, tmps); | |
169 | printf ("\n"); | |
170 | return 1; | |
171 | } | |
172 | ||
173 | fclose (fp); | |
174 | ||
175 | return 0; | |
176 | } | |
177 | ||
178 | static int | |
179 | do_test_read_seek_negative (void) | |
180 | { | |
181 | int ret = 0; | |
182 | ||
183 | /* 'r' and 'w' modes defines the initial position at the buffer start and | |
184 | seek with SEEK_END shall seek relative to its size give in fmemopen | |
185 | call. The expected tmp result is 0 to 9 *without* the ending null */ | |
186 | ret += do_test_read_seek_neg ("r", "0123456789"); | |
187 | /* 'a+' mode sets the initial position at the first null byte in buffer and | |
188 | SEEK_END shall seek relative to its size as well. The expected result is | |
189 | z012345678, since SEEK_END plus a+ start at '\0', not size. */ | |
190 | ret += do_test_read_seek_neg ("a+", "z012345678"); | |
191 | ||
192 | return ret; | |
193 | } | |
194 | ||
b65b205f AZ |
195 | static int |
196 | do_test_write_append_2 (const char *str) | |
197 | { | |
198 | char buf[10]; | |
199 | size_t strn = strlen (str); | |
200 | strcpy (buf, str); | |
201 | ||
202 | FILE *fp = fmemopen (buf, sizeof (buf), "a+"); | |
203 | size_t r = ftell (fp); | |
204 | size_t e = strlen (buf); | |
205 | if (r != e) | |
206 | { | |
207 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e); | |
208 | return 1; | |
209 | } | |
210 | ||
211 | if (fseek (fp, 0, SEEK_SET) == -1) | |
212 | { | |
213 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
214 | return 1; | |
215 | } | |
216 | ||
217 | int gr; | |
218 | for (int i=0; i<strn; ++i) | |
219 | { | |
220 | if ((gr = getc (fp)) != str[i]) | |
221 | { | |
222 | printf ("%s: getc failed returned %d, expected %d\n", __FUNCTION__, | |
223 | gr, str[i]); | |
224 | return 1; | |
225 | } | |
226 | } | |
227 | if ((gr = getc (fp)) != EOF) | |
228 | { | |
229 | printf ("%s: getc failed returned %d, expected EOF\n", __FUNCTION__, | |
230 | gr); | |
231 | return 1; | |
232 | } | |
233 | ||
234 | if (fseek (fp, e+1, SEEK_SET) == -1) | |
235 | { | |
236 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
237 | return 1; | |
238 | } | |
239 | ||
240 | if ((r = ftell (fp)) != e+1) | |
241 | { | |
242 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); | |
243 | return 1; | |
244 | } | |
245 | ||
246 | if ((gr = getc (fp)) != EOF) | |
247 | { | |
248 | printf ("%s: getc failed returned %i\n", __FUNCTION__, gr); | |
249 | return 1; | |
250 | } | |
251 | ||
252 | /* Check if internal position is not changed with a getc returning EOF. */ | |
253 | if ((r = ftell (fp)) != e+1) | |
254 | { | |
255 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); | |
256 | return 1; | |
257 | } | |
258 | ||
259 | if (fseek (fp, 0, SEEK_CUR) == -1) | |
260 | { | |
261 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
262 | return 1; | |
263 | } | |
264 | ||
265 | /* This should be overwritten by fprintf + fflush. */ | |
266 | buf[e+2] = 'X'; | |
267 | ||
268 | if ((r = fprintf (fp, "%d", 101)) != 3) | |
269 | { | |
270 | printf ("%s: fprintf returned %zu, expected %d\n", __FUNCTION__, r, 3); | |
271 | return 1; | |
272 | } | |
273 | ||
274 | fflush (fp); | |
275 | ||
276 | /* Check if internal position is changed by 3 (strlen of '101'). */ | |
277 | if ((r = ftell (fp)) != e+3) | |
278 | { | |
279 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+3); | |
280 | return 1; | |
281 | } | |
282 | ||
283 | char exp[20]; | |
284 | sprintf (exp, "%s%d", str, 101); | |
285 | if (memcmp (buf, exp, strlen (exp)) != 0) | |
286 | { | |
287 | printf ("%s: check failed:", __FUNCTION__); | |
288 | printf ("\nexpected: "); | |
289 | print_buffer (buf, sizeof (buf)); | |
290 | printf ("\nbuffer: "); | |
291 | print_buffer (exp, sizeof (exp)); | |
292 | printf ("\n"); | |
293 | return 1; | |
294 | } | |
295 | ||
296 | fclose(fp); | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
fdb7d390 AZ |
301 | static int |
302 | do_test (void) | |
303 | { | |
304 | int ret = 0; | |
305 | ||
306 | ret += do_test_write_append ("a"); | |
307 | ret += do_test_write_append_without_null ("a"); | |
308 | ret += do_test_write_append ("a+"); | |
309 | ret += do_test_write_append_without_null ("a+"); | |
310 | ||
311 | ret += do_test_read_append (); | |
312 | ||
313 | ret += do_test_read_seek_negative (); | |
314 | ||
b65b205f AZ |
315 | /* First test plus addend will fit in the define buffer of size 10. */ |
316 | ret += do_test_write_append_2 ("test"); | |
317 | /* The second test will also fit, but not the final '\0'. */ | |
318 | ret += do_test_write_append_2 ("testing"); | |
319 | ||
fdb7d390 AZ |
320 | return ret; |
321 | } | |
322 | ||
323 | #define TEST_FUNCTION do_test () | |
324 | #include "../test-skeleton.c" |