2 some simple html template routines
3 Copyright (C) Andrew Tridgell 2001
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 static void process_tag(struct template_state *tmpl, const char *tag);
25 fetch a variable from the template variables list
27 static struct template_var *find_var(struct template_state *tmpl, const char *name)
29 struct template_var *var;
31 for (var = tmpl->variables; var; var = var->next) {
32 if (strcmp(var->name, name) == 0) {
40 add a name/value pair to the list of template variables
42 static void put(struct template_state *tmpl, const char *name,
43 const char *value, template_fn fn)
45 struct template_var *var;
46 if (!name || !value) return;
48 var = find_var(tmpl, name);
52 var = malloc(sizeof(*var));
53 var->next = tmpl->variables;
54 tmpl->variables = var;
55 var->name = strdup(name);
58 var->value = strdup(value);
61 /* fetch a variable from the template variables list */
62 static const char *get(struct template_state *tmpl, const char *name)
64 struct template_var *var;
66 var = find_var(tmpl, name);
67 if (var) return var->value;
73 /* process a template variable */
74 static void process_variable(struct template_state *tmpl, const char *tag)
76 const char *v = tmpl->get(tmpl, tag);
82 /* process setting a template variable */
83 static void process_set_var(struct template_state *tmpl, char *tag)
89 trim_tail(tag, " \t");
91 while (isspace(*p)) p++;
92 tmpl->put(tmpl, tag, p, NULL);
95 /* process a template variable with quote escaping */
96 static void process_escaped_variable(struct template_state *tmpl, const char *tag)
98 const char *v = tmpl->get(tmpl, tag);
109 /* process a inline shell script
110 all current template variables are passed to the script in the environment
111 recursively processes any tags in the output of the script
113 static void process_shell(struct template_state *tmpl, const char *tag, int recurse)
119 if ((pid=fork()) == 0) {
120 struct template_var *var;
125 for (var = tmpl->variables; var; var = var->next) {
126 setenv(var->name, var->value, 1);
131 printf("Failed to execute script\n");
134 while ((c = fgetc(p)) != EOF) {
137 tag1 = realloc(tag1, taglen+2);
138 tag1[taglen++] = c; tag1[taglen] = 0;
139 if (!recurse || strncmp(tag1, START_TAG, taglen) != 0) {
141 free(tag1); tag1 = NULL; taglen = 0;
144 if (strcmp(tag1, START_TAG) != 0) continue;
147 /* keep going until END_TAG */
148 while (depth && (c = fgetc(p)) != EOF) {
149 tag1 = realloc(tag1, taglen+2);
150 tag1[taglen++] = c; tag1[taglen] = 0;
151 if (strcmp(tag1+taglen-strlen(END_TAG),
155 if (strcmp(tag1+taglen-strlen(START_TAG),
162 tag1[taglen-strlen(END_TAG)] = 0;
163 process_tag(tmpl, tag1+strlen(START_TAG));
164 free(tag1); tag1 = NULL; taglen = 0;
174 waitpid(pid, NULL, 0);
177 /* process a call into a C function setup with put_function() */
178 static void process_c_call(struct template_state *tmpl, const char *tag)
180 struct template_var *var;
181 char *name, *args, *p, *tok;
185 if (!(p=strchr(tag, '('))) return;
187 name = strndup(tag, strcspn(tag, "("));
189 var = find_var(tmpl, name);
190 if (!var || !var->function) {
195 args = strndup(p+1, strcspn(p+1, ")"));
197 argv = malloc(sizeof(char *));
198 for (tok = strtok_r(args, ",", &p); tok; tok = strtok_r(NULL, ",", &p)) {
199 argv = realloc(argv, (argc+2)*sizeof(char *));
200 while (isspace(*tok)) tok++;
201 trim_tail(tok, " \t\r\n");
206 var->function(tmpl, name, var->value, argc, argv);
214 static void process_tag(struct template_state *tmpl, const char *tag)
219 while (isspace(*tag)) tag++;
222 trim_tail(tag2, " \t\n\r");
233 process_variable(tmpl, p+1);
236 process_escaped_variable(tmpl, p+1);
239 process_shell(tmpl, p+1, recurse);
242 process_c_call(tmpl, p+1);
245 /* its a comment, ignore it */
248 if (strchr(tag2, '=')) {
249 process_set_var(tmpl, p);
251 /* an include file */
252 tmpl->process(tmpl, p, recurse);
261 process a template file
263 static int process(struct template_state *tmpl, const char *filename, int recurse)
265 size_t size, remaining;
269 setvbuf(stdout, NULL, _IONBF, 0);
271 mp = map_file(filename, &size);
273 fprintf(stderr,"Failed to map %s (%s)\n",
274 filename, strerror(errno));
281 if (strncmp(m, "#!", 2) == 0) {
282 /* advance past shell script tag */
289 /* tags look like {{ TAG }}
290 where TAG can be of several forms
292 while (recurse && remaining && (p = strstr(m, START_TAG))) {
295 char *contents, *s2, *m2;
298 fwrite(m, 1, (p-m), stdout);
299 m = p + strlen(START_TAG);
302 s2 = strstr(m2, START_TAG);
303 s = strstr(m2, END_TAG);
307 m2 = s2 + strlen(START_TAG);
310 m2 = s + strlen(END_TAG);
314 fprintf(stderr,"No termination of tag!\n");
318 while (len && isspace(m[len-1])) len--;
319 contents = strndup(m, len);
320 process_tag(tmpl, contents);
322 m = s + strlen(END_TAG);
323 remaining -= (m - m0);
327 fwrite(m, 1, remaining, stdout);
330 unmap_file(mp, size);
335 destroy a open template
337 static void destroy(struct template_state *tmpl)
339 while (tmpl->variables) {
340 struct template_var *var = tmpl->variables;
343 tmpl->variables = tmpl->variables->next;
347 memset(tmpl, 0, sizeof(tmpl));
352 static struct template_state template_base = {
362 struct template_state *template_init(void)
364 struct template_state *tmpl;
366 tmpl = x_malloc(sizeof(*tmpl));
367 memcpy(tmpl, &template_base, sizeof(*tmpl));