1 /*
2 FUNCTION
3 <<getdelim>>---read a line up to a specified line delimeter
4 
5 INDEX
6 	getdelim
7 
8 ANSI_SYNOPSIS
9 	#include <stdio.h>
10 	int getdelim(char **<[bufptr]>, size_t *<[n]>,
11                      int <[delim]>, FILE *<[fp]>);
12 
13 TRAD_SYNOPSIS
14 	#include <stdio.h>
15 	int getdelim(<[bufptr]>, <[n]>, <[delim]>, <[fp]>)
16 	char **<[bufptr]>;
17 	size_t *<[n]>;
18 	int <[delim]>;
19 	FILE *<[fp]>;
20 
21 DESCRIPTION
22 <<getdelim>> reads a file <[fp]> up to and possibly including a specified
23 delimeter <[delim]>.  The line is read into a buffer pointed to
24 by <[bufptr]> and designated with size *<[n]>.  If the buffer is
25 not large enough, it will be dynamically grown by <<getdelim>>.
26 As the buffer is grown, the pointer to the size <[n]> will be
27 updated.
28 
29 RETURNS
30 <<getdelim>> returns <<-1>> if no characters were successfully read,
31 otherwise, it returns the number of bytes successfully read.
32 at end of file, the result is nonzero.
33 
34 PORTABILITY
35 <<getdelim>> is a glibc extension.
36 
37 No supporting OS subroutines are directly required.
38 */
39 
40 /* Copyright 2002, Red Hat Inc. - all rights reserved */
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <errno.h>
45 #include "local.h"
46 
47 #define MIN_LINE_SIZE 4
48 #define DEFAULT_LINE_SIZE 128
49 
50 ssize_t
51 __getdelim (bufptr, n, delim, fp)
52      char **bufptr;
53      size_t *n;
54      int delim;
55      FILE *fp;
56 {
57   char *buf;
58   char *ptr;
59   size_t newsize, numbytes;
60   int pos;
61   int ch;
62   int cont;
63 
64   if (fp == NULL || bufptr == NULL || n == NULL)
65     {
66       errno = EINVAL;
67       return -1;
68     }
69 
70   buf = *bufptr;
71   if (buf == NULL || *n < MIN_LINE_SIZE)
72     {
73       buf = (char *)realloc (*bufptr, DEFAULT_LINE_SIZE);
74       if (buf == NULL)
75         {
76 	  return -1;
77         }
78       *bufptr = buf;
79       *n = DEFAULT_LINE_SIZE;
80     }
81 
82   _flockfile(fp);
83 
84   CHECK_INIT(fp);
85 
86   numbytes = *n;
87   ptr = buf;
88 
89   cont = 1;
90 
91   while (cont)
92     {
93       /* fill buffer - leaving room for nul-terminator */
94       while (--numbytes > 0)
95         {
96           if ((ch = getc_unlocked (fp)) == EOF)
97             {
98 	      cont = 0;
99               break;
100             }
101 	  else
102             {
103               *ptr++ = ch;
104               if (ch == delim)
105                 {
106                   cont = 0;
107                   break;
108                 }
109             }
110         }
111 
112       if (cont)
113         {
114           /* Buffer is too small so reallocate a larger buffer.  */
115           pos = ptr - buf;
116           newsize = (*n << 1);
117           buf = realloc (buf, newsize);
118           if (buf == NULL)
119             {
120               cont = 0;
121               break;
122             }
123 
124           /* After reallocating, continue in new buffer */
125           *bufptr = buf;
126           *n = newsize;
127           ptr = buf + pos;
128           numbytes = newsize - pos;
129         }
130     }
131 
132   _funlockfile (fp);
133 
134   /* if no input data, return failure */
135   if (ptr == buf)
136     return -1;
137 
138   /* otherwise, nul-terminate and return number of bytes read */
139   *ptr = '\0';
140   return (ssize_t)(ptr - buf);
141 }
142 
143