xref: /openbsd-src/gnu/usr.bin/cvs/lib/getline.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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      char 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     }
77 
78   nchars_avail = *n - offset;
79   read_pos = *lineptr + offset;
80 
81   for (;;)
82     {
83       int save_errno;
84       register int c;
85 
86       if (limit == 0)
87           break;
88       else
89       {
90           c = getc (stream);
91 
92           /* If limit is negative, then we shouldn't pay attention to
93              it, so decrement only if positive. */
94           if (limit > 0)
95               limit--;
96       }
97 
98       save_errno = errno;
99 
100       /* We always want at least one char left in the buffer, since we
101 	 always (unless we get an error while reading the first char)
102 	 NUL-terminate the line buffer.  */
103 
104       assert((*lineptr + *n) == (read_pos + nchars_avail));
105       if (nchars_avail < 2)
106 	{
107 	  if (*n > MIN_CHUNK)
108 	    *n *= 2;
109 	  else
110 	    *n += MIN_CHUNK;
111 
112 	  nchars_avail = *n + *lineptr - read_pos;
113 	  *lineptr = realloc (*lineptr, *n);
114 	  if (!*lineptr)
115 	    {
116 	      errno = ENOMEM;
117 	      return -1;
118 	    }
119 	  read_pos = *n - nchars_avail + *lineptr;
120 	  assert((*lineptr + *n) == (read_pos + nchars_avail));
121 	}
122 
123       if (ferror (stream))
124 	{
125 	  /* Might like to return partial line, but there is no
126 	     place for us to store errno.  And we don't want to just
127 	     lose errno.  */
128 	  errno = save_errno;
129 	  return -1;
130 	}
131 
132       if (c == EOF)
133 	{
134 	  /* Return partial line, if any.  */
135 	  if (read_pos == *lineptr)
136 	    return -1;
137 	  else
138 	    break;
139 	}
140 
141       *read_pos++ = c;
142       nchars_avail--;
143 
144       if (c == terminator)
145 	/* Return the line.  */
146 	break;
147     }
148 
149   /* Done - NUL terminate and return the number of chars read.  */
150   *read_pos = '\0';
151 
152   ret = read_pos - (*lineptr + offset);
153   return ret;
154 }
155 
156 int
157 getline (lineptr, n, stream)
158      char **lineptr;
159      size_t *n;
160      FILE *stream;
161 {
162   return getstr (lineptr, n, stream, '\n', 0, GETLINE_NO_LIMIT);
163 }
164 
165 int
166 getline_safe (lineptr, n, stream, limit)
167      char **lineptr;
168      size_t *n;
169      FILE *stream;
170      int limit;
171 {
172   return getstr (lineptr, n, stream, '\n', 0, limit);
173 }
174