2 * LuCI Template - Parser implementation
4 * Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.org>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include "template_parser.h"
20 #include "template_utils.h"
21 #include "template_lmo.h"
24 /* leading and trailing code for different types */
25 const char *gen_code
[9][2] = {
27 { "write(\"", "\")" },
29 { "write(tostring(", " or \"\"))" },
30 { "include(\"", "\")" },
31 { "write(\"", "\")" },
32 { "write(\"", "\")" },
37 /* Simple strstr() like function that takes len arguments for both haystack and needle. */
38 static char *strfind(char *haystack
, int hslen
, const char *needle
, int ndlen
)
43 for( i
= 0; i
< hslen
; i
++ )
45 if( haystack
[i
] == needle
[0] )
47 match
= ((ndlen
== 1) || ((i
+ ndlen
) <= hslen
));
49 for( j
= 1; (j
< ndlen
) && ((i
+ j
) < hslen
); j
++ )
51 if( haystack
[i
+j
] != needle
[j
] )
66 struct template_parser
* template_open(const char *file
)
69 struct template_parser
*parser
;
71 if (!(parser
= malloc(sizeof(*parser
))))
74 memset(parser
, 0, sizeof(*parser
));
81 if ((parser
->fd
= open(file
, O_RDONLY
)) < 0)
84 parser
->size
= s
.st_size
;
85 parser
->data
= mmap(NULL
, parser
->size
, PROT_READ
, MAP_PRIVATE
,
88 if (parser
->data
!= MAP_FAILED
)
90 parser
->off
= parser
->data
;
91 parser
->cur_chunk
.type
= T_TYPE_INIT
;
92 parser
->cur_chunk
.s
= parser
->data
;
93 parser
->cur_chunk
.e
= parser
->data
;
99 template_close(parser
);
103 struct template_parser
* template_string(const char *str
, uint32_t len
)
105 struct template_parser
*parser
;
112 if (!(parser
= malloc(sizeof(*parser
))))
115 memset(parser
, 0, sizeof(*parser
));
119 parser
->data
= (char*)str
;
121 parser
->off
= parser
->data
;
122 parser
->cur_chunk
.type
= T_TYPE_INIT
;
123 parser
->cur_chunk
.s
= parser
->data
;
124 parser
->cur_chunk
.e
= parser
->data
;
129 template_close(parser
);
133 void template_close(struct template_parser
*parser
)
138 if (parser
->gc
!= NULL
)
141 /* if file is not set, we were parsing a string */
143 if ((parser
->data
!= NULL
) && (parser
->data
!= MAP_FAILED
))
144 munmap(parser
->data
, parser
->size
);
153 void template_text(struct template_parser
*parser
, const char *e
)
155 const char *s
= parser
->off
;
157 if (s
< (parser
->data
+ parser
->size
))
159 if (parser
->strip_after
)
161 while ((s
<= e
) && isspace(*s
))
165 parser
->cur_chunk
.type
= T_TYPE_TEXT
;
169 parser
->cur_chunk
.type
= T_TYPE_EOF
;
172 parser
->cur_chunk
.line
= parser
->line
;
173 parser
->cur_chunk
.s
= s
;
174 parser
->cur_chunk
.e
= e
;
177 void template_code(struct template_parser
*parser
, const char *e
)
179 const char *s
= parser
->off
;
181 parser
->strip_before
= 0;
182 parser
->strip_after
= 0;
186 parser
->strip_before
= 1;
187 for (s
++; (s
<= e
) && (*s
== ' ' || *s
== '\t'); s
++);
192 parser
->strip_after
= 1;
193 for (e
--; (e
>= s
) && (*e
== ' ' || *e
== '\t'); e
--);
201 parser
->cur_chunk
.type
= T_TYPE_COMMENT
;
207 parser
->cur_chunk
.type
= T_TYPE_INCLUDE
;
213 parser
->cur_chunk
.type
= T_TYPE_I18N
;
219 parser
->cur_chunk
.type
= T_TYPE_I18N_RAW
;
225 parser
->cur_chunk
.type
= T_TYPE_EXPR
;
230 parser
->cur_chunk
.type
= T_TYPE_CODE
;
234 parser
->cur_chunk
.line
= parser
->line
;
235 parser
->cur_chunk
.s
= s
;
236 parser
->cur_chunk
.e
= e
;
240 template_format_chunk(struct template_parser
*parser
, size_t *sz
)
243 const char *head
, *tail
;
244 struct template_chunk
*c
= &parser
->prv_chunk
;
245 struct template_buffer
*buf
;
248 s
= parser
->gc
= NULL
;
250 if (parser
->strip_before
&& c
->type
== T_TYPE_TEXT
)
252 while ((c
->e
> c
->s
) && isspace(*(c
->e
- 1)))
259 if (c
->type
== T_TYPE_EOF
)
272 else if ((buf
= buf_init(c
->e
- c
->s
)) != NULL
)
274 if ((head
= gen_code
[c
->type
][0]) != NULL
)
275 buf_append(buf
, head
, strlen(head
));
280 luastr_escape(buf
, c
->s
, c
->e
- c
->s
, 0);
284 buf_append(buf
, c
->s
, c
->e
- c
->s
);
285 for (p
= c
->s
; p
< c
->e
; p
++)
286 parser
->line
+= (*p
== '\n');
290 luastr_escape(buf
, c
->s
, c
->e
- c
->s
, 0);
294 luastr_translate(buf
, c
->s
, c
->e
- c
->s
, 1);
297 case T_TYPE_I18N_RAW
:
298 luastr_translate(buf
, c
->s
, c
->e
- c
->s
, 0);
302 buf_append(buf
, c
->s
, c
->e
- c
->s
);
303 for (p
= c
->s
; p
< c
->e
; p
++)
304 parser
->line
+= (*p
== '\n');
308 if ((tail
= gen_code
[c
->type
][1]) != NULL
)
309 buf_append(buf
, tail
, strlen(tail
));
311 *sz
= buf_length(buf
);
312 s
= parser
->gc
= buf_destroy(buf
);
324 const char *template_reader(lua_State
*L
, void *ud
, size_t *sz
)
326 struct template_parser
*parser
= ud
;
327 int rem
= parser
->size
- (parser
->off
- parser
->data
);
330 parser
->prv_chunk
= parser
->cur_chunk
;
332 /* free previous string */
340 if (!parser
->in_expr
)
342 if ((tag
= strfind(parser
->off
, rem
, "<%", 2)) != NULL
)
344 template_text(parser
, tag
);
345 parser
->off
= tag
+ 2;
350 template_text(parser
, parser
->data
+ parser
->size
);
351 parser
->off
= parser
->data
+ parser
->size
;
358 if ((tag
= strfind(parser
->off
, rem
, "%>", 2)) != NULL
)
360 template_code(parser
, tag
);
361 parser
->off
= tag
+ 2;
367 template_code(parser
, parser
->data
+ parser
->size
);
374 return template_format_chunk(parser
, sz
);
377 int template_error(lua_State
*L
, struct template_parser
*parser
)
379 const char *err
= luaL_checkstring(L
, -1);
380 const char *off
= parser
->prv_chunk
.s
;
386 if ((ptr
= strfind((char *)err
, strlen(err
), "]:", 2)) != NULL
)
388 chunkline
= atoi(ptr
+ 2) - parser
->prv_chunk
.line
;
400 if (strfind((char *)err
, strlen(err
), "'char(27)'", 10) != NULL
)
402 off
= parser
->data
+ parser
->size
;
403 err
= "'%>' expected before end of file";
407 for (ptr
= parser
->data
; ptr
< off
; ptr
++)
411 snprintf(msg
, sizeof(msg
), "Syntax error in %s:%d: %s",
412 parser
->file
? parser
->file
: "[string]", line
+ chunkline
, err
? err
: "(unknown error)");
415 lua_pushinteger(L
, line
+ chunkline
);
416 lua_pushstring(L
, msg
);