alt_term is a secondary loop terminator (in addition to term); '\0' means none. */
| 241 | |
| 242 | /* alt_term is a secondary loop terminator (in addition to term); '\0' means none. */ |
| 243 | static struct report_format * |
| 244 | parse_report_format(const tal_t *ctx, |
| 245 | const char **start, |
| 246 | char term, |
| 247 | char alt_term, |
| 248 | const char **err) |
| 249 | { |
| 250 | const char *p; |
| 251 | struct report_format *f; |
| 252 | |
| 253 | f = tal(ctx, struct report_format); |
| 254 | f->fmt = tal_arr(f, typeof(*f->fmt), 0); |
| 255 | f->str = tal_arr(f, const char *, 0); |
| 256 | f->ifset = tal_arr(f, struct report_format *, 0); |
| 257 | f->ifnotset = tal_arr(f, struct report_format *, 0); |
| 258 | |
| 259 | p = *start; |
| 260 | while (*p != term && !(alt_term && *p == alt_term)) { |
| 261 | struct report_format *ifset, *ifnotset; |
| 262 | const struct report_tag *rt; |
| 263 | |
| 264 | if (*p == '\0') { |
| 265 | *err = tal_fmt(ctx, "Unterminated tag"); |
| 266 | return tal_free(f); |
| 267 | } |
| 268 | |
| 269 | if (*p != '{') { |
| 270 | p++; |
| 271 | continue; |
| 272 | } |
| 273 | |
| 274 | /* Escaped '{{' => literal '{' */ |
| 275 | if (p[1] != term && p[1] == '{') { |
| 276 | char *lit; |
| 277 | |
| 278 | lit = tal_strndup(f->str, *start, p - *start); |
| 279 | lit = tal_strcat(tmpctx, take(lit), "{"); |
| 280 | tal_arr_expand(&f->fmt, NULL); |
| 281 | tal_arr_expand(&f->str, lit); |
| 282 | tal_arr_expand(&f->ifset, NULL); |
| 283 | tal_arr_expand(&f->ifnotset, NULL); |
| 284 | p += 2; |
| 285 | *start = p; |
| 286 | continue; |
| 287 | } |
| 288 | |
| 289 | /* Emit preceding literal, if any. */ |
| 290 | add_literal(f, start, p); |
| 291 | |
| 292 | const char *endtag = p + 1 + strcspn(p+1, "?:}"); |
| 293 | if (*endtag == '\0') { |
| 294 | *err = tal_fmt(ctx, "Unterminated tag %s", p + 1); |
| 295 | return tal_free(f); |
| 296 | } |
| 297 | |
| 298 | rt = find_report_tag(p + 1, endtag - (p + 1)); |
| 299 | if (!rt) { |
| 300 | *err = tal_fmt(ctx, |