1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include "tmplpro.h"
7 #include "pconst.h"
8 #include "procore.h"
9 #include "prostate.h"
10 #include "provalue.h"
11 #include "tagstack.h"
12 #include "pbuffer.h"
13 #include "parse_expr.h"
14 #include "pparam.h"
15 #include "optint.h"
16 #include "proscope.h"
17 #include "proscope.inc"
18 #include "pstrutils.inc"
19 #include "pmiscdef.h" /*for snprintf */
20 /* for mmap_load_file & mmap_unload_file */
21 #include "loadfile.inc"
22 #include "loopvar.inc"
23
24 #define HTML_TEMPLATE_NO_TAG -1
25 #define HTML_TEMPLATE_BAD_TAG 0
26 #define HTML_TEMPLATE_FIRST_TAG_USED 1
27 #define HTML_TEMPLATE_TAG_VAR 1
28 #define HTML_TEMPLATE_TAG_INCLUDE 2
29 #define HTML_TEMPLATE_TAG_LOOP 3
30 #define HTML_TEMPLATE_TAG_IF 4
31 #define HTML_TEMPLATE_TAG_ELSE 5
32 #define HTML_TEMPLATE_TAG_UNLESS 6
33 #define HTML_TEMPLATE_TAG_ELSIF 7
34 #define HTML_TEMPLATE_LAST_TAG_USED 7
35
36 static
37 const char* const tagname[]={
38 "Bad or unsupported tag", /* 0 */
39 "var", "include", "loop", "if", "else", "unless", "elsif"
40 };
41
42 static
43 const char* const TAGNAME[]={
44 "Bad or unsupported tag", /* 0 */
45 "VAR", "INCLUDE", "LOOP", "IF", "ELSE", "UNLESS", "ELSIF"
46 };
47
48 static int debuglevel=0;
49
50 #define TAG_OPT_NAME 0
51 #define TAG_OPT_EXPR 1
52 #define TAG_OPT_ESCAPE 2
53 #define TAG_OPT_DEFAULT 3
54 #define MIN_TAG_OPT 0
55 #define MAX_TAG_OPT 3
56
57 static const char* const tagopt[]={"name", "expr", "escape", "default" };
58 static const char* const TAGOPT[]={"NAME", "EXPR", "ESCAPE", "DEFAULT" };
59
60 #include "prostate.inc"
61 #include "tags.inc"
62
63 static const char const tag_can_be_closed[]={
64 1 /*Bad or unsupported tag*/,
65 0 /*VAR*/,
66 0 /*INCLUDE*/,
67 1 /*LOOP*/,
68 1 /*IF*/,
69 0 /*ELSE*/,
70 1 /*UNLESS*/,
71 1 /*ELSIF*/,
72 0 /**/,
73 };
74
75 static const char const tag_has_opt[][6]={
76 /* "name", "expr", "escape", "default", todo, todo */
77
78 { 0, 0, 0, 0, 0, 0 }, /*Bad or unsupported tag*/
79 { 1, 1, 1, 1, 0, 0 }, /*VAR*/
80 { 1, 1, 0, 1, 0, 0 }, /*INCLUDE*/
81 { 1, 0, 0, 0, 0, 0 }, /*LOOP*/
82 { 1, 1, 0, 0, 0, 0 }, /*IF*/
83 { 0, 0, 0, 0, 0, 0 }, /*ELSE*/
84 { 1, 1, 0, 0, 0, 0 }, /*UNLESS*/
85 { 1, 1, 0, 0, 0, 0 }, /*ELSIF*/
86 { 0, 0, 0, 0, 0, 0 }, /**/
87 };
88
89 typedef void (*tag_handler_func)(struct tmplpro_state *state, const PSTRING* const TagOptVal);
90
91 static const tag_handler_func const output_closetag_handler[]={
92 tag_handler_unknown, /*Bad or unsupported tag*/
93 tag_handler_unknown, /*VAR*/
94 tag_handler_unknown, /*INCLUDE*/
95 tag_handler_closeloop, /*LOOP*/
96 tag_handler_closeif, /*IF*/
97 tag_handler_unknown, /*ELSE*/
98 tag_handler_closeunless, /*UNLESS*/
99 tag_handler_unknown, /*ELSIF*/
100 tag_handler_unknown, /**/
101 };
102 static const tag_handler_func const output_opentag_handler[]={
103 tag_handler_unknown, /*Bad or unsupported tag*/
104 tag_handler_var, /*VAR*/
105 tag_handler_include, /*INCLUDE*/
106 tag_handler_loop, /*LOOP*/
107 tag_handler_if, /*IF*/
108 tag_handler_else, /*ELSE*/
109 tag_handler_unless, /*UNLESS*/
110 tag_handler_elsif, /*ELSIF*/
111 tag_handler_unknown, /**/
112 };
113
114 static
115 int
is_string(struct tmplpro_state * state,const char * pattern,const char * PATTERN)116 is_string(struct tmplpro_state *state, const char* pattern,const char* PATTERN)
117 {
118 const char* cur_pos=state->cur_pos;
119 register const char* const next_to_end = state->next_to_end;
120 while (*pattern && cur_pos<next_to_end) {
121 if (*pattern == *cur_pos || *PATTERN == *cur_pos) {
122 pattern++;
123 PATTERN++;
124 cur_pos++;
125 } else {
126 return 0;
127 }
128 }
129 if (cur_pos>=next_to_end) return 0;
130 state->cur_pos=cur_pos;
131 return 1;
132 }
133
134 static
135 INLINE
136 void
jump_over_space(struct tmplpro_state * state)137 jump_over_space(struct tmplpro_state *state)
138 {
139 register const char* const next_to_end = state->next_to_end;
140 while (isspace(*(state->cur_pos)) && state->cur_pos<next_to_end) {state->cur_pos++;};
141 }
142
143 static
144 INLINE
145 void
jump_to_char(struct tmplpro_state * state,char c)146 jump_to_char(struct tmplpro_state *state, char c)
147 {
148 register const char* const next_to_end = state->next_to_end;
149 while (c!=*(state->cur_pos) && state->cur_pos<next_to_end) {state->cur_pos++;};
150 }
151
152 static
153 PSTRING
read_tag_parameter_value(struct tmplpro_state * state)154 read_tag_parameter_value (struct tmplpro_state *state)
155 {
156 PSTRING modifier_value;
157 char cur_char;
158 char quote_char=0;
159 register const char* cur_pos;
160 const char* const next_to_end=state->next_to_end;
161 jump_over_space(state);
162 cur_pos=state->cur_pos;
163 cur_char=*cur_pos;
164 if (('"'==cur_char) || ('\''==cur_char)) {
165 quote_char=*cur_pos;
166 cur_pos++;
167 }
168 modifier_value.begin=cur_pos;
169 cur_char=*cur_pos;
170 if (quote_char) {
171 while (quote_char!=cur_char
172 #ifdef COMPAT_ON_BROKEN_QUOTE
173 /* compatibility mode; HTML::Template doesn't allow '>' inside quotes */
174 && ('>' != quote_char)
175 #endif
176 && cur_pos<next_to_end) {
177 cur_pos++;
178 cur_char=*cur_pos;
179 }
180 } else {
181 while ('>'!=cur_char && ! isspace(cur_char) && cur_pos<next_to_end) {
182 cur_pos++;
183 cur_char=*cur_pos;
184 }
185 }
186 if (cur_pos>=next_to_end) {
187 log_state(state,TMPL_LOG_ERROR,"quote char %c at pos " MOD_TD " is not terminated\n",
188 quote_char,TO_PTRDIFF_T(state->cur_pos - state->top));
189 modifier_value.endnext=modifier_value.begin;
190 jump_over_space(state);
191 return modifier_value;
192 }
193 modifier_value.endnext=cur_pos;
194 if (quote_char) {
195 if (quote_char==*cur_pos) {
196 cur_pos++;
197 } else {
198 log_state(state,TMPL_LOG_ERROR,"found %c instead of end quote %c at pos " MOD_TD "\n",
199 *cur_pos,quote_char,TO_PTRDIFF_T(cur_pos - state->top));
200 }
201 }
202 state->cur_pos=cur_pos;
203 /* if (debuglevel) log_state(state,TMPL_LOG_DEBUG2," at pos " MOD_TD "",TO_PTRDIFF_T(state->cur_pos-state->top)); */
204 jump_over_space(state);
205 return modifier_value;
206 }
207
208 static
209 int
try_tag_parameter(struct tmplpro_state * state,const char * modifier,const char * MODIFIER)210 try_tag_parameter (struct tmplpro_state *state,const char *modifier,const char *MODIFIER)
211 {
212 const char* const initial_pos=state->cur_pos;
213 jump_over_space(state);
214 if (is_string(state, modifier, MODIFIER)) {
215 jump_over_space(state);
216 if ('='==*(state->cur_pos)) {
217 state->cur_pos++;
218 jump_over_space(state);
219 return 1;
220 }
221 }
222 state->cur_pos=initial_pos;
223 return 0;
224 }
225
226 static
227 void
try_tmpl_var_options(struct tmplpro_state * state,int tag_type,PSTRING * TagOptVal)228 try_tmpl_var_options (struct tmplpro_state *state, int tag_type, PSTRING* TagOptVal)
229 {
230 int i;
231 int opt_found = 1;
232 /* reading parameter */
233 while (opt_found) {
234 int found_in_loop=0;
235 for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
236 if (
237 /* we will complain about syntax errors later;
238 tag_has_opt[tag_type][i] && */
239 try_tag_parameter(state, tagopt[i], TAGOPT[i])) {
240 TagOptVal[i] = read_tag_parameter_value(state);
241 found_in_loop=1;
242 if (debuglevel) log_state(state,TMPL_LOG_DEBUG,"in tag %s: found option %s=%.*s\n", TAGNAME[tag_type], TAGOPT[i],(int)(TagOptVal[i].endnext-TagOptVal[i].begin),TagOptVal[i].begin);
243 }
244 }
245 if (!found_in_loop) opt_found = 0;
246 }
247 }
248
249 static
250 void
process_tmpl_tag(struct tmplpro_state * state)251 process_tmpl_tag(struct tmplpro_state *state)
252 {
253 const int is_tag_closed=state->is_tag_closed;
254
255 int tag_type=HTML_TEMPLATE_BAD_TAG;
256 PSTRING TagOptVal[MAX_TAG_OPT+1];
257
258 int i;
259 for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
260 TagOptVal[i].begin = NULL;
261 TagOptVal[i].endnext = NULL;
262 }
263
264 for (i=HTML_TEMPLATE_FIRST_TAG_USED; i<=HTML_TEMPLATE_LAST_TAG_USED; i++) {
265 if (is_string(state, tagname[i], TAGNAME[i])) {
266 tag_type=i;
267 state->tag=tag_type;
268 if (debuglevel) {
269 if (is_tag_closed) {
270 tmpl_log(TMPL_LOG_DEBUG, "found </TMPL_%s> at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
271 } else {
272 tmpl_log(TMPL_LOG_DEBUG, "found <TMPL_%s> at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
273 }
274 }
275 break;
276 }
277 }
278 if (HTML_TEMPLATE_BAD_TAG==tag_type) {
279 state->param->found_syntax_error=1;
280 log_state(state,TMPL_LOG_ERROR, "found bad/unsupported tag at pos " MOD_TD "\n", TO_PTRDIFF_T(state->cur_pos-state->top));
281 /* TODO: flush its data --- */
282 state->cur_pos++;
283 return;
284 }
285
286 if (is_tag_closed && !tag_can_be_closed[tag_type]) {
287 state->param->found_syntax_error=1;
288 log_state(state,TMPL_LOG_ERROR, "incorrect closed tag </TMPL_%s> at pos " MOD_TD "\n",
289 TAGNAME[tag_type], TO_PTRDIFF_T(state->cur_pos-state->top));
290 }
291
292 if (is_tag_closed || ! tag_has_opt[tag_type][TAG_OPT_NAME]) {
293 /* tag has no parameter */
294 #ifdef COMPAT_ALLOW_NAME_IN_CLOSING_TAG
295 /* requested compatibility mode
296 to try reading NAME inside </closing tags NAME=" ">
297 (useful for comments?) */
298 try_tag_parameter(state, tagopt[TAG_OPT_NAME], TAGOPT[TAG_OPT_NAME]);
299 read_tag_parameter_value(state);
300 #endif
301 } else {
302 try_tmpl_var_options(state, tag_type, TagOptVal);
303 /* suport for short syntax */
304 if (TagOptVal[TAG_OPT_NAME].begin == NULL &&
305 tag_has_opt[tag_type][TAG_OPT_NAME] &&
306 (!tag_has_opt[tag_type][TAG_OPT_EXPR] || TagOptVal[TAG_OPT_EXPR].begin == NULL )) {
307 TagOptVal[TAG_OPT_NAME]=read_tag_parameter_value(state);
308 try_tmpl_var_options(state, tag_type, TagOptVal);
309 }
310
311 if (TagOptVal[TAG_OPT_NAME].begin == NULL &&
312 tag_has_opt[tag_type][TAG_OPT_NAME] &&
313 (!tag_has_opt[tag_type][TAG_OPT_EXPR] || TagOptVal[TAG_OPT_EXPR].begin == NULL )) {
314 state->param->found_syntax_error=1;
315 log_state(state,TMPL_LOG_ERROR,"NAME or EXPR is required for TMPL_%s\n", TAGNAME[tag_type]);
316 }
317 for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
318 if (TagOptVal[i].begin!=NULL && ! tag_has_opt[tag_type][i]) {
319 state->param->found_syntax_error=1;
320 log_state(state,TMPL_LOG_ERROR,"TMPL_%s does not support %s= option\n", TAGNAME[tag_type], TAGOPT[i]);
321 }
322 }
323 }
324
325 if (state->is_tag_commented) {
326 /* try read comment end */
327 /* jump_over_space(state); it should be already done :( */
328 jump_over_space(state);
329 if (state->cur_pos<state->next_to_end-2 && '-'==*(state->cur_pos) && '-'==*(state->cur_pos+1)) {
330 state->cur_pos+=2;
331 }
332 }
333 /* template tags could also be decorated as xml <tmpl_TAG /> */
334 if (!is_tag_closed && '/'==*(state->cur_pos)) state->cur_pos++;
335
336 if ('>'==*(state->cur_pos)) {
337 state->cur_pos++;
338 } else {
339 state->param->found_syntax_error=1;
340 log_state(state,TMPL_LOG_ERROR,"end tag:found %c instead of > at pos " MOD_TD "\n",
341 *state->cur_pos, TO_PTRDIFF_T(state->cur_pos-state->top));
342 }
343 /* flush run chars (if in SHOW mode) */
344 if (state->is_visible) {
345 (state->param->WriterFuncPtr)(state->param->ext_writer_state,state->last_processed_pos,state->tag_start);
346 state->last_processed_pos=state->cur_pos;
347 }
348 if (is_tag_closed) {
349 output_closetag_handler[tag_type](state,TagOptVal);
350 } else {
351 output_opentag_handler[tag_type](state,TagOptVal);
352 }
353 }
354
355
356 /* max offset to ensure we are not out of file when try <!--/ */
357 #define TAG_WIDTH_OFFSET 4
358 static
359 void
process_state(struct tmplpro_state * state)360 process_state (struct tmplpro_state * state)
361 {
362 static const char* const metatag="tmpl_";
363 static const char* const METATAG="TMPL_";
364 int is_tag_closed;
365 int is_tag_commented;
366 register const char* const last_safe_pos=state->next_to_end-TAG_WIDTH_OFFSET;
367 /* constructor */
368 tagstack_init(&(state->tag_stack));
369 /* magic; 256 > 50 (50 is min.required for double to string conversion */
370 pbuffer_init_as(&(state->expr_left_pbuffer), 256);
371 pbuffer_init_as(&(state->expr_right_pbuffer), 256);
372
373 if (debuglevel) tmpl_log(TMPL_LOG_DEBUG,"process_state:initiated at scope stack depth = %d\n",
374 curScopeLevel(&state->param->var_scope_stack));
375
376 while (state->cur_pos < last_safe_pos) {
377 register const char* cur_pos=state->cur_pos;
378 while ('<'!=*(cur_pos++)) {
379 if (cur_pos >= last_safe_pos) {
380 goto exit_mainloop;
381 }
382 };
383 state->tag_start=cur_pos-1;
384 is_tag_closed=0;
385 is_tag_commented=0;
386 state->cur_pos=cur_pos;
387 if (('!'==*(cur_pos)) && ('-'==*(cur_pos+1)) && ('-'==*(cur_pos+2))) {
388 state->cur_pos+=3;
389 jump_over_space(state);
390 is_tag_commented=1;
391 }
392 if ('/'==*(state->cur_pos)) {
393 state->cur_pos++;
394 is_tag_closed=1;
395 }
396 if (is_string(state,metatag,METATAG)) {
397 state->is_tag_commented=is_tag_commented;
398 state->is_tag_closed=is_tag_closed;
399 process_tmpl_tag(state);
400 }
401 }
402 exit_mainloop:;
403 (state->param->WriterFuncPtr)(state->param->ext_writer_state,state->last_processed_pos,state->next_to_end);
404
405 /* destructor */
406 pbuffer_free(&(state->expr_right_pbuffer));
407 pbuffer_free(&(state->expr_left_pbuffer));
408 tagstack_free(&(state->tag_stack));
409 if (debuglevel) tmpl_log(TMPL_LOG_DEBUG,"process_state:finished\n");
410 }
411
412 static
413 void
init_state(struct tmplpro_state * state,struct tmplpro_param * param)414 init_state (struct tmplpro_state *state, struct tmplpro_param *param)
415 {
416 /* initializing state */
417 state->param=param;
418 state->last_processed_pos=state->top;
419 state->cur_pos=state->top;
420 state->tag=HTML_TEMPLATE_NO_TAG;
421 state->is_visible=1;
422 }
423
424 static
425 int
tmplpro_exec_tmpl_filename(struct tmplpro_param * param,const char * filename)426 tmplpro_exec_tmpl_filename (struct tmplpro_param *param, const char* filename)
427 {
428 struct tmplpro_state state;
429 int mmapstatus;
430 PSTRING memarea;
431 int retval = 0;
432 const char* saved_masterpath;
433 /*
434 * param->masterpath is path to upper level template
435 * (or NULL in toplevel) which called <include filename>.
436 * we use it to calculate filepath for filename.
437 * Then filename becames upper level template for its <include>.
438 */
439 const char* filepath=(param->FindFileFuncPtr)(param->ext_findfile_state,filename, param->masterpath);
440 if (NULL==filepath) return ERR_PRO_FILE_NOT_FOUND;
441 /* filepath should be alive for every nested template */
442 filepath = strdup(filepath);
443 if (NULL==filepath) return ERR_PRO_NOT_ENOUGH_MEMORY;
444 saved_masterpath=param->masterpath; /* saving current file name */
445 param->masterpath=filepath;
446 if (param->filters) memarea=(param->LoadFileFuncPtr)(param->ext_filter_state,filepath);
447 else memarea=mmap_load_file(filepath);
448 if (memarea.begin == NULL) {
449 retval = ERR_PRO_CANT_OPEN_FILE;
450 goto cleanup_filepath;
451 }
452 state.top =memarea.begin;
453 state.next_to_end=memarea.endnext;
454 if (memarea.begin < memarea.endnext) {
455 /* to avoid crash with empty file */
456 init_state(&state,param);
457 if (debuglevel) log_state(&state,TMPL_LOG_DEBUG, "exec_tmpl: loading %s\n",filename);
458 process_state(&state);
459 }
460 /* destroying */
461 if (param->filters) mmapstatus=(param->UnloadFileFuncPtr)(param->ext_filter_state,memarea);
462 else mmapstatus=mmap_unload_file(memarea);
463 cleanup_filepath:
464 if (filepath!=NULL) free((void*) filepath);
465 param->masterpath=saved_masterpath;
466 return retval;
467 }
468
469 static
470 int
tmplpro_exec_tmpl_scalarref(struct tmplpro_param * param,PSTRING memarea)471 tmplpro_exec_tmpl_scalarref (struct tmplpro_param *param, PSTRING memarea)
472 {
473 struct tmplpro_state state;
474 const char* saved_masterpath=param->masterpath; /* saving current file name */
475 param->masterpath=NULL; /* no upper file */
476 state.top = memarea.begin;
477 state.next_to_end=memarea.endnext;
478 if (memarea.begin != memarea.endnext) {
479 init_state(&state,param);
480 process_state(&state);
481 }
482 /* exit cleanup code */
483 param->masterpath=saved_masterpath;
484 return 0;
485 }
486
487 #include "builtin_findfile.inc"
488 #include "callback_stubs.inc"
489
490 API_IMPL
491 int
492 APICALL
tmplpro_exec_tmpl(struct tmplpro_param * param)493 tmplpro_exec_tmpl (struct tmplpro_param *param)
494 {
495 int exitcode=0;
496 param->htp_errno=0;
497 if (param->GetAbstractValFuncPtr==NULL ||
498 param->AbstractVal2pstringFuncPtr==NULL ||
499 param->AbstractVal2abstractArrayFuncPtr==NULL ||
500 /*param->GetAbstractArrayLengthFuncPtr==NULL ||*/
501 param->GetAbstractMapFuncPtr==NULL ||
502 (param->IsExprUserfncFuncPtr!=NULL && param->IsExprUserfncFuncPtr != stub_is_expr_userfnc_func &&
503 (param->InitExprArglistFuncPtr==NULL ||
504 param->PushExprArglistFuncPtr==NULL ||
505 param->FreeExprArglistFuncPtr==NULL ||
506 param->CallExprUserfncFuncPtr==NULL))
507 )
508 {
509 tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: required callbacks are missing:");
510 if (param->GetAbstractValFuncPtr==NULL) tmpl_log(TMPL_LOG_ERROR," GetAbstractValFuncPtr");
511 if (param->AbstractVal2pstringFuncPtr==NULL) tmpl_log(TMPL_LOG_ERROR," AbstractVal2pstringFuncPtr");
512 if (param->AbstractVal2abstractArrayFuncPtr==NULL) tmpl_log(TMPL_LOG_ERROR," AbstractVal2abstractArrayFuncPtr");
513 if (param->GetAbstractMapFuncPtr==NULL) tmpl_log(TMPL_LOG_ERROR," GetAbstractMapFuncPtr");
514 if ((param->IsExprUserfncFuncPtr!=NULL &&
515 (param->InitExprArglistFuncPtr==NULL ||
516 param->PushExprArglistFuncPtr==NULL ||
517 param->FreeExprArglistFuncPtr==NULL ||
518 param->CallExprUserfncFuncPtr==NULL))
519 ) tmpl_log(TMPL_LOG_ERROR," one of the Expr callbacks");
520 tmpl_log(TMPL_LOG_ERROR,". The library is not initialized properly.\n");
521 return ERR_PRO_INVALID_ARGUMENT;
522 }
523 if (param->filters &&
524 (param->LoadFileFuncPtr==NULL ||
525 param->UnloadFileFuncPtr==NULL)) {
526 tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: filters is set but filter callbacks are missing.\n");
527 }
528 /* set up stabs */
529 if (NULL==param->WriterFuncPtr) param->WriterFuncPtr = stub_write_chars_to_stdout;
530 if (NULL==param->ext_findfile_state) param->ext_findfile_state = param;
531 if (NULL==param->FindFileFuncPtr) {
532 param->FindFileFuncPtr = stub_find_file_func;
533 param->ext_findfile_state = param;
534 /*pbuffer_init(¶m->builtin_findfile_buffer);*/
535 }
536 if (NULL==param->IsExprUserfncFuncPtr) param->IsExprUserfncFuncPtr = stub_is_expr_userfnc_func;
537 if (NULL==param->LoadFileFuncPtr) param->LoadFileFuncPtr = stub_load_file_func;
538 if (NULL==param->UnloadFileFuncPtr) param->UnloadFileFuncPtr = stub_unload_file_func;
539 if (NULL==param->GetAbstractArrayLengthFuncPtr) param->GetAbstractArrayLengthFuncPtr = stub_get_ABSTRACT_ARRAY_length_func;
540
541 Scope_reset(¶m->var_scope_stack, param->param_map_count);
542 /* reset other internals */
543 param->cur_includes=0; /* internal counter of include depth */
544 param->found_syntax_error=0;
545 /*masterpath=NULL;*/
546
547
548 /* TODO: hackaround;*/
549 debuglevel=param->debug;
550 tmpl_log_set_level(debuglevel);
551
552 if (param->scalarref.begin) exitcode = tmplpro_exec_tmpl_scalarref(param, param->scalarref);
553 else if (param->filename) exitcode = tmplpro_exec_tmpl_filename(param, param->filename);
554 else {
555 tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: neither scalarref nor filename was specified.\n");
556 exitcode = ERR_PRO_INVALID_ARGUMENT;
557 }
558 if (param->strict && param->found_syntax_error && 0==exitcode) exitcode = ERR_PRO_TEMPLATE_SYNTAX_ERROR;
559 param->htp_errno=exitcode;
560 return exitcode;
561 }
562
563 API_IMPL
564 PSTRING
565 APICALL
tmplpro_tmpl2pstring(struct tmplpro_param * param,int * retvalptr)566 tmplpro_tmpl2pstring (struct tmplpro_param *param, int *retvalptr)
567 {
568 int exitcode;
569 PSTRING retval;
570 struct builtin_writer_state state;
571 writer_functype save_writer_func = param->WriterFuncPtr;
572 ABSTRACT_WRITER* save_writer_state = param->ext_writer_state;
573 param->WriterFuncPtr = stub_write_chars_to_pbuffer;
574 param->ext_writer_state = &state;
575 state.bufptr=¶m->builtin_tmpl2string_buffer;
576 pbuffer_resize(state.bufptr, 4000);
577 state.size = 0;
578 exitcode = tmplpro_exec_tmpl (param);
579 param->WriterFuncPtr = save_writer_func;
580 param->ext_writer_state = save_writer_state;
581 if (NULL!=retvalptr) *retvalptr=exitcode;
582 retval.begin = pbuffer_string(state.bufptr);
583 retval.endnext = retval.begin+state.size;
584 *((char*) retval.endnext)='\0';
585 return retval;
586 }
587
588 API_IMPL
589 void
590 APICALL
tmplpro_clear_option_param_map(struct tmplpro_param * param)591 tmplpro_clear_option_param_map(struct tmplpro_param *param)
592 {
593 param->param_map_count=0;
594 Scope_reset(¶m->var_scope_stack,param->param_map_count);
595 }
596
597 API_IMPL
598 int
599 APICALL
tmplpro_push_option_param_map(struct tmplpro_param * param,ABSTRACT_MAP * map,EXPR_int64 flags)600 tmplpro_push_option_param_map(struct tmplpro_param *param, ABSTRACT_MAP* map, EXPR_int64 flags)
601 {
602 pushScopeMap(¶m->var_scope_stack, map, (int) flags);
603 return ++(param->param_map_count);
604 }
605
606 API_IMPL
607 int
608 APICALL
tmplpro_count_option_param_map(struct tmplpro_param * param)609 tmplpro_count_option_param_map(struct tmplpro_param *param)
610 {
611 return param->param_map_count;
612 }
613
614
615 API_IMPL
616 void
617 APICALL
tmplpro_procore_init(void)618 tmplpro_procore_init(void)
619 {
620 }
621
622 API_IMPL
623 void
624 APICALL
tmplpro_procore_done(void)625 tmplpro_procore_done(void)
626 {
627 }
628
629 /* internal initialization of struct tmplpro_param */
630 API_IMPL
631 struct tmplpro_param*
632 APICALL
tmplpro_param_init(void)633 tmplpro_param_init(void)
634 {
635 struct tmplpro_param* param=(struct tmplpro_param*) malloc (sizeof(struct tmplpro_param));
636 if (param==NULL) return param;
637 /* filling initial struct tmplpro_param with 0 */
638 memset (param, 0, sizeof(struct tmplpro_param));
639 /* current level of inclusion */
640 /* param->cur_includes=0; */
641 /* not to use external file loader */
642 /* param->filters=0;
643 param->default_escape=HTML_TEMPLATE_OPT_ESCAPE_NO;
644 param->masterpath=NULL; *//* we are not included by something *//*
645 param->expr_func_map=NULL;
646 param->expr_func_arglist=NULL;
647 */
648 _reset_int_options_set_nonzero_defaults(param);
649 Scope_init(¶m->var_scope_stack);
650 /* no need for them due to memset 0
651 pbuffer_preinit(¶m->builtin_findfile_buffer);
652 pbuffer_preinit(¶m->builtin_tmpl2string_buffer);
653 pbuffer_preinit(¶m->lowercase_varname_buffer);
654 pbuffer_preinit(¶m->uppercase_varname_buffer);
655 pbuffer_preinit(¶m->escape_pstring_buffer);
656 */
657 return param;
658 }
659
660 API_IMPL
661 void
662 APICALL
tmplpro_param_free(struct tmplpro_param * param)663 tmplpro_param_free(struct tmplpro_param* param)
664 {
665 pbuffer_free(¶m->builtin_findfile_buffer);
666 pbuffer_free(¶m->builtin_tmpl2string_buffer);
667 pbuffer_free(¶m->lowercase_varname_buffer);
668 pbuffer_free(¶m->uppercase_varname_buffer);
669 pbuffer_free(¶m->escape_pstring_buffer);
670 Scope_free(¶m->var_scope_stack);
671 free(param);
672 }
673
674 API_IMPL
675 int
676 APICALL
tmplpro_errno(struct tmplpro_param * param)677 tmplpro_errno(struct tmplpro_param* param)
678 {
679 return param->htp_errno;
680 }
681
682 API_IMPL
683 const char*
684 APICALL
tmplpro_errmsg(struct tmplpro_param * param)685 tmplpro_errmsg(struct tmplpro_param* param)
686 {
687 return errlist[param->htp_errno];
688 }
689
690 API_IMPL
691 int
692 APICALL
tmplpro_set_log_file(struct tmplpro_param * param,const char * logfilename)693 tmplpro_set_log_file(struct tmplpro_param* param, const char* logfilename)
694 {
695 FILE *file_p;
696 if (NULL==logfilename) {
697 if (tmpl_log_stream!=NULL) {
698 fclose(tmpl_log_stream);
699 tmpl_log_stream=NULL;
700 }
701 tmpl_log_set_callback(tmpl_log_default_callback);
702 return 0;
703 }
704 file_p = fopen(logfilename, "a");
705 if (!file_p) {
706 tmpl_log(TMPL_LOG_ERROR,"tmplpro_set_log_file: can't create log file [%s]\n",logfilename);
707 return ERR_PRO_FILE_NOT_FOUND;
708 } else {
709 if (tmpl_log_stream!=NULL) fclose(tmpl_log_stream);
710 tmpl_log_stream=file_p;
711 tmpl_log_set_callback(tmpl_log_stream_callback);
712 return 0;
713 }
714 }
715
716 API_IMPL
717 size_t
718 APICALL
tmplpro_param_allocated_memory_info(struct tmplpro_param * param)719 tmplpro_param_allocated_memory_info(struct tmplpro_param* param)
720 {
721 return 0L +
722 pbuffer_size(¶m->builtin_findfile_buffer) +
723 pbuffer_size(¶m->builtin_tmpl2string_buffer) +
724 pbuffer_size(¶m->lowercase_varname_buffer) +
725 pbuffer_size(¶m->uppercase_varname_buffer) +
726 pbuffer_size(¶m->escape_pstring_buffer) +
727 (1+curScopeLevel(¶m->var_scope_stack)) * sizeof(struct scope_stack);
728 }
729
730 #include "tagstack.inc"
731
732 /*
733 * Local Variables:
734 * mode: c
735 * End:
736 */
737