changeset 584:d35b9749eb26 v3.2

Merge branch 'tmpl-conditionals'
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Mon, 08 Jun 2015 23:13:51 -0400
parents d7bc8562f5db (current diff) 805b6e53e8fb (diff)
children c4bc73e34590
files config.cmake config.h.in post.c template.y
diffstat 15 files changed, 198 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/config.cmake	Mon Jun 08 22:19:28 2015 -0400
+++ b/config.cmake	Mon Jun 08 23:13:51 2015 -0400
@@ -34,6 +34,8 @@
 set_default(VAR_VAL_KEY_MAXLEN		32)
 set_default(VAR_NAME_MAXLEN		32)
 
+set_default(COND_STACK_DEPTH		10)
+
 set_default(TAGCLOUD_MIN_SIZE		6)
 set_default(TAGCLOUD_MAX_SIZE		18)
 
--- a/config.h.in	Mon Jun 08 22:19:28 2015 -0400
+++ b/config.h.in	Mon Jun 08 23:13:51 2015 -0400
@@ -31,6 +31,8 @@
 #cmakedefine VAR_VAL_KEY_MAXLEN		${VAR_VAL_KEY_MAXLEN}
 #cmakedefine VAR_NAME_MAXLEN		${VAR_NAME_MAXLEN}
 
+#cmakedefine COND_STACK_DEPTH		${COND_STACK_DEPTH}
+
 #cmakedefine TAGCLOUD_MIN_SIZE		${TAGCLOUD_MIN_SIZE}
 #cmakedefine TAGCLOUD_MAX_SIZE		${TAGCLOUD_MAX_SIZE}
 
--- a/index.c	Mon Jun 08 22:19:28 2015 -0400
+++ b/index.c	Mon Jun 08 23:13:51 2015 -0400
@@ -27,7 +27,7 @@
 	SQL_BIND_INT(stmt, 1, req->opts.index_stories);
 	SQL_BIND_INT(stmt, 2, page * req->opts.index_stories);
 
-	load_posts(req, stmt);
+	load_posts(req, stmt, req->opts.index_stories);
 
 	SQL_END(stmt);
 }
@@ -58,7 +58,7 @@
 	SQL_BIND_INT(stmt, 3, req->opts.index_stories);
 	SQL_BIND_INT(stmt, 4, page * req->opts.index_stories);
 
-	load_posts(req, stmt);
+	load_posts(req, stmt, req->opts.index_stories);
 
 	SQL_END(stmt);
 }
@@ -71,6 +71,7 @@
 static void __store_pages(struct vars *vars, int page)
 {
 	vars_set_int(vars, "prevpage", page + 1);
+	vars_set_int(vars, "curpage",  page);
 	vars_set_int(vars, "nextpage", page - 1);
 }
 
--- a/parse.h	Mon Jun 08 22:19:28 2015 -0400
+++ b/parse.h	Mon Jun 08 23:13:51 2015 -0400
@@ -3,6 +3,7 @@
 
 #include "req.h"
 #include "post.h"
+#include "error.h"
 #include "str.h"
 
 struct parser_output {
@@ -17,6 +18,10 @@
 	size_t len;
 	size_t pos;
 	int lineno;
+
+	/* template related */
+	bool cond_stack[COND_STACK_DEPTH];
+	int cond_stack_use;
 };
 
 typedef void* yyscan_t;
@@ -30,4 +35,31 @@
 extern int fmt3_lex_init(yyscan_t* scanner);
 extern int tmpl_lex_init(yyscan_t* scanner);
 
+static inline bool cond_value(struct parser_output *data)
+{
+	return ((data->cond_stack_use == -1) ||
+		data->cond_stack[data->cond_stack_use]);
+}
+
+static inline void cond_if(struct parser_output *data, bool val)
+{
+	ASSERT3S(data->cond_stack_use, <, COND_STACK_DEPTH);
+
+	data->cond_stack[++data->cond_stack_use] = val;
+}
+
+static inline void cond_else(struct parser_output *data)
+{
+	ASSERT3S(data->cond_stack_use, >=, 0);
+
+	data->cond_stack[data->cond_stack_use] = !data->cond_stack[data->cond_stack_use];
+}
+
+static inline void cond_endif(struct parser_output *data)
+{
+	ASSERT3S(data->cond_stack_use, >=, 0);
+
+	data->cond_stack_use--;
+}
+
 #endif
