// // aegis - project change supervisor // Copyright (C) 1999-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 #include #include #include #include #include #include #include wide_output_unexpand::~wide_output_unexpand() { flush(); } wide_output_unexpand::wide_output_unexpand(const wide_output::pointer &a_deeper, int a_tab_width) : deeper(a_deeper), icol(0), ocol(0), tab_width(a_tab_width > 0 ? a_tab_width : option_tab_width_get()) { } wide_output::pointer wide_output_unexpand::open(const wide_output::pointer &a_deeper, int a_tabwidth) { return pointer(new wide_output_unexpand(a_deeper, a_tabwidth)); } nstring wide_output_unexpand::filename() { return deeper->filename(); } void wide_output_unexpand::write_inner(const wchar_t *data, size_t len) { // // Put all of the output into a stash, rather then direct calls // to deeper->put_wc(). This allows us to minimize // the number of language_C() and language_human() calls, which // tend to be slow-ish // wstring_accumulator stash; trace(("wide_output_unexpand::write_inner(this = %08lX, data = %08lX, " "len = %ld)\n{\n", (long)this, (long)data, (long)len)); language_human(); while (len > 0) { if (stash.size() > 2000) { language_C(); deeper->write(stash.get_data(), stash.size()); stash.clear(); language_human(); } wchar_t wc = *data++; --len; switch (wc) { case L'\n': case L'\f': stash.push_back(wc); icol = 0; ocol = 0; break; case L'\t': // internal tabs are 8 characters wide icol = (icol + 8) & ~7; break; case (wchar_t)0: case L' ': icol++; break; default: trace(("icol = %d\n", icol)); if (tab_width >= 2) { trace(("tab_width = %d\n", tab_width)); for (;;) { trace(("ocol = %d\n", ocol)); if (ocol + 1 >= icol) break; int ncol = ((ocol / tab_width) + 1) * tab_width; trace(("ncol = %d\n", ncol)); if (ncol > icol) break; stash.push_back(L'\t'); ocol = ncol; } } while (ocol < icol) { trace(("ocol = %d\n", ocol)); stash.push_back(L' '); ocol++; } trace(("ocol = %d\n", ocol)); icol += wcwidth(wc); stash.push_back(wc); trace(("icol = %d\n", icol)); ocol = icol; break; } } language_C(); if (!stash.empty()) { deeper->write(stash.get_data(), stash.size()); } trace(("}\n")); } void wide_output_unexpand::flush_inner() { deeper->flush(); } int wide_output_unexpand::page_width() { return deeper->page_width(); } int wide_output_unexpand::page_length() { return deeper->page_length(); } void wide_output_unexpand::end_of_line_inner() { trace(("wide_output_unexpand::end_of_line_inner(this = %08lX)\n{\n", (long)this)); if (icol > 0) put_wc(L'\n'); trace(("}\n")); } const char * wide_output_unexpand::type_name() const { return "wide_output_unexpand"; }