Hello,
I miss some std libc functions in OpenBSD. So, I deside to implement a
few of them by myself. This is a diff for getdelim(3) and getline(3).
Which are described here:
http://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
The manpage tooked from NetBSD, because I am not able to write it
better.
At the moment this patch breaks the build, because some programs has
there own getline() function. I do not know the best solution for this
problem now. In my opinion you could rename the self-made functions
to get the std libc function into the source tree. And then, replace
some of them with the std libc functions. I think, you have to choose
a decition individually for every case.
Please, test them and tell me everything that is wrong with it.
I test it with OpenBSD amd64 current.
thanks,
Jan
Index: Makefile.inc
===================================================================
RCS file: /cvs/src/lib/libc/stdio/Makefile.inc,v
retrieving revision 1.21
diff -u -p -r1.21 Makefile.inc
--- Makefile.inc 18 Jan 2012 14:01:38 -0000 1.21
+++ Makefile.inc 25 Jan 2012 20:16:30 -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: getdelim.3
===================================================================
RCS file: getdelim.3
diff -N getdelim.3
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ getdelim.3 25 Jan 2012 20:16:30 -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: getdelim.c
===================================================================
RCS file: getdelim.c
diff -N getdelim.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ getdelim.c 25 Jan 2012 20:16:30 -0000
@@ -0,0 +1,108 @@
+/* $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)
+{
+ char* c;
+ size_t len = 0;
+ size_t offset = 0;
+
+ if (lineptr == NULL || n == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* the application has to ensure this, bus we check this here, too. */
+ if (delim < 0)
+ return -1;
+
+ if (fp == NULL)
+ return -1;
+
+ FLOCKFILE(fp);
+ do {
+ /* if file buffer is empty, refill it */
+ if (fp->_r <= 0)
+ __srefill(fp);
+
+ /* 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 - (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;
+
+ *lineptr = realloc(*lineptr, *n);
+
+ if (*lineptr == NULL) {
+ FUNLOCKFILE(fp);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+
+ memcpy((void*) (*lineptr + offset), (void*)fp->_p, len);
+ offset += len;
+ fp->_r -= len;
+ fp->_p += len;
+ } while (c == NULL && len != 0);
+ FUNLOCKFILE(fp);
+
+ *(*lineptr + (char) 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);
+}