--- a/post.c	Mon Jun 08 22:19:28 2015 -0400
+++ b/post.c	Mon Jun 08 23:13:51 2015 -0400
@@ -431,7 +431,7 @@
  *     post id
  *     post time
  */
-void load_posts(struct req *req, sqlite3_stmt *stmt)
+void load_posts(struct req *req, sqlite3_stmt *stmt, int expected)
 {
 	nvlist_t **posts;
 	uint_t nposts;
@@ -466,6 +466,7 @@
 
 	vars_set_nvl_array(&req->vars, "posts", posts, nposts);
 	vars_set_int(&req->vars, "lastupdate", maxtime);
+	vars_set_int(&req->vars, "moreposts", nposts == expected);
 
 	for (i = 0; i < nposts; i++)
 		nvlist_free(posts[i]);
--- a/post.h	Mon Jun 08 22:19:28 2015 -0400
+++ b/post.h	Mon Jun 08 23:13:51 2015 -0400
@@ -68,7 +68,7 @@
 extern nvlist_t *load_post(struct req *req, int postid, const char *titlevar, bool preview);
 extern void dump_post(struct post_old *post);
 extern void destroy_post(struct post *post);
-extern void load_posts(struct req *req, sqlite3_stmt *stmt);
+extern void load_posts(struct req *req, sqlite3_stmt *stmt, int expected);
 
 #define max(a,b)	((a)<(b)? (b) : (a))
 
--- a/render.c	Mon Jun 08 22:19:28 2015 -0400
+++ b/render.c	Mon Jun 08 23:13:51 2015 -0400
@@ -23,6 +23,8 @@
 	x.len   = strlen(str);
 	x.pos   = 0;
 
+	x.cond_stack_use = -1;
+
 	tmpl_lex_init(&x.scanner);
 	tmpl_set_extra(&x, x.scanner);
 
--- a/tag.c	Mon Jun 08 22:19:28 2015 -0400
+++ b/tag.c	Mon Jun 08 23:13:51 2015 -0400
@@ -69,6 +69,7 @@
 static void __store_pages(struct vars *vars, int page)
 {
 	vars_set_int(vars, "prevpage", page + 1);
+	vars_set_int(vars, "curpage",  page);
 	vars_set_int(vars, "nextpage", page - 1);
 }
 
@@ -91,7 +92,7 @@
 	SQL_BIND_INT(stmt, 2, req->opts.index_stories);
 	SQL_BIND_INT(stmt, 3, page * req->opts.index_stories);
 
-	load_posts(req, stmt);
+	load_posts(req, stmt, req->opts.index_stories);
 
 	SQL_END(stmt);
 }
--- a/template.l	Mon Jun 08 22:19:28 2015 -0400
+++ b/template.l	Mon Jun 08 23:13:51 2015 -0400
@@ -20,7 +20,7 @@
 %}
 
 %%
-[{}|%]			{ return *yytext; }
+[{}|%(),]		{ return *yytext; }
 [A-Za-z0-9_]+		{ yylval->ptr = xstrdup(yytext); return WORD; }
 [ \r\t]			{ yylval->c = *yytext; return CHAR; }
 \n			{
--- a/template.y	Mon Jun 08 22:19:28 2015 -0400
+++ b/template.y	Mon Jun 08 23:13:51 2015 -0400
@@ -41,6 +41,16 @@
 	return ret;
 }
 
+static char *condconcat(struct parser_output *data, char *a, char *b)
+{
+	if (!cond_value(data)) {
+		free(b);
+		return a;
+	}
+
+	return concat(a, b);
+}
+
 static char *__foreach_nv(struct req *req, nvpair_t *var, char *tmpl)
 {
 	nvlist_t **items;
@@ -93,11 +103,15 @@
 	return out;
 }
 
-char *foreach(struct req *req, char *varname, char *tmpl)
+static char *foreach(struct parser_output *data, struct req *req, char *varname,
+                     char *tmpl)
 {
 	nvpair_t *var;
 	char *ret;
 
+	if (!cond_value(data))
+		return xstrdup("");
+
 	var = vars_lookup(&req->vars, varname);
 	if (!var)
 		return xstrdup("");
@@ -161,13 +175,19 @@
 	return xstrdup(tmp);
 }
 
