#include "HTMLstream.h"
#include <fstream>
#include <sstream>
#include <cctype>
#include <algorithm>
#include <stdexcept>
using namespace std;
#include "cgi.h"
HTMLstream::HTMLstream (const string & filename)
{
open (filename);
}
void HTMLstream::open (const string & filename)
{
ifstream html_file (filename.c_str());
if (!html_file)
{
throw invalid_argument
("Could not open data file: " + filename);
}
string line = "";
while (getline (html_file, line))
{
html_code += line;
html_code += '\n';
}
}
void HTMLstream::send (ostream & output) const
{
output << "Content-type: text/html\n\n\n";
output << html_code << flush;
}
void
HTMLstream::set_field (const string & field,
const string & content)
{
// position of last partial-tag found (for the loop)
int pos_end = 0;
string search_tag = "<a name=\"" + field + "\"></a>";
bool tag_found = false;
while (!tag_found)
{
// Find partial tag
int field_position =
html_code.find ("\"" + field + "\"", pos_end);
if (field_position == string::npos)
{
throw invalid_argument
("Target not found: `" + field + "'");
}
// find immediately preceding character <
// (opening the HTML tag)
int pos_start = html_code.rfind ('<', field_position);
if (pos_start == string::npos)
{
throw invalid_argument
("Target not found: `" + field + "'");
}
pos_end = html_code.find ('>', field_position);
// find the second ocurence of the character >
// (closing the /a tag)
pos_end = html_code.find ('>', pos_end + 1);
if (pos_end == string::npos)
{
throw invalid_argument
("Target not found: `" + field + "'");
}
string tag_in_html_code =
html_code.substr (pos_start, pos_end - pos_start + 1);
if (html_substrings_equal (tag_in_html_code, search_tag))
{
tag_found = true;
html_code.replace (pos_start,
tag_in_html_code.length(), content);
}
else
{
// so that next pass starts looking right after the
// field, not after the '>' character found somewhere
// after the field.
pos_end = field_position + field.length() + 2;
}
}
}
void
HTMLstream::add_option (const string & select_field,
const string & option)
{
int pos = tag_position ("select", select_field);
if (pos == tag_not_found)
{
throw invalid_argument
("Select field not found: `" + select_field + "'");
}
// Now look for the </select> matching tag
int pos_end = lcase(html_code).find ("</select>", pos);
if (pos_end == string::npos)
{
throw invalid_argument
("Select field `" + select_field +
"' misses matching </select> tag");
}
html_code.insert (pos_end, "<option> " + option + "\n");
}
void HTMLstream::remove_table_row (const string & table, int row)
{
int table_tag_pos = tag_position ("table", table);
if (table_tag_pos == tag_not_found)
{
throw invalid_argument
("Table not found: `" + table + "'");
}
// Now look for the closing tag (</table>)
size_t table_end_pos =
lcase(html_code).find ("</table>", table_tag_pos);
if (table_end_pos == string::npos)
{
throw invalid_argument
("Table `" + table + "' doesn't have closing tag");
}
size_t row_pos = table_tag_pos,
row_end_pos;
bool row_found = false;
while (!row_found && row_pos < table_end_pos)
{
row_pos = lcase(html_code).find ("<tr", row_pos + 1);
row_end_pos = lcase(html_code).find ("</tr>", row_pos);
if (row_end_pos == string::npos)
{
throw invalid_argument
("Table row doesn't have closing tag");
}
string row_content =
removed_separators
(lcase
(html_code.substr
(row_pos, row_end_pos - row_pos)));
ostringstream search_row_id;
search_row_id << "<aname=\"" << row;
if (row_content.find(search_row_id.str())!=string::npos)
{
row_found = true;
}
}
if (! row_found)
{
ostringstream error_msg;
error_msg << "Table row not found: table `"
<< table << "', row " << row;
throw invalid_argument (error_msg.str());
}
html_code.erase (row_pos, row_end_pos - row_pos + 5);
}
HTMLstream & HTMLstream::operator<< (const string & s)
{
html_code += s;
return *this;
}
void HTMLstream::save (const string & filename) const
{
ofstream file (filename.c_str());
if (!file)
{
throw runtime_error
("Error saving HTML file `" + filename + "'");
}
file << html_code;
}
bool
HTMLstream::html_substrings_equal (const string & s1,
const string & s2)
{
return lcase(removed_separators(s1)) ==
lcase(removed_separators(s2));
}
int
HTMLstream::tag_position (const string & tag,
const string & name) const
{
int pos_start = tag_not_found;
// position of last partial-tag found (for the loop)
int pos_end = 0;
string search_tag = "<" + tag + " name=\"" + name + "\"";
bool tag_found = false;
while (!tag_found)
{
// Find partial tag
int field_position =
lcase(html_code).find ("\"" + lcase(name) + "\"",
pos_end);
if (field_position == string::npos)
{
return tag_not_found;
}
// find immediately preceding character <
// (opening the HTML tag)
pos_start = html_code.rfind ('<', field_position);
if (pos_start == string::npos)
{
return tag_not_found;
}
pos_end = field_position + name.length() + 1;
string tag_in_html_code =
html_code.substr (pos_start,
pos_end - pos_start + 1);
if (html_substrings_equal (tag_in_html_code, search_tag))
{
tag_found = true;
}
else
{
// so that next pass starts looking right after
// the field, not after the '>' character found
// somewhere after the field.
pos_end++;
}
}
return pos_start;
}