1570af302Sopenharmony_ci#include "stdio_impl.h"
2570af302Sopenharmony_ci#include <string.h>
3570af302Sopenharmony_ci#include <stdlib.h>
4570af302Sopenharmony_ci#include <inttypes.h>
5570af302Sopenharmony_ci#include <errno.h>
6570af302Sopenharmony_ci
7570af302Sopenharmony_cissize_t getdelim(char **restrict s, size_t *restrict n, int delim, FILE *restrict f)
8570af302Sopenharmony_ci{
9570af302Sopenharmony_ci	char *tmp;
10570af302Sopenharmony_ci	unsigned char *z;
11570af302Sopenharmony_ci	size_t k;
12570af302Sopenharmony_ci	size_t i=0;
13570af302Sopenharmony_ci	int c;
14570af302Sopenharmony_ci
15570af302Sopenharmony_ci	FLOCK(f);
16570af302Sopenharmony_ci
17570af302Sopenharmony_ci	if (!n || !s) {
18570af302Sopenharmony_ci		f->mode |= f->mode-1;
19570af302Sopenharmony_ci		f->flags |= F_ERR;
20570af302Sopenharmony_ci		FUNLOCK(f);
21570af302Sopenharmony_ci		errno = EINVAL;
22570af302Sopenharmony_ci		return -1;
23570af302Sopenharmony_ci	}
24570af302Sopenharmony_ci
25570af302Sopenharmony_ci	if (!*s) *n=0;
26570af302Sopenharmony_ci
27570af302Sopenharmony_ci	for (;;) {
28570af302Sopenharmony_ci		if (f->rpos != f->rend) {
29570af302Sopenharmony_ci			z = memchr(f->rpos, delim, f->rend - f->rpos);
30570af302Sopenharmony_ci			k = z ? z - f->rpos + 1 : f->rend - f->rpos;
31570af302Sopenharmony_ci		} else {
32570af302Sopenharmony_ci			z = 0;
33570af302Sopenharmony_ci			k = 0;
34570af302Sopenharmony_ci		}
35570af302Sopenharmony_ci		if (i+k >= *n) {
36570af302Sopenharmony_ci			size_t m = i+k+2;
37570af302Sopenharmony_ci			if (!z && m < SIZE_MAX/4) m += m/2;
38570af302Sopenharmony_ci			tmp = realloc(*s, m);
39570af302Sopenharmony_ci			if (!tmp) {
40570af302Sopenharmony_ci				m = i+k+2;
41570af302Sopenharmony_ci				tmp = realloc(*s, m);
42570af302Sopenharmony_ci				if (!tmp) {
43570af302Sopenharmony_ci					/* Copy as much as fits and ensure no
44570af302Sopenharmony_ci					 * pushback remains in the FILE buf. */
45570af302Sopenharmony_ci					k = *n-i;
46570af302Sopenharmony_ci					memcpy(*s+i, f->rpos, k);
47570af302Sopenharmony_ci					f->rpos += k;
48570af302Sopenharmony_ci					f->mode |= f->mode-1;
49570af302Sopenharmony_ci					f->flags |= F_ERR;
50570af302Sopenharmony_ci					FUNLOCK(f);
51570af302Sopenharmony_ci					errno = ENOMEM;
52570af302Sopenharmony_ci					return -1;
53570af302Sopenharmony_ci				}
54570af302Sopenharmony_ci			}
55570af302Sopenharmony_ci			*s = tmp;
56570af302Sopenharmony_ci			*n = m;
57570af302Sopenharmony_ci		}
58570af302Sopenharmony_ci		if (k) {
59570af302Sopenharmony_ci			memcpy(*s+i, f->rpos, k);
60570af302Sopenharmony_ci			f->rpos += k;
61570af302Sopenharmony_ci			i += k;
62570af302Sopenharmony_ci		}
63570af302Sopenharmony_ci		if (z) break;
64570af302Sopenharmony_ci		if ((c = getc_unlocked(f)) == EOF) {
65570af302Sopenharmony_ci			if (!i || !feof(f)) {
66570af302Sopenharmony_ci				FUNLOCK(f);
67570af302Sopenharmony_ci				return -1;
68570af302Sopenharmony_ci			}
69570af302Sopenharmony_ci			break;
70570af302Sopenharmony_ci		}
71570af302Sopenharmony_ci		/* If the byte read by getc won't fit without growing the
72570af302Sopenharmony_ci		 * output buffer, push it back for next iteration. */
73570af302Sopenharmony_ci		if (i+1 >= *n) *--f->rpos = c;
74570af302Sopenharmony_ci		else if (((*s)[i++] = c) == delim) break;
75570af302Sopenharmony_ci	}
76570af302Sopenharmony_ci	(*s)[i] = 0;
77570af302Sopenharmony_ci
78570af302Sopenharmony_ci	FUNLOCK(f);
79570af302Sopenharmony_ci
80570af302Sopenharmony_ci	return i;
81570af302Sopenharmony_ci}
82570af302Sopenharmony_ci
83570af302Sopenharmony_ciweak_alias(getdelim, __getdelim);
84