Be more tolerant of invalid arguments

FossilOrigin-Name: d2f07d884a4f4319ff687e085c3233e210ee05b46a2675ecd757a261e6f19e6e
This commit is contained in:
Jonathan Schleifer 2025-03-12 00:16:05 +00:00
parent f1968ce5af
commit 38747afbb5
12 changed files with 112 additions and 88 deletions

View file

@ -1,4 +1,5 @@
#import "Command.h" #import "Command.h"
#import "OFString+Cube.h"
#include <cube.h> #include <cube.h>
@ -38,34 +39,34 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
((void(__cdecl *)(int))_function)( ((void(__cdecl *)(int))_function)(
[arguments[1] intValueWithBase:0]); [arguments[1] cube_intValueWithBase:0]);
} }
break; break;
case ARG_2INT: case ARG_2INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 3); arguments = padArguments(arguments, 3);
((void(__cdecl *)(int, int))_function)( ((void(__cdecl *)(int, int))_function)(
[arguments[1] intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] intValueWithBase:0]); [arguments[2] cube_intValueWithBase:0]);
} }
break; break;
case ARG_3INT: case ARG_3INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 4); arguments = padArguments(arguments, 4);
((void(__cdecl *)(int, int, int))_function)( ((void(__cdecl *)(int, int, int))_function)(
[arguments[1] intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] intValueWithBase:0], [arguments[2] cube_intValueWithBase:0],
[arguments[3] intValueWithBase:0]); [arguments[3] cube_intValueWithBase:0]);
} }
break; break;
case ARG_4INT: case ARG_4INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 5); arguments = padArguments(arguments, 5);
((void(__cdecl *)(int, int, int, int))_function)( ((void(__cdecl *)(int, int, int, int))_function)(
[arguments[1] intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] intValueWithBase:0], [arguments[2] cube_intValueWithBase:0],
[arguments[3] intValueWithBase:0], [arguments[3] cube_intValueWithBase:0],
[arguments[4] intValueWithBase:0]); [arguments[4] cube_intValueWithBase:0]);
} }
break; break;
case ARG_NONE: case ARG_NONE:

View file

@ -23,12 +23,17 @@
x = _text.intValue; x = _text.intValue;
} @catch (OFInvalidFormatException *e) { } @catch (OFInvalidFormatException *e) {
x = 0; x = 0;
} @catch (OFOutOfRangeException *e) {
x = 0;
} }
@try { @
try {
y = otherItem.text.intValue; y = otherItem.text.intValue;
} @catch (OFInvalidFormatException *e) { } @catch (OFInvalidFormatException *e) {
y = 0; y = 0;
} @catch (OFOutOfRangeException *e) {
y = 0;
} }
if (x > y) if (x > y)

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "OFString+Cube.h"
int nextmode = 0; // nextmode becomes gamemode after next map load int nextmode = 0; // nextmode becomes gamemode after next map load
VAR(gamemode, 1, 0, 0); VAR(gamemode, 1, 0, 0);
@ -238,7 +239,7 @@ static OFString *sleepcmd = nil;
void void
sleepf(OFString *msec, OFString *cmd) sleepf(OFString *msec, OFString *cmd)
{ {
sleepwait = msec.intValue + lastmillis; sleepwait = msec.cube_intValue + lastmillis;
sleepcmd = cmd; sleepcmd = cmd;
} }
COMMANDN(sleep, sleepf, ARG_2STR) COMMANDN(sleep, sleepf, ARG_2STR)

View file

