GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: shf.c,v 1.31 2016/03/20 00:01:21 krw Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Shell file I/O routines |
||
5 |
*/ |
||
6 |
|||
7 |
#include <sys/stat.h> |
||
8 |
|||
9 |
#include <ctype.h> |
||
10 |
#include <errno.h> |
||
11 |
#include <fcntl.h> |
||
12 |
#include <limits.h> |
||
13 |
#include <stdio.h> |
||
14 |
#include <string.h> |
||
15 |
#include <unistd.h> |
||
16 |
|||
17 |
#include "sh.h" |
||
18 |
|||
19 |
/* flags to shf_emptybuf() */ |
||
20 |
#define EB_READSW 0x01 /* about to switch to reading */ |
||
21 |
#define EB_GROW 0x02 /* grow buffer if necessary (STRING+DYNAMIC) */ |
||
22 |
|||
23 |
/* |
||
24 |
* Replacement stdio routines. Stdio is too flakey on too many machines |
||
25 |
* to be useful when you have multiple processes using the same underlying |
||
26 |
* file descriptors. |
||
27 |
*/ |
||
28 |
|||
29 |
static int shf_fillbuf(struct shf *); |
||
30 |
static int shf_emptybuf(struct shf *, int); |
||
31 |
|||
32 |
/* Open a file. First three args are for open(), last arg is flags for |
||
33 |
* this package. Returns NULL if file could not be opened, or if a dup |
||
34 |
* fails. |
||
35 |
*/ |
||
36 |
struct shf * |
||
37 |
shf_open(const char *name, int oflags, int mode, int sflags) |
||
38 |
{ |
||
39 |
struct shf *shf; |
||
40 |
✗✓ | 115629 |
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; |
41 |
int fd; |
||
42 |
|||
43 |
/* Done before open so if alloca fails, fd won't be lost. */ |
||
44 |
38543 |
shf = alloc(sizeof(struct shf) + bsize, ATEMP); |
|
45 |
38543 |
shf->areap = ATEMP; |
|
46 |
38543 |
shf->buf = (unsigned char *) &shf[1]; |
|
47 |
38543 |
shf->bsize = bsize; |
|
48 |
38543 |
shf->flags = SHF_ALLOCS; |
|
49 |
/* Rest filled in by reopen. */ |
||
50 |
|||
51 |
38543 |
fd = open(name, oflags, mode); |
|
52 |
✓✓ | 38543 |
if (fd < 0) { |
53 |
85 |
afree(shf, shf->areap); |
|
54 |
85 |
return NULL; |
|
55 |
} |
||
56 |
✓✗ | 38458 |
if ((sflags & SHF_MAPHI) && fd < FDBASE) { |
57 |
int nfd; |
||
58 |
|||
59 |
38458 |
nfd = fcntl(fd, F_DUPFD, FDBASE); |
|
60 |
38458 |
close(fd); |
|
61 |
✗✓ | 38458 |
if (nfd < 0) { |
62 |
afree(shf, shf->areap); |
||
63 |
return NULL; |
||
64 |
} |
||
65 |
fd = nfd; |
||
66 |
✓✗ | 38458 |
} |
67 |
38458 |
sflags &= ~SHF_ACCMODE; |
|
68 |
✗✓ | 76916 |
sflags |= (oflags & O_ACCMODE) == O_RDONLY ? SHF_RD : |
69 |
((oflags & O_ACCMODE) == O_WRONLY ? SHF_WR : SHF_RDWR); |
||
70 |
|||
71 |
38458 |
return shf_reopen(fd, sflags, shf); |
|
72 |
38543 |
} |
|
73 |
|||
74 |
/* Set up the shf structure for a file descriptor. Doesn't fail. */ |
||
75 |
struct shf * |
||
76 |
shf_fdopen(int fd, int sflags, struct shf *shf) |
||
77 |
{ |
||
78 |
✓✓ | 12196867 |
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; |
79 |
|||
80 |
/* use fcntl() to figure out correct read/write flags */ |
||
81 |
✗✓ | 4064700 |
if (sflags & SHF_GETFL) { |
82 |
int flags = fcntl(fd, F_GETFL); |
||
83 |
|||
84 |
if (flags < 0) |
||
85 |
/* will get an error on first read/write */ |
||
86 |
sflags |= SHF_RDWR; |
||
87 |
else { |
||
88 |
switch (flags & O_ACCMODE) { |
||
89 |
case O_RDONLY: |
||
90 |
sflags |= SHF_RD; |
||
91 |
break; |
||
92 |
case O_WRONLY: |
||
93 |
sflags |= SHF_WR; |
||
94 |
break; |
||
95 |
case O_RDWR: |
||
96 |
sflags |= SHF_RDWR; |
||
97 |
break; |
||
98 |
} |
||
99 |
} |
||
100 |
} |
||
101 |
|||
102 |
✗✓ | 4064700 |
if (!(sflags & (SHF_RD | SHF_WR))) |
103 |
internal_errorf(1, "shf_fdopen: missing read/write"); |
||
104 |
|||
105 |
✓✓ | 4064700 |
if (shf) { |
106 |
✓✗ | 653310 |
if (bsize) { |
107 |
653310 |
shf->buf = alloc(bsize, ATEMP); |
|
108 |
653310 |
sflags |= SHF_ALLOCB; |
|
109 |
653310 |
} else |
|
110 |
shf->buf = NULL; |
||
111 |
} else { |
||
112 |
3411390 |
shf = alloc(sizeof(struct shf) + bsize, ATEMP); |
|
113 |
3411390 |
shf->buf = (unsigned char *) &shf[1]; |
|
114 |
3411390 |
sflags |= SHF_ALLOCS; |
|
115 |
} |
||
116 |
4064700 |
shf->areap = ATEMP; |
|
117 |
4064700 |
shf->fd = fd; |
|
118 |
4064700 |
shf->rp = shf->wp = shf->buf; |
|
119 |
4064700 |
shf->rnleft = 0; |
|
120 |
4064700 |
shf->rbsize = bsize; |
|
121 |
4064700 |
shf->wnleft = 0; /* force call to shf_emptybuf() */ |
|
122 |
4064700 |
shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; |
|
123 |
4064700 |
shf->flags = sflags; |
|
124 |
4064700 |
shf->errno_ = 0; |
|
125 |
4064700 |
shf->bsize = bsize; |
|
126 |
✗✓ | 4064700 |
if (sflags & SHF_CLEXEC) |
127 |
fcntl(fd, F_SETFD, FD_CLOEXEC); |
||
128 |
4064700 |
return shf; |
|
129 |
} |
||
130 |
|||
131 |
/* Set up an existing shf (and buffer) to use the given fd */ |
||
132 |
struct shf * |
||
133 |
shf_reopen(int fd, int sflags, struct shf *shf) |
||
134 |
{ |
||
135 |
✓✓ | 31535204 |
int bsize = sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE; |
136 |
|||
137 |
/* use fcntl() to figure out correct read/write flags */ |
||
138 |
✗✓ | 10509880 |
if (sflags & SHF_GETFL) { |
139 |
int flags = fcntl(fd, F_GETFL); |
||
140 |
|||
141 |
if (flags < 0) |
||
142 |
/* will get an error on first read/write */ |
||
143 |
sflags |= SHF_RDWR; |
||
144 |
else { |
||
145 |
switch (flags & O_ACCMODE) { |
||
146 |
case O_RDONLY: |
||
147 |
sflags |= SHF_RD; |
||
148 |
break; |
||
149 |
case O_WRONLY: |
||
150 |
sflags |= SHF_WR; |
||
151 |
break; |
||
152 |
case O_RDWR: |
||
153 |
sflags |= SHF_RDWR; |
||
154 |
break; |
||
155 |
} |
||
156 |
} |
||
157 |
} |
||
158 |
|||
159 |
✗✓ | 10509880 |
if (!(sflags & (SHF_RD | SHF_WR))) |
160 |
internal_errorf(1, "shf_reopen: missing read/write"); |
||
161 |
✓✗✓✗ ✗✓ |
31529640 |
if (!shf || !shf->buf || shf->bsize < bsize) |
162 |
internal_errorf(1, "shf_reopen: bad shf/buf/bsize"); |
||
163 |
|||
164 |
/* assumes shf->buf and shf->bsize already set up */ |
||
165 |
10509880 |
shf->fd = fd; |
|
166 |
10509880 |
shf->rp = shf->wp = shf->buf; |
|
167 |
10509880 |
shf->rnleft = 0; |
|
168 |
10509880 |
shf->rbsize = bsize; |
|
169 |
10509880 |
shf->wnleft = 0; /* force call to shf_emptybuf() */ |
|
170 |
10509880 |
shf->wbsize = sflags & SHF_UNBUF ? 0 : bsize; |
|
171 |
10509880 |
shf->flags = (shf->flags & (SHF_ALLOCS | SHF_ALLOCB)) | sflags; |
|
172 |
10509880 |
shf->errno_ = 0; |
|
173 |
✓✓ | 10509880 |
if (sflags & SHF_CLEXEC) |
174 |
38458 |
fcntl(fd, F_SETFD, FD_CLOEXEC); |
|
175 |
10509880 |
return shf; |
|
176 |
} |
||
177 |
|||
178 |
/* Open a string for reading or writing. If reading, bsize is the number |
||
179 |
* of bytes that can be read. If writing, bsize is the maximum number of |
||
180 |
* bytes that can be written. If shf is not null, it is filled in and |
||
181 |
* returned, if it is null, shf is allocated. If writing and buf is null |
||
182 |
* and SHF_DYNAMIC is set, the buffer is allocated (if bsize > 0, it is |
||
183 |
* used for the initial size). Doesn't fail. |
||
184 |
* When writing, a byte is reserved for a trailing null - see shf_sclose(). |
||
185 |
*/ |
||
186 |
struct shf * |
||
187 |
shf_sopen(char *buf, int bsize, int sflags, struct shf *shf) |
||
188 |
{ |
||
189 |
/* can't have a read+write string */ |
||
190 |
✓✗✗✓ |
22492278 |
if (!(sflags & (SHF_RD | SHF_WR)) || |
191 |
7497426 |
(sflags & (SHF_RD | SHF_WR)) == (SHF_RD | SHF_WR)) |
|
192 |
internal_errorf(1, "shf_sopen: flags 0x%x", sflags); |
||
193 |
|||
194 |
✗✓ | 7497426 |
if (!shf) { |
195 |
shf = alloc(sizeof(struct shf), ATEMP); |
||
196 |
sflags |= SHF_ALLOCS; |
||
197 |
} |
||
198 |
7497426 |
shf->areap = ATEMP; |
|
199 |
✓✓✓✗ ✓✗ |
7667522 |
if (!buf && (sflags & SHF_WR) && (sflags & SHF_DYNAMIC)) { |
200 |
✓✓ | 85048 |
if (bsize <= 0) |
201 |
200 |
bsize = 64; |
|
202 |
85048 |
sflags |= SHF_ALLOCB; |
|
203 |
85048 |
buf = alloc(bsize, shf->areap); |
|
204 |
85048 |
} |
|
205 |
7497426 |
shf->fd = -1; |
|
206 |
7497426 |
shf->buf = shf->rp = shf->wp = (unsigned char *) buf; |
|
207 |
7497426 |
shf->rnleft = bsize; |
|
208 |
7497426 |
shf->rbsize = bsize; |
|
209 |
7497426 |
shf->wnleft = bsize - 1; /* space for a '\0' */ |
|
210 |
7497426 |
shf->wbsize = bsize; |
|
211 |
7497426 |
shf->flags = sflags | SHF_STRING; |
|
212 |
7497426 |
shf->errno_ = 0; |
|
213 |
7497426 |
shf->bsize = bsize; |
|
214 |
|||
215 |
7497426 |
return shf; |
|
216 |
} |
||
217 |
|||
218 |
/* Flush and close file descriptor, free the shf structure */ |
||
219 |
int |
||
220 |
shf_close(struct shf *shf) |
||
221 |
{ |
||
222 |
int ret = 0; |
||
223 |
|||
224 |
✓✓ | 6323456 |
if (shf->fd >= 0) { |
225 |
3155188 |
ret = shf_flush(shf); |
|
226 |
✗✓ | 3155188 |
if (close(shf->fd) < 0) |
227 |
ret = EOF; |
||
228 |
} |
||
229 |
✓✗ | 3161728 |
if (shf->flags & SHF_ALLOCS) |
230 |
3161728 |
afree(shf, shf->areap); |
|
231 |
else if (shf->flags & SHF_ALLOCB) |
||
232 |
afree(shf->buf, shf->areap); |
||
233 |
|||
234 |
3161728 |
return ret; |
|
235 |
} |
||
236 |
|||
237 |
/* Flush and close file descriptor, don't free file structure */ |
||
238 |
int |
||
239 |
shf_fdclose(struct shf *shf) |
||
240 |
{ |
||
241 |
int ret = 0; |
||
242 |
|||
243 |
✓✗ | 14502 |
if (shf->fd >= 0) { |
244 |
7251 |
ret = shf_flush(shf); |
|
245 |
✗✓ | 7251 |
if (close(shf->fd) < 0) |
246 |
ret = EOF; |
||
247 |
7251 |
shf->rnleft = 0; |
|
248 |
7251 |
shf->rp = shf->buf; |
|
249 |
7251 |
shf->wnleft = 0; |
|
250 |
7251 |
shf->fd = -1; |
|
251 |
7251 |
} |
|
252 |
|||
253 |
7251 |
return ret; |
|
254 |
} |
||
255 |
|||
256 |
/* Close a string - if it was opened for writing, it is null terminated; |
||
257 |
* returns a pointer to the string and frees shf if it was allocated |
||
258 |
* (does not free string if it was allocated). |
||
259 |
*/ |
||
260 |
char * |
||
261 |
shf_sclose(struct shf *shf) |
||
262 |
{ |
||
263 |
14994852 |
unsigned char *s = shf->buf; |
|
264 |
|||
265 |
/* null terminate */ |
||
266 |
✓✗ | 7497426 |
if (shf->flags & SHF_WR) { |
267 |
7497426 |
shf->wnleft++; |
|
268 |
✗✓ | 14994852 |
shf_putc('\0', shf); |
269 |
} |
||
270 |
✗✓ | 7497426 |
if (shf->flags & SHF_ALLOCS) |
271 |
afree(shf, shf->areap); |
||
272 |
7497426 |
return (char *) s; |
|
273 |
} |
||
274 |
|||
275 |
/* Un-read what has been read but not examined, or write what has been |
||
276 |
* buffered. Returns 0 for success, EOF for (write) error. |
||
277 |
*/ |
||
278 |
int |
||
279 |
shf_flush(struct shf *shf) |
||
280 |
{ |
||
281 |
✗✓ | 35993586 |
if (shf->flags & SHF_STRING) |
282 |
return (shf->flags & SHF_WR) ? EOF : 0; |
||
283 |
|||
284 |
✗✓ | 17996793 |
if (shf->fd < 0) |
285 |
internal_errorf(1, "shf_flush: no fd"); |
||
286 |
|||
287 |
✗✓ | 17996793 |
if (shf->flags & SHF_ERROR) { |
288 |
errno = shf->errno_; |
||
289 |
return EOF; |
||
290 |
} |
||
291 |
|||
292 |
✓✓ | 17996793 |
if (shf->flags & SHF_READING) { |
293 |
3095078 |
shf->flags &= ~(SHF_EOF | SHF_READING); |
|
294 |
✓✓ | 3095078 |
if (shf->rnleft > 0) { |
295 |
101722 |
lseek(shf->fd, (off_t) -shf->rnleft, SEEK_CUR); |
|
296 |
101722 |
shf->rnleft = 0; |
|
297 |
101722 |
shf->rp = shf->buf; |
|
298 |
101722 |
} |
|
299 |
3095078 |
return 0; |
|
300 |
✓✓ | 14901715 |
} else if (shf->flags & SHF_WRITING) |
301 |
351172 |
return shf_emptybuf(shf, 0); |
|
302 |
|||
303 |
14550543 |
return 0; |
|
304 |
17996793 |
} |
|
305 |
|||
306 |
/* Write out any buffered data. If currently reading, flushes the read |
||
307 |
* buffer. Returns 0 for success, EOF for (write) error. |
||
308 |
*/ |
||
309 |
static int |
||
310 |
shf_emptybuf(struct shf *shf, int flags) |
||
311 |
{ |
||
312 |
int ret = 0; |
||
313 |
|||
314 |
✓✓✗✓ |
56573113 |
if (!(shf->flags & SHF_STRING) && shf->fd < 0) |
315 |
internal_errorf(1, "shf_emptybuf: no fd"); |
||
316 |
|||
317 |
✗✓ | 28004071 |
if (shf->flags & SHF_ERROR) { |
318 |
errno = shf->errno_; |
||
319 |
return EOF; |
||
320 |
} |
||
321 |
|||
322 |
✗✓ | 28004071 |
if (shf->flags & SHF_READING) { |
323 |
if (flags & EB_READSW) /* doesn't happen */ |
||
324 |
return 0; |
||
325 |
ret = shf_flush(shf); |
||
326 |
shf->flags &= ~SHF_READING; |
||
327 |
} |
||
328 |
✓✓ | 28004071 |
if (shf->flags & SHF_STRING) { |
329 |
unsigned char *nbuf; |
||
330 |
|||
331 |
/* Note that we assume SHF_ALLOCS is not set if SHF_ALLOCB |
||
332 |
* is set... (changing the shf pointer could cause problems) |
||
333 |
*/ |
||
334 |
✓✗✓✓ ✗✓ |
54878450 |
if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || |
335 |
250 |
!(shf->flags & SHF_ALLOCB)) |
|
336 |
27438850 |
return EOF; |
|
337 |
/* allocate more space for buffer */ |
||
338 |
250 |
nbuf = areallocarray(shf->buf, 2, shf->wbsize, shf->areap); |
|
339 |
250 |
shf->rp = nbuf + (shf->rp - shf->buf); |
|
340 |
250 |
shf->wp = nbuf + (shf->wp - shf->buf); |
|
341 |
250 |
shf->rbsize += shf->wbsize; |
|
342 |
250 |
shf->wnleft += shf->wbsize; |
|
343 |
250 |
shf->wbsize *= 2; |
|
344 |
250 |
shf->buf = nbuf; |
|
345 |
✓✓ | 250 |
} else { |
346 |
✓✓ | 564971 |
if (shf->flags & SHF_WRITING) { |
347 |
352035 |
int ntowrite = shf->wp - shf->buf; |
|
348 |
unsigned char *buf = shf->buf; |
||
349 |
int n; |
||
350 |
|||
351 |
✓✓ | 1286184 |
while (ntowrite > 0) { |
352 |
291057 |
n = write(shf->fd, buf, ntowrite); |
|
353 |
✗✓ | 291057 |
if (n < 0) { |
354 |
if (errno == EINTR && |
||
355 |
!(shf->flags & SHF_INTERRUPT)) |
||
356 |
continue; |
||
357 |
shf->flags |= SHF_ERROR; |
||
358 |
shf->errno_ = errno; |
||
359 |
shf->wnleft = 0; |
||
360 |
if (buf != shf->buf) { |
||
361 |
/* allow a second flush |
||
362 |
* to work */ |
||
363 |
memmove(shf->buf, buf, |
||
364 |
ntowrite); |
||
365 |
shf->wp = shf->buf + ntowrite; |
||
366 |
} |
||
367 |
return EOF; |
||
368 |
} |
||
369 |
291057 |
buf += n; |
|
370 |
291057 |
ntowrite -= n; |
|
371 |
} |
||
372 |
✗✓ | 352035 |
if (flags & EB_READSW) { |
373 |
shf->wp = shf->buf; |
||
374 |
shf->wnleft = 0; |
||
375 |
shf->flags &= ~SHF_WRITING; |
||
376 |
return 0; |
||
377 |
} |
||
378 |
✓✗ | 352035 |
} |
379 |
564971 |
shf->wp = shf->buf; |
|
380 |
564971 |
shf->wnleft = shf->wbsize; |
|
381 |
} |
||
382 |
565221 |
shf->flags |= SHF_WRITING; |
|
383 |
|||
384 |
565221 |
return ret; |
|
385 |
28004071 |
} |
|
386 |
|||
387 |
/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ |
||
388 |
static int |
||
389 |
shf_fillbuf(struct shf *shf) |
||
390 |
{ |
||
391 |
✗✓ | 16810802 |
if (shf->flags & SHF_STRING) |
392 |
return 0; |
||
393 |
|||
394 |
✗✓ | 8405401 |
if (shf->fd < 0) |
395 |
internal_errorf(1, "shf_fillbuf: no fd"); |
||
396 |
|||
397 |
✓✓ | 8405401 |
if (shf->flags & (SHF_EOF | SHF_ERROR)) { |
398 |
✗✓ | 75 |
if (shf->flags & SHF_ERROR) |
399 |
errno = shf->errno_; |
||
400 |
75 |
return EOF; |
|
401 |
} |
||
402 |
|||
403 |
✗✓✗✗ |
8405326 |
if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) |
404 |
return EOF; |
||
405 |
|||
406 |
8405326 |
shf->flags |= SHF_READING; |
|
407 |
|||
408 |
8405326 |
shf->rp = shf->buf; |
|
409 |
8405326 |
while (1) { |
|
410 |
27087622 |
shf->rnleft = blocking_read(shf->fd, (char *) shf->buf, |
|
411 |
13543811 |
shf->rbsize); |
|
412 |
✓✓✓✗ ✓✗ |
23820781 |
if (shf->rnleft < 0 && errno == EINTR && |
413 |
5138485 |
!(shf->flags & SHF_INTERRUPT)) |
|
414 |
continue; |
||
415 |
break; |
||
416 |
} |
||
417 |
✓✓ | 8405326 |
if (shf->rnleft <= 0) { |
418 |
✗✓ | 2964941 |
if (shf->rnleft < 0) { |
419 |
shf->flags |= SHF_ERROR; |
||
420 |
shf->errno_ = errno; |
||
421 |
shf->rnleft = 0; |
||
422 |
shf->rp = shf->buf; |
||
423 |
return EOF; |
||
424 |
} |
||
425 |
2964941 |
shf->flags |= SHF_EOF; |
|
426 |
2964941 |
} |
|
427 |
8405326 |
return 0; |
|
428 |
8405401 |
} |
|
429 |
|||
430 |
/* Read a buffer from shf. Returns the number of bytes read into buf, |
||
431 |
* if no bytes were read, returns 0 if end of file was seen, EOF if |
||
432 |
* a read error occurred. |
||
433 |
*/ |
||
434 |
int |
||
435 |
shf_read(char *buf, int bsize, struct shf *shf) |
||
436 |
{ |
||
437 |
int orig_bsize = bsize; |
||
438 |
int ncopy; |
||
439 |
|||
440 |
if (!(shf->flags & SHF_RD)) |
||
441 |
internal_errorf(1, "shf_read: flags %x", shf->flags); |
||
442 |
|||
443 |
if (bsize <= 0) |
||
444 |
internal_errorf(1, "shf_read: bsize %d", bsize); |
||
445 |
|||
446 |
while (bsize > 0) { |
||
447 |
if (shf->rnleft == 0 && |
||
448 |
(shf_fillbuf(shf) == EOF || shf->rnleft == 0)) |
||
449 |
break; |
||
450 |
ncopy = shf->rnleft; |
||
451 |
if (ncopy > bsize) |
||
452 |
ncopy = bsize; |
||
453 |
memcpy(buf, shf->rp, ncopy); |
||
454 |
buf += ncopy; |
||
455 |
bsize -= ncopy; |
||
456 |
shf->rp += ncopy; |
||
457 |
shf->rnleft -= ncopy; |
||
458 |
} |
||
459 |
/* Note: fread(3S) returns 0 for errors - this doesn't */ |
||
460 |
return orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : |
||
461 |
orig_bsize - bsize; |
||
462 |
} |
||
463 |
|||
464 |
/* Read up to a newline or EOF. The newline is put in buf; buf is always |
||
465 |
* null terminated. Returns NULL on read error or if nothing was read before |
||
466 |
* end of file, returns a pointer to the null byte in buf otherwise. |
||
467 |
*/ |
||
468 |
char * |
||
469 |
shf_getse(char *buf, int bsize, struct shf *shf) |
||
470 |
{ |
||
471 |
unsigned char *end; |
||
472 |
int ncopy; |
||
473 |
char *orig_buf = buf; |
||
474 |
|||
475 |
✗✓ | 40145188 |
if (!(shf->flags & SHF_RD)) |
476 |
internal_errorf(1, "shf_getse: flags %x", shf->flags); |
||
477 |
|||
478 |
✗✓ | 20072594 |
if (bsize <= 0) |
479 |
return NULL; |
||
480 |
|||
481 |
20072594 |
--bsize; /* save room for null */ |
|
482 |
20072594 |
do { |
|
483 |
✓✓ | 21652215 |
if (shf->rnleft == 0) { |
484 |
✓✓ | 1721738 |
if (shf_fillbuf(shf) == EOF) |
485 |
75 |
return NULL; |
|
486 |
✓✓ | 1721663 |
if (shf->rnleft == 0) { |
487 |
12440 |
*buf = '\0'; |
|
488 |
12440 |
return buf == orig_buf ? NULL : buf; |
|
489 |
} |
||
490 |
} |
||
491 |
43279400 |
end = (unsigned char *) memchr((char *) shf->rp, '\n', |
|
492 |
21639700 |
shf->rnleft); |
|
493 |
✓✓ | 64919100 |
ncopy = end ? end - shf->rp + 1 : shf->rnleft; |
494 |
✓✓ | 21639700 |
if (ncopy > bsize) |
495 |
25 |
ncopy = bsize; |
|
496 |
21639700 |
memcpy(buf, (char *) shf->rp, ncopy); |
|
497 |
21639700 |
shf->rp += ncopy; |
|
498 |
21639700 |
shf->rnleft -= ncopy; |
|
499 |
21639700 |
buf += ncopy; |
|
500 |
21639700 |
bsize -= ncopy; |
|
501 |
✓✓ | 21639700 |
} while (!end && bsize); |
502 |
20060079 |
*buf = '\0'; |
|
503 |
20060079 |
return buf; |
|
504 |
20072594 |
} |
|
505 |
|||
506 |
/* Returns the char read. Returns EOF for error and end of file. */ |
||
507 |
int |
||
508 |
shf_getchar(struct shf *shf) |
||
509 |
{ |
||
510 |
✗✓ | 13367326 |
if (!(shf->flags & SHF_RD)) |
511 |
internal_errorf(1, "shf_getchar: flags %x", shf->flags); |
||
512 |
|||
513 |
✓✗✓✗ ✓✓ |
20050989 |
if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) |
514 |
2952501 |
return EOF; |
|
515 |
3731162 |
--shf->rnleft; |
|
516 |
3731162 |
return *shf->rp++; |
|
517 |
6683663 |
} |
|
518 |
|||
519 |
/* Put a character back in the input stream. Returns the character if |
||
520 |
* successful, EOF if there is no room. |
||
521 |
*/ |
||
522 |
int |
||
523 |
shf_ungetc(int c, struct shf *shf) |
||
524 |
{ |
||
525 |
✗✓ | 9405470 |
if (!(shf->flags & SHF_RD)) |
526 |
internal_errorf(1, "shf_ungetc: flags %x", shf->flags); |
||
527 |
|||
528 |
✓✗✗✗ |
4702735 |
if ((shf->flags & SHF_ERROR) || c == EOF || |
529 |
✗✓ | 4702735 |
(shf->rp == shf->buf && shf->rnleft)) |
530 |
return EOF; |
||
531 |
|||
532 |
✗✓✗✗ |
4702735 |
if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) |
533 |
return EOF; |
||
534 |
|||
535 |
✗✓ | 4702735 |
if (shf->rp == shf->buf) |
536 |
shf->rp = shf->buf + shf->rbsize; |
||
537 |
✗✓ | 4702735 |
if (shf->flags & SHF_STRING) { |
538 |
/* Can unget what was read, but not something different - we |
||
539 |
* don't want to modify a string. |
||
540 |
*/ |
||
541 |
if (shf->rp[-1] != c) |
||
542 |
return EOF; |
||
543 |
shf->flags &= ~SHF_EOF; |
||
544 |
shf->rp--; |
||
545 |
shf->rnleft++; |
||
546 |
return c; |
||
547 |
} |
||
548 |
4702735 |
shf->flags &= ~SHF_EOF; |
|
549 |
4702735 |
*--(shf->rp) = c; |
|
550 |
4702735 |
shf->rnleft++; |
|
551 |
4702735 |
return c; |
|
552 |
4702735 |
} |
|
553 |
|||
554 |
/* Write a character. Returns the character if successful, EOF if |
||
555 |
* the char could not be written. |
||
556 |
*/ |
||
557 |
int |
||
558 |
shf_putchar(int c, struct shf *shf) |
||
559 |
{ |
||
560 |
✗✓ | 350217856 |
if (!(shf->flags & SHF_WR)) |
561 |
internal_errorf(1, "shf_putchar: flags %x", shf->flags); |
||
562 |
|||
563 |
✗✓ | 175108928 |
if (c == EOF) |
564 |
return EOF; |
||
565 |
|||
566 |
✗✓ | 175108928 |
if (shf->flags & SHF_UNBUF) { |
567 |
char cc = c; |
||
568 |
int n; |
||
569 |
|||
570 |
if (shf->fd < 0) |
||
571 |
internal_errorf(1, "shf_putchar: no fd"); |
||
572 |
if (shf->flags & SHF_ERROR) { |
||
573 |
errno = shf->errno_; |
||
574 |
return EOF; |
||
575 |
} |
||
576 |
while ((n = write(shf->fd, &cc, 1)) != 1) |
||
577 |
if (n < 0) { |
||
578 |
if (errno == EINTR && |
||
579 |
!(shf->flags & SHF_INTERRUPT)) |
||
580 |
continue; |
||
581 |
shf->flags |= SHF_ERROR; |
||
582 |
shf->errno_ = errno; |
||
583 |
return EOF; |
||
584 |
} |
||
585 |
} else { |
||
586 |
/* Flush deals with strings and sticky errors */ |
||
587 |
✓✓✓✓ |
202360142 |
if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) |
588 |
27239971 |
return EOF; |
|
589 |
147868957 |
shf->wnleft--; |
|
590 |
147868957 |
*shf->wp++ = c; |
|
591 |
} |
||
592 |
|||
593 |
147868957 |
return c; |
|
594 |
175108928 |
} |
|
595 |
|||
596 |
/* Write a string. Returns the length of the string if successful, EOF if |
||
597 |
* the string could not be written. |
||
598 |
*/ |
||
599 |
int |
||
600 |
shf_puts(const char *s, struct shf *shf) |
||
601 |
{ |
||
602 |
✗✓ | 811556 |
if (!s) |
603 |
return EOF; |
||
604 |
|||
605 |
405778 |
return shf_write(s, strlen(s), shf); |
|
606 |
405778 |
} |
|
607 |
|||
608 |
/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ |
||
609 |
int |
||
610 |
shf_write(const char *buf, int nbytes, struct shf *shf) |
||
611 |
{ |
||
612 |
int orig_nbytes = nbytes; |
||
613 |
int n; |
||
614 |
int ncopy; |
||
615 |
|||
616 |
✗✓ | 811806 |
if (!(shf->flags & SHF_WR)) |
617 |
internal_errorf(1, "shf_write: flags %x", shf->flags); |
||
618 |
|||
619 |
✗✓ | 405903 |
if (nbytes < 0) |
620 |
internal_errorf(1, "shf_write: nbytes %d", nbytes); |
||
621 |
|||
622 |
/* Don't buffer if buffer is empty and we're writting a large amount. */ |
||
623 |
✓✓✓✗ |
406003 |
if ((ncopy = shf->wnleft) && |
624 |
✓✓ | 147159 |
(shf->wp != shf->buf || nbytes < shf->wnleft)) { |
625 |
✓✓ | 147059 |
if (ncopy > nbytes) |
626 |
4200 |
ncopy = nbytes; |
|
627 |
147059 |
memcpy(shf->wp, buf, ncopy); |
|
628 |
147059 |
nbytes -= ncopy; |
|
629 |
147059 |
buf += ncopy; |
|
630 |
147059 |
shf->wp += ncopy; |
|
631 |
147059 |
shf->wnleft -= ncopy; |
|
632 |
147059 |
} |
|
633 |
✓✓ | 405903 |
if (nbytes > 0) { |
634 |
/* Flush deals with strings and sticky errors */ |
||
635 |
✓✓ | 401685 |
if (shf_emptybuf(shf, EB_GROW) == EOF) |
636 |
198879 |
return EOF; |
|
637 |
✓✓ | 202806 |
if (nbytes > shf->wbsize) { |
638 |
ncopy = nbytes; |
||
639 |
✓✗ | 50622 |
if (shf->wbsize) |
640 |
50622 |
ncopy -= nbytes % shf->wbsize; |
|
641 |
50622 |
nbytes -= ncopy; |
|
642 |
✓✓ | 202488 |
while (ncopy > 0) { |
643 |
50622 |
n = write(shf->fd, buf, ncopy); |
|
644 |
✗✓ | 50622 |
if (n < 0) { |
645 |
if (errno == EINTR && |
||
646 |
!(shf->flags & SHF_INTERRUPT)) |
||
647 |
continue; |
||
648 |
shf->flags |= SHF_ERROR; |
||
649 |
shf->errno_ = errno; |
||
650 |
shf->wnleft = 0; |
||
651 |
/* Note: fwrite(3S) returns 0 for |
||
652 |
* errors - this doesn't */ |
||
653 |
return EOF; |
||
654 |
} |
||
655 |
50622 |
buf += n; |
|
656 |
50622 |
ncopy -= n; |
|
657 |
} |
||
658 |
} |
||
659 |
✓✗ | 202806 |
if (nbytes > 0) { |
660 |
202806 |
memcpy(shf->wp, buf, nbytes); |
|
661 |
202806 |
shf->wp += nbytes; |
|
662 |
202806 |
shf->wnleft -= nbytes; |
|
663 |
202806 |
} |
|
664 |
} |
||
665 |
|||
666 |
207024 |
return orig_nbytes; |
|
667 |
405903 |
} |
|
668 |
|||
669 |
int |
||
670 |
shf_fprintf(struct shf *shf, const char *fmt, ...) |
||
671 |
{ |
||
672 |
289348 |
va_list args; |
|
673 |
int n; |
||
674 |
|||
675 |
144674 |
va_start(args, fmt); |
|
676 |
144674 |
n = shf_vfprintf(shf, fmt, args); |
|
677 |
144674 |
va_end(args); |
|
678 |
|||
679 |
144674 |
return n; |
|
680 |
144674 |
} |
|
681 |
|||
682 |
int |
||
683 |
shf_snprintf(char *buf, int bsize, const char *fmt, ...) |
||
684 |
{ |
||
685 |
409990 |
struct shf shf; |
|
686 |
204995 |
va_list args; |
|
687 |
int n; |
||
688 |
|||
689 |
✗✓ | 204995 |
if (!buf || bsize <= 0) |
690 |
internal_errorf(1, "shf_snprintf: buf %lx, bsize %d", |
||
691 |
(long) buf, bsize); |
||
692 |
|||
693 |
204995 |
shf_sopen(buf, bsize, SHF_WR, &shf); |
|
694 |
204995 |
va_start(args, fmt); |
|
695 |
204995 |
n = shf_vfprintf(&shf, fmt, args); |
|
696 |
204995 |
va_end(args); |
|
697 |
204995 |
shf_sclose(&shf); /* null terminates */ |
|
698 |
204995 |
return n; |
|
699 |
204995 |
} |
|
700 |
|||
701 |
char * |
||
702 |
shf_smprintf(const char *fmt, ...) |
||
703 |
{ |
||
704 |
400 |
struct shf shf; |
|
705 |
200 |
va_list args; |
|
706 |
|||
707 |
200 |
shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf); |
|
708 |
200 |
va_start(args, fmt); |
|
709 |
200 |
shf_vfprintf(&shf, fmt, args); |
|
710 |
200 |
va_end(args); |
|
711 |
400 |
return shf_sclose(&shf); /* null terminates */ |
|
712 |
200 |
} |
|
713 |
|||
714 |
#define FL_HASH 0x001 /* `#' seen */ |
||
715 |
#define FL_PLUS 0x002 /* `+' seen */ |
||
716 |
#define FL_RIGHT 0x004 /* `-' seen */ |
||
717 |
#define FL_BLANK 0x008 /* ` ' seen */ |
||
718 |
#define FL_SHORT 0x010 /* `h' seen */ |
||
719 |
#define FL_LONG 0x020 /* `l' seen */ |
||
720 |
#define FL_LLONG 0x040 /* `ll' seen */ |
||
721 |
#define FL_ZERO 0x080 /* `0' seen */ |
||
722 |
#define FL_DOT 0x100 /* '.' seen */ |
||
723 |
#define FL_UPPER 0x200 /* format character was uppercase */ |
||
724 |
#define FL_NUMBER 0x400 /* a number was formated %[douxefg] */ |
||
725 |
|||
726 |
int |
||
727 |
shf_vfprintf(struct shf *shf, const char *fmt, va_list args) |
||
728 |
{ |
||
729 |
char c, *s; |
||
730 |
int tmp = 0; |
||
731 |
int field, precision; |
||
732 |
int len; |
||
733 |
int flags; |
||
734 |
unsigned long long llnum; |
||
735 |
/* %#o produces the longest output */ |
||
736 |
847922 |
char numbuf[(BITS(long long) + 2) / 3 + 1]; |
|
737 |
/* this stuff for dealing with the buffer */ |
||
738 |
int nwritten = 0; |
||
739 |
|||
740 |
✗✓ | 423961 |
if (!fmt) |
741 |
return 0; |
||
742 |
|||
743 |
✓✓ | 3300411 |
while ((c = *fmt++)) { |
744 |
✓✓ | 2876450 |
if (c != '%') { |
745 |
✓✓ | 4758312 |
shf_putc(c, shf); |
746 |
2379156 |
nwritten++; |
|
747 |
2379156 |
continue; |
|
748 |
} |
||
749 |
/* |
||
750 |
* This will accept flags/fields in any order - not |
||
751 |
* just the order specified in printf(3), but this is |
||
752 |
* the way _doprnt() seems to work (on bsd and sysV). |
||
753 |
* The only restriction is that the format character must |
||
754 |
* come last :-). |
||
755 |
*/ |
||
756 |
flags = field = precision = 0; |
||
757 |
✓✗ | 1049697 |
for ( ; (c = *fmt++) ; ) { |
758 |
✓✗✓✗ ✓✓✓✓ ✗✓ |
552403 |
switch (c) { |
759 |
case '#': |
||
760 |
34 |
flags |= FL_HASH; |
|
761 |
34 |
continue; |
|
762 |
|||
763 |
case '+': |
||
764 |
flags |= FL_PLUS; |
||
765 |
continue; |
||
766 |
|||
767 |
case '-': |
||
768 |
3104 |
flags |= FL_RIGHT; |
|
769 |
3104 |
continue; |
|
770 |
|||
771 |
case ' ': |
||
772 |
flags |= FL_BLANK; |
||
773 |
continue; |
||
774 |
|||
775 |
case '0': |
||
776 |
✗✓ | 11820 |
if (!(flags & FL_DOT)) |
777 |
11820 |
flags |= FL_ZERO; |
|
778 |
continue; |
||
779 |
|||
780 |
case '.': |
||
781 |
34 |
flags |= FL_DOT; |
|
782 |
precision = 0; |
||
783 |
34 |
continue; |
|
784 |
|||
785 |
case '*': |
||
786 |
✓✗ | 31497 |
tmp = va_arg(args, int); |
787 |
✗✓ | 10499 |
if (flags & FL_DOT) |
788 |
precision = tmp; |
||
789 |
✓✗ | 10499 |
else if ((field = tmp) < 0) { |
790 |
field = -field; |
||
791 |
flags |= FL_RIGHT; |
||
792 |
} |
||
793 |
continue; |
||
794 |
|||
795 |
case 'l': |
||
796 |
✓✓ | 17730 |
if (*fmt == 'l') { |
797 |
11820 |
fmt++; |
|
798 |
11820 |
flags |= FL_LLONG; |
|
799 |
11820 |
} else |
|
800 |
5910 |
flags |= FL_LONG; |
|
801 |
continue; |
||
802 |
|||
803 |
case 'h': |
||
804 |
flags |= FL_SHORT; |
||
805 |
continue; |
||
806 |
} |
||
807 |
✓✓ | 509182 |
if (digit(c)) { |
808 |
11888 |
tmp = c - '0'; |
|
809 |
✗✓ | 23776 |
while (c = *fmt++, digit(c)) |
810 |
tmp = tmp * 10 + c - '0'; |
||
811 |
11888 |
--fmt; |
|
812 |
✗✓ | 11888 |
if (tmp < 0) /* overflow? */ |
813 |
tmp = 0; |
||
814 |
✓✓ | 11888 |
if (flags & FL_DOT) |
815 |
34 |
precision = tmp; |
|
816 |
else |
||
817 |
field = tmp; |
||
818 |
continue; |
||
819 |
} |
||
820 |
break; |
||
821 |
} |
||
822 |
|||
823 |
✗✓ | 497294 |
if (precision < 0) |
824 |
precision = 0; |
||
825 |
|||
826 |
✓✗ | 497294 |
if (!c) /* nasty format */ |
827 |
break; |
||
828 |
|||
829 |
✓✗✗✓ |
994588 |
if (c >= 'A' && c <= 'Z') { |
830 |
flags |= FL_UPPER; |
||
831 |
c = c - 'A' + 'a'; |
||
832 |
} |
||
833 |
|||
834 |
✗✗✗✗ ✗✓✓✓ ✗ |
497294 |
switch (c) { |
835 |
case 'p': /* pointer */ |
||
836 |
flags &= ~(FL_LLONG | FL_SHORT); |
||
837 |
flags |= FL_LONG; |
||
838 |
/* aaahhh... */ |
||
839 |
case 'd': |
||
840 |
case 'i': |
||
841 |
case 'o': |
||
842 |
case 'u': |
||
843 |
case 'x': |
||
844 |
19803 |
flags |= FL_NUMBER; |
|
845 |
19803 |
s = &numbuf[sizeof(numbuf)]; |
|
846 |
✓✓ | 19803 |
if (flags & FL_LLONG) |
847 |
✓✗ | 35460 |
llnum = va_arg(args, unsigned long long); |
848 |
✓✓ | 7983 |
else if (flags & FL_LONG) { |
849 |
✗✓✗✗ |
5910 |
if (c == 'd' || c == 'i') |
850 |
✗✓ | 17730 |
llnum = va_arg(args, long); |
851 |
else |
||
852 |
llnum = va_arg(args, unsigned long); |
||
853 |
} else { |
||
854 |
✓✓✗✓ |
2107 |
if (c == 'd' || c == 'i') |
855 |
✓✗ | 6117 |
llnum = va_arg(args, int); |
856 |
else |
||
857 |
✓✗ | 102 |
llnum = va_arg(args, unsigned int); |
858 |
} |
||
859 |
✗✓✓✓ ✗✗✓ |
63641 |
switch (c) { |
860 |
case 'd': |
||
861 |
case 'i': |
||
862 |
✗✓ | 19769 |
if (0 > (long long) llnum) |
863 |
llnum = - (long long) llnum, tmp = 1; |
||
864 |
else |
||
865 |
tmp = 0; |
||
866 |
/* aaahhhh..... */ |
||
867 |
|||
868 |
case 'u': |
||
869 |
do { |
||
870 |
23976 |
*--s = llnum % 10 + '0'; |
|
871 |
23976 |
llnum /= 10; |
|
872 |
✓✓ | 23976 |
} while (llnum); |
873 |
|||
874 |
✓✗ | 19769 |
if (c != 'u') { |
875 |
✗✓ | 19769 |
if (tmp) |
876 |
*--s = '-'; |
||
877 |
✗✓ | 19769 |
else if (flags & FL_PLUS) |
878 |
*--s = '+'; |
||
879 |
✗✓ | 19769 |
else if (flags & FL_BLANK) |
880 |
*--s = ' '; |
||
881 |
} |
||
882 |
break; |
||
883 |
|||
884 |
case 'o': |
||
885 |
do { |
||
886 |
93 |
*--s = (llnum & 0x7) + '0'; |
|
887 |
93 |
llnum >>= 3; |
|
888 |
✓✓ | 93 |
} while (llnum); |
889 |
|||
890 |
✓✗✓✗ |
68 |
if ((flags & FL_HASH) && *s != '0') |
891 |
34 |
*--s = '0'; |
|
892 |
break; |
||
893 |
|||
894 |
case 'p': |
||
895 |
case 'x': |
||
896 |
{ |
||
897 |
const char *digits = (flags & FL_UPPER) ? |
||
898 |
"0123456789ABCDEF" : |
||
899 |
"0123456789abcdef"; |
||
900 |
do { |
||
901 |
*--s = digits[llnum & 0xf]; |
||
902 |
llnum >>= 4; |
||
903 |
} while (llnum); |
||
904 |
|||
905 |
if (flags & FL_HASH) { |
||
906 |
*--s = (flags & FL_UPPER) ? 'X' : 'x'; |
||
907 |
*--s = '0'; |
||
908 |
} |
||
909 |
} |
||
910 |
} |
||
911 |
19803 |
len = &numbuf[sizeof(numbuf)] - s; |
|
912 |
✓✓ | 19803 |
if (flags & FL_DOT) { |
913 |
✗✓ | 34 |
if (precision > len) { |
914 |
field = precision; |
||
915 |
flags |= FL_ZERO; |
||
916 |
} else |
||
917 |
precision = len; /* no loss */ |
||
918 |
} |
||
919 |
break; |
||
920 |
|||
921 |
case 's': |
||
922 |
✓✓ | 1431873 |
if (!(s = va_arg(args, char *))) |
923 |
s = "(null %s)"; |
||
924 |
477291 |
len = strlen(s); |
|
925 |
477291 |
break; |
|
926 |
|||
927 |
case 'c': |
||
928 |
200 |
flags &= ~FL_DOT; |
|
929 |
✓✗ | 600 |
numbuf[0] = va_arg(args, int); |
930 |
200 |
s = numbuf; |
|
931 |
len = 1; |
||
932 |
200 |
break; |
|
933 |
|||
934 |
case '%': |
||
935 |
default: |
||
936 |
numbuf[0] = c; |
||
937 |
s = numbuf; |
||
938 |
len = 1; |
||
939 |
break; |
||
940 |
} |
||
941 |
|||
942 |
/* |
||
943 |
* At this point s should point to a string that is |
||
944 |
* to be formatted, and len should be the length of the |
||
945 |
* string. |
||
946 |
*/ |
||
947 |
✓✓✗✓ |
497328 |
if (!(flags & FL_DOT) || len < precision) |
948 |
497260 |
precision = len; |
|
949 |
✓✓ | 497294 |
if (field > precision) { |
950 |
18442 |
field -= precision; |
|
951 |
✓✓ | 18442 |
if (!(flags & FL_RIGHT)) { |
952 |
15416 |
field = -field; |
|
953 |
/* skip past sign or 0x when padding with 0 */ |
||
954 |
✓✓✓✗ |
23437 |
if ((flags & FL_ZERO) && (flags & FL_NUMBER)) { |
955 |
✓✗✓✗ ✗✓ |
24063 |
if (*s == '+' || *s == '-' || *s ==' ') { |
956 |
shf_putc(*s, shf); |
||
957 |
s++; |
||
958 |
precision--; |
||
959 |
nwritten++; |
||
960 |
✓✓ | 8021 |
} else if (*s == '0') { |
961 |
✗✓ | 10982 |
shf_putc(*s, shf); |
962 |
5491 |
s++; |
|
963 |
5491 |
nwritten++; |
|
964 |
✗✓✗✗ |
5491 |
if (--precision > 0 && |
965 |
(*s | 0x20) == 'x') { |
||
966 |
shf_putc(*s, shf); |
||
967 |
s++; |
||
968 |
precision--; |
||
969 |
nwritten++; |
||
970 |
} |
||
971 |
} |
||
972 |
c = '0'; |
||
973 |
8021 |
} else |
|
974 |
7395 |
c = flags & FL_ZERO ? '0' : ' '; |
|
975 |
✓✗ | 15416 |
if (field < 0) { |
976 |
15416 |
nwritten += -field; |
|
977 |
✓✓ | 97468 |
for ( ; field < 0 ; field++) |
978 |
✓✓ | 66636 |
shf_putc(c, shf); |
979 |
} |
||
980 |
} else |
||
981 |
c = ' '; |
||
982 |
} else |
||
983 |
field = 0; |
||
984 |
|||
985 |
✓✓ | 497294 |
if (precision > 0) { |
986 |
480953 |
nwritten += precision; |
|
987 |
✓✓ | 5422784 |
for ( ; precision-- > 0 ; s++) |
988 |
✓✓ | 4460878 |
shf_putc(*s, shf); |
989 |
} |
||
990 |
✓✓ | 497294 |
if (field > 0) { |
991 |
3026 |
nwritten += field; |
|
992 |
✓✓ | 31436 |
for ( ; field > 0 ; --field) |
993 |
✗✓ | 25384 |
shf_putc(c, shf); |
994 |
} |
||
995 |
} |
||
996 |
|||
997 |
423961 |
return shf_error(shf) ? EOF : nwritten; |
|
998 |
423961 |
} |
Generated by: GCOVR (Version 3.3) |