| 1 | #include "stdio_impl.h" |
| 2 | #include <string.h> |
| 3 | #include <stdlib.h> |
| 4 | #include <inttypes.h> |
| 5 | #include <errno.h> |
| 6 | |
| 7 | ssize_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 | |
| 83 | weak_alias(getdelim, __getdelim); |