aboutsummaryrefslogtreecommitdiff
path: root/ctemplates.c
diff options
context:
space:
mode:
Diffstat (limited to 'ctemplates.c')
-rw-r--r--ctemplates.c1210
1 files changed, 0 insertions, 1210 deletions
diff --git a/ctemplates.c b/ctemplates.c
deleted file mode 100644
index aa7c650..0000000
--- a/ctemplates.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/*
- * C TemplateS : template expander
- * Based on the original libctemplate by Stephen C. Losen
- *
- * Version 0.1
- *
- * Copyright (c) 2017-2018 Alexander M. Pickering (alex@cogarr.net)
- *
- * Distributed under GPL V3, see COPYING for more information.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as publish by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public Liscense for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <stdarg.h>
-#include <ctemplates.h>
-
-struct TMPL_token* TMPL_alloc_token(void);
-void TMPL_free_token(struct TMPL_token* token);
-enum TMPL_tagtype starts_with_token(char* str, size_t strlen);
-size_t tagtype_len(enum TMPL_tagtype t);
-struct TMPL_token* scan_text(
- char* start,
- size_t strlen,
- size_t* consumed
- );
-struct TMPL_token* scan_tag(
- char* start,
- size_t strlen,
- size_t* consumed
- );
-void print_tokens(struct TMPL_token* head);
-struct TMPL_varitem* TMPL_alloc_varitem(void);
-void TMPL_free_varitem(struct TMPL_varitem* vi);
-void TMPL_add_var_to_varlist(
- struct TMPL_varlist* t,
- char* varname,
- char* var
- );
-void print_ast_helper(
- struct TMPL_tagnode* cursor,
- int level
- );
-void print_ast(struct TMPL_tagnode* root);
-struct TMPL_token* TMPL_tokenize(char* tmplstr, size_t strlen);
-struct TMPL_tagnode* alloc_tagnode(void);
-size_t get_quoted_string(char* start, size_t len);
-int is_whitespace(char c);
-struct TMPL_tagnode* parse_text(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_tagnode* parse_else(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_tagnode* parse_elseif(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_tagnode* parse_if(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_tagnode* parse_loop(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_tagnode* parse_variable(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_varlist* TMPL_alloc_varlist(void);
-int TMPL_free_hashmapitems(any_t a, any_t b);
-void TMPL_free_varlist(struct TMPL_varlist* vl);
-struct TMPL_loop* TMPL_alloc_loop(void);
-void TMPL_free_loop(struct TMPL_loop* tl);
-void TMPL_add_varlist_to_loop(
- struct TMPL_loop* tl,
- struct TMPL_varlist* vl
- );
-void TMPL_add_loop_to_varlist(
- struct TMPL_varlist* vl,
- char* name,
- struct TMPL_loop* l
- );
-struct TMPL_tagnode* parse(
- struct TMPL_token* head,
- struct TMPL_buf* errbuf
- );
-struct TMPL_templates* alloc_templates(void);
-struct TMPL_templates* compile(char* tmplstr);
-int render_variable(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-int render_text(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-int print_pair(any_t indent, any_t b);
-int render_if(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-int render_elseif(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-int render_loop(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-int render_any(
- struct TMPL_templates* t,
- struct TMPL_tagnode* node,
- struct TMPL_varlist* varlist
- );
-void TMPL_render_helper(
- struct TMPL_templates* t,
- struct TMPL_varlist* varlist
- );
-char* TMPL_render(
- struct TMPL_templates* t,
- struct TMPL_varlist* varlist,
- size_t* size_p
- );
-struct TMPL_templates* TMPL_alloc_template(char* tmplstr);
-void TMPL_free_template(struct TMPL_templates* t);
-void TMPL_free_tagnode(struct TMPL_tagnode* tn);
-char* TMPL_get_error(struct TMPL_templates* t);
-void print_varlist_helper(
- struct TMPL_varlist* vl,
- int indent
- );
-
-
-/*Allocates a token*/
-struct TMPL_token*
-TMPL_alloc_token(){
- struct TMPL_token* ret = (struct TMPL_token*)malloc(sizeof(struct TMPL_token));
- ret->next = NULL;
- return ret;
-}
-
-/*Frees an allocated token*/
-void
-TMPL_free_token(struct TMPL_token* token){
- struct TMPL_token* cursor = token;
- while(cursor != NULL){
- struct TMPL_token* this = cursor;
- cursor = cursor->next;
- free(this);
- }
-}
-
-/*Check if it starts with the names of any of our tokens*/
-enum TMPL_tagtype
-starts_with_token(char* str, size_t strlen){
- /*Make sure we get TMPL_ first*/
- if(strlen < 5){
- return tag_null;
- }
- if(*str != 'T'
- || *(str + 1) != 'M'
- || *(str + 2) != 'P'
- || *(str + 3) != 'L'
- || *(str + 4) != '_'){
- return tag_null;
- }
- if(strlen > TAG_VAR_LENGTH
- && *(str + 5) == 'V'
- && *(str + 6) == 'A'
- && *(str + 7) == 'R'
- && *(str + 8) == ' '){
- return tag_var;
- }else if(strlen > TAG_IF_LENGTH
- && *(str + 5) == 'I'
- && *(str + 6) == 'F'
- && *(str + 7) == ' '){
- return tag_if;
- }else if(strlen > TAG_END_LENGTH
- && *(str + 5) == 'E'
- && *(str + 6) == 'N'
- && *(str + 7) == 'D'){
- return tag_end;
- }else if(strlen > TAG_ELSE_LENGTH
- && *(str + 5) == 'E'/*Check for both else and elseif*/
- && *(str + 6) == 'L'
- && *(str + 7) == 'S'
- && *(str + 8) == 'E'){
- if(*(str + 9) != 'I'){
- return tag_else;
- }else if(strlen > TAG_ELSEIF_LENGTH
- && *(str + 9) == 'I'
- && *(str + 10) == 'F'
- && *(str + 11) == ' '){
- return tag_elseif;
- }else{
- return tag_null;
- }
- }else if(strlen > TAG_LOOP_LENGTH
- && *(str + 5) == 'L'
- && *(str + 6) == 'O'
- && *(str + 7) == 'O'
- && *(str + 8) == 'P'
- && *(str + 9) == ' '){
- return tag_loop;
- }else if(strlen > TAG_BREAK_LENGTH
- && *(str + 5) == 'B'
- && *(str + 6) == 'R'
- && *(str + 7) == 'E'
- && *(str + 8) == 'A'
- && *(str + 9) == 'K'
- && *(str + 10) == ' '){
- return tag_break;
- }else if(strlen > TAG_CONTINUE_LENGTH
- && *(str + 5) == 'C'
- && *(str + 6) == 'O'
- && *(str + 7) == 'N'
- && *(str + 8) == 'T'
- && *(str + 9) == 'I'
- && *(str + 10) == 'N'
- && *(str + 11) == 'U'
- && *(str + 12) == 'E'
- && *(str + 13) == ' '){
- return tag_continue;
- }else{
- return tag_null;
- }
-}
-
-/*Find the lenth of a tag*/
-size_t
-tagtype_len(enum TMPL_tagtype t){
- switch(t){
- case tag_null:
- return TAG_NULL_LENGTH;
- case tag_text:
- return TAG_TEXT_LENGTH;
- case tag_var:
- return TAG_VAR_LENGTH;
- case tag_if:
- return TAG_IF_LENGTH;
- case tag_end:
- return TAG_END_LENGTH;
- case tag_elseif:
- return TAG_ELSEIF_LENGTH;
- case tag_else:
- return TAG_ELSE_LENGTH;
- case tag_loop:
- return TAG_LOOP_LENGTH;
- case tag_break:
- return TAG_BREAK_LENGTH;
- case tag_continue:
- return TAG_CONTINUE_LENGTH;
- }
- return 0;
-}
-
-/*Quickly find the token*/
-struct TMPL_token*
-scan_text(char* start, size_t strlen, size_t* consumed){
- struct TMPL_token* t = TMPL_alloc_token();
- t->start = start;
- enum TMPL_tagtype type = tag_null;
- char* cursor = start;
- while(type == tag_null){
- int left = strlen - (cursor - start);
- cursor = (char*)memchr(cursor,'<',left);
- if(cursor == NULL){
- cursor = start + (strlen > 0 ? strlen : 1);
- break;
- }
- type = starts_with_token(cursor+1,strlen);
- if(type == tag_null){
- cursor++;
- }
- }
- t->end = cursor;
- t->length = t->end - t->start;
- *consumed = t->length;
- char* c;
- for(c = start; c < cursor; c++){
- }
- return t;
-}
-
-struct TMPL_token*
-scan_tag(char* start, size_t strlen, size_t* consumed){
- struct TMPL_token* t = TMPL_alloc_token();
- t->start = start;
- char* cursor = (char*)memchr(start,'>',strlen);
- t->end = cursor+1;/*Include the '>'*/
- t->length = t->end - t->start;
- *consumed = t->length;
- return t;
-}
-
-void
-print_tokens(struct TMPL_token* head){
- struct TMPL_token* cursor = head;
- while(cursor != NULL){
- printf("char start is %p char end is %p cursor is %p type is %d\n",cursor->start, cursor->end,(void*)cursor,(int)cursor->type);
- char* i;
- for(i = cursor->start; i != cursor->end; i++){
- printf("%c",*i);
- }
- printf("\n----\n");
- cursor = cursor->next;
- }
- printf("Finished printing tokens\n");
-}
-
-struct TMPL_varitem*
-TMPL_alloc_varitem(){
- struct TMPL_varitem* ret = (struct TMPL_varitem*)malloc(sizeof(struct TMPL_varitem));
- return ret;
-}
-
-void
-TMPL_free_varitem(struct TMPL_varitem* vi){
- if(vi->type == vartype_var){
- free(vi->item.s);
- }else{
- TMPL_free_loop(vi->item.l);
- }
- free(vi);
-}
-
-void
-TMPL_add_var_to_varlist(struct TMPL_varlist* t, char* varname, char* var){
- struct TMPL_varitem* vi = TMPL_alloc_varitem();
- vi->type = vartype_var;
- size_t slen = strlen(var);/*strlen dosn't count \0*/
- vi->item.s = (char*)malloc(sizeof(char)*(slen + 1));
- vi->item.s[slen] = '\0';
- memcpy(vi->item.s,var,slen);
- int succ = hashmap_put(t->map,varname,vi);
- if(succ != MAP_OK){
- exit(-1);
- }
-}
-
-void
-print_ast_helper(struct TMPL_tagnode* cursor, int level){
- int i;
- for(i = 0; i < level; i++){
- printf("|");
- }
- printf("} %d ->",(int)cursor->type);
- switch(cursor->type){
- case tag_null:
- printf("TAG NULL");
- break;
- case tag_text:
- printf("TAG Text %d\n", (int)cursor->TMPL_tag.text.len);
- break;
- case tag_var:
- printf("TAG var(%s)",cursor->TMPL_tag.var.varname);
- if(cursor->TMPL_tag.var.default_len > 0){
- printf(" +default:%d",(int)cursor->TMPL_tag.var.default_len);
- }
- printf("\n");
- break;
- case tag_if:
- case tag_elseif:
- printf("TAG If/elseif,(%s) == (%s)\n",cursor->TMPL_tag.ifelse.varname,cursor->TMPL_tag.ifelse.testval);
- level++;
- for(i=0;i<level;i++){
- printf("|");
- }
- printf("True:\n");
- print_ast_helper(cursor->TMPL_tag.ifelse.tbranch,level);
- if(cursor->TMPL_tag.ifelse.fbranch != NULL){
- for(i=0;i<level;i++){
- printf("|");
- }
- printf("False:\n");
- print_ast_helper(cursor->TMPL_tag.ifelse.fbranch,level);
- }
- level--;
- break;
- case tag_else:
- printf("TAG Else\n");
- break;
- case tag_end:
- printf("TAG End\n");
- break;
- case tag_loop:
- printf("TAG Loop (%s), body:\n",cursor->TMPL_tag.loop.loopname);
- print_ast_helper(cursor->TMPL_tag.loop.body,level+1);
- break;
- case tag_break:
- printf("TAG Break\n");
- break;
- case tag_continue:
- printf("TAG Continue\n");
- break;
- }
- if(cursor->next != NULL){
- print_ast_helper(cursor->next,level);
- }
-}
-void
-print_ast(struct TMPL_tagnode* root){
- print_ast_helper(root,0);
-}
-
-struct TMPL_token*
-TMPL_tokenize(char* tmplstr, size_t m_strlen){
- if(m_strlen == 0) return NULL;
- struct TMPL_token* first;
- char* textcursor = tmplstr;
- size_t newlength;
- enum TMPL_tagtype ttype;
- ttype = starts_with_token(tmplstr+1,m_strlen);
- if(*tmplstr == '<' && ttype != tag_null){
- first = scan_tag(textcursor,m_strlen,&newlength);
- first->type = ttype;
- }else{
- first = scan_text(textcursor,m_strlen,&newlength);
- first->type = tag_text;
- }
- textcursor += newlength;
- first->end = textcursor;
- first->length = newlength;
- m_strlen -= newlength;
- struct TMPL_token* tokencursor = first;
- struct TMPL_token* newnode;
- while(*textcursor != '\0'){
- ttype = starts_with_token(textcursor+1,m_strlen);
- if(ttype == tag_null){
- newnode = scan_text(textcursor,m_strlen,&newlength);
- newnode->type = tag_text;
- }else{
- newnode = scan_tag(textcursor,m_strlen,&newlength);
- newnode->type = ttype;
- }
- tokencursor->next = newnode;
- textcursor += newlength;
- m_strlen -= newlength;
- tokencursor = newnode;
- }
- return first;
-}
-
-struct TMPL_tagnode*
-alloc_tagnode(){
- struct TMPL_tagnode* t = malloc(sizeof(struct TMPL_tagnode));
- return t;
-}
-
-/*Finds a quoted string, allows for \"*/
-size_t
-get_quoted_string(char* start, size_t len){
- size_t i;
- int setup = 0;
- for(i = 0; i < len; i++){
- if(*(start+i) == '\\'){
- setup = 1;
- }else if(*(start+i) == '"'){
- if(setup == 1){
- /*Do nothing, this is \"*/
- }else{
- return i;
- }
- }else{
- setup = 0;
- }
- }
- return i;
-}
-
-int
-is_whitespace(char c){
- return (c == ' ' || c == '\t' || c == '\n') ? 1 : 0;
-}
-
-struct TMPL_tagnode*
-parse_text(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* t = alloc_tagnode();
- t->TMPL_tag.text.start = head->start;
- t->TMPL_tag.text.len = head->length;
- t->type = head->type;
- struct TMPL_tagnode* n = parse(head->next, errbuf);
- t->next = n;
- return t;
-}
-
-struct TMPL_tagnode*
-parse_else(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* branch = parse(head->next,errbuf);
- return branch;
-}
-
-struct TMPL_tagnode*
-parse_elseif(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* t = alloc_tagnode();
- char* start_of_attribs = head->start + TAG_ELSEIF_LENGTH;
- int name_offset = kmp(start_of_attribs,head->length, ATTRIBUTE_VARNAME,ATTRIBUTE_VARNAME_LENGTH);
- char* start_of_name = start_of_attribs + name_offset + ATTRIBUTE_VARNAME_LENGTH;
- while(is_whitespace(*start_of_name))
- start_of_name++;
- if(*start_of_name != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_ELSEIF ...> after name near ");
- bputsn(errbuf,head->start, ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_name++;
- }
- while(is_whitespace(*start_of_name))
- start_of_name++;
- start_of_name++;//consume "
- size_t name_length = get_quoted_string(start_of_name,head->length);
- char* name = (char*)malloc(sizeof(char)*name_length);
- memcpy(name,start_of_name,name_length);
- name[name_length] = '\0';
- t->TMPL_tag.ifelse.varname = name;
-
- int testval_offset = kmp(start_of_attribs,head->length, ATTRIBUTE_VALUE,ATTRIBUTE_VALUE_LENGTH);
- if(testval_offset == -1){
- t->TMPL_tag.ifelse.testval = NULL;
- }else{
- char* start_of_value = start_of_attribs + testval_offset + ATTRIBUTE_VALUE_LENGTH;
- while(is_whitespace(*start_of_value))
- start_of_value++;
- if(*start_of_value != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_ELSEIF ...> after value near ");
- bputsn(errbuf,head->start,ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_value++;//consume =
- }
- while(is_whitespace(*start_of_value))
- start_of_value++;
- start_of_value++;//consume "
- size_t value_length = get_quoted_string(start_of_value,head->length);
- char* value = (char*)malloc(sizeof(char)*value_length);
- memcpy(value,start_of_value,value_length);
- value[value_length] = '\0';
- t->TMPL_tag.ifelse.testval = value;
- }
- struct TMPL_token* cursor = head->next;
- int nest_level = 0;
- struct TMPL_token* fstart = NULL;
- while(nest_level > 0 || cursor->type != tag_end){
- if(fstart == NULL){
- if(cursor->type == tag_elseif){
- fstart = cursor;
- }else if(cursor->type == tag_else){
- fstart = cursor;
- }
- }
- if(cursor->type == tag_if || cursor->type == tag_loop){
- nest_level++;
- }else if(cursor->type == tag_end){
- nest_level--;
- }
- cursor = cursor->next;
- }
- if(fstart != NULL){
- if(fstart->type == tag_elseif){
- t->TMPL_tag.ifelse.fbranch = parse_elseif(fstart,errbuf);
- }else if(fstart->type == tag_else){
- t->TMPL_tag.ifelse.fbranch = parse_else(fstart,errbuf);
- }else{
- t->TMPL_tag.ifelse.fbranch = parse(fstart,errbuf);
- }
- }else{
- t->TMPL_tag.ifelse.fbranch = NULL;
- }
-
- t->TMPL_tag.ifelse.tbranch = parse(head->next,errbuf);
- t->next = parse(cursor->next,errbuf);
-
- t->type = tag_elseif;
- return t;
-
-}
-
-struct TMPL_tagnode*
-parse_if(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* t = alloc_tagnode();
- char* start_of_attribs = head->start + TAG_IF_LENGTH;
- /*Find the name of the varialbe*/
- int name_offset = kmp(start_of_attribs,head->length,ATTRIBUTE_VARNAME,ATTRIBUTE_VARNAME_LENGTH);
- char* start_of_name = start_of_attribs + name_offset + ATTRIBUTE_VARNAME_LENGTH;
- while(is_whitespace(*start_of_name))
- start_of_name++;
- if(*start_of_name != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_IF ...> after name near ");
- bputsn(errbuf, head->start, ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_name++;
- }
- while(is_whitespace(*start_of_name))
- start_of_name++;
- start_of_name++;//consume "
- size_t name_length = get_quoted_string(start_of_name,head->length);
- char* name = (char*)malloc(sizeof(char)*name_length);
- memcpy(name,start_of_name,name_length);
- name[name_length] = '\0';
- t->TMPL_tag.ifelse.varname = name;
- /*Find the name to check against*/
- int testval_offset = kmp(start_of_attribs,head->length, ATTRIBUTE_VALUE,ATTRIBUTE_VALUE_LENGTH);
- if(testval_offset == -1){
- t->TMPL_tag.ifelse.testval = NULL;
- }else{
- char* start_of_value = start_of_attribs + testval_offset + ATTRIBUTE_VALUE_LENGTH;
- while(is_whitespace(*start_of_value))
- start_of_value++;
- if(*start_of_value != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_IF/TMPL_ELSEIF ...> after value near ");
- bputsn(errbuf,head->start,ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_value++;
- }
- while(is_whitespace(*start_of_value))
- start_of_value++;
- start_of_value++;//consume "
- size_t value_length = get_quoted_string(start_of_value,head->length);
- char* value = (char*)malloc(sizeof(char)*value_length);
- memcpy(value,start_of_value,value_length);
- value[value_length] = '\0';
- t->TMPL_tag.ifelse.testval = value;
- }
- /*Find the true branch*/
- struct TMPL_token* cursor = head->next;
- int nest_level = 0;
- struct TMPL_token* fstart = NULL;
- while(nest_level > 0 || cursor->type != tag_end){
- if(fstart == NULL){
- if(cursor->type == tag_elseif){
- fstart = cursor;
- }else if(cursor->type == tag_else){
- fstart = cursor;
- }
- }
- if(cursor->type == tag_if || cursor->type == tag_loop){
- nest_level++;
- }else if(cursor->type == tag_end){
- nest_level--;
- }
- cursor = cursor->next;
- }
- if(fstart != NULL){
- if(fstart->type == tag_elseif){
- t->TMPL_tag.ifelse.fbranch = parse_elseif(fstart,errbuf);
- }else if(fstart->type == tag_else){
- t->TMPL_tag.ifelse.fbranch = parse_else(fstart,errbuf);
- }else{
- t->TMPL_tag.ifelse.fbranch = parse(fstart,errbuf);
- }
- }else{
- t->TMPL_tag.ifelse.fbranch = NULL;
- }
-
- t->TMPL_tag.ifelse.tbranch = parse(head->next,errbuf);
- /*Walk the tbranch and try to find if we have elseifs*/
- t->next = parse(cursor->next,errbuf);
-
- t->type = tag_if;
- return t;
-}
-
-
-struct TMPL_tagnode*
-parse_loop(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* t = alloc_tagnode();
- char* loop_start = head->start + TAG_LOOP_LENGTH;
- int loop_length = head->length - TAG_LOOP_LENGTH;
- int name_offset = kmp(loop_start,loop_length, ATTRIBUTE_VARNAME, ATTRIBUTE_VARNAME_LENGTH);
- if(name_offset == -1 && DEBUGGING){
- bputs(errbuf,"Parsing error: Could not find name attribute for loop near\n");
- bputsn(errbuf,head->start, ERRBUF_HINTLEN);
- return NULL;
- }
- if(name_offset >= 0){
- char* start_of_name = loop_start + name_offset + ATTRIBUTE_VARNAME_LENGTH;
- while(is_whitespace(*start_of_name))
- start_of_name++;
- if(*start_of_name != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_LOOP ...> after name near ");
- bputsn(errbuf, head->start, ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_name++;//consume '='
- }
- while(is_whitespace(*start_of_name))
- start_of_name++;
- start_of_name++;//consume "
- size_t name_size = get_quoted_string(start_of_name,head->length);
- char* loopname = (char*)malloc(sizeof(char)*name_size);
- memcpy(loopname,start_of_name,name_size);
- loopname[name_size] = '\0';
- t->TMPL_tag.loop.loopname = loopname;
-
- }
- t->type = tag_loop;
- int nest_level = 0;
- struct TMPL_token* cursor = head->next;
- while(cursor != NULL && (nest_level > 0 || cursor->type != tag_end)){
- if(cursor == NULL){
- bputs(errbuf,"Parse error : tried parsing loop and hit end of stream near\n");
- bputsn(errbuf,head->start,ERRBUF_HINTLEN);
- return NULL;
- }
- if(cursor->type == tag_if ||
- cursor->type == tag_loop){
- nest_level++;
- }else if(cursor->type == tag_end){
- nest_level--;
- }
- cursor = cursor->next;
- }
- if(cursor == NULL){
- bputs(errbuf,"Parse error: Tried parsing loop and hit end of stream near\n");
- bputsn(errbuf,head->start,ERRBUF_HINTLEN);
- return NULL;
- }
- t->TMPL_tag.loop.body = parse(head->next,errbuf);
- t->next = parse(cursor->next,errbuf);
- return t;
-}
-
-/*Parses the <TMPL_VAR ...> tokens*/
-struct TMPL_tagnode*
-parse_variable(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* t = alloc_tagnode();
- /*<TMPL_VAR name="..." default="...">
- ^*/
- char* start_of_attribs = head->start + TAG_VAR_LENGTH;
- /*Find the length of attributes*/
- int attribs_length = head->length - TAG_VAR_LENGTH;
- /*Find where the "name" attribute is*/
- int in_name = kmp(start_of_attribs,attribs_length,ATTRIBUTE_VARNAME,ATTRIBUTE_VARNAME_LENGTH);
- /*Find where the "default" attribute is*/
- int in_default = kmp(start_of_attribs,attribs_length,ATTRIBUTE_DEFAULT,ATTRIBUTE_DEFAULT_LENGTH);
- if(in_name == -1){
- bputs(errbuf,"Parsing error: Could not find \"name\" field in <TMPL_VAR ...> near ");
- bputsn(errbuf,head->start,ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }
- if(in_name >= 0){
- char* start_of_name = start_of_attribs + in_name + ATTRIBUTE_VARNAME_LENGTH;
- while(is_whitespace(*start_of_name))
- start_of_name++;
- if(*start_of_name != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_VAR ...> after name near ");
- bputsn(errbuf,head->start, ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_name++;//consume =
- }
- while(is_whitespace(*start_of_name))
- start_of_name++;
- start_of_name++; //consume "
- size_t name_size = get_quoted_string(start_of_name,head->length);
- char* name = (char*)malloc(sizeof(char)*name_size);
- memcpy(name,start_of_name,name_size);
- name[name_size] = '\0';
- t->TMPL_tag.var.varname = name;
- t->TMPL_tag.var.name_len = name_size;
- }
- if(in_default >= 0){
- char* start_of_default = start_of_attribs + in_default + ATTRIBUTE_DEFAULT_LENGTH;
- while(is_whitespace(*start_of_default))
- start_of_default++;
- if(*start_of_default != '='){
- bputs(errbuf,"Parsing error: Expected \"=\" in <TMPL_VAR ...> after default near ");
- bputsn(errbuf,head->start, ERR_MSG_LEN);
- bputs(errbuf,"\n");
- }else{
- start_of_default++;//consume =
- }
- while(is_whitespace(*start_of_default))
- start_of_default++;
- start_of_default++; //consume "
- size_t default_size = get_quoted_string(start_of_default,head->length);
- char* def = (char*) malloc(sizeof(char)*default_size);
- def[default_size] = '\0';
- memcpy(def,start_of_default,default_size);
- t->TMPL_tag.var.defaultval = def;
- t->TMPL_tag.var.default_len = default_size;
- }else{
- t->TMPL_tag.var.default_len = 0;
- }
- t->type = tag_var;
- t->next = parse(head->next,errbuf);
- return t;
-}
-
-struct TMPL_varlist*
-TMPL_alloc_varlist(){
- struct TMPL_varlist* ret = (struct TMPL_varlist*)malloc(sizeof(struct TMPL_varlist));
- ret->map = hashmap_new();
- return ret;
-}
-
-
-int
-TMPL_free_hashmapitems(any_t a, any_t b){
- struct TMPL_varitem* vi = (struct TMPL_varitem*)b;
- TMPL_free_varitem(vi);
- return MAP_OK;
-}
-
-void
-TMPL_free_varlist(struct TMPL_varlist* vl){
- hashmap_iterate(vl->map,TMPL_free_hashmapitems,NULL);
- hashmap_free(vl->map);
- free(vl);
-}
-
-struct TMPL_loop*
-TMPL_alloc_loop(){
- struct TMPL_loop* ret = (struct TMPL_loop*)malloc(sizeof(struct TMPL_loop));
- ret->loop_len = 0;
- ret->varlist = NULL;
- ret->next = NULL;
- ret->tail = NULL;
- return ret;
-}
-
-void
-TMPL_free_loop(struct TMPL_loop* tl){
- if(tl->next != NULL){
- TMPL_free_loop(tl->next);
- }
- if(tl->varlist != NULL)
- TMPL_free_varlist(tl->varlist);
- free(tl);
-}
-
-void TMPL_add_varlist_to_loop(struct TMPL_loop* tl,struct TMPL_varlist* vl){
- if(tl->loop_len == 0){/*Add the first node*/
- tl->varlist = vl;
- tl->tail = tl;
- tl->loop_len++;
- }else{
- struct TMPL_loop* new = TMPL_alloc_loop();
- new->varlist = vl;
- tl->tail->next = new;
- tl->tail = new;
- }
-}
-
-void
-TMPL_add_loop_to_varlist(struct TMPL_varlist* vl, char* name, struct TMPL_loop* l){
- struct TMPL_varitem* vi = TMPL_alloc_varitem();
- vi->type = vartype_loop;
- vi->item.l = l;
- int err = hashmap_put(vl->map,name,vi);
- if(err != MAP_OK){
- }
- struct TMPL_varitem* back;
- hashmap_get(vl->map,name,(void**)&back);
-}
-
-
-
-/*Parses tokens into a syntax tree*/
-struct TMPL_tagnode*
-parse(struct TMPL_token* head, struct TMPL_buf* errbuf){
- struct TMPL_tagnode* root;
- if(head == NULL){
- return NULL;
- }
- switch(head->type){
- case tag_text:
- root = parse_text(head,errbuf);
- break;
- case tag_var:
- root = parse_variable(head,errbuf);
- break;
- case tag_loop:
- root = parse_loop(head,errbuf);
- break;
- case tag_end:
- root = NULL;
- break;
- case tag_if:
- root = parse_if(head,errbuf);
- break;
- case tag_elseif:
- root = NULL;
- break;
- case tag_else:
- root = NULL;
- break;
- default:
- exit(-1);
- break;
- }
- if(errbuf->total_len > 0){
- return NULL;
- }
- return root;
-}
-
-struct TMPL_templates*
-alloc_templates(){
- struct TMPL_templates* t = malloc(sizeof(struct TMPL_templates));
- return t;
-}
-
-struct TMPL_templates*
-compile(char* tmplstr){
- size_t slen = strlen(tmplstr);
- struct TMPL_templates* ret = alloc_templates();
- ret->out = alloc_tmpl_buf();
- ret->errout = alloc_tmpl_buf();
- struct TMPL_token* tokens = TMPL_tokenize(tmplstr,slen);
- struct TMPL_tagnode* ast = parse(tokens,ret->errout);
- if(ast == NULL){
- //size_t dummy;
- //printf("error: %s\n",bstringify(ret->errout,&dummy));
- }else{
- ret->roottag = ast;
- }
- return ret;
-}
-
-
-int
-render_variable(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- struct TMPL_varitem* vi;
- char* varname = node->TMPL_tag.var.varname;
- int err = hashmap_get(varlist->map,varname,(void**)&vi);
- if(err == MAP_OK){
- bputs(t->out,vi->item.s);
- }else if(err == MAP_MISSING){
- size_t has_default = node->TMPL_tag.var.default_len;
- if(has_default){
- bputs(t->out,node->TMPL_tag.var.defaultval);
- }else{
- /*Error, not bound and no default*/
- return -1;
- }
- }else{
- return -1;
- }
- return 0;
-}
-
-int
-render_text(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- struct TMPL_buf* buf = t->out;
- char* text = (char*)node->TMPL_tag.text.start;
- size_t length = node->TMPL_tag.text.len;
- bputsn(buf,text,length);
- return 0;
-}
-
-int
-print_pair(any_t indent, any_t b){
- struct TMPL_varitem* vi = (struct TMPL_varitem*)b;
- printf("Print pair, varitem is %p, type is %d\n",(void*)vi,(int)vi->type);
- int* ip = (int*)indent;
- int ind = *ip;
- if(vi->type == vartype_var){
- int i;
- for(i = 0; i < ind; i++)
- printf("\t");
- printf("%s\n",vi->item.s);
- }else{
- struct TMPL_loop* cursor;
- printf("{\n");
- ind++;
- /*If the loop doesn't have any varlists added, the cursor's varlist will be null*/
- for(cursor = vi->item.l; cursor != NULL && cursor->varlist != NULL; cursor = cursor->next){
- printf("First iteration though, cursor was %p\n",(void*)cursor);
- print_varlist_helper(cursor->varlist,ind);
- }
- printf("}\n");
- }
- return MAP_OK;
-}
-
-void
-print_varlist_helper(struct TMPL_varlist* vl, int indent){
- hashmap_iterate(vl->map, print_pair,&indent);
-}
-
-
-void
-print_varlist(struct TMPL_varlist* vl){
- print_varlist_helper(vl,0);
-}
-
-int
-render_if(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- char* varname = node->TMPL_tag.ifelse.varname;
- char* testval = node->TMPL_tag.ifelse.testval;
- struct TMPL_varitem* vi;
- int err = hashmap_get(varlist->map,varname,(void**)&vi);
- struct TMPL_tagnode* cursor;
- if(err == MAP_OK){
- if(testval == NULL || strcmp(vi->item.s, testval) == 0){
- cursor = node->TMPL_tag.ifelse.tbranch;
- while(cursor != NULL){
- render_any(t,cursor,varlist);
- cursor = cursor->next;
- }
-
- }else{
-
- }
-
- }else if(node->TMPL_tag.ifelse.fbranch != NULL){
- cursor = node->TMPL_tag.ifelse.fbranch;
- while(cursor != NULL){
- render_any(t,cursor,varlist);
- cursor = cursor->next;
- }
- }
- return 0;
-}
-
-/*Exactly the same thing as if*/
-int
-render_elseif(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- return render_if(t,node,varlist);
-}
-
-int
-resolve_name(struct TMPL_varlist* varlist, char* name,struct TMPL_varitem** item){
- return hashmap_get(varlist->map,name,(void*)item);
- /*
- struct TMPL_varlist* cursor = varlist;
- int err;
- do{
- err = hashmap_get(cursor->map,name,(void*)item);
- cursor = cursor->parent;
- }while(cursor != NULL && err == MAP_MISSING);
- if(err == MAP_MISSING){
- return MAP_MISSING;
- }
- return MAP_OK;
- */
-}
-
-int
-render_loop(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- char* loopname = node->TMPL_tag.loop.loopname;
- struct TMPL_varitem* loop;
- int err = resolve_name(varlist,loopname,&loop);
- if(err != MAP_OK){
- return -1;
- }
- struct TMPL_templates* nt = (struct TMPL_templates*)malloc(sizeof(struct TMPL_templates));
- nt->out = t->out;
- nt->errout = t->errout;
- nt->roottag = node->TMPL_tag.loop.body;
- struct TMPL_loop* cursor;
- /*If the loop has no items, it's varlist will be null*/
- for(cursor = loop->item.l; cursor != NULL && cursor->varlist != NULL; cursor = cursor->next){
- if(err != 0){
- }
- TMPL_render_helper(nt,cursor->varlist);
- }
- free(nt);
- return 0;
-}
-
-int
-render_any(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){
- /*Interpret the template*/
- int err;
- switch(node->type){
- case tag_text:
- err = render_text(t,node,varlist);
- if(err < 0){
- }
- break;
- case tag_var:
- err = render_variable(t,node,varlist);
- if(err < 0){
- }
- break;
- case tag_loop:
- err = render_loop(t,node,varlist);
- if(err < 0){
- }
- break;
- case tag_if:
- err = render_if(t,node,varlist);
- if(err < 0){
- }
- break;
- case tag_elseif:
- err = render_elseif(t,node,varlist);
- if(err < 0){
- }
- break;
- default:
- exit(-1);
- break;
- }
- return err;
-}
-
-void
-TMPL_render_helper(struct TMPL_templates* t, struct TMPL_varlist* varlist){
- struct TMPL_tagnode* cursor = t->roottag;
- while(cursor != NULL){
- render_any(t,cursor,varlist);
- cursor = cursor->next;
- }
-
-}
-
-char*
-TMPL_render(struct TMPL_templates* t, struct TMPL_varlist* varlist, size_t* size_p){
- if(t->out != NULL){
- free_tmpl_buf(t->out);
- }
- t->out = alloc_tmpl_buf();
- TMPL_render_helper(t,varlist);
- char* ret = bstringify(t->out,size_p);
- return ret;
-}
-
-struct TMPL_templates*
-TMPL_alloc_template(char* tmplstr){
- struct TMPL_templates* n = compile(tmplstr);
-
- if(n != NULL){
- return n;
- }else{
- TMPL_free_template(n);
- return NULL;
- }
-}
-
-void
-TMPL_free_template(struct TMPL_templates* t){
- free_tmpl_buf(t->out);
- free_tmpl_buf(t->errout);
- TMPL_free_tagnode(t->roottag);
- free(t);
-}
-
-void
-TMPL_free_tagnode(struct TMPL_tagnode* tn){
- switch(tn->type){
- case tag_text:
- break;
- case tag_var:
- free(tn->TMPL_tag.var.varname);
- if(tn->TMPL_tag.var.default_len > 0){
- free(tn->TMPL_tag.var.defaultval);
- }
- break;
- case tag_if:
- case tag_elseif:
- case tag_else:
- free(tn->TMPL_tag.ifelse.varname);
- if(tn->TMPL_tag.ifelse.testval != NULL)
- free(tn->TMPL_tag.ifelse.testval);
- TMPL_free_tagnode(tn->TMPL_tag.ifelse.tbranch);
- if(tn->TMPL_tag.ifelse.fbranch){
- TMPL_free_tagnode(tn->TMPL_tag.ifelse.fbranch);
- }
- break;
- case tag_loop:
- free(tn->TMPL_tag.loop.loopname);
- TMPL_free_tagnode(tn->TMPL_tag.loop.body);
- break;
- case tag_null:
- case tag_break:
- case tag_continue:
- case tag_end:
- break;
- }
- if(tn->next != NULL)
- TMPL_free_tagnode(tn->next);
- free(tn);
-}
-
-char*
-TMPL_get_error(struct TMPL_templates* t){
- size_t dummy;
- return bstringify(t->errout,&dummy);
-}