File Coverage

procore.c
Criterion Covered Total %
statement 248 326 76.0
branch 155 232 66.8
condition n/a
subroutine n/a
pod n/a
total 403 558 72.2


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5              
6             #include "tmplpro.h"
7             #include "pconst.h"
8             #include "procore.h"
9             #include "prostate.h"
10             #include "provalue.h"
11             #include "tagstack.h"
12             #include "pbuffer.h"
13             #include "parse_expr.h"
14             #include "pparam.h"
15             #include "optint.h"
16             #include "proscope.h"
17             #include "proscope.inc"
18             #include "pstrutils.inc"
19             #include "pmiscdef.h" /*for snprintf */
20             /* for mmap_load_file & mmap_unload_file */
21             #include "loadfile.inc"
22             #include "loopvar.inc"
23              
24             #define HTML_TEMPLATE_NO_TAG -1
25             #define HTML_TEMPLATE_BAD_TAG 0
26             #define HTML_TEMPLATE_FIRST_TAG_USED 1
27             #define HTML_TEMPLATE_TAG_VAR 1
28             #define HTML_TEMPLATE_TAG_INCLUDE 2
29             #define HTML_TEMPLATE_TAG_LOOP 3
30             #define HTML_TEMPLATE_TAG_IF 4
31             #define HTML_TEMPLATE_TAG_ELSE 5
32             #define HTML_TEMPLATE_TAG_UNLESS 6
33             #define HTML_TEMPLATE_TAG_ELSIF 7
34             #define HTML_TEMPLATE_LAST_TAG_USED 7
35              
36             static
37             const char* const tagname[]={
38             "Bad or unsupported tag", /* 0 */
39             "var", "include", "loop", "if", "else", "unless", "elsif"
40             };
41              
42             static
43             const char* const TAGNAME[]={
44             "Bad or unsupported tag", /* 0 */
45             "VAR", "INCLUDE", "LOOP", "IF", "ELSE", "UNLESS", "ELSIF"
46             };
47              
48             static int debuglevel=0;
49              
50             #define TAG_OPT_NAME 0
51             #define TAG_OPT_EXPR 1
52             #define TAG_OPT_ESCAPE 2
53             #define TAG_OPT_DEFAULT 3
54             #define MIN_TAG_OPT 0
55             #define MAX_TAG_OPT 3
56              
57             static const char* const tagopt[]={"name", "expr", "escape", "default" };
58             static const char* const TAGOPT[]={"NAME", "EXPR", "ESCAPE", "DEFAULT" };
59              
60             #include "prostate.inc"
61             #include "tags.inc"
62              
63             static const char tag_can_be_closed[]={
64             1 /*Bad or unsupported tag*/,
65             0 /*VAR*/,
66             0 /*INCLUDE*/,
67             1 /*LOOP*/,
68             1 /*IF*/,
69             0 /*ELSE*/,
70             1 /*UNLESS*/,
71             1 /*ELSIF*/,
72             0 /**/,
73             };
74              
75             static const char tag_has_opt[][6]={
76             /* "name", "expr", "escape", "default", todo, todo */
77              
78             { 0, 0, 0, 0, 0, 0 }, /*Bad or unsupported tag*/
79             { 1, 1, 1, 1, 0, 0 }, /*VAR*/
80             { 1, 1, 0, 1, 0, 0 }, /*INCLUDE*/
81             { 1, 0, 0, 0, 0, 0 }, /*LOOP*/
82             { 1, 1, 0, 0, 0, 0 }, /*IF*/
83             { 0, 0, 0, 0, 0, 0 }, /*ELSE*/
84             { 1, 1, 0, 0, 0, 0 }, /*UNLESS*/
85             { 1, 1, 0, 0, 0, 0 }, /*ELSIF*/
86             { 0, 0, 0, 0, 0, 0 }, /**/
87             };
88              
89             typedef void (*tag_handler_func)(struct tmplpro_state *state, const PSTRING* const TagOptVal);
90              
91             static const tag_handler_func output_closetag_handler[]={
92             tag_handler_unknown, /*Bad or unsupported tag*/
93             tag_handler_unknown, /*VAR*/
94             tag_handler_unknown, /*INCLUDE*/
95             tag_handler_closeloop, /*LOOP*/
96             tag_handler_closeif, /*IF*/
97             tag_handler_unknown, /*ELSE*/
98             tag_handler_closeunless, /*UNLESS*/
99             tag_handler_unknown, /*ELSIF*/
100             tag_handler_unknown, /**/
101             };
102             static const tag_handler_func output_opentag_handler[]={
103             tag_handler_unknown, /*Bad or unsupported tag*/
104             tag_handler_var, /*VAR*/
105             tag_handler_include, /*INCLUDE*/
106             tag_handler_loop, /*LOOP*/
107             tag_handler_if, /*IF*/
108             tag_handler_else, /*ELSE*/
109             tag_handler_unless, /*UNLESS*/
110             tag_handler_elsif, /*ELSIF*/
111             tag_handler_unknown, /**/
112             };
113              
114             static
115             int
116 33109           is_string(struct tmplpro_state *state, const char* pattern,const char* PATTERN)
117             {
118 33109           const char* cur_pos=state->cur_pos;
119 33109           register const char* const next_to_end = state->next_to_end;
120 70443 100         while (*pattern && cur_pos
    50          
121 61915 100         if (*pattern == *cur_pos || *PATTERN == *cur_pos) {
    100          
122 37334           pattern++;
123 37334           PATTERN++;
124 37334           cur_pos++;
125             } else {
126 24581           return 0;
127             }
128             }
129 8528 50         if (cur_pos>=next_to_end) return 0;
130 8528           state->cur_pos=cur_pos;
131 8528           return 1;
132             }
133              
134             static
135             INLINE
136             void
137 26246           jump_over_space(struct tmplpro_state *state)
138             {
139 26246           register const char* const next_to_end = state->next_to_end;
140 32397 100         while (isspace(*(state->cur_pos)) && state->cur_poscur_pos++;};
    50          
141 26246           }
142              
143             static
144             INLINE
145             void
146             jump_to_char(struct tmplpro_state *state, char c)
147             {
148             register const char* const next_to_end = state->next_to_end;
149             while (c!=*(state->cur_pos) && state->cur_poscur_pos++;};
150             }
151              
152             static
153             PSTRING
154 2411           read_tag_parameter_value (struct tmplpro_state *state)
155             {
156             PSTRING modifier_value;
157             char cur_char;
158 2411           char quote_char=0;
159             register const char* cur_pos;
160 2411           const char* const next_to_end=state->next_to_end;
161 2411           jump_over_space(state);
162 2411           cur_pos=state->cur_pos;
163 2411           cur_char=*cur_pos;
164 2411 100         if (('"'==cur_char) || ('\''==cur_char)) {
    100          
165 1518           quote_char=*cur_pos;
166 1518           cur_pos++;
167             }
168 2411           modifier_value.begin=cur_pos;
169 2411           cur_char=*cur_pos;
170 2411 100         if (quote_char) {
171 14298 100         while (quote_char!=cur_char
172             #ifdef COMPAT_ON_BROKEN_QUOTE
173             /* compatibility mode; HTML::Template doesn't allow '>' inside quotes */
174             && ('>' != quote_char)
175             #endif
176 12782 100         && cur_pos
177 12780           cur_pos++;
178 12780           cur_char=*cur_pos;
179             }
180             } else {
181 5132 100         while ('>'!=cur_char && ! isspace(cur_char) && cur_pos
    100          
    50          
182 4239           cur_pos++;
183 4239           cur_char=*cur_pos;
184             }
185             }
186 2411 100         if (cur_pos>=next_to_end) {
187 2           log_state(state,TMPL_LOG_ERROR,"quote char %c at pos " MOD_TD " is not terminated\n",
188 4           quote_char,TO_PTRDIFF_T(state->cur_pos - state->top));
189 2           modifier_value.endnext=modifier_value.begin;
190 2           jump_over_space(state);
191 2           return modifier_value;
192             }
193 2409           modifier_value.endnext=cur_pos;
194 2409 100         if (quote_char) {
195 1516 50         if (quote_char==*cur_pos) {
196 1516           cur_pos++;
197             } else {
198 0           log_state(state,TMPL_LOG_ERROR,"found %c instead of end quote %c at pos " MOD_TD "\n",
199 0           *cur_pos,quote_char,TO_PTRDIFF_T(cur_pos - state->top));
200             }
201             }
202 2409           state->cur_pos=cur_pos;
203             /* if (debuglevel) log_state(state,TMPL_LOG_DEBUG2," at pos " MOD_TD "",TO_PTRDIFF_T(state->cur_pos-state->top)); */
204 2409           jump_over_space(state);
205 2411           return modifier_value;
206             }
207              
208             static
209             int
210 17904           try_tag_parameter (struct tmplpro_state *state,const char *modifier,const char *MODIFIER)
211             {
212 17904           const char* const initial_pos=state->cur_pos;
213 17904           jump_over_space(state);
214 17904 100         if (is_string(state, modifier, MODIFIER)) {
215 1738           jump_over_space(state);
216 1738 100         if ('='==*(state->cur_pos)) {
217 1736           state->cur_pos++;
218 1736           jump_over_space(state);
219 1736           return 1;
220             }
221             }
222 16168           state->cur_pos=initial_pos;
223 16168           return 0;
224             }
225              
226             static
227             void
228 2866           try_tmpl_var_options (struct tmplpro_state *state, int tag_type, PSTRING* TagOptVal)
229             {
230             int i;
231 2866           int opt_found = 1;
232             /* reading parameter */
233 7342 100         while (opt_found) {
234 4476           int found_in_loop=0;
235 22380 100         for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
236 17904 100         if (
237             /* we will complain about syntax errors later;
238             tag_has_opt[tag_type][i] && */
239 17904           try_tag_parameter(state, tagopt[i], TAGOPT[i])) {
240 1736           TagOptVal[i] = read_tag_parameter_value(state);
241 1736           found_in_loop=1;
242 1736 100         if (debuglevel) log_state(state,TMPL_LOG_DEBUG,"in tag %s: found option %s=%.*s\n", TAGNAME[tag_type], TAGOPT[i],(int)(TagOptVal[i].endnext-TagOptVal[i].begin),TagOptVal[i].begin);
243             }
244             }
245 4476 100         if (!found_in_loop) opt_found = 0;
246             }
247 2866           }
248              
249             static
250             void
251 3395           process_tmpl_tag(struct tmplpro_state *state)
252             {
253 3395           const int is_tag_closed=state->is_tag_closed;
254              
255 3395           int tag_type=HTML_TEMPLATE_BAD_TAG;
256             PSTRING TagOptVal[MAX_TAG_OPT+1];
257              
258             int i;
259 16975 100         for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
260 13580           TagOptVal[i].begin = NULL;
261 13580           TagOptVal[i].endnext = NULL;
262             }
263              
264 9398 50         for (i=HTML_TEMPLATE_FIRST_TAG_USED; i<=HTML_TEMPLATE_LAST_TAG_USED; i++) {
265 9398 100         if (is_string(state, tagname[i], TAGNAME[i])) {
266 3395           tag_type=i;
267 3395           state->tag=tag_type;
268 3395 100         if (debuglevel) {
269 5 100         if (is_tag_closed) {
270 1           tmpl_log(TMPL_LOG_DEBUG, "found at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
271             } else {
272 4           tmpl_log(TMPL_LOG_DEBUG, "found at pos " MOD_TD "\n",TAGNAME[i], TO_PTRDIFF_T(state->cur_pos-state->top));
273             }
274             }
275 3395           break;
276             }
277             }
278 3395 50         if (HTML_TEMPLATE_BAD_TAG==tag_type) {
279 0           state->param->found_syntax_error=1;
280 0           log_state(state,TMPL_LOG_ERROR, "found bad/unsupported tag at pos " MOD_TD "\n", TO_PTRDIFF_T(state->cur_pos-state->top));
281             /* TODO: flush its data --- */
282 0           state->cur_pos++;
283 0           return;
284             }
285              
286 3395 100         if (is_tag_closed && !tag_can_be_closed[tag_type]) {
    50          
287 0           state->param->found_syntax_error=1;
288 0           log_state(state,TMPL_LOG_ERROR, "incorrect closed tag at pos " MOD_TD "\n",
289 0           TAGNAME[tag_type], TO_PTRDIFF_T(state->cur_pos-state->top));
290             }
291              
292 3395 100         if (is_tag_closed || ! tag_has_opt[tag_type][TAG_OPT_NAME]) {
    100          
293             /* tag has no parameter */
294             #ifdef COMPAT_ALLOW_NAME_IN_CLOSING_TAG
295             /* requested compatibility mode
296             to try reading NAME inside
297             (useful for comments?) */
298             try_tag_parameter(state, tagopt[TAG_OPT_NAME], TAGOPT[TAG_OPT_NAME]);
299             read_tag_parameter_value(state);
300             #endif
301             } else {
302 2191           try_tmpl_var_options(state, tag_type, TagOptVal);
303             /* suport for short syntax */
304 2191 100         if (TagOptVal[TAG_OPT_NAME].begin == NULL &&
    50          
305 1234 100         tag_has_opt[tag_type][TAG_OPT_NAME] &&
306 1201 100         (!tag_has_opt[tag_type][TAG_OPT_EXPR] || TagOptVal[TAG_OPT_EXPR].begin == NULL )) {
307 675           TagOptVal[TAG_OPT_NAME]=read_tag_parameter_value(state);
308 675           try_tmpl_var_options(state, tag_type, TagOptVal);
309             }
310              
311 2191 100         if (TagOptVal[TAG_OPT_NAME].begin == NULL &&
    50          
312 559 50         tag_has_opt[tag_type][TAG_OPT_NAME] &&
313 559 50         (!tag_has_opt[tag_type][TAG_OPT_EXPR] || TagOptVal[TAG_OPT_EXPR].begin == NULL )) {
314 0           state->param->found_syntax_error=1;
315 0           log_state(state,TMPL_LOG_ERROR,"NAME or EXPR is required for TMPL_%s\n", TAGNAME[tag_type]);
316             }
317 10955 100         for (i=MIN_TAG_OPT; i<=MAX_TAG_OPT; i++) {
318 8764 100         if (TagOptVal[i].begin!=NULL && ! tag_has_opt[tag_type][i]) {
    50          
319 0           state->param->found_syntax_error=1;
320 0           log_state(state,TMPL_LOG_ERROR,"TMPL_%s does not support %s= option\n", TAGNAME[tag_type], TAGOPT[i]);
321             }
322             }
323             }
324              
325 3395 100         if (state->is_tag_commented) {
326             /* try read comment end */
327             /* jump_over_space(state); it should be already done :( */
328 18           jump_over_space(state);
329 18 50         if (state->cur_posnext_to_end-2 && '-'==*(state->cur_pos) && '-'==*(state->cur_pos+1)) {
    50          
    50          
330 18           state->cur_pos+=2;
331             }
332             }
333             /* template tags could also be decorated as xml */
334 3395 100         if (!is_tag_closed && '/'==*(state->cur_pos)) state->cur_pos++;
    100          
335              
336 3395 100         if ('>'==*(state->cur_pos)) {
337 3392           state->cur_pos++;
338             } else {
339 3           state->param->found_syntax_error=1;
340 3           log_state(state,TMPL_LOG_ERROR,"end tag:found %c instead of > at pos " MOD_TD "\n",
341 9           *state->cur_pos, TO_PTRDIFF_T(state->cur_pos-state->top));
342             }
343             /* flush run chars (if in SHOW mode) */
344 3395 100         if (state->is_visible) {
345 2486           (state->param->WriterFuncPtr)(state->param->ext_writer_state,state->last_processed_pos,state->tag_start);
346 2486           state->last_processed_pos=state->cur_pos;
347             }
348 3395 100         if (is_tag_closed) {
349 798           output_closetag_handler[tag_type](state,TagOptVal);
350             } else {
351 3395           output_opentag_handler[tag_type](state,TagOptVal);
352             }
353             }
354              
355              
356             /* max offset to ensure we are not out of file when try