getline cleanup. This changes the getndelim2 API: both order of arguments,
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 16 May 2004 19:03:42 +0000 (19:03 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 16 May 2004 19:03:42 +0000 (19:03 +0000)
and meaning of delim2 (now uses EOF, not 0, to indicate no delimiter).

lib/ChangeLog
lib/getline.c
lib/getndelim2.c
lib/getndelim2.h
lib/getnline.c
lib/getnline.h

index 7ce0bf5dad497f6fd4fef3bd7c523f586bdba1a9..37f2703b673dcf497efb7ea61151f4dbeb780595 100644 (file)
@@ -1,3 +1,33 @@
+2004-05-16  Derek Price  <derek@ximbiot.com>
+           Paul Eggert  <eggert@cs.ucla.edu>
+
+       getline cleanup.  This changes the getndelim2 API: both order of
+       arguments, and meaning of delim2 (now uses EOF, not 0, to indicate
+       no delimiter).
+       
+       * lib/getline.c: Don't include stddef.h or stdio.h, since our
+       interface does that.
+       (getline): Always use getdelim, so that we don't have two
+       copies of this code.
+       * lib/getndelim2.c: Include <limits.h>, <inttypes.h>, <stdint.h>
+       if available.
+       (PTRDIFF_MAX, SIZE_MAX, SSIZE_MAX): Define if not defined.
+       (GETNDELIM2_MAXIMUM): New macro.
+       (getndelim2): Reorder arguments.  delim==EOF now means no delimiter,
+       instead of the old practice of delim2==0.  All callers changed.
+       Return -1 on overflow, instead of returning junk.
+       Do not set *linesize unless allocation succeeds.
+       * lib/getndelim2.h: Do not include stddef.h; no longer needed, now
+       that we include sys/types.h.
+       * lib/getnline.h: Likewise.
+       * lib/getndelim2.h (GETNLINE_NO_LIMIT): New macro.
+       (getndelim2): Reorder arguments.
+       * lib/getnline.c (getnline, getndelim):
+       Don't discard the NMAX argument.
+       (getnline): Invoke getndelim, to avoid code duplication.
+       * lib/getnline.h (GETNLINE_NO_LIMIT): New macro, used instead
+       of (size_t) -1 by callers of the getnline family.
+
 2004-05-13  Paul Eggert  <eggert@cs.ucla.edu>
 
        * nanosleep.c (suspended): Change its type from int to
index 896b6bbd84cb05326175d98a6f5af8a53c112708..746d708878c84e6f360c05d4ebd42424ac1a8b37 100644 (file)
@@ -1,7 +1,7 @@
 /* getline.c -- Replacement for GNU C library function getline
 
-   Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003 Free Software
-   Foundation, Inc.
+   Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003, 2004 Free
+   Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 # include <config.h>
 #endif
 
-/* Specification.  */
 #include "getline.h"
 
-#include <stddef.h>
-#include <stdio.h>
-
-/* Get ssize_t.  */
-#include <sys/types.h>
-
-#if defined __GNU_LIBRARY__ && HAVE_GETDELIM
-
-ssize_t
-getline (char **lineptr, size_t *linesize, FILE *stream)
-{
-  return getdelim (lineptr, linesize, '\n', stream);
-}
-
-#else /* ! have getdelim */
+#if ! (defined __GNU_LIBRARY__ && HAVE_GETDELIM)
 
 # include "getndelim2.h"
 
 ssize_t
-getline (char **lineptr, size_t *linesize, FILE *stream)
+getdelim (char **lineptr, size_t *linesize, int delimiter, FILE *stream)
 {
-  return getndelim2 (lineptr, linesize, (size_t)(-1), stream, '\n', 0, 0);
+  return getndelim2 (lineptr, linesize, 0, GETNLINE_NO_LIMIT, delimiter, EOF,
+                     stream);
 }
+#endif
 
 ssize_t
-getdelim (char **lineptr, size_t *linesize, int delimiter, FILE *stream)
+getline (char **lineptr, size_t *linesize, FILE *stream)
 {
-  return getndelim2 (lineptr, linesize, (size_t)(-1), stream, delimiter, 0, 0);
+  return getdelim (lineptr, linesize, '\n', stream);
 }
-#endif
index 2b6dc11571d4a5c6954c4a621f5663a20a7eb367..c3c0566be78ff99b832ef855fa22d8632080be22 100644 (file)
 # include <config.h>
 #endif
 
-/* Specification.  */
 #include "getndelim2.h"
 
 #include <stdlib.h>
 
 #include "unlocked-io.h"
 
-/* Always add at least this many bytes when extending the buffer.  */
+#include <limits.h>
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#if 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 64
 
 ssize_t
-getndelim2 (char **lineptr, size_t *linesize, size_t nmax,
-           FILE *stream, int delim1, int delim2, size_t offset)
+getndelim2 (char **lineptr, size_t *linesize, size_t offset, size_t nmax,
+            int delim1, int delim2, FILE *stream)
 {
-  size_t nbytes_avail;         /* Allocated but unused chars in *LINEPTR.  */
+  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 = *lineptr;
+  size_t size = *linesize;
 
-  if (!lineptr || !linesize || !nmax || !stream)
-    return -1;
-
-  if (!*lineptr)
+  if (!ptr)
     {
-      size_t newlinesize = MIN_CHUNK;
-
-      if (newlinesize > nmax)
-       newlinesize = nmax;
-
-      *linesize = newlinesize;
-      *lineptr = malloc (*linesize);
-      if (!*lineptr)
+      size = nmax < MIN_CHUNK ? nmax : MIN_CHUNK;
+      ptr = malloc (size);
+      if (!ptr)
        return -1;
     }
 
-  if (*linesize < offset)
-    return -1;
+  if (size < offset)
+    goto done;
 
-  nbytes_avail = *linesize - offset;
-  read_pos = *lineptr + offset;
+  nbytes_avail = size - offset;
+  read_pos = ptr + offset;
 
-  if (nbytes_avail == 0 && *linesize >= nmax)
-    return -1;
+  if (nbytes_avail == 0 && nmax <= size)
+    goto done;
 
   for (;;)
     {
-      /* Here always *lineptr + *linesize == read_pos + nbytes_avail.  */
+      /* Here always ptr + size == read_pos + nbytes_avail.  */
 
-      register int c;
+      int c;
 
-      /* We always want at least one char left in the buffer, since we
-        always (unless we get an error while reading the first char)
+      /* 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 && *linesize < nmax)
+      if (nbytes_avail < 2 && size < nmax)
        {
-         size_t newlinesize =
-           (*linesize > MIN_CHUNK ? 2 * *linesize : *linesize + MIN_CHUNK);
-         char *p;
-
-         if (! (*linesize < newlinesize && newlinesize <= nmax))
-           newlinesize = nmax;
-
-         *linesize = newlinesize;
-         nbytes_avail = *linesize + *lineptr - read_pos;
-         p = realloc (*lineptr, *linesize);
-         if (!p)
-           return -1;
-         *lineptr = p;
-         read_pos = *linesize - nbytes_avail + *lineptr;
+         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 = getc (stream);
       if (c == EOF)
        {
          /* Return partial line, if any.  */
-         if (read_pos == *lineptr)
-           return -1;
+         if (read_pos == ptr)
+           goto done;
          else
            break;
        }
@@ -110,14 +134,19 @@ getndelim2 (char **lineptr, size_t *linesize, size_t nmax,
          nbytes_avail--;
        }
 
-      if (c == delim1 || (delim2 && c == delim2))
+      if (c == delim1 || c == delim2)
        /* Return the line.  */
        break;
     }
 
-  /* Done - NUL terminate and return the number of chars read.
+  /* Done - NUL terminate and return the number of bytes read.
      At this point we know that nbytes_avail >= 1.  */
   *read_pos = '\0';
 
-  return read_pos - (*lineptr + offset);
+  bytes_stored = read_pos - (ptr + offset);
+
+ done:
+  *lineptr = ptr;
+  *linesize = size;
+  return bytes_stored;
 }
