/* See LICENSE file for copyright and license details. */ #include "common.h" static char * substitute(struct libgeome_context *ctx, const char *text, uint64_t features) { size_t len = 0, sublen; size_t i; int negative, include; uint64_t if_features, digit; char *ret, *p; for (i = 0; text[i];) { if (text[i] != '%') { i += 1U; len += 1U; } else if (text[i + 1U] == '%') { i += 2U; len += 1U; } else if (text[i + 1U] == '{') { i += 2U; negative = text[i] == '!'; i += (size_t)negative; if_features = 0; for (; isdigit(text[i]); i++) { digit = (uint64_t)(text[i] & 15); if (if_features > (UINT64_MAX - digit) / 10U) goto invalid; if_features = if_features * 10U + digit; } if (!if_features || text[i++] != ':') goto invalid; include = !!(if_features & features); include ^= negative; sublen = 0; for (;;) { if (text[i] == '}') { i += 1U; break; } else if (!text[i]) { goto invalid; } else if (text[i] != '%') { i += 1U; sublen += 1U; } else if (text[i + 1U] == '%') { i += 1U; sublen += 2U; } else if (text[i + 1U] == '}') { i += 1U; sublen += 2U; } else { goto invalid; } } if (include ^ negative) len += sublen; } else { invalid: ctx->print_error(ctx, "invalid %-pattern in `%s'\n", text); return NULL; } } p = ret = malloc(len + 1U); if (!ret) { ctx->print_error(ctx, "malloc: %s\n", strerror(errno)); return NULL; } while (*text) { if (*text != '%') { *p++ = *text++; } else if (text[i + 1U] == '%') { text = &text[2]; *p++ = '%'; } else if (text[i + 1U] == '{') { text = &text[2]; negative = *text == '!'; text = &text[negative]; if_features = 0; while (isdigit(*text)) { digit = (uint64_t)(*text++ & 15); if_features = if_features * 10U + digit; } text++; include = !!(if_features & features); include ^= negative; for (; *text != '}'; text++) { if (include) *p++ = text[*text == '%']; if (*text == '%') text++; } text++; } } *p = '\0'; return ret; } int libgeome_get_from_patterned_command(struct libgeome_context *ctx, struct libgeome_data *out, size_t limit, /* TODO test */ unsigned int alarm_sec, const char *path, const char *const *argv) { const char **argv_new = NULL; char **array; size_t count = 0; size_t index = 0; size_t i, argc = 0; int ret = -1; if (strchr(path, '%')) count += 1U; for (i = 0; argv[i]; i++) if (strchr(argv[i], '%')) count += 1U; argc = i; if (!count) return libgeome_get_from_patterned_command(ctx, out, limit, alarm_sec, path, argv); array = calloc(count, sizeof(*array)); if (!array) { ctx->print_error(ctx, "calloc: %s\n", strerror(errno)); return -1; } if (strchr(path, '%')) { path = array[index++] = substitute(ctx, path, out->requested_data); if (!path) goto out; } if (index != count) { argv_new = calloc(argc + 1U, sizeof(*argv_new)); if (!argv_new) { ctx->print_error(ctx, "calloc: %s\n", strerror(errno)); goto out; } argv_new[argc] = NULL; for (i = 0; argv[i]; i++) { if (strchr(argv[i], '%')) { argv_new[i] = array[index++] = substitute(ctx, argv[i], out->requested_data); if (!argv_new[i]) goto out; } else { argv_new[i] = argv[i]; } } argv = argv_new; } ret = libgeome_get_from_patterned_command(ctx, out, limit, alarm_sec, path, argv); out: for (i = 0; i < count; i++) free(array[i]); free(array); free(argv_new); return ret; }