@ -8,6 +8,7 @@
#import "Alias.h" #import "Alias.h"
#import "Command.h" #import "Command.h"
#import "Identifier.h" #import "Identifier.h"
#import "OFString+Cube.h"
#import "Variable.h" #import "Variable.h"
// contains ALL vars/commands/aliases // contains ALL vars/commands/aliases
@ -181,6 +182,54 @@ lookup(OFString *n) // find value of ident referenced with $ in exp
return n; return n;
} }
int
executeIdentifier(__kindof Identifier *identifier,
OFArray<OFString *> *arguments, bool isDown)
{
if (identifier == nil) {
@try {
return [arguments[0] intValueWithBase:0];
} @catch (OFInvalidFormatException *e) {
conoutf(@"unknown command: %@", arguments[0]);
return 0;
} @catch (OFOutOfRangeException *e) {
conoutf(@"invalid value: %@", arguments[0]);
return 0;
}
}
if ([identifier isKindOfClass:Command.class])
// game defined commands use very ad-hoc function signature,
// and just call it
return [identifier callWithArguments:arguments isDown:isDown];
if ([identifier isKindOfClass:Variable.class]) {
if (!isDown)
return 0;
// game defined variables
if (arguments.count < 2 || arguments[1].length == 0)
[identifier printValue];
else
[identifier
setValue:[arguments[1] cube_intValueWithBase:0]];
}
if ([identifier isKindOfClass:Alias.class]) {
// alias, also used as functions and (global) variables
for (int i = 1; i < arguments.count; i++) {
// set any arguments as (global) arg values so
// functions can access them
OFString *t = [OFString stringWithFormat:@"arg%d", i];
alias(t, arguments[i]);
}
return execute([identifier action], isDown);
}
return 0;
}
// all evaluation happens here, recursively // all evaluation happens here, recursively
int int
execute(OFString *string, bool isDown) execute(OFString *string, bool isDown)
@ -230,55 +279,8 @@ execute(OFString *string, bool isDown)
if (c.length == 0) if (c.length == 0)
continue; continue;
__kindof Identifier *identifier = identifiers[c]; val = executeIdentifier(identifiers[c],
if (identifier == nil) { [OFArray arrayWithObjects:w count:numargs], isDown);
@try {
val = [c intValueWithBase:0];
} @catch (OFInvalidFormatException *e) {
conoutf(@"unknown command: %@", c);
}
} else {
if ([identifier isKindOfClass:Command.class]) {
// game defined commands use very
// ad-hoc function signature, and just
// call it
OFArray<OFString *> *arguments =
[[OFArray alloc]
initWithObjects:w
count:numargs];
val = [identifier
callWithArguments:arguments
isDown:isDown];
} else if ([identifier
isKindOfClass:Variable.class]) {
// game defined variables
if (isDown) {
if (w[1].length == 0)
[identifier printValue];
else
[identifier
setValue:
[w[1]
intValueWithBase:
0]];
}
} else if ([identifier
isKindOfClass:Alias.class]) {
// alias, also used as functions and
// (global) variables
for (int i = 1; i < numargs; i++) {
// set any arguments as
// (global) arg values so
// functions can access them
OFString *t = [OFString
stringWithFormat:@"arg%d",
i];
alias(t, w[i]);
}
val = execute(
[identifier action], isDown);
}
}
} }
return val; return val;
@ -378,10 +380,9 @@ writecfg()
return; return;
} }
[stream writeString: [stream writeString:@"// automatically written on exit, do not modify\n"
@"// automatically written on exit, do not modify\n" @"// delete this file to have defaults.cfg "
@"// delete this file to have defaults.cfg overwrite these " @"overwrite these settings\n"
@"settings\n"
@"// modify settings in game, or put settings in " @"// modify settings in game, or put settings in "
@"autoexec.cfg to override anything\n" @"autoexec.cfg to override anything\n"
@"\n"]; @"\n"];
@ -418,8 +419,8 @@ writecfg()
COMMAND(writecfg, ARG_NONE) COMMAND(writecfg, ARG_NONE)
// below the commands that implement a small imperative language. thanks to the // below the commands that implement a small imperative language. thanks to the
// semantics of // semantics of () and [] expressions, any control construct can be defined
// () and [] expressions, any control construct can be defined trivially. // trivially.
void void
intset(OFString *name, int v) intset(OFString *name, int v)
@ -439,7 +440,7 @@ void
loopa(OFString *times, OFString *body) loopa(OFString *times, OFString *body)
{ {
@autoreleasepool { @autoreleasepool {
int t = times.intValue; int t = times.cube_intValue;
loopi(t) loopi(t)
{ {
@ -497,10 +498,9 @@ void
at(OFString *s_, OFString *pos) at(OFString *s_, OFString *pos)
{ {
@autoreleasepool { @autoreleasepool {
int n = pos.intValue; int n = pos.cube_intValue;
std::unique_ptr<char> copy(strdup(s_.UTF8String)); std::unique_ptr<char> copy(strdup(s_.UTF8String));
char *s = copy.get(); char *s = copy.get();
loopi(n) s += strspn(s += strcspn(s, " \0"), " "); loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
s[strcspn(s, " \0")] = 0; s[strcspn(s, " \0")] = 0;
concat(@(s)); concat(@(s));

View file

@ -5,6 +5,7 @@
#include <ctype.h> #include <ctype.h>
#import "KeyMapping.h" #import "KeyMapping.h"
#import "OFString+Cube.h"
struct cline { struct cline {
char *cref; char *cref;
@ -106,8 +107,8 @@ keymap(OFString *code, OFString *key, OFString *action)
if (keyMappings == nil) if (keyMappings == nil)
keyMappings = [[OFMutableArray alloc] init]; keyMappings = [[OFMutableArray alloc] init];
KeyMapping *mapping = [[KeyMapping alloc] initWithCode:code.intValue KeyMapping *mapping =
name:key]; [[KeyMapping alloc] initWithCode:code.cube_intValue name:key];
mapping.action = action; mapping.action = action;
[keyMappings addObject:mapping]; [keyMappings addObject:mapping];
} }

View file

@ -4,6 +4,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "OFString+Cube.h"
bool editmode = false; bool editmode = false;
@ -605,8 +606,8 @@ newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4)
EDITSEL; EDITSEL;
@autoreleasepool { @autoreleasepool {
newentity(sel.x, sel.y, (int)player1.o.z, what, newentity(sel.x, sel.y, (int)player1.o.z, what,
[a1 intValueWithBase:0], [a2 intValueWithBase:0], [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
[a3 intValueWithBase:0], [a4 intValueWithBase:0]); [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
} }
} }

View file

@ -10,6 +10,7 @@ executable('client',
'MapModelInfo.m', 'MapModelInfo.m',
'Menu.m', 'Menu.m',
'MenuItem.m', 'MenuItem.m',
'OFString+Cube.mm',
'Projectile.m', 'Projectile.m',
'ServerInfo.mm', 'ServerInfo.mm',
'Variable.mm', 'Variable.mm',

View file

@ -206,6 +206,9 @@ loadsky(OFString *basename)
@autoreleasepool { @autoreleasepool {
static OFString *lastsky = @""; static OFString *lastsky = @"";
basename = [basename stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"];
if ([lastsky isEqual:basename]) if ([lastsky isEqual:basename])
return; return;

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "OFString+Cube.h"
#ifdef DARWIN #ifdef DARWIN
# define GL_COMBINE_EXT GL_COMBINE_ARB # define GL_COMBINE_EXT GL_COMBINE_ARB
@ -197,11 +198,15 @@ void
texture(OFString *aframe, OFString *name) texture(OFString *aframe, OFString *name)
{ {
@autoreleasepool { @autoreleasepool {
int num = curtexnum++, frame = aframe.intValue; int num = curtexnum++, frame = aframe.cube_intValue;
if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES)
return; return;
mapping[num][frame] = 1; mapping[num][frame] = 1;
mapname[num][frame] = name; mapname[num][frame] =
[name stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"];
} }
} }
COMMAND(texture, ARG_2STR) COMMAND(texture, ARG_2STR)

View file

@ -5,6 +5,7 @@
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "MD2.h" #import "MD2.h"
#import "MapModelInfo.h" #import "MapModelInfo.h"
#import "OFString+Cube.h"
static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil; static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil;
static OFMutableArray<MD2 *> *mapmodels = nil; static OFMutableArray<MD2 *> *mapmodels = nil;
@ -67,11 +68,12 @@ void
mapmodel( mapmodel(
OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name)
{ {
MD2 *m = loadmodel(name); MD2 *m = loadmodel([name stringByReplacingOccurrencesOfString:@"\\"
m.mmi = [[MapModelInfo alloc] initWithRad:rad.intValue withString:@"/"]);
h:h.intValue m.mmi = [[MapModelInfo alloc] initWithRad:rad.cube_intValue
zoff:zoff.intValue h:h.cube_intValue
snap:snap.intValue zoff:zoff.cube_intValue
snap:snap.cube_intValue
name:m.loadname]; name:m.loadname];
if (mapmodels == nil) if (mapmodels == nil)

View file

@ -88,6 +88,8 @@ music(OFString *name)
stopsound(); stopsound();
if (soundvol && musicvol) { if (soundvol && musicvol) {
@autoreleasepool { @autoreleasepool {
name = [name stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"];
OFString *path = OFString *path =
[OFString stringWithFormat:@"packages/%@", name]; [OFString stringWithFormat:@"packages/%@", name];
OFIRI *IRI = [Cube.sharedInstance.gameDataIRI OFIRI *IRI = [Cube.sharedInstance.gameDataIRI
@ -148,7 +150,8 @@ registersound(OFString *name)
if (snames == nil) if (snames == nil)
snames = [[OFMutableArray alloc] init]; snames = [[OFMutableArray alloc] init];
[snames addObject:name]; [snames addObject:[name stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"]];
samples.add(NULL); samples.add(NULL);
return samples.length() - 1; return samples.length() - 1;

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "OFString+Cube.h"
#import "Projectile.h" #import "Projectile.h"
static const int MONSTERDAMAGEFACTOR = 4; static const int MONSTERDAMAGEFACTOR = 4;
@ -63,9 +64,9 @@ reloadtime(int gun)
void void
weapon(OFString *a1, OFString *a2, OFString *a3) weapon(OFString *a1, OFString *a2, OFString *a3)
{ {
selectgun((a1.length > 0 ? a1.intValue : -1), selectgun((a1.length > 0 ? a1.cube_intValue : -1),
(a2.length > 0 ? a2.intValue : -1), (a2.length > 0 ? a2.cube_intValue : -1),
(a3.length > 0 ? a3.intValue : -1)); (a3.length > 0 ? a3.cube_intValue : -1));
} }
COMMAND(weapon, ARG_3STR) COMMAND(weapon, ARG_3STR)