index d9bafe3b429e0954b614a601370109385ee61b81..39f80cb5572339c83a8826da60048e16e8b03417 100644 (file)
@@ -1,7 +1,7 @@
 /* getndelim2 - Read a line from a stream, stopping at one of 2 delimiters,
    with bounded memory allocation.
 
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #ifndef GETNDELIM2_H
 #define GETNDELIM2_H 1
 
-#include <stddef.h>
 #include <stdio.h>
-
-/* Get ssize_t.  */
 #include <sys/types.h>
 
-/* Read up to (and including) a delimiter DELIM1 from STREAM into *LINEPTR
-   + OFFSET (and NUL-terminate it).  If DELIM2 is non-zero, then read up
-   and including the first occurrence of DELIM1 or DELIM2.  *LINEPTR is
-   a pointer returned from malloc (or NULL), pointing to *LINESIZE bytes of
-   space.  It is realloc'd as necessary.  Reallocation is limited to
-   NMAX bytes; if the line is longer than that, the extra bytes are read but
-   thrown away.
+#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
+   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 ssize_t getndelim2 (char **lineptr, size_t *linesize, size_t nmax,
-                          FILE *stream, int delim1, int delim2,
-                          size_t offset);
+extern ssize_t getndelim2 (char **lineptr, size_t *linesize, size_t offset,
+                           size_t nmax, int delim1, int delim2,
+                           FILE *stream);
 
 #endif /* GETNDELIM2_H */
index 7b858e37fa59a37a468ea1d8b88e4467bfd01f5f..9b2ce3ba0ac7005077e840db7ee1c60921ddd378 100644 (file)
@@ -1,6 +1,6 @@
 /* getnline - Read a line from a stream, with bounded memory allocation.
 
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "getndelim2.h"
 
 ssize_t
-getnline (char **lineptr, size_t *linesize, size_t nmax, FILE *stream)
+getndelim (char **lineptr, size_t *linesize, size_t nmax,
+          int delimiter, FILE *stream)
 {
-  return getndelim2 (lineptr, linesize, (size_t)(-1), stream, '\n', 0, 0);
+  return getndelim2 (lineptr, linesize, 0, nmax, delimiter, EOF, stream);
 }
 
 ssize_t
-getndelim (char **lineptr, size_t *linesize, size_t nmax,
-          int delimiter, FILE *stream)
+getnline (char **lineptr, size_t *linesize, size_t nmax, FILE *stream)
 {
-  return getndelim2 (lineptr, linesize, (size_t)(-1), stream, delimiter, 0, 0);
+  return getndelim (lineptr, linesize, nmax, '\n', stream);
 }
index e455300ab9ae64957d7afd70736c1041bd77c2bb..fae1367caf172684a86dcfebbc651204882a781a 100644 (file)
@@ -1,6 +1,6 @@
 /* getnline - Read a line from a stream, with bounded memory allocation.
 
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #ifndef GETNLINE_H
 #define GETNLINE_H 1
 
-#include <stddef.h>
 #include <stdio.h>
-
-/* Get ssize_t.  */
 #include <sys/types.h>
 
+#define GETNLINE_NO_LIMIT ((size_t) -1)
+
 /* Read a line, up to the next newline, from STREAM, and store it in *LINEPTR.
    *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE
    bytes of space.  It is realloc'd as necessary.  Reallocation is limited to