/*-
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by David A. Holland.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Find the end of the logical line. End of line characters that are
* commented out do not count.
*/
static
size_t
findeol(const char *buf, size_t start, size_t limit)
{
size_t i;
int incomment = 0;
bool inquote = false;
char quote = '\0';
for (i=start; i<limit; i++) {
if (buf[i] == '\n') {
count++;
if (count == 0) {
/* just return the max and error downstream */
return count - 1;
}
}
}
return count;
}
while (1) {
if (lineend >= bufend) {
/* do not have a whole line in the buffer; read more */
assert(bufend >= linestart);
if (linestart > 0 && bufend > linestart) {
/* slide to beginning of buffer */
memmove(buf, buf+linestart, bufend-linestart);
bufend -= linestart;
lineend -= linestart;
linestart = 0;
}
if (bufend >= bufmax) {
/* need bigger buffer */
buf = dorealloc(buf, bufmax, bufmax*2);
bufmax = bufmax*2;
/* just in case someone's screwing around */
if (bufmax > 0xffffffff) {
complain(&places.current,
"Input line too long");
die();
}
}
if (ateof) {
/* don't read again, in case it's a socket */
result = 0;
} else {
result = read(fd, buf+bufend, bufmax - bufend);
}
if (result == -1) {
/* read error */
complain(NULL, "%s: %s",
name, strerror(errno));
complain_fail();
} else if (result == 0 && bufend == linestart) {
/* eof */
ateof = true;
break;
} else if (result == 0) {
/* eof in middle of line */
ateof = true;
ptmp = places.current;
place_addcolumns(&ptmp, bufend - linestart);
if (buf[bufend - 1] == '\n') {
complain(&ptmp, "Unclosed comment");
complain_fail();
} else {
complain(&ptmp,
"No newline at end of file");
}
if (mode.werror) {
complain_fail();
}
assert(bufend < bufmax);
lineend = bufend++;
buf[lineend] = '\n';
} else {
bufend += (size_t)result;
lineend = findeol(buf, linestart, bufend);
}
/* loop in case we still don't have a whole line */
continue;
}
/* have a line */
assert(buf[lineend] == '\n');
buf[lineend] = '\0';
nextlinestart = lineend+1;
place_addlines(&places.nextline, 1);
/* check for CR/NL */
if (lineend > 0 && buf[lineend-1] == '\r') {
buf[lineend-1] = '\0';
lineend--;
}
/* check for continuation line */
if (lineend > 0 && buf[lineend-1]=='\\') {
lineend--;
tmp = nextlinestart - lineend;
if (bufend > nextlinestart) {
memmove(buf+lineend, buf+nextlinestart,
bufend - nextlinestart);
}
bufend -= tmp;
nextlinestart -= tmp;
lineend = findeol(buf, linestart, bufend);
/* might not have a whole line, so loop */
continue;
}
/* line now goes from linestart to lineend */
assert(buf[lineend] == '\0');
/* count how many commented-out newlines we swallowed */
place_addlines(&places.nextline,
countnls(buf, linestart, lineend));
/* process the line (even if it's empty) */
directive_gotline(&places, buf+linestart, lineend-linestart);