tech-userlevel archive

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

Re: adding getdelim(3) and getline(3) to libc



On Sun, Jul 12, 2009 at 11:46:57PM +0100, Roy Marples wrote:
> Our libc lacks getdelim(3) and getline(3) which are in POSIX IEEE Std  
> 1003.1-2008
> http://www.opengroup.org/onlinepubs/9699919799/functions/getline.html
>
> Attached is patch to add these fucntions and man page to our libc.
> I've not extensively tested it, but it seems to work fine.

I'd add some appropriate tests in regress/lib/libc/stdio (?)
to go with this.


> The only issue is that getline collides with quite a few userland bits  
> such as ctags and nawk. I propose we change their internal definitons to  
> get_line, unless the really implement their own getline(3) and we can  
> just remove it.

Rename theirs is probably the way to go -- they'll have problems
on other modern POSIX systems anyway.


> Comments?

More inline.



  | Index: lib/libc/stdio/getdelim.c
  | ===================================================================
  | RCS file: lib/libc/stdio/getdelim.c
  | diff -N lib/libc/stdio/getdelim.c
  | --- /dev/null       1 Jan 1970 00:00:00 -0000
  | +++ lib/libc/stdio/getdelim.c       12 Jul 2009 22:29:37 -0000
  | @@ -0,0 +1,111 @@
  | +/* $NetBSD: $ */

Convert this to "$NetBSD$" so it gets expanded correctly.


  | +#include <sys/cdefs.h>
  | +#if !defined(lint)
  | +__RCSID("$NetBSD: fgetstr.c,v 1.5 2009/01/31 06:14:13 lukem Exp $");
  | +#endif

Convert this to "$NetBSD$" before checkin (just as a matter of style).


  | +#include <assert.h>
  | +#include <errno.h>
  | +#include <stdio.h>
  | +#include <stdlib.h>
  | +#include <string.h>
  | +#include "reentrant.h"
  | +#include "local.h"

Add a blank line after <string.h>


  | +ssize_t
  | +getdelim(char **__restrict buf, size_t *__restrict buflen,
  | +    int sep, FILE *__restrict fp)
  | +{
  | +   unsigned char *p;
  | +   ssize_t len, off;
  | +   char *newb;
  | +
  | +   _DIAGASSERT(buf != NULL);
  | +   _DIAGASSERT(bufsiz != NULL);

Arguably these aren't necessary when the function explicitly
checks the parameters, as it does below.


  | +   _DIAGASSERT(fp != NULL);
  | +
  | +   if (buf == NULL || buflen == NULL) {
  | +           errno = EINVAL;
  | +           return -1;
  | +   }
  | +
  | +   FLOCKFILE(fp);
  | +   _SET_ORIENTATION(fp, -1);
  | +   off = 0;
  | +   for (;;) {
  | +           /* If the buffer is empty, refill it. */
  | +           if (fp->_r <= 0) {
  | +                   if (__srefill(fp)) {
  | +                           /* EOF/error: stop with partial or no line */
  | +                           if (off == 0) {
  | +                                   FUNLOCKFILE(fp);
  | +                                   return -1;
  | +                           }
  | +                           break;
  | +                   }
  | +           }
  | +
  | +           /* Scan through looking for the seperator. */

"separator"


  | +           p = memchr(fp->_p, sep, fp->_r);
  | +           if (p == NULL)
  | +                   len = fp->_r;
  | +           else
  | +                   len = (p - fp->_p) + 1;
  | +
  | +           /* Ensure that the resultant buffer length fits in ssize_t */
  | +           if (off + len + 1 < off) {
  | +                   FUNLOCKFILE(fp);
  | +                   errno = EOVERFLOW;
  | +                   return -1;
  | +           }
  | +           /* Ensure our buffer is large enough, including a terminator */
  | +           if ((size_t)(off + len + 1) > *buflen) {
  | +                   newb = realloc(*buf, off + len + 1);
  | +                   if (newb == NULL) {
  | +                           FUNLOCKFILE(fp);
  | +                           return -1;
  | +                   }
  | +                   *buf = newb;
  | +                   *buflen = off + len;
  | +           }
  | +
  | +           (void)memcpy((void *)(*buf + off), (void *)fp->_p, len);
  | +           fp->_r -= len;
  | +           fp->_p += len;
  | +           off += len;
  | +           if (p != NULL)
  | +                   break;
  | +   }
  | +   FUNLOCKFILE(fp);
  | +   if (*buf != NULL)
  | +           *(*buf + off) = '\0';
  | +   return off;
  | +}
  | Index: lib/libc/stdio/getline.c
  | ===================================================================
  | RCS file: lib/libc/stdio/getline.c
  | diff -N lib/libc/stdio/getline.c
  | --- /dev/null       1 Jan 1970 00:00:00 -0000
  | +++ lib/libc/stdio/getline.c        12 Jul 2009 22:29:37 -0000
  | @@ -0,0 +1,46 @@
  | +/* $NetBSD: $ */

Same change as for getdelim.c


  | +#include <sys/cdefs.h>
  | +#if !defined(lint)
  | +__RCSID("$NetBSD: fgetln.c,v 1.14 2004/05/10 16:47:11 drochner Exp $");
  | +#endif

Same change as for getdelim.c


  | Index: lib/libc/stdio/getdelim.3
  | ===================================================================
  | RCS file: lib/libc/stdio/getdelim.3
  | diff -N lib/libc/stdio/getdelim.3
  | --- /dev/null       1 Jan 1970 00:00:00 -0000
  | +++ lib/libc/stdio/getdelim.3       12 Jul 2009 22:29:37 -0000
  | @@ -0,0 +1,118 @@
  | +.\"     $NetBSD: Exp $

Oops!


  | +.\"
  | +.Dd July 12, 2009
  | +.Dt GETDELIM 3
  | +.Os
  | +.Sh NAME
  | +.Nm getdelim ,
  | +.Nm getline
  | +.Nd read a delimited record from input stream
  | +.Sh LIBRARY
  | +.Lb libc
  | +.Sh SYNOPSIS
  | +.In stdio.h
  | +.Ft ssize_t
  | +.Fn getdelim "char ** restrict lineptr" "size_t * restrict n" "int 
delimiter" "FILE * restrict stream"
  | +.Ft ssize_t
  | +.Fn getdeline "char ** restrict lineptr" "size_t * restrict n" "FILE * 
restrict stream"

This should be "getline" not "getdeline"


I suggest that you update stdio(3) for these methods.



cheers,
Luke.

Attachment: pgptEdgWIiLNc.pgp
Description: PGP signature



Home | Main Index | Thread Index | Old Index