//
// aegis - project change supervisor
// Copyright (C) 1999, 2002-2006, 2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
input_crlf::~input_crlf()
{
trace(("input_crlf::~input_crlf(this = %08lX)\n{\n", (long)this));
pullback_transfer(deeper);
deeper.close();
trace(("}\n"));
}
input_crlf::input_crlf(input &arg1, bool arg2) :
deeper(arg1),
pos(0),
line_number(0),
prev_was_newline(true),
newlines_may_be_escaped(arg2)
{
trace(("input_crlf::input_crlf(this = %08lX)\n{\n", (long)this));
trace(("}\n"));
}
long
input_crlf::read_inner(void *data, size_t len)
{
trace(("input_crlf::read_inner(this = %08lX)\n{\n", (long)this));
if (prev_was_newline)
{
++line_number;
prev_was_newline = false;
//
// The name cache includes the line number, and the line
// number just changed, so nuke it.
//
name_cache.clear();
}
unsigned char *cp = (unsigned char *)data;
unsigned char *end = cp + len;
while (cp < end)
{
int c = deeper->getch();
switch (c)
{
case '\r':
c = deeper->getch();
if (c == '\n')
goto newline;
if (c >= 0)
deeper->ungetc(c);
#ifdef __mac_os_x__
goto newline;
#else
*cp++ = '\r';
continue;
#endif
case '\\':
if (newlines_may_be_escaped)
{
c = deeper->getch();
if (c == '\n')
{
//
// Don't put the newline in the
// buffer, but DO stop here,
// so that the line numbers
// are right.
//
prev_was_newline = 1;
break;
}
if (c >= 0)
deeper->ungetc(c);
}
*cp++ = '\\';
continue;
case -1:
break;
case 0:
//
// For plain ASCII text, the conditions reads
//
// if (!isprint((unsigned char)c) &&
// !isspace((unsigned char)c))
//
// However, for international text, just about
// anything is acceptable. But not NUL.
//
{
sub_context_ty sc;
sc.var_set_format("Name", "\\%o", c);
string_ty *s = sc.subst_intl(i18n("illegal '$name' character"));
fatal_error(s->str_text);
}
continue;
default:
//
// The default should be enough, but these are
// to force the use of a lookup table instead of
// an if-then-else chain in the code generated for
// the switch.
//
case '!': case '"': case '#': case '$': case '%': case '&':
case '\'': case '(': case ')': case '*': case '+': case ',':
case '-': case '.': case '/': case '0': case '1': case '2':
case '3': case '4': case '5': case '6': case '7': case '8':
case '9': case ':': case ';': case '<': case '=': case '>':
case '?': case '@': case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V':
case 'W': case 'X': case 'Y': case 'Z': case '[': case ']':
case '^': case '_': case '`': case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f': case 'g': case 'h': case 'i':
case 'j': case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z': case '{':
case '|': case '}': case '~':
*cp++ = c;
continue;
case '\n':
//
// We are line buffered. This is the best way to
// allow us to report line numbers accurately.
// It results is some inefficiencies, but it also
// lets us get rid of a whole layer of function
// calls in the lexer.
//
newline:
*cp++ = '\n';
prev_was_newline = 1;
break;
}
break;
}
//
// Figure what happened.
//
size_t nbytes = (cp - (unsigned char *)data);
pos += nbytes;
trace(("return %ld;\n", (long)nbytes));
trace(("}\n"));
return nbytes;
}
long
input_crlf::ftell_inner()
{
trace(("input_crlf_ftell(this = %08lX) => %ld\n", (long)this, pos));
return pos;
}
nstring
input_crlf::name()
{
trace(("input_crlf_name(this = %08lX)\n", (long)this));
if (!line_number)
return deeper->name();
if (!name_cache)
{
name_cache =
nstring::format("%s: %ld", deeper->name().c_str(), line_number);
}
return name_cache;
}
long
input_crlf::length()
{
trace(("input_crlf_length(this = %08lX) => -1\n", (long)this));
return -1;
}
void
input_crlf::keepalive()
{
deeper->keepalive();
}
bool
input_crlf::is_remote()
const
{
return deeper->is_remote();
}