xref: /openbsd-src/gnu/usr.bin/cvs/lib/getline.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
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 
26 #if STDC_HEADERS
27 #include <stdlib.h>
28 #else
29 char *malloc (), *realloc ();
30 #endif
31 
32 /* Always add at least this many bytes when extending the buffer.  */
33 #define MIN_CHUNK 64
34 
35 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
36    + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
37    malloc (or NULL), pointing to *N characters of space.  It is realloc'd
38    as necessary.  Return the number of characters read (not including the
39    null terminator), or -1 on error or EOF.  On a -1 return, the caller
40    should check feof(), if not then errno has been set to indicate
41    the error.  */
42 
43 int
44 getstr (lineptr, n, stream, terminator, offset)
45      char **lineptr;
46      size_t *n;
47      FILE *stream;
48      char terminator;
49      int offset;
50 {
51   int nchars_avail;		/* Allocated but unused chars in *LINEPTR.  */
52   char *read_pos;		/* Where we're reading into *LINEPTR. */
53   int ret;
54 
55   if (!lineptr || !n || !stream)
56     {
57       errno = EINVAL;
58       return -1;
59     }
60 
61   if (!*lineptr)
62     {
63       *n = MIN_CHUNK;
64       *lineptr = malloc (*n);
65       if (!*lineptr)
66 	{
67 	  errno = ENOMEM;
68 	  return -1;
69 	}
70     }
71 
72   nchars_avail = *n - offset;
73   read_pos = *lineptr + offset;
74 
75   for (;;)
76     {
77       int save_errno;
78       register int c = getc (stream);
79 
80       save_errno = errno;
81 
82       /* We always want at least one char left in the buffer, since we
83 	 always (unless we get an error while reading the first char)
84 	 NUL-terminate the line buffer.  */
85 
86       assert((*lineptr + *n) == (read_pos + nchars_avail));
87       if (nchars_avail < 2)
88 	{
89 	  if (*n > MIN_CHUNK)
90 	    *n *= 2;
91 	  else
92 	    *n += MIN_CHUNK;
93 
94 	  nchars_avail = *n + *lineptr - read_pos;
95 	  *lineptr = realloc (*lineptr, *n);
96 	  if (!*lineptr)
97 	    {
98 	      errno = ENOMEM;
99 	      return -1;
100 	    }
101 	  read_pos = *n - nchars_avail + *lineptr;
102 	  assert((*lineptr + *n) == (read_pos + nchars_avail));
103 	}
104 
105       if (ferror (stream))
106 	{
107 	  /* Might like to return partial line, but there is no
108 	     place for us to store errno.  And we don't want to just
109 	     lose errno.  */
110 	  errno = save_errno;
111 	  return -1;
112 	}
113 
114       if (c == EOF)
115 	{
116 	  /* Return partial line, if any.  */
117 	  if (read_pos == *lineptr)
118 	    return -1;
119 	  else
120 	    break;
121 	}
122 
123       *read_pos++ = c;
124       nchars_avail--;
125 
126       if (c == terminator)
127 	/* Return the line.  */
128 	break;
129     }
130 
131   /* Done - NUL terminate and return the number of chars read.  */
132   *read_pos = '\0';
133 
134   ret = read_pos - (*lineptr + offset);
135   return ret;
136 }
137 
138 int
139 getline (lineptr, n, stream)
140      char **lineptr;
141      size_t *n;
142      FILE *stream;
143 {
144   return getstr (lineptr, n, stream, '\n', 0);
145 }
146