#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
char uppercase(char c) {
if(c <= 'z' && c >= 'a') {
c -= 'a' - 'A';
}
return c;
}
void err(string s) {
cerr << s << endl;
exit(1);
}
bool eline(string tag) {
if(tag == "H1" || tag == "H2" || tag == "P" || tag == "HR") {
return true;
}
return false;
}
void horizline(std::ostream& o) {
//o << endl;
for(int i = 0; i<40; i++) {
o << "-";
}
//o << endl;
}
int main(int argc, char ** argv) {
if(argc < 3) {
err("bad number of parameters");
}
istream *in;
ostream *out;
in = new ifstream(argv[1]);
out = new ofstream(argv[2]);
vector<string> tagstack;
vector<char> ctag;
vector<char> cwsp;
bool tagtext = false;
bool wasspace = false;
bool wasnl = false;
bool intag = false;
char c;
while(in->get(c)) {
if(!intag) {
if(c == '<') { // start of tag - '<'
ctag.erase(ctag.begin(), ctag.end());
wasnl = false;
wasspace = true;
intag = true;
} else {
// write to output
if(!isspace(c)) {
if(tagstack.empty()) {
err("payload w/o tag");
}
if(tagstack.back() == "LI" && !tagtext) { // LI -> generate asterisks
int depth = 0;
for(auto it = tagstack.begin(); it != tagstack.end(); it++) {
if(*it == "UL") {
depth++;
}
}
int spaces = depth*4;
*out << endl;
for(int i = 0; i<spaces; i++) {
*out << ' ';
}
*out << "* ";
for(auto it = cwsp.begin(); it != cwsp.end(); it++) {
*out << *it;
}
cwsp.erase(cwsp.begin(), cwsp.end());
}
if(tagstack.back() == "H1") { // H1 -> to upper
*out << uppercase(c);
} else if (tagstack.back() == "H2") { // H2 -> first letter of word to upper
if(wasspace) {
*out << uppercase(c);
} else {
*out << c;
}
} else if(tagstack.back() == "HR") {
err("text in HR tag");
} else if(tagstack.back() == "UL") {
err("text in UL tag");
} else {
*out << c;
}
wasspace = false;
tagtext = true;
} else { // whitespaces
if(!tagstack.empty()) { // ignore whitespaces in free space
if(tagstack.back() != "HR" && tagstack.back() != "UL") {
char iot = 0;
if(c == '\n') { // newline
if(!wasnl) { // first newline - write one space to output
iot = ' ';
}
wasnl = true;
} else {
iot = c;
wasnl = false;
}
if(iot) {
if(tagstack.back() == "LI" && !tagtext) {
cwsp.push_back(iot);
} else {
*out << iot;
}
}
}
wasspace = true;
}
}
}
} else { // intag
if(c == '>') { // end of tag - '>'
intag = false;
// parse tag
if(ctag.size() < 1) {
err("empty tag");
}
if(ctag.at(0) == '/') { // closing tag
string tag(ctag.begin()+1, ctag.end());
if(tag.size() == 0) {
err("empty closing tag");
}
if(tagstack.empty()) {
err("closing tag with no tag open");
}
string last = tagstack.back();
if(last == tag) { // closing tag -- delete from tag stack
tagstack.pop_back();
} else {
err("closing tag that was not opened");
}
if(eline(tag)) {
*out << endl;
*out << endl;
}
} else { // opening tag
string tag(ctag.begin(), ctag.end());
// check allowed nesting
if(!tagstack.empty()) {
string last = tagstack.back();
//cout << "nest " << last << " " << tag << " " <<tagtext << endl;
// only ul can be in li
if( (last == "LI" && !tagtext) || (last == "UL" && tag == "LI")) {
// pass
} else {
err("bad tag nesting");
}
}
if(eline(tag)) {
*out << endl;
}
// special cases
if(tag == "HR") {
horizline(*out);
}
// push tag to stack
tagstack.push_back(tag);
// clean vector
ctag.erase(ctag.begin(), ctag.end());
}
tagtext = false;
} else { // push tag contents
ctag.push_back(uppercase(c));
}
}
// debug
if(argc > 3) {
cout<<c << " tagstack ";
for(auto it = tagstack.begin(); it != tagstack.end(); it++) {
cout<<*it << ".";
}
cout << endl;
}
}
*out << endl;
return 0;
}