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