1228060Sbapt/* getline.c -- Replacement for GNU C library function getline
2228060Sbapt
3228060SbaptCopyright (C) 1993, 1996, 2001-2002 Free Software Foundation, Inc.
4228060Sbapt
5228060SbaptThis program is free software; you can redistribute it and/or
6228060Sbaptmodify it under the terms of the GNU General Public License as
7228060Sbaptpublished by the Free Software Foundation; either version 2 of the
8228060SbaptLicense, or (at your option) any later version.
9228060Sbapt
10228060SbaptThis program is distributed in the hope that it will be useful, but
11228060SbaptWITHOUT ANY WARRANTY; without even the implied warranty of
12228060SbaptMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13228060SbaptGeneral Public License for more details.
14228060Sbapt
15228060SbaptYou should have received a copy of the GNU General Public License
16228060Sbaptalong with this program; if not, write to the Free Software
17228060SbaptFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18228060SbaptUSA. */
19228060Sbapt
20228060Sbapt/* Written by Jan Brittenson, bson@gnu.ai.mit.edu.  */
21228060Sbapt
22228060Sbapt/* Specification.  */
23228060Sbapt#include "getline.h"
24228060Sbapt
25228060Sbapt#include <stddef.h>
26228060Sbapt#include <stdio.h>
27228060Sbapt#include <string.h>
28228060Sbapt#include <assert.h>
29228060Sbapt
30228060Sbapt/* Always add at least this many bytes when extending the buffer.  */
31228060Sbapt#define MIN_CHUNK 64
32228060Sbapt
33228060Sbapt/* Reads up to (and including) a TERMINATOR from STREAM into *LINEPTR + OFFSET
34228060Sbapt   (and null-terminate it). *LINEPTR is a pointer returned from new [] (or
35228060Sbapt   NULL), pointing to *N characters of space.  It is realloc'd as
36228060Sbapt   necessary.  Returns the number of characters read (not including the
37228060Sbapt   null terminator), or -1 on error or immediate EOF.
38228060Sbapt   NOTE: There is another getstr() function declared in <curses.h>.  */
39228060Sbapt
40228060Sbaptstatic int
41228060Sbaptgetstr (char **lineptr, size_t *n, FILE *stream, char terminator, size_t offset)
42228060Sbapt{
43228060Sbapt  size_t nchars_avail;          /* Allocated but unused chars in *LINEPTR.  */
44228060Sbapt  char *read_pos;               /* Where we're reading into *LINEPTR. */
45228060Sbapt
46228060Sbapt  if (!lineptr || !n || !stream)
47228060Sbapt    return -1;
48228060Sbapt
49228060Sbapt  if (!*lineptr)
50228060Sbapt    {
51228060Sbapt      *n = MIN_CHUNK;
52228060Sbapt      *lineptr = new char[*n];
53228060Sbapt    }
54228060Sbapt
55228060Sbapt  nchars_avail = *n - offset;
56228060Sbapt  read_pos = *lineptr + offset;
57228060Sbapt
58228060Sbapt  for (;;)
59228060Sbapt    {
60228060Sbapt      register int c = getc (stream);
61228060Sbapt
62228060Sbapt      /* We always want at least one char left in the buffer, since we
63228060Sbapt         always (unless we get an error while reading the first char)
64228060Sbapt         NUL-terminate the line buffer.  */
65228060Sbapt
66228060Sbapt      assert (*n - nchars_avail == (size_t) (read_pos - *lineptr));
67228060Sbapt      if (nchars_avail < 2)
68228060Sbapt        {
69228060Sbapt          if (*n > MIN_CHUNK)
70228060Sbapt            *n *= 2;
71228060Sbapt          else
72228060Sbapt            *n += MIN_CHUNK;
73228060Sbapt
74228060Sbapt          nchars_avail = *n + *lineptr - read_pos;
75228060Sbapt          char *new_line = new char[*n];
76228060Sbapt          if (*lineptr)
77228060Sbapt            {
78228060Sbapt              memcpy (new_line, *lineptr, read_pos - *lineptr);
79228060Sbapt              delete[] *lineptr;
80228060Sbapt            }
81228060Sbapt          *lineptr = new_line;
82228060Sbapt          read_pos = *n - nchars_avail + *lineptr;
83228060Sbapt          assert (*n - nchars_avail == (size_t) (read_pos - *lineptr));
84228060Sbapt        }
85228060Sbapt
86228060Sbapt      if (c == EOF || ferror (stream))
87228060Sbapt        {
88228060Sbapt          /* Return partial line, if any.  */
89228060Sbapt          if (read_pos == *lineptr)
90228060Sbapt            return -1;
91228060Sbapt          else
92228060Sbapt            break;
93228060Sbapt        }
94228060Sbapt
95228060Sbapt      *read_pos++ = c;
96228060Sbapt      nchars_avail--;
97228060Sbapt
98228060Sbapt      if (c == terminator)
99228060Sbapt        /* Return the line.  */
100228060Sbapt        break;
101228060Sbapt    }
102228060Sbapt
103228060Sbapt  /* Done - NUL terminate and return the number of chars read.  */
104228060Sbapt  *read_pos = '\0';
105228060Sbapt
106228060Sbapt  return read_pos - (*lineptr + offset);
107228060Sbapt}
108228060Sbapt
109228060Sbaptint
110228060Sbaptget_line (char **lineptr, size_t *n, FILE *stream)
111228060Sbapt{
112228060Sbapt  return getstr (lineptr, n, stream, '\n', 0);
113228060Sbapt}
114228060Sbapt
115228060Sbaptint
116228060Sbaptget_delim (char **lineptr, size_t *n, int delimiter, FILE *stream)
117228060Sbapt{
118228060Sbapt  return getstr (lineptr, n, stream, delimiter, 0);
119228060Sbapt}
120