core-lightning/common/configvar.c
Vincenzo Palazzo 53154a40a5 fix: build on alpine linux
This fixes the compile issue that we are having on
alpine.

```
cc wallet/wallet.c
cc wallet/walletrpc.c
cc wallet/reservation.c
cc wallet/db_sqlite3_sqlgen.c
cc wallet/db_postgres_sqlgen.c
cc common/addr.c
cc common/bolt11.c
cc common/bolt11_json.c
cc common/bolt12.c
cc common/configdir.c
cc common/configvar.c
cc common/scb_wiregen.c
common/configvar.c: In function 'configvar_remove':
common/configvar.c:118:9: error: unknown type name 'ssize_t'; did you mean 'size_t'?
  118 |         ssize_t prev = -1;
      |         ^~~~~~~
      |         size_t
make: *** [Makefile:292: common/configvar.o] Error 1
make: *** Waiting for unfinished jobs....
```

Link: https://github.com/ElementsProject/lightning/issues/6321
Reported-by: @gruve-p
Fixes: 36200a6593
Changelog-None
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
2023-06-15 09:52:31 +09:30

233 lines
5.7 KiB
C

#include "config.h"
#include <assert.h>
#include <ccan/cast/cast.h>
#include <ccan/tal/str/str.h>
#include <common/configvar.h>
#include <common/utils.h>
#include <unistd.h>
struct configvar *configvar_new(const tal_t *ctx,
enum configvar_src src,
const char *file,
size_t linenum,
const char *configline)
{
struct configvar *cv = tal(ctx, struct configvar);
if (file)
cv->file = tal_strdup(cv, file);
else
cv->file = NULL;
cv->src = src;
cv->linenum = linenum;
cv->configline = tal_strdup(cv, configline);
cv->overridden = false;
cv->optvar = NULL;
/* We fill in cv->optvar and cv->optarg when parsing! */
return cv;
}
const struct opt_table *configvar_unparsed(struct configvar *cv)
{
const struct opt_table *ot;
if (cv->src == CONFIGVAR_CMDLINE_SHORT) {
ot = opt_find_short(cv->configline[0]);
cv->optarg = NULL;
} else {
ot = opt_find_long(cv->configline, &cv->optarg);
}
if (!ot)
return NULL;
/* We get called multiple times, but we're expected to always
* finish the cv vars, even if they're added at the last minute
* on the cmdline, so we check this is only done once, and we
* do it even if we're not going to use it now. */
if (!cv->optvar) {
/* optvar is up to the = (i.e. one char before optarg) */
if (!cv->optarg)
cv->optvar = cv->configline;
else
cv->optvar = tal_strndup(cv, cv->configline,
cv->optarg - cv->configline - 1);
}
return ot;
}
const char *configvar_parse(struct configvar *cv,
bool early,
bool full_knowledge,
bool developer)
{
const struct opt_table *ot;
ot = configvar_unparsed(cv);
if (!ot) {
/* Do we ignore unknown entries? */
if (!full_knowledge)
return NULL;
return "unknown option";
}
if ((ot->type & OPT_DEV) && !developer)
return "requires DEVELOPER";
/* If we're early and we want late, or vv, ignore. */
if (!!(ot->type & OPT_EARLY) != early)
return NULL;
if (ot->type & OPT_NOARG) {
/* MULTI doesn't make sense with single args */
assert(!(ot->type & OPT_MULTI));
if (cv->optarg)
return "doesn't allow an argument";
return ot->cb(ot->u.arg);
} else {
if (!cv->optarg)
return "requires an argument";
return ot->cb_arg(cv->optarg, ot->u.arg);
}
}
/* This is O(N^2) but nobody cares */
void configvar_finalize_overrides(struct configvar **cvs)
{
/* Map to options: two different names can be the same option,
* given aliases! */
const struct opt_table **opts;
opts = tal_arr(tmpctx, const struct opt_table *, tal_count(cvs));
for (size_t i = 0; i < tal_count(cvs); i++) {
opts[i] = opt_find_long(cvs[i]->optvar, NULL);
/* If you're allowed multiple, they don't override */
if (opts[i]->type & OPT_MULTI)
continue;
for (size_t j = 0; j < i; j++) {
if (opts[j] == opts[i])
cvs[j]->overridden = true;
}
}
}
void configvar_remove(struct configvar ***cvs,
const char *name,
enum configvar_src src,
const char *optarg)
{
/* We remove all from this source, potentially restoring an overridden */
ssize_t prev = -1;
bool removed;
removed = false;
for (size_t i = 0; i < tal_count(*cvs); i++) {
/* This can happen if plugin fails during startup! */
if ((*cvs)[i]->optvar == NULL)
continue;
if (!streq((*cvs)[i]->optvar, name))
continue;
if (optarg && !streq((*cvs)[i]->optarg, optarg))
continue;
if ((*cvs)[i]->src == src) {
tal_free((*cvs)[i]);
tal_arr_remove(cvs, i);
i--;
removed = true;
continue;
}
/* Wrong type, correct name. */
prev = i;
}
/* Unmark prev if we removed overriding ones. If it's multi,
* this is a noop. */
if (removed && prev != -1)
(*cvs)[prev]->overridden = false;
}
struct configvar *configvar_dup(const tal_t *ctx, const struct configvar *cv)
{
struct configvar *ret;
if (taken(cv))
return tal_steal(ctx, cast_const(struct configvar *, cv));
ret = tal_dup(ctx, struct configvar, cv);
if (ret->file)
ret->file = tal_strdup(ret, ret->file);
if (ret->configline)
ret->configline = tal_strdup(ret, ret->configline);
if (ret->optvar) {
ret->optvar = tal_strdup(ret, ret->optvar);
/* Optarg, if non-NULL, points into cmdline! */
if (ret->optarg) {
size_t off = cv->optarg - cv->configline;
assert(off < strlen(cv->configline));
ret->optarg = ret->configline + off;
}
}
return ret;
}
struct configvar **configvar_join(const tal_t *ctx,
struct configvar **first,
struct configvar **second)
{
struct configvar **cvs;
size_t n = tal_count(first);
if (taken(first)) {
cvs = tal_steal(ctx, first);
tal_resize(&cvs, n + tal_count(second));
} else {
cvs = tal_arr(ctx, struct configvar *, n + tal_count(second));
for (size_t i = 0; i < n; i++) {
cvs[i] = configvar_dup(cvs, first[i]);
}
}
if (taken(second)) {
for (size_t i = 0; i < tal_count(second); i++)
cvs[n + i] = tal_steal(cvs, second[i]);
tal_free(second);
} else {
for (size_t i = 0; i < tal_count(second); i++)
cvs[n + i] = configvar_dup(cvs, second[i]);
}
return cvs;
}
static struct configvar *configvar_iter(struct configvar **cvs,
const char **names,
const struct configvar *firstcv)
{
for (size_t i = 0; i < tal_count(cvs); i++) {
/* Wait until we reach firstcv, if any */
if (firstcv) {
if (cvs[i] == firstcv)
firstcv = NULL;
continue;
}
for (size_t j = 0; j < tal_count(names); j++) {
/* In case we iterate before initialization! */
if (!cvs[i]->optvar)
continue;
if (streq(cvs[i]->optvar, names[j]) && !cvs[i]->overridden)
return cvs[i];
}
}
return NULL;
}
struct configvar *configvar_first(struct configvar **cvs, const char **names)
{
return configvar_iter(cvs, names, NULL);
}
struct configvar *configvar_next(struct configvar **cvs,
const struct configvar *cv,
const char **names)
{
return configvar_iter(cvs, names, cv);
}