//
// 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";
}