bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: getline


From: Simon Josefsson
Subject: Re: getline
Date: Sat, 16 Jul 2005 23:29:59 +0200
User-agent: Gnus/5.110004 (No Gnus v0.4) Emacs/22.0.50 (gnu/linux)

I'm following up on this thread, it may be useful (or not..) to rehash
it:

http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/2710

As you can see, I gave up and ported the glibc implementation into a
gnulib module and used that.

I read the libc getline and getdelim implementations now, and they use
memchr.  gnulib's getndelim2 uses a loop, and may be slower for other
reasons too.  I think libc getline/getdelim would be slowed down if we
moved getndelim2 into libc and made libc getline/getdelim use it.
That was Paul's plan, I think, assuming it was possible without
slow-down.

So here is what I propose:

1) Port the libc LGPL getdelim into a gnulib module.
2a) Port the libc LGPL getline into a gnulib module.
2b) Write a gnulib LGPL getline module that use the gnulib LGPL getdelim.
3) Keep the current getndelim2 as a GPL module.

The libc getline seem somewhat different from libc getdelim;
presumably it is faster than a simple getline implementation that use
getdelim.  I'm not sure this matter for gnulib though, so I prefer 2b
for simplicity.

Finally, I'm not sure we can ever hope to sync these files between
gnulib and libc.  The libc implementation look inside the FILE
structure.  Gnulib code can't do that.

Incidentally, implementing this plan appear to be exactly what I did
for lessergnulib in December.  The getdelim module (which is the only
substantial code needed in the above plan) look as below.  Fairly
untested.

Is this an OK plan?  If you agree, I'll propose a complete patch.
Specifically:

1. Split current getline module into a getndelim2 and getline.
2. Make the getline module LGPL by using getdelim code below, and
   simple getline wrapper to call getdelim.

Thanks.

/* Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2004, 2005 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.  */

/* Ported from libc by Simon Josefsson. */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

/* Get specification.  */
#include "lgetdelim.h"

/* Get malloc. */
#include <stdlib.h>

/* Read up to (and including) a TERMINATOR from FP into *LINEPTR
   (and null-terminate it).  *LINEPTR is a pointer returned from malloc (or
   NULL), pointing to *N characters of space.  It is realloc'ed as
   necessary.  Returns the number of characters read (not including the
   null terminator), or -1 on error or EOF.  */
ssize_t
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
{
  ssize_t cur_len = 0;

  if (lineptr == NULL || n == NULL)
    return -1;

  if (*lineptr == NULL || *n == 0)
    {
      *n = 120;
      *lineptr = (char *) malloc (*n);
      if (*lineptr == NULL)
        return -1;
    }

  for (;;)
    {
      char *t;
      int i;

      i = getc (fp);
      if (i == EOF)
        break;

      /* Make enough space for curlen+1 bytes plus last NUL.  */
      if (cur_len + 1 >= *n)
        {
          size_t needed = 2 * (cur_len + 1) + 1;   /* Be generous. */
          char *new_lineptr;

          if (needed < cur_len)
            return -1; /* overflow */

          new_lineptr = realloc (*lineptr, needed);
          if (new_lineptr == NULL)
            return -1;

          *lineptr = new_lineptr;
          *n = needed;
        }

      (*lineptr)[cur_len] = i;
      cur_len++;

      if (i == delimiter)
        break;
    }
  (*lineptr)[cur_len] = '\0';

  return cur_len;
}




reply via email to

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