2 Author: José Bollo <jobol@nonadev.net>
3 Author: José Bollo <jose.bollo@iot.bzh>
5 https://gitlab.com/jobol/mustach
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
30 #define NAME_LENGTH_MAX 1024
33 static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result)
40 file = open_memstream(result, &size);
42 rc = MUSTACH_ERROR_SYSTEM;
44 rc = itf->put(closure, name, 0, file);
46 /* adds terminating null */
47 rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
57 static int process(const char *template, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr)
59 char name[NAME_LENGTH_MAX + 1], *partial, c;
60 const char *beg, *term;
61 struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX];
62 size_t oplen, cllen, len, l;
66 oplen = strlen(opstr);
67 cllen = strlen(clstr);
70 beg = strstr(template, opstr);
74 fwrite(template, strlen(template), 1, file);
75 return depth ? MUSTACH_ERROR_UNEXPECTED_END : 0;
78 fwrite(template, (size_t)(beg - template), 1, file);
80 term = strstr(beg, clstr);
82 return MUSTACH_ERROR_UNEXPECTED_END;
83 template = term + cllen;
84 len = (size_t)(term - beg);
91 for (l = 0 ; clstr[l] == '}' ; l++);
93 if (!len || beg[len-1] != '}')
94 return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
98 return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
108 #if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH)
113 while (len && isspace(beg[0])) { beg++; len--; }
114 while (len && isspace(beg[len-1])) len--;
116 return MUSTACH_ERROR_EMPTY_TAG;
117 if (len > NAME_LENGTH_MAX)
118 return MUSTACH_ERROR_TAG_TOO_LONG;
119 memcpy(name, beg, len);
129 /* defines separators */
130 if (len < 5 || beg[len - 1] != '=')
131 return MUSTACH_ERROR_BAD_SEPARATORS;
134 for (l = 0; l < len && !isspace(beg[l]) ; l++);
136 return MUSTACH_ERROR_BAD_SEPARATORS;
137 opstr = strndupa(beg, l);
138 while (l < len && isspace(beg[l])) l++;
140 return MUSTACH_ERROR_BAD_SEPARATORS;
141 clstr = strndupa(beg + l, len - l);
142 oplen = strlen(opstr);
143 cllen = strlen(clstr);
148 if (depth == DEPTH_MAX)
149 return MUSTACH_ERROR_TOO_DEPTH;
152 rc = itf->enter(closure, name);
156 stack[depth].name = beg;
157 stack[depth].again = template;
158 stack[depth].length = len;
159 stack[depth].emit = emit;
160 stack[depth].entered = rc;
161 if ((c == '#') == (rc == 0))
167 if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
168 return MUSTACH_ERROR_CLOSING;
169 rc = emit && stack[depth].entered ? itf->next(closure) : 0;
173 template = stack[depth++].again;
175 emit = stack[depth].emit;
176 if (emit && stack[depth].entered)
183 rc = getpartial(itf, closure, name, &partial);
185 rc = process(partial, itf, closure, file, opstr, clstr);
195 rc = itf->put(closure, name, c != '&', file);
204 int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file)
206 int rc = itf->start ? itf->start(closure) : 0;
208 rc = process(template, itf, closure, file, "{{", "}}");
212 int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd)
217 file = fdopen(fd, "w");
219 rc = MUSTACH_ERROR_SYSTEM;
222 rc = fmustach(template, itf, closure, file);
228 int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size)
237 file = open_memstream(result, size);
239 rc = MUSTACH_ERROR_SYSTEM;
242 rc = fmustach(template, itf, closure, file);
244 /* adds terminating null */
245 rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
248 /* removes terminating null of the length */