01-getnline.diff (was Re: getline & getline_safe)

Derek Robert Price <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs,gmane.comp.version-control.cvs.bugs
Organization Ximbiot <http://ximbiot.com>
Message-ID <[email protected]>
Paul Eggert wrote:

>Derek Robert Price <[email protected]> writes:
>  
>
>>Incidentally, this implies having a getnline.c file which is always
>>compiled, and possibly which getline.c is dependent on.  Is this
>>reasonable?
>>    
>>
>Sounds reasonable to me.
>  
>
>>The long run alternative is to get getndelim() & getnline() into
>>libc.  I haven't really dealt with libc before.  Is _this_
>>reasonable?  Is this likely?
>>    
>>
>Maybe, maybe not.  Let's try gnulib first.  If only CVS uses it, then
>perhaps it's not worth worrying about for libc.
>  
>

Okay, here's my first pass.  It configures, builds, and passes `make 
check' with CVS, so I updated modules/getline, created modules/getnline, 
and am resubmitting to bug-gnulib.  Please let me know what you think.

I call it a first pass only because I wasn't sure how to document this 
complex dependency.  I think what I did was acceptable, but notice that 
I duplicated the getnline.* stuff between the two module descriptions.  
The basic difference is that if you want getline compiled conditionally 
but getnline compiled unconditionally then you add a call to 
gl_PREREQ_GETNLINE to configure.ac.  This is what I did with CVS.  If 
you just include the info as per the modules/getline file, getnline.c 
will only be compiled when it is needed for getline.c.

I still need to write the ChangeLog for CVS but I should commit these 
changes there soon.

Incidentally, my glibc defines both getdelim & getline to return 
ssize_t.  Is it intentional that the GNULIB versions return int instead?

	* lib/getnline.c: New file.
	* lib/getnline.h: Ditto.
	* m4/getnline.m4: Ditto.
	* modules/getnline: Ditto.

	* lib/getline.c: Move some include cruft with getdelim2 below.
	(getdelim2): Move to the new getnline.c above.
	(getdelim, getline): Wrap getndelim & getnline, respectitvely.
	* lib/getline.h: Use HAVE_WORKING_GETLINE & HAVE_GETDELIM rather than
	__GLIBC__ < 2, as per the autoconf paradigm.
	* m4/getline.m4 (AM_FUNC_GETLINE): Define HAVE_WORKING_GETLINE when
	appropriate.
	(gl_PREREQ_GETLINE): Call gl_PREREQ_GETNLINE when getdelim is not
	found.
	* modules/getline: Add new files to module setup instructions.


Index: lib/getline.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getline.c,v
retrieving revision 1.12
diff -u -r1.12 getline.c
--- lib/getline.c	4 Jun 2003 19:22:29 -0000	1.12
+++ lib/getline.c	16 Jul 2003 19:50:47 -0000
@@ -17,7 +17,9 @@
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/* Written by Jan Brittenson, [email protected].  */
+/* Adapted by Derek Price <[email protected]>
+ * from getline.c written by Jan Brittenson <[email protected]>.
+ */
 
 #if HAVE_CONFIG_H
 # include <config.h>
@@ -44,105 +46,18 @@
 
 #else /* ! have getdelim */
 
