The example CGI program uses 2 template files. See the template processor page for the details on template processor and template statements.
index.tpl, loaded directly from the program:
<(if $main)> <(include $main)> <(else)> <(include index.tpl)> <(fi)> <(print a=, $a, b=, $b)> <(if $a!=$b)> a != b <(else)> a == b <(fi)>
test.tpl, loaded from index.tpl using include statement:
<form enctype="multipart/form-data" method="POST">
<input type="file" name="file">
<input type="hidden" name="hidden" value="post">
<input type="text" name="text" value="text">
<input type="submit" value="push file">
</form>
<form method="POST">
<input type="hidden" name="hidden" value="post">
<input type="text" name="text" value="text">
<input type="submit" value="push">
</form>
<pre>
<(* test template *)>
<(assign a = 1)>
<(assign b = 2)>
<(print test=, $test)>
<(> <( not )> parsed area <)>
<(* simple 'if' statement *)>
<(if $test!=test)>
$test != 'test'
<(else)>
$test == 'test'
<(fi)>
<(* nested 'if' statements *)>
<(if $test)>
$test
<(if $test==test)>
$test == 'test'
<(fi)>
<(if $test!=test)>
$test != 'test'
<(fi)>
<(if $test)>
test
<(if $test==test)>
$test == 'test'
<(else)>
$test != 'test'
<(fi)>
<(else)>
<(if $test!=test)>
$test != 'test'
<(fi)>
<(if false)>
WTF?
<(fi)>
<(fi)>
<(if 3>2)>
3>2
<(fi)>
<(if 3<2)>
WTF?
<(fi)>
<(if!false)>!false<(fi)>
<(fi)>
<(* simple 'for' statement *)>
<(for $i in $strarr)>
<(for $j in $i)><(print $j)><(rof)>
<(rof)>
<(for $b in $strmaparr)>
<(for $c in $b)>
|<(print $c)>|<(print $b.one)>
<(rof)>
<(rof)>
<(for $c in $strmaparr.1)>
|<(print $c)>
<(rof)>
<(* namespace *)>
<(for $i in $strmaparr)>
<(for $i in $i)> <(* HERE : '$i in $i' is OK because of the namespace scope *)>
|<(print $i)>
<(print $dodo.iterator)>
<(rof)>
|<(print $i.one)>
<(print $dodo.iterator)>
<(rof)>
<(assign a = test1)>
<(if true)>
<(assign a = test2)>
<(for $i in $strmaparr)>
<(for $i => $j in $i)>
<(if $i == three)>
<(break 3)>
<(fi)>
<(print $i)> - <(print $j)>
<(assign a = test3)>
<(print a= ', $a,' (must be equal to 'test3'))>
<(rof)>
-------
<(rof)>
<(print a= ', $a,' (must be equal to 'test2'))>
<(fi)>
<(print a= ', $a,' (must be equal to 'test1'))>
<(ns)>
<(ns)>
<(assign a = in namespace)>
<(print a= ', $a,' (must be equal to 'in namespace'))>
<(sn)>
<(print a= ', $a,' (must be equal to 'test1'))>
<(sn)>
<(* print statement and variable resolution *)>
<(print string literal)>
<(print {$strmaparr.{0}.{$one}})>
<(print $strmaparr.1.{$strmap.{$one}})>
<(print $strarr.0.0)>
<(print $strmap.one)>
<(print $strmaparr.0.one)>
<(print $strmaparr.1.one)>
<(print $strmaparr.1.{$strmap.{$one}}, " -- ", {$strmaparr.{0}.{$one}})>
<(print $dodo.version, " : ", $dodo)>
</pre>
The main CGI program looks like:
#include <libdodo/dodo.h> using namespace dodo; using namespace data::tpl; using cgi::exchange; void handler(exchange &ex) { using namespace cgi; // First type: pass headers and force constructor print them immediately // In this case you will not be able to pass cookies(though you can embed them in headers) // dodoStringMap head; // head[cgi::RESPONSE_HEADER_CONTENTTYPE] = "text/html"; // dialogue d(&ex, head, false); // // Second type: use default headers and do not print them immediately dialogue d(ex, true); dodoString user = d.authenticationResponse().user; if (d.GET["status"] == "forbidden") { d.setResponseStatus(cgi::STATUS_CODE_FORBIDDEN); d.printString("FORBIDDEN"); return ; } else if (d.GET["status"] == "notfound") { d.setResponseStatus(cgi::STATUS_CODE_NOTFOUND); d.printString("NOT FOUND"); return ; } /** * A workaround for apache web server to get auth headers: * * RewriteEngine on * RewriteBase / * RewriteCond %{HTTP:Authorization} ^(.*) * RewriteRule ^(.*)$ $1 [e=HTTP_AUTHORIZATION:%1 */ else if (d.GET["status"] == "basic_auth") { if (user.size() == 0 || !d.isAuthenticated("libdodo", "password")) { d.requestAuthentication("libdodo", cgi::AUTH_BASIC); return ; } } else if (d.GET["status"] == "digest_auth") { if (user.size() == 0 || !d.isAuthenticated("libdodo", "password")) { d.requestAuthentication("libdodo", cgi::AUTH_DIGEST); return ; } } d.HEADERS[cgi::RESPONSE_HEADER_CONTENTTYPE] = "text/html"; d.setCookie(cookie("test", "cookie")); exchange *io = d; io->writeString("The headers should have been already printed.<br>"); d.printString("User: " + user + "<br>"); d.printString("GET[\"argument\"]: " + d.GET["argument"] + "<br>"); d.printString("POST[\"hidden\"]: " + d.POST["hidden"] + "<br>"); d.printString("POST[\"text\"]: " + d.POST["text"] + "<br>"); d.printString("ENVIRONMENT[CGI_ENVIRONMENT_QUERYSTRING]: " + d.ENVIRONMENT[cgi::ENVIRONMENT_QUERYSTRING] + "<br>"); d.printString("COOKIES[\"test\"]: " + d.COOKIES["test"] + "<br>"); d.printString("FILES[\"file\"].size: " + tools::string::iToString(d.FILES["file"].size) + "<br>"); d.printString("FILES[\"file\"].mime: " + d.FILES["file"].mime + "<br>"); d.printString("charset: " + d.charset() + "<br>"); d.printString("tpl::processor:<br>"); try { processor p; // Define template variables p.assign("main", "test.tpl"); p.assign("test", "test"); p.assign("show", "show"); p.assign("one", "one"); dodoStringArray strarr; strarr.push_back("one"); strarr.push_back("two"); strarr.push_back("three"); p.assign("strarr", strarr); dodoStringMap strmap; strmap["one"] = "one"; strmap["two"] = "two"; strmap["three"] = "three"; p.assign("strmap", strmap); dodoArray<dodoStringMap> strmaparr; strmaparr.push_back(strmap); strmap["one"] = "three"; strmaparr.push_back(strmap); p.assign("strmaparr", strmaparr); // Process the file p.processFile("index.tpl", *io); } catch (dodo::exception::basic ex) { d.printString((dodoString)ex + " " + tools::string::lToString(ex.line) + " " + ex.file + " " + ex.message ); } } int main(int argc, char **argv) { using namespace cgi::basic; // Create CGI server instance server s; // Define request handler and start to listen for request s.serve(&handler); return 0; }
For Fast-CGI everything remains the same except *main* function. In the case of Fast-CGI it looks like:
int main(int argc, char **argv) { try { using namespace cgi::fast; // Create CGI server instance // Server will process 5 requests and // Separate threads for processing each request will not be used server c(5, false); if (!c.isFastCgi()) { cout << "Not a fastCGI."; return 1; } // Define request handler and start to listen for request c.serve(&handler); } catch (dodo::exception::basic &ex) { cout << (dodoString)ex << "\t" << ex.line << "\t" << ex.file << endl; } return 0; }
