// Feeping Creaturism // // Douglas Thrift // // $Id$ #include "Environment.hpp" #include "Matcher.hpp" #include "Jargon.hpp" extern "C" { #include #include #include } int main(int argc, char* argv[]) { FeepingCreaturism::program = argv[0]; FeepingCreaturism creaturism; return 0; } FeepingCreaturism::FeepingCreaturism() { initialize(); parse(); ext::String path(env.get("PATH_INFO")); Matcher matcher; if (path == matcher("^/daily/(\\d{4}-\\d{2}-\\d{2})?$")) { daily(matcher.size() > 1 ? matcher[1] : ""); } else if (path == matcher("^/random/(\\d+)?$")) { random(matcher.size() > 1 ? matcher[1] : ""); } else if (path == matcher("^/(" + this->matcher + ")$")) { select(matcher[1], true); } else { api::Cout << "Location: http://" << env.get("HTTP_HOST") << env.get("SCRIPT_NAME") << "/daily/\r\n\r\n"; } } ext::String FeepingCreaturism::program; bool FeepingCreaturism::CaseLess::operator()(const std::string& one, const std::string& two) { std::string one_(one), two_(two); // XXX: should be std::tolower except g++34 doesn't believe it std::transform(one.begin(), one.end(), one_.begin(), ::tolower); std::transform(two.begin(), two.end(), two_.begin(), ::tolower); return one_ < two_; } void FeepingCreaturism::initialize() { ext::Handle document(xml::Parse("jargon.xml")); ext::Handle node(*document/"feepingcreaturism"); this->path = *node/"jargon"; this->matcher = *node/"matcher"; char* path[] = { new char[this->path.GetData().GetSize()] }; std::strcpy(path[0], this->path.NullTerminate()); ::FTS* traversal(::fts_open(path, FTS_LOGICAL, NULL)); Matcher matcher("^" + this->path + "/(" + this->matcher + ")$"); if (traversal == NULL) { api::Cerr << program << ": Horrible Failure!\n"; std::exit(1); } for (::FTSENT* entity(::fts_read(traversal)); entity != NULL; entity = ::fts_read(traversal)) { if (entity->fts_info == FTS_F && entity->fts_path == matcher) { jargon.insert(matcher[1]); } } ::fts_close(traversal); delete [] path[0]; } void FeepingCreaturism::parse() { std::stringstream query(env.get("QUERY_STRING")); if (env.get("REQUEST_METHOD") == "POST") { std::streamsize length(lexical_cast(env.get("CONTENT_" "TYPE"))); char* content(new char[length]); api::Cin.Read(content, length); query.write(content, length); delete [] content; } if (query.str().empty()) return; do { std::string name, value; std::getline(query, name, '='); std::getline(query, value, '&'); cgi.insert(_P(name, value)); } while (query.good()); } void FeepingCreaturism::daily(const ext::String& date) { std::time_t when(std::time(NULL)); std::tm* day(std::localtime(&when)); day->tm_sec = 0; day->tm_min = 0; day->tm_hour = 0; if (!date.IsEmpty()) ::strptime(date.NullTerminate(), "%Y-%m-%d", day); std::time_t difference(mktime(day) / 86400); std::vector jargon(this->jargon.begin(), this->jargon.end()); ext::String entry(jargon.size() ? jargon[difference % jargon.size()] : ""); select(entry); } void FeepingCreaturism::random(const ext::String& number) { ::srandomdev(); std::vector jargon(this->jargon.begin(), this->jargon.end()); std::vector::size_type random(number.IsEmpty() ? ::random() : lexical_cast::size_type>(number)); assert(random >= 0); assert(random % jargon.size() < jargon.size()); ext::String entry(jargon.size() ? jargon[random % jargon.size()] : ""); select(entry); } void FeepingCreaturism::select(const ext::String& selection, bool validate) { if (!validate || jargon.find(selection) != jargon.end()) { api::Cout << "Content-Type: text/html; charset=UTF-8\r\n\r\n"; Jargon jargon(path, selection, cgi.find("include") != cgi.end() && lexical_cast(ext::String(cgi.find("include")->second)), cgi.find("relative") != cgi.end() ? ext::String(cgi.find("relative")->second) : ext::String()); api::Cout << jargon; } else { api::Cout << "Status: 404\r\n" << "Content-Type: text/html; charset=ISO-8859-1\r\n\r\n" << "\n" << "\n404 Not Found\n\n" << "

Not Found

\n

The requested URL " << env.get("PATH_INFO") << " was not found on this server.

\n" << "
\n" << env.get("SERVER_SIGNATURE") << "\n"; } }