// // aegis - project change supervisor // Copyright (C) 1999, 2001-2006, 2008, 2011, 2012 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 #include output::~output() { // // Note: calling the flush() method here is pointless, because // the derived class has already been destroyed. // trace(("~output(this = %p)\n{\n", this)); callback(); assert(buffer); delete [] buffer; buffer = 0; trace(("}\n")); } output::output() : buffer(0), buffer_size(0), buffer_position(0), buffer_end(0) { trace(("output(this = %p)\n", this)); buffer_size = (size_t)1 << 13; buffer = new unsigned char [buffer_size]; buffer_position = buffer; buffer_end = buffer + buffer_size; } long output::ftell() const { trace(("output::ftell(this = %p)\n{\n", this)); trace(("typeid(*this).name() = \"%s\"\n", typeid(*this).name())); long result = ftell_inner() + (buffer_position - buffer); trace(("return %ld;\n", result)); trace(("}\n")); return result; } void output::overflow(char c) { trace(("output::overflow(this = %p, c = %d)\n{\n", this, c)); trace(("typeid(*this).name() = \"%s\"\n", typeid(*this).name())); assert(buffer); assert(buffer_position >= buffer); assert(buffer_end == buffer + buffer_size); assert(buffer_position <= buffer_end); if (buffer_position >= buffer_end) { size_t nbytes = buffer_position - buffer; write_inner(buffer, nbytes); buffer_position = buffer; } *buffer_position++ = c; trace(("}\n")); } void output::fputs(const char *s) { trace(("output::fputs(this = %p, s = \"%s\")\n{\n", this, s)); size_t nbytes = strlen(s); if (nbytes) write(s, nbytes); trace(("}\n")); } void output::fputs(string_ty *s) { if (!s || !s->str_length) return; write(s->str_text, s->str_length); } void output::fputs(const nstring &s) { if (!s.empty()) write(s.c_str(), s.length()); } void output::write(const void *data, size_t len) { trace(("output::write(this = %p, data = %p, len = %ld)\n{\n", this, data, (long)len)); trace(("typeid(*this).name() = \"%s\"\n", typeid(*this).name())); if (len) { if (buffer_position + len <= buffer_end) { memcpy(buffer_position, data, len); buffer_position += len; } else { size_t nbytes = buffer_position - buffer; if (nbytes) { write_inner(buffer, nbytes); buffer_position = buffer; } if (len < buffer_size) { memcpy(buffer, data, len); buffer_position += len; } else write_inner(data, len); } } trace(("}\n")); } void output::flush() { trace(("output::flush(this = %p)\n{\n", this)); trace(("typeid(*this).name() = \"%s\"\n", typeid(*this).name())); if (buffer_position > buffer) { size_t nbytes = buffer_position - buffer; write_inner(buffer, nbytes); buffer_position = buffer; } flush_inner(); trace(("}\n")); } void output::end_of_line() { // // If possible, just stuff a newline into the buffer and bail. // This results in the fewest deeper calls. // trace(("output::end_of_line(this = %p)\n{\n", this)); trace(("typeid(*this).name() = \"%s\"\n", typeid(*this).name())); if ( buffer_position > buffer && buffer_position[-1] != '\n' && buffer_position < buffer_end ) { *buffer_position++ = '\n'; trace(("}\n")); return; } // // If there is something in the buffer, we need to flush it, // so that the deeper eoln will have the current state. // if (buffer_position > buffer) { size_t nbytes = buffer_position - buffer; write_inner(buffer, nbytes); buffer_position = buffer; } // // Now ask the deeper class to do it's end of line thing. // end_of_line_inner(); trace(("}\n")); } void output_fprintf(output::pointer fp, const char *fmt, ...) { va_list ap; va_start(ap, fmt); fp->vfprintf(fmt, ap); va_end(ap); } void output::fprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(fmt, ap); va_end(ap); } void output::vfprintf(const char *fmt, va_list ap) { // // We have to make a temporary copy of it, in case a deeper output // stream also uses output::fprintf to satisfy the virtual // write_inner call via output::fputs. // // The moral is: avoid output::fprintf. // nstring tmp(nstring::vformat(fmt, ap)); fputs(tmp); } void output::register_delete_callback(functor::pointer fp) { callback.push_back(fp); } void output::unregister_delete_callback(functor::pointer fp) { callback.remove(fp); } int output::page_width() const { return page_width_get(-1) - 1; } int output::page_length() const { return page_length_get(-1); } void output::flush_inner() { // Do nothing. } // vim: set ts=8 sw=4 et :