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 static 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
->mmap
= mmap(NULL
, parser
->size
, PROT_READ
, MAP_PRIVATE
,
88 if (parser
->mmap
!= MAP_FAILED
)
90 parser
->off
= parser
->mmap
;
91 parser
->cur_chunk
.type
= T_TYPE_INIT
;
92 parser
->cur_chunk
.s
= parser
->mmap
;
93 parser
->cur_chunk
.e
= parser
->mmap
;
99 template_close(parser
);
103 void template_close(struct template_parser
*parser
)
108 if (parser
->gc
!= NULL
)
111 if ((parser
->mmap
!= NULL
) && (parser
->mmap
!= MAP_FAILED
))
112 munmap(parser
->mmap
, parser
->size
);
120 void template_text(struct template_parser
*parser
, const char *e
)
122 const char *s
= parser
->off
;
124 if (s
< (parser
->mmap
+ parser
->size
))
126 if (parser
->strip_after
)
128 while ((s
<= e
) && isspace(*s
))
132 parser
->cur_chunk
.type
= T_TYPE_TEXT
;
136 parser
->cur_chunk
.type
= T_TYPE_EOF
;
139 parser
->cur_chunk
.line
= parser
->line
;
140 parser
->cur_chunk
.s
= s
;
141 parser
->cur_chunk
.e
= e
;
144 void template_code(struct template_parser
*parser
, const char *e
)
146 const char *s
= parser
->off
;
148 parser
->strip_before
= 0;
149 parser
->strip_after
= 0;
153 parser
->strip_before
= 1;
154 for (s
++; (s
<= e
) && (*s
== ' ' || *s
== '\t'); s
++);
159 parser
->strip_after
= 1;
160 for (e
--; (e
>= s
) && (*e
== ' ' || *e
== '\t'); e
--);
168 parser
->cur_chunk
.type
= T_TYPE_COMMENT
;
174 parser
->cur_chunk
.type
= T_TYPE_INCLUDE
;
180 parser
->cur_chunk
.type
= T_TYPE_I18N
;
186 parser
->cur_chunk
.type
= T_TYPE_I18N_RAW
;
192 parser
->cur_chunk
.type
= T_TYPE_EXPR
;
197 parser
->cur_chunk
.type
= T_TYPE_CODE
;
201 parser
->cur_chunk
.line
= parser
->line
;
202 parser
->cur_chunk
.s
= s
;
203 parser
->cur_chunk
.e
= e
;
207 template_format_chunk(struct template_parser
*parser
, size_t *sz
)
210 const char *head
, *tail
;
211 struct template_chunk
*c
= &parser
->prv_chunk
;
212 struct template_buffer
*buf
;
215 s
= parser
->gc
= NULL
;
217 if (parser
->strip_before
&& c
->type
== T_TYPE_TEXT
)
219 while ((c
->e
> c
->s
) && isspace(*(c
->e
- 1)))
226 if (c
->type
== T_TYPE_EOF
)
239 else if ((buf
= buf_init(c
->e
- c
->s
)) != NULL
)
241 if ((head
= gen_code
[c
->type
][0]) != NULL
)
242 buf_append(buf
, head
, strlen(head
));
247 luastr_escape(buf
, c
->s
, c
->e
- c
->s
, 0);
251 buf_append(buf
, c
->s
, c
->e
- c
->s
);
252 for (p
= c
->s
; p
< c
->e
; p
++)
253 parser
->line
+= (*p
== '\n');
257 luastr_escape(buf
, c
->s
, c
->e
- c
->s
, 0);
261 luastr_translate(buf
, c
->s
, c
->e
- c
->s
, 1);
264 case T_TYPE_I18N_RAW
:
265 luastr_translate(buf
, c
->s
, c
->e
- c
->s
, 0);
269 buf_append(buf
, c
->s
, c
->e
- c
->s
);
270 for (p
= c
->s
; p
< c
->e
; p
++)
271 parser
->line
+= (*p
== '\n');
275 if ((tail
= gen_code
[c
->type
][1]) != NULL
)
276 buf_append(buf
, tail
, strlen(tail
));
278 *sz
= buf_length(buf
);
279 s
= parser
->gc
= buf_destroy(buf
);
291 const char *template_reader(lua_State
*L
, void *ud
, size_t *sz
)
293 struct template_parser
*parser
= ud
;
294 int rem
= parser
->size
- (parser
->off
- parser
->mmap
);
297 parser
->prv_chunk
= parser
->cur_chunk
;
299 /* free previous string */
307 if (!parser
->in_expr
)
309 if ((tag
= strfind(parser
->off
, rem
, "<%", 2)) != NULL
)
311 template_text(parser
, tag
);
312 parser
->off
= tag
+ 2;
317 template_text(parser
, parser
->mmap
+ parser
->size
);
318 parser
->off
= parser
->mmap
+ parser
->size
;
325 if ((tag
= strfind(parser
->off
, rem
, "%>", 2)) != NULL
)
327 template_code(parser
, tag
);
328 parser
->off
= tag
+ 2;
334 template_code(parser
, parser
->mmap
+ parser
->size
);
341 return template_format_chunk(parser
, sz
);
344 int template_error(lua_State
*L
, struct template_parser
*parser
)
346 const char *err
= luaL_checkstring(L
, -1);
347 const char *off
= parser
->prv_chunk
.s
;
353 if ((ptr
= strfind((char *)err
, strlen(err
), "]:", 2)) != NULL
)
355 chunkline
= atoi(ptr
+ 2) - parser
->prv_chunk
.line
;
367 if (strfind((char *)err
, strlen(err
), "'char(27)'", 10) != NULL
)
369 off
= parser
->mmap
+ parser
->size
;
370 err
= "'%>' expected before end of file";
374 for (ptr
= parser
->mmap
; ptr
< off
; ptr
++)
378 snprintf(msg
, sizeof(msg
), "Syntax error in %s:%d: %s",
379 parser
->file
, line
+ chunkline
, err
? err
: "(unknown error)");
382 lua_pushinteger(L
, line
+ chunkline
);
383 lua_pushstring(L
, msg
);