// // aegis - project change supervisor // Copyright (C) 1991-1999, 2002-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 output_filter_indent::~output_filter_indent() { trace(("output_filter_indent::destructor()\n{\n")); // // Make sure all buffered data has been passed to our write_inner // method. // flush(); end_of_line_inner(); trace(("}\n")); } output_filter_indent::output_filter_indent(const output::pointer &a_deeper) : output_filter(a_deeper), depth(0), in_col(0), out_col(0), continuation_line(0), pos(0) { trace(("output_filter_indent::output_filter_indent(this = %p, " "deeper = %p)\n", this, a_deeper.get())); } output_filter_indent::ipointer output_filter_indent::create(const output::pointer &a_deeper) { return ipointer(new output_filter_indent(a_deeper)); } long output_filter_indent::ftell_inner(void) const { return pos; } // // Function Name: // indent_putchar // // Description: // The indent_putchar function is used to emity characters. // It keeps track of (){}[] pairs and indents between them. // Leading whitespace is suppressed and replaced with its own // idea of indenting. // // Preconditions: // none // // validation: // none // // Passed: // 'c' the character to emit. // void output_filter_indent::write_inner(const void *p, size_t len) { const unsigned char *data = (unsigned char *)p; while (len > 0) { unsigned char c = *data++; --len; ++pos; switch (c) { case '\n': deeper_fputc('\n'); in_col = 0; out_col = 0; if (continuation_line == 1) continuation_line = 2; else continuation_line = 0; break; case ' ': if (out_col) ++in_col; break; case '\t': if (out_col) in_col = (in_col / INDENT + 1) * INDENT; break; case '\1': if (!out_col) break; if (in_col >= INDENT * (depth + 2)) in_col++; else in_col = INDENT * (depth + 2); break; case '}': case ')': case ']': --depth; // fall through default: if (!out_col && c != '#' && continuation_line != 2) in_col += INDENT * depth; if (!out_col) { // // Only emit tabs into the output if we are at // the start of a line. // for (;;) { if (out_col + 1 >= in_col) break; int x = ((out_col / INDENT) + 1) * INDENT; if (x > in_col) break; deeper_fputc('\t'); out_col = x; } } while (out_col < in_col) { deeper_fputc(' '); ++out_col; } if (c == '{' || c == '(' || c == '[') ++depth; deeper_fputc(c); ++in_col; out_col = in_col; continuation_line = (c == '\\'); break; } } } void output_filter_indent::end_of_line_inner(void) { if (in_col) write_inner("\n", 1); } nstring output_filter_indent::type_name(void) const { return ("indent " + output_filter::type_name()); } void output_filter_indent::indent_more(void) { ++depth; } void output_filter_indent::indent_less(void) { if (depth > 0) --depth; } // vim: set ts=8 sw=4 et :