Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / getdelim.c
blob90cd5d47faf63322f307204ae878e2cc4b08ccef
1 /* Copyright 2002, Red Hat Inc. - all rights reserved */
2 /*
3 FUNCTION
4 <<getdelim>>---read a line up to a specified line delimiter
6 INDEX
7 getdelim
9 SYNOPSIS
10 #include <stdio.h>
11 int getdelim(char **<[bufptr]>, size_t *<[n]>,
12 int <[delim]>, FILE *<[fp]>);
14 DESCRIPTION
15 <<getdelim>> reads a file <[fp]> up to and possibly including a specified
16 delimiter <[delim]>. The line is read into a buffer pointed to
17 by <[bufptr]> and designated with size *<[n]>. If the buffer is
18 not large enough, it will be dynamically grown by <<getdelim>>.
19 As the buffer is grown, the pointer to the size <[n]> will be
20 updated.
22 RETURNS
23 <<getdelim>> returns <<-1>> if no characters were successfully read;
24 otherwise, it returns the number of bytes successfully read.
25 At end of file, the result is nonzero.
27 PORTABILITY
28 <<getdelim>> is a glibc extension.
30 No supporting OS subroutines are directly required.
33 #include <_ansi.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include "local.h"
39 #define MIN_LINE_SIZE 4
40 #define DEFAULT_LINE_SIZE 128
42 ssize_t
43 __getdelim (char **bufptr,
44 size_t *n,
45 int delim,
46 FILE *fp)
48 char *buf;
49 char *ptr;
50 size_t newsize, numbytes;
51 int pos;
52 int ch;
53 int cont;
55 if (fp == NULL || bufptr == NULL || n == NULL)
57 errno = EINVAL;
58 return -1;
61 buf = *bufptr;
62 if (buf == NULL || *n < MIN_LINE_SIZE)
64 buf = (char *)realloc (*bufptr, DEFAULT_LINE_SIZE);
65 if (buf == NULL)
67 return -1;
69 *bufptr = buf;
70 *n = DEFAULT_LINE_SIZE;
73 CHECK_INIT (_REENT, fp);
75 _newlib_flockfile_start (fp);
77 numbytes = *n;
78 ptr = buf;
80 cont = 1;
82 while (cont)
84 /* fill buffer - leaving room for nul-terminator */
85 while (--numbytes > 0)
87 if ((ch = getc_unlocked (fp)) == EOF)
89 cont = 0;
90 break;
92 else
94 *ptr++ = ch;
95 if (ch == delim)
97 cont = 0;
98 break;
103 if (cont)
105 /* Buffer is too small so reallocate a larger buffer. */
106 pos = ptr - buf;
107 newsize = (*n << 1);
108 buf = realloc (buf, newsize);
109 if (buf == NULL)
111 cont = 0;
112 break;
115 /* After reallocating, continue in new buffer */
116 *bufptr = buf;
117 *n = newsize;
118 ptr = buf + pos;
119 numbytes = newsize - pos;
123 _newlib_flockfile_end (fp);
125 /* if no input data, return failure */
126 if (ptr == buf)
127 return -1;
129 /* otherwise, nul-terminate and return number of bytes read */
130 *ptr = '\0';
131 return (ssize_t)(ptr - buf);