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