-# if STDC_HEADERS
-#  include <stdlib.h>
-# else
-char *malloc (), *realloc ();
-# endif
-
-#include "unlocked-io.h"
-
-/* Always add at least this many bytes when extending the buffer.  */
-#define MIN_CHUNK 64
-
-/* 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 *N characters of
-   space.  It is realloc'd as necessary.  Return the number of characters
-   read (not including the NUL terminator), or -1 on error or EOF.  */
-
-static int
-getdelim2 (char **lineptr, size_t *n, FILE *stream, int delim1, int delim2,
-	   size_t offset)
-{
-  size_t nchars_avail;		/* Allocated but unused chars in *LINEPTR.  */
-  char *read_pos;		/* Where we're reading into *LINEPTR. */
-  int ret;
-
-  if (!lineptr || !n || !stream)
-    return -1;
-
-  if (!*lineptr)
-    {
-      *n = MIN_CHUNK;
-      *lineptr = malloc (*n);
-      if (!*lineptr)
-	return -1;
-    }
-
-  if (*n < offset)
-    return -1;
-
-  nchars_avail = *n - offset;
-  read_pos = *lineptr + offset;
-
-  for (;;)
-    {
-      register int c = getc (stream);
-
-      /* We always want at least one char left in the buffer, since we
-	 always (unless we get an error while reading the first char)
-	 NUL-terminate the line buffer.  */
-
-      if (nchars_avail < 2)
-	{
-	  if (*n > MIN_CHUNK)
-	    *n *= 2;
-	  else
-	    *n += MIN_CHUNK;
-
-	  nchars_avail = *n + *lineptr - read_pos;
-	  *lineptr = realloc (*lineptr, *n);
-	  if (!*lineptr)
-	    return -1;
-	  read_pos = *n - nchars_avail + *lineptr;
-	}
-
-      if (c == EOF || ferror (stream))
-	{
-	  /* Return partial line, if any.  */
-	  if (read_pos == *lineptr)
-	    return -1;
-	  else
-	    break;
-	}
-
-      *read_pos++ = c;
-      nchars_avail--;
-
-      if (c == delim1 || (delim2 && c == delim2))
-	/* Return the line.  */
-	break;
-    }
-
-  /* Done - NUL terminate and return the number of chars read.  */
-  *read_pos = '\0';
-
-  ret = read_pos - (*lineptr + offset);
-  return ret;
-}
-
+# include "getnline.h"
+# include "unlocked-io.h"
 
 int
 getline (char **lineptr, size_t *n, FILE *stream)
 {
-  return getdelim2 (lineptr, n, stream, '\n', 0, 0);
+  return getnline (lineptr, n, stream, GETNDELIM_NO_LIMIT);
 }
 
 int
 getdelim (char **lineptr, size_t *n, int delimiter, FILE *stream)
 {
-  return getdelim2 (lineptr, n, stream, delimiter, 0, 0);
+  return getndelim (lineptr, n, delimiter, stream, GETNDELIM_NO_LIMIT);
 }
-#endif
+#endif /* have getdelim */
Index: lib/getline.h
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/getline.h,v
retrieving revision 1.12
diff -u -r1.12 getline.h
--- lib/getline.h	18 Jun 2003 05:52:19 -0000	1.12
+++ lib/getline.h	16 Jul 2003 19:50:47 -0000
@@ -24,12 +24,16 @@
 # include <stdio.h>
 
 /* glibc2 has these functions declared in <stdio.h>.  Avoid redeclarations.  */
-# if __GLIBC__ < 2
+# if !HAVE_WORKING_GETLINE
 
 int getline (char **_lineptr, size_t *_n, FILE *_stream);
 
+# endif /* ! have getline */
+
+# if !HAVE_GETDELIM
+
 int getdelim (char **_lineptr, size_t *_n, int _delimiter, FILE *_stream);
 
-# endif
+# endif /* ! have getdelim */
 
 #endif /* not GETLINE_H_ */
