empserver/src/lib/subs/snxtitem.c
Markus Armbruster e3cf1e3280 Make generation numbers catch more potential yields on input
getstarg(), snxtitem() and snxtsct() can yield the processor, because
they call getstring().  But only for null or empty arguments.  For
other arguments, we should call ef_make_stale(), to catch errors.
Problem: if a caller never passes null or empty arguments, it may rely
on these functions not yielding.  We'd get false positives.  In
general, we can't know whether that's the case.  But we do know in the
common special case of player arguments.  Call ef_make_stale() for
those.
2011-04-14 20:21:23 +02:00

251 lines
5.7 KiB
C

/*
* Empire - A multi-player, client/server Internet based war game.
* Copyright (C) 1986-2011, Dave Pare, Jeff Bailey, Thomas Ruschak,
* Ken Stevens, Steve McClure, Markus Armbruster
*
* Empire is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ---
*
* See files README, COPYING and CREDITS in the root of the source
* tree for related information and legal notices. It is expected
* that future projects/authors will amend these files as needed.
*
* ---
*
* snxtitem.c: Arrange item selection using one of many criteria.
*
* Known contributors to this file:
* Dave Pare, 1989
* Markus Armbruster, 2009-2011
*/
#include <config.h>
#include <ctype.h>
#include "misc.h"
#include "player.h"
#include "xy.h"
#include "nsc.h"
#include "file.h"
#include "prototypes.h"
#include "unit.h"
/*
* setup the nstr structure for sector selection.
* can select on NS_ALL, NS_AREA, NS_DIST, and NS_LIST.
* iterate thru the "condarg" string looking
* for arguments to compile into the nstr.
* Using this function for anything but command arguments is usually
* incorrect, because it respects conditionals. Use the snxtitem_FOO()
* instead.
*/
int
snxtitem(struct nstr_item *np, int type, char *str, char *prompt)
{
struct range range;
int list[NS_LSIZE];
int cnum, n;
coord cx, cy;
int dist;
int flags;
char promptbuf[128];
char buf[1024];
np->type = EF_BAD;
np->sel = NS_UNDEF;
if (!str) {
if (!prompt) {
sprintf(promptbuf, "%s(s)? ", ef_nameof(type));
prompt = promptbuf;
}
str = getstring(prompt, buf);
if (!str)
return 0;
} else
make_stale_if_command_arg(str);
if (*str == 0) {
return 0;
}
if (type == EF_NATION && isalpha(*str)) {
cnum = natarg(str, NULL);
if (cnum < 0)
return 0;
sprintf(buf, "%d", cnum);
str = buf;
}
flags = ef_flags(type);
switch (sarg_type(str)) {
case NS_AREA:
if (!(flags & EFF_XY))
return 0;
if (!sarg_area(str, &range))
return 0;
snxtitem_area(np, type, &range);
break;
case NS_DIST:
if (!(flags & EFF_XY))
return 0;
if (!sarg_range(str, &cx, &cy, &dist))
return 0;
snxtitem_dist(np, type, cx, cy, dist);
break;
case NS_ALL:
snxtitem_all(np, type);
break;
case NS_LIST:
if ((n = sarg_list(str, list, NS_LSIZE)) == 0)
return 0;
if (!snxtitem_list(np, type, list, n))
return 0;
break;
case NS_XY:
if (!(flags & EFF_XY))
return 0;
if (!sarg_xy(str, &cx, &cy))
return 0;
snxtitem_xy(np, type, cx, cy);
break;
case NS_GROUP:
if (!(flags & EFF_GROUP))
return 0;
snxtitem_group(np, type, *str);
break;
default:
return 0;
}
return snxtitem_use_condarg(np);
}
void
snxtitem_area(struct nstr_item *np, int type, struct range *range)
{
memset(np, 0, sizeof(*np));
np->cur = -1;
np->type = type;
np->sel = NS_AREA;
np->index = -1;
np->range = *range;
xysize_range(&np->range);
}
void
snxtitem_dist(struct nstr_item *np, int type, int cx, int cy, int dist)
{
memset(np, 0, sizeof(*np));
xydist_range(cx, cy, dist, &np->range);
np->cur = -1;
np->type = type;
np->sel = NS_DIST;
np->cx = cx;
np->cy = cy;
np->index = -1;
np->dist = dist;
}
void
snxtitem_xy(struct nstr_item *np, int type, coord x, coord y)
{
memset(np, 0, sizeof(*np));
np->cur = -1;
np->type = type;
np->sel = NS_XY;
np->cx = xnorm(x);
np->cy = ynorm(y);
np->index = -1;
np->dist = 0;
}
void
snxtitem_all(struct nstr_item *np, int type)
{
memset(np, 0, sizeof(*np));
np->cur = -1;
np->sel = NS_ALL;
np->type = type;
np->index = -1;
xysize_range(&np->range);
}
void
snxtitem_group(struct nstr_item *np, int type, char group)
{
if (group == '~')
group = 0;
memset(np, 0, sizeof(*np));
np->cur = -1;
np->sel = NS_GROUP;
np->group = group;
np->type = type;
np->index = -1;
xysize_range(&np->range);
}
void
snxtitem_rewind(struct nstr_item *np)
{
np->cur = -1;
np->index = -1;
}
int
snxtitem_list(struct nstr_item *np, int type, int *list, int len)
{
int i;
memset(np, 0, sizeof(*np));
np->cur = -1;
np->type = type;
np->sel = NS_LIST;
np->index = -1;
if (len <= 0 || len > NS_LSIZE)
return 0;
for (i = 0; i < len; i++)
np->list[i] = list[i];
np->size = len;
return 1;
}
/*
* Initialize NP to iterate over the items of type TYPE in a carrier.
* The carrier has file type CARRIER_TYPE and uid CARRIER_UID.
* Note: you can take an item gotten with nxtitem() off its carrier
* without disturbing the iterator. Whether the iterator will pick up
* stuff you load onto the carrier during iteration is unspecified.
*/
void
snxtitem_cargo(struct nstr_item *np, int type,
int carrier_type, int carrier_uid)
{
memset(np, 0, sizeof(*np));
np->cur = -1;
np->type = type;
np->sel = NS_CARGO;
np->next = unit_cargo_first(carrier_type, carrier_uid, type);
}
int
snxtitem_use_condarg(struct nstr_item *np)
{
int n;
if (!player->condarg)
return 1;
n = nstr_comp(np->cond, sizeof(np->cond) / sizeof(*np->cond),
np->type, player->condarg);
if (n < 0)
return 0;
np->ncond = n;
return 1;
}