154820Speter/* $NetBSD: fparseln.c,v 1.9 1999/09/20 04:48:06 lukem Exp $ */ 254820Speter 354820Speter/* 454820Speter * Copyright (c) 1997 Christos Zoulas. All rights reserved. 554820Speter * 654820Speter * Redistribution and use in source and binary forms, with or without 754820Speter * modification, are permitted provided that the following conditions 854820Speter * are met: 954820Speter * 1. Redistributions of source code must retain the above copyright 1054820Speter * notice, this list of conditions and the following disclaimer. 1154820Speter * 2. Redistributions in binary form must reproduce the above copyright 1254820Speter * notice, this list of conditions and the following disclaimer in the 1354820Speter * documentation and/or other materials provided with the distribution. 1454820Speter * 3. All advertising materials mentioning features or use of this software 1554820Speter * must display the following acknowledgement: 1654820Speter * This product includes software developed by Christos Zoulas. 1754820Speter * 4. The name of the author may not be used to endorse or promote products 1854820Speter * derived from this software without specific prior written permission. 1954820Speter * 2054820Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2154820Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2254820Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2354820Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2454820Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2554820Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2654820Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2754820Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2854820Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2954820Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3054820Speter */ 3154820Speter 3254820Speter#include <sys/cdefs.h> 3384225Sdillon__FBSDID("$FreeBSD$"); 3454820Speter 3555227Speter#include <sys/types.h> 3654820Speter#include <assert.h> 3754820Speter#include <errno.h> 3854820Speter#include <stdio.h> 3954820Speter#include <string.h> 4054820Speter#include <stdlib.h> 4155227Speter#include <libutil.h> 4254820Speter 4392917Sobrienstatic int isescaped(const char *, const char *, int); 4454820Speter 4554820Speter/* isescaped(): 4654820Speter * Return true if the character in *p that belongs to a string 4754820Speter * that starts in *sp, is escaped by the escape character esc. 4854820Speter */ 4954820Speterstatic int 50121193Smarkmisescaped(const char *sp, const char *p, int esc) 5154820Speter{ 5254820Speter const char *cp; 5354820Speter size_t ne; 5454820Speter 5555227Speter#if 0 5654820Speter _DIAGASSERT(sp != NULL); 5754820Speter _DIAGASSERT(p != NULL); 5855227Speter#endif 5954820Speter 6054820Speter /* No escape character */ 6154820Speter if (esc == '\0') 6254820Speter return 1; 6354820Speter 6454820Speter /* Count the number of escape characters that precede ours */ 6554820Speter for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) 6654820Speter continue; 6754820Speter 6854820Speter /* Return true if odd number of escape characters */ 6954820Speter return (ne & 1) != 0; 7054820Speter} 7154820Speter 7254820Speter 7354820Speter/* fparseln(): 7454820Speter * Read a line from a file parsing continuations ending in \ 7554820Speter * and eliminating trailing newlines, or comments starting with 7654820Speter * the comment char. 7754820Speter */ 7854820Speterchar * 79121193Smarkmfparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) 8054820Speter{ 8154820Speter static const char dstr[3] = { '\\', '\\', '#' }; 8254820Speter 8354820Speter size_t s, len; 8454820Speter char *buf; 8554820Speter char *ptr, *cp; 8654820Speter int cnt; 8754820Speter char esc, con, nl, com; 8854820Speter 8955227Speter#if 0 9054820Speter _DIAGASSERT(fp != NULL); 9155227Speter#endif 9254820Speter 9354820Speter len = 0; 9454820Speter buf = NULL; 9554820Speter cnt = 1; 9654820Speter 9754820Speter if (str == NULL) 9854820Speter str = dstr; 9954820Speter 10054820Speter esc = str[0]; 10154820Speter con = str[1]; 10254820Speter com = str[2]; 10354820Speter /* 10454820Speter * XXX: it would be cool to be able to specify the newline character, 10554820Speter * but unfortunately, fgetln does not let us 10654820Speter */ 10754820Speter nl = '\n'; 10854820Speter 10954820Speter while (cnt) { 11054820Speter cnt = 0; 11154820Speter 11254820Speter if (lineno) 11354820Speter (*lineno)++; 11454820Speter 11554820Speter if ((ptr = fgetln(fp, &s)) == NULL) 11654820Speter break; 11754820Speter 11854820Speter if (s && com) { /* Check and eliminate comments */ 11954820Speter for (cp = ptr; cp < ptr + s; cp++) 12054820Speter if (*cp == com && !isescaped(ptr, cp, esc)) { 12154820Speter s = cp - ptr; 12254820Speter cnt = s == 0 && buf == NULL; 12354820Speter break; 12454820Speter } 12554820Speter } 12654820Speter 12754820Speter if (s && nl) { /* Check and eliminate newlines */ 12854820Speter cp = &ptr[s - 1]; 12954820Speter 13054820Speter if (*cp == nl) 13154820Speter s--; /* forget newline */ 13254820Speter } 13354820Speter 13454820Speter if (s && con) { /* Check and eliminate continuations */ 13554820Speter cp = &ptr[s - 1]; 13654820Speter 13754820Speter if (*cp == con && !isescaped(ptr, cp, esc)) { 13854820Speter s--; /* forget escape */ 13954820Speter cnt = 1; 14054820Speter } 14154820Speter } 14254820Speter 14354820Speter if (s == 0 && buf != NULL) 14454820Speter continue; 14554820Speter 14654820Speter if ((cp = realloc(buf, len + s + 1)) == NULL) { 14754820Speter free(buf); 14854820Speter return NULL; 14954820Speter } 15054820Speter buf = cp; 15154820Speter 15254820Speter (void) memcpy(buf + len, ptr, s); 15354820Speter len += s; 15454820Speter buf[len] = '\0'; 15554820Speter } 15654820Speter 15754820Speter if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && 15854820Speter strchr(buf, esc) != NULL) { 15954820Speter ptr = cp = buf; 16054820Speter while (cp[0] != '\0') { 16154820Speter int skipesc; 16254820Speter 16354820Speter while (cp[0] != '\0' && cp[0] != esc) 16454820Speter *ptr++ = *cp++; 16554820Speter if (cp[0] == '\0' || cp[1] == '\0') 16654820Speter break; 16754820Speter 16854820Speter skipesc = 0; 16954820Speter if (cp[1] == com) 17054820Speter skipesc += (flags & FPARSELN_UNESCCOMM); 17154820Speter if (cp[1] == con) 17254820Speter skipesc += (flags & FPARSELN_UNESCCONT); 17354820Speter if (cp[1] == esc) 17454820Speter skipesc += (flags & FPARSELN_UNESCESC); 17554820Speter if (cp[1] != com && cp[1] != con && cp[1] != esc) 17654820Speter skipesc = (flags & FPARSELN_UNESCREST); 17754820Speter 17854820Speter if (skipesc) 17954820Speter cp++; 18054820Speter else 18154820Speter *ptr++ = *cp++; 18254820Speter *ptr++ = *cp++; 18354820Speter } 18454820Speter *ptr = '\0'; 18554820Speter len = strlen(buf); 18654820Speter } 18754820Speter 18854820Speter if (size) 18954820Speter *size = len; 19054820Speter return buf; 19154820Speter} 19254820Speter 19354820Speter#ifdef TEST 19454820Speter 19554820Speterint 196121193Smarkmmain(int argc, char *argv[]) 19754820Speter{ 19854820Speter char *ptr; 19954820Speter size_t size, line; 20054820Speter 20154820Speter line = 0; 20254820Speter while ((ptr = fparseln(stdin, &size, &line, NULL, 20354820Speter FPARSELN_UNESCALL)) != NULL) 20454820Speter printf("line %d (%d) |%s|\n", line, size, ptr); 20554820Speter return 0; 20654820Speter} 20754820Speter 20854820Speter/* 20954820Speter 21054820Speter# This is a test 21154820Speterline 1 21254820Speterline 2 \ 21354820Speterline 3 # Comment 21454820Speterline 4 \# Not comment \\\\ 21554820Speter 21654820Speter# And a comment \ 21754820Speterline 5 \\\ 21854820Speterline 6 21954820Speter 22054820Speter*/ 22154820Speter 22254820Speter#endif /* TEST */ 223