Index: lib/getnline.c
===================================================================
RCS file: lib/getnline.c
diff -N lib/getnline.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/getnline.c	16 Jul 2003 19:50:47 -0000
@@ -0,0 +1,143 @@
+/* getnline.c -- Implementation of getnline function, a modification of
+   the GNU C library function getline to allow the caller to set a
+   maximum number of characters to be retrieved.
+
+   Copyright (C) 1993, 1996, 1997, 1998, 2000, 2003 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
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Adapted by Derek Price <[email protected]>
+ * from getline.c written by Jan Brittenson <[email protected]>.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "getnline.h"
+
+#include <stddef.h>
+#include <stdio.h>
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+char *malloc (), *realloc ();
+#endif
+
+#include "unlocked-io.h"
+
+/* Always add at least this many bytes when extending the buffer.  */
+#define MIN_CHUNK 64
+
+/* 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 *N characters of
+   space.  It is realloc'd as necessary.  Return the number of characters
+   read (not including the NUL terminator), or -1 on error or EOF.  */
+
+static int
+getdelim2( char **lineptr, size_t *n, size_t offset, int limit,
+           int delim1, int delim2, FILE *stream )
+{
+  size_t nchars_avail;		/* Allocated but unused chars in *LINEPTR.  */
+  char *read_pos;		/* Where we're reading into *LINEPTR. */
+  int ret;
+
+  if (!lineptr || !n || !stream)
+    return -1;
+
+  if (!*lineptr)
+    {
+      *n = MIN_CHUNK;
+      *lineptr = malloc (*n);
+      if (!*lineptr)
+	return -1;
+    }
+
+  if (*n < offset)
+    return -1;
+
+  nchars_avail = *n - offset;
+  read_pos = *lineptr + offset;
+
+  for (;;)
+    {
+      register int c;
+
+      if (limit == 0)
+	break;
+
+      c = getc (stream);
+
+      if (limit != GETNLINE_NO_LIMIT)
+	limit--;
+
+      /* We always want at least one char left in the buffer, since we
+	 always (unless we get an error while reading the first char)
+	 NUL-terminate the line buffer.  */
+
+      if (nchars_avail < 2)
+	{
+	  if (*n > MIN_CHUNK)
+	    *n *= 2;
+	  else
+	    *n += MIN_CHUNK;
+
+	  nchars_avail = *n + *lineptr - read_pos;
+	  *lineptr = realloc (*lineptr, *n);
+	  if (!*lineptr)
+	    return -1;
+	  read_pos = *n - nchars_avail + *lineptr;
+	}
+
+      if (c == EOF || ferror (stream))
+	{
+	  /* Return partial line, if any.  */
+	  if (read_pos == *lineptr)
+	    return -1;
+	  else
+	    break;
+	}
+
+      *read_pos++ = c;
+      nchars_avail--;
+
+      if (c == delim1 || (delim2 && c == delim2))
+	/* Return the line.  */
+	break;
+    }
+
+  /* Done - NUL terminate and return the number of chars read.  */
+  *read_pos = '\0';
+
+  ret = read_pos - (*lineptr + offset);
+  return ret;
+}
+
+
+int
+getnline( char **lineptr, size_t *n, int limit, FILE *stream )
+{
+  return getdelim2( lineptr, n, 0, limit, '\n', 0, stream );
+}
+
+int
+getndelim( char **lineptr, size_t *n, int limit, int delimiter, FILE *stream )
+{
+  return getdelim2( lineptr, n, 0, limit, delimiter, 0, stream );
+}
Index: lib/getnline.h
===================================================================
RCS file: lib/getnline.h
diff -N lib/getnline.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ lib/getnline.h	16 Jul 2003 19:50:47 -0000
@@ -0,0 +1,35 @@
+/* Implementation of getnline function, a version of the GNU C library
+   function getline which allows a maximum number of characters retrieved
+   to be set.
+
+   Copyright (C) 1995, 1997, 1999, 2000, 2001, 2002, 2003 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
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef GETNLINE_H_
+# define GETNLINE_H_ 1
+
+# include <stddef.h>
+# include <stdio.h>
+
+# define GETNLINE_NO_LIMIT -1
+
+int getnline( char **_lineptr, size_t *_n, int limit, FILE *_stream );
+
+int getndelim( char **_lineptr, size_t *_n, int limit, int _delimiter,
+               FILE *_stream );
+
+#endif /* not GETNLINE_H_ */
Index: m4/getline.m4
===================================================================
RCS file: /cvsroot/gnulib/gnulib/m4/getline.m4,v
retrieving revision 1.11
diff -u -r1.11 getline.m4
--- m4/getline.m4	13 Jan 2003 07:08:00 -0000	1.11
+++ m4/getline.m4	16 Jul 2003 19:50:48 -0000
@@ -1,4 +1,4 @@
-# getline.m4 serial 8
+# getline.m4 serial 9
 
 dnl Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software
 dnl Foundation, Inc.
