1 /* 2 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> 3 This program and the accompanying materials are licensed and made available 4 under the terms and conditions of the BSD License that accompanies this 5 distribution. The full text of the license may be found at 6 http://opensource.org/licenses/bsd-license. 7 8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 11 * Copyright (c) 1997 Christos Zoulas. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by Christos Zoulas. 24 * 4. The name of the author may not be used to endorse or promote products 25 * derived from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 38 NetBSD: fparseln.c,v 1.5 2004/06/20 22:20:15 jmc Exp 39 */ 40 #include <LibConfig.h> 41 #include <sys/EfiCdefs.h> 42 43 #include "namespace.h" 44 45 #include <assert.h> 46 #include <errno.h> 47 #include <stdio.h> 48 #include <string.h> 49 #include <stdlib.h> 50 51 #ifdef __weak_alias 52 __weak_alias(fparseln,_fparseln) 53 #endif 54 55 #if ! HAVE_FPARSELN 56 57 #ifndef HAVE_NBTOOL_CONFIG_H 58 #include "reentrant.h" 59 #include "local.h" 60 #else 61 #define FLOCKFILE(fp) 62 #define FUNLOCKFILE(fp) 63 #endif 64 65 #if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H 66 #define __fgetln(f, l) __fgetstr(f, l, '\n') 67 #else 68 #define __fgetln(f, l) fgetln(f, l) 69 #endif 70 71 static int isescaped(const char *, const char *, int); 72 73 /* isescaped(): 74 * Return true if the character in *p that belongs to a string 75 * that starts in *sp, is escaped by the escape character esc. 76 */ 77 static int 78 isescaped(const char *sp, const char *p, int esc) 79 { 80 const char *cp; 81 size_t ne; 82 83 _DIAGASSERT(sp != NULL); 84 _DIAGASSERT(p != NULL); 85 86 /* No escape character */ 87 if (esc == '\0') 88 return 1; 89 90 /* Count the number of escape characters that precede ours */ 91 for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) 92 continue; 93 94 /* Return true if odd number of escape characters */ 95 return (ne & 1) != 0; 96 } 97 98 99 /* fparseln(): 100 * Read a line from a file parsing continuations ending in \ 101 * and eliminating trailing newlines, or comments starting with 102 * the comment char. 103 */ 104 char * 105 fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) 106 { 107 static const char dstr[3] = { '\\', '\\', '#' }; 108 109 size_t s, len; 110 char *buf; 111 char *ptr, *cp; 112 int cnt; 113 char esc, con, nl, com; 114 115 _DIAGASSERT(fp != NULL); 116 if(fp == NULL) { 117 errno = EINVAL; 118 return (NULL); 119 } 120 121 len = 0; 122 buf = NULL; 123 cnt = 1; 124 125 if (str == NULL) 126 str = dstr; 127 128 esc = str[0]; 129 con = str[1]; 130 com = str[2]; 131 /* 132 * XXX: it would be cool to be able to specify the newline character, 133 * but unfortunately, fgetln does not let us 134 */ 135 nl = '\n'; 136 137 FLOCKFILE(fp); 138 139 while (cnt) { 140 cnt = 0; 141 142 if (lineno) 143 (*lineno)++; 144 145 if ((ptr = __fgetln(fp, &s)) == NULL) 146 break; 147 148 if (s && com) { /* Check and eliminate comments */ 149 for (cp = ptr; cp < ptr + s; cp++) 150 if (*cp == com && !isescaped(ptr, cp, esc)) { 151 s = cp - ptr; 152 cnt = s == 0 && buf == NULL; 153 break; 154 } 155 } 156 157 if (s && nl) { /* Check and eliminate newlines */ 158 cp = &ptr[s - 1]; 159 160 if (*cp == nl) 161 s--; /* forget newline */ 162 } 163 164 if (s && con) { /* Check and eliminate continuations */ 165 cp = &ptr[s - 1]; 166 167 if (*cp == con && !isescaped(ptr, cp, esc)) { 168 s--; /* forget escape */ 169 cnt = 1; 170 } 171 } 172 173 if (s == 0 && buf != NULL) 174 continue; 175 176 if ((cp = realloc(buf, len + s + 1)) == NULL) { 177 FUNLOCKFILE(fp); 178 free(buf); 179 return NULL; 180 } 181 buf = cp; 182 183 (void) memcpy(buf + len, ptr, s); 184 len += s; 185 buf[len] = '\0'; 186 } 187 188 FUNLOCKFILE(fp); 189 190 if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && 191 strchr(buf, esc) != NULL) { 192 ptr = cp = buf; 193 while (cp[0] != '\0') { 194 int skipesc; 195 196 while (cp[0] != '\0' && cp[0] != esc) 197 *ptr++ = *cp++; 198 if (cp[0] == '\0' || cp[1] == '\0') 199 break; 200 201 skipesc = 0; 202 if (cp[1] == com) 203 skipesc += (flags & FPARSELN_UNESCCOMM); 204 if (cp[1] == con) 205 skipesc += (flags & FPARSELN_UNESCCONT); 206 if (cp[1] == esc) 207 skipesc += (flags & FPARSELN_UNESCESC); 208 if (cp[1] != com && cp[1] != con && cp[1] != esc) 209 skipesc = (flags & FPARSELN_UNESCREST); 210 211 if (skipesc) 212 cp++; 213 else 214 *ptr++ = *cp++; 215 *ptr++ = *cp++; 216 } 217 *ptr = '\0'; 218 len = strlen(buf); 219 } 220 221 if (size) 222 *size = len; 223 return buf; 224 } 225 226 #ifdef TEST 227 228 int main(int, char **); 229 230 int 231 main(int argc, char **argv) 232 { 233 char *ptr; 234 size_t size, line; 235 236 line = 0; 237 while ((ptr = fparseln(stdin, &size, &line, NULL, 238 FPARSELN_UNESCALL)) != NULL) 239 printf("line %d (%d) |%s|\n", line, size, ptr); 240 return 0; 241 } 242 243 /* 244 245 # This is a test 246 line 1 247 line 2 \ 248 line 3 # Comment 249 line 4 \# Not comment \\\\ 250 251 # And a comment \ 252 line 5 \\\ 253 line 6 254 255 */ 256 257 #endif /* TEST */ 258 #endif /* ! HAVE_FPARSELN */ 259