html-template-pro 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. data/.autotest +9 -0
  2. data/ARTISTIC +131 -0
  3. data/History.txt +4 -0
  4. data/LGPL +504 -0
  5. data/Manifest.txt +221 -0
  6. data/README.rdoc +52 -0
  7. data/Rakefile +18 -0
  8. data/benchmark.rb +136 -0
  9. data/config/website.yml +2 -0
  10. data/ext/html/template/internal/Pro.xs +679 -0
  11. data/ext/html/template/internal/builtin_findfile.inc +361 -0
  12. data/ext/html/template/internal/calc.h +26 -0
  13. data/ext/html/template/internal/calc.inc +120 -0
  14. data/ext/html/template/internal/callback_stubs.inc +63 -0
  15. data/ext/html/template/internal/expr.c +2267 -0
  16. data/ext/html/template/internal/expr.y +476 -0
  17. data/ext/html/template/internal/expr_iface.c +94 -0
  18. data/ext/html/template/internal/exprpstr.h +36 -0
  19. data/ext/html/template/internal/exprpstr.inc +144 -0
  20. data/ext/html/template/internal/exprtool.h +99 -0
  21. data/ext/html/template/internal/exprtool.inc +289 -0
  22. data/ext/html/template/internal/exprtype.h +62 -0
  23. data/ext/html/template/internal/exprval.h +30 -0
  24. data/ext/html/template/internal/extconf.rb +6 -0
  25. data/ext/html/template/internal/internal.c +449 -0
  26. data/ext/html/template/internal/loadfile.h +11 -0
  27. data/ext/html/template/internal/loadfile.inc +171 -0
  28. data/ext/html/template/internal/pabidecl.h +54 -0
  29. data/ext/html/template/internal/pabstract.h +426 -0
  30. data/ext/html/template/internal/parse_expr.h +15 -0
  31. data/ext/html/template/internal/pbuffer.c +76 -0
  32. data/ext/html/template/internal/pbuffer.h +31 -0
  33. data/ext/html/template/internal/pmiscdef.h +54 -0
  34. data/ext/html/template/internal/pparam.h +101 -0
  35. data/ext/html/template/internal/ppport.h +1098 -0
  36. data/ext/html/template/internal/procore.c +1189 -0
  37. data/ext/html/template/internal/procore.h +18 -0
  38. data/ext/html/template/internal/proparam.c +443 -0
  39. data/ext/html/template/internal/proparam.h +571 -0
  40. data/ext/html/template/internal/proscope.h +32 -0
  41. data/ext/html/template/internal/proscope.inc +107 -0
  42. data/ext/html/template/internal/prostate.h +49 -0
  43. data/ext/html/template/internal/prostate.inc +24 -0
  44. data/ext/html/template/internal/provalue.h +14 -0
  45. data/ext/html/template/internal/pstring.h +60 -0
  46. data/ext/html/template/internal/pstrutils.h +25 -0
  47. data/ext/html/template/internal/pstrutils.inc +150 -0
  48. data/ext/html/template/internal/tagstack.h +30 -0
  49. data/ext/html/template/internal/tagstack.inc +65 -0
  50. data/ext/html/template/internal/tmpllog.c +62 -0
  51. data/ext/html/template/internal/tmpllog.h +27 -0
  52. data/ext/html/template/internal/tmplpro.h +218 -0
  53. data/ext/html/template/internal/tmplpro_version.c +35 -0
  54. data/lib/html/template/pro.rb +225 -0
  55. data/script/console +10 -0
  56. data/script/destroy +14 -0
  57. data/script/generate +14 -0
  58. data/script/txt2html +71 -0
  59. data/tasks/extconf.rake +13 -0
  60. data/tasks/extconf/tmplpro.rake +43 -0
  61. data/templates-Pro/a.incl +1 -0
  62. data/templates-Pro/empty.incl +0 -0
  63. data/templates-Pro/include/1/a.incl +1 -0
  64. data/templates-Pro/include/2.out +3 -0
  65. data/templates-Pro/include/2.tmpl +1 -0
  66. data/templates-Pro/include/2/a.incl +1 -0
  67. data/templates-Pro/include/3.tmpl +1 -0
  68. data/templates-Pro/include/4.tmpl +1 -0
  69. data/templates-Pro/include/a.incl +1 -0
  70. data/templates-Pro/test_broken.tmpl +25 -0
  71. data/templates-Pro/test_broken1.out +1 -0
  72. data/templates-Pro/test_broken1.tmpl +1 -0
  73. data/templates-Pro/test_esc1.out +4 -0
  74. data/templates-Pro/test_esc1.tmpl +4 -0
  75. data/templates-Pro/test_esc2.out +5 -0
  76. data/templates-Pro/test_esc2.tmpl +6 -0
  77. data/templates-Pro/test_esc3.out +4 -0
  78. data/templates-Pro/test_esc3.tmpl +4 -0
  79. data/templates-Pro/test_esc4.out +3 -0
  80. data/templates-Pro/test_esc4.tmpl +4 -0
  81. data/templates-Pro/test_expr1.out +26 -0
  82. data/templates-Pro/test_expr1.tmpl +26 -0
  83. data/templates-Pro/test_expr2.out +34 -0
  84. data/templates-Pro/test_expr2.tmpl +34 -0
  85. data/templates-Pro/test_expr3.out +6 -0
  86. data/templates-Pro/test_expr3.tmpl +6 -0
  87. data/templates-Pro/test_expr4.out +4 -0
  88. data/templates-Pro/test_expr4.tmpl +4 -0
  89. data/templates-Pro/test_expr5.out +18 -0
  90. data/templates-Pro/test_expr5.tmpl +18 -0
  91. data/templates-Pro/test_expr6.out +18 -0
  92. data/templates-Pro/test_expr6.tmpl +18 -0
  93. data/templates-Pro/test_expr7.out +44 -0
  94. data/templates-Pro/test_expr7.tmpl +20 -0
  95. data/templates-Pro/test_expr8.out +15 -0
  96. data/templates-Pro/test_expr8.tmpl +15 -0
  97. data/templates-Pro/test_if1.out +25 -0
  98. data/templates-Pro/test_if1.tmpl +28 -0
  99. data/templates-Pro/test_if2.out +17 -0
  100. data/templates-Pro/test_if2.tmpl +25 -0
  101. data/templates-Pro/test_if3.out +12 -0
  102. data/templates-Pro/test_if3.tmpl +14 -0
  103. data/templates-Pro/test_if4.out +15 -0
  104. data/templates-Pro/test_if4.tmpl +31 -0
  105. data/templates-Pro/test_if5.out +16 -0
  106. data/templates-Pro/test_if5.tmpl +16 -0
  107. data/templates-Pro/test_if6.out +15 -0
  108. data/templates-Pro/test_if6.tmpl +31 -0
  109. data/templates-Pro/test_if7.out +14 -0
  110. data/templates-Pro/test_if7.tmpl +18 -0
  111. data/templates-Pro/test_include1.out +23 -0
  112. data/templates-Pro/test_include1.tmpl +7 -0
  113. data/templates-Pro/test_include2.out +120 -0
  114. data/templates-Pro/test_include2.tmpl +10 -0
  115. data/templates-Pro/test_include3.out +8 -0
  116. data/templates-Pro/test_include3.tmpl +8 -0
  117. data/templates-Pro/test_include4.out +7 -0
  118. data/templates-Pro/test_include4.tmpl +6 -0
  119. data/templates-Pro/test_include5.out +7 -0
  120. data/templates-Pro/test_include5.tmpl +6 -0
  121. data/templates-Pro/test_loop1.erb +17 -0
  122. data/templates-Pro/test_loop1.out +12 -0
  123. data/templates-Pro/test_loop1.tmpl +16 -0
  124. data/templates-Pro/test_loop2.erb +19 -0
  125. data/templates-Pro/test_loop2.out +40 -0
  126. data/templates-Pro/test_loop2.tmpl +19 -0
  127. data/templates-Pro/test_loop3.out +38 -0
  128. data/templates-Pro/test_loop3.tmpl +40 -0
  129. data/templates-Pro/test_loop4.out +44 -0
  130. data/templates-Pro/test_loop4.tmpl +20 -0
  131. data/templates-Pro/test_loop5.out +9 -0
  132. data/templates-Pro/test_loop5.tmpl +11 -0
  133. data/templates-Pro/test_loop6.out +33 -0
  134. data/templates-Pro/test_loop6.tmpl +15 -0
  135. data/templates-Pro/test_malloc.tmpl +1 -0
  136. data/templates-Pro/test_userfunc1.out +14 -0
  137. data/templates-Pro/test_userfunc1.tmpl +14 -0
  138. data/templates-Pro/test_userfunc2.out +35 -0
  139. data/templates-Pro/test_userfunc2.tmpl +5 -0
  140. data/templates-Pro/test_userfunc3.out +5 -0
  141. data/templates-Pro/test_userfunc3.tmpl +5 -0
  142. data/templates-Pro/test_userfunc4.out +10 -0
  143. data/templates-Pro/test_userfunc4.tmpl +10 -0
  144. data/templates-Pro/test_userfunc5.out +4 -0
  145. data/templates-Pro/test_userfunc5.tmpl +4 -0
  146. data/templates-Pro/test_userfunc6.out +4 -0
  147. data/templates-Pro/test_userfunc6.tmpl +4 -0
  148. data/templates-Pro/test_var1.erb +23 -0
  149. data/templates-Pro/test_var1.out +20 -0
  150. data/templates-Pro/test_var1.tmpl +23 -0
  151. data/templates-Pro/test_var2.erb +7 -0
  152. data/templates-Pro/test_var2.out +6 -0
  153. data/templates-Pro/test_var2.tmpl +7 -0
  154. data/templates-Pro/test_var3.out +14 -0
  155. data/templates-Pro/test_var3.tmpl +16 -0
  156. data/templates/case_loop.tmpl +3 -0
  157. data/templates/context.tmpl +3 -0
  158. data/templates/counter.tmpl +2 -0
  159. data/templates/default.tmpl +1 -0
  160. data/templates/default_escape.tmpl +4 -0
  161. data/templates/double_loop.tmpl +7 -0
  162. data/templates/escape.tmpl +5 -0
  163. data/templates/global-loops.tmpl +9 -0
  164. data/templates/globals.tmpl +11 -0
  165. data/templates/if.tmpl +7 -0
  166. data/templates/ifelse.tmpl +6 -0
  167. data/templates/include.tmpl +14 -0
  168. data/templates/include_path/a.tmpl +2 -0
  169. data/templates/include_path/b.tmpl +1 -0
  170. data/templates/include_path/inner.tmpl +1 -0
  171. data/templates/include_path/one.tmpl +2 -0
  172. data/templates/include_path2/inner.tmpl +1 -0
  173. data/templates/included.tmpl +4 -0
  174. data/templates/included2.tmpl +3 -0
  175. data/templates/js.tmpl +1 -0
  176. data/templates/long_loops.tmpl +307 -0
  177. data/templates/loop-context.tmpl +2 -0
  178. data/templates/loop-if.tmpl +9 -0
  179. data/templates/medium.tmpl +217 -0
  180. data/templates/multiline_tags.tmpl +7 -0
  181. data/templates/newline_test1.tmpl +1 -0
  182. data/templates/newline_test2.tmpl +1 -0
  183. data/templates/other-loop.tmpl +7 -0
  184. data/templates/outer.tmpl +3 -0
  185. data/templates/query-test.tmpl +21 -0
  186. data/templates/query-test2.tmpl +12 -0
  187. data/templates/recursive.tmpl +2 -0
  188. data/templates/searchpath/included.tmpl +4 -0
  189. data/templates/searchpath/three.tmpl +1 -0
  190. data/templates/searchpath/two.tmpl +2 -0
  191. data/templates/simple-loop-nonames.tmpl +13 -0
  192. data/templates/simple-loop.tmpl +12 -0
  193. data/templates/simple.tmpl +9 -0
  194. data/templates/unless.tmpl +5 -0
  195. data/templates/urlescape.tmpl +3 -0
  196. data/templates/vanguard1.tmpl +2 -0
  197. data/templates/vanguard2.tmpl +3 -0
  198. data/test/templates/complex.tmpl +24 -0
  199. data/test/templates/foo.tmpl +6 -0
  200. data/test/templates/func.tmpl +2 -0
  201. data/test/templates/loop.tmpl +14 -0
  202. data/test/templates/negative.tmpl +1 -0
  203. data/test/templates/numerics.tmpl +6 -0
  204. data/test/templates/register.tmpl +2 -0
  205. data/test/test_basic.rb +23 -0
  206. data/test/test_coderefs.rb +16 -0
  207. data/test/test_complex.rb +106 -0
  208. data/test/test_helper.rb +3 -0
  209. data/test/test_html_template.rb +583 -0
  210. data/test/test_html_template_internal_extn.rb +10 -0
  211. data/test/test_html_template_pro.rb +177 -0
  212. data/test/test_path_like_variable_scope.rb +59 -0
  213. data/test/test_random.rb +21 -0
  214. data/test/test_realloc.rb +16 -0
  215. data/test/test_register.rb +25 -0
  216. data/test/test_tmplpro.rb +9 -0
  217. data/test/tests.rb +9 -0
  218. data/website/index.txt +57 -0
  219. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  220. data/website/stylesheets/screen.css +159 -0
  221. data/website/template.html.erb +50 -0
  222. metadata +303 -0
