1 /* Copyright 2002, Red Hat Inc. - all rights reserved */
2 /*
3 FUNCTION
4 <<getdelim>>---read a line up to a specified line delimiter
5 
6 INDEX
7 	getdelim
8 
9 SYNOPSIS
10 	#include <stdio.h>
11 	int getdelim(char **<[bufptr]>, size_t *<[n]>,
12                      int <[delim]>, FILE *<[fp]>);
13 
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.
21 
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.
26 
27 PORTABILITY
28 <<getdelim>> is a glibc extension.
29 
30 No supporting OS subroutines are directly required.
31 */
32 
33 #define _DEFAULT_SOURCE
34 #define _DEFAULT_SOURCE
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include "local.h"
39 
40 #define MIN_LINE_SIZE 4
41 #define DEFAULT_LINE_SIZE 128
42 
43 ssize_t
__getdelim(char ** bufptr,size_t * n,int delim,FILE * fp)44 __getdelim (char **bufptr,
45        size_t *n,
46        int delim,
47        FILE *fp)
48 {
49   char *buf;
50   char *ptr;
51   size_t newsize, numbytes;
52   int pos;
53   int ch;
54   int cont;
55 
56   if (fp == NULL || bufptr == NULL || n == NULL)
57     {
58       errno = EINVAL;
59       return -1;
60     }
61 
62   buf = *bufptr;
63   if (buf == NULL || *n < MIN_LINE_SIZE)
64     {
65       buf = (char *)realloc (*bufptr, DEFAULT_LINE_SIZE);
66       if (buf == NULL)
67         {
68 	  return -1;
69         }
70       *bufptr = buf;
71       *n = DEFAULT_LINE_SIZE;
72     }
73 
74   CHECK_INIT (_REENT, fp);
75 
76   _newlib_flockfile_start (fp);
77 
78   numbytes = *n;
79   ptr = buf;
80 
81   cont = 1;
82 
83   while (cont)
84     {
85       /* fill buffer - leaving room for nul-terminator */
86       while (--numbytes > 0)
87         {
88           if ((ch = getc_unlocked (fp)) == EOF)
89             {
90 	      cont = 0;
91               break;
92             }
93 	  else
94             {
95               *ptr++ = ch;
96               if (ch == delim)
97                 {
98                   cont = 0;
99                   break;
100                 }
101             }
102         }
103 
104       if (cont)
105         {
106           /* Buffer is too small so reallocate a larger buffer.  */
107           pos = ptr - buf;
108           newsize = (*n << 1);
109           buf = realloc (buf, newsize);
110           if (buf == NULL)
111             {
112               cont = 0;
113               break;
114             }
115 
116           /* After reallocating, continue in new buffer */
117           *bufptr = buf;
118           *n = newsize;
119           ptr = buf + pos;
120           numbytes = newsize - pos;
121         }
122     }
123 
124   _newlib_flockfile_end (fp);
125 
126   /* if no input data, return failure */
127   if (ptr == buf)
128     return -1;
129 
130   /* otherwise, nul-terminate and return number of bytes read */
131   *ptr = '\0';
132   return (ssize_t)(ptr - buf);
133 }
134 
135