diff options
| -rw-r--r-- | Makefile | 29 | ||||
| -rw-r--r-- | README.html | 420 | ||||
| -rw-r--r-- | README.md | 20 | ||||
| -rw-r--r-- | ctemplates.c (renamed from ctemplate.c) | 21 | ||||
| -rw-r--r-- | ctemplates.h (renamed from ctemplate.h) | 0 | ||||
| -rw-r--r-- | ctemplates_i.h (renamed from ctemplate_i.h) | 2 |
6 files changed, 474 insertions, 18 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8880d3e --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +CFLAGS = -I. -L. -std=c99 -pedantic -Wall -Werror -O3 +CC = gcc +LIBNAME = libctemplates.a + +$(LIBNAME): ctemplates.o fbuf.o kmp.o hashmap.o + ar rc $(LIBNAME) ctemplates.o fbuf.o kmp.o hashmap.o + ranlib $(LIBNAME) + +fbuf.o : fbuf.c fbuf.h + $(CC) $(CFLAGS) -c -o fbuf.o fbuf.c + +kmp.o : kmp.c kmp.h + $(CC) $(CFLAGS) -c -o kmp.o kmp.c + +ctemplates.o: ctemplates.c ctemplates.h + $(CC) $(CFLAGS) -c -o ctemplates.o ctemplates.c + +hashmap.o: hashmap.c hashmap.h + $(CC) $(CFLAGS) -c -o hashmap.o hashmap.c + +clean: + rm -f *.o *.a template + +test: + cd t; ./test.sh + +install: $(LIBNAME) + cp $(LIBNAME) /usr/local/lib + cp ctemplates.h /usr/local/include/ diff --git a/README.html b/README.html new file mode 100644 index 0000000..f519ec9 --- /dev/null +++ b/README.html @@ -0,0 +1,420 @@ +<h1>C TemplateS</h1> + +<p>If you found this page using a search engine, you may be looking for the +original <a href="http://libctemplate.sourceforge.net">libctemplate</a> by Stephen C. Losen</p> + +<p>libctemplates is a template expander written for use with HTML. It's goals are +to be simple, versitile, and fast. This library started off as a +fork of libctemplate, but eventually became a total rewrite. libctemplate, +the original, was built primarily for cgi applications. libctemplate was +tightly coupled with file streams, while libctemplate<strong>S</strong> renders templates to +strings for use in any application, FastCGI or <a href="kore.io">Kore</a>, for example. +If you think libctemplates is missing a feature, feel free to suggest it to +<a href="mailto://alexandermpickering@gmail">alexandermpickering@gmail.com</a>, +or, even better, write it yourself and send the patch! You can find +instructions on createing and sending git patches <a href="http://cogarr.net/source/cgit.cgi/?p=about">here</a>.</p> + +<h2>Contents</h2> + +<ol> +<li><a href="#Installation">Installation</a></li> +<li><a href="#Usage">Usage</a></li> +<li><a href="#Quick%20refernce">Quick refrence</a></li> +<li><a href="#Examples">Examples</a></li> +</ol> + +<p><section id="Installation"></section></p> + +<h2>Installation</h2> + +<p>Run the make file. libctemplates should compile on any system with a c99 +complient c compiler. If you are on linux, run</p> + +<pre><code>make; make install +</code></pre> + +<p><section id="Usage"></section></p> + +<h2>Usage</h2> + +<p>Just include the ctemplates.h header and make sure you're linking against +libctemplates.a, for example:</p> + +<pre><code>gcc main.c -lctemplates +</code></pre> + +<p><section id="Quick refrence"></section></p> + +<h2>Quick refrence</h2> + +<h3>Structs</h3> + +<ul> +<li>struct TMPL_templates<br> +Holds a template</li> +<li>struct TMPL_varlist<br> +Holds a list of variables to be used when rendering a template +loops can be held in a varlist, and varlists can be held in loops.</li> +<li>struct TMPL_loop<br> +Used to defien things to loop through in a varlist.</li> +</ul> + +<h3>Functions</h3> + +<pre><code>struct TMPL_templates* TMPL_alloc_template(char* template_string) +</code></pre> + +<p>Creates a template from the given string. This can be pretty expensive +so try to only do it once for each template you need, and call render() +as many times as you need on that template.</p> + +<pre><code>void TMPL_free_template(struct TMPL_templates* template) +</code></pre> + +<p>Frees a previously allocated template.</p> + +<pre><code>struct TMPL_varlist* TMPL_alloc_varlist() +</code></pre> + +<p>Allocates a variable list that you can add variables and loops to.</p> + +<pre><code>void TMPL_free_varlist(struct TMPL_varlist* varlist) +</code></pre> + +<p>Frees a previously allocated varlist, and any loops that have been added.</p> + +<pre><code>struct TMPL_loop* TMPL_alloc_loop() +</code></pre> + +<p>Allocates a loop that you can add varlists to.</p> + +<pre><code>void TMPL_free_loop(struct TMPL_loop* loop) +</code></pre> + +<p>Frees a previously allocated loop, and any varlists that have been added.</p> + +<pre><code>void TMPL_add_var_to_varlist(struct TMPL_varlist* vl, char* name, char* value) +</code></pre> + +<p>Adds a variable to a variable list</p> + +<pre><code>void TMPL_add_loop_to_varlist(struct TMPL_varlist* vl,char* name,struct TMPL_loop* loop) +</code></pre> + +<p>Adds a loop to a varlist</p> + +<pre><code>void TMPL_add_varlist_to_loop(struct TMPL_loop* l, struct TMPL_varlist* vl) +</code></pre> + +<p>Adds a varlist that should be used one iteration through the loop</p> + +<pre><code>char* TMPL_render(struct TMPL_templates* t, struct TMPL_varlist* vl) +</code></pre> + +<p>Turns a template and varlist into a string. the returned char* should NOT be freed. The returned char* is only valid until TMPL_render() is called again. If you need it even after TMPL_render() is called, copy it.</p> + +<p><section id="Examples"></section></p> + +<h2>Examples</h2> + +<h3>Hello, World!</h3> + +<p>At it's most simple, libctemplates just copies whatever template you give it. +For example:</p> + +<p><em>main.c</em></p> + +<pre><code>#include <ctemplate.h> +#include <stdio.h> +#include <stdlib.h> + +char* template = "Hello, world!"; + +int main(){ + struct TMPL_templates* t = TMPL_alloc_template(template); + if(t == NULL){ + printf("Failed to compile\n"); + exit(-1); + } + struct TMPL_varlist* vl = TMPL_alloc_varlist(); + char* output = TMPL_render(t,vl); + printf("Output: %s\n",output); + TMPL_free_varlist(vl); + TMPL_free_template(t); + return 0; +} +</code></pre> + +<p><em>output</em></p> + +<pre><code>Output: Hello, world! +</code></pre> + +<h3>Variable substitution</h3> + +<p><em>template.html</em></p> + +<pre><code>Value is:<TMPL_VAR name="varname" default="optional default"> +</code></pre> + +<p><em>main.c</em></p> + +<pre><code>#include <ctemplate.h> + +int main(){ + /* + It usually helps to seperate the template from the + C code. It does mean to need to read in a file though. + Try to only call TMPL_alloc_template once for each + template you have, and then use TMPL_render() whenever + you need to use them. + */ + FILE* fp = fopen("template.html","r"); + if(fp == NULL){ + printf("Failed to open file!\n"); + exit(-1); + } + fseek(fp,0,SEEK_END); + size_t file_len = ftell(fp); + char template[file_len]; + fread(template,sizeof(char),file_len,fp); + + struct TMPL_templates* t; + struct TMPL_varlist* vl; + + /* + Render the template without a variable named "varname" + This will use the variable's default, if it has one. + If the variable has no default, and is not supplied a value, + it errors, and stores a message that can be retrived with + TMPL_get_error(...) + */ + t = TMPL_alloc_template(template); + vl = TMPL_alloc_varlist(); + char* without_variable = TMPL_render(t,vl); + printf("Without variable: %s\n",without_variable); + TMPL_free_template(t); + TMPL_free_varlist(vl); + + /* + Now render a template with a variable, use the + TMPL_add_var_to_varlist(...) to supply the template with + variables. + */ + t = TMPL_alloc_template(template); + vl = TMPL_alloc_varlist(); + TMPL_add_var_to_varlist(vl,"varname","Hello, world!"); + char* with_variable = TMPL_render(t,vl); + printf("With variable:%s\n",with_variable); + TMPL_free_template(t); + TMPL_free_varlist(vl); + + return 0; +} +</code></pre> + +<p><em>output</em></p> + +<pre><code>Without variable: +Value is:optional default + + +With variable: +Value is:Hello, world! +</code></pre> + +<h3>If/Elseif/Else</h3> + +<p>If and elseif statements check if strings are the same. They do a strcmp(), so be mindful not to use really long strings if you don't need them.</p> + +<p><em>template.html</em></p> + +<pre><code>What happened: +<TMPL_IF name="varname" value="1234"> + "varname" was "1234" +<TMPL_ELSEIF name="var2" value="pass"> + "var2" was "pass" +<TMPL_ELSE> + "varname" was not "1234", and "var2" was not "pass" +<TMPL_END> +</code></pre> + +<p><em>main.c</em></p> + +<pre><code>#include <stdlib.h> +#include <stdio.h> +#include <ctemplate.h> + +int main(){ + /* + Same as before, just read a file in + */ + FILE* fp = fopen("template.html","r"); + if(fp == NULL){ + printf("Failed to open file!\n"); + exit(-1); + } + fseek(fp,0,SEEK_END); + size_t file_len = ftell(fp); + rewind(fp); + char template[file_len]; + fread(template,sizeof(char),file_len,fp); + + /* + No need to rebuild the template each time, + just alloc it once. + */ + struct TMPL_templates* t = TMPL_alloc_template(template); + struct TMPL_varlist* vl; + + /* + If the variable the "if" or "elseif" is looking for dosn't exist, + the condition is considered false. + */ + vl = TMPL_alloc_varlist(); + char* without_variable = TMPL_render(t,vl); + printf("Without variable:\n%s\n",without_variable); + + /* + Add a variable to make the second condition true, and reprint + After we call TMPL_render() again, whatever pointer it returned + last time may have been freed. Be sure to copy it into your own + buffer if you still need it. + */ + TMPL_add_var_to_varlist(vl,"var2","pass"); + char* with_one = TMPL_render(t,vl); + printf("With 1 variable:\n%s\n",TMPL_render(t,vl)); + + /* + Always be sure to free things! + */ + TMPL_free_varlist(vl); + TMPL_free_template(t); + + return 0; +} +</code></pre> + +<p><em>output</em></p> + +<pre><code>Without variable: + +What happened: + + "varname" was not "1234", and "var2" was not "pass" + + + +With 1 variable: + +What happened: + + "var2" was "pass" +</code></pre> + +<p>Notice that the tabs in the template are preserved in the output. This is not +a minifier! Just a template expander!</p> + +<h3>Loops</h3> + +<p>Loops are special in libctemplates, loops each have their own namespace, and +only variables that have been added to the namespace are acessable in the loop.</p> + +<p><em>template.html</em></p> + +<pre><code>What happened: +<TMPL_LOOP name="myloop"> + This time through the loop, my variable is <TMPL_VAR name="loopvar"> +<TMPL_END> +</code></pre> + +<p><em>main.c</em></p> + +<pre><code>#include <stdlib.h> +#include <stdio.h> +#include <ctemplate.h> + +int main(){ + /* + Same as before + */ + FILE* fp = fopen("template.html","r"); + if(fp == NULL){ + printf("Failed to open file!\n"); + exit(-1); + } + fseek(fp,0,SEEK_END); + size_t file_len = ftell(fp); + rewind(fp); + char template[file_len]; + fread(template,sizeof(char),file_len,fp); + + /* + Same as before + */ + struct TMPL_templates* t = TMPL_alloc_template(template); + struct TMPL_varlist* vl = TMPL_alloc_varlist(); + + /* + Now create a loop variable and add some things to it. + This is usually not as verbose as it looks here, since you'll + usually do this in a C loop. + */ + struct TMPL_loop* loop = TMPL_alloc_loop(); + + struct TMPL_varlist* first = TMPL_alloc_varlist(); + TMPL_add_var_to_varlist(first,"loopvar","first"); + TMPL_add_varlist_to_loop(loop,first); + + struct TMPL_varlist* second = TMPL_alloc_varlist(); + TMPL_add_var_to_varlist(second,"loopvar","second"); + TMPL_add_varlist_to_loop(loop,second); + + struct TMPL_varlist* third = TMPL_alloc_varlist(); + TMPL_add_var_to_varlist(third,"loopvar","third"); + TMPL_add_varlist_to_loop(loop,third); + + /* + Remember to add the loop to the varlist you'll eventually + pass to TMPL_render() with the correct name. + */ + TMPL_add_loop_to_varlist(vl,"myloop",loop); + + char* output = TMPL_render(t,vl); + printf("Output:\n%s\n",output); + + /* + When freeing a varlist, any loops it has are automatically + also freed. When freeing a loop, any varlists it contains + are also automatically freed. This means you only need to + free your top-level varlist! + */ + TMPL_free_varlist(vl); + TMPL_free_template(t); +} +</code></pre> + +<p><em>output</em></p> + +<pre><code>Output: +What happened: +This time through the loop, my variable is first +This time through the loop, my variable is second +This time through the loop, my variable is theird +Done! +</code></pre> + +<!-- Some styleing, make it pretty! --> + +<style> +body,html{ + line-height:1.2; + font-size:18; + color:#333; +} +pre{ + background-color:#eee; + padding:10; + border-radius:5; +} +</style> @@ -4,15 +4,15 @@ If you found this page using a search engine, you may be looking for the original [libctemplate](http://libctemplate.sourceforge.net) by Stephen C. Losen libctemplates is a template expander written for use with HTML. It's goals are -to be simple, versitile, and fast. This is a library that started off as a +to be simple, versitile, and fast. This library started off as a fork of libctemplate, but eventually became a total rewrite. libctemplate, -the original, was built primarily for cgi applications. It was tightly coupled -with file streams, while libctemplate**s** allows you to output templates to -strings for use in any application. If you think libctemplates is missing a -feature, feel free to suggest it to +the original, was built primarily for cgi applications. libctemplate was +tightly coupled with file streams, while libctemplate**S** renders templates to +strings for use in any application, FastCGI or [Kore](kore.io), for example. +If you think libctemplates is missing a feature, feel free to suggest it to [alexandermpickering@gmail.com](mailto://alexandermpickering@gmail), or, even better, write it yourself and send the patch! You can find -instructions on createing and sending git patches [here](http://cogarr.net/source/cgit.cgi/?p=about) +instructions on createing and sending git patches [here](http://cogarr.net/source/cgit.cgi/?p=about). ## Contents @@ -27,13 +27,17 @@ instructions on createing and sending git patches [here](http://cogarr.net/sourc ## Installation Run the make file. libctemplates should compile on any system with a c99 -complient c compiler. If you are on linux, run `make; make install`. +complient c compiler. If you are on linux, run + + make; make install <section id="Usage"></section> ## Usage Just include the ctemplates.h header and make sure you're linking against -libctemplates.a +libctemplates.a, for example: + + gcc main.c -lctemplates <section id="Quick refrence"></section> ## Quick refrence diff --git a/ctemplate.c b/ctemplates.c index 291c6f9..77832e6 100644 --- a/ctemplate.c +++ b/ctemplates.c @@ -18,15 +18,17 @@ #include <stdio.h> #include <sys/stat.h> #include <stdarg.h> -#include <ctemplate_i.h> +#include <ctemplates_i.h> + void TMPL_free_loop(struct TMPL_loop* tl); +/*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){ @@ -38,7 +40,6 @@ void TMPL_free_token(struct TMPL_token* token){ /*Check if it starts with the names of any of our tokens*/ enum TMPL_tagtype starts_with_token(char* str, size_t strlen){ - //printf("hit starts_with_token, \"%s\"\n",str); //Make sure we get TMPL_ first if(strlen < 5){ return tag_null; @@ -48,16 +49,13 @@ enum TMPL_tagtype starts_with_token(char* str, size_t strlen){ || *(str + 2) != 'P' || *(str + 3) != 'L' || *(str + 4) != '_'){ - //printf("Didn't even start with tmpl_\n"); return tag_null; } - //printf("Did start with tmpl\n"); if(strlen > TAG_VAR_LENGTH && *(str + 5) == 'V' && *(str + 6) == 'A' && *(str + 7) == 'R' && *(str + 8) == ' '){ - //printf("Hit var\n"); return tag_var; }else if(strlen > TAG_IF_LENGTH && *(str + 5) == 'I' @@ -115,6 +113,7 @@ enum TMPL_tagtype starts_with_token(char* str, size_t strlen){ } } +/*Find the lenth of a tag*/ size_t tagtype_len(enum TMPL_tagtype t){ switch(t){ case tag_null: @@ -351,12 +350,12 @@ struct TMPL_tagnode* alloc_tagnode(){ //Finds a quoted string, allows for \" size_t get_quoted_string(char* start, size_t len){ size_t i; - int setup; + int setup = 0; for(i = 0; i < len; i++){ if(*(start+i) == '\\'){ setup = 1; }else if(*(start+i) == '"'){ - if( setup == 1){ + if(setup == 1){ //Do nothing, this is \" }else{ return i; @@ -869,7 +868,10 @@ int render_if(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_v 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); + /* char* varname = node->TMPL_tag.ifelse.varname; char* testval = node->TMPL_tag.ifelse.testval; struct TMPL_varitem* vi; @@ -893,7 +895,8 @@ int render_elseif(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TM } } return 0; -} + */ +} void TMPL_render_helper(struct TMPL_templates* t, struct TMPL_varlist* varlist); int render_loop(struct TMPL_templates* t, struct TMPL_tagnode* node, struct TMPL_varlist* varlist){ diff --git a/ctemplate.h b/ctemplates.h index 4479141..4479141 100644 --- a/ctemplate.h +++ b/ctemplates.h diff --git a/ctemplate_i.h b/ctemplates_i.h index b485298..0e76fc3 100644 --- a/ctemplate_i.h +++ b/ctemplates_i.h @@ -14,7 +14,7 @@ #include "fbuf.h" #include "kmp.h" #include "hashmap.h" -#include "ctemplate.h" +#include "ctemplates.h" #define MAX_TEMPLATE_LENGTH 2147384647 |
