X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fwgtpkg-mustach.c;h=5e4348a29ef61e8d0fa70d9a37aa63ceeadd86ee;hb=f8b04951b4ccafdf28b875825edd46316fafb519;hp=4b05bc28a240eec668b97b7278b097ff7cdf60d3;hpb=1d4de11a907e41c06063a2cd5028dc4101690f50;p=src%2Fapp-framework-main.git diff --git a/src/wgtpkg-mustach.c b/src/wgtpkg-mustach.c index 4b05bc2..5e4348a 100644 --- a/src/wgtpkg-mustach.c +++ b/src/wgtpkg-mustach.c @@ -21,14 +21,18 @@ #include #include +#include #include #include "mustach.h" +#include "verbose.h" #define MAX_DEPTH 256 - +/* + * exploration state when instantiating mustache + */ struct expl { struct json_object *root; int depth; @@ -45,47 +49,92 @@ struct expl { * If the sign = is not here, returns NULL. * Replace any \= of the key by its unescaped version =. */ -static char *keyval(char *head) +static char *keyval(char *read, int isptr) { - char *w, c; + char *write, c; - c = *(w = head); + c = *(write = read); while (c && c != '=') { - if (c == '\\') { - switch (head[1]) { - case '\\': *w++ = c; - case '=': c = *++head; - default: break; + if (isptr) { + if (c == '~' && read[1] == '=') { + c = *++read; + } + } else { + if (c == '\\') { + switch (read[1]) { + case '\\': *write++ = c; /*@fallthrough@*/ + case '=': c = *++read; /*@fallthrough@*/ + default: break; + } } } - *w++ = c; - c = *++head; + *write++ = c; + c = *++read; } - *w = 0; - return c == '=' ? ++head : NULL; + *write = 0; + return c == '=' ? ++read : NULL; } /* * Returns the unescaped version of the first component * and update 'name' to point the next components if any. */ -static char *first(char **name) +static char *first(char **name, int isptr) { - char *r, *i, *w, c; + char *r, *read, *write, c; - c = *(i = *name); + c = *(read = *name); if (!c) r = NULL; else { - r = w = i; - while (c && c != '.') { - if (c == '\\' && (i[1] == '.' || i[1] == '\\')) - c = *++i; - *w++ = c; - c = *++i; + r = write = read; + if (isptr) { + while (c && c != '/') { + if (c == '~') { + switch(read[1]) { + case '1': c = '/'; /*@fallthrough@*/ + case '0': read++; /*@fallthrough@*/ + default: break; + } + } + *write++ = c; + c = *++read; + } + } else { + while (c && c != '.') { + if (c == '\\' && (read[1] == '.' || read[1] == '\\')) + c = *++read; + *write++ = c; + c = *++read; + } } - *w = 0; - *name = i + !!c; + *write = 0; + *name = read + !!c; + } + return r; +} + +/* + * Returns the unescaped version of the first value + * and update 'val' to point the next value if any. + */ +static char *value(char **val) +{ + char *r, *read, *write, c; + + c = *(read = *val); + if (!c) + r = NULL; + else { + r = write = read; + while (c && c != '|') { + if (c == '\\' && (read[1] == '|' || read[1] == '\\')) + c = *++read; + *write++ = c; + c = *++read; + } + *write = 0; + *val = read + !!c; } return r; } @@ -119,19 +168,23 @@ static char *globalize(char *key) */ static struct json_object *find(struct expl *e, const char *name) { - int i; + int i, isptr; struct json_object *o, *r; char *n, *c, *v; /* get a local key */ n = strdupa(name); + /* is it a JSON pointer? */ + isptr = n[0] == '/'; + n += isptr; + /* extract its value */ - v = keyval(n); + v = keyval(n, isptr); /* search the first component for each valid globalisation */ i = e->depth; - c = first(&n); + c = first(&n, isptr); while (c) { if (i < 0) { /* next globalisation */ @@ -141,7 +194,7 @@ static struct json_object *find(struct expl *e, const char *name) else if (json_object_object_get_ex(e->stack[i].obj, c, &o)) { /* found the root, search the subcomponents */ - c = first(&n); + c = first(&n, isptr); while(c) { while (!json_object_object_get_ex(o, c, &r)) { c = globalize(c); @@ -149,13 +202,17 @@ static struct json_object *find(struct expl *e, const char *name) return NULL; } o = r; - c = first(&n); + c = first(&n, isptr); } /* check the value if requested */ if (v) { i = v[0] == '!'; - if (i == !strcmp(&v[i], json_object_get_string(o))) + v += i; + do { + c = value(&v); + } while (c && strcmp(c, json_object_get_string(o))); + if (i != !c) o = NULL; } return o; @@ -255,10 +312,40 @@ static struct mustach_itf itf = { .leave = leave }; +/* + * Apply the object 'root' to the mustache 'template'. + * In case of success, the function returns 0, the pointer + * 'result' receives the allocated instanciation and + * the pointer 'size' its size. Note that the real size + * is one byte more to effectively store the terminating + * null. + * In case of error, it returns a negative error code. + */ int apply_mustach(const char *template, struct json_object *root, char **result, size_t *size) { + int rc; struct expl e; + e.root = root; - return mustach(template, &itf, &e, result, size); + rc = mustach(template, &itf, &e, result, size); + if (rc < 0) { + static const char *msgs[] = { + "SYSTEM", + "UNEXPECTED_END", + "EMPTY_TAG", + "TAG_TOO_LONG", + "BAD_SEPARATORS", + "TOO_DEPTH", + "CLOSING", + "BAD_UNESCAPE_TAG" + }; + + rc = -(rc + 1); + ERROR("mustach error found: MUSTACH_ERROR_%s", + rc < 0 || rc >= (int)(sizeof msgs / sizeof * msgs) ? "???" : msgs[rc]); + rc = -1; + errno = EINVAL; + } + return rc; }