1 : /* Copyright (c) 2007 James Antill -- See LICENSE file for terms. */
2 :
3 : #ifndef USTR_IO_H
4 : #error " You should have already included ustr-io.h, or just include ustr.h."
5 : #endif
6 :
7 : USTR_CONF_i_PROTO
8 : int ustrp__io_get(struct Ustr_pool *p, struct Ustr **ps1, FILE *fp,
9 : size_t minlen, size_t *got)
10 108 : {
11 108 : size_t olen = ustr_len(*ps1);
12 108 : size_t ret = 0;
13 :
14 54 : USTR_ASSERT(ps1 && ustrp__assert_valid(!!p, *ps1) && fp);
15 :
16 108 : if (!minlen)
17 : {
18 4 : if (got)
19 4 : *got = 0;
20 4 : return (USTR_TRUE);
21 : }
22 :
23 104 : if (!ustrp__add_undef(p, ps1, minlen))
24 4 : return (USTR_FALSE);
25 :
26 100 : ret = fread(ustr_wstr(*ps1) + olen, 1, minlen, fp);
27 100 : if (ret < minlen)
28 44 : ustrp__del(p, ps1, minlen - ret);
29 :
30 100 : if (got)
31 92 : *got = ret;
32 :
33 100 : return (ret > 0);
34 : }
35 : USTR_CONF_I_PROTO
36 : int ustr_io_get(struct Ustr **ps1, FILE *fp, size_t minlen, size_t *got)
37 24 : { return (ustrp__io_get(0, ps1, fp, minlen, got)); }
38 : USTR_CONF_I_PROTO
39 : int ustrp_io_get(struct Ustr_pool *p, struct Ustrp **ps1, FILE *fp,
40 : size_t minlen, size_t *got)
41 4 : {
42 4 : struct Ustr *tmp = &(*ps1)->s;
43 4 : int ret = ustrp__io_get(p, &tmp, fp, minlen, got);
44 4 : *ps1 = USTRP(tmp);
45 4 : return (ret);
46 : }
47 :
48 : USTR_CONF_i_PROTO
49 : int ustrp__io_getfile(struct Ustr_pool *p, struct Ustr **ps1, FILE *fp)
50 36 : {
51 36 : const size_t blksz = (1024 * 8) - (1 + 8 + 8 + 8 + sizeof(USTR_END_ALOCDx));
52 36 : size_t num = blksz;
53 36 : size_t got = 0;
54 :
55 : do
56 : { /* round up... not perfect as we'll be able to round up post add_undef */
57 80 : size_t sz = ustr_size(*ps1);
58 80 : size_t clen = ustr_len(*ps1);
59 :
60 80 : num = blksz;
61 80 : if (num < (sz - clen))
62 12 : num = sz - clen;
63 80 : } while (ustrp__io_get(p, ps1, fp, num, &got) && (got == num));
64 :
65 36 : return (feof(fp));
66 : }
67 : USTR_CONF_I_PROTO
68 : int ustr_io_getfile(struct Ustr **ps1, FILE *fp)
69 16 : { return (ustrp__io_getfile(0, ps1, fp)); }
70 : USTR_CONF_I_PROTO
71 : int ustrp_io_getfile(struct Ustr_pool *p, struct Ustrp **ps1, FILE *fp)
72 8 : {
73 8 : struct Ustr *tmp = &(*ps1)->s;
74 8 : int ret = ustrp__io_getfile(p, &tmp, fp);
75 8 : *ps1 = USTRP(tmp);
76 8 : return (ret);
77 : }
78 :
79 : USTR_CONF_i_PROTO
80 : int ustrp__io_getfilename(struct Ustr_pool *p, struct Ustr **ps1,
81 : const char *name)
82 16 : {
83 16 : FILE *fp = fopen(name, "rb");
84 16 : int ret = USTR_FALSE;
85 16 : int save_errno = 0;
86 :
87 16 : if (!fp)
88 4 : return (USTR_FALSE);
89 :
90 12 : ret = ustrp__io_getfile(p, ps1, fp);
91 :
92 12 : save_errno = errno;
93 12 : fclose(fp);
94 12 : errno = save_errno;
95 :
96 12 : return (ret);
97 : }
98 : USTR_CONF_I_PROTO
99 : int ustr_io_getfilename(struct Ustr **ps1, const char *name)
100 8 : { return (ustrp__io_getfilename(0, ps1, name)); }
101 : USTR_CONF_I_PROTO
102 : int ustrp_io_getfilename(struct Ustr_pool *p, struct Ustrp **ps1,
103 : const char *name)
104 8 : {
105 8 : struct Ustr *tmp = &(*ps1)->s;
106 8 : int ret = ustrp__io_getfilename(p, &tmp, name);
107 8 : *ps1 = USTRP(tmp);
108 8 : return (ret);
109 : }
110 :
111 : /* We bow to retarded GLibc getc_unlocked */
112 : #ifdef getc_unlocked
113 : # define USTR__IO_GETC(x) getc_unlocked(x)
114 : #else
115 : # define USTR__IO_GETC(x) getc(x)
116 : #endif
117 :
118 : USTR_CONF_i_PROTO int ustrp__io_getdelim(struct Ustr_pool *p, struct Ustr **ps1,
119 : FILE *fp, char delim)
120 272 : {
121 272 : int val = EOF;
122 272 : size_t olen = 0;
123 272 : size_t clen = 0;
124 272 : size_t linesz = 80; /* Unix "tradition" is 80x24, assuming delim == '\n' */
125 :
126 136 : USTR_ASSERT(ps1 && ustrp__assert_valid(!!p, *ps1) && fp);
127 :
128 340 : olen = clen = ustr_len(*ps1);
129 560 : while (ustrp__add_undef(p, ps1, linesz))
130 : {
131 288 : char *wstr = ustr_wstr(*ps1) + clen;
132 288 : size_t num = linesz;
133 :
134 3472 : while (num && ((val = USTR__IO_GETC(fp)) != EOF))
135 : {
136 3164 : --num;
137 3164 : if ((*wstr++ = val) == delim)
138 268 : break;
139 : }
140 :
141 288 : if (num)
142 : {
143 272 : if (!ferror(fp)) /* only way we can easily test,
144 : as it might be hanging from previously */
145 272 : errno = 0;
146 :
147 272 : ustrp__del(p, ps1, num);
148 272 : break;
149 : }
150 :
151 16 : clen += linesz;
152 : }
153 :
154 273 : return ((val == delim) || ((val == EOF) && (ustr_len(*ps1) != olen)));
155 : }
156 : #undef USTR__IO_GETC
157 : USTR_CONF_I_PROTO
158 : int ustr_io_getdelim(struct Ustr **ps1, FILE *fp, char delim)
159 156 : { return (ustrp__io_getdelim(0, ps1, fp, delim)); }
160 : USTR_CONF_I_PROTO int ustrp_io_getdelim(struct Ustr_pool *p, struct Ustrp **ps1,
161 : FILE *fp, char delim)
162 4 : {
163 4 : struct Ustr *tmp = &(*ps1)->s;
164 4 : int ret = ustrp__io_getdelim(p, &tmp, fp, delim);
165 4 : *ps1 = USTRP(tmp);
166 4 : return (ret);
167 : }
168 :
169 : USTR_CONF_I_PROTO
170 : int ustr_io_getline(struct Ustr **ps1, FILE *fp)
171 96 : { return (ustrp__io_getdelim(0, ps1, fp, '\n')); }
172 : USTR_CONF_I_PROTO
173 : int ustrp_io_getline(struct Ustr_pool *p, struct Ustrp **ps1, FILE *fp)
174 16 : {
175 16 : struct Ustr *tmp = &(*ps1)->s;
176 16 : int ret = ustrp__io_getdelim(p, &tmp, fp, '\n');
177 16 : *ps1 = USTRP(tmp);
178 16 : return (ret);
179 : }
180 :
181 : USTR_CONF_i_PROTO
182 : int ustrp__io_put(struct Ustr_pool *p, struct Ustr **ps1,FILE *fp,size_t beglen)
183 52 : {
184 52 : size_t ret = 0;
185 52 : size_t clen = ustr_len(*ps1);
186 :
187 26 : USTR_ASSERT(ps1 && ustrp__assert_valid(!!p, *ps1) && fp);
188 :
189 52 : USTR_ASSERT_RET(beglen <= clen, USTR_FALSE);
190 :
191 52 : if (!beglen)
192 8 : return (USTR_TRUE);
193 :
194 : /* Because most errors only happen when a fflush() of the stdio stream,
195 : * you have to assume that any data written is indeterminate anyway.
196 : * So only go to the effort of making it determinate if beglen != clen.
197 : * If you need efficient IO, that you can deal with errors for, use Vstr
198 : * and POSIX IO. */
199 44 : if ((beglen != clen) && !ustrp__sc_ensure_owner(p, ps1))
200 4 : return (USTR_FALSE);
201 :
202 50 : if ((ret = fwrite(ustr_cstr(*ps1), 1, beglen, fp)))
203 : {
204 36 : int save_errno = errno;
205 :
206 36 : if (beglen != clen) /* Note not ret != clen, see above. */
207 8 : ustrp__del_subustr(p, ps1, 1, ret); /* if it fails, see above */
208 : else
209 : /* In certain cases this means we'll lose the config. for *ps1. But it's
210 : * worth it so we don't have to ensure_owner() all the time. If you care
211 : * pass owned Ustr's. */
212 28 : ustrp__sc_del(p, ps1);
213 36 : errno = save_errno;
214 : }
215 :
216 40 : return (ret == beglen);
217 : }
218 : USTR_CONF_I_PROTO
219 : int ustr_io_put(struct Ustr **ps1, FILE *fp, size_t beglen)
220 16 : { return (ustrp__io_put(0, ps1, fp, beglen)); }
221 : USTR_CONF_I_PROTO
222 : int ustrp_io_put(struct Ustr_pool *p, struct Ustrp **ps1,FILE *fp,size_t beglen)
223 4 : {
224 4 : struct Ustr *tmp = &(*ps1)->s;
225 4 : int ret = ustrp__io_put(p, &tmp, fp, beglen);
226 4 : *ps1 = USTRP(tmp);
227 4 : return (ret);
228 : }
229 :
230 : /* We bow to retarded GLibc putc_unlocked */
231 : #ifdef putc_unlocked
232 : # define USTR__IO_PUTC(x, y) putc_unlocked(x, y)
233 : #else
234 : # define USTR__IO_PUTC(x, y) putc(x, y)
235 : #endif
236 : USTR_CONF_i_PROTO int ustrp__io_putline(struct Ustr_pool *p, struct Ustr **ps1,
237 : FILE *fp, size_t beglen)
238 12 : {
239 12 : if (!ustrp__io_put(p, ps1, fp, beglen))
240 4 : return (USTR_FALSE);
241 :
242 8 : return (USTR__IO_PUTC('\n', fp) != EOF);
243 : }
244 : #undef USTR__IO_PUTC
245 : USTR_CONF_I_PROTO
246 : int ustr_io_putline(struct Ustr **ps1, FILE *fp, size_t beglen)
247 8 : { return (ustrp__io_putline(0, ps1, fp, beglen)); }
248 : USTR_CONF_I_PROTO int ustrp_io_putline(struct Ustr_pool *p, struct Ustrp **ps1,
249 : FILE *fp, size_t beglen)
250 4 : {
251 4 : struct Ustr *tmp = &(*ps1)->s;
252 4 : int ret = ustrp__io_putline(p, &tmp, fp, beglen);
253 4 : *ps1 = USTRP(tmp);
254 4 : return (ret);
255 : }
256 :
257 : USTR_CONF_i_PROTO
258 : int ustrp__io_putfilename(struct Ustr_pool *p, struct Ustr **ps1,
259 : const char *name, const char *mode)
260 28 : {
261 28 : FILE *fp = fopen(name, mode);
262 28 : int ret = USTR_FALSE;
263 :
264 28 : if (!fp)
265 8 : return (USTR_FALSE);
266 :
267 25 : if ((ret = ustrp__io_put(p, ps1, fp, ustr_len(*ps1))))
268 16 : ret = !fclose(fp); /* if everything OK, defer to the fclose() return */
269 : else
270 : {
271 4 : int save_errno = errno; /* otherwise ignore it */
272 4 : fclose(fp);
273 4 : errno = save_errno;
274 : }
275 :
276 20 : return (ret);
277 : }
278 : USTR_CONF_I_PROTO
279 : int ustr_io_putfilename(struct Ustr **ps1, const char *name, const char *mode)
280 20 : { return (ustrp__io_putfilename(0, ps1, name, mode)); }
281 : USTR_CONF_I_PROTO
282 : int ustrp_io_putfilename(struct Ustr_pool *p, struct Ustrp **ps1,
283 : const char *name, const char *mode)
284 8 : {
285 8 : struct Ustr *tmp = &(*ps1)->s;
286 8 : int ret = ustrp__io_putfilename(p, &tmp, name, mode);
287 8 : *ps1 = USTRP(tmp);
288 8 : return (ret);
289 : }
|