]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/lib/getline.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / lib / getline.c
1 /* getline.c -- Replacement for GNU C library function getline
2
3 Copyright (C) 1993 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 /* Written by Jan Brittenson, bson@gnu.ai.mit.edu.  */
16
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include "getline.h"
26
27 #if STDC_HEADERS
28 #include <stdlib.h>
29 #else
30 char *malloc (), *realloc ();
31 #endif
32
33 /* Always add at least this many bytes when extending the buffer.  */
34 #define MIN_CHUNK 64
35
36 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
37    + OFFSET (and null-terminate it).  If LIMIT is non-negative, then
38    read no more than LIMIT chars.
39
40    *LINEPTR is a pointer returned from malloc (or NULL), pointing to
41    *N characters of space.  It is realloc'd as necessary.  
42
43    Return the number of characters read (not including the null
44    terminator), or -1 on error or EOF.  On a -1 return, the caller
45    should check feof(), if not then errno has been set to indicate the
46    error.  */
47
48 int
49 getstr (lineptr, n, stream, terminator, offset, limit)
50      char **lineptr;
51      size_t *n;
52      FILE *stream;
53      int terminator;
54      int offset;
55      int limit;
56 {
57   int nchars_avail;             /* Allocated but unused chars in *LINEPTR.  */
58   char *read_pos;               /* Where we're reading into *LINEPTR. */
59   int ret;
60
61   if (!lineptr || !n || !stream)
62     {
63       errno = EINVAL;
64       return -1;
65     }
66
67   if (!*lineptr)
68     {
69       *n = MIN_CHUNK;
70       *lineptr = malloc (*n);
71       if (!*lineptr)
72         {
73           errno = ENOMEM;
74           return -1;
75         }
76       *lineptr[0] = '\0';
77     }
78
79   nchars_avail = *n - offset;
80   read_pos = *lineptr + offset;
81
82   for (;;)
83     {
84       int save_errno;
85       register int c;
86
87       if (limit == 0)
88           break;
89       else
90       {
91           c = getc (stream);
92
93           /* If limit is negative, then we shouldn't pay attention to
94              it, so decrement only if positive. */
95           if (limit > 0)
96               limit--;
97       }
98
99       save_errno = errno;
100
101       /* We always want at least one char left in the buffer, since we
102          always (unless we get an error while reading the first char)
103          NUL-terminate the line buffer.  */
104
105       assert((*lineptr + *n) == (read_pos + nchars_avail));
106       if (nchars_avail < 2)
107         {
108           if (*n > MIN_CHUNK)
109             *n *= 2;
110           else
111             *n += MIN_CHUNK;
112
113           nchars_avail = *n + *lineptr - read_pos;
114           *lineptr = realloc (*lineptr, *n);
115           if (!*lineptr)
116             {
117               errno = ENOMEM;
118               return -1;
119             }
120           read_pos = *n - nchars_avail + *lineptr;
121           assert((*lineptr + *n) == (read_pos + nchars_avail));
122         }
123
124       if (ferror (stream))
125         {
126           /* Might like to return partial line, but there is no
127              place for us to store errno.  And we don't want to just
128              lose errno.  */
129           errno = save_errno;
130           return -1;
131         }
132
133       if (c == EOF)
134         {
135           /* Return partial line, if any.  */
136           if (read_pos == *lineptr)
137             return -1;
138           else
139             break;
140         }
141
142       *read_pos++ = c;
143       nchars_avail--;
144
145       if (c == terminator)
146         /* Return the line.  */
147         break;
148     }
149
150   /* Done - NUL terminate and return the number of chars read.  */
151   *read_pos = '\0';
152
153   ret = read_pos - (*lineptr + offset);
154   return ret;
155 }
156
157 int
158 getline (lineptr, n, stream)
159      char **lineptr;
160      size_t *n;
161      FILE *stream;
162 {
163   return getstr (lineptr, n, stream, '\n', 0, GETLINE_NO_LIMIT);
164 }
165
166 int
167 getline_safe (lineptr, n, stream, limit)
168      char **lineptr;
169      size_t *n;
170      FILE *stream;
171      int limit;
172 {
173   return getstr (lineptr, n, stream, '\n', 0, limit);
174 }