123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /* $OpenBSD: fparseln.c,v 1.6 2005/08/02 21:46:23 espie Exp $ */
- /* $NetBSD: fparseln.c,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.
- */
- /* OPENBSD ORIGINAL: lib/libutil/fparseln.c */
- #include <sys/types.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "tmux.h"
- /*
- * fparseln() specific operation flags.
- */
- #define FPARSELN_UNESCESC 0x01
- #define FPARSELN_UNESCCONT 0x02
- #define FPARSELN_UNESCCOMM 0x04
- #define FPARSELN_UNESCREST 0x08
- #define FPARSELN_UNESCALL 0x0f
- 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;
- /* 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(FILE *fp, size_t *size, size_t *lineno, const char str[3],
- int flags)
- {
- static const char dstr[3] = { '\\', '\\', '#' };
- char *buf = NULL, *ptr, *cp, esc, con, nl, com;
- size_t s, len = 0;
- int 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(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 */
|