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