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 <_ansi.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 #include "local.h"
40 
41 #define MIN_LINE_SIZE 4
42 #define DEFAULT_LINE_SIZE 128
43 
44 ssize_t
__getdelim(char ** bufptr,size_t * n,int delim,FILE * fp)45 __getdelim (char **bufptr,
46        size_t *n,
47        int delim,
48        FILE *fp)
49 {
50   char *buf;
51   char *ptr;
52   size_t newsize, numbytes;
53   int pos;
54   int ch;
55   int cont;
56 
57   if (fp == NULL || bufptr == NULL || n == NULL)
58     {
59       errno = EINVAL;
60       return -1;
61     }
62 
63   buf = *bufptr;
64   if (buf == NULL || *n < MIN_LINE_SIZE)
65     {
66       buf = (char *)realloc (*bufptr, DEFAULT_LINE_SIZE);
67       if (buf == NULL)
68         {
69 	  return -1;
70         }
71       *bufptr = buf;
72       *n = DEFAULT_LINE_SIZE;
73     }
74 
75   CHECK_INIT (_REENT, fp);
76 
77   _newlib_flockfile_start (fp);
78 
79   numbytes = *n;
80   ptr = buf;
81 
82   cont = 1;
83 
84   while (cont)
85     {
86       /* fill buffer - leaving room for nul-terminator */
87       while (--numbytes > 0)
88         {
89           if ((ch = getc_unlocked (fp)) == EOF)
90             {
91 	      cont = 0;
92               break;
93             }
94 	  else
95             {
96               *ptr++ = ch;
97               if (ch == delim)
98                 {
99                   cont = 0;
100                   break;
101                 }
102             }
103         }
104 
105       if (cont)
106         {
107           /* Buffer is too small so reallocate a larger buffer.  */
108           pos = ptr - buf;
109           newsize = (*n << 1);
110           buf = realloc (buf, newsize);
111           if (buf == NULL)
112             {
113               cont = 0;
114               break;
115             }
116 
117           /* After reallocating, continue in new buffer */
118           *bufptr = buf;
119           *n = newsize;
120           ptr = buf + pos;
121           numbytes = newsize - pos;
122         }
123     }
124 
125   _newlib_flockfile_end (fp);
126 
127   /* if no input data, return failure */
128   if (ptr == buf)
129     return -1;
130 
131   /* otherwise, nul-terminate and return number of bytes read */
132   *ptr = '\0';
133   return (ssize_t)(ptr - buf);
134 }
135 
136