From 2fc1e74a72df92098bb4cffb074862b29da97652 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 27 Oct 2005 21:33:17 +0000 Subject: [PATCH] (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. --- include/file.h | 1 + src/lib/commands/cede.c | 10 +++------- src/lib/commands/cons.c | 3 ++- src/lib/commands/fuel.c | 7 +++---- src/lib/commands/mfir.c | 3 ++- src/lib/commands/miss.c | 7 +++---- src/lib/commands/set.c | 13 ++++--------- src/lib/common/file.c | 40 ++++++++++++++++++++++++++++++++++++---- 8 files changed, 54 insertions(+), 30 deletions(-) diff --git a/include/file.h b/include/file.h index 301a0ca7..27395580 100644 --- a/include/file.h +++ b/include/file.h @@ -150,6 +150,7 @@ extern int ef_ensure_space(int, int, int); extern int ef_nelem(int); extern int ef_flags(int); extern int ef_byname(char *); +extern int ef_byname_from(char *, int *); extern struct empfile empfile[]; diff --git a/src/lib/commands/cede.c b/src/lib/commands/cede.c index 7e882554..7ca01d6a 100644 --- a/src/lib/commands/cede.c +++ b/src/lib/commands/cede.c @@ -55,6 +55,7 @@ static void grab_ship(struct shpstr *, natid); int cede(void) { + static int sct_or_shp[] = { EF_SECTOR, EF_SHIP, EF_BAD }; natid to; int n; int is_sector = 0, is_ship = 0; @@ -83,13 +84,8 @@ cede(void) return RET_FAIL; if (strlen(p) > 4) p[2] = 0; - type = ef_byname(p); - - if (type == EF_SECTOR) - is_ship = 0; - else if (type == EF_SHIP) - is_sector = 0; - else { + type = ef_byname_from(p, sct_or_shp); + if (type < 0) { pr("Please type 'se' or 'sh'!\n"); return RET_FAIL; } diff --git a/src/lib/commands/cons.c b/src/lib/commands/cons.c index 51292f4b..f1999536 100644 --- a/src/lib/commands/cons.c +++ b/src/lib/commands/cons.c @@ -110,6 +110,7 @@ cons(void) static int cons_choose(struct ltcomstr *ltcp) { + static int lon_or_trt[] = { EF_LOAN, EF_TREATY, EF_BAD }; s_char *p; struct lonstr *lp; struct trtstr *tp; @@ -119,7 +120,7 @@ cons_choose(struct ltcomstr *ltcp) memset(ltcp, 0, sizeof(*ltcp)); if (getstarg(player->argp[1], "loan or treaty? ", buf) == 0) return RET_SYN; - ltcp->type = ef_byname(buf); + ltcp->type = ef_byname_from(buf, lon_or_trt); switch (ltcp->type) { case EF_TREATY: if (!opt_TREATIES) { diff --git a/src/lib/commands/fuel.c b/src/lib/commands/fuel.c index 5ddc7daa..f97456d8 100644 --- a/src/lib/commands/fuel.c +++ b/src/lib/commands/fuel.c @@ -54,6 +54,7 @@ union item_u { int fuel(void) { + static int shp_or_lnd[] = { EF_SHIP, EF_LAND, EF_BAD }; struct nstr_item ni; union item_u item, item2; int type; @@ -80,10 +81,8 @@ fuel(void) if ((p = getstarg(player->argp[1], "Ship or land unit (s,l)? ", buf)) == 0) return RET_SYN; - type = ef_byname(p); - if (type == EF_SECTOR) - type = EF_SHIP; - if (type != EF_SHIP && type != EF_LAND) { + type = ef_byname_from(p, shp_or_lnd); + if (type < 0) { pr("Ships or land units only! (s, l)\n"); return RET_SYN; } diff --git a/src/lib/commands/mfir.c b/src/lib/commands/mfir.c index e4f23059..643077d3 100644 --- a/src/lib/commands/mfir.c +++ b/src/lib/commands/mfir.c @@ -86,6 +86,7 @@ static void use_ammo(struct emp_qelem *); int multifire(void) { + static int ef_with_guns[] = { EF_SECTOR, EF_SHIP, EF_LAND, EF_BAD }; s_char vbuf[20]; s_char *ptr; double range2, range; @@ -132,7 +133,7 @@ multifire(void) buf))) return RET_SYN; player->argp[1] = 0; - type = ef_byname(p); + type = ef_byname_from(p, ef_with_guns); if (type == EF_SECTOR) { if (opt_NO_FORT_FIRE) { pr("Fort firing is disabled.\n"); diff --git a/src/lib/commands/miss.c b/src/lib/commands/miss.c index 9dfb982a..60defb8f 100644 --- a/src/lib/commands/miss.c +++ b/src/lib/commands/miss.c @@ -55,6 +55,7 @@ int mission(void) { + static int ef_with_missions[] = { EF_SHIP, EF_LAND, EF_PLANE, EF_BAD }; s_char *p; int type; int mission; @@ -72,10 +73,8 @@ mission(void) getstarg(player->argp[1], "Ship, plane or land unit (p,sh,la)? ", buf)) == 0) return RET_SYN; - type = ef_byname(p); - if (type == EF_SECTOR) - type = EF_SHIP; - if (type != EF_SHIP && type != EF_LAND && type != EF_PLANE) { + type = ef_byname_from(p, ef_with_missions); + if (type < 0) { pr("Ships, land units or planes only! (s, l, p)\n"); return RET_SYN; } diff --git a/src/lib/commands/set.c b/src/lib/commands/set.c index 45f887c8..9e6a3b28 100644 --- a/src/lib/commands/set.c +++ b/src/lib/commands/set.c @@ -53,6 +53,7 @@ int set(void) { + static int ef_saleable[] = { EF_SHIP, EF_PLANE, EF_LAND, EF_NUKE, EF_BAD }; char *p; int type; int price; @@ -76,18 +77,12 @@ set(void) check_market(); 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; - if ((type = ef_byname(p)) < 0) { - pr("%s: not an item type\n", p); + if ((type = ef_byname_from(p, ef_saleable)) < 0) { + pr("You can sell only ships, planes, land units or nukes\n", p); 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])) return RET_SYN; while (nxtitem(&ni, &item)) { diff --git a/src/lib/common/file.c b/src/lib/common/file.c index a1a4b975..c647a337 100644 --- a/src/lib/common/file.c +++ b/src/lib/common/file.c @@ -41,12 +41,12 @@ #if !defined(_WIN32) #include #endif +#include "common.h" +#include "file.h" +#include "gen.h" +#include "match.h" #include "misc.h" #include "nsc.h" -#include "file.h" -#include "common.h" -#include "gen.h" - static int fillcache(struct empfile *, int); static int do_write(struct empfile *, void *, int, int); @@ -437,6 +437,7 @@ ef_mtime(int type) int ef_byname(char *name) { + /* FIXME should use stmtch() */ struct empfile *ef; int i; int len; @@ -450,6 +451,37 @@ ef_byname(char *name) 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 * ef_nameof(int type) {