/* * This file is part of the Advance project. * * Copyright (C) 2001, 2002, 2003, 2004, 2005 Andrea Mazzoleni * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include using namespace std; //--------------------------------------------------------------------------- // string string fill(unsigned l, char c) { string r; for(unsigned i=0;i 0 && isspace(r[0])) r.erase(0, 1); return r; } string trim_right(const string& s) { string r = s; while (r.length() > 0 && isspace(r[r.length()-1])) r.erase(r.length()-1, 1); return r; } string trim(const string& s) { return trim_left(trim_right(s)); } string up(const string& s) { string r; for(unsigned i=0;i 0 && s[0] == ':') { a = s.substr(1); return true; } return false; } bool convert::is_line(const string& s, string& a) { if (s.length() > 0 && s[0] == '+') { a = s.substr(1); return true; } return false; } bool convert::is_dot(const string& s, string& a) { if (s.length() > 0 && (s[0] == '*' || s[0]==')') && s[1] == ' ') { a = s.substr(2); return true; } return false; } bool convert::is_option(const string& s, string& a) { string r = trim(s); if (r.length() > 0 && (r[0] == '-' || r[0] =='/')) { a = s; return true; } if (r.length() > 0 && (r[0]=='=')) { a = s.substr(1); return true; } return false; } bool convert::is_tag(const string& s, string& a, string& b, bool root_tag) { if (s.length() > 0 && (s[0] == ':' || s[0] == '+')) return false; unsigned d = s.find(" - "); if (d == string::npos) return false; a = trim(s.substr(0, d)); b = trim(s.substr(d+3)); if (root_tag && a.find(' ') != string::npos) return false; return true; } void convert::next(unsigned level, unsigned& Alevel0, unsigned& Alevel1, unsigned& Alevel2) { if (level == 0) { ++Alevel0; Alevel1 = 0; Alevel2 = 0; } else if (level == 1) { ++Alevel1; Alevel2 = 0; } else { ++Alevel2; } } void convert::index_begin() { } void convert::index_end() { } void convert::index_text(unsigned level, unsigned index0, unsigned index1, unsigned index2, const string& s) { } void convert::step(const string& r) { string s = trim_right(r); // count left space unsigned nt = 0; while (nt < s.length() && s[nt] == '\t') ++nt; s.erase(0, nt); unsigned ns = 0; while (ns < s.length() && s[ns] == ' ') ++ns; s.erase(0, ns); ns += nt*8; // continue with separator support if (s.length() == 0 && (state == state_tag0 || state == state_tag1)) { request_separator = true; return; } if ((ns == 16 && state == state_tag0) || (ns == 24 && state == state_tag1)) { if (request_separator) { request_separator = false; sep(); } string a; if (is_line(s, a)) { tag_text(a); line(); } else { tag_text(s); } return; } if (request_separator) { tag_stop(); tag_end(); request_separator = false; state = state_separator; } // continue without separator support if (s.length() > 0) { if (ns == 16 && state == state_option) { option_text(s); return; } if ((ns == 16 && state == state_dot0) || (ns == 24 && state == state_dot1)) { dot_text(s); return; } if ((ns == 0 && state == state_section0) || (ns == 2 && state == state_section1) || (ns == 4 && state == state_section2)) { section_text(s); return; } if ((ns == 8 && state == state_para0) || (ns == 16 && state == state_para1)) { string a; if (is_line(s, a)) { para_text(a); line(); } else { para_text(s); } return; } } // end if (state == state_section0 || state == state_section1 || state == state_section2) { section_end(); } if (state == state_para0 || state == state_para1) { para_end(); } // start if (ns == 8 || ns == 16) { string a, b; if (is_tag(s, a, b, ns == 8)) { state_t state_new = ns == 8 ? state_tag0 : state_tag1; if (state != state_new) { tag_begin(ns == 16); } else { tag_stop(); } state = state_new; string c; if (is_line(b, c)) { tag_start(a, c); line(); } else { tag_start(a, b); } return; } } if (state == state_tag0 || state == state_tag1) { tag_stop(); tag_end(); } if (ns == 8) { string a; if (is_option(s, a) && state != state_para0) { if (state != state_option) { option_begin(); } else { option_stop(); } state = state_option; option_start(a); return; } } if (state == state_option) { option_stop(); option_end(); } if (ns == 8 || ns == 16) { string a; if (is_dot(s, a)) { state_t state_new = ns == 8 ? state_dot0 : state_dot1; if (state != state_new) { dot_begin(ns == 16); } else { dot_stop(); } state = state_new; dot_start(a); return; } } if (state == state_dot0 || state == state_dot1) { dot_stop(); dot_end(); } if (ns == 8 || ns == 16) { string a; if (is_pre(s, a)) { state_t state_new = ns == 8 ? state_pre0 : state_pre1; if (state != state_new) pre_begin(ns == 16); state = state_new; pre_text(a); return; } } if (state == state_pre0 || state == state_pre1) { pre_end(); } if (s.length()>0 && (ns == 0 || ns == 2 || ns == 4)) { state_t state_new = ns == 0 ? state_section0 : (ns == 2 ? state_section1 : state_section2); if (state != state_new) { next(ns / 2, level0, level1, level2); section_begin(ns / 2); } state = state_new; section_text(s); return; } if (s.length()>0 && (ns == 8 || ns == 16)) { state_t state_new = ns == 8 ? state_para0 : state_para1; if (state != state_new) para_begin(ns == 16); state = state_new; string a; if (is_line(s, a)) { para_text(a); line(); } else { para_text(s); } return; } if (s.length() == 0) { state = state_separator; return; } cerr << "warning: unrecognized (" << ns << ") `" << s << "'" << endl; state = state_filled; return; } unsigned convert::index_level(const string& s) { if (isalnum(s[0])) { return 0; } else if (s[0] == ' ' && s[1] == ' ' && isalnum(s[2])) { return 1; } else if (s[0] == ' ' && s[1] == ' ' && s[2] == ' ' && s[3] == ' ' && isalnum(s[4])) { return 2; } else { return 3; } } void convert::index_all(const string& file, unsigned depth) { string s; unsigned index0 = 0; unsigned index1 = 0; unsigned index2 = 0; int j = 0; index_begin(); while (j < file.length()) { string u; s = token(j, file); u = up(s); if (u != "NAME" && u != "NAME{NUMBER}" && u != "INDEX" && u != "SUBINDEX" && u != "SUBSUBINDEX") { unsigned level = index_level(s); if (depth >= level) { next(level, index0, index1, index2); string t = trim(s); while (j < file.length()) { int jj = j; s = token(j, file); if (index_level(s) != level) { j = jj; break; } t += " "; t += trim(s); } index_text(level, index0, index1, index2, t); } } } index_end(); } void convert::run() { int i; string file; string s; // read the whole file getline(is, file, static_cast(EOF)); state = state_filled; request_separator = false; i = 0; s = token(i, file); if (up(s) == "NAME" || up(s) == "NAME{NUMBER}") { numbered = up(s) == "NAME{NUMBER}"; s = token(i, file); unsigned d = s.find(" - "); header(trim(s.substr(0, d)), trim(s.substr(d+3))); } else { header("", ""); i = 0; } level0 = 0; level1 = 0; level2 = 0; while (i < file.length()) { string u; s = token(i, file); u = up(s); if (u == "INDEX") { index_all(file, 0); } else if (u == "SUBINDEX") { index_all(file, 1); } else if (u == "SUBSUBINDEX") { index_all(file, 2); } else { step(s); } } // end if (state == state_section0 || state == state_section1 || state == state_section2) { section_end(); } if (state == state_para0 || state == state_para1) { para_end(); } if (state == state_tag0 || state == state_tag1) { tag_stop(); tag_end(); } if (state == state_option) { option_stop(); option_end(); } if (state == state_dot0 || state == state_dot1) { dot_stop(); dot_end(); } if (state == state_pre0 || state == state_pre1) { pre_end(); } footer(); } //--------------------------------------------------------------------------- // convert_man class convert_man : public convert { bool para_indent; string mask(string s); public: convert_man(istream& Ais, ostream& Aos) : convert(Ais, Aos) { }; virtual void header(const string& a, const string& b); virtual void footer(); virtual void sep(); virtual void line(); virtual void section_begin(unsigned level); virtual void section_end(); virtual void section_text(const string& s); virtual void para_begin(unsigned level); virtual void para_end(); virtual void para_text(const string& s); virtual void pre_begin(unsigned level); virtual void pre_end(); virtual void pre_text(const string& s); virtual void dot_begin(unsigned level); virtual void dot_end(); virtual void dot_start(const string& s); virtual void dot_stop(); virtual void dot_text(const string& s); virtual void option_begin(); virtual void option_end(); virtual void option_start(const string& s); virtual void option_stop(); virtual void option_text(const string& s); virtual void tag_begin(unsigned level); virtual void tag_end(); virtual void tag_start(const string& a, const string& b); virtual void tag_stop(); virtual void tag_text(const string& s); }; string convert_man::mask(string s) { string r; for(unsigned i=0;i' : r += ">"; break; case '\t' : r += "    "; break; case '&' : r += "&"; break; default: r += s[i]; break; } } return r; } string convert_html::link(string s) { int i = s.find("http://"); if (i == string::npos) { i = s.find("ftp://"); } if (i == string::npos) { i = s.find("file://"); } if (i == string::npos) { return s; } int begin = i; int end = i; while (end0 && (s[end-1] == '.' || s[end-1] == ',' || s[end-1] == ':' || s[end-1] == ';' || s[end-1] == '>' || s[end-1] == ')')) --end; string address = s.substr(begin, end - begin); s.erase(begin, end - begin); string l = "" + address + ""; s.insert(begin, l); return s; } void convert_html::header(const string& a, const string& b) { os << "" << endl; os << "" << endl; os << "" << mask(b) << "" << endl; os << "" << endl; os << "" << endl; if (b.length()) { os << "
<" HTML_H1 ">" << mask(b) << "
" << endl; } } void convert_html::footer() { os << "" << endl; os << "" << endl; } void convert_html::index_begin() { os << "

The sections of this document are:

\n"; os << "\n"; } void convert_html::index_end() { os << "
\n"; } void convert_html::index_text(unsigned level, unsigned index0, unsigned index1, unsigned index2, const string& s) { if (level == 0) { os << "\n"; os << ""; os << index0; os << " " << s << "
\n"; os << "\n"; } else if (level == 1) { if (index0) { os << "\n"; os << ""; os << index0 << "." << index1; os << " " << s << "
\n"; os << "\n"; } } else if (level == 2) { if (index0 && index1) { os << "\n"; os << ""; os << index0 << "." << index1 << "." << index2; os << " " << s << "
\n"; os << "\n"; } } } void convert_html::section_begin(unsigned level) { if (level == 0) { os << "<" HTML_H1 ">"; if (numbered) { os << ""; os << level0; os << ""; } os << " " << endl; } else if (level == 1) { if (level0) { os << "<" HTML_H2 ">"; if (numbered) { os << ""; os << level0 << "." << level1; os << ""; } os << " " << endl; } else { os << "<" HTML_H2 ">" << endl; } } else { if (level0 && level1) { os << "<" HTML_H3 ">"; if (numbered) { os << ""; os << level0 << "." << level1 << "." << level2; os << ""; } os << " " << endl; } else { os << "<" HTML_H3 ">" << endl; } } } void convert_html::section_end() { if (state == state_section0) os << "" << endl; else if (state == state_section1) os << "" << endl; else os << "" << endl; state = state_filled; } void convert_html::section_text(const string& s) { os << link(mask(s)) << endl; } void convert_html::para_begin(unsigned level) { if (state == state_separator) sep(); if (level) { os << ""; os << "
" << endl; } } void convert_html::para_end() { if (state == state_para1) { os << "
" << endl; } state = state_filled; } void convert_html::para_text(const string& s) { os << link(mask(s)) << endl; } void convert_html::pre_begin(unsigned level) { if (state == state_separator) sep(); if (level) { os << ""; os << "
" << endl; } #if 0 os << "" << endl; #else os << "
" << endl;
#endif
}

void convert_html::pre_end()
{
#if 0
	os << "" << endl;
#else
	os << "
" << endl; #endif if (state == state_pre1) { os << "
" << endl; } state = state_filled; } void convert_html::pre_text(const string& s) { os << link(mask(s)); #if 0 os << "
"; #endif os << "\n"; } void convert_html::sep() { os << "

" << endl; } void convert_html::line() { os << "
" << endl; } void convert_html::dot_begin(unsigned level) { os << "

    " << endl; } void convert_html::dot_end() { os << "
" << endl; state = state_filled; } void convert_html::dot_start(const string& s) { os << "
  • " << endl; os << mask(s) << endl; } void convert_html::dot_stop() { os << "
  • " << endl; } void convert_html::dot_text(const string& s) { os << link(mask(s)) << endl; } void convert_html::option_begin() { os << "" << endl; } void convert_html::option_end() { os << "
    " << endl; state = state_filled; } void convert_html::option_start(const string& s) { os << "" << endl; os << mask(s) << endl; os << "" << endl; } void convert_html::option_stop() { os << "" << endl; } void convert_html::option_text(const string& s) { os << link(mask(s)) << endl; } void convert_html::tag_begin(unsigned level) { os << "" << endl; } void convert_html::tag_end() { os << "
    " << endl; state = state_separator; } void convert_html::tag_start(const string& a, const string& b) { os << "" << endl; os << mask(a) << endl; os << "" << endl; os << mask(b) << endl; } void convert_html::tag_stop() { os << "" << endl; } void convert_html::tag_text(const string& s) { os << link(mask(s)) << endl; } //--------------------------------------------------------------------------- // convert_frame class convert_frame : public convert_html { public: convert_frame(istream& Ais, ostream& Aos) : convert_html(Ais, Aos) { }; virtual void header(const string& a, const string& b); virtual void footer(); }; void convert_frame::header(const string& a, const string& b) { if (b.length()) { os << "
    <" HTML_H1 ">" << mask(b) << "
    " << endl; } } void convert_frame::footer() { } //--------------------------------------------------------------------------- // convert_txt class convert_txt : public convert { bool first_line; unsigned max_length; string mask(string s); public: convert_txt(istream& Ais, ostream& Aos) : convert(Ais, Aos) { }; virtual void header(const string& a, const string& b); virtual void footer(); virtual void sep(); virtual void line(); virtual void section_begin(unsigned level); virtual void section_end(); virtual void section_text(const string& s); virtual void para_begin(unsigned level); virtual void para_end(); virtual void para_text(const string& s); virtual void pre_begin(unsigned level); virtual void pre_end(); virtual void pre_text(const string& s); virtual void dot_begin(unsigned level); virtual void dot_end(); virtual void dot_start(const string& s); virtual void dot_stop(); virtual void dot_text(const string& s); virtual void option_begin(); virtual void option_end(); virtual void option_start(const string& s); virtual void option_stop(); virtual void option_text(const string& s); virtual void tag_begin(unsigned level); virtual void tag_end(); virtual void tag_start(const string& a, const string& b); virtual void tag_stop(); virtual void tag_text(const string& s); }; #define MI "" // begin #define I " " // tag string convert_txt::mask(string s) { return s; } void convert_txt::header(const string& a, const string& b) { if (b.length()) { unsigned space = (80 - b.length()) / 2; os << fill(space, ' ') << fill(b.length(), '=') << endl; os << fill(space, ' ') << b << endl; os << fill(space, ' ') << fill(b.length(), '=') << endl; } } void convert_txt::footer() { } void convert_txt::section_begin(unsigned level) { if (level == 0) os << endl; if (state == state_separator) os << endl; first_line = true; max_length = 0; } void convert_txt::section_end() { if (state == state_section0) { os << fill(max_length, '=') << endl; os << endl; } else if (state == state_section1) { os << fill(max_length, '-') << endl; os << endl; } else { } state = state_filled; } void convert_txt::section_text(const string& s) { ostringstream ss; if (first_line) { if (state == state_section0) { if (numbered) ss << level0 << " "; ss << up(mask(s)); } else if (state == state_section1) { if (numbered) ss << level0 << "." << level1 << " "; ss << mask(s); } else { ss << "---- "; if (numbered) ss << level0 << "." << level1 << "." << level2 << " "; ss << mask(s) << " ----"; } first_line = false; } else { if (state == state_section0) { ss << up(mask(s)); } else if (state == state_section1) { ss << mask(s); } else { ss << "---- " << mask(s) << " ----"; } } if (ss.str().length() > max_length) max_length = ss.str().length(); os << ss.str() << endl; } void convert_txt::para_begin(unsigned level) { if (state == state_separator) sep(); } void convert_txt::para_end() { state = state_filled; } void convert_txt::para_text(const string& s) { os << MI; if (state == state_para1) os << I; os << mask(s) << endl; } void convert_txt::pre_begin(unsigned level) { if (state == state_separator) sep(); } void convert_txt::pre_end() { state = state_filled; } void convert_txt::pre_text(const string& s) { os << MI; if (state == state_pre1) os << I; os << mask(s) << endl; } void convert_txt::sep() { os << endl; } void convert_txt::line() { } void convert_txt::dot_begin(unsigned level) { if (state == state_separator) sep(); } void convert_txt::dot_end() { state = state_filled; } void convert_txt::dot_start(const string& s) { os << MI; if (state == state_dot1) os << I ; os << "* " << mask(s) << endl; } void convert_txt::dot_stop() { } void convert_txt::dot_text(const string& s) { os << MI; if (state == state_dot1) os << I; os << " " << mask(s) << endl; } void convert_txt::option_begin() { if (state == state_separator) sep(); } void convert_txt::option_end() { state = state_filled; } void convert_txt::option_start(const string& s) { os << MI; os << I << mask(s) << endl; } void convert_txt::option_stop() { } void convert_txt::option_text(const string& s) { os << MI; os << I I << mask(s) << endl; } void convert_txt::tag_begin(unsigned level) { if (state == state_separator) sep(); } void convert_txt::tag_end() { state = state_filled; } void convert_txt::tag_start(const string& a, const string& b) { os << MI; if (state == state_tag1) os << I; os << mask(a) << " - " << mask(b) << endl; } void convert_txt::tag_stop() { } void convert_txt::tag_text(const string& s) { os << MI; if (state == state_tag1) os << I ; os << I << mask(s) << endl; } //--------------------------------------------------------------------------- // main int main(int argc, char* argv[]) { if (argc != 2) { cerr << "Syntax: txt2 man | html | frame | txt" << endl; exit(EXIT_FAILURE); } convert* c; string arg = argv[1]; if (arg == "html") c = new convert_html(cin, cout); else if (arg == "frame") c = new convert_frame(cin, cout); else if (arg == "man") c = new convert_man(cin, cout); else if (arg == "txt") c = new convert_txt(cin, cout); else { cerr << "Unknown format `" << arg << "'" << endl; exit(EXIT_FAILURE); } c->run(); delete c; return EXIT_SUCCESS; }