JetCore/Tag.cpp
2025-12-10 16:48:23 -08:00

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.");
}
}