Virtual selectors

Where ordinary selectors specify a value stored in some object,
virtual selectors specify a function to call to compute a value
associated with some object.

Use them to replace the special case xdump ver by new table
EF_VERSION.

Move configkeys[] to lib/common because nsc_init() needs it to
initialize empfile[EF_VERSION].cadef.
This commit is contained in:
Markus Armbruster 2008-03-04 21:02:00 +01:00
parent 38047a62f7
commit da8a1daeef
12 changed files with 541 additions and 482 deletions

View file

@ -158,9 +158,6 @@ Without such a key, you need to count records to find the record
index, and that works only if you can see a prefix of the complete
table.
The special table "ver" collects all scalar configuration parameters
in a single record. It does not occur in the table of tables.
Syntax of xdump command
@ -368,8 +365,7 @@ table itself. Let's try it:
[...]
/45
It worked! Mind that the special table "ver" is not in the table of
tables.
It worked!
Now dump the two symbol tables we postponed. Because xdump accepts
table IDs as well as names, we don't have to know their names:

View file

@ -142,6 +142,7 @@ enum {
EF_INFRASTRUCTURE,
EF_UPDATES, /* not actually static */
EF_TABLE,
EF_VERSION,
EF_META, /* not really configuration */
/* Symbol tables */
EF_AGREEMENT_STATUS,

View file

@ -95,14 +95,21 @@ typedef char packed_nsc_cat;
* promoted type.
* If category is NSC_OFF, the value is in a context object, and
* val_as.sym specifies how to get it, as follows.
* If type is NSC_STRINGY, the value is an array of sym.len characters
* starting at sym.offs in the context object. sym.idx must be zero.
* Else if sym.len is zero, the value is in the context object at offset
* sym.off. sym.idx must be zero.
* Else sym.len is non-zero, and the value has index sym.idx in an
* array of sym.len elements at offset sym.off in in the context
* object. I.e. the value is at sym.off + sym.idx * SZ, where SZ is
* the size of the value.
* If sym.get is null, and type is NSC_STRINGY, the value is an array
* of sym.len characters starting at sym.offs in the context object.
* sym.idx must be zero.
* Else if sym.get is null, and sym.len is zero, the value is in the
* context object at offset sym.off. sym.idx must be zero.
* Else if sym.get is null, sym.len is non-zero, and the value has
* index sym.idx in an array of sym.len elements at offset sym.off in
* in the context object. I.e. the value is at sym.off + sym.idx *
* SZ, where SZ is the size of the value.
* If sym.get is not null, you obtain the value by calling get() like
* VAL->get(VAL, CNUM, CTXO), where CNUM is the country to use for
* coordinate translation and access control, and CTXO is the context
* object. get() either returns a null pointer and sets VAL->val_as
* to the value, as appropriate for the type. Or it returns another
* context object and sets VAL->val_as.sym for it.
*/
struct valstr {
packed_nsc_type val_type; /* type of value */
@ -112,6 +119,7 @@ struct valstr {
ptrdiff_t off;
int len;
int idx;
void *(*get)(struct valstr *, natid, void *);
} sym;
double dbl; /* cat NSC_VAL, type NSC_DOUBLE */
struct { /* cat NSC_VAL, type NSC_STRING, cat NSC_ID */
@ -197,11 +205,16 @@ typedef unsigned char nsc_flags;
*
* A selector describes an attribute of some context object.
* A selector with ca_type NSC_NOTYPE is invalid.
* A valid selector describes a datum of type ca_type at offset
* ca_offs in the context object.
* If ca_get is null, the selector describes a datum of type ca_type
* at offset ca_offs in the context object.
* A datum of type NSC_STRINGY is an array of ca_len characters.
* A datum of any other type is either a scalar of that type (if
* ca_len is zero), or an array of ca_len elements of that type.
* If ca_get is not null, the selector is virtual. Values can be
* obtained by calling ca_get(VAL, CNUM, CTXO), where VAL has been
* initialized from the selector and an index, CNUM is the country to
* use for coordinate translation and access control, and CTXO is the
* context object. See struct valstr for details.
* If flag NSC_DEITY is set, only to deities can use this selector.
* If flag NSC_EXTRA is set, xdump ignores this selector.
* If flag NSC_CONST is set, the datum can't be changed from its
@ -216,6 +229,7 @@ struct castr {
ptrdiff_t ca_off;
packed_nsc_type ca_type;
unsigned short ca_len;
void *(*ca_get)(struct valstr *, natid, void *);
int ca_table;
nsc_flags ca_flags;
};

View file

@ -3,8 +3,6 @@
.LV Expert
.SY "xdump <TYPE|NUMBER> <RECORDS>"
.SY "xdump meta <TYPE|NUMBER>"
.SY "xdump ver"
.SY "xdump meta ver"
The xdump command displays information on game configuration and state
in machine readable format. It is intended for use by clients and
tools. This info page gives an overview; see doc/xdump in the source

View file

@ -87,21 +87,19 @@
/*
* Evaluate a attribute of an object into VAL, return VAL.
* TYPE is the attribute's type.
* CA describes the attribute.
* PTR points to the context object.
* The attribute is stored there at offset OFF + IDX * S, where S is
* its size.
* LEN is the #array elements if it is an array, else zero.
* IDX is the index within the attribute.
*/
static struct valstr *
xdeval(struct valstr *val,
nsc_type type, void *ptr, ptrdiff_t off, int idx, int len)
xdeval(struct valstr *val, struct castr *ca, void *ptr, int idx)
{
val->val_type = type;
val->val_type = ca->ca_type;
val->val_cat = NSC_OFF;
val->val_as.sym.off = off;
val->val_as.sym.len = len;
val->val_as.sym.off = ca->ca_off;
val->val_as.sym.len = ca->ca_len;
val->val_as.sym.idx = idx;
val->val_as.sym.get = ca->ca_get;
return nstr_exec_val(val, player->cnum, ptr, NSC_NOTYPE);
}
@ -175,7 +173,7 @@ xdflds(struct castr ca[], void *ptr)
n = ca[i].ca_type != NSC_STRINGY ? ca[i].ca_len : 0;
j = 0;
do {
xdeval(&val, ca[i].ca_type, ptr, ca[i].ca_off, j, ca[i].ca_len);
xdeval(&val, &ca[i], ptr, j);
sep = xdprval(&val, sep);
} while (++j < n);
}
@ -337,62 +335,7 @@ xdmeta(int type)
return RET_OK;
}
/*
* Dump configkeys[], return RET_OK.
* If META, dump meta-data rather than data.
*/
static int
xdver(int meta)
{
static struct castr vers_ca = {
"version", 0, NSC_STRINGY, sizeof(PACKAGE_STRING), EF_BAD, 0
};
struct keymatch *kp;
char *sep;
int n;
struct castr ca;
struct valstr val;
xdhdr("version", meta);
if (meta) {
n = 0;
xdflds(mdchr_ca, &vers_ca);
pr("\n");
n++;
for (kp = configkeys; kp->km_key; ++kp) {
if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL)) {
ca.ca_type = kp->km_type;
ca.ca_flags = 0;
ca.ca_len = 0;
ca.ca_off = 0;
ca.ca_name = kp->km_key;
ca.ca_table = EF_BAD;
xdflds(mdchr_ca, &ca);
pr("\n");
n++;
}
}
xdftr(n);
return RET_OK;
}
xdeval(&val, vers_ca.ca_type, version, vers_ca.ca_off, 0, vers_ca.ca_len);
sep = xdprval(&val, "");
for (kp = configkeys; kp->km_key; ++kp) {
if (kp->km_type != NSC_NOTYPE && !(kp->km_flags & KM_INTERNAL)) {
xdeval(&val, kp->km_type, kp->km_data, 0, 0, 0);
sep = xdprval(&val, sep);
}
}
pr("\n");
xdftr(1);
return RET_OK;
}
/* Experimental extended dump command */
/* Extended dump command */
int
xdump(void)
{
@ -412,18 +355,17 @@ xdump(void)
natp = getnatp(player->cnum);
type = isdigit(p[0]) ? atoi(p) : ef_byname(p);
if (type >= 0 && type < EF_MAX) {
if (type < 0 || type >= EF_MAX)
return RET_SYN;
if (meta)
return xdmeta(type);
else if ((EF_IS_GAME_STATE(type) || EF_IS_VIEW(type))
if ((EF_IS_GAME_STATE(type) || EF_IS_VIEW(type))
&& !(natp->nat_stat == STAT_ACTIVE || player->god)) {
pr("Access to table %s denied\n", ef_nameof(type));
return RET_FAIL;
} else
}
if (type == EF_VERSION && !player->argp[2])
return xditem(type, "*"); /* backward compatibility */
return xditem(type, player->argp[2]);
} else if (!strncmp(p, "ver", strlen(p))) {
return xdver(meta);
}
return RET_SYN;
}

