/* | |
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials are licensed and made available | |
under the terms and conditions of the BSD License that accompanies this | |
distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license. | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
* 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. | |
NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp | |
*/ | |
#include <LibConfig.h> | |
#include <sys/EfiCdefs.h> | |
#include "namespace.h" | |
#include <assert.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#ifdef __weak_alias | |
__weak_alias(fparseln,_fparseln) | |
#endif | |
#if ! HAVE_FPARSELN | |
#ifndef HAVE_NBTOOL_CONFIG_H | |
#include "reentrant.h" | |
#include "local.h" | |
#else | |
#define FLOCKFILE(fp) | |
#define FUNLOCKFILE(fp) | |
#endif | |
#if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H | |
#define __fgetln(f, l) __fgetstr(f, l, '\n') | |
#else | |
#define __fgetln(f, l) fgetln(f, l) | |
#endif | |
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 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] = { '\\', '\\', '#' }; | |
size_t s, len; | |
char *buf; | |
char *ptr, *cp; | |
int cnt; | |
char esc, con, nl, com; | |
_DIAGASSERT(fp != NULL); | |
if(fp == NULL) { | |
errno = EINVAL; | |
return (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 escape */ | |
cnt = 1; | |
} | |
} | |
if (s == 0 && 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 */ | |
#endif /* ! HAVE_FPARSELN */ |