]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gperf/lib/getline.cc
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gperf / lib / getline.cc
1 /* getline.c -- Replacement for GNU C library function getline
2
3 Copyright (C) 1993, 1996, 2001-2002 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 USA. */
19
20 /* Written by Jan Brittenson, bson@gnu.ai.mit.edu.  */
21
22 /* Specification.  */
23 #include "getline.h"
24
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29
30 /* Always add at least this many bytes when extending the buffer.  */
31 #define MIN_CHUNK 64
32
33 /* Reads up to (and including) a TERMINATOR from STREAM into *LINEPTR + OFFSET
34    (and null-terminate it). *LINEPTR is a pointer returned from new [] (or
35    NULL), pointing to *N characters of space.  It is realloc'd as
36    necessary.  Returns the number of characters read (not including the
37    null terminator), or -1 on error or immediate EOF.
38    NOTE: There is another getstr() function declared in <curses.h>.  */
39
40 static int
41 getstr (char **lineptr, size_t *n, FILE *stream, char terminator, size_t offset)
42 {
43   size_t nchars_avail;          /* Allocated but unused chars in *LINEPTR.  */
44   char *read_pos;               /* Where we're reading into *LINEPTR. */
45
46   if (!lineptr || !n || !stream)
47     return -1;
48
49   if (!*lineptr)
50     {
51       *n = MIN_CHUNK;
52       *lineptr = new char[*n];
53     }
54
55   nchars_avail = *n - offset;
56   read_pos = *lineptr + offset;
57
58   for (;;)
59     {
60       register int c = getc (stream);
61
62       /* We always want at least one char left in the buffer, since we
63          always (unless we get an error while reading the first char)
64          NUL-terminate the line buffer.  */
65
66       assert (*n - nchars_avail == (size_t) (read_pos - *lineptr));
67       if (nchars_avail < 2)
68         {
69           if (*n > MIN_CHUNK)
70             *n *= 2;
71           else
72             *n += MIN_CHUNK;
73
74           nchars_avail = *n + *lineptr - read_pos;
75           char *new_line = new char[*n];
76           if (*lineptr)
77             {
78               memcpy (new_line, *lineptr, read_pos - *lineptr);
79               delete[] *lineptr;
80             }
81           *lineptr = new_line;
82           read_pos = *n - nchars_avail + *lineptr;
83           assert (*n - nchars_avail == (size_t) (read_pos - *lineptr));
84         }
85
86       if (c == EOF || ferror (stream))
87         {
88           /* Return partial line, if any.  */
89           if (read_pos == *lineptr)
90             return -1;
91           else
92             break;
93         }
94
95       *read_pos++ = c;
96       nchars_avail--;
97
98       if (c == terminator)
99         /* Return the line.  */
100         break;
101     }
102
103   /* Done - NUL terminate and return the number of chars read.  */
104   *read_pos = '\0';
105
106   return read_pos - (*lineptr + offset);
107 }
108
109 int
110 get_line (char **lineptr, size_t *n, FILE *stream)
111 {
112   return getstr (lineptr, n, stream, '\n', 0);
113 }
114
115 int
116 get_delim (char **lineptr, size_t *n, int delimiter, FILE *stream)
117 {
118   return getstr (lineptr, n, stream, delimiter, 0);
119 }