Commit 23eb20a6 23eb20a68d6054abcbacc1f4f4a5172061fd9627 by Alain Magloire

New LGPL implementation of getline() and getdelim()

1 parent 8c7bd549
1 /* getline.c -- Replacement for GNU C library function getline 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
2 3
3 Copyright (C) 1993, 1996, 2001 Free Software Foundation, Inc. 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
4 8
5 This program is free software; you can redistribute it and/or 9 This program is distributed in the hope that it will be useful,
6 modify it under the terms of the GNU General Public License as 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
7 published by the Free Software Foundation; either version 2 of the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8 License, or (at your option) any later version. 12 GNU Library General Public License for more details.
9 13
10 This program is distributed in the hope that it will be useful, but 14 You should have received a copy of the GNU Library General Public License
11 WITHOUT ANY WARRANTY; without even the implied warranty of 15 along with this program; if not, write to the Free Software
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
13 General Public License for more details.
14 17
15 You should have received a copy of the GNU General Public License 18 /* First implementation by Alain Magloire */
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 19
19 /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ 20 #ifdef HAVE_CONFIG_H
20
21 #if HAVE_CONFIG_H
22 # include <config.h> 21 # include <config.h>
23 #endif 22 #endif
24 23
25 /* The `getdelim' function is only declared if the following symbol
26 is defined. */
27 #define _GNU_SOURCE 1
28 #include <stdio.h> 24 #include <stdio.h>
29 #include <sys/types.h> 25 #include <stdlib.h>
30 26 #include <string.h>
31 #if defined __GNU_LIBRARY__ && HAVE_GETDELIM
32 27
33 ssize_t 28 ssize_t
34 getline (lineptr, n, stream) 29 getline (char **lineptr, size_t *n, FILE *stream)
35 char **lineptr;
36 size_t *n;
37 FILE *stream;
38 { 30 {
39 return getdelim (lineptr, n, '\n', stream); 31 return getdelim (lineptr, n, '\n', stream);
40 } 32 }
41 33
34 #ifndef HAVE_GETDELIM
42 35
43 #else /* ! have getdelim */ 36 /* Default value for line length. */
44 37 static const int line_size = 128;
45 # define NDEBUG
46 # include <assert.h>
47
48 # if STDC_HEADERS
49 # include <stdlib.h>
50 # else
51 char *malloc (), *realloc ();
52 # endif
53
54 /* Always add at least this many bytes when extending the buffer. */
55 # define MIN_CHUNK 64
56
57 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
58 + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
59 malloc (or NULL), pointing to *N characters of space. It is realloc'd
60 as necessary. Return the number of characters read (not including the
61 null terminator), or -1 on error or EOF. */
62 38
63 ssize_t 39 ssize_t
64 getstr (lineptr, n, stream, terminator, offset) 40 getdelim (char **lineptr, size_t *n, int delim, FILE *stream)
65 char **lineptr;
66 size_t *n;
67 FILE *stream;
68 char terminator;
69 size_t offset;
70 { 41 {
71 int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ 42 int indx = 0;
72 char *read_pos; /* Where we're reading into *LINEPTR. */ 43 int c;
73 int ret;
74 44
75 if (!lineptr || !n || !stream) 45 /* Sanity checks. */
46 if (lineptr == NULL || n == NULL || stream == NULL)
76 return -1; 47 return -1;
77 48
78 if (!*lineptr) 49 /* Allocate the line the first time. */
50 if (*lineptr == NULL)
79 { 51 {
80 *n = MIN_CHUNK; 52 *lineptr = malloc (line_size);
81 *lineptr = malloc (*n); 53 if (*lineptr == NULL)
82 if (!*lineptr)
83 return -1; 54 return -1;
55 *n = line_size;
84 } 56 }
85 57
86 nchars_avail = *n - offset; 58 while ((c = getc (stream)) != EOF)
87 read_pos = *lineptr + offset;
88
89 for (;;)
90 { 59 {
91 register int c = getc (stream); 60 /* Check if more memory is needed. */
92 61 if (indx >= *n)
93 /* We always want at least one char left in the buffer, since we
94 always (unless we get an error while reading the first char)
95 NUL-terminate the line buffer. */
96
97 assert(*n - nchars_avail == read_pos - *lineptr);
98 if (nchars_avail < 2)
99 { 62 {
100 if (*n > MIN_CHUNK) 63 *lineptr = realloc (*lineptr, *n + line_size);
101 *n *= 2; 64 if (*lineptr == NULL)
102 else
103 *n += MIN_CHUNK;
104
105 nchars_avail = *n + *lineptr - read_pos;
106 *lineptr = realloc (*lineptr, *n);
107 if (!*lineptr)
108 return -1; 65 return -1;
109 read_pos = *n - nchars_avail + *lineptr; 66 *n += line_size;
110 assert(*n - nchars_avail == read_pos - *lineptr);
111 } 67 }
112 68
113 if (c == EOF || ferror (stream)) 69 /* Push the result in the line. */
114 { 70 (*lineptr)[indx++] = c;
115 /* Return partial line, if any. */
116 if (read_pos == *lineptr)
117 return -1;
118 else
119 break;
120 }
121
122 *read_pos++ = c;
123 nchars_avail--;
124 71
125 if (c == terminator) 72 /* Bail out. */
126 /* Return the line. */ 73 if (c == delim)
127 break; 74 break;
128 } 75 }
129 76
130 /* Done - NUL terminate and return the number of chars read. */ 77 /* Make room for the null character. */
131 *read_pos = '\0'; 78 if (indx >= *n)
79 {
80 *lineptr = realloc (*lineptr, *n + line_size);
81 if (*lineptr == NULL)
82 return -1;
83 *n += line_size;
84 }
132 85
133 ret = read_pos - (*lineptr + offset); 86 /* Null terminate the buffer. */
134 return ret; 87 (*lineptr)[indx++] = 0;
135 }
136 88
137 ssize_t 89 /* The last line may not have the delimiter, we have to
138 getline (lineptr, n, stream) 90 * return what we got and the error will be seen on the
139 char **lineptr; 91 * next iteration. */
140 size_t *n; 92 return (c == EOF && (indx - 1) == 0) ? -1 : indx - 1;
141 FILE *stream;
142 {
143 return getstr (lineptr, n, stream, '\n', 0);
144 } 93 }
145 94
146 ssize_t 95 #endif /* HAVE_GETDELIM */
147 getdelim (lineptr, n, delimiter, stream) 96
148 char **lineptr; 97
149 size_t *n; 98 #ifdef STANDALONE
150 int delimiter; 99 int main(void)
151 FILE *stream;
152 { 100 {
153 return getstr (lineptr, n, stream, delimiter, 0); 101 FILE * fp;
102 char * line = NULL;
103 size_t len = 0;
104 ssize_t read;
105 fp = fopen("/etc/passwd", "r");
106 if (fp == NULL)
107 exit(EXIT_FAILURE);
108 while ((read = getline(&line, &len, fp)) != -1) {
109 printf("Retrieved line of length %zu :\n", read);
110 printf("%s", line);
111 }
112 if (line)
113 free(line);
114 return EXIT_SUCCESS;
154 } 115 }
155 #endif 116 #endif
......
1 /* Copyright (C) 1995 Free Software Foundation, Inc. 1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
2 3
3 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Library Public License as published by
5 the Free Software Foundation; either version 2, or (at your option) 6 the Free Software Foundation; either version 2, or (at your option)
6 any later version. 7 any later version.
7 8
8 This program is distributed in the hope that it will be useful, 9 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details. 12 GNU Library General Public License for more details.
12 13
13 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU Library General Public License
14 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
16 17
17 #ifndef GETLINE_H_ 18 #ifndef _GETLINE_H_
18 # define GETLINE_H_ 1 19 # define _GETLINE_H_ 1
19 20
20 # include <stdio.h> 21 # include <stdio.h>
21 22
...@@ -27,10 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ...@@ -27,10 +28,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 # endif 28 # endif
28 # endif 29 # endif
29 30
30 int 31 extern int getline PARAMS ((char **_lineptr, size_t *_n, FILE *_stream));
31 getline PARAMS ((char **_lineptr, size_t *_n, FILE *_stream));
32 32
33 int 33 extern int getdelim PARAMS ((char **_lineptr, size_t *_n, int _delimiter, FILE *_stream));
34 getdelim PARAMS ((char **_lineptr, size_t *_n, int _delimiter, FILE *_stream));
35 34
36 #endif /* not GETLINE_H_ */ 35 #endif /* ! _GETLINE_H_ */
......