537 lines
17 KiB
C++
537 lines
17 KiB
C++
#include "Tag.h"
|
|
#include "Exception.h"
|
|
#include "Global.h"
|
|
#include "__mysql.h"
|
|
#include "__sql.h"
|
|
#include "__whilerow.h"
|
|
#include "__comment.h"
|
|
#include "__exclude.h"
|
|
#include "__for.h"
|
|
#include "__if.h"
|
|
#include "__ifrow.h"
|
|
#include "__include.h"
|
|
#include "__read.h"
|
|
#include "__write.h"
|
|
#include "__set.h"
|
|
#include "__call.h"
|
|
#include "__system.h"
|
|
#include "__jet.h"
|
|
#include "__while.h"
|
|
#include "__until.h"
|
|
#include "__header.h"
|
|
#include "__cookie.h"
|
|
#include "__whiledir.h"
|
|
#include "__tag.h"
|
|
#include "__dotag.h"
|
|
#include "__stream.h"
|
|
#include "__dump.h"
|
|
#include "Operand.h"
|
|
#include <iostream>
|
|
|
|
namespace jet {
|
|
|
|
Tag::Tag(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local, coreutils::ZString splitTagName)
|
|
: ZString(in), parentOut(parentOut), global(global), parent(parent), local(local) {
|
|
this->splitTagName = splitTagName;
|
|
global.errorCursor = in.getCursor();
|
|
if(parent && in.ifNext("<")) {
|
|
name = in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_!");
|
|
if(in.startsWith(" ") || in.startsWith("/") || in.startsWith(">")) {
|
|
bool finished = false;
|
|
while(!finished) {
|
|
in.skipWhitespace();
|
|
if(in.ifNext(">")) {
|
|
hasContainer = true;
|
|
hasContainer2 = false;
|
|
finished = true;
|
|
break;
|
|
} else if(in.ifNext("/>")) {
|
|
hasContainer = false;
|
|
hasContainer2 = false;
|
|
finished = true;
|
|
break;
|
|
}
|
|
if(!finished) {
|
|
coreutils::ZString keywordName = in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
|
|
if(in.ifNext("=\"")) {
|
|
if(keywords.count(keywordName) == 0)
|
|
keywords[keywordName] = in.getTokenExclude("\"");
|
|
else
|
|
throw coreutils::Exception("keyword name must be unique for tag.");
|
|
}
|
|
if(!in.ifNext("\"")) {}
|
|
}
|
|
}
|
|
if(keywordDefined("filterblanklines")) {
|
|
filterBlankLines = keywords["filterblanklines"] == "true" ? true: false;
|
|
}
|
|
if(keywordDefined("trimlines")) {
|
|
trimLines = keywords["trimlines"] == "true" ? true: false;
|
|
}
|
|
if(hasContainer) {
|
|
bool hasSplitTag = splitTagName == "" ? false: true;
|
|
char *start = in.getCursor();
|
|
while(!in.eod()) {
|
|
char *end = in.getCursor();
|
|
if(ifEndTagName(in)) {
|
|
if(hasContainer2)
|
|
container2 = coreutils::ZString(start, end - start);
|
|
else
|
|
container = coreutils::ZString(start, end - start);
|
|
break;
|
|
} else if(hasSplitTag && ifSplitTagName(in)) {
|
|
hasContainer2 = true;
|
|
container = coreutils::ZString(start, end - start);
|
|
in.ifNext("<else>");
|
|
start = in.getCursor();
|
|
} else if(ifNested(in)) {
|
|
} else
|
|
in.nextChar();
|
|
}
|
|
}
|
|
setZString(in.parsed());
|
|
if(keywordDefined("eval")) {
|
|
if(keywords["eval"] == "yes") {
|
|
evaluate = true;
|
|
} else if(keywords["eval"] == "no") {
|
|
evaluate = false;
|
|
} else
|
|
throw coreutils::Exception("keyword 'eval' must be 'yes' or 'no'.");
|
|
}
|
|
}
|
|
} else
|
|
parseContainer(in, out);
|
|
}
|
|
|
|
Tag::~Tag() {
|
|
if(evaluate)
|
|
if(output)
|
|
copyContainer(out, parentOut);
|
|
else if(output)
|
|
copyContainer(container, parentOut);
|
|
}
|
|
|
|
coreutils::MString Tag::resolveKeyword(coreutils::ZString keyword) {
|
|
coreutils::MString resolved;
|
|
keywords[keyword].reset();
|
|
while(!keywords[keyword].eod()) {
|
|
if(keywords[keyword].startsWith("$[") || keywords[keyword].startsWith("#[")) {
|
|
resolved.write(getVariable(keywords[keyword]));
|
|
} else {
|
|
resolved.write(keywords[keyword].charAt(0));
|
|
keywords[keyword].nextChar();
|
|
}
|
|
}
|
|
keywords[keyword].reset();
|
|
return resolved;
|
|
}
|
|
|
|
void Tag::processContainer(coreutils::ZString &container, coreutils::ZString container2, bool topLevel) {
|
|
if(hasContainer && evaluate)
|
|
parseContainer(container, out, container2, topLevel);
|
|
}
|
|
|
|
void Tag::parseContainer(coreutils::ZString &in, coreutils::MString &out, coreutils::ZString container2, bool topLevel) {
|
|
coreutils::ZString tag;
|
|
char *start = in.getCursor();
|
|
while(!in.eod()) {
|
|
if(in.ifNext("|>")) {
|
|
if(!topLevel)
|
|
out.write("|>");
|
|
char ch = in.nextChar();
|
|
while(!in.ifNext("<|")) {
|
|
out.write(ch);
|
|
ch = in.nextChar();
|
|
}
|
|
out.write(ch);
|
|
if(!topLevel)
|
|
out.write("<|");
|
|
continue;
|
|
} else if(in.startsWith("<")) {
|
|
if(ifTagName(in, "mysql")) {
|
|
__mysql _mysql(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "comment")) {
|
|
__comment _comment(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "sql")) {
|
|
__sql _sql(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "whilerow")) {
|
|
__whilerow _whilerow(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "for")) {
|
|
__for _for(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "if")) {
|
|
__if _if(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "ifrow")) {
|
|
__ifrow _ifrow(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "include")) {
|
|
__include _include(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "exclude")) {
|
|
__exclude _exclude(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "jet")) {
|
|
__jet _jet(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "read")) {
|
|
__read _read(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "write")) {
|
|
__write _write(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "set")) {
|
|
__set _set(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "call")) {
|
|
__call _call(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "system")) {
|
|
__system _system(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "while")) {
|
|
__while _while(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "until")) {
|
|
__until _until(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "header")) {
|
|
__header _header(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "cookie")) {
|
|
__cookie _cookie(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "whiledir")) {
|
|
__whiledir _whiledir(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "stream")) {
|
|
__stream _stream(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "dump")) {
|
|
__dump _dump(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "tag")) {
|
|
__tag _tag(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagDefined(in, tag)) {
|
|
__dotag _dotag(in, out, global, this, local);
|
|
continue;
|
|
} else if(ifTagName(in, "container")) {
|
|
processContainer(container2);
|
|
in.ifNext("<container");
|
|
in.skipWhitespace();
|
|
in.ifNext("/>");
|
|
continue;
|
|
} else {
|
|
out.write(in.nextChar());
|
|
continue;
|
|
}
|
|
} else if(in.startsWith("$[") || in.startsWith("#[")) {
|
|
global.errorCursor = in.getCursor();
|
|
out.write(getVariable(in, true));
|
|
} else {
|
|
out.write(in.nextChar());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Tag::scanContainer(coreutils::ZString &in) {
|
|
while(!in.eod()) {
|
|
if(ifEndTagName(in))
|
|
return;
|
|
else if(ifNested(in)) {}
|
|
else in.nextChar();
|
|
}
|
|
}
|
|
|
|
bool Tag::ifTagName(coreutils::ZString &in, const char *tag) {
|
|
in.push();
|
|
if(in.ifNext("<"))
|
|
if(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_").equals(tag)) {
|
|
if(in.ifNext(" ")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext("/>")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext(">")) {
|
|
in.pop();
|
|
return true;
|
|
}
|
|
}
|
|
in.pop();
|
|
return false;
|
|
}
|
|
|
|
bool Tag::ifTagName(coreutils::ZString &in) {
|
|
in.push();
|
|
if(in.ifNext("<"))
|
|
if(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_").equals(name)) {
|
|
in.push();
|
|
if(in.ifNext(" ")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext("/>")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext(">")) {
|
|
in.pop();
|
|
return true;
|
|
}
|
|
in.pop();
|
|
}
|
|
in.pop();
|
|
return false;
|
|
}
|
|
|
|
bool Tag::ifTagDefined(coreutils::ZString &in, coreutils::ZString &tag) {
|
|
in.push();
|
|
if(in.ifNext("<")) {
|
|
tag = in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
|
|
if(global.tags.count(tag)) {
|
|
if(in.ifNext(" ")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext("/>")) {
|
|
in.pop();
|
|
return true;
|
|
} else if(in.ifNext(">")) {
|
|
in.pop();
|
|
return true;
|
|
}
|
|
in.pop();
|
|
}
|
|
}
|
|
in.pop();
|
|
return false;
|
|
}
|
|
|
|
bool Tag::ifEndTagName(coreutils::ZString &in) {
|
|
in.push();
|
|
if(in.ifNext("</"))
|
|
if(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_").equals(name)) {
|
|
if(in.ifNext(">"))
|
|
return true;
|
|
}
|
|
in.pop();
|
|
return false;
|
|
}
|
|
|
|
bool Tag::ifSplitTagName(coreutils::ZString &in) {
|
|
in.push();
|
|
if(in.ifNext("<"))
|
|
if(in.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_").equals(splitTagName)) {
|
|
if(in.ifNext(">"))
|
|
in.pop();
|
|
return true;
|
|
}
|
|
in.pop();
|
|
return false;
|
|
}
|
|
|
|
int Tag::skipBlankLine(coreutils::ZString in) {
|
|
ZString temp = in.getTokenInclude(" \t");
|
|
if(ifNext("\n"))
|
|
return temp.getLength() + 1;
|
|
return 0;
|
|
}
|
|
|
|
void Tag::copyContainer(coreutils::ZString &in, coreutils::MString &out) {
|
|
while(!in.eod()) {
|
|
if(filterBlankLines) {
|
|
if(!in.lineIsWhitespace()) {
|
|
if(trimLines)
|
|
out.write(in.goeol().trim());
|
|
else
|
|
out.write(in.goeol());
|
|
out.write('\n');
|
|
}
|
|
else {
|
|
in.goeol();
|
|
}
|
|
}
|
|
else {
|
|
out.write(in.charAt(0));
|
|
in.nextChar();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Tag::keywordDefined(coreutils::ZString keyword) {
|
|
return keywords.find(keyword) != keywords.end();
|
|
}
|
|
|
|
bool Tag::ifNested(coreutils::ZString &in) {
|
|
bool hasContainer = false;
|
|
if(ifTagName(in)) {
|
|
while(!in.eod()) {
|
|
in.skipWhitespace();
|
|
if(in.ifNext(">")) {
|
|
hasContainer = true;
|
|
break;
|
|
} else if(in.ifNext("/>")) {
|
|
hasContainer = false;
|
|
return true;
|
|
} else if(in.getTokenExclude("=").getLength() != 0) {
|
|
if(in.ifNext("=\"")) {
|
|
while(1) {
|
|
if(in.ifNext("\"")) {
|
|
break;
|
|
}
|
|
in.nextChar();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(hasContainer)
|
|
scanContainer(in);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
coreutils::MString Tag::getVariable(coreutils::ZString &variable, bool inContainer) {
|
|
if(variable.ifNext("$[")) {
|
|
coreutils::MString name;
|
|
coreutils::MString modifier;
|
|
if(variable.ifNext("!")) {
|
|
renderVariableName(variable, name, modifier);
|
|
return global.variables[name];
|
|
} else if(variable.ifNext("%")) {
|
|
renderVariableName(variable, name, modifier);
|
|
if(inContainer)
|
|
return keywords[name];
|
|
else
|
|
return parent->keywords[name];
|
|
} else if(variable.ifNext(":")) {
|
|
if(global.cgi) {
|
|
renderVariableName(variable, name, modifier);
|
|
if(name.find(":") == -1) {
|
|
name << ":0";
|
|
}
|
|
return processModifier(global.cgiData[name], modifier);
|
|
} else
|
|
throw coreutils::Exception("cgi variable only allowed in cgi mode.");
|
|
} else if(variable.ifNext("@")) {
|
|
// TODO: should only allow session variables. Allow substitution.
|
|
} else if(variable.ifNext("%")) {
|
|
renderVariableName(variable, name, modifier);
|
|
return getenv(name.c_str());
|
|
} else if(variable.ifNext("^")) {
|
|
renderVariableName(variable, name, modifier);
|
|
return global.cookies.data[name];
|
|
} else {
|
|
renderVariableName(variable, name, modifier);
|
|
name.split(".");
|
|
if(name.getList().size() == 1) {
|
|
if(global.variables.find(name[0]) == global.variables.end())
|
|
throw coreutils::Exception("global variable is not initialized.");
|
|
return processModifier(global.variables[name[0]], modifier);
|
|
}
|
|
return global.getSessionVariable(name);
|
|
}
|
|
throw coreutils::Exception("expected variable name or type designator.");
|
|
} else if(variable.ifNext("#[")) {
|
|
coreutils::MString name;
|
|
coreutils::MString modifier;
|
|
renderVariableName(variable, name, modifier);
|
|
if(local->variables.find(name) == local->variables.end())
|
|
throw coreutils::Exception("local variable is not initialized.");
|
|
return local->variables[name];
|
|
}
|
|
throw coreutils::Exception("Expecting a variable initializer ('$[' or '#[').");
|
|
}
|
|
|
|
void Tag::renderVariableName(coreutils::ZString &variable, coreutils::MString &name, coreutils::MString &modifier) {
|
|
while(!variable.ifNext("]")) {
|
|
name << variable.getTokenInclude("?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");
|
|
if(variable.ifNext(";")) {
|
|
renderVariableName(variable, modifier, modifier);
|
|
return;
|
|
} else if(variable.ifNext(":")) {
|
|
name << ":";
|
|
} else if(variable.startsWith("$[") || variable.startsWith("#[")) {
|
|
name << getVariable(variable);
|
|
} else if(variable.ifNext("]"))
|
|
return;
|
|
else if(!variable.ifNextInclude("?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"))
|
|
throw coreutils::Exception("invalid variable name.");
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Tag::storeVariable(coreutils::ZString variable, coreutils::MString value, coreutils::ZString scope) {
|
|
if((scope == "global") || (scope == ""))
|
|
global.variables[variable] = value;
|
|
else if(scope == "local")
|
|
local->variables[variable] = value;
|
|
else if(scope == "parent")
|
|
local->parent->variables[variable] = value;
|
|
}
|
|
|
|
void Tag::storeVariable(coreutils::ZString variable) {
|
|
if(keywordDefined("expr")) {
|
|
if(!keywordDefined("scope") || (resolveKeyword("scope") == "global"))
|
|
global.variables[variable] = Operand(keywords["expr"], *this).string;
|
|
else if(resolveKeyword("scope") == "local")
|
|
local->variables[variable] = Operand(keywords["expr"], *this).string;
|
|
else if(resolveKeyword("scope") == "parent")
|
|
local->parent->variables[variable] = Operand(keywords["expr"], *this).string;
|
|
} else if(hasContainer) {
|
|
processContainer(container);
|
|
if(evaluate) {
|
|
if(!keywordDefined("scope") || (resolveKeyword("scope") == "global"))
|
|
global.variables[variable] = out;
|
|
else if(resolveKeyword("scope") == "local")
|
|
local->variables[variable] = out;
|
|
else if(resolveKeyword("scope") == "parent")
|
|
local->parent->variables[variable] = out;
|
|
} else {
|
|
if(!keywordDefined("scope") || (resolveKeyword("scope") == "global"))
|
|
global.variables[variable] = container;
|
|
else if(resolveKeyword("scope") == "local")
|
|
local->variables[variable] = container;
|
|
else if(resolveKeyword("scope") == "parent")
|
|
local->parent->variables[variable] = container;
|
|
}
|
|
} else {
|
|
if(!keywordDefined("scope") || (resolveKeyword("scope") == "global"))
|
|
global.variables[variable] = resolveKeyword("value");
|
|
else if(resolveKeyword("scope") == "local")
|
|
local->variables[variable] = resolveKeyword("value");
|
|
else if(resolveKeyword("scope") == "parent")
|
|
local->parent->variables[variable] = resolveKeyword("value");
|
|
}
|
|
}
|
|
|
|
coreutils::MString Tag::processModifier(coreutils::MString &value, coreutils::MString &modifier) {
|
|
if(modifier == "")
|
|
return value;
|
|
if(modifier == "tobinary")
|
|
return value.toBinary();
|
|
else if(modifier == "frombinary")
|
|
return value.fromBinary();
|
|
else if(modifier == "tohex")
|
|
return value.toHex();
|
|
else if(modifier == "fromhex")
|
|
return value.fromHex();
|
|
else if(modifier == "tobase64")
|
|
return value.toBase64();
|
|
else if(modifier == "frombase64")
|
|
return value.fromBase64();
|
|
else if(modifier == "toupper")
|
|
return value.toUpper();
|
|
else if(modifier == "tolower")
|
|
return value.toLower();
|
|
else if(modifier == "tocgi")
|
|
return value.toCGI();
|
|
else if(modifier == "fromcgi")
|
|
return value.fromCGI();
|
|
throw coreutils::Exception("modifier not valid.");
|
|
}
|
|
|
|
}
|