chiark / gitweb /
gnupg2 (2.1.17-3) unstable; urgency=medium
[gnupg2.git] / common / xreadline.c
1 /* xreadline.c - fgets replacement function
2  * Copyright (C) 1999, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35 #include "util.h"
36
37
38 /* Same as fgets() but if the provided buffer is too short a larger
39    one will be allocated.  This is similar to getline. A line is
40    considered a byte stream ending in a LF.
41
42    If MAX_LENGTH is not NULL, it shall point to a value with the
43    maximum allowed allocation.
44
45    Returns the length of the line. EOF is indicated by a line of
46    length zero. A truncated line is indicated by setting the value at
47    MAX_LENGTH to 0.  If the returned value is less then 0 not enough
48    memory was enable and ERRNO is set accordingly.
49
50    If a line has been truncated, the file pointer is moved forward to
51    the end of the line so that the next read starts with the next
52    line.  Note that MAX_LENGTH must be re-initialzied in this case.
53
54    Note: The returned buffer is allocated with enough extra space to
55    append a CR,LF,Nul
56  */
57 ssize_t
58 read_line (FILE *fp,
59            char **addr_of_buffer, size_t *length_of_buffer,
60            size_t *max_length)
61 {
62   int c;
63   char  *buffer = *addr_of_buffer;
64   size_t length = *length_of_buffer;
65   size_t nbytes = 0;
66   size_t maxlen = max_length? *max_length : 0;
67   char *p;
68
69   if (!buffer)
70     { /* No buffer given - allocate a new one. */
71       length = 256;
72       buffer = xtrymalloc (length);
73       *addr_of_buffer = buffer;
74       if (!buffer)
75         {
76           *length_of_buffer = 0;
77           if (max_length)
78             *max_length = 0;
79           return -1;
80         }
81       *length_of_buffer = length;
82     }
83
84   length -= 3; /* Reserve 3 bytes for CR,LF,EOL. */
85   p = buffer;
86   while  ((c = getc (fp)) != EOF)
87     {
88       if (nbytes == length)
89         { /* Enlarge the buffer. */
90           if (maxlen && length > maxlen) /* But not beyond our limit. */
91             {
92               /* Skip the rest of the line. */
93               while (c != '\n' && (c=getc (fp)) != EOF)
94                 ;
95               *p++ = '\n'; /* Always append a LF (we reserved some space). */
96               nbytes++;
97               if (max_length)
98                 *max_length = 0; /* Indicate truncation. */
99               break; /* the while loop. */
100             }
101           length += 3; /* Adjust for the reserved bytes. */
102           length += length < 1024? 256 : 1024;
103           *addr_of_buffer = xtryrealloc (buffer, length);
104           if (!*addr_of_buffer)
105             {
106               int save_errno = errno;
107               xfree (buffer);
108               *length_of_buffer = 0;
109               if (max_length)
110                 *max_length = 0;
111               gpg_err_set_errno (save_errno);
112               return -1;
113             }
114           buffer = *addr_of_buffer;
115           *length_of_buffer = length;
116           length -= 3;
117           p = buffer + nbytes;
118         }
119       *p++ = c;
120       nbytes++;
121       if (c == '\n')
122         break;
123     }
124   *p = 0; /* Make sure the line is a string. */
125
126   return nbytes;
127 }