Index: src/console.mm ================================================================== --- src/console.mm +++ src/console.mm @@ -5,15 +5,35 @@ #include #import "KeyMapping.h" #import "OFString+Cube.h" -struct cline { - char *cref; - int outtime; -}; -vector conlines; +@interface ConsoleLine: OFObject +@property (readonly, copy) OFString *text; +@property (readonly) int outtime; + +- (instancetype)initWithText:(OFString *)text outtime:(int)outtime; +@end + +static OFMutableArray *conlines; + +@implementation ConsoleLine +- (instancetype)initWithText:(OFString *)text outtime:(int)outtime +{ + self = [super init]; + + _text = [text copy]; + _outtime = outtime; + + return self; +} + +- (OFString *)description +{ + return _text; +} +@end const int ndraw = 5; const int WORDWRAP = 80; int conskip = 0; @@ -30,26 +50,33 @@ COMMANDN(conskip, setconskip, ARG_1INT) static void conline(OFString *sf, bool highlight) // add a line to the console buffer { - cline cl; + OFMutableString *text; + // constrain the buffer size - cl.cref = conlines.length() > 100 ? conlines.pop().cref - : (char *)calloc(_MAXDEFSTR, 1); - // for how long to keep line on screen - cl.outtime = lastmillis; - conlines.insert(0, cl); - if (highlight) { + if (conlines.count > 100) { + text = [conlines.lastObject.text mutableCopy]; + [conlines removeLastObject]; + } else + text = [[OFMutableString alloc] init]; + + if (highlight) // show line in a different colour, for chat etc. - cl.cref[0] = '\f'; - cl.cref[1] = 0; - strcat_s(cl.cref, sf.UTF8String); - } else { - strcpy_s(cl.cref, sf.UTF8String); - } - puts(cl.cref); + [text appendString:@"\f"]; + + [text appendString:sf]; + + if (conlines == nil) + conlines = [[OFMutableArray alloc] init]; + + [conlines insertObject:[[ConsoleLine alloc] initWithText:text + outtime:lastmillis] + atIndex:0]; + + puts(text.UTF8String); #ifndef OF_WINDOWS fflush(stdout); #endif } @@ -72,30 +99,33 @@ } conline(string, n != 0); } } +// render buffer taking into account time & scrolling void -renderconsole() // render buffer taking into account time & scrolling +renderconsole() { int nd = 0; - char *refs[ndraw]; - loopv(conlines) - { - if (conskip ? i >= conskip - 1 || i >= conlines.length() - ndraw - : lastmillis - conlines[i].outtime < 20000) { - refs[nd++] = conlines[i].cref; + OFString *refs[ndraw]; + + size_t i = 0; + for (ConsoleLine *conline in conlines) { + if (conskip ? i >= conskip - 1 || i >= conlines.count - ndraw + : lastmillis - conline.outtime < 20000) { + refs[nd++] = conline.text; if (nd == ndraw) break; } + + i++; } - @autoreleasepool { - loopj(nd) - { - draw_text(@(refs[j]), FONTH / 3, - (FONTH / 4 * 5) * (nd - j - 1) + FONTH / 3, 2); - } + + loopj(nd) + { + draw_text(refs[j], FONTH / 3, + (FONTH / 4 * 5) * (nd - j - 1) + FONTH / 3, 2); } } // keymap is defined externally in keymap.cfg Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -5,10 +5,12 @@ #define gamma gamma__ #include #undef gamma #include "tools.h" + +#define _MAXDEFSTR 260 @class DynamicEntity; @interface Cube: OFObject @property (class, readonly, nonatomic) Cube *sharedInstance; Index: src/savegamedemo.mm ================================================================== --- src/savegamedemo.mm +++ src/savegamedemo.mm @@ -103,13 +103,13 @@ gzwrite(f, (void *)"CUBESAVE", 8); gzputc(f, islittleendian); gzputi(SAVEGAMEVERSION); OFData *data = [player1 dataBySerializing]; gzputi(data.count); - char map[260] = { 0 }; + char map[_MAXDEFSTR] = { 0 }; memcpy(map, getclientmap().UTF8String, - min(getclientmap().UTF8StringLength, 259)); + min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1)); gzwrite(f, map, _MAXDEFSTR); gzputi(gamemode); gzputi(ents.length()); loopv(ents) gzputc(f, ents[i].spawned); gzwrite(f, data.items, data.count); @@ -161,11 +161,12 @@ if (!f) { conoutf(@"could not open %@", IRI.string); return; } - string buf; + char mapname[_MAXDEFSTR] = { 0 }; + char buf[8]; gzread(f, buf, 8); if (strncmp(buf, "CUBESAVE", 8)) goto out; if (gzgetc(f) != islittleendian) goto out; // not supporting save->load accross @@ -172,11 +173,10 @@ // incompatible architectures simpifies things // a LOT if (gzgeti() != SAVEGAMEVERSION || gzgeti() != DynamicEntity.serializedSize) goto out; - string mapname; gzread(f, mapname, _MAXDEFSTR); nextmode = gzgeti(); @autoreleasepool { // continue below once map has been loaded and client & // server have updated @@ -451,11 +451,11 @@ assert(target); int extras; // read additional client side state not present in normal // network stream - if (extras = gzget()) { + if ((extras = gzget())) { target.gunselect = gzget(); target.lastattackgun = gzget(); target.lastaction = scaletime(gzgeti()); target.gunwait = gzgeti(); target.health = gzgeti(); @@ -462,13 +462,13 @@ target.armour = gzgeti(); target.armourtype = gzget(); loopi(NUMGUNS) target.ammo[i] = gzget(); target.state = gzget(); target.lastmove = playbacktime; - if (bdamage = gzgeti()) + if ((bdamage = gzgeti())) damageblend(bdamage); - if (ddamage = gzgeti()) { + if ((ddamage = gzgeti())) { gzgetv(dorig); particle_splash(3, ddamage, 1000, dorig); } // FIXME: set more client state here } Index: src/serverbrowser.mm ================================================================== --- src/serverbrowser.mm +++ src/serverbrowser.mm @@ -38,12 +38,11 @@ @synchronized(ResolverThread.class) { if (resolverqueries.count == 0) continue; _query = resolverqueries.lastObject; - [resolverqueries - removeObjectAtIndex:resolverqueries.count - 1]; + [resolverqueries removeLastObject]; _starttime = lastmillis; } ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; enet_address_set_host(&address, _query.UTF8String); @@ -146,12 +145,11 @@ @synchronized(ResolverThread.class) { if (resolverresults.count > 0) { ResolverResult *rr = resolverresults.lastObject; *name = rr.query; *address = rr.address; - [resolverresults - removeObjectAtIndex:resolverresults.count - 1]; + [resolverresults removeLastObject]; return true; } for (size_t i = 0; i < resolverthreads.count; i++) { ResolverThread *rt = resolverthreads[i]; Index: src/serverutil.mm ================================================================== --- src/serverutil.mm +++ src/serverutil.mm @@ -45,12 +45,14 @@ void sendstring(OFString *t_, uchar *&p) { @autoreleasepool { const char *t = t_.UTF8String; - while (*t) + + for (size_t i = 0; i < _MAXDEFSTR && *t != '\0'; i++) putint(p, *t++); + putint(p, 0); } } static const OFString *modenames[] = { Index: src/tools.h ================================================================== --- src/tools.h +++ src/tools.h @@ -53,35 +53,10 @@ #ifndef OF_WINDOWS # define __cdecl # define _vsnprintf vsnprintf #endif -// easy safe strings - -#define _MAXDEFSTR 260 -typedef char string[_MAXDEFSTR]; - -inline void -strn0cpy(char *d, const char *s, size_t m) -{ - strncpy(d, s, m); - d[(m)-1] = 0; -} - -inline void -strcpy_s(char *d, const char *s) -{ - strn0cpy(d, s, _MAXDEFSTR); -} - -inline void -strcat_s(char *d, const char *s) -{ - size_t n = strlen(d); - strn0cpy(d + n, s, _MAXDEFSTR - n); -} - #define fast_f2nat(val) ((int)(val)) extern void endianswap(void *, int, int); template struct vector {