(ef_byname_from): New.

(set, mission, multifire, fuel, cons_choose, cede): Use it instead of
ef_byname().  Remove the hacks to map unwanted results to wanted
results.  The hacks in set() were broken: bad input made the code cast
arbitrary items to union trdgenstr, with potentially disastrous
consequences.  Closes #906483 and #906486.

(set): Less cryptic prompt and diagnostics.
This commit is contained in:
Markus Armbruster 2005-10-27 21:33:17 +00:00
parent 2df98825e9
commit 2fc1e74a72
8 changed files with 54 additions and 30 deletions

View file

@ -150,6 +150,7 @@ extern int ef_ensure_space(int, int, int);
extern int ef_nelem(int); extern int ef_nelem(int);
extern int ef_flags(int); extern int ef_flags(int);
extern int ef_byname(char *); extern int ef_byname(char *);
extern int ef_byname_from(char *, int *);
extern struct empfile empfile[]; extern struct empfile empfile[];

View file

@ -55,6 +55,7 @@ static void grab_ship(struct shpstr *, natid);
int int
cede(void) cede(void)
{ {
static int sct_or_shp[] = { EF_SECTOR, EF_SHIP, EF_BAD };
natid to; natid to;
int n; int n;
int is_sector = 0, is_ship = 0; int is_sector = 0, is_ship = 0;
@ -83,13 +84,8 @@ cede(void)
return RET_FAIL; return RET_FAIL;
if (strlen(p) > 4) if (strlen(p) > 4)
p[2] = 0; p[2] = 0;
type = ef_byname(p); type = ef_byname_from(p, sct_or_shp);
if (type < 0) {
if (type == EF_SECTOR)
is_ship = 0;
else if (type == EF_SHIP)
is_sector = 0;
else {
pr("Please type 'se' or 'sh'!\n"); pr("Please type 'se' or 'sh'!\n");
return RET_FAIL; return RET_FAIL;
} }

View file

@ -110,6 +110,7 @@ cons(void)
static int static int
cons_choose(struct ltcomstr *ltcp) cons_choose(struct ltcomstr *ltcp)
{ {
static int lon_or_trt[] = { EF_LOAN, EF_TREATY, EF_BAD };
s_char *p; s_char *p;
struct lonstr *lp; struct lonstr *lp;
struct trtstr *tp; struct trtstr *tp;
@ -119,7 +120,7 @@ cons_choose(struct ltcomstr *ltcp)
memset(ltcp, 0, sizeof(*ltcp)); memset(ltcp, 0, sizeof(*ltcp));
if (getstarg(player->argp[1], "loan or treaty? ", buf) == 0) if (getstarg(player->argp[1], "loan or treaty? ", buf) == 0)
return RET_SYN; return RET_SYN;
ltcp->type = ef_byname(buf); ltcp->type = ef_byname_from(buf, lon_or_trt);
switch (ltcp->type) { switch (ltcp->type) {
case EF_TREATY: case EF_TREATY:
if (!opt_TREATIES) { if (!opt_TREATIES) {

View file

@ -54,6 +54,7 @@ union item_u {
int int
fuel(void) fuel(void)
{ {
static int shp_or_lnd[] = { EF_SHIP, EF_LAND, EF_BAD };
struct nstr_item ni; struct nstr_item ni;
union item_u item, item2; union item_u item, item2;
int type; int type;
@ -80,10 +81,8 @@ fuel(void)
if ((p = if ((p =
getstarg(player->argp[1], "Ship or land unit (s,l)? ", buf)) == 0) getstarg(player->argp[1], "Ship or land unit (s,l)? ", buf)) == 0)
return RET_SYN; return RET_SYN;
type = ef_byname(p); type = ef_byname_from(p, shp_or_lnd);
if (type == EF_SECTOR) if (type < 0) {
type = EF_SHIP;
if (type != EF_SHIP && type != EF_LAND) {
pr("Ships or land units only! (s, l)\n"); pr("Ships or land units only! (s, l)\n");
return RET_SYN; return RET_SYN;
} }

View file

@ -86,6 +86,7 @@ static void use_ammo(struct emp_qelem *);
int int
multifire(void) multifire(void)
{ {
static int ef_with_guns[] = { EF_SECTOR, EF_SHIP, EF_LAND, EF_BAD };
s_char vbuf[20]; s_char vbuf[20];
s_char *ptr; s_char *ptr;
double range2, range; double range2, range;
@ -132,7 +133,7 @@ multifire(void)
buf))) buf)))
return RET_SYN; return RET_SYN;
player->argp[1] = 0; player->argp[1] = 0;
type = ef_byname(p); type = ef_byname_from(p, ef_with_guns);
if (type == EF_SECTOR) { if (type == EF_SECTOR) {
if (opt_NO_FORT_FIRE) { if (opt_NO_FORT_FIRE) {
pr("Fort firing is disabled.\n"); pr("Fort firing is disabled.\n");

View file

@ -55,6 +55,7 @@
int int
mission(void) mission(void)
{ {
static int ef_with_missions[] = { EF_SHIP, EF_LAND, EF_PLANE, EF_BAD };
s_char *p; s_char *p;
int type; int type;
int mission; int mission;
@ -72,10 +73,8 @@ mission(void)
getstarg(player->argp[1], "Ship, plane or land unit (p,sh,la)? ", getstarg(player->argp[1], "Ship, plane or land unit (p,sh,la)? ",
buf)) == 0) buf)) == 0)
return RET_SYN; return RET_SYN;
type = ef_byname(p); type = ef_byname_from(p, ef_with_missions);
if (type == EF_SECTOR) if (type < 0) {
type = EF_SHIP;
if (type != EF_SHIP && type != EF_LAND && type != EF_PLANE) {
pr("Ships, land units or planes only! (s, l, p)\n"); pr("Ships, land units or planes only! (s, l, p)\n");
return RET_SYN; return RET_SYN;
} }

View file

@ -53,6 +53,7 @@
int int
set(void) set(void)
{ {
static int ef_saleable[] = { EF_SHIP, EF_PLANE, EF_LAND, EF_NUKE, EF_BAD };
char *p; char *p;
int type; int type;
int price; int price;
@ -76,18 +77,12 @@ set(void)
check_market(); check_market();
check_trade(); check_trade();
if ((p = getstarg(player->argp[1], "Item type? ", buf)) == 0) if ((p = getstarg(player->argp[1], "Ship, plane, land unit or nuke? ", buf)) == 0)
return RET_SYN; return RET_SYN;
if ((type = ef_byname(p)) < 0) { if ((type = ef_byname_from(p, ef_saleable)) < 0) {
pr("%s: not an item type\n", p); pr("You can sell only ships, planes, land units or nukes\n", p);
return RET_SYN; return RET_SYN;
} }
if (type == EF_SECTOR)
type = EF_SHIP;
if (type == EF_NEWS)
type = EF_NUKE;
if (type == EF_LOAN)
type = EF_LAND;
if (!snxtitem(&ni, type, player->argp[2])) if (!snxtitem(&ni, type, player->argp[2]))
return RET_SYN; return RET_SYN;
while (nxtitem(&ni, &item)) { while (nxtitem(&ni, &item)) {

View file

@ -41,12 +41,12 @@
#if !defined(_WIN32) #if !defined(_WIN32)
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "common.h"
#include "file.h"
#include "gen.h"
#include "match.h"
#include "misc.h" #include "misc.h"
#include "nsc.h" #include "nsc.h"
#include "file.h"
#include "common.h"
#include "gen.h"
static int fillcache(struct empfile *, int); static int fillcache(struct empfile *, int);
static int do_write(struct empfile *, void *, int, int); static int do_write(struct empfile *, void *, int, int);
@ -437,6 +437,7 @@ ef_mtime(int type)
int int
ef_byname(char *name) ef_byname(char *name)
{ {
/* FIXME should use stmtch() */
struct empfile *ef; struct empfile *ef;
int i; int i;
int len; int len;
@ -450,6 +451,37 @@ ef_byname(char *name)
return -1; return -1;
} }
/*
* Search CHOICES[] for a table ID matching NAME.
* CHOICES[] contains indexes in empfile[] and is terminated with a
* negative value.
* Return the matching index if there is one, else -1.
*/
int
ef_byname_from(char *name, int choices[])
{
int res;
int *p;
res = M_NOTFOUND;
for (p = choices; *p >= 0; p++) {
if (ef_check(*p) < 0)
continue;
switch (mineq(name, empfile[*p].name)) {
case ME_MISMATCH:
break;
case ME_PARTIAL:
if (res >= 0)
return M_NOTUNIQUE;
res = *p;
break;
case ME_EXACT:
return *p;
}
}
return res;
}
char * char *
ef_nameof(int type) ef_nameof(int type)
{ {