View file

@ -107,6 +107,7 @@ verify_row(int type, int row)
val.val_as.sym.off = ca[i].ca_off;
val.val_as.sym.len = ca[i].ca_len;
val.val_as.sym.idx = j;
val.val_as.sym.get = ca[i].ca_get;
nstr_exec_val(&val, 0, row_ref, NSC_NOTYPE);
if (val.val_type != NSC_LONG)
continue;

View file

@ -55,16 +55,6 @@
#include "optlist.h"
#include "prototypes.h"
/* Dummy one */
static int emp_config_dummy;
/* things that can be changed */
struct keymatch configkeys[] = {
#define EMP_CONFIG_C_OUTPUT
#include "econfig-spec.h"
#undef EMP_CONFIG_C_OUTPUT
};
static struct keymatch *keylookup(char *key, struct keymatch tbl[]);
static int set_paths(char *);

View file

@ -69,6 +69,17 @@ nstr_exec_val(struct valstr *val, natid cnum, void *ptr, nsc_type want)
valtype = val->val_type;
break;
case NSC_OFF:
if (val->val_as.sym.get) {
do {
ptr = val->val_as.sym.get(val, cnum, ptr);
} while (ptr && val->val_as.sym.get);
if (!ptr) {
valtype = val->val_type;
val->val_cat = NSC_VAL;
break;
}
}
valtype = NSC_LONG;
memb_ptr = ptr;
memb_ptr += val->val_as.sym.off;

