From: Strake Date: Tue, 7 Aug 2012 13:44:30 +0000 (-0500) Subject: Add new fparseln() function X-Git-Tag: 0.5.0~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee0489eb2bd09298f547c57a59f28dcd094d781e;p=thirdparty%2Flibbsd.git Add new fparseln() function Taken from NetBSD. [guillem@hadrons.org: - Import from NetBSD instead of FreeBSD to get a 3-clause BSD license, instead of a 4-clause one. - Define compatibility macros. - Change library from libc to libbsd and header in man page. - Add copyright information to COPYING. - Add symbol to map file. ] Signed-off-by: Guillem Jover --- diff --git a/COPYING b/COPYING index 5a42e50..417a884 100644 --- a/COPYING +++ b/COPYING @@ -283,6 +283,9 @@ The rest of the licenses apply to code and/or man pages. -- + Copyright © 1997 Christos Zoulas. + All rights reserved. + Copyright © 2002 Niels Provos All rights reserved. diff --git a/include/bsd/libutil.h b/include/bsd/libutil.h index 648473c..ebb6160 100644 --- a/include/bsd/libutil.h +++ b/include/bsd/libutil.h @@ -40,8 +40,10 @@ #define _LIBUTIL_H_ #include +#include #include #include +#include /* for pidfile.c */ struct pidfh { @@ -62,6 +64,8 @@ struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); int pidfile_write(struct pidfh *pfh); int pidfile_close(struct pidfh *pfh); int pidfile_remove(struct pidfh *pfh); + +char *fparseln(FILE *, size_t *, size_t *, const char[3], int); __END_DECLS /* humanize_number(3) */ @@ -73,4 +77,13 @@ __END_DECLS #define HN_GETSCALE 0x10 #define HN_AUTOSCALE 0x20 +/* + * fparseln() specific operation flags. + */ +#define FPARSELN_UNESCESC 0x01 +#define FPARSELN_UNESCCONT 0x02 +#define FPARSELN_UNESCCOMM 0x04 +#define FPARSELN_UNESCREST 0x08 +#define FPARSELN_UNESCALL 0x0f + #endif /* !_LIBUTIL_H_ */ diff --git a/man/Makefile.am b/man/Makefile.am index d43ce85..6881f12 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -26,6 +26,7 @@ dist_man_MANS = \ fgetln.3 \ flopen.3 \ fmtcheck.3 \ + fparseln.3 \ getmode.3 \ getpeereid.3 \ getprogname.3 \ diff --git a/man/fparseln.3 b/man/fparseln.3 new file mode 100644 index 0000000..1c215ac --- /dev/null +++ b/man/fparseln.3 @@ -0,0 +1,149 @@ +.\" $NetBSD: fparseln.3,v 1.4 2009/10/21 01:07:45 snj Exp $ +.\" +.\" Copyright (c) 1997 Christos Zoulas. All rights reserved. +.\" +.\" 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 AUTHOR ``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 AUTHOR 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 November 30, 2002 +.Dt FPARSELN 3 +.Os +.Sh NAME +.Nm fparseln +.Nd return the next logical line from a stream +.Sh LIBRARY +.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd) +.Lb libbsd +.Sh SYNOPSIS +.In bsd/stdio.h +.Ft "char *" +.Fo "fparseln" +.Fa "FILE *stream" "size_t *len" "size_t *lineno" +.Fa "const char delim[3]" "int flags" +.Fc +.Sh DESCRIPTION +The +.Fn fparseln +function +returns a pointer to the next logical line from the stream referenced by +.Fa stream . +This string is +.Dv NUL +terminated and it is dynamically allocated on each invocation. +It is the responsibility of the caller to free the pointer. +.Pp +By default, if a character is escaped, both it and the preceding escape +character will be present in the returned string. +Various +.Fa flags +alter this behaviour. +.Pp +The meaning of the arguments is as follows: +.Bl -tag -width "lineno" +.It Fa stream +The stream to read from. +.It Fa len +If not +.Dv NULL , +the length of the string is stored in the memory location to which it +points. +.It Fa lineno +If not +.Dv NULL , +the value of the memory location to which is pointed to, is incremented +by the number of lines actually read from the file. +.It Fa delim +Contains the escape, continuation, and comment characters. +If a character is +.Dv NUL +then processing for that character is disabled. +If +.Dv NULL , +all characters default to values specified below. +The contents of +.Fa delim +is as follows: +.Bl -tag -width "delim[0]" +.It Fa delim[0] +The escape character, which defaults to +.Cm \e , +is used to remove any special meaning from the next character. +.It Fa delim[1] +The continuation character, which defaults to +.Cm \e , +is used to indicate that the next line should be concatenated with the +current one if this character is the last character on the current line +and is not escaped. +.It Fa delim[2] +The comment character, which defaults to +.Cm # , +if not escaped indicates the beginning of a comment that extends until the +end of the current line. +.El +.It Fa flags +If non-zero, alter the operation of +.Fn fparseln . +The various flags, which may be +.Em or Ns -ed +together, are: +.Bl -tag -width "FPARSELN_UNESCCOMM" +.It Dv FPARSELN_UNESCCOMM +Remove escape preceding an escaped comment. +.It Dv FPARSELN_UNESCCONT +Remove escape preceding an escaped continuation. +.It Dv FPARSELN_UNESCESC +Remove escape preceding an escaped escape. +.It Dv FPARSELN_UNESCREST +Remove escape preceding any other character. +.It Dv FPARSELN_UNESCALL +All of the above. +.El +.Pp +.El +.Sh RETURN VALUES +Upon successful completion a pointer to the parsed line is returned; +otherwise, +.Dv NULL +is returned. +.Pp +The +.Fn fparseln +function uses internally +.Xr fgetln 3 , +so all error conditions that apply to +.Xr fgetln 3 , +apply to +.Fn fparseln . +In addition +.Fn fparseln +may set +.Va errno +to +.Bq Er ENOMEM +and return +.Dv NULL +if it runs out of memory. +.Sh SEE ALSO +.Xr fgetln 3 +.Sh HISTORY +The +.Fn fparseln +function first appeared in +.Nx 1.4 . diff --git a/src/Makefile.am b/src/Makefile.am index f2ef81d..2146438 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ libbsd_la_SOURCES = \ fgetln.c \ flopen.c \ fmtcheck.c \ + fparseln.c \ fpurge.c \ getpeereid.c \ hash/md5.c \ diff --git a/src/fparseln.c b/src/fparseln.c new file mode 100644 index 0000000..0796b66 --- /dev/null +++ b/src/fparseln.c @@ -0,0 +1,230 @@ +/* $NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include + +#define FLOCKFILE(fp) +#define FUNLOCKFILE(fp) +#define _DIAGASSERT(t) + +static int isescaped(const char *, const char *, int); + +/* isescaped(): + * Return true if the character in *p that belongs to a string + * that starts in *sp, is escaped by the escape character esc. + */ +static int +isescaped(const char *sp, const char *p, int esc) +{ + const char *cp; + size_t ne; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* No escape character */ + if (esc == '\0') + return 0; + + /* Count the number of escape characters that precede ours */ + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) + continue; + + /* Return true if odd number of escape characters */ + return (ne & 1) != 0; +} + + +/* fparseln(): + * Read a line from a file parsing continuations ending in \ + * and eliminating trailing newlines, or comments starting with + * the comment char. + */ +char * +fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) +{ + static const char dstr[3] = { '\\', '\\', '#' }; + + size_t s, len; + char *buf; + char *ptr, *cp; + int cnt; + char esc, con, nl, com; + + _DIAGASSERT(fp != NULL); + + len = 0; + buf = NULL; + cnt = 1; + + if (str == NULL) + str = dstr; + + esc = str[0]; + con = str[1]; + com = str[2]; + /* + * XXX: it would be cool to be able to specify the newline character, + * but unfortunately, fgetln does not let us + */ + nl = '\n'; + + FLOCKFILE(fp); + + while (cnt) { + cnt = 0; + + if (lineno) + (*lineno)++; + + if ((ptr = fgetln(fp, &s)) == NULL) + break; + + if (s && com) { /* Check and eliminate comments */ + for (cp = ptr; cp < ptr + s; cp++) + if (*cp == com && !isescaped(ptr, cp, esc)) { + s = cp - ptr; + cnt = s == 0 && buf == NULL; + break; + } + } + + if (s && nl) { /* Check and eliminate newlines */ + cp = &ptr[s - 1]; + + if (*cp == nl) + s--; /* forget newline */ + } + + if (s && con) { /* Check and eliminate continuations */ + cp = &ptr[s - 1]; + + if (*cp == con && !isescaped(ptr, cp, esc)) { + s--; /* forget continuation char */ + cnt = 1; + } + } + + if (s == 0) { + /* + * nothing to add, skip realloc except in case + * we need a minimal buf to return an empty line + */ + if (cnt || buf != NULL) + continue; + } + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + FUNLOCKFILE(fp); + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + FUNLOCKFILE(fp); + + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && + strchr(buf, esc) != NULL) { + ptr = cp = buf; + while (cp[0] != '\0') { + int skipesc; + + while (cp[0] != '\0' && cp[0] != esc) + *ptr++ = *cp++; + if (cp[0] == '\0' || cp[1] == '\0') + break; + + skipesc = 0; + if (cp[1] == com) + skipesc += (flags & FPARSELN_UNESCCOMM); + if (cp[1] == con) + skipesc += (flags & FPARSELN_UNESCCONT); + if (cp[1] == esc) + skipesc += (flags & FPARSELN_UNESCESC); + if (cp[1] != com && cp[1] != con && cp[1] != esc) + skipesc = (flags & FPARSELN_UNESCREST); + + if (skipesc) + cp++; + else + *ptr++ = *cp++; + *ptr++ = *cp++; + } + *ptr = '\0'; + len = strlen(buf); + } + + if (size) + *size = len; + return buf; +} + +#ifdef TEST + +int main(int, char **); + +int +main(int argc, char **argv) +{ + char *ptr; + size_t size, line; + + line = 0; + while ((ptr = fparseln(stdin, &size, &line, NULL, + FPARSELN_UNESCALL)) != NULL) + printf("line %d (%d) |%s|\n", line, size, ptr); + return 0; +} + +/* + +# This is a test +line 1 +line 2 \ +line 3 # Comment +line 4 \# Not comment \\\\ + +# And a comment \ +line 5 \\\ +line 6 + +*/ + +#endif /* TEST */ diff --git a/src/libbsd.map b/src/libbsd.map index 2f518d9..488267c 100644 --- a/src/libbsd.map +++ b/src/libbsd.map @@ -96,6 +96,8 @@ LIBBSD_0.4 { } LIBBSD_0.3; LIBBSD_0.5 { + fparseln; + strnstr; wcslcat;