-static char *pipeline(struct req *req, char *varname, struct pipeline *line)
+static char *pipeline(struct parser_output *data, struct req *req,
+		      char *varname, struct pipeline *line)
 {
 	struct pipestage *cur;
 	struct val *val;
 	nvpair_t *var;
 	char *out;
 
+	if (!cond_value(data)) {
+		pipeline_destroy(line);
+		return xstrdup("");
+	}
+
 	var = vars_lookup(&req->vars, varname);
 	if (!var) {
 		pipeline_destroy(line);
@@ -200,6 +220,95 @@
 
 	return out;
 }
+
+static char *variable(struct parser_output *data, struct req *req, char *name)
+{
+	nvpair_t *var;
+
+	if (!cond_value(data))
+		return xstrdup("");
+
+	var = vars_lookup(&req->vars, name);
+
+	if (!var)
+		return render_template(req, name);
+	else
+		return print_var(var);
+}
+
+enum if_fxns {
+	IFFXN_GT,
+	IFFXN_LT,
+	IFFXN_EQ,
+};
+
+static uint64_t __function_get_arg(struct req *req, const char *arg)
+{
+	nvpair_t *var;
+	uint64_t val;
+
+	if (!str2u64(arg, &val))
+		return val;
+
+	var = vars_lookup(&req->vars, arg);
+	if (!var)
+		return 0;
+
+	switch (nvpair_type(var)) {
+		case DATA_TYPE_UINT64:
+			return pair2int(var);
+		default:
+			ASSERT(0);
+	}
+}
+
+static char *__function(struct parser_output *data, struct req *req,
+			enum if_fxns fxn, const char *sa1,
+			const char *sa2)
+{
+	uint64_t ia1, ia2;		/* int value of saX */
+	bool result = true;
+
+	ia1 = __function_get_arg(req, sa1);
+	ia2 = __function_get_arg(req, sa2);
+
+	switch (fxn) {
+		case IFFXN_GT:
+			result = ia1 > ia2;
+			break;
+		case IFFXN_LT:
+			result = ia1 < ia2;
+			break;
+		case IFFXN_EQ:
+			result = ia1 == ia2;
+			break;
+	}
+
+	cond_if(data, result);
+
+	return xstrdup(NULL);
+}
+
+static char *function(struct parser_output *data, struct req *req,
+                      const char *fxn, const char *sa1, const char *sa2)
+{
+	if (!strcmp(fxn, "ifgt")) {
+		return __function(data, req, IFFXN_GT, sa1, sa2);
+	} else if (!strcmp(fxn, "iflt")) {
+		return __function(data, req, IFFXN_LT, sa1, sa2);
+	} else if (!strcmp(fxn, "ifeq")) {
+		return __function(data, req, IFFXN_EQ, sa1, sa2);
+	} else if (!strcmp(fxn, "endif")) {
+		cond_endif(data);
+	} else if (!strcmp(fxn, "else")) {
+		cond_else(data);
+	} else {
+		LOG("unknown template function '%s'", fxn);
+		ASSERT(0);
+	}
+
+	return xstrdup(NULL);
+}
 %}
 
 %union {
@@ -221,33 +330,40 @@
 page : words					{ data->output = $1; }
      ;
 
-words : words CHAR				{ $$ = concat($1, tostr($2)); }
-      | words WORD				{ $$ = concat($1, $2); }
-      | words '|'				{ $$ = concat($1, xstrdup("|")); }
-      | words '%'				{ $$ = concat($1, xstrdup("%")); }
+words : words CHAR				{ $$ = condconcat(data, $1, tostr($2)); }
+      | words WORD				{ $$ = condconcat(data, $1, $2); }
+      | words '|'				{ $$ = condconcat(data, $1, xstrdup("|")); }
+      | words '%'				{ $$ = condconcat(data, $1, xstrdup("%")); }
+      | words '('				{ $$ = condconcat(data, $1, xstrdup("(")); }
+      | words ')'				{ $$ = condconcat(data, $1, xstrdup(")")); }
+      | words ','				{ $$ = condconcat(data, $1, xstrdup(",")); }
       | words cmd				{ $$ = concat($1, $2); }
       |						{ $$ = xstrdup(""); }
       ;
 
 cmd : '{' WORD pipeline '}'		{
-						$$ = pipeline(data->req, $2, $3);
+						$$ = pipeline(data, data->req, $2, $3);
 						free($2);
 					}
     | '{' WORD '%' WORD '}'		{
-						$$ = foreach(data->req, $2, $4);
+						$$ = foreach(data, data->req, $2, $4);
 						free($2);
 						free($4);
 					}
+    | '{' WORD '(' WORD ',' WORD ')' '}'{
+						$$ = function(data, data->req, $2, $4, $6);
+						free($2);
+					}
+    | '{' WORD '(' WORD ')' '}'		{
+						$$ = function(data, data->req, $2, $4, NULL);
+						free($2);
+					}
+    | '{' WORD '(' ')' '}'		{
+						$$ = function(data, data->req, $2, NULL, NULL);
+						free($2);
+					}
     | '{' WORD '}'			{
-						nvpair_t *var;
-
-						var = vars_lookup(&data->req->vars, $2);
-
-						if (!var)
-							$$ = render_template(data->req, $2);
-						else
-							$$ = print_var(var);
-
+						$$ = variable(data, data->req, $2);
 						free($2);
 					}
     ;
--- a/web/templates/html/archivepager.tmpl	Mon Jun 08 22:19:28 2015 -0400
+++ b/web/templates/html/archivepager.tmpl	Mon Jun 08 23:13:51 2015 -0400
@@ -1,4 +1,8 @@
 <div class="navigation">
+	{ifeq(moreposts,1)}
 	<div class="alignleft"><a href="?m={archid}&amp;paged={prevpage}">&laquo; Older Entries</a></div>
+	{endif()}
+	{ifgt(curpage,0)}
 	<div class="alignright"><a href="?m={archid}&amp;paged={nextpage}">Newer Entries &raquo;</a></div>
+	{endif()}
 </div>
--- a/web/templates/html/catpager.tmpl	Mon Jun 08 22:19:28 2015 -0400
+++ b/web/templates/html/catpager.tmpl	Mon Jun 08 23:13:51 2015 -0400
@@ -1,4 +1,8 @@
 <div class="navigation">
+	{ifeq(moreposts,1)}
 	<div class="alignleft"><a href="?cat={tagid}&amp;paged={prevpage}">&laquo; Older Entries</a></div>
+	{endif()}
+	{ifgt(curpage,0)}
 	<div class="alignright"><a href="?cat={tagid}&amp;paged={nextpage}">Newer Entries &raquo;</a></div>
+	{endif()}
 </div>
--- a/web/templates/html/fullstory.tmpl	Mon Jun 08 22:19:28 2015 -0400
+++ b/web/templates/html/fullstory.tmpl	Mon Jun 08 23:13:51 2015 -0400
@@ -1,9 +1,11 @@
 {story}
 <h2>{numcom} Comments <a href="#respond" title="Leave a comment">&raquo;</a></h2>
 
+{ifgt(numcom,0)}
 <ol id="commentlist">
 {comments%comment}
 </ol>
+{endif()}
 
 <p><a href='{baseurl}/?p={id}&amp;feed=atom'>Atom feed for comments on this post.</a></p>
 
--- a/web/templates/html/indexpager.tmpl	Mon Jun 08 22:19:28 2015 -0400
+++ b/web/templates/html/indexpager.tmpl	Mon Jun 08 23:13:51 2015 -0400
@@ -1,4 +1,8 @@
 <div class="navigation">
+	{ifeq(moreposts,1)}
 	<div class="alignleft"><a href="?paged={prevpage}">&laquo; Older Entries</a></div>
+	{endif()}
+	{ifgt(curpage,0)}
 	<div class="alignright"><a href="?paged={nextpage}">Newer Entries &raquo;</a></div>
+	{endif()}
 </div>
--- a/web/templates/html/tagpager.tmpl	Mon Jun 08 22:19:28 2015 -0400
+++ b/web/templates/html/tagpager.tmpl	Mon Jun 08 23:13:51 2015 -0400
@@ -1,4 +1,8 @@
 <div class="navigation">
+	{ifeq(moreposts,1)}
 	<div class="alignleft"><a href="?tag={tagid}&amp;paged={prevpage}">&laquo; Older Entries</a></div>
+	{endif()}
+	{ifgt(curpage,0)}
 	<div class="alignright"><a href="?tag={tagid}&amp;paged={nextpage}">Newer Entries &raquo;</a></div>
+	{endif()}
 </div>