The return of EINVAL on fp NULL comes from me. I think its even an invalid argument like the other pointers. The rest should be fine now.
Thank you. On Thu, Mar 08, 2012 at 02:15:28AM +0000, Federico Schwindt wrote: > On Wed, Mar 7, 2012 at 7:42 AM, Jan Klemkow <[email protected]> wrote: > > Hi Federico, > > > > First I just want to port the NetBSD Implementation. But the NetBSD > > Implementation just looks like bad code. In my opinion the worst thing > > is these five times bit shifting to get a number with the power of two. > > It is more complex than it have to. So I decide it to implement it on > > my own. (I just try to make is better :-) > > > > The manpage, I just copied cause of my ugly English skills. > > I just looked at your diff quickly and I have a few comments: > > - you return EINVAL on fp NULL. where is that coming from? > - there is no check for __srefill returning an error. > - no call to _SET_ORIENTATION() > - you're not setting __SERR on error. > - c should be unsigned > > I will take another look tomorrow but I don't think this is ready to > go in as it is, sorry. > > f.- Index: stdio/Makefile.inc =================================================================== RCS file: /cvs/src/lib/libc/stdio/Makefile.inc,v retrieving revision 1.21 diff -u -p -r1.21 Makefile.inc --- stdio/Makefile.inc 18 Jan 2012 14:01:38 -0000 1.21 +++ stdio/Makefile.inc 12 Mar 2012 12:45:57 -0000 @@ -18,12 +18,14 @@ SRCS+= asprintf.c clrerr.c fclose.c fdop fgetwc.c fgetws.c fputwc.c fputws.c fwide.c getwc.c getwchar.c \ putwc.c putwchar.c ungetwc.c \ fwprintf.c swprintf.c vfwprintf.c vswprintf.c vwprintf.c wprintf.c \ - fwscanf.c swscanf.c vfwscanf.c vswscanf.c vwscanf.c wscanf.c + fwscanf.c swscanf.c vfwscanf.c vswscanf.c vwscanf.c wscanf.c \ + getdelim.c MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fopen.3 fputs.3 \ fread.3 fseek.3 funopen.3 getc.3 mktemp.3 perror.3 printf.3 putc.3 \ remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 ungetc.3 \ - fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 wscanf.3 + fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 wscanf.3 \ + getdelim.3 MLINKS+=ferror.3 clearerr.3 ferror.3 feof.3 ferror.3 fileno.3 MLINKS+=fflush.3 fpurge.3 Index: stdio/getdelim.3 =================================================================== RCS file: stdio/getdelim.3 diff -N stdio/getdelim.3 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ stdio/getdelim.3 12 Mar 2012 12:45:57 -0000 @@ -0,0 +1,156 @@ +.\" $OpenBSD$ +.\" $NetBSD: getdelim.3,v 1.9 2011/04/20 23:37:51 enami Exp $ +.\" +.\" Copyright (c) 2009 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Roy Marples. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd $Mdocdate$ +.Dt GETDELIM 3 +.Os +.Sh NAME +.Nm getdelim , +.Nm getline +.Nd read a delimited record from a 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 getline "char ** restrict lineptr" "size_t * restrict n" "FILE * restrict stream" +.Sh DESCRIPTION +The +.Fn getdelim +function reads from the +.Fa stream +until it encounters a character matching +.Fa delimiter , +storing the input in +.Fa *lineptr . +The buffer is +.Dv NUL Ns No -terminated +and includes the delimiter. +The +.Fa delimiter +character must be representable as an unsigned char. +.Pp +If +.Fa *n +is non-zero, then +.Fa *lineptr +must be pre-allocated to at least +.Fa *n +bytes. +The buffer should be allocated dynamically; +it must be possible to +.Xr free 3 +.Fa *lineptr . +.Fn getdelim +ensures that +.Fa *lineptr +is large enough to hold the input, updating +.Fa *n +to reflect the new size. +.Pp +The +.Fn getline +function is equivalent to +.Fn getdelim +with +.Fa delimiter +set to the newline character. +.Sh RETURN VALUES +The +.Fn getdelim +and +.Fn getline +functions return the number of characters read, including the delimiter. +If no characters were read and the stream is at end-of-file, the functions +return \-1. +If an error occurs, the functions return \-1 and the global variable +.Va errno +is set to indicate the error. +.Pp +The functions do not distinguish between end-of-file and error, +and callers must use +.Xr feof 3 +and +.Xr ferror 3 +to determine which occurred. +.Sh EXAMPLES +The following code fragment reads lines from a file and writes them to +standard output. +.Bd -literal -offset indent +char *line = NULL; +size_t linesize = 0; +ssize_t linelen; + +while ((linelen = getline(\*[Am]line, \*[Am]linesize, fp)) != -1) + fwrite(line, linelen, 1, stdout); + +if (ferror(fp)) + perror("getline"); +.Ed +.Sh ERRORS +.Bl -tag -width [EOVERFLOW] +.It Bq Er EINVAL +.Fa lineptr +or +.Fa n +is a +.Dv NULL +pointer. +.It Bq Er EOVERFLOW +More than SSIZE_MAX characters were read without encountering the delimiter. +.El +.Pp +The +.Fn getdelim +and +.Fn getline +functions may also fail and set +.Va errno +for any of the errors specified in the routines +.Xr fflush 3 , +.Xr malloc 3 , +.Xr read 2 , +.Xr stat 2 , +or +.Xr realloc 3 . +.Sh SEE ALSO +.Xr ferror 3 , +.Xr fgets 3 , +.Xr fgetln 3 , +.Xr fopen 3 +.Sh STANDARDS +The +.Fn getdelim +and +.Fn getline +functions conform to +.St -p1003.1-2008 . Index: stdio/getdelim.c =================================================================== RCS file: stdio/getdelim.c diff -N stdio/getdelim.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ stdio/getdelim.c 12 Mar 2012 12:45:57 -0000 @@ -0,0 +1,107 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2012 Jan Klemkow <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include "local.h" + +ssize_t +getdelim(char** lineptr, size_t* n, int delim, FILE* fp) +{ + unsigned char* c; + char* newp; + size_t len = 0; + size_t offset = 0; + + if (lineptr == NULL || n == NULL || fp == NULL) { + errno = EINVAL; + return -1; + } + + _SET_ORIENTATION(fp, -1); + FLOCKFILE(fp); + do { + /* if file buffer is empty, refill it */ + if (fp->_r <= 0 && __srefill(fp) == EOF && __sferror(fp)) { + fp->_flags |= __SERR; + return -1; + } + + /* search for delimiter in fp buffer */ + if ((c = memchr((void*)fp->_p, delim, (size_t)fp->_r)) == NULL){ + /* delimiter not found */ + len = (size_t) fp->_r; + } else { + /* found delimiter */ + len = (size_t) (c - (unsigned char*) fp->_p); + len++; + } + + /* checking for enought space in buffer lineptr */ + if (*n < offset + len + 1) { + if (offset + len > SSIZE_MAX) { + FUNLOCKFILE(fp); + errno = EOVERFLOW; + return -1; + } + + /* duplicate the buffersize of line */ + *n <<= 1; + + /* + * Starting with BUFSIZ if the application starts with + * an empty buffer. + */ + if (*n == 0) + *n = BUFSIZ; + + if ((newp = realloc(*lineptr, *n)) == NULL) { + FUNLOCKFILE(fp); + free(*lineptr); + *lineptr = NULL; + *n = 0; + errno = ENOMEM; + return -1; + } + *lineptr = newp; + } + + memcpy((void*) (*lineptr + offset), (void*)fp->_p, len); + offset += len; + fp->_r -= len; + fp->_p += len; + } while (c == NULL && len != 0); + FUNLOCKFILE(fp); + + *(*lineptr + offset) = '\0'; + + /* end of file */ + if (offset == 0) + return -1; + + return (ssize_t) offset; +} + +ssize_t +getline(char** lineptr, size_t* n, FILE* fp) +{ + return getdelim(lineptr, n, '\n', fp); +}