View file

@ -221,3 +221,11 @@ float start_education = 0.0;
float start_happiness = 0.0;
float start_technology = 0.0;
float start_research = 0.0;
/* econfig keys */
static int emp_config_dummy;
struct keymatch configkeys[] = {
#define EMP_CONFIG_C_OUTPUT
#include "econfig-spec.h"
#undef EMP_CONFIG_C_OUTPUT
};

View file

@ -53,6 +53,7 @@
#include "server.h"
#include "trade.h"
#include "treaty.h"
#include "version.h"
#include "xy.h"
/* Number of elements in ARRAY. */
@ -102,7 +103,8 @@ struct empfile empfile[] = {
* that can be changed by users.
*
* Whatever of the above can't be done here must be done in
* empfile_init() or empfile_fixup().
* empfile_init() or empfile_fixup(). Except cadef may be set in
* nsc_init() instead.
*/
/*
@ -187,10 +189,13 @@ struct empfile empfile[] = {
ARRAY_TABLE(update_time, EFF_CFG)},
/*
* Special tables. EF_META gets bogus size, cids and fids here.
* Fixed up by empfile_init().
* Fixed up by empfile_init(). EF_VERSION's cadef is set by
* nsc_init().
*/
{EF_TABLE, "table", NULL, empfile_ca,
ARRAY_TABLE(empfile, EFF_CFG)},
{EF_VERSION, "version", NULL, NULL,
sizeof(PACKAGE_STRING), 0, version, 0, 0, 1, 1, -1, NULL, NULL},
{EF_META, "meta", NULL, mdchr_ca,
PTR_CACHE(mdchr_ca, EFF_CFG)},

File diff suppressed because it is too large Load diff

View file

@ -432,6 +432,7 @@ nstr_resolve_sel(struct valstr *val, struct castr *ca)
val->val_as.sym.off = ca->ca_off;
val->val_as.sym.len = ca->ca_len;
val->val_as.sym.idx = 0;
val->val_as.sym.get = ca->ca_get;
return val;
}