#include "tree_walker.h"
/**************************
* walk_the_tree
**************************/
void walk_the_tree(SV * self,
SV * buffer,
struct tnode * node,
HV* vars) {
char * label;
SV** variable_ref;
SV** sub_ref;
SV* included_lines;
SV* included_lines_ref;
struct tnode * already_included_node;
struct tnode * included_syntax_tree;
int c;
int ret;
int count;
int skip_includes;
char log_message[256];
dSP;
/*
printf("buffer::::::::::::::::::::::::::::::::::::::::\n");
printf("%s", SvPV_nolen(buffer));
printf("..............................................\n");
show_tnode(node,2);
printf("tttttttttttttttttttttttttttttttttttttttttttttt\n");
*/
/* if the node or the node text are not defined, return empty string */
if (!node || !(node->text)) {
return;
}
if (strcmp(node->text, "comment") == 0) {
walk_the_tree(self, buffer, node->children[0], vars);
return;
}
if (strcmp(node->text, "text") == 0) {
sv_catpv(buffer, node->children[0]->text);
walk_the_tree(self, buffer, node->children[1], vars);
return;
}
if (strcmp(node->text, "variable") == 0) {
label = node->children[0]->text; /* get the label of the variable */
/* fetch the variable from vars */
variable_ref = hv_fetch(vars, label, (U32)strlen(label), 0);
/* if the variable is not available or not defined */
if (variable_ref == 0 || !SvOK(*variable_ref) ) {
sv_catpvf(buffer, "$%s", label); /* add to the buffer "$label" */
walk_the_tree(self, buffer, node->children[1], vars);
return;
}
/* get the variable as text */
sv_catsv(buffer, *variable_ref);
walk_the_tree(self, buffer, node->children[1], vars);
return;
}
if (strcmp(node->text, "if") == 0 ||
strcmp(node->text, "elsif") == 0) {
label = node->children[0]->text; /* get the label of the condition */
/* fetch the variable from vars */
variable_ref = hv_fetch(vars, label, (U32)strlen(label), 0);
/* if the variable is available and defined and gives true,
we walk in the block of the if */
if (variable_ref != 0 &&
SvOK(*variable_ref) &&
SvTRUE(*variable_ref)) {
walk_the_tree(self, buffer, node->children[1], vars);
}
/* if the condition above was not successful, we should check if there
is elsif or else for it */
else if (node->children_number > 2 &&
(strcmp(node->children[2]->text, "elsif") == 0 ||
strcmp(node->children[2]->text, "else") == 0)) {
walk_the_tree(self, buffer, node->children[2], vars);
}
/* in any case of "if" we walk the next node in the tree */
if (strcmp(node->text, "if") == 0 &&
node->children_number > 2) {
walk_the_tree(self, buffer, node->children[node->children_number-1],
vars);
}
return;
}
if (strcmp(node->text, "else") == 0) {
walk_the_tree(self, buffer, node->children[0], vars);
return;
}
if (strcmp(node->text, "include") == 0) {
/* check if that node was already included */
if (node->children_number > 2 &&
node->children[node->children_number - 2]->text &&
strcmp(node->children[node->children_number - 2]->text,
"already_included") == 0) {
walk_the_tree(self, buffer,
node->children[node->children_number - 1], vars);
return;
}
label = node->children[0]->text; /* get the file name of the include */
/* check if we should skip */
/* fetch the SKIP_INCLUDES from self */
variable_ref = hv_fetch((HV*)SvRV(self), "SKIP_INCLUDES",
(U32)strlen("SKIP_INCLUDES"), 0);
/* if the variable is not available or not defined */
if (variable_ref == 0 || !SvOK(*variable_ref) ) {
skip_includes = 0;
}
else {
skip_includes = SvIV(*variable_ref);
}
if (skip_includes) { /* skip all the includes because
SKIP_INCLUDES is true */
/* we should skip, so instead we write to the buffer the same include
we had and then we just continue */
if (node->children_number > 0 &&
node->children[1]->text != 0 &&
strcmp(node->children[1]->text, "skip") == 0 &&
node->children[1]->number > 0) {
sv_catpvf(buffer, "<include src=\"%s\" skip=\"%d\">", label,
node->children[1]->number);
}
else {
sv_catpvf(buffer, "<include src=\"%s\">", label);
}
walk_the_tree(self, buffer,
node->children[node->children_number - 1], vars);
return;
}
/* check about the skip attribute */
else if (node->children_number > 0 &&
node->children[1]->text != 0 &&
strcmp(node->children[1]->text, "skip") == 0) {
if (node->children[1]->number > 0) {
/* we should skip, so instead we write to the buffer an includ
with decremented skip value and then we just continue */
sv_catpvf(buffer, "<include src=\"%s\" skip=\"%d\">", label,
node->children[1]->number - 1);
walk_the_tree(self, buffer,
node->children[node->children_number - 1], vars);
return;
}
}
/* if the included template file name is passed in a varibale, get it
from the variable */
if (label[0] == '$') {
label = label + 1;
/* fetch the variable from vars */
variable_ref = hv_fetch(vars, label, (U32)strlen(label), 0);
/* if the variable is not available or not defined */
if (variable_ref == 0 || !SvOK(*variable_ref) ) {
/* we just send a message to the log, and ignore the include */
sprintf(log_message, "Include tag with undefined variable $%0.30s",
label);
write_log(self, log_message, 4);
walk_the_tree(self, buffer,
node->children[node->children_number - 1], vars);
return;
}
/* get the variable as text and put it in label */
label = SvPV_nolen(*variable_ref);
}
/* prepare the included lines variable and its reference */
included_lines = newSVpvn("", 0); /* create empty string perl scalar */
included_lines_ref = newRV_inc((SV*)included_lines);
/* call read and read the template into lines */
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(self);
XPUSHs(sv_2mortal(newSVpvn(label, strlen(label))));
XPUSHs(included_lines_ref);
PUTBACK;
count = call_method("read", G_SCALAR);
SPAGAIN;
if (count != 1) {
/* a problem. must log it */
sprintf(log_message, "Failed to call the read method");
write_log(self, log_message, 4);
return;
}
ret = POPi;
PUTBACK;
FREETMPS;
LEAVE;
if (ret != 1) {
/* a problem. must log it */
sprintf(log_message, "The call read(\"%0.30s\") returned 0", label);
write_log(self, log_message, 4);
return;
}
/* call parse_skin to get the syntax tree */
included_syntax_tree = parse_skin(SvPV_nolen(included_lines));
/* add the included syntax tree to the include node */
already_included_node = make_tnode("already_included", 0);
add_tnode(already_included_node, included_syntax_tree);
/* add_tnode(already_included_node,
node->children[node->children_number - 1]); */
add_tnode(node, already_included_node);
/* walk that new node */
walk_the_tree(self, buffer, already_included_node, vars);
/* walk the node that was after the include */
walk_the_tree(self, buffer, node->children[2], vars);
return;
}
if (strcmp(node->text, "already_included") == 0) {
/* first we walk the included tree */
walk_the_tree(self, buffer, node->children[0], vars);
/* and then the rest of the tree */
/* walk_the_tree(self, buffer, node->children[1], vars);*/
return;
}
if (strcmp(node->text, "while") == 0) {
/* get the reference to the callback function */
label = node->children[0]->text; /* get the label of the condition */
/* fetch the reference to the subroutine from vars using label as a key */
sub_ref = hv_fetch(vars, label, (U32)strlen(label), 0);
/* if the variable is not available or not defined */
if (sub_ref == 0 || !SvOK(*sub_ref) ) {
/* call the log to tell that the callback is not available */
sprintf(log_message, "Callback function %0.30s is unavailable", label);
write_log(self, log_message, 4);
return;
}
while (1) {
/* call the callback function */
SPAGAIN;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(newRV_noinc((SV*) vars));
PUTBACK;
count = call_sv(*sub_ref, G_SCALAR);
SPAGAIN;
if (count != 1) {
/* a problem. must log it */
sprintf(log_message, "Failed to call the callback function %0.30s",
label);
write_log(self, log_message, 4);
return;
}
ret = POPi;
PUTBACK;
FREETMPS;
LEAVE;
/* if the callback function returns 0 get out of the loop */
if (!ret) {
break;
}
/* walk the while block */
walk_the_tree(self, buffer, node->children[1], vars);
}
/* walk the rest of the tree */
walk_the_tree(self, buffer, node->children[2], vars);
return;
}
} /* of walk_the_tree */
/***********************
* write_log
***********************/
void write_log(SV* self, char* message, int level) {
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(self);
XPUSHs(sv_2mortal(newSVpv(message, 0)));
XPUSHs(sv_2mortal(newSViv(level)));
PUTBACK;
call_method("perl_write_log", G_DISCARD);
FREETMPS;
LEAVE;
} /* of write_log */