@@ -22,9 +22,9 @@
 
   am_getline_needs_run_time_check=no
   AC_CHECK_FUNC(getline,
-		dnl Found it in some library.  Verify that it works.
-		am_getline_needs_run_time_check=yes,
-		am_cv_func_working_getline=no)
+                dnl Found it in some library.  Verify that it works.
+                am_getline_needs_run_time_check=yes,
+                am_cv_func_working_getline=no)
   if test $am_getline_needs_run_time_check = yes; then
     AC_CACHE_CHECK([for working getline function], am_cv_func_working_getline,
     [echo fooN |tr -d '\012'|tr N '\012' > conftest.data
@@ -49,7 +49,10 @@
     )])
   fi
 
-  if test $am_cv_func_working_getline = no; then
+  if test $am_cv_func_working_getline = yes; then
+    AC_DEFINE([HAVE_WORKING_GETLINE], [1],
+      [Define to 1 if your system has a working GNU getline() function.])
+  else
     dnl We must choose a different name for our function, since on ELF systems
     dnl a broken getline() in libc.so would override our getline() in
     dnl libgettextlib.so.
@@ -63,6 +66,11 @@
 # Prerequisites of lib/getline.c.
 AC_DEFUN([gl_PREREQ_GETLINE],
 [
-  AC_REQUIRE([AC_HEADER_STDC])
-  AC_CHECK_FUNCS(getdelim)
+  AC_CHECK_FUNCS(getdelim,
+                 dnl found it.
+                 gl_have_getdelim=yes,
+                 gl_have_getdelim=no)
+  if test $gl_have_getdelim = no; then
+    gl_PREREQ_GETNLINE
+  fi
 ])
Index: m4/getnline.m4
===================================================================
RCS file: m4/getnline.m4
diff -N m4/getnline.m4
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ m4/getnline.m4	16 Jul 2003 19:50:48 -0000
@@ -0,0 +1,16 @@
+# getnline.m4 serial 1
+
+dnl Copyright (C) 2003 Free Software Foundation, Inc.
+
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+# Prerequisites of lib/getnline.c.
+AC_DEFUN([gl_PREREQ_GETNLINE],
+[
+  AC_REQUIRE([AC_HEADER_STDC])
+  AC_LIBOBJ(getnline)
+])
Index: modules/getline
===================================================================
RCS file: /cvsroot/gnulib/gnulib/modules/getline,v
retrieving revision 1.4
diff -u -r1.4 getline
--- modules/getline	20 Jan 2003 10:02:37 -0000	1.4
+++ modules/getline	16 Jul 2003 19:50:48 -0000
@@ -4,7 +4,10 @@
 Files:
 lib/getline.h
 lib/getline.c
+lib/getnline.h
+lib/getnline.c
 m4/getline.m4
+m4/getnline.m4
 
 Depends-on:
 unlocked-io
@@ -13,7 +16,7 @@
 AM_FUNC_GETLINE
 
 Makefile.am:
-lib_SOURCES += getline.h
+lib_SOURCES += getline.h getnline.h
 
 Include:
 "getline.h"
Index: modules/getnline
===================================================================
RCS file: modules/getnline
diff -N modules/getnline
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/getnline	16 Jul 2003 19:50:48 -0000
@@ -0,0 +1,23 @@
+Description:
+Read a line of n characters or less from a stream.
+
+Files:
+lib/getnline.h
+lib/getnline.c
+m4/getnline.m4
+
+Depends-on:
+unlocked-io
+
+configure.ac:
+gl_PREREQ_GETNLINE
+
+Makefile.am:
+lib_SOURCES += getnline.h
+
+Include:
+"getnline.h"
+
+Maintainer:
+all
+



Derek

-- 
                *8^)

Email: [email protected]

Get CVS support at <http://ximbiot.com>!
-- 
I cannot live without books.

			- Thomas Jefferson
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.