exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

mustach.c (14516B)


      1 /*
      2  Author: José Bollo <jobol@nonadev.net>
      3 
      4  https://gitlab.com/jobol/mustach
      5 
      6  SPDX-License-Identifier: 0BSD
      7 */
      8 
      9 #ifndef _GNU_SOURCE
     10 #define _GNU_SOURCE
     11 #endif
     12 
     13 #include "mustach.h"
     14 
     15 #include <stdlib.h>
     16 #include <stdio.h>
     17 #include <string.h>
     18 #include <errno.h>
     19 #include <ctype.h>
     20 #ifdef _WIN32
     21 #include <malloc.h>
     22 #endif
     23 
     24 struct iwrap {
     25 	int (*emit)(void *closure, const char *buffer, size_t size, int escape, FILE *file);
     26 	void *closure; /* closure for: enter, next, leave, emit, get */
     27 	int (*put)(void *closure, const char *name, int escape, FILE *file);
     28 	void *closure_put; /* closure for put */
     29 	int (*enter)(void *closure, const char *name);
     30 	int (*next)(void *closure);
     31 	int (*leave)(void *closure);
     32 	int (*get)(void *closure, const char *name, struct mustach_sbuf *sbuf);
     33 	int (*partial)(void *closure, const char *name, struct mustach_sbuf *sbuf);
     34 	void *closure_partial; /* closure for partial */
     35 	FILE *file;
     36 	int flags;
     37 	int nesting;
     38 };
     39 
     40 struct prefix {
     41 	size_t len;
     42 	const char *start;
     43 	struct prefix *prefix;
     44 };
     45 
     46 /*********************************************************
     47 * This section wraps implementation details of memory files.
     48 * It also takes care of adding a terminating zero to the
     49 * produced text.
     50 * When the function open_memstream exists, use it.
     51 * Otherwise emulate it using a temporary file.
     52 **********************************************************/
     53 #if !defined(NO_OPEN_MEMSTREAM)
     54 static FILE *memfile_open(char **buffer, size_t *size)
     55 {
     56 	return open_memstream(buffer, size);
     57 }
     58 static void memfile_abort(FILE *file, char **buffer, size_t *size)
     59 {
     60 	fclose(file);
     61 	free(*buffer);
     62 	*buffer = NULL;
     63 	*size = 0;
     64 }
     65 static int memfile_close(FILE *file, char **buffer, size_t *size)
     66 {
     67 	int rc;
     68 
     69 	/* adds terminating null */
     70 	rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
     71 	fclose(file);
     72 	if (rc == 0)
     73 		/* removes terminating null of the length */
     74 		(*size)--;
     75 	else {
     76 		free(*buffer);
     77 		*buffer = NULL;
     78 		*size = 0;
     79 	}
     80 	return rc;
     81 }
     82 #else
     83 static FILE *memfile_open(char **buffer, size_t *size)
     84 {
     85 	/*
     86 	 * We can't provide *buffer and *size as open_memstream does but
     87 	 * at least clear them so the caller won't get bad data.
     88 	 */
     89 	*buffer = NULL;
     90 	*size = 0;
     91 
     92 	return tmpfile();
     93 }
     94 static void memfile_abort(FILE *file, char **buffer, size_t *size)
     95 {
     96 	fclose(file);
     97 	*buffer = NULL;
     98 	*size = 0;
     99 }
    100 static int memfile_close(FILE *file, char **buffer, size_t *size)
    101 {
    102 	int rc;
    103 	size_t s;
    104 	char *b;
    105 
    106 	s = (size_t)ftell(file);
    107 	b = malloc(s + 1);
    108 	if (b == NULL) {
    109 		rc = MUSTACH_ERROR_SYSTEM;
    110 		errno = ENOMEM;
    111 		s = 0;
    112 	} else {
    113 		rewind(file);
    114 		if (1 == fread(b, s, 1, file)) {
    115 			rc = 0;
    116 			b[s] = 0;
    117 		} else {
    118 			rc = MUSTACH_ERROR_SYSTEM;
    119 			free(b);
    120 			b = NULL;
    121 			s = 0;
    122 		}
    123 	}
    124 	*buffer = b;
    125 	*size = s;
    126 	return rc;
    127 }
    128 #endif
    129 
    130 /*********************************************************
    131 * This section has functions for managing instances of
    132 * struct mustach_sbuf.
    133 *********************************************************/
    134 static inline void sbuf_reset(struct mustach_sbuf *sbuf)
    135 {
    136 	sbuf->value = NULL;
    137 	sbuf->freecb = NULL;
    138 	sbuf->closure = NULL;
    139 	sbuf->length = 0;
    140 }
    141 
    142 static inline void sbuf_release(struct mustach_sbuf *sbuf)
    143 {
    144 	if (sbuf->releasecb)
    145 		sbuf->releasecb(sbuf->value, sbuf->closure);
    146 }
    147 
    148 static inline size_t sbuf_length(struct mustach_sbuf *sbuf)
    149 {
    150 	size_t length = sbuf->length;
    151 	if (length == 0 && sbuf->value != NULL)
    152 		length = strlen(sbuf->value);
    153 	return length;
    154 }
    155 
    156 /*********************************************************
    157 * This section is for default implementations of
    158 * optional callbacks that are although required
    159 *********************************************************/
    160 static int iwrap_emit(void *closure, const char *buffer, size_t size, int escape, FILE *file)
    161 {
    162 	size_t i, j, r;
    163 
    164 	(void)closure; /* unused */
    165 
    166 	if (!escape)
    167 		return fwrite(buffer, 1, size, file) != size ? MUSTACH_ERROR_SYSTEM : MUSTACH_OK;
    168 
    169 	r = i = 0;
    170 	while (i < size) {
    171 		j = i;
    172 		while (j < size && buffer[j] != '<' && buffer[j] != '>' && buffer[j] != '&' && buffer[j] != '"')
    173 			j++;
    174 		if (j != i && fwrite(&buffer[i], j - i, 1, file) != 1)
    175 			return MUSTACH_ERROR_SYSTEM;
    176 		if (j < size) {
    177 			switch(buffer[j++]) {
    178 			case '<':
    179 				r = fwrite("&lt;", 4, 1, file);
    180 				break;
    181 			case '>':
    182 				r = fwrite("&gt;", 4, 1, file);
    183 				break;
    184 			case '&':
    185 				r = fwrite("&amp;", 5, 1, file);
    186 				break;
    187 			case '"':
    188 				r = fwrite("&quot;", 6, 1, file);
    189 				break;
    190 			}
    191 			if (r != 1)
    192 				return MUSTACH_ERROR_SYSTEM;
    193 		}
    194 		i = j;
    195 	}
    196 	return MUSTACH_OK;
    197 }
    198 
    199 static int iwrap_put(void *closure, const char *name, int escape, FILE *file)
    200 {
    201 	struct iwrap *iwrap = closure;
    202 	int rc;
    203 	struct mustach_sbuf sbuf;
    204 	size_t length;
    205 
    206 	sbuf_reset(&sbuf);
    207 	rc = iwrap->get(iwrap->closure, name, &sbuf);
    208 	if (rc >= 0) {
    209 		length = sbuf_length(&sbuf);
    210 		if (length)
    211 			rc = iwrap->emit(iwrap->closure, sbuf.value, length, escape, file);
    212 		sbuf_release(&sbuf);
    213 	}
    214 	return rc;
    215 }
    216 
    217 static int iwrap_partial(void *closure, const char *name, struct mustach_sbuf *sbuf)
    218 {
    219 	struct iwrap *iwrap = closure;
    220 	int rc;
    221 	FILE *file;
    222 	size_t size;
    223 	char *result;
    224 
    225 	result = NULL;
    226 	file = memfile_open(&result, &size);
    227 	if (file == NULL)
    228 		rc = MUSTACH_ERROR_SYSTEM;
    229 	else {
    230 		rc = iwrap->put(iwrap->closure_put, name, 0, file);
    231 		if (rc < 0)
    232 			memfile_abort(file, &result, &size);
    233 		else {
    234 			rc = memfile_close(file, &result, &size);
    235 			if (rc == 0) {
    236 				sbuf->value = result;
    237 				sbuf->freecb = free;
    238 				sbuf->length = size;
    239 			}
    240 		}
    241 	}
    242 	return rc;
    243 }
    244 
    245 /*********************************************************
    246 * Function for writing the indentation prefix
    247 *********************************************************/
    248 static int emitprefix(struct iwrap *iwrap, struct prefix *prefix)
    249 {
    250 	if (prefix->prefix) {
    251 		int rc = emitprefix(iwrap, prefix->prefix);
    252 		if (rc < 0)
    253 			return rc;
    254 	}
    255 	return prefix->len ? iwrap->emit(iwrap->closure, prefix->start, prefix->len, 0, iwrap->file) : 0;
    256 }
    257 
    258 /*********************************************************
    259 * This section is for default implementations of
    260 * optional callbacks that are although required
    261 *********************************************************/
    262 static int process(const char *template, size_t length, struct iwrap *iwrap, struct prefix *prefix)
    263 {
    264 	struct mustach_sbuf sbuf;
    265 	char opstr[MUSTACH_MAX_DELIM_LENGTH], clstr[MUSTACH_MAX_DELIM_LENGTH];
    266 	char name[MUSTACH_MAX_LENGTH + 1], c;
    267 	const char *beg, *term, *end;
    268 	struct { const char *name, *again; size_t length; unsigned enabled: 1, entered: 1; } stack[MUSTACH_MAX_DEPTH];
    269 	size_t oplen, cllen, len, l;
    270 	int depth, rc, enabled, stdalone;
    271 	struct prefix pref;
    272 
    273 	pref.prefix = prefix;
    274 	end = template + (length ? length : strlen(template));
    275 	opstr[0] = opstr[1] = '{';
    276 	clstr[0] = clstr[1] = '}';
    277 	oplen = cllen = 2;
    278 	stdalone = enabled = 1;
    279 	depth = pref.len = 0;
    280 	for (;;) {
    281 		/* search next openning delimiter */
    282 		for (beg = template ; ; beg++) {
    283 			if (beg == end)
    284 				c = '\n';
    285 			else {
    286 				c = *beg;
    287 				if (c == '\r') {
    288 					if ((beg + 1) != end && beg[1] == '\n')
    289 						beg++;
    290 					c = '\n';
    291 				}
    292 			}
    293 			if (c == '\n') {
    294 				l = (beg != end) + (size_t)(beg - template);
    295 				if (stdalone != 2 && enabled) {
    296 					if (beg != template /* don't prefix empty lines */) {
    297 						rc = emitprefix(iwrap, &pref);
    298 						if (rc < 0)
    299 							return rc;
    300 					}
    301 					rc = iwrap->emit(iwrap->closure, template, l, 0, iwrap->file);
    302 					if (rc < 0)
    303 						return rc;
    304 				}
    305 				if (beg == end) /* no more mustach */
    306 					return depth ? MUSTACH_ERROR_UNEXPECTED_END : MUSTACH_OK;
    307 				template += l;
    308 				stdalone = 1;
    309 				pref.len = 0;
    310 				pref.prefix = prefix;
    311 			}
    312 			else if (!isspace(c)) {
    313 				if (stdalone == 2 && enabled) {
    314 					rc = emitprefix(iwrap, &pref);
    315 					if (rc < 0)
    316 						return rc;
    317 					pref.len = 0;
    318 					stdalone = 0;
    319 					pref.prefix = NULL;
    320 				}
    321 				if (c == *opstr && end - beg >= (ssize_t)oplen) {
    322 					for (l = 1 ; l < oplen && beg[l] == opstr[l] ; l++);
    323 					if (l == oplen)
    324 						break;
    325 				}
    326 				stdalone = 0;
    327 			}
    328 		}
    329 
    330 		pref.start = template;
    331 		pref.len = enabled ? (size_t)(beg - template) : 0;
    332 		beg += oplen;
    333 
    334 		/* search next closing delimiter */
    335 		for (term = beg ; ; term++) {
    336 			if (term == end)
    337 				return MUSTACH_ERROR_UNEXPECTED_END;
    338 			if (*term == *clstr && end - term >= (ssize_t)cllen) {
    339 				for (l = 1 ; l < cllen && term[l] == clstr[l] ; l++);
    340 				if (l == cllen)
    341 					break;
    342 			}
    343 		}
    344 		template = term + cllen;
    345 		len = (size_t)(term - beg);
    346 		c = *beg;
    347 		switch(c) {
    348 		case ':':
    349 			stdalone = 0;
    350 			if (iwrap->flags & Mustach_With_Colon)
    351 				goto exclude_first;
    352 			goto get_name;
    353 		case '!':
    354 		case '=':
    355 			break;
    356 		case '{':
    357 			for (l = 0 ; l < cllen && clstr[l] == '}' ; l++);
    358 			if (l < cllen) {
    359 				if (!len || beg[len-1] != '}')
    360 					return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
    361 				len--;
    362 			} else {
    363 				if (term[l] != '}')
    364 					return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
    365 				template++;
    366 			}
    367 			c = '&';
    368 			/*@fallthrough@*/
    369 		case '&':
    370 			stdalone = 0;
    371 			/*@fallthrough@*/
    372 		case '^':
    373 		case '#':
    374 		case '/':
    375 		case '>':
    376 exclude_first:
    377 			beg++;
    378 			len--;
    379 			goto get_name;
    380 		default:
    381 			stdalone = 0;
    382 get_name:
    383 			while (len && isspace(beg[0])) { beg++; len--; }
    384 			while (len && isspace(beg[len-1])) len--;
    385 			if (len == 0 && !(iwrap->flags & Mustach_With_EmptyTag))
    386 				return MUSTACH_ERROR_EMPTY_TAG;
    387 			if (len > MUSTACH_MAX_LENGTH)
    388 				return MUSTACH_ERROR_TAG_TOO_LONG;
    389 			memcpy(name, beg, len);
    390 			name[len] = 0;
    391 			break;
    392 		}
    393 		if (stdalone)
    394 			stdalone = 2;
    395 		else if (enabled) {
    396 			rc = emitprefix(iwrap, &pref);
    397 			if (rc < 0)
    398 				return rc;
    399 			pref.len = 0;
    400 			pref.prefix = NULL;
    401 		}
    402 		switch(c) {
    403 		case '!':
    404 			/* comment */
    405 			/* nothing to do */
    406 			break;
    407 		case '=':
    408 			/* defines delimiters */
    409 			if (len < 5 || beg[len - 1] != '=')
    410 				return MUSTACH_ERROR_BAD_SEPARATORS;
    411 			beg++;
    412 			len -= 2;
    413 			while (len && isspace(*beg))
    414 				beg++, len--;
    415 			while (len && isspace(beg[len - 1]))
    416 				len--;
    417 			for (l = 0; l < len && !isspace(beg[l]) ; l++);
    418 			if (l == len || l > MUSTACH_MAX_DELIM_LENGTH)
    419 				return MUSTACH_ERROR_BAD_SEPARATORS;
    420 			oplen = l;
    421 			memcpy(opstr, beg, l);
    422 			while (l < len && isspace(beg[l])) l++;
    423 			if (l == len || len - l > MUSTACH_MAX_DELIM_LENGTH)
    424 				return MUSTACH_ERROR_BAD_SEPARATORS;
    425 			cllen = len - l;
    426 			memcpy(clstr, beg + l, cllen);
    427 			break;
    428 		case '^':
    429 		case '#':
    430 			/* begin section */
    431 			if (depth == MUSTACH_MAX_DEPTH)
    432 				return MUSTACH_ERROR_TOO_DEEP;
    433 			rc = enabled;
    434 			if (rc) {
    435 				rc = iwrap->enter(iwrap->closure, name);
    436 				if (rc < 0)
    437 					return rc;
    438 			}
    439 			stack[depth].name = beg;
    440 			stack[depth].again = template;
    441 			stack[depth].length = len;
    442 			stack[depth].enabled = enabled != 0;
    443 			stack[depth].entered = rc != 0;
    444 			if ((c == '#') == (rc == 0))
    445 				enabled = 0;
    446 			depth++;
    447 			break;
    448 		case '/':
    449 			/* end section */
    450 			if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
    451 				return MUSTACH_ERROR_CLOSING;
    452 			rc = enabled && stack[depth].entered ? iwrap->next(iwrap->closure) : 0;
    453 			if (rc < 0)
    454 				return rc;
    455 			if (rc) {
    456 				template = stack[depth++].again;
    457 			} else {
    458 				enabled = stack[depth].enabled;
    459 				if (enabled && stack[depth].entered)
    460 					iwrap->leave(iwrap->closure);
    461 			}
    462 			break;
    463 		case '>':
    464 			/* partials */
    465 			if (enabled) {
    466 				if (iwrap->nesting >= MUSTACH_MAX_NESTING)
    467 					rc = MUSTACH_ERROR_TOO_MUCH_NESTING;
    468 				else {
    469 					sbuf_reset(&sbuf);
    470 					rc = iwrap->partial(iwrap->closure_partial, name, &sbuf);
    471 					if (rc >= 0) {
    472 						iwrap->nesting++;
    473 						rc = process(sbuf.value, sbuf_length(&sbuf), iwrap, &pref);
    474 						sbuf_release(&sbuf);
    475 						iwrap->nesting--;
    476 					}
    477 				}
    478 				if (rc < 0)
    479 					return rc;
    480 			}
    481 			break;
    482 		default:
    483 			/* replacement */
    484 			if (enabled) {
    485 				rc = iwrap->put(iwrap->closure_put, name, c != '&', iwrap->file);
    486 				if (rc < 0)
    487 					return rc;
    488 			}
    489 			break;
    490 		}
    491 	}
    492 }
    493 
    494 /*********************************************************
    495 * This section is for the public interface functions
    496 *********************************************************/
    497 int mustach_file(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, FILE *file)
    498 {
    499 	int rc;
    500 	struct iwrap iwrap;
    501 
    502 	/* check validity */
    503 	if (!itf->enter || !itf->next || !itf->leave || (!itf->put && !itf->get))
    504 		return MUSTACH_ERROR_INVALID_ITF;
    505 
    506 	/* init wrap structure */
    507 	iwrap.closure = closure;
    508 	if (itf->put) {
    509 		iwrap.put = itf->put;
    510 		iwrap.closure_put = closure;
    511 	} else {
    512 		iwrap.put = iwrap_put;
    513 		iwrap.closure_put = &iwrap;
    514 	}
    515 	if (itf->partial) {
    516 		iwrap.partial = itf->partial;
    517 		iwrap.closure_partial = closure;
    518 	} else if (itf->get) {
    519 		iwrap.partial = itf->get;
    520 		iwrap.closure_partial = closure;
    521 	} else {
    522 		iwrap.partial = iwrap_partial;
    523 		iwrap.closure_partial = &iwrap;
    524 	}
    525 	iwrap.emit = itf->emit ? itf->emit : iwrap_emit;
    526 	iwrap.enter = itf->enter;
    527 	iwrap.next = itf->next;
    528 	iwrap.leave = itf->leave;
    529 	iwrap.get = itf->get;
    530 	iwrap.file = file;
    531 	iwrap.flags = flags;
    532 	iwrap.nesting = 0;
    533 
    534 	/* process */
    535 	rc = itf->start ? itf->start(closure) : 0;
    536 	if (rc == 0)
    537 		rc = process(template, length, &iwrap, NULL);
    538 	if (itf->stop)
    539 		itf->stop(closure, rc);
    540 	return rc;
    541 }
    542 
    543 int mustach_fd(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, int fd)
    544 {
    545 	int rc;
    546 	FILE *file;
    547 
    548 	file = fdopen(fd, "w");
    549 	if (file == NULL) {
    550 		rc = MUSTACH_ERROR_SYSTEM;
    551 		errno = ENOMEM;
    552 	} else {
    553 		rc = mustach_file(template, length, itf, closure, flags, file);
    554 		fclose(file);
    555 	}
    556 	return rc;
    557 }
    558 
    559 int mustach_mem(const char *template, size_t length, const struct mustach_itf *itf, void *closure, int flags, char **result, size_t *size)
    560 {
    561 	int rc;
    562 	FILE *file;
    563 	size_t s;
    564 
    565 	*result = NULL;
    566 	if (size == NULL)
    567 		size = &s;
    568 	file = memfile_open(result, size);
    569 	if (file == NULL)
    570 		rc = MUSTACH_ERROR_SYSTEM;
    571 	else {
    572 		rc = mustach_file(template, length, itf, closure, flags, file);
    573 		if (rc < 0)
    574 			memfile_abort(file, result, size);
    575 		else
    576 			rc = memfile_close(file, result, size);
    577 	}
    578 	return rc;
    579 }
    580 
    581 int fmustach(const char *template, const struct mustach_itf *itf, void *closure, FILE *file)
    582 {
    583 	return mustach_file(template, 0, itf, closure, Mustach_With_AllExtensions, file);
    584 }
    585 
    586 int fdmustach(const char *template, const struct mustach_itf *itf, void *closure, int fd)
    587 {
    588 	return mustach_fd(template, 0, itf, closure, Mustach_With_AllExtensions, fd);
    589 }
    590 
    591 int mustach(const char *template, const struct mustach_itf *itf, void *closure, char **result, size_t *size)
    592 {
    593 	return mustach_mem(template, 0, itf, closure, Mustach_With_AllExtensions, result, size);
    594 }
    595