getdelim.c raw

   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);
  84