]> git.ipfire.org Git - thirdparty/libbsd.git/commitdiff
Add new fparseln() function
authorStrake <strake888@gmail.com>
Tue, 7 Aug 2012 13:44:30 +0000 (08:44 -0500)
committerGuillem Jover <guillem@hadrons.org>
Mon, 27 May 2013 00:47:32 +0000 (02:47 +0200)
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 <guillem@hadrons.org>
COPYING
include/bsd/libutil.h
man/Makefile.am
man/fparseln.3 [new file with mode: 0644]
src/Makefile.am
src/fparseln.c [new file with mode: 0644]
src/libbsd.map

diff --git a/COPYING b/COPYING
index 5a42e5052af678d1fac2711c45f25c593f0ce697..417a88472e6893ed39c0745e5980871a27608d43 100644 (file)
--- 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 <provos@citi.umich.edu>
     All rights reserved.
 
index 648473c5742b5d3d580af53b004ed91bd315b15e..ebb6160692aca80ac60d49a57dfb029bfcc01df7 100644 (file)
 #define _LIBUTIL_H_
 
 #include <features.h>
+#include <sys/cdefs.h>
 #include <sys/types.h>
 #include <stdint.h>
+#include <stdio.h>
 
 /* 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_ */
index d43ce85702d3f4005f9e434127f17dfb34263464..6881f1290dc5fa58a0810ff082d9c604170e5c31 100644 (file)
@@ -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 (file)
index 0000000..1c215ac
--- /dev/null
@@ -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 .
index f2ef81d1cf3cfdcfd30f930148f7d9f7cb4c900b..2146438113458dbf3b55bab818e4f8b3a245b3f4 100644 (file)
@@ -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 (file)
index 0000000..0796b66
--- /dev/null
@@ -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 <sys/cdefs.h>
+#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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 */
index 2f518d9bfc8ccd2dffe886a559632d51d6f04ef0..488267c4d75bc3d7800d54db223dc6a6619da14e 100644 (file)
@@ -96,6 +96,8 @@ LIBBSD_0.4 {
 } LIBBSD_0.3;
 
 LIBBSD_0.5 {
+    fparseln;
+
     strnstr;
 
     wcslcat;