bug-gnulib
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]