html-template-pro 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ */