]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/cvs/lib/getline.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.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
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 }