diff options
author | peter <peter@FreeBSD.org> | 1999-12-19 14:14:37 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-12-19 14:14:37 +0000 |
commit | a80a84873985be133ae59d0a674342e751bfa3a4 (patch) | |
tree | 443d579a4ca6fbf847fe59b576a52926a6b81f90 /lib/libutil | |
parent | 73b600cb26b21fa1f5a822b9baf2e2a97266dfbc (diff) | |
parent | 3cf81c35aeec9a68f04a9ff772f9d4eb26e3605b (diff) | |
download | FreeBSD-src-a80a84873985be133ae59d0a674342e751bfa3a4.zip FreeBSD-src-a80a84873985be133ae59d0a674342e751bfa3a4.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r54820,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'lib/libutil')
-rw-r--r-- | lib/libutil/fparseln.3 | 153 | ||||
-rw-r--r-- | lib/libutil/fparseln.c | 230 |
2 files changed, 383 insertions, 0 deletions
diff --git a/lib/libutil/fparseln.3 b/lib/libutil/fparseln.3 new file mode 100644 index 0000000..a5ea8db --- /dev/null +++ b/lib/libutil/fparseln.3 @@ -0,0 +1,153 @@ +.\" $NetBSD: fparseln.3,v 1.7 1999/07/02 15:49:12 simonb 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Christos Zoulas. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" 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 December 1, 1997 +.Dt FPARSELN 3 +.Os +.Sh NAME +.Nm fparseln +.Nd return the next logical line from a stream +.Sh LIBRARY +.Lb libutil +.Sh SYNOPSIS +.Fd #include <util.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 dynamicaly 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 preceeding 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 preceeding an escaped comment. +.It Dv FPARSELN_UNESCCONT +Remove escape preceeding an escaped continuation. +.It Dv FPARSELN_UNESCESC +Remove escape preceeding an escaped escape. +.It Dv FPARSELN_UNESCREST +Remove escape preceeding 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/lib/libutil/fparseln.c b/lib/libutil/fparseln.c new file mode 100644 index 0000000..cd4d3dd --- /dev/null +++ b/lib/libutil/fparseln.c @@ -0,0 +1,230 @@ +/* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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.9 1999/09/20 04:48:06 lukem Exp $"); +#endif + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <util.h> + +static int isescaped __P((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(sp, p, esc) + const char *sp, *p; + int esc; +{ + const char *cp; + size_t ne; + + _DIAGASSERT(sp != NULL); + _DIAGASSERT(p != NULL); + + /* No escape character */ + if (esc == '\0') + return 1; + + /* 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(fp, size, lineno, str, flags) + 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'; + + 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 escape */ + cnt = 1; + } + } + + if (s == 0 && buf != NULL) + continue; + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + 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 __P((int, char **)); + +int +main(argc, argv) + 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 */ |