1/* Verify that ftell returns the correct value after a read and a write on a
2 file opened in a+ mode.
3 Copyright (C) 2014-2022 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25#include <locale.h>
26#include <wchar.h>
27
28/* data points to either char_data or wide_data, depending on whether we're
29 testing regular file mode or wide mode respectively. Similarly,
30 fputs_func points to either fputs or fputws. data_len keeps track of the
31 length of the current data and file_len maintains the current file
32 length. */
33#define BUF_LEN 4
34static void *buf;
35static char char_buf[BUF_LEN];
36static wchar_t wide_buf[BUF_LEN];
37static const void *data;
38static const char *char_data = "abcdefghijklmnopqrstuvwxyz";
39static const wchar_t *wide_data = L"abcdefghijklmnopqrstuvwxyz";
40static size_t data_len;
41static size_t file_len;
42
43typedef int (*fputs_func_t) (const void *data, FILE *fp);
44fputs_func_t fputs_func;
45
46typedef void *(*fgets_func_t) (void *s, int size, FILE *stream);
47fgets_func_t fgets_func;
48
49static int do_test (void);
50
51#define TEST_FUNCTION do_test ()
52#include "../test-skeleton.c"
53
54static FILE *
55init_file (const char *filename)
56{
57 FILE *fp = fopen (filename, "w");
58 if (fp == NULL)
59 {
60 printf (format: "fopen: %m\n");
61 return NULL;
62 }
63
64 int written = fputs_func (data, fp);
65
66 if (written == EOF)
67 {
68 printf (format: "fputs failed to write data\n");
69 fclose (fp);
70 return NULL;
71 }
72
73 file_len = data_len;
74
75 fclose (fp);
76
77 fp = fopen (filename, "a+");
78 if (fp == NULL)
79 {
80 printf (format: "fopen(a+): %m\n");
81 return NULL;
82 }
83
84 return fp;
85}
86
87static int
88do_one_test (const char *filename)
89{
90 FILE *fp = init_file (filename);
91
92 if (fp == NULL)
93 return 1;
94
95 void *ret = fgets_func (buf, BUF_LEN, fp);
96
97 if (ret == NULL)
98 {
99 printf (format: "read failed: %m\n");
100 fclose (fp);
101 return 1;
102 }
103
104 int written = fputs_func (data, fp);
105
106 if (written == EOF)
107 {
108 printf (format: "fputs failed to write data\n");
109 fclose (fp);
110 return 1;
111 }
112
113 file_len += data_len;
114
115 long off = ftell (stream: fp);
116
117 if (off != file_len)
118 {
119 printf (format: "Incorrect offset %ld, expected %zu\n", off, file_len);
120 fclose (fp);
121 return 1;
122 }
123 else
124 printf (format: "Correct offset %ld after write.\n", off);
125
126 return 0;
127}
128
129/* Run the tests for regular files and wide mode files. */
130static int
131do_test (void)
132{
133 int ret = 0;
134 char *filename;
135 int fd = create_temp_file (base: "tst-ftell-append-tmp.", filename: &filename);
136
137 if (fd == -1)
138 {
139 printf (format: "create_temp_file: %m\n");
140 return 1;
141 }
142
143 close (fd: fd);
144
145 /* Tests for regular files. */
146 puts (s: "Regular mode:");
147 fputs_func = (fputs_func_t) fputs;
148 fgets_func = (fgets_func_t) fgets;
149 data = char_data;
150 buf = char_buf;
151 data_len = strlen (char_data);
152 ret |= do_one_test (filename);
153
154 /* Tests for wide files. */
155 puts (s: "Wide mode:");
156 if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
157 {
158 printf (format: "Cannot set en_US.UTF-8 locale.\n");
159 return 1;
160 }
161 fputs_func = (fputs_func_t) fputws;
162 fgets_func = (fgets_func_t) fgetws;
163 data = wide_data;
164 buf = wide_buf;
165 data_len = wcslen (s: wide_data);
166 ret |= do_one_test (filename);
167
168 return ret;
169}
170

source code of glibc/libio/tst-ftell-append.c