//
// aegis - project change supervisor
// Copyright (C) 1999, 2003-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 // for assert
#include
#include
#include
input_ty::~input_ty()
{
trace(("input_ty::~input_ty(this = %08lX)\n{\n", (long)this));
assert(reference_count_valid());
reference_count = -666;
assert(buffer);
mem_free(buffer);
buffer = 0;
buffer_position = 0;
buffer_end = 0;
buffer_size = 0;
trace(("}\n"));
}
input_ty::input_ty() :
reference_count(1),
buffer(0),
buffer_size(0),
buffer_position(0),
buffer_end(0)
{
trace(("input_ty::input_ty(this = %08lX)\n{\n", (long)this));
buffer_size = (size_t)1 << 14;
buffer = (unsigned char *)mem_alloc(buffer_size);
buffer_position = buffer;
buffer_end = buffer;
trace(("}\n"));
}
void
input_ty::reference_count_up()
{
trace(("input_ty::reference_count_up(this = %08lX)\n{\n", (long)this));
assert(reference_count_valid());
reference_count++;
trace(("count = %ld after\n", reference_count));
trace(("}\n"));
}
void
input_ty::reference_count_down()
{
trace(("input_ty::reference_count_down(this = %08lX)\n{\n", (long)this));
trace(("count = %ld before\n", reference_count));
assert(reference_count_valid());
if (reference_count <= 1)
delete this;
else
reference_count--;
trace(("}\n"));
}
long
input_ty::read(void *data, size_t len)
{
//
// If they asked for nothing, give them nothing.
//
if (len <= 0)
return 0;
//
// If there is anything in the buffer, return the contents of
// the buffer.
//
if (buffer_position < buffer_end)
{
size_t nbytes = buffer_end - buffer_position;
if (nbytes > len)
nbytes = len;
memcpy(data, buffer_position, nbytes);
buffer_position += nbytes;
return nbytes;
}
//
// The buffer is empty. Read the data directly into the
// destination. There is no profit in double handling.
//
return read_inner(data, len);
}
int
input_ty::getc_complicated()
{
//
// If there is anything in the buffer, return the first byte of the
// buffer. This should never happen, because the inline getch method
// is supposed to make it go away.
//
if (buffer_position < buffer_end)
{
assert(0);
return *buffer_position++;
}
//
// Fill the buffer with data, and then return the first byte of
// the new buffer.
//
long nbytes = read_inner(buffer, buffer_size);
if (nbytes <= 0)
return (-1);
buffer_position = buffer;
buffer_end = buffer + nbytes;
return *buffer_position++;
}
void
input_ty::ungetc_complicated(int c)
{
if (c < 0)
{
//
// Toss the end-of-file indicator.
//
return;
}
if (buffer_position > buffer)
{
//
// If there is room in the buffer, back up and put the character
// in the buffer. The inline ungetc method is supposed to have
// taken care of this already.
//
assert(0);
}
else if (buffer_position >= buffer_end)
{
//
// If the buffer is empty, just mangle the pointers to make it
// possible to push the character back.
//
buffer_end = buffer + buffer_size;
buffer_position = buffer_end;
}
else
{
//
// Double the size of the buffer, moving the current
// data into the second half. That way, there will
// always be enough room for the old data and always
// enough room for the character to be pushed back.
//
// By doubling the buffer size every time (and halving the
// probability we will need to grow again) it is still O(1)
// overall.
//
buffer_size *= 2;
unsigned char *tmp = (unsigned char *)mem_alloc(buffer_size);
size_t nbytes = buffer_end - buffer_position;
memcpy(tmp + buffer_size - nbytes, buffer_position, nbytes);
mem_free(buffer);
buffer = tmp;
buffer_end = buffer + buffer_size;
buffer_position = buffer_end - nbytes;
}
//
// The character goes before the current pointer,
// and the current pointer is moved back by one.
//
*--buffer_position = c;
}
void
input_ty::unread(const void *data, size_t len)
{
if (buffer_position >= buffer_end)
{
//
// If the buffer is empty, just mangle the pointers to
// make it possible to push the characters back.
//
buffer_end = buffer + buffer_size;
buffer_position = buffer_end - len;
memcpy(buffer_position, data, len);
return;
}
//
// Make the buffer large enough to hold the pushback.
//
while (buffer_position - len < buffer)
{
//
// Double the size of the buffer, moving the current
// data into the second half. That way, there will
// always be enough room for the old data and always
// enough room for the character to be pushed back.
//
// By doubling the buffer size every time (and halving the
// probability we will need to grow again) it is still O(1)
// overall.
//
buffer_size *= 2;
unsigned char *tmp = (unsigned char *)mem_alloc(buffer_size);
size_t nbytes = buffer_end - buffer_position;
memcpy(tmp + buffer_size - nbytes, buffer_position, nbytes);
mem_free(buffer);
buffer = tmp;
buffer_end = buffer + buffer_size;
buffer_position = buffer_end - nbytes;
}
//
// Copy the data into the buffer, before the current position.
//
buffer_position -= len;
memcpy(buffer_position, data, len);
}
long
input_ty::ftell()
{
//
// The underlying file is going to thinks we are further along
// than we do, because of the read-ahead we did to fill the
// buffer.
//
// To correct for this, we subtract what's left in the buffer
// from where the underlying file thinks we are.
//
return ftell_inner() + buffer_position - buffer_end;
}
void
input_ty::keepalive()
{
}
bool
input_ty::at_end()
{
return (peek() < 0);
}
bool
input_ty::is_remote()
const
{
return false;
}