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;
107 #if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH)
112 while (len && isspace(beg[0])) { beg++; len--; }
113 while (len && isspace(beg[len-1])) len--;
115 return MUSTACH_ERROR_EMPTY_TAG;
116 if (len > NAME_LENGTH_MAX)
117 return MUSTACH_ERROR_TAG_TOO_LONG;
118 memcpy(name, beg, len);
128 /* defines separators */
129 if (len < 5 || beg[len - 1] != '=')
130 return MUSTACH_ERROR_BAD_SEPARATORS;
133 for (l = 0; l < len && !isspace(beg[l]) ; l++);
135 return MUSTACH_ERROR_BAD_SEPARATORS;
136 opstr = strndupa(beg, l);
137 while (l < len && isspace(beg[l])) l++;
139 return MUSTACH_ERROR_BAD_SEPARATORS;
140 clstr = strndupa(beg + l, len - l);
141 oplen = strlen(opstr);
142 cllen = strlen(clstr);
147 if (depth == DEPTH_MAX)
148 return MUSTACH_ERROR_TOO_DEPTH;
151 rc = itf->enter(closure, name);
155 stack[depth].name = beg;
156 stack[depth].again = template;
157 stack[depth].length = len;
158 stack[depth].emit = emit;
159 stack[depth].entered = rc;
160 if ((c == '#') == (rc == 0))
166 if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
167 return MUSTACH_ERROR_CLOSING;
168 rc = emit && stack[depth].entered ? itf->next(closure) : 0;
172 template = stack[depth++].again;
174 emit = stack[depth].emit;
175 if (emit && stack[depth].entered)
182 rc = getpartial(itf, closure, name, &partial);
184 rc = process(partial, itf, closure, file, opstr, clstr);
194 rc = itf->put(closure, name, c != '&', file);
203 int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file)
205 int rc = itf->start ? itf->start(closure) : 0;
207 rc = process(template, itf, closure, file, "{{", "}}");
211 int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd)
216 file = fdopen(fd, "w");
218 rc = MUSTACH_ERROR_SYSTEM;
221 rc = fmustach(template, itf, closure, file);
227 int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size)
236 file = open_memstream(result, size);
238 rc = MUSTACH_ERROR_SYSTEM;
241 rc = fmustach(template, itf, closure, file);
243 /* adds terminating null */
244 rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
247 /* removes terminating null of the length */