// // aegis - project change supervisor // Copyright (C) 1999, 2003-2006, 2008, 2012, 2014 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 #include #include #include input::~input() { trace(("input::~input(this = %p)\n{\n", this)); assert(buffer); delete [] buffer; buffer = 0; buffer_position = 0; buffer_end = 0; buffer_size = 0; trace(("}\n")); } input::input() : buffer(0), buffer_size(0), buffer_position(0), buffer_end(0) { trace(("input::input(this = %p)\n{\n", this)); buffer_size = (size_t)1 << 14; buffer = new unsigned char [buffer_size]; buffer_position = buffer; buffer_end = buffer; trace(("}\n")); } #if 0 input::input(const input &rhs) : buffer(0), buffer_size(0), buffer_position(0), buffer_end(0) { unread(buffer_position, rhs.buffer_end - rhs.buffer_position); } #endif ssize_t input::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::getc_complicated(void) { // // 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. // ssize_t nbytes = read_inner(buffer, buffer_size); if (nbytes <= 0) return (-1); buffer_position = buffer; buffer_end = buffer + nbytes; return *buffer_position++; } void input::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 = new unsigned char [buffer_size]; size_t nbytes = buffer_end - buffer_position; memcpy(tmp + buffer_size - nbytes, buffer_position, nbytes); delete [] 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::unread(const void *data, size_t len) { if (len == 0) return; 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 = new unsigned char [buffer_size]; size_t nbytes = buffer_end - buffer_position; memcpy(tmp + buffer_size - nbytes, buffer_position, nbytes); delete [] 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); } off_t input::ftell(void) { // // 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::keepalive(void) { } bool input::at_end(void) { return (peek() < 0); } bool input::is_remote(void) const { return false; } #if 0 input & input::operator=(const input &rhs) { input(rhs).swap(*this); return *this; } #endif // vim: set ts=8 sw=4 et :