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