master
 1#include "stdio_impl.h"
 2#include <string.h>
 3#include <stdlib.h>
 4#include <inttypes.h>
 5#include <errno.h>
 6
 7ssize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f)
 8{
 9	char *tmp;
10	unsigned char *z;
11	size_t k;
12	size_t i=0;
13	int c;
14
15	FLOCK(f);
16
17	if (!n || !s) {
18		f->mode |= f->mode-1;
19		f->flags |= F_ERR;
20		FUNLOCK(f);
21		errno = EINVAL;
22		return -1;
23	}
24
25	if (!*s) *n=0;
26
27	for (;;) {
28		if (f->rpos != f->rend) {
29			z = memchr(f->rpos, delim, f->rend - f->rpos);
30			k = z ? z - f->rpos + 1 : f->rend - f->rpos;
31		} else {
32			z = 0;
33			k = 0;
34		}
35		if (i+k >= *n) {
36			size_t m = i+k+2;
37			if (!z && m < SIZE_MAX/4) m += m/2;
38			tmp = realloc(*s, m);
39			if (!tmp) {
40				m = i+k+2;
41				tmp = realloc(*s, m);
42				if (!tmp) {
43					/* Copy as much as fits and ensure no
44					 * pushback remains in the FILE buf. */
45					k = *n-i;
46					memcpy(*s+i, f->rpos, k);
47					f->rpos += k;
48					f->mode |= f->mode-1;
49					f->flags |= F_ERR;
50					FUNLOCK(f);
51					errno = ENOMEM;
52					return -1;
53				}
54			}
55			*s = tmp;
56			*n = m;
57		}
58		if (k) {
59			memcpy(*s+i, f->rpos, k);
60			f->rpos += k;
61			i += k;
62		}
63		if (z) break;
64		if ((c = getc_unlocked(f)) == EOF) {
65			if (!i || !feof(f)) {
66				FUNLOCK(f);
67				return -1;
68			}
69			break;
70		}
71		/* If the byte read by getc won't fit without growing the
72		 * output buffer, push it back for next iteration. */
73		if (i+1 >= *n) *--f->rpos = c;
74		else if (((*s)[i++] = c) == delim) break;
75	}
76	(*s)[i] = 0;
77
78	FUNLOCK(f);
79
80	return i;
81}
82
83weak_alias(getdelim, __getdelim);