Overview
Comment: | Be more tolerant of invalid arguments |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
d2f07d884a4f4319ff687e085c3233e2 |
User & Date: | js on 2025-03-12 00:16:05 |
Other Links: | manifest | tags |
Context
2025-03-12
| ||
22:35 | Add files forgotten in last commit check-in: e208417f95 user: js tags: trunk | |
00:16 | Be more tolerant of invalid arguments check-in: d2f07d884a user: js tags: trunk | |
2025-03-11
| ||
01:20 | Make use of the new -[OFString intValue] check-in: 09eb96f339 user: js tags: trunk | |
Changes
Modified src/Command.mm from [07fd8b4957] to [16592a90b0].
1 2 3 4 5 6 7 8 | #import "Command.h" #include <cube.h> static OFArray<OFString *> * padArguments(OFArray<OFString *> *arguments, size_t count) { OFMutableArray<OFString *> *copy; | > | 1 2 3 4 5 6 7 8 9 | #import "Command.h" #import "OFString+Cube.h" #include <cube.h> static OFArray<OFString *> * padArguments(OFArray<OFString *> *arguments, size_t count) { OFMutableArray<OFString *> *copy; |
︙ | ︙ | |||
34 35 36 37 38 39 40 | - (int)callWithArguments:(OFArray<OFString *> *)arguments isDown:(bool)isDown { switch (_argumentsTypes) { case ARG_1INT: if (isDown) { arguments = padArguments(arguments, 2); ((void(__cdecl *)(int))_function)( | | | | | | | | | | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | - (int)callWithArguments:(OFArray<OFString *> *)arguments isDown:(bool)isDown { switch (_argumentsTypes) { case ARG_1INT: if (isDown) { arguments = padArguments(arguments, 2); ((void(__cdecl *)(int))_function)( [arguments[1] cube_intValueWithBase:0]); } break; case ARG_2INT: if (isDown) { arguments = padArguments(arguments, 3); ((void(__cdecl *)(int, int))_function)( [arguments[1] cube_intValueWithBase:0], [arguments[2] cube_intValueWithBase:0]); } break; case ARG_3INT: if (isDown) { arguments = padArguments(arguments, 4); ((void(__cdecl *)(int, int, int))_function)( [arguments[1] cube_intValueWithBase:0], [arguments[2] cube_intValueWithBase:0], [arguments[3] cube_intValueWithBase:0]); } break; case ARG_4INT: if (isDown) { arguments = padArguments(arguments, 5); ((void(__cdecl *)(int, int, int, int))_function)( [arguments[1] cube_intValueWithBase:0], [arguments[2] cube_intValueWithBase:0], [arguments[3] cube_intValueWithBase:0], [arguments[4] cube_intValueWithBase:0]); } break; case ARG_NONE: if (isDown) ((void(__cdecl *)())_function)(); break; case ARG_1STR: |
︙ | ︙ |
Modified src/MenuItem.m from [2e2fceadfe] to [2a6ad46c6d].
︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 | @throw [OFInvalidArgumentException exception]; int x, y; @try { x = _text.intValue; } @catch (OFInvalidFormatException *e) { x = 0; } | > > > | > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | @throw [OFInvalidArgumentException exception]; int x, y; @try { x = _text.intValue; } @catch (OFInvalidFormatException *e) { x = 0; } @catch (OFOutOfRangeException *e) { x = 0; } @ try { y = otherItem.text.intValue; } @catch (OFInvalidFormatException *e) { y = 0; } @catch (OFOutOfRangeException *e) { y = 0; } if (x > y) return OFOrderedAscending; if (x < y) return OFOrderedDescending; |
︙ | ︙ |
Modified src/clientgame.mm from [c71213128a] to [ec0093549c].
1 2 3 4 5 6 7 8 9 10 11 12 | // clientgame.cpp: core game related stuff #include "cube.h" #import "DynamicEntity.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); void mode(int n) { | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // clientgame.cpp: core game related stuff #include "cube.h" #import "DynamicEntity.h" #import "OFString+Cube.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); void mode(int n) { |
︙ | ︙ | |||
234 235 236 237 238 239 240 | } int sleepwait = 0; static OFString *sleepcmd = nil; void sleepf(OFString *msec, OFString *cmd) { | | | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | } int sleepwait = 0; static OFString *sleepcmd = nil; void sleepf(OFString *msec, OFString *cmd) { sleepwait = msec.cube_intValue + lastmillis; sleepcmd = cmd; } COMMANDN(sleep, sleepf, ARG_2STR) void updateworld(int millis) // main game update loop { |
︙ | ︙ |
Modified src/commands.mm from [69ee305979] to [e9b116439f].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // command.cpp: implements the parsing and execution of a tiny script language // which is largely backwards compatible with the quake console language. #include "cube.h" #include <memory> #import "Alias.h" #import "Command.h" #import "Identifier.h" #import "Variable.h" // contains ALL vars/commands/aliases static OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers; void alias(OFString *name, OFString *action) | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // command.cpp: implements the parsing and execution of a tiny script language // which is largely backwards compatible with the quake console language. #include "cube.h" #include <memory> #import "Alias.h" #import "Command.h" #import "Identifier.h" #import "OFString+Cube.h" #import "Variable.h" // contains ALL vars/commands/aliases static OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers; void alias(OFString *name, OFString *action) |
︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 | } else if ([identifier isKindOfClass:Alias.class]) return [identifier action]; } conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]); return n; } // all evaluation happens here, recursively int execute(OFString *string, bool isDown) { @autoreleasepool { std::unique_ptr<char> copy(strdup(string.UTF8String)); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | } else if ([identifier isKindOfClass:Alias.class]) return [identifier action]; } conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]); 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 int execute(OFString *string, bool isDown) { @autoreleasepool { std::unique_ptr<char> copy(strdup(string.UTF8String)); |
︙ | ︙ | |||
226 227 228 229 230 231 232 | c = [c substringFromIndex:1]; w[0] = c; } // empty statement if (c.length == 0) continue; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | c = [c substringFromIndex:1]; w[0] = c; } // empty statement if (c.length == 0) continue; val = executeIdentifier(identifiers[c], [OFArray arrayWithObjects:w count:numargs], isDown); } return val; } } // tab-completion of all identifiers |
︙ | ︙ | |||
374 375 376 377 378 379 380 | IRIByAppendingPathComponent:@"config.cfg"]; stream = [[OFIRIHandler handlerForIRI:IRI] openItemAtIRI:IRI mode:@"w"]; } @catch (id e) { return; } | < | | | | | | | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | IRIByAppendingPathComponent:@"config.cfg"]; stream = [[OFIRIHandler handlerForIRI:IRI] openItemAtIRI:IRI mode:@"w"]; } @catch (id e) { return; } [stream writeString:@"// automatically written on exit, do not modify\n" @"// delete this file to have defaults.cfg " @"overwrite these settings\n" @"// modify settings in game, or put settings in " @"autoexec.cfg to override anything\n" @"\n"]; writeclientinfo(stream); [stream writeString:@"\n"]; [identifiers enumerateKeysAndObjectsUsingBlock:^( OFString *name, __kindof Identifier *identifier, bool *stop) { if (![identifier isKindOfClass:Variable.class] || ![identifier persisted]) |
︙ | ︙ | |||
414 415 416 417 418 419 420 | [stream close]; } COMMAND(writecfg, ARG_NONE) // below the commands that implement a small imperative language. thanks to the | < | > | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | [stream close]; } COMMAND(writecfg, ARG_NONE) // below the commands that implement a small imperative language. thanks to the // semantics of () and [] expressions, any control construct can be defined // trivially. void intset(OFString *name, int v) { @autoreleasepool { alias(name, [OFString stringWithFormat:@"%d", v]); } } void ifthen(OFString *cond, OFString *thenp, OFString *elsep) { execute((![cond hasPrefix:@"0"] ? thenp : elsep)); } void loopa(OFString *times, OFString *body) { @autoreleasepool { int t = times.cube_intValue; loopi(t) { intset(@"i", i); execute(body); } } |
︙ | ︙ | |||
493 494 495 496 497 498 499 | } } void at(OFString *s_, OFString *pos) { @autoreleasepool { | | < | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | } } void at(OFString *s_, OFString *pos) { @autoreleasepool { int n = pos.cube_intValue; std::unique_ptr<char> copy(strdup(s_.UTF8String)); char *s = copy.get(); loopi(n) s += strspn(s += strcspn(s, " \0"), " "); s[strcspn(s, " \0")] = 0; concat(@(s)); } } COMMANDN(loop, loopa, ARG_2STR) |
︙ | ︙ |
Modified src/console.mm from [1408af0279] to [40d6223ddd].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // console.cpp: the console buffer, its display, and command line control #include "cube.h" #include <ctype.h> #import "KeyMapping.h" struct cline { char *cref; int outtime; }; vector<cline> conlines; | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // console.cpp: the console buffer, its display, and command line control #include "cube.h" #include <ctype.h> #import "KeyMapping.h" #import "OFString+Cube.h" struct cline { char *cref; int outtime; }; vector<cline> conlines; |
︙ | ︙ | |||
102 103 104 105 106 107 108 | void keymap(OFString *code, OFString *key, OFString *action) { if (keyMappings == nil) keyMappings = [[OFMutableArray alloc] init]; | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | void keymap(OFString *code, OFString *key, OFString *action) { if (keyMappings == nil) keyMappings = [[OFMutableArray alloc] init]; KeyMapping *mapping = [[KeyMapping alloc] initWithCode:code.cube_intValue name:key]; mapping.action = action; [keyMappings addObject:mapping]; } COMMAND(keymap, ARG_3STR) void bindkey(OFString *key, OFString *action) |
︙ | ︙ |
Modified src/editing.mm from [b565167d7b] to [76cc8ec718].
1 2 3 4 5 6 7 8 9 10 11 12 13 | // editing.cpp: most map editing commands go here, entity editing commands are // in world.cpp #include "cube.h" #import "DynamicEntity.h" bool editmode = false; // the current selection, used by almost all editing commands // invariant: all code assumes that these are kept inside MINBORD distance of // the edge of the map | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // editing.cpp: most map editing commands go here, entity editing commands are // in world.cpp #include "cube.h" #import "DynamicEntity.h" #import "OFString+Cube.h" bool editmode = false; // the current selection, used by almost all editing commands // invariant: all code assumes that these are kept inside MINBORD distance of // the edge of the map |
︙ | ︙ | |||
601 602 603 604 605 606 607 | void newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; @autoreleasepool { newentity(sel.x, sel.y, (int)player1.o.z, what, | | | | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 | void newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; @autoreleasepool { newentity(sel.x, sel.y, (int)player1.o.z, what, [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0], [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]); } } COMMANDN(select, selectpos, ARG_4INT) COMMAND(edittag, ARG_1INT) COMMAND(replace, ARG_NONE) COMMAND(archvertex, ARG_3INT) |
︙ | ︙ |
Modified src/meson.build from [ff6b55de94] to [db6c55f2bb].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | executable('client', [ 'Alias.m', 'Command.mm', 'Cube.mm', 'DynamicEntity.mm', 'Identifier.m', 'KeyMapping.m', 'MD2.mm', 'MapModelInfo.m', 'Menu.m', 'MenuItem.m', 'Projectile.m', 'ServerInfo.mm', 'Variable.mm', 'client.mm', 'clientextras.mm', 'clientgame.mm', 'clients2c.mm', | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | executable('client', [ 'Alias.m', 'Command.mm', 'Cube.mm', 'DynamicEntity.mm', 'Identifier.m', 'KeyMapping.m', 'MD2.mm', 'MapModelInfo.m', 'Menu.m', 'MenuItem.m', 'OFString+Cube.mm', 'Projectile.m', 'ServerInfo.mm', 'Variable.mm', 'client.mm', 'clientextras.mm', 'clientgame.mm', 'clients2c.mm', |
︙ | ︙ |
Modified src/renderextras.mm from [3c937d7f40] to [5d964620ef].
︙ | ︙ | |||
202 203 204 205 206 207 208 209 210 211 212 213 214 215 | void loadsky(OFString *basename) { @autoreleasepool { static OFString *lastsky = @""; if ([lastsky isEqual:basename]) return; static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn", @"up" }; int texnum = 14; loopi(6) | > > > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | void loadsky(OFString *basename) { @autoreleasepool { static OFString *lastsky = @""; basename = [basename stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; if ([lastsky isEqual:basename]) return; static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn", @"up" }; int texnum = 14; loopi(6) |
︙ | ︙ |
Modified src/rendergl.mm from [4da3c2483c] to [e315f901d3].
1 2 3 4 5 6 7 8 9 10 11 12 | // rendergl.cpp: core opengl rendering stuff #include "cube.h" #import "DynamicEntity.h" #ifdef DARWIN # define GL_COMBINE_EXT GL_COMBINE_ARB # define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB # define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB # define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB # define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // rendergl.cpp: core opengl rendering stuff #include "cube.h" #import "DynamicEntity.h" #import "OFString+Cube.h" #ifdef DARWIN # define GL_COMBINE_EXT GL_COMBINE_ARB # define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB # define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB # define GL_SOURCE1_RBG_EXT GL_SOURCE1_RGB_ARB # define GL_RGB_SCALE_EXT GL_RGB_SCALE_ARB |
︙ | ︙ | |||
193 194 195 196 197 198 199 | } COMMAND(texturereset, ARG_NONE) void texture(OFString *aframe, OFString *name) { @autoreleasepool { | | > > | > > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | } COMMAND(texturereset, ARG_NONE) void texture(OFString *aframe, OFString *name) { @autoreleasepool { int num = curtexnum++, frame = aframe.cube_intValue; if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) return; mapping[num][frame] = 1; mapname[num][frame] = [name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; } } COMMAND(texture, ARG_2STR) int lookuptexture(int tex, int *xs, int *ys) { |
︙ | ︙ |
Modified src/rendermd2.mm from [53ddda709f] to [08d6b30ba2].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // rendermd2.cpp: loader code adapted from a nehe tutorial #include "cube.h" #import "DynamicEntity.h" #import "MD2.h" #import "MapModelInfo.h" static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil; static OFMutableArray<MD2 *> *mapmodels = nil; static const int FIRSTMDL = 20; void | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // rendermd2.cpp: loader code adapted from a nehe tutorial #include "cube.h" #import "DynamicEntity.h" #import "MD2.h" #import "MapModelInfo.h" #import "OFString+Cube.h" static OFMutableDictionary<OFString *, MD2 *> *mdllookup = nil; static OFMutableArray<MD2 *> *mapmodels = nil; static const int FIRSTMDL = 20; void |
︙ | ︙ | |||
63 64 65 66 67 68 69 | } } void mapmodel( OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { | | > | | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | } } void mapmodel( OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { MD2 *m = loadmodel([name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]); m.mmi = [[MapModelInfo alloc] initWithRad:rad.cube_intValue h:h.cube_intValue zoff:zoff.cube_intValue snap:snap.cube_intValue name:m.loadname]; if (mapmodels == nil) mapmodels = [[OFMutableArray alloc] init]; [mapmodels addObject:m]; } |
︙ | ︙ |
Modified src/sound.mm from [f6d08d4aed] to [7cef1841c0].
︙ | ︙ | |||
84 85 86 87 88 89 90 91 92 93 94 95 96 97 | music(OFString *name) { if (nosound) return; stopsound(); if (soundvol && musicvol) { @autoreleasepool { OFString *path = [OFString stringWithFormat:@"packages/%@", name]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:path]; #ifdef USE_MIXER if ((mod = Mix_LoadMUS( | > > | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | music(OFString *name) { if (nosound) return; stopsound(); if (soundvol && musicvol) { @autoreleasepool { name = [name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]; OFString *path = [OFString stringWithFormat:@"packages/%@", name]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:path]; #ifdef USE_MIXER if ((mod = Mix_LoadMUS( |
︙ | ︙ | |||
144 145 146 147 148 149 150 | i++; } if (snames == nil) snames = [[OFMutableArray alloc] init]; | | > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | i++; } if (snames == nil) snames = [[OFMutableArray alloc] init]; [snames addObject:[name stringByReplacingOccurrencesOfString:@"\\" withString:@"/"]]; samples.add(NULL); return samples.length() - 1; } COMMAND(registersound, ARG_1EST) void |
︙ | ︙ |
Modified src/weapon.mm from [1d3f50a464] to [a4e8e0ad47].
1 2 3 4 5 6 7 8 9 10 11 12 | // weapon.cpp: all shooting and effects code #include "cube.h" #import "DynamicEntity.h" #import "Projectile.h" static const int MONSTERDAMAGEFACTOR = 4; static const int SGRAYS = 20; static const float SGSPREAD = 2; static OFVector3D sg[SGRAYS]; | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // weapon.cpp: all shooting and effects code #include "cube.h" #import "DynamicEntity.h" #import "OFString+Cube.h" #import "Projectile.h" static const int MONSTERDAMAGEFACTOR = 4; static const int SGRAYS = 20; static const float SGSPREAD = 2; static OFVector3D sg[SGRAYS]; |
︙ | ︙ | |||
59 60 61 62 63 64 65 | { return guns[gun].attackdelay; } void weapon(OFString *a1, OFString *a2, OFString *a3) { | | | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | { return guns[gun].attackdelay; } void weapon(OFString *a1, OFString *a2, OFString *a3) { selectgun((a1.length > 0 ? a1.cube_intValue : -1), (a2.length > 0 ? a2.cube_intValue : -1), (a3.length > 0 ? a3.cube_intValue : -1)); } COMMAND(weapon, ARG_3STR) void createrays(OFVector3D &from, OFVector3D &to) // create random spread of rays for the shotgun { |
︙ | ︙ |