@@ -0,0 +1,1189 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <ctype.h>
5
+
6
+ #include "tmplpro.h"
7
+ #include "procore.h"
8
+ #include "prostate.h"
9
+ #include "provalue.h"
10
+ #include "tagstack.h"
11
+ #include "pbuffer.h"
12
+ #include "parse_expr.h"
13
+ #include "pparam.h"
14
+ #include "proscope.h"
15
+ #include "proscope.inc"
16
+ #include "pstrutils.inc"
17
+ #include "pmiscdef.h" /*for snprintf */
18
+ /* for mmap_load_file & mmap_unload_file */
19
+ #include "loadfile.inc"
20
+
21
+ #define HTML_TEMPLATE_NO_TAG -1
22
+ #define HTML_TEMPLATE_BAD_TAG 0
23
+ #define HTML_TEMPLATE_FIRST_TAG_USED 1
24
+ #define HTML_TEMPLATE_TAG_VAR 1
25
+ #define HTML_TEMPLATE_TAG_INCLUDE 2
26
+ #define HTML_TEMPLATE_TAG_LOOP 3
27
+ #define HTML_TEMPLATE_TAG_IF 4
28
+ #define HTML_TEMPLATE_TAG_ELSE 5
29
+ #define HTML_TEMPLATE_TAG_UNLESS 6
30
+ #define HTML_TEMPLATE_TAG_ELSIF 7
31
+ #define HTML_TEMPLATE_LAST_TAG_USED 7
32
+
33
+ static
34
+ const char* const tagname[]={
35
+ "Bad or unsupported tag", /* 0 */
36
+ "var", "include", "loop", "if", "else", "unless", "elsif"
37
+ };
38
+
39
+ static
40
+ const char* const TAGNAME[]={
41
+ "Bad or unsupported tag", /* 0 */
42
+ "VAR", "INCLUDE", "LOOP", "IF", "ELSE", "UNLESS", "ELSIF"
43
+ };
44
+
45
+ /* max offset to ensure we are not out of file when try <!--/ */
46
+ #define TAG_WIDTH_OFFSET 4
47
+
48
+ static int debuglevel=0;
49
+
50
+ #include "prostate.inc"
51
+
52
+ static
53
+ const char* const innerloopname[]={
54
+ "", "first__", "last__", "inner__", "odd__", "counter__"
55
+ };
56
+
57
+ static
58
+ const char* const INNERLOOPNAME[]={
59
+ "", "FIRST__", "LAST__", "INNER__", "ODD__", "COUNTER__"
60
+ };
61
+
62
+ #define HTML_TEMPLATE_INNER_LOOP_VAR_FIRST 1
63
+ #define HTML_TEMPLATE_INNER_LOOP_VAR_LAST 2
64
+ #define HTML_TEMPLATE_INNER_LOOP_VAR_INNER 3
65
+ #define HTML_TEMPLATE_INNER_LOOP_VAR_ODD 4
66
+ #define HTML_TEMPLATE_INNER_LOOP_VAR_COUNTER 5
67
+
68
+ #define HTML_TEMPLATE_FIRST_INNER_LOOP 1
69
+ #define HTML_TEMPLATE_LAST_INNER_LOOP 5
70
+
71
+
72
+ static
73
+ int
74
+ try_inner_loop_variable (PSTRING name)
75
+ {
76
+ int i;
77
+ const char* cur_pos;
78
+ const char* pattern;
79
+ const char* PATTERN;
80
+ for (i=HTML_TEMPLATE_FIRST_INNER_LOOP; i<=HTML_TEMPLATE_LAST_INNER_LOOP; i++) {
81
+ cur_pos=name.begin;
82
+ pattern=innerloopname[i];
83
+ PATTERN=INNERLOOPNAME[i];
84
+ while (*pattern && cur_pos<name.endnext) {
85
+ if (*pattern == *cur_pos || *PATTERN == *cur_pos) {
86
+ pattern++;
87
+ PATTERN++;
88
+ cur_pos++;
89
+ } else {
90
+ break;
91
+ }
92
+ }
93
+ if (cur_pos==name.endnext) {
94
+ return i;
95
+ }
96
+ }
97
+ return 0;
98
+ }
99
+
100
+ static
101
+ PSTRING
102
+ get_loop_context_vars_value (struct tmplpro_param *param, PSTRING name) {
103
+ static char* FalseString="0";
104
+ static char* TrueString ="1";
105
+ static char buffer[20]; /* for snprintf %d */
106
+ int loop;
107
+ PSTRING retval={NULL,NULL};
108
+ struct ProScopeEntry* currentScope = getCurrentScope(&param->var_scope_stack);
109
+ if (isScopeLoop(currentScope)
110
+ && name.endnext-name.begin>4
111
+ && '_'==*(name.begin)
112
+ && '_'==*(name.begin+1)
113
+ ) {
114
+ /* we can meet loop variables here -- try it first */
115
+ /* length of its name >4 */
116
+ /* __first__ __last__ __inner__ __odd__ __counter__ */
117
+ PSTRING shiftedname; /* (PSTRING) {name.begin+2,name.endnext} */
118
+ shiftedname.begin=name.begin+2;
119
+ shiftedname.endnext=name.endnext;
120
+ switch (try_inner_loop_variable(shiftedname)) {
121
+ case 0: break;
122
+ case HTML_TEMPLATE_INNER_LOOP_VAR_FIRST:
123
+ if (currentScope->loop==0) { /* first__ */
124
+ retval.begin=TrueString; retval.endnext=TrueString+1;
125
+ } else {
126
+ retval.begin=FalseString; retval.endnext=FalseString+1;
127
+ }; break;
128
+ case HTML_TEMPLATE_INNER_LOOP_VAR_LAST:
129
+ if (currentScope->loop==(currentScope->loop_count-1)) {
130
+ retval.begin=TrueString; retval.endnext=TrueString+1;
131
+ } else {
132
+ retval.begin=FalseString; retval.endnext=FalseString+1;
133
+ }; break;
134
+ case HTML_TEMPLATE_INNER_LOOP_VAR_ODD:
135
+ if ((currentScope->loop%2)==0) {
136
+ retval.begin=TrueString; retval.endnext=TrueString+1;
137
+ } else {
138
+ retval.begin=FalseString; retval.endnext=FalseString+1;
139
+ }; break;
140
+ case HTML_TEMPLATE_INNER_LOOP_VAR_INNER:
141
+ if (currentScope->loop>0 &&
142
+ (currentScope->loop_count<0 /* loop_count < 0 if number of loops is unknown/undefined */
143
+ || currentScope->loop < (currentScope->loop_count-1))) {
144
+ retval.begin=TrueString; retval.endnext=TrueString+1;
145
+ } else {
146
+ retval.begin=FalseString; retval.endnext=FalseString+1;
147
+ }; break;
148
+ case HTML_TEMPLATE_INNER_LOOP_VAR_COUNTER:
149
+ loop=currentScope->loop+1;
150
+ snprintf(buffer,sizeof(buffer),"%d",loop);
151
+ retval.begin=buffer; retval.endnext=buffer+strlen(buffer);
152
+ break;
153
+ }
154
+ }
155
+ return retval;
156
+ }
157
+
158
+ static
159
+ void init_tmpl_var_case_buffers (struct tmplpro_param *param) {
160
+ param->lowercase_varname.begin = NULL;
161
+ param->lowercase_varname.endnext = NULL;
162
+ param->uppercase_varname.begin = NULL;
163
+ param->uppercase_varname.endnext = NULL;
164
+ }
165
+
166
+ static
167
+ ABSTRACT_VALUE* get_abstract_value (struct tmplpro_param *param, int scope_level, PSTRING name) {
168
+ ABSTRACT_VALUE* retval = NULL;
169
+ ABSTRACT_MAP* param_HV = getScope(&param->var_scope_stack, scope_level)->param_HV;
170
+ ABSTRACT_DATASTATE* data_state = param->ext_data_state;
171
+ get_ABSTRACT_VALUE_functype getval_func = param->GetAbstractValFuncPtr;
172
+ int tmpl_var_case = param->tmpl_var_case;
173
+ if ((tmpl_var_case & ASK_NAME_MASK) == ASK_NAME_DEFAULT
174
+ || tmpl_var_case & ASK_NAME_AS_IS) {
175
+ retval = getval_func(data_state, param_HV, name);
176
+ if (retval != NULL) return retval;
177
+ }
178
+ if (tmpl_var_case & ASK_NAME_LOWERCASE) {
179
+ if (param->lowercase_varname.begin == NULL) {
180
+ param->lowercase_varname=lowercase_pstring(&param->lowercase_varname_buffer, name);
181
+ }
182
+ retval = getval_func(data_state, param_HV, param->lowercase_varname);
183
+ if (retval != NULL) return retval;
184
+ }
185
+ if (tmpl_var_case & ASK_NAME_UPPERCASE) {
186
+ if (param->uppercase_varname.begin == NULL) {
187
+ param->uppercase_varname=uppercase_pstring(&param->uppercase_varname_buffer, name);
188
+ }
189
+ retval = getval_func(data_state, param_HV, param->uppercase_varname);
190
+ if (retval != NULL) return retval;
191
+ }
192
+ return retval;
193
+ }
194
+
195
+ static
196
+ ABSTRACT_VALUE* walk_through_nested_loops (struct tmplpro_param *param, PSTRING name) {
197
+ int CurLevel;
198
+ ABSTRACT_VALUE* valptr;
199
+ init_tmpl_var_case_buffers (param);
200
+ /* Shigeki Morimoto path_like_variable_scope extension */
201
+ if (param->path_like_variable_scope) {
202
+ if(*(name.begin) == '/' || strncmp(name.begin, "../", 3) == 0){
203
+ PSTRING tmp_name;
204
+ int GoalHash;
205
+ if(*(name.begin) == '/'){
206
+ tmp_name.begin = name.begin+1; // skip '/'
207
+ tmp_name.endnext = name.endnext;
208
+ GoalHash = 0;
209
+ }else{
210
+ tmp_name.begin = name.begin;
211
+ tmp_name.endnext = name.endnext;
212
+ GoalHash = curScopeLevel(&param->var_scope_stack);
213
+ while(strncmp(tmp_name.begin, "../", 3) == 0){
214
+ tmp_name.begin = tmp_name.begin + 3; // skip '../'
215
+ GoalHash --;
216
+ }
217
+ }
218
+ return get_abstract_value(param, GoalHash, tmp_name);
219
+ }
220
+ }
221
+ /* end Shigeki Morimoto path_like_variable_scope extension */
222
+
223
+ CurLevel = curScopeLevel(&param->var_scope_stack);
224
+ valptr = get_abstract_value(param, CurLevel, name);
225
+ if (valptr) return valptr;
226
+ /* optional strict scoping; does it have much sence?
227
+ if ((STRICT_SCOPING==param->global_vars)) return NULL;
228
+ */
229
+
230
+ /* loop-bounded scoping; */
231
+ if (0==param->global_vars) {
232
+ while (isScopeMap(getScope(&param->var_scope_stack,CurLevel)) && --CurLevel>=0) {
233
+ valptr = get_abstract_value(param, CurLevel, name);
234
+ if (valptr!=NULL) return valptr;
235
+ }
236
+ return NULL;
237
+ }
238
+
239
+ while (--CurLevel>=0) {
240
+ valptr = get_abstract_value(param, CurLevel, name);
241
+ if (valptr!=NULL) return valptr;
242
+ }
243
+ return NULL;
244
+ }
245
+
246
+ static
247
+ int
248
+ is_string(struct tmplpro_state *state, const char* pattern,const char* PATTERN)
249
+ {
250
+ const char* cur_pos=state->cur_pos;
251
+ while (*pattern && cur_pos<state->next_to_end) {
252
+ if (*pattern == *cur_pos || *PATTERN == *cur_pos) {
253
+ pattern++;
254
+ PATTERN++;
255
+ cur_pos++;
256
+ } else {
257
+ return 0;
258
+ }
259
+ }
260
+ if (cur_pos>=state->next_to_end) return 0;
261
+ state->cur_pos=cur_pos;
262
+ return 1;
263
+ }
264
+
265
+
266
+ static
267
+ INLINE
268
+ void
269
+ jump_over_space(struct tmplpro_state *state)
270
+ {
271
+ while (isspace(*(state->cur_pos)) && state->cur_pos<state->next_to_end) {state->cur_pos++;};
272
+ }
273
+
274
+ static
275
+ INLINE
276
+ void
277
+ jump_to_char(struct tmplpro_state *state, char c)
278
+ {
279
+ while (c!=*(state->cur_pos) && state->cur_pos<state->next_to_end) {state->cur_pos++;};
280
+ }
281
+
282
+ TMPLPRO_LOCAL
283
+ PSTRING _get_variable_value (struct tmplpro_param *param, PSTRING name) {
284
+ PSTRING varvalue ={NULL, NULL};
285
+ ABSTRACT_VALUE* abstrval;
286
+ if (param->loop_context_vars) {
287
+ varvalue=get_loop_context_vars_value(param, name);
288
+ }
289
+ if (varvalue.begin==NULL) {
290
+ abstrval=walk_through_nested_loops(param, name);
291
+ if (abstrval!=NULL) varvalue=(param->AbstractVal2pstringFuncPtr)(param->ext_data_state, abstrval);
292
+ }
293
+ if (debuglevel>=TMPL_LOG_DEBUG2) {
294
+ if (name.begin!=NULL) {
295
+ tmpl_log(TMPL_LOG_DEBUG2,"_get_variable_value: name = %.*s ",(int)(name.endnext-name.begin),name.begin);
296
+ } else {
297
+ tmpl_log(TMPL_LOG_DEBUG2,"_get_variable_value: name = NULL ");
298
+ }
299
+ if (varvalue.begin!=NULL) {
300
+ tmpl_log(TMPL_LOG_DEBUG2,"value = %.*s\n",(int)(varvalue.endnext-varvalue.begin),varvalue.begin);
301
+ } else {
302
+ tmpl_log(TMPL_LOG_DEBUG2,"value = UNDEF\n");
303
+ }
304
+ }
305
+ return varvalue;
306
+ }
307
+
308
+ static
309
+ void
310
+ tag_handler_var (struct tmplpro_state *state, PSTRING name, PSTRING defvalue, int escapeopt)
311
+ {
312
+ PSTRING varvalue ={NULL, NULL};
313
+ /*
314
+ if (debuglevel>=TMPL_LOG_DEBUG2) {
315
+ log_state(state,TMPL_LOG_DEBUG2,"Entered tag_handler_var\n");
316
+ }*/
317
+ if (! state->is_visible) return;
318
+ if (state->is_expr) {
319
+ varvalue=parse_expr(name, state);
320
+ } else {
321
+ varvalue=_get_variable_value(state->param, name);
322
+ }
323
+ if (debuglevel>=TMPL_LOG_DEBUG) {
324
+ if (name.begin!=NULL) {
325
+ log_state(state,TMPL_LOG_DEBUG,"variable name = %.*s ",(int)(name.endnext-name.begin),name.begin);
326
+ } else {
327
+ log_state(state,TMPL_LOG_DEBUG,"variable name = NULL ");
328
+ }
329
+ if (varvalue.begin!=NULL) {
330
+ tmpl_log(TMPL_LOG_DEBUG,"value = %.*s\n",(int)(varvalue.endnext-varvalue.begin),varvalue.begin);
331
+ } else {
332
+ tmpl_log(TMPL_LOG_DEBUG,"value = UNDEF\n");
333
+ }
334
+ }
335
+ if (varvalue.begin==NULL) {
336
+ if (defvalue.begin!=defvalue.endnext) {
337
+ varvalue=defvalue;
338
+ } else return;
339
+ }
340
+ if (escapeopt!=HTML_TEMPLATE_OPT_ESCAPE_NO) {
341
+ varvalue=escape_pstring(&(state->str_buffer), varvalue, escapeopt);
342
+ }
343
+ (state->param->WriterFuncPtr)(state->param->ext_writer_state,varvalue.begin,varvalue.endnext);
344
+ }
345
+
346
+ static
347
+ void
348
+ tag_handler_include (struct tmplpro_state *state, PSTRING name, PSTRING defvalue)
349
+ {
350
+ struct tmplpro_param* param;
351
+ char* filename;
352
+ const char* masterpath;
353
+ int x;
354
+ PSTRING varvalue=name;
355
+ if (! state->is_visible) return;
356
+ param=state->param;
357
+ if (param->no_includes) {
358
+ log_state(state,TMPL_LOG_ERROR, "HTML::Template::Pro : Illegal attempt to use TMPL_INCLUDE in template file : (no_includes => 1)\n");
359
+ return;
360
+ }
361
+ if (param->max_includes && param->max_includes < param->cur_includes) return;
362
+ param->cur_includes++;
363
+
364
+ if (state->is_expr) {
365
+ varvalue=parse_expr(name, state);
366
+ } else
367
+ if (varvalue.begin==varvalue.endnext && defvalue.begin!=defvalue.endnext)
368
+ varvalue=defvalue;
369
+ /* pstrdup */
370
+ filename =(char*) malloc(varvalue.endnext-varvalue.begin+1);
371
+ for (x=0;x<varvalue.endnext-varvalue.begin;x++) {
372
+ *(filename+x)=*(varvalue.begin+x);
373
+ }
374
+ *(filename+(varvalue.endnext-varvalue.begin))=0;
375
+ /* end pstrdup */
376
+ masterpath=param->masterpath; /* saving current file name */
377
+ tmplpro_exec_tmpl_filename (param,filename);
378
+ free (filename);
379
+ param->masterpath=masterpath;
380
+ param->cur_includes--;
381
+ return;
382
+ }
383
+
384
+ static
385
+ int
386
+ is_var_true(struct tmplpro_state *state, PSTRING name)
387
+ {
388
+ register int ifval=-1; /*not yet defined*/
389
+ if (state->is_expr) {
390
+ ifval=is_pstring_true(parse_expr(name, state));
391
+ } else
392
+ if (state->param->loop_context_vars) {
393
+ PSTRING loop_var=get_loop_context_vars_value(state->param, name);
394
+ if (loop_var.begin!=NULL) {
395
+ ifval=is_pstring_true(loop_var);
396
+ }
397
+ }
398
+ if (ifval==-1) {
399
+ is_ABSTRACT_VALUE_true_functype userSuppliedIsTrueFunc;
400
+ ABSTRACT_VALUE* abstrval=walk_through_nested_loops(state->param, name);
401
+ if (abstrval==NULL) return 0;
402
+ userSuppliedIsTrueFunc = state->param->IsAbstractValTrueFuncPtr;
403
+ if (userSuppliedIsTrueFunc!=NULL) {
404
+ ifval=(userSuppliedIsTrueFunc)(state->param->ext_data_state, abstrval);
405
+ } else {
406
+ ifval=is_pstring_true((state->param->AbstractVal2pstringFuncPtr)(state->param->ext_data_state, abstrval));
407
+ }
408
+ }
409
+ return ifval;
410
+ }
411
+
412
+ static
413
+ void
414
+ tag_handler_if (struct tmplpro_state *state, PSTRING name)
415
+ {
416
+ struct tagstack_entry iftag;
417
+ iftag.tag=HTML_TEMPLATE_TAG_IF;
418
+ iftag.vcontext=state->is_visible;
419
+ iftag.position=state->cur_pos; /* unused */
420
+ /* state->is_visible && means that we do not evaluate variable in shadow */
421
+ if (state->is_visible && is_var_true(state,name)) {
422
+ iftag.value=1;
423
+ /* state->is_visible is not touched */
424
+ } else {
425
+ iftag.value=0;
426
+ state->is_visible=0;
427
+ }
428
+ tagstack_push(&(state->tag_stack), iftag);
429
+ if (debuglevel>=TMPL_LOG_DEBUG2) log_state(state,TMPL_LOG_DEBUG2,"tag_handler_if:visible context =%d value=%d ",iftag.vcontext,iftag.value);
430
+ }
431
+
432
+ static
433
+ void
434
+ tag_handler_unless (struct tmplpro_state *state, PSTRING name)
435
+ {
436
+ struct tagstack_entry iftag;
437
+ iftag.tag=HTML_TEMPLATE_TAG_UNLESS;
438
+ iftag.vcontext=state->is_visible;
439
+ iftag.position=state->cur_pos; /* unused */
440
+ /* state->is_visible && means that we do not evaluate variable in shadow */
441
+ if (state->is_visible && !is_var_true(state,name)) {
442
+ iftag.value=1;
443
+ /* state->is_visible is not touched */
444
+ } else {
445
+ iftag.value=0;
446
+ state->is_visible=0;
447
+ }
448
+ tagstack_push(&(state->tag_stack), iftag);
449
+ if (debuglevel>=TMPL_LOG_DEBUG2) log_state(state,TMPL_LOG_DEBUG2,"tag_handler_unless:visible context =%d value=%d ",iftag.vcontext,iftag.value);
450
+ }
451
+
452
+ static
453
+ INLINE
454
+ int
455
+ test_stack (int tag)
456
+ {
457
+ // return (tagstack_notempty(&(state->tag_stack)) && (tagstack_top(&(state->tag_stack))->tag==tag));
458
+ return 1;
459
+ }
460
+
461
+ static
462
+ void
463
+ tag_stack_debug (struct tmplpro_state *state, int stack_tag_type)
464
+ {
465
+ if (stack_tag_type) {
466
+ if (tagstack_notempty(&(state->tag_stack))) {
467
+ struct tagstack_entry* iftag=tagstack_top(&(state->tag_stack));
468
+ if (iftag->tag!=stack_tag_type) {
469
+ log_state(state,TMPL_LOG_ERROR, "ERROR: tag mismatch with %s\n",TAGNAME[iftag->tag]);
470
+ }
471
+ } else {
472
+ log_state(state,TMPL_LOG_ERROR, "ERROR: opening tag %s not found\n",TAGNAME[stack_tag_type]);
473
+ }
474
+ }
475
+ }
476
+
477
+ static
478
+ void
479
+ tag_handler_closeif (struct tmplpro_state *state)
480
+ {
481
+ struct tagstack_entry iftag;
482
+ if (! test_stack(HTML_TEMPLATE_TAG_IF)) {
483
+ tag_stack_debug(state,HTML_TEMPLATE_TAG_IF);
484
+ return;
485
+ }
486
+ iftag=tagstack_pop(&(state->tag_stack));
487
+ if (0==state->is_visible) state->last_processed_pos=state->cur_pos;
488
+ state->is_visible=iftag.vcontext;
489
+ }
490
+
491
+ static
492
+ void
493
+ tag_handler_closeunless (struct tmplpro_state *state)
494
+ {
495
+ struct tagstack_entry iftag;
496
+ if (! test_stack(HTML_TEMPLATE_TAG_UNLESS)) {
497
+ tag_stack_debug(state,HTML_TEMPLATE_TAG_UNLESS);
498
+ return;
499
+ }
500
+ iftag=tagstack_pop(&(state->tag_stack));
501
+ if (0==state->is_visible) state->last_processed_pos=state->cur_pos;
502
+ state->is_visible=iftag.vcontext;
503
+ }
504
+
505
+ static
506
+ void
507
+ tag_handler_else (struct tmplpro_state *state)
508
+ {
509
+ struct tagstack_entry* iftag;
510
+ if (! test_stack(HTML_TEMPLATE_TAG_IF) &&
511
+ ! test_stack(HTML_TEMPLATE_TAG_UNLESS)) {
512
+ tag_stack_debug(state,HTML_TEMPLATE_TAG_ELSE);
513
+ return;
514
+ }
515
+ iftag=tagstack_top(&(state->tag_stack));
516
+ if (0==state->is_visible) state->last_processed_pos=state->cur_pos;
517
+ if (iftag->value) {
518
+ state->is_visible=0;
519
+ } else if (1==iftag->vcontext) {
520
+ state->is_visible=1;
521
+ }
522
+ if (debuglevel>=TMPL_LOG_DEBUG2) log_state(state,TMPL_LOG_DEBUG2,"else:(pos " MOD_TD ") visible:context =%d, set to %d ",
523
+ TO_PTRDIFF_T(iftag->position - state->top),iftag->vcontext,state->is_visible);
524
+ }
525
+
526
+ static
527
+ void
528
+ tag_handler_elsif (struct tmplpro_state *state, PSTRING name)
529
+ {
530
+ struct tagstack_entry *iftag;
531
+ if (! test_stack(HTML_TEMPLATE_TAG_IF) &&
532
+ ! test_stack(HTML_TEMPLATE_TAG_UNLESS)) {
533
+ tag_stack_debug(state,HTML_TEMPLATE_TAG_ELSIF);
534
+ return;
535
+ }
536
+ iftag=tagstack_top(&(state->tag_stack));
537
+ if (0==state->is_visible) state->last_processed_pos=state->cur_pos;
538
+ if (iftag->value) {
539
+ state->is_visible=0;
540
+ } else if (1==iftag->vcontext) {
541
+ /* test only if vcontext==true; if the whole tag if..endif itself is invisible, skip the is_var_true test */
542
+ /*TODO: it is reasonable to skip is_var_true test in if/unless too */
543
+ if (is_var_true(state,name)) {
544
+ iftag->value=1;
545
+ state->is_visible=1;
546
+ } else {
547
+ iftag->value=0;
548
+ state->is_visible=0;
549
+ }
550
+ }
551
+ if (debuglevel>=TMPL_LOG_DEBUG2) log_state(state,TMPL_LOG_DEBUG2,"elsif:(pos " MOD_TD ") visible:context =%d, set to %d ",
552
+ TO_PTRDIFF_T(iftag->position - state->top), iftag->vcontext, state->is_visible);
553
+ }
554
+
555
+ static
556
+ int
557
+ next_loop (struct tmplpro_state* state) {
558
+ #ifdef DEBUG
559
+ log_state(state,TMPL_LOG_DEBUG2,"next_loop:before NextLoopFuncPtr\n");
560
+ #endif
561
+ struct ProScopeEntry* currentScope = getCurrentScope(&state->param->var_scope_stack);
562
+ if (!isScopeLoop(currentScope)) {
563
+ log_state(state,TMPL_LOG_ERROR, "next_loop:at scope level %d: internal error - loop is null\n", curScopeLevel(&state->param->var_scope_stack));
564
+ return 0;
565
+ }
566
+ if (++currentScope->loop < currentScope->loop_count || currentScope->loop_count< 0) {
567
+ ABSTRACT_MAP* arrayvalptr=(state->param->GetAbstractMapFuncPtr)(state->param->ext_data_state, currentScope->loops_AV,currentScope->loop);
568
+ if ((arrayvalptr!=NULL)) {
569
+ currentScope->param_HV=arrayvalptr;
570
+ return 1;
571
+ } else {
572
+ /* either undefined loop ended normally or defined loop ended ubnormally */
573
+ if (currentScope->loop_count>0) log_state(state,TMPL_LOG_ERROR, "PARAM:LOOP:next_loop(%d): callback returned null scope\n", currentScope->loop);
574
+ }
575
+ }
576
+ if (state->param->ExitLoopScopeFuncPtr) state->param->ExitLoopScopeFuncPtr(state->param->ext_data_state, currentScope->loops_AV);
577
+ popScope(&state->param->var_scope_stack);
578
+ return 0;
579
+ }
580
+
581
+ static
582
+ int init_loop (struct tmplpro_state *state, PSTRING name) {
583
+ int loop_count;
584
+ ABSTRACT_ARRAY* loopptr=(ABSTRACT_ARRAY*) walk_through_nested_loops(state->param,name);
585
+ if (loopptr==NULL) {
586
+ return 0;
587
+ } else {
588
+ /* set loop array */
589
+ loopptr = (*state->param->AbstractVal2abstractArrayFuncPtr)(state->param->ext_data_state, loopptr);
590
+ if (loopptr == NULL)
591
+ {
592
+ log_state(state,TMPL_LOG_ERROR, "PARAM:LOOP:loop argument:loop was expected but not found.\n");
593
+ return 0;
594
+ }
595
+ loop_count = (*state->param->GetAbstractArrayLengthFuncPtr)(state->param->ext_data_state, loopptr);
596
+ /* 0 is an empty array; <0 is an undefined array (iterated until next_loop==NULL */
597
+ if (0==loop_count) return 0;
598
+ pushScopeLoop(&state->param->var_scope_stack, loop_count, loopptr);
599
+ return 1;
600
+ }
601
+ }
602
+
603
+ static
604
+ void
605
+ tag_handler_loop (struct tmplpro_state *state, PSTRING name)
606
+ {
607
+ struct tagstack_entry iftag;
608
+ iftag.tag=HTML_TEMPLATE_TAG_LOOP;
609
+ iftag.vcontext=state->is_visible;
610
+ iftag.value=0;
611
+ iftag.position=state->cur_pos; /* loop start - to restore in </tmpl_loop> */
612
+ #ifdef DEBUG
613
+ log_state(state,TMPL_LOG_DEBUG2,"tag_handler_loop:before InitLoopFuncPtr\n");
614
+ #endif
615
+ if (state->is_visible && init_loop(state,name) && next_loop(state)) {
616
+ iftag.value=1; /* the loop is non - empty */
617
+ } else {
618
+ /* empty loop is equal to <if false> ... </if> */
619
+ state->is_visible=0;
620
+ }
621
+ #ifdef DEBUG
622
+ log_state(state,TMPL_LOG_DEBUG2,"tag_handler_loop:after InitLoopFuncPtr\n");
623
+ #endif
624
+ tagstack_push(&(state->tag_stack), iftag);
625
+ }
626
+
627
+ static
628
+ void
629
+ tag_handler_closeloop (struct tmplpro_state *state)
630
+ {
631
+ struct tagstack_entry* iftag_ptr;
632
+ if (! test_stack(HTML_TEMPLATE_TAG_LOOP)) {
633
+ tag_stack_debug(state,HTML_TEMPLATE_TAG_LOOP);
634
+ return;
635
+ }
636
+ iftag_ptr=tagstack_top(&(state->tag_stack));
637
+ if (iftag_ptr->value==1 && next_loop(state)) {
638
+ /* continue loop */
639
+ state->cur_pos=iftag_ptr->position;
640
+ state->last_processed_pos=iftag_ptr->position;
641
+ return;
642
+ } else {
643
+ /* finish loop */
644
+ struct tagstack_entry iftag;
645
+ iftag=tagstack_pop(&(state->tag_stack));
646
+ state->is_visible=iftag.vcontext;
647
+ state->last_processed_pos=state->cur_pos;
648
+ }
649
+ }
650
+
651
+ static
652
+ void
653
+ tag_handler_unknown (struct tmplpro_state *state)
654
+ {
655
+ log_state(state,TMPL_LOG_ERROR,"tag_handler_unknown: unknown tag\n");
656
+ }
657
+
658
+ static
659
+ PSTRING
660
+ read_tag_parameter_value (struct tmplpro_state *state)
661
+ {
662
+ PSTRING modifier_value;
663
+ char cur_char;
664
+ char quote_char=0;
665
+ register const char* cur_pos;
666
+ register const char* next_to_end=state->next_to_end;
667
+ jump_over_space(state);
668
+ cur_pos=state->cur_pos;
669
+ cur_char=*(cur_pos);
670
+ if (('"'==cur_char) || ('\''==cur_char)) {
671
+ quote_char=*(cur_pos);
672
+ cur_pos++;
673
+ }
674
+ modifier_value.begin=cur_pos;
675
+ cur_char=*(cur_pos);
676
+ if (quote_char) {
677
+ while (quote_char!=cur_char
678
+ #ifdef COMPAT_ON_BROKEN_QUOTE
679
+ /* compatibility mode; HTML::Template doesn't allow '>' inside quotes */
680
+ && ('>' != quote_char)
681
+ #endif
682
+ && cur_pos<next_to_end) {
683
+ cur_pos++;
684
+ cur_char=*(cur_pos);
685
+ }
686
+ } else {
687
+ while ('>'!=cur_char && ! isspace(cur_char) && cur_pos<next_to_end) {
688
+ cur_pos++;
689
+ cur_char=*(cur_pos);
690
+ }
691
+ }
692
+ if (cur_pos>=next_to_end) {
693
+ log_state(state,TMPL_LOG_ERROR,"quote char %c at pos " MOD_TD " is not terminated\n",
694
+ quote_char,TO_PTRDIFF_T(state->cur_pos-state->top));
695
+ modifier_value.endnext=modifier_value.begin;
696
+ jump_over_space(state);
697
+ return modifier_value;
698
+ }
699
+ modifier_value.endnext=cur_pos;
700
+ if (quote_char) {
701
+ if (quote_char==*cur_pos) {
702
+ cur_pos++;
703
+ } else {
704
+ log_state(state,TMPL_LOG_ERROR,"found %c instead of end quote %c at pos " MOD_TD "\n",
705
+ *cur_pos,quote_char,TO_PTRDIFF_T(cur_pos - state->top));
706
+ }
707
+ }
708
+ state->cur_pos=cur_pos;
709
+ /* log_state(state,TMPL_LOG_DEBUG2," at pos " MOD_TD "",TO_PTRDIFF_T(state->cur_pos-state->top)); */
710
+ jump_over_space(state);
711
+ return modifier_value;
712
+ }
713
+
714
+ static
715
+ int
716
+ try_tag_parameter (struct tmplpro_state *state,const char *modifier,const char *MODIFIER)
717
+ {
718
+ const char* initial_pos=state->cur_pos;
719
+ jump_over_space(state);
720
+ if (is_string(state, modifier, MODIFIER)) {
721
+ jump_over_space(state);
722
+ if ('='==*(state->cur_pos)) {
723
+ state->cur_pos++;
724
+ jump_over_space(state);
725
+ return 1;
726
+ }
727
+ }
728
+ state->cur_pos=initial_pos;
729
+ return 0;
730
+ }
731
+
732
+ static
733
+ void
734
+ try_tmpl_var_options (struct tmplpro_state *state, PSTRING* OptEscape, PSTRING* OptDefault)
735
+ {
736
+ static const char* escapeopt="escape";
737
+ static const char* ESCAPEOPT="ESCAPE";
738
+ static const char* defaultopt="default";
739
+ static const char* DEFAULTOPT="DEFAULT";
740
+ if (try_tag_parameter(state, escapeopt, ESCAPEOPT)) {
741
+ *OptEscape=read_tag_parameter_value(state);
742
+ log_state(state,TMPL_LOG_DEBUG, "found option ESCAPE at pos " MOD_TD "\n",TO_PTRDIFF_T(state->cur_pos-state->top));
743
+ }
744
+ if (try_tag_parameter(state, defaultopt, DEFAULTOPT)) {
745
+ *OptDefault=read_tag_parameter_value(state);
746
+ log_state(state,TMPL_LOG_DEBUG, "found option DEFAULT at pos " MOD_TD "\n",TO_PTRDIFF_T(state->cur_pos-state->top));
747
+ }
748
+ }
749
+
750
+
751
+ static
752
+ void
753
+ process_tmpl_tag(struct tmplpro_state *state)
754
+ {
755
+ const char* tag_start=state->tag_start;
756
+ int is_tag_closed=state->is_tag_closed;
757
+
758
+ int tag_type=HTML_TEMPLATE_BAD_TAG;
759
+ static const char* nameopt="name";
760
+ static const char* NAMEOPT="NAME";
761
+ static const char* expropt="expr";
762
+ static const char* EXPROPT="EXPR";
763
+
764
+ PSTRING OptName = {NULL,NULL};
765
+ PSTRING OptDefault={NULL,NULL};
766
+ PSTRING OptEscape= {NULL,NULL};
767
+
768
+ int i;
769
+ for (i=HTML_TEMPLATE_FIRST_TAG_USED; i<=HTML_TEMPLATE_LAST_TAG_USED; i++) {
770
+ if (is_string(state, tagname[i], TAGNAME[i])) {
771
+ tag_type=i;
772
+ state->tag=tag_type;
773
+ if (debuglevel) {
774
+ if (is_tag_closed) {
775
+ tmpl_log(TMPL_LOG_DEBUG, "found </TMPL_%s> at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
776
+ } else {
777
+ tmpl_log(TMPL_LOG_DEBUG, "found <TMPL_%s> at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
778
+ }
779
+ }
780
+ break;
781
+ }
782
+ }
783
+ if (HTML_TEMPLATE_BAD_TAG==tag_type) {
784
+ log_state(state,TMPL_LOG_ERROR, "found bad tag at pos " MOD_TD "\n", TO_PTRDIFF_T(state->cur_pos-state->top));
785
+ /* TODO: flush its data --- */
786
+ state->cur_pos++;
787
+ return;
788
+ }
789
+
790
+ if (is_tag_closed && (
791
+ tag_type==HTML_TEMPLATE_TAG_ELSE
792
+ || tag_type==HTML_TEMPLATE_TAG_INCLUDE
793
+ || tag_type==HTML_TEMPLATE_TAG_VAR
794
+ )) {
795
+ log_state(state,TMPL_LOG_ERROR, "incorrect tag </TMPL_%s> at pos " MOD_TD "\n",
796
+ TAGNAME[tag_type], TO_PTRDIFF_T(state->cur_pos-state->top));
797
+ }
798
+
799
+ if (is_tag_closed || tag_type==HTML_TEMPLATE_TAG_ELSE) {
800
+ /* tag has no parameter */
801
+
802
+ /* requested compatibility mode
803
+ to try reading NAME inside </closing tags NAME=" ">
804
+ (useful for comments?) */
805
+ #ifdef COMPAT_ALLOW_NAME_IN_CLOSING_TAG
806
+ try_tag_parameter(state, nameopt, NAMEOPT);
807
+ read_tag_parameter_value(state);
808
+ #endif
809
+ } else {
810
+ /* reading parameter */
811
+ state->is_expr=0;
812
+ if (tag_type==HTML_TEMPLATE_TAG_VAR
813
+ || tag_type==HTML_TEMPLATE_TAG_INCLUDE
814
+ ) {
815
+ try_tmpl_var_options(state,&OptEscape,&OptDefault);
816
+ }
817
+
818
+ if (try_tag_parameter(state, expropt, EXPROPT)) {
819
+ state->is_expr=1;
820
+ } else {
821
+ try_tag_parameter(state, nameopt, NAMEOPT);
822
+ }
823
+ OptName=read_tag_parameter_value(state);
824
+
825
+ if (tag_type==HTML_TEMPLATE_TAG_VAR
826
+ || tag_type==HTML_TEMPLATE_TAG_INCLUDE
827
+ ) {
828
+ try_tmpl_var_options(state,&OptEscape,&OptDefault);
829
+ }
830
+ }
831
+
832
+ if (state->is_tag_commented) {
833
+ /* try read comment end */
834
+ /* jump_over_space(state); it should be already done :( */
835
+ jump_over_space(state);
836
+ if (state->cur_pos<state->next_to_end-2 && '-'==*(state->cur_pos) && '-'==*(state->cur_pos+1)) {
837
+ state->cur_pos+=2;
838
+ }
839
+ }
840
+ /* template tags could also be decorated as xml <tmpl_TAG /> */
841
+ if (!state->is_tag_closed && '/'==*(state->cur_pos)) state->cur_pos++;
842
+
843
+ if ('>'==*(state->cur_pos)) {
844
+ state->cur_pos++;
845
+ } else {
846
+ log_state(state,TMPL_LOG_ERROR,"end tag:found %c instead of > at pos " MOD_TD "\n",
847
+ *state->cur_pos, TO_PTRDIFF_T(state->cur_pos-state->top));
848
+ }
849
+ /* flush run chars (if in SHOW mode) */
850
+ if (state->is_visible) {
851
+ (state->param->WriterFuncPtr)(state->param->ext_writer_state,state->last_processed_pos,tag_start);
852
+ state->last_processed_pos=state->cur_pos;
853
+ }
854
+ /* TODO: call tag_specific handler by array of handlers
855
+ var_tag_handler(..) */
856
+ if (is_tag_closed) {
857
+ switch (tag_type) {
858
+ case HTML_TEMPLATE_TAG_IF: tag_handler_closeif(state);break;
859
+ case HTML_TEMPLATE_TAG_UNLESS: tag_handler_closeunless(state);break;
860
+ case HTML_TEMPLATE_TAG_LOOP: tag_handler_closeloop(state);break;
861
+ default: tag_handler_unknown(state);break;
862
+
863
+ }
864
+ } else {
865
+ /* int escape = HTML_TEMPLATE_OPT_ESCAPE_NO; */
866
+ int escape = state->param->default_escape;
867
+ switch (tag_type) {
868
+ case HTML_TEMPLATE_TAG_VAR:
869
+ if (OptEscape.begin!=OptEscape.endnext) {
870
+ switch (*OptEscape.begin) {
871
+ case '1': case 'H': case 'h': /* HTML*/
872
+ escape = HTML_TEMPLATE_OPT_ESCAPE_HTML;
873
+ break;
874
+ case 'U': case 'u': /* URL */
875
+ escape = HTML_TEMPLATE_OPT_ESCAPE_URL;
876
+ break;
877
+ case 'J': case 'j': /* JS */
878
+ escape = HTML_TEMPLATE_OPT_ESCAPE_JS;
879
+ break;
880
+ case '0': case 'N': case 'n': /* 0 or NONE */
881
+ escape = HTML_TEMPLATE_OPT_ESCAPE_NO;
882
+ break;
883
+ default:
884
+ log_state(state,TMPL_LOG_ERROR, " unsupported value of ESCAPE=%.*s\n",(int)(OptEscape.endnext-OptEscape.begin),OptEscape.begin);
885
+ }
886
+ }
887
+ tag_handler_var(state,OptName,OptDefault,escape);
888
+ break;
889
+ case HTML_TEMPLATE_TAG_IF: tag_handler_if(state,OptName); break;
890
+ case HTML_TEMPLATE_TAG_UNLESS: tag_handler_unless(state,OptName);break;
891
+ case HTML_TEMPLATE_TAG_ELSE: tag_handler_else(state); break;
892
+ case HTML_TEMPLATE_TAG_ELSIF: tag_handler_elsif(state,OptName);break;
893
+ case HTML_TEMPLATE_TAG_LOOP: tag_handler_loop(state,OptName);break;
894
+ case HTML_TEMPLATE_TAG_INCLUDE: tag_handler_include(state,OptName,OptDefault);break;
895
+ default: tag_handler_unknown(state);break;
896
+ }
897
+ }
898
+
899
+ }
900
+
901
+ static
902
+ void
903
+ process_state (struct tmplpro_state * state)
904
+ {
905
+ static const char* metatag="tmpl_";
906
+ static const char* METATAG="TMPL_";
907
+ flag is_tag_closed;
908
+ flag is_tag_commented;
909
+ const char* last_safe_pos=state->next_to_end-TAG_WIDTH_OFFSET;
910
+ if (debuglevel) tmpl_log(TMPL_LOG_DEBUG,"process_state:initiated at scope stack depth = %d\n",
911
+ curScopeLevel(&state->param->var_scope_stack));
912
+ tagstack_init(&(state->tag_stack));
913
+ pbuffer_init(&(state->str_buffer));
914
+ /* magic; 256 > 50 (50 is min.required for double to string conversion */
915
+ pbuffer_init_as(&(state->expr_left_pbuffer), 256);
916
+ pbuffer_init_as(&(state->expr_right_pbuffer), 256);
917
+
918
+ while (state->cur_pos < last_safe_pos) {
919
+ register const char* cur_pos=state->cur_pos;
920
+ while (cur_pos < last_safe_pos && '<'!=*(cur_pos++)) {};
921
+ if (cur_pos >= last_safe_pos) break;
922
+ state->tag_start=cur_pos-1;
923
+ is_tag_closed=0;
924
+ is_tag_commented=0;
925
+ state->cur_pos=cur_pos;
926
+ if (('!'==*(cur_pos)) && ('-'==*(cur_pos+1)) && ('-'==*(cur_pos+2))) {
927
+ state->cur_pos+=3;
928
+ jump_over_space(state);
929
+ is_tag_commented=1;
930
+ }
931
+ if ('/'==*(state->cur_pos)) {
932
+ state->cur_pos++;
933
+ is_tag_closed=1;
934
+ }
935
+ if (is_string(state,metatag,METATAG)) {
936
+ state->is_tag_commented=is_tag_commented;
937
+ state->is_tag_closed=is_tag_closed;
938
+ process_tmpl_tag(state);
939
+ }
940
+ }
941
+ (state->param->WriterFuncPtr)(state->param->ext_writer_state,state->last_processed_pos,state->next_to_end);
942
+
943
+ pbuffer_free(&(state->expr_right_pbuffer));
944
+ pbuffer_free(&(state->expr_left_pbuffer));
945
+ pbuffer_free(&(state->str_buffer));
946
+ tagstack_free(&(state->tag_stack));
947
+ if (debuglevel) tmpl_log(TMPL_LOG_DEBUG,"process_state:finished\n");
948
+ }
949
+
950
+ static
951
+ void
952
+ init_state (struct tmplpro_state *state, struct tmplpro_param *param)
953
+ {
954
+ debuglevel=param->debug;
955
+ tmpl_log_set_level(debuglevel);
956
+ /* initializing state */
957
+ state->param=param;
958
+ state->last_processed_pos=state->top;
959
+ state->cur_pos=state->top;
960
+ state->tag=HTML_TEMPLATE_NO_TAG;
961
+ state->is_visible=1;
962
+ }
963
+
964
+ static
965
+ int
966
+ tmplpro_exec_tmpl_filename (struct tmplpro_param *param, const char* filename)
967
+ {
968
+ struct tmplpro_state state;
969
+ int mmapstatus;
970
+ PSTRING memarea;
971
+ int retval = 0;
972
+ /*
973
+ * param->masterpath is path to upper level template
974
+ * (or NULL in toplevel) which called <include filename>.
975
+ * we use it to calculate filepath for filename.
976
+ * Then filename becames upper level template for its <include>.
977
+ */
978
+ const char* filepath=(param->FindFileFuncPtr)(param->ext_findfile_state,filename, param->masterpath);
979
+ if (NULL==filepath) return ERR_PRO_FILE_NOT_FOUND;
980
+ /* filepath should be alive for every nested template */
981
+ filepath = strdup(filepath);
982
+
983
+ param->masterpath=filepath;
984
+ if (param->filters) memarea=(param->LoadFileFuncPtr)(param->ext_filter_state,filepath);
985
+ else memarea=mmap_load_file(filepath);
986
+ if (memarea.begin == NULL) {
987
+ retval = ERR_PRO_CANT_OPEN_FILE;
988
+ goto cleanup_filepath;
989
+ }
990
+ state.top =memarea.begin;
991
+ state.next_to_end=memarea.endnext;
992
+ if (memarea.begin < memarea.endnext) {
993
+ /* to avoid crash with empty file */
994
+ init_state(&state,param);
995
+ log_state(&state,TMPL_LOG_DEBUG, "exec_tmpl: loading %s\n",filename);
996
+ process_state(&state);
997
+ }
998
+ /* destroying */
999
+ if (param->filters) mmapstatus=(param->UnloadFileFuncPtr)(param->ext_filter_state,memarea);
1000
+ else mmapstatus=mmap_unload_file(memarea);
1001
+ cleanup_filepath:
1002
+ if (filepath!=NULL) free((void*) filepath);
1003
+ return retval;
1004
+ }
1005
+
1006
+ static
1007
+ int
1008
+ tmplpro_exec_tmpl_scalarref (struct tmplpro_param *param, PSTRING memarea)
1009
+ {
1010
+ struct tmplpro_state state;
1011
+ param->masterpath=NULL; /* no upper file */
1012
+ state.top = memarea.begin;
1013
+ state.next_to_end=memarea.endnext;
1014
+ if (memarea.begin == memarea.endnext) return 0;
1015
+ init_state(&state,param);
1016
+ process_state(&state);
1017
+ return 0;
1018
+ }
1019
+
1020
+ #include "builtin_findfile.inc"
1021
+ #include "callback_stubs.inc"
1022
+
1023
+ API_IMPL
1024
+ int
1025
+ APICALL
1026
+ tmplpro_exec_tmpl (struct tmplpro_param *param)
1027
+ {
1028
+ int exitcode=0;
1029
+ if (param->GetAbstractValFuncPtr==NULL ||
1030
+ param->AbstractVal2pstringFuncPtr==NULL ||
1031
+ param->AbstractVal2abstractArrayFuncPtr==NULL ||
1032
+ /*param->GetAbstractArrayLengthFuncPtr==NULL ||*/
1033
+ param->GetAbstractMapFuncPtr==NULL ||
1034
+ (param->IsExprUserfncFuncPtr!=NULL &&
1035
+ (param->InitExprArglistFuncPtr==NULL ||
1036
+ param->PushExprArglistFuncPtr==NULL ||
1037
+ param->FreeExprArglistFuncPtr==NULL ||
1038
+ param->CallExprUserfncFuncPtr==NULL))
1039
+ )
1040
+ {
1041
+ tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: a required callback is missing.");
1042
+ return ERR_PRO_INVALID_ARGUMENT;
1043
+ }
1044
+ if (param->filters &&
1045
+ (param->LoadFileFuncPtr==NULL ||
1046
+ param->UnloadFileFuncPtr==NULL)) {
1047
+ tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: filters is set but filter callbacks are missing.");
1048
+ }
1049
+ /* set up stabs */
1050
+ if (NULL==param->WriterFuncPtr) param->WriterFuncPtr = stub_write_chars_to_stdout;
1051
+ if (NULL==param->ext_findfile_state) param->ext_findfile_state = param;
1052
+ if (NULL==param->FindFileFuncPtr) {
1053
+ param->FindFileFuncPtr = stub_find_file_func;
1054
+ param->ext_findfile_state = param;
1055
+ /*pbuffer_init(&param->builtin_findfile_buffer);*/
1056
+ }
1057
+ if (NULL==param->IsExprUserfncFuncPtr) param->IsExprUserfncFuncPtr = stub_is_expr_userfnc_func;
1058
+ if (NULL==param->LoadFileFuncPtr) param->LoadFileFuncPtr = stub_load_file_func;
1059
+ if (NULL==param->UnloadFileFuncPtr) param->UnloadFileFuncPtr = stub_unload_file_func;
1060
+ if (NULL==param->GetAbstractArrayLengthFuncPtr) param->GetAbstractArrayLengthFuncPtr = stub_get_ABSTRACT_ARRAY_length_func;
1061
+
1062
+ Scope_reset(&param->var_scope_stack, param->param_map_count);
1063
+ /* reset other internals */
1064
+ param->cur_includes=0; /* internal counter of include depth */
1065
+ /*masterpath=NULL;*/
1066
+
1067
+ if (param->scalarref.begin) exitcode = tmplpro_exec_tmpl_scalarref(param, param->scalarref);
1068
+ else if (param->filename) exitcode = tmplpro_exec_tmpl_filename(param, param->filename);
1069
+ else {
1070
+ tmpl_log(TMPL_LOG_ERROR,"tmplpro_exec_tmpl: neither scalarref nor filename was specified.");
1071
+ exitcode = ERR_PRO_INVALID_ARGUMENT;
1072
+ }
1073
+
1074
+ return exitcode;
1075
+ }
1076
+
1077
+ API_IMPL
1078
+ MPSTRING
1079
+ APICALL
1080
+ tmplpro_tmpl2pstring (struct tmplpro_param *param, int *retvalptr)
1081
+ {
1082
+ int exitcode;
1083
+ MPSTRING retval;
1084
+ struct builtin_writer_state state;
1085
+ writer_functype save_writer_func = param->WriterFuncPtr;
1086
+ ABSTRACT_WRITER* save_writer_state = param->ext_writer_state;
1087
+ param->WriterFuncPtr = stub_write_chars_to_pbuffer;
1088
+ param->ext_writer_state = &state;
1089
+ pbuffer_init_as(&state.buffer, 4000);
1090
+ state.size = 0;
1091
+ exitcode = tmplpro_exec_tmpl (param);
1092
+ param->WriterFuncPtr = save_writer_func;
1093
+ param->ext_writer_state = save_writer_state;
1094
+ if (retvalptr) *retvalptr=exitcode;
1095
+ retval.begin = pbuffer_string(&state.buffer);
1096
+ retval.endnext = retval.begin+state.size;
1097
+ *retval.endnext='\0';
1098
+ return retval;
1099
+ }
1100
+
1101
+ API_IMPL
1102
+ void
1103
+ APICALL
1104
+ tmplpro_clear_option_param_map(struct tmplpro_param *param)
1105
+ {
1106
+ param->param_map_count=0;
1107
+ Scope_reset(&param->var_scope_stack,param->param_map_count);
1108
+ }
1109
+
1110
+ API_IMPL
1111
+ int
1112
+ APICALL
1113
+ tmplpro_push_option_param_map(struct tmplpro_param *param, ABSTRACT_MAP* map, EXPR_int64 flags)
1114
+ {
1115
+ pushScopeMap(&param->var_scope_stack, map, (int) flags);
1116
+ return ++(param->param_map_count);
1117
+ }
1118
+
1119
+ API_IMPL
1120
+ int
1121
+ APICALL
1122
+ tmplpro_count_option_param_map(struct tmplpro_param *param)
1123
+ {
1124
+ return param->param_map_count;
1125
+ }
1126
+
1127
+
1128
+ API_IMPL
1129
+ void
1130
+ APICALL
1131
+ tmplpro_procore_init(void)
1132
+ {
1133
+ }
1134
+
1135
+ API_IMPL
1136
+ void
1137
+ APICALL
1138
+ tmplpro_procore_done(void)
1139
+ {
1140
+ }
1141
+
1142
+ /* internal initialization of struct tmplpro_param */
1143
+ API_IMPL
1144
+ struct tmplpro_param*
1145
+ APICALL
1146
+ tmplpro_param_init(void)
1147
+ {
1148
+ struct tmplpro_param* param=(struct tmplpro_param*) malloc (sizeof(struct tmplpro_param));
1149
+ if (param==NULL) return param;
1150
+ /* filling initial struct tmplpro_param with 0 */
1151
+ memset (param, 0, sizeof(struct tmplpro_param));
1152
+ /* current level of inclusion */
1153
+ /* param->cur_includes=0; */
1154
+ /* not to use external file loader */
1155
+ /* param->filters=0;
1156
+ param->default_escape=HTML_TEMPLATE_OPT_ESCAPE_NO;
1157
+ param->masterpath=NULL; *//* we are not included by something *//*
1158
+ param->expr_func_map=NULL;
1159
+ param->expr_func_arglist=NULL;
1160
+ */
1161
+ param->max_includes=256;
1162
+ Scope_init(&param->var_scope_stack);
1163
+ /* no need for them due to memset 0
1164
+ pbuffer_preinit(&param->builtin_findfile_buffer);
1165
+ pbuffer_preinit(&param->lowercase_varname_buffer);
1166
+ pbuffer_preinit(&param->uppercase_varname_buffer);
1167
+ */
1168
+ return param;
1169
+ }
1170
+
1171
+ API_IMPL
1172
+ void
1173
+ APICALL
1174
+ tmplpro_param_free(struct tmplpro_param* param)
1175
+ {
1176
+ pbuffer_free(&param->builtin_findfile_buffer);
1177
+ pbuffer_free(&param->lowercase_varname_buffer);
1178
+ pbuffer_free(&param->uppercase_varname_buffer);
1179
+ Scope_free(&param->var_scope_stack);
1180
+ free(param);
1181
+ }
1182
+
1183
+ #include "tagstack.inc"
1184
+
1185
+ /*
1186
+ * Local Variables:
1187
+ * mode: c
1188
+ * End:
1189
+ */