[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[bug-gnulib] Re: getline
From: |
Simon Josefsson |
Subject: |
[bug-gnulib] Re: getline |
Date: |
Thu, 02 Dec 2004 13:26:13 +0100 |
User-agent: |
Gnus/5.110003 (No Gnus v0.3) Emacs/21.3.50 (gnu/linux) |
Paul Eggert <address@hidden> writes:
> Simon Josefsson <address@hidden> writes:
>
>> Will glibc accept GPL'd code?
>
> The code in question is copyrighted by the FSF, so the FSF can change
> it from GPL to LGPL. I'd prefer to do this via submitting it to
> glibc.
Fair enough. Comments on the glibc patch below? I didn't compile the
code, if someone have more patience with glibc builds to test it, that
would be useful.
Is GETNLINE_NO_LIMIT a good name?
I don't understand why glibc use _IO_ssize_t instead of ssize_t, nor
why variable names are prefixed with __ in headers, but I followed the
existing style.
A next step would be to fix the file so it can be shared from CVS in
gnulib.
Index: NEWS
===================================================================
RCS file: /cvs/glibc/libc/NEWS,v
retrieving revision 1.148
diff -u -p -r1.148 NEWS
--- NEWS 19 Oct 2004 10:42:59 -0000 1.148
+++ NEWS 2 Dec 2004 12:23:26 -0000
@@ -41,6 +41,8 @@ Version 2.3.4
were added. These are to be used in conjunction with a gcc patch by
Jakub Jelinek which adds calls to these functions if possible.
Patch by Jakub Jelinek and Ulrich Drepper.
+
+* getndelim2 interface in libio added.
Version 2.3.3
Index: manual/stdio.texi
===================================================================
RCS file: /cvs/glibc/libc/manual/stdio.texi,v
retrieving revision 1.133
diff -u -p -r1.133 stdio.texi
--- manual/stdio.texi 30 Jun 2002 03:35:21 -0000 1.133
+++ manual/stdio.texi 2 Dec 2004 12:23:27 -0000
@@ -1152,6 +1152,10 @@ Another GNU extension, @code{getdelim},
reads a delimited record, defined as everything through the next
occurrence of a specified delimiter character.
+A further generalization, also a GNU extension, is @code{getndelim2}.
+It reads a delimited record but supports two delimiters, and provide a
+way to restrict the allocated output size.
+
All these functions are declared in @file{stdio.h}.
@comment stdio.h
@@ -1214,6 +1218,30 @@ getline (char **lineptr, size_t *n, FILE
@end deftypefun
@comment stdio.h
address@hidden GNU
address@hidden ssize_t getndelim2 (char address@hidden, size_t address@hidden,
size_t @var{offset}, size_t @var{nmax}, int @var{delim1}, int @var{delim2},
FILE address@hidden)
+This function is a further generalization of @code{getdelim}. It will
+read until it sees either of two delimiters (or end of file). It can
+write the output characters into an offset within the allocated
+buffer. An upper limit on the allocated buffer size can be specified.
+
+The read bytes are stored at @var{lineptr} + @var{offset}. As before,
+the @var{lineptr} is reallocated as necessary, but if @var{nmax} is
+not @code{GETNLINE_NO_LIMIT} then do not allocate more than @var{nmax}
+bytes; if the line is longer than that, read and discard the extra
+bytes. Stop reading after the first occurrence of @var{delim1} or
address@hidden, whichever comes first; a delimiter equal to EOF stands
+for no delimiter. Read the input bytes from @var{stream}.
+
+When @code{getndelim2} is successful, it returns the number of
+characters read (including the delimiter, but not including the
+terminating null).
+
+If an error occurs or end of file is reached without any bytes read,
address@hidden returns @code{-1}.
address@hidden deftypefun
+
address@hidden stdio.h
@comment ISO
@deftypefun {char *} fgets (char address@hidden, int @var{count}, FILE
address@hidden)
The @code{fgets} function reads characters from the stream @var{stream}
Index: libio/Versions
===================================================================
RCS file: /cvs/glibc/libc/libio/Versions,v
retrieving revision 1.17
diff -u -p -r1.17 Versions
--- libio/Versions 22 Jul 2003 23:55:36 -0000 1.17
+++ libio/Versions 2 Dec 2004 12:23:27 -0000
@@ -145,6 +145,10 @@ libc {
# w*
wprintf; wscanf;
}
+ GLIBC_2.3.4 {
+ # g*
+ getndelim2;
+ }
GLIBC_PRIVATE {
# Used by NPTL and librt
__libc_fatal;
Index: libio/iogetndelim2.c
===================================================================
RCS file: libio/iogetndelim2.c
diff -N libio/iogetndelim2.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libio/iogetndelim2.c 2 Dec 2004 12:23:27 -0000
@@ -0,0 +1,198 @@
+/* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters,
+ with bounded memory allocation.
+
+ Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003, 2004 Free Software
+ Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA.
+
+ As a special exception, if you link the code in this file with
+ files compiled with a GNU compiler to produce an executable,
+ that does not cause the resulting executable to be covered by
+ the GNU Lesser General Public License. This exception does not
+ however invalidate any other reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+ This exception applies to code released by its copyright holders
+ in files containing the exception. */
+
+/* Originally written by Jan Brittenson, address@hidden */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+#include "libioP.h"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <limits.h>
+#if _LIBC || HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if _LIBC || HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX ((ptrdiff_t) (SIZE_MAX / 2))
+#endif
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+#ifndef SSIZE_MAX
+# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
+#endif
+
+/* The maximum value that getndelim2 can return without suffering from
+ overflow problems, either internally (because of pointer
+ subtraction overflow) or due to the API (because of ssize_t). */
+#define GETNDELIM2_MAXIMUM (PTRDIFF_MAX < SSIZE_MAX ? PTRDIFF_MAX : SSIZE_MAX)
+
+/* Try to add at least this many bytes when extending the buffer.
+ MIN_CHUNK must be no greater than GETNDELIM2_MAXIMUM. */
+#define MIN_CHUNK 128
+
+/* Read into a buffer *LINEPTR returned from malloc (or NULL),
+ pointing to *LINESIZE bytes of space. Store the input bytes
+ starting at *LINEPTR + OFFSET, and null-terminate them. Reallocate
+ the buffer as necessary, but if NMAX is not GETNLINE_NO_LIMIT then
+ do not allocate more than NMAX bytes; if the line is longer than
+ that, read and discard the extra bytes. Stop reading after the
+ first occurrence of DELIM1 or DELIM2, whichever comes first; a
+ delimiter equal to EOF stands for no delimiter. Read the input
+ bytes from STREAM.
+ Return the number of bytes read and stored at *LINEPTR + OFFSET (not
+ including the NUL terminator), or -1 on error or EOF. */
+_IO_ssize_t
+_IO_getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
+ int delim1, int delim2, FILE *fp)
+{
+ size_t nbytes_avail; /* Allocated but unused bytes in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ ssize_t bytes_stored = -1;
+ char *ptr;
+ size_t size;
+
+ if (lineptr == NULL || linesize == NULL)
+ {
+ MAYBE_SET_EINVAL;
+ return -1;
+ }
+
+ CHECK_FILE (fp, -1);
+ _IO_acquire_lock (fp);
+ if (_IO_ferror_unlocked (fp))
+ goto unlock_return;
+
+ ptr = *lineptr;
+ size = *linesize;
+
+ if (!ptr)
+ {
+ size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
+ ptr = malloc (size);
+ if (!ptr)
+ goto unlock_return;
+ }
+
+ if (size < offset)
+ goto done;
+
+ nbytes_avail = size - offset;
+ read_pos = ptr + offset;
+
+ if (nbytes_avail == 0 && nmax <= size)
+ goto done;
+
+ for (;;)
+ {
+ /* Here always ptr + size == read_pos + nbytes_avail. */
+
+ int c;
+
+ /* We always want at least one byte left in the buffer, since we
+ always (unless we get an error while reading the first byte)
+ NUL-terminate the line buffer. */
+
+ if (nbytes_avail < 2 && size < nmax)
+ {
+ size_t newsize = size < MIN_CHUNK ? size + MIN_CHUNK : 2 * size;
+ char *newptr;
+
+ if (! (size < newsize && newsize <= nmax))
+ newsize = nmax;
+
+ if (GETNDELIM2_MAXIMUM < newsize - offset)
+ {
+ size_t newsizemax = offset + GETNDELIM2_MAXIMUM + 1;
+ if (size == newsizemax)
+ goto done;
+ newsize = newsizemax;
+ }
+
+ nbytes_avail = newsize - (read_pos - ptr);
+ newptr = realloc (ptr, newsize);
+ if (!newptr)
+ goto done;
+ ptr = newptr;
+ size = newsize;
+ read_pos = size - nbytes_avail + ptr;
+ }
+
+ c = _IO_getc_unlocked (fp);
+ if (c == EOF)
+ {
+ /* Return partial line, if any. */
+ if (read_pos == ptr)
+ goto done;
+ else
+ break;
+ }
+
+ if (nbytes_avail >= 2)
+ {
+ *read_pos++ = c;
+ nbytes_avail--;
+ }
+
+ if (c == delim1 || c == delim2)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of bytes read.
+ At this point we know that nbytes_avail >= 1. */
+ *read_pos = '\0';
+
+ bytes_stored = read_pos - (ptr + offset);
+
+ done:
+ *lineptr = ptr;
+ *linesize = size;
+ unlock_return:
+ _IO_release_lock (fp);
+ return bytes_stored;
+}
+
+#ifdef weak_alias
+weak_alias (_IO_getndelim2, getndelim2)
+#endif
Index: libio/stdio.h
===================================================================
RCS file: /cvs/glibc/libc/libio/stdio.h,v
retrieving revision 1.79
diff -u -p -r1.79 stdio.h
--- libio/stdio.h 18 Oct 2004 04:17:15 -0000 1.79
+++ libio/stdio.h 2 Dec 2004 12:23:27 -0000
@@ -546,6 +546,25 @@ extern char *fgets_unlocked (char *__res
#ifdef __USE_GNU
+#define GETNLINE_NO_LIMIT ((size_t) -1)
+
+/* Read into a buffer *LINEPTR returned from malloc (or NULL),
+ pointing to *LINESIZE bytes of space. Store the input bytes
+ starting at *LINEPTR + OFFSET, and null-terminate them. Reallocate
+ the buffer as necessary, but if NMAX is not GETNLINE_NO_LIMIT then
+ do not allocate more than NMAX bytes; if the line is longer than
+ that, read and discard the extra bytes. Stop reading after the
+ first occurrence of DELIM1 or DELIM2, whichever comes first; a
+ delimiter equal to EOF stands for no delimiter. Read the input
+ bytes from STREAM.
+ Return the number of bytes read and stored at *LINEPTR + OFFSET (not
+ including the NUL terminator), or -1 on error or EOF. */
+extern _IO_ssize_t getndelim2 (char **__restrict __lineptr,
+ size_t *__restrict __linesize,
+ size_t __offset, size_t __nmax,
+ int __delim1, int __delim2,
+ FILE *__restrict __stream);
+
/* Read up to (and including) a DELIMITER from STREAM into *LINEPTR
(and null-terminate it). *LINEPTR is a pointer returned from malloc (or
NULL), pointing to *N characters of space. It is realloc'd as
- [bug-gnulib] getline, Simon Josefsson, 2004/12/01
- Re: [bug-gnulib] getline, Paul Eggert, 2004/12/01
- [bug-gnulib] Re: getline, Simon Josefsson, 2004/12/01
- Re: [bug-gnulib] Re: getline, Paul Eggert, 2004/12/02
- [bug-gnulib] Re: getline,
Simon Josefsson <=
- Re: [bug-gnulib] Re: getline, Paul Eggert, 2004/12/02
- [bug-gnulib] Re: getline, Simon Josefsson, 2004/12/25
- [bug-gnulib] Re: getline, Paul Eggert, 2004/12/25
- [bug-gnulib] Re: getline, Simon Josefsson, 2004/12/26
- [bug-gnulib] Re: getline, Paul Eggert, 2004/12/27
- [bug-gnulib] Re: getline, Simon Josefsson, 2004/12/27