Subversion Repositories eduke32

Rev

Rev 4963 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 Plagman 1
// On-screen Display (ie. console)
2
// for the Build Engine
2456 hendricks2 3
// by Jonathon Fowler (jf@jonof.id.au)
5 Plagman 4
 
5
#include "build.h"
6
#include "osd.h"
7
#include "compat.h"
8
#include "baselayer.h"
821 terminx 9
#include "cache1d.h"
876 terminx 10
#include "pragmas.h"
1625 terminx 11
#include "scancodes.h"
1635 terminx 12
#include "crc32.h"
4387 terminx 13
#include "xxhash.h"
4660 terminx 14
#include "common.h"
4890 terminx 15
#include "editor.h"
5 Plagman 16
 
4213 helixhorne 17
static symbol_t *symbols = NULL;
5 Plagman 18
static symbol_t *addnewsymbol(const char *name);
19
static symbol_t *findsymbol(const char *name, symbol_t *startingat);
20
static symbol_t *findexactsymbol(const char *name);
21
 
1205 terminx 22
// static int32_t _validate_osdlines(void *);
5 Plagman 23
 
1205 terminx 24
static int32_t _internal_osdfunc_listsymbols(const osdfuncparm_t *);
25
static int32_t _internal_osdfunc_help(const osdfuncparm_t *);
26
static int32_t _internal_osdfunc_alias(const osdfuncparm_t *);
27
// static int32_t _internal_osdfunc_dumpbuildinfo(const osdfuncparm_t *);
28
// static int32_t _internal_osdfunc_setrendermode(const osdfuncparm_t *);
5 Plagman 29
 
1205 terminx 30
static int32_t white=-1;            // colour of white (used by default display routines)
31
static void _internal_drawosdchar(int32_t, int32_t, char, int32_t, int32_t);
3321 helixhorne 32
static void _internal_drawosdstr(int32_t, int32_t, const char *, int32_t, int32_t, int32_t);
1205 terminx 33
static void _internal_drawosdcursor(int32_t,int32_t,int32_t,int32_t);
34
static int32_t _internal_getcolumnwidth(int32_t);
35
static int32_t _internal_getrowheight(int32_t);
36
static void _internal_clearbackground(int32_t,int32_t);
37
static int32_t _internal_gettime(void);
38
static void _internal_onshowosd(int32_t);
5 Plagman 39
 
4536 terminx 40
osdmain_t *osd = NULL;
1625 terminx 41
 
1205 terminx 42
static int32_t  osdrowscur=-1;
43
static int32_t  osdscroll=0;
44
static int32_t  osdmaxrows=20;      // maximum number of lines which can fit on the screen
4821 hendricks2 45
BFILE *osdlog;      // log filehandle
46
const char* osdlogfn;
1205 terminx 47
static int32_t  keytime=0;
48
static int32_t osdscrtime = 0;
5 Plagman 49
 
50
 
4536 terminx 51
#define editlinewidth (osd->draw.cols-1-3)
5 Plagman 52
 
53
 
4536 terminx 54
static hashtable_t h_osd      = { OSDMAXSYMBOLS<<1, NULL };
4139 helixhorne 55
 
56
// Application callbacks: these are the currently effective ones.
1205 terminx 57
static void (*drawosdchar)(int32_t, int32_t, char, int32_t, int32_t) = _internal_drawosdchar;
3321 helixhorne 58
static void (*drawosdstr)(int32_t, int32_t, const char *, int32_t, int32_t, int32_t) = _internal_drawosdstr;
1205 terminx 59
static void (*drawosdcursor)(int32_t, int32_t, int32_t, int32_t) = _internal_drawosdcursor;
60
static int32_t (*getcolumnwidth)(int32_t) = _internal_getcolumnwidth;
61
static int32_t (*getrowheight)(int32_t) = _internal_getrowheight;
4139 helixhorne 62
 
1205 terminx 63
static void (*clearbackground)(int32_t,int32_t) = _internal_clearbackground;
64
static int32_t (*gettime)(void) = _internal_gettime;
65
static void (*onshowosd)(int32_t) = _internal_onshowosd;
5 Plagman 66
 
4139 helixhorne 67
// Application callbacks: these are the backed-up ones.
1205 terminx 68
static void (*_drawosdchar)(int32_t, int32_t, char, int32_t, int32_t) = _internal_drawosdchar;
3321 helixhorne 69
static void (*_drawosdstr)(int32_t, int32_t, const char *, int32_t, int32_t, int32_t) = _internal_drawosdstr;
1205 terminx 70
static void (*_drawosdcursor)(int32_t, int32_t, int32_t, int32_t) = _internal_drawosdcursor;
71
static int32_t (*_getcolumnwidth)(int32_t) = _internal_getcolumnwidth;
72
static int32_t (*_getrowheight)(int32_t) = _internal_getrowheight;
876 terminx 73
 
4536 terminx 74
static hashtable_t h_cvars      = { OSDMAXSYMBOLS<<1, NULL };
1649 helixhorne 75
int32_t m32_osd_tryscript=0;  // whether to try executing m32script on unkown command in the osd
76
 
1352 terminx 77
int32_t OSD_RegisterCvar(const cvar_t *cvar)
78
{
79
    const char *cp;
80
 
4536 terminx 81
    if (!osd)
1625 terminx 82
        OSD_Init();
1352 terminx 83
 
3350 terminx 84
    if (!cvar->name || !cvar->name[0] || !cvar->vptr)
1352 terminx 85
    {
1625 terminx 86
        OSD_Printf("OSD_RegisterCvar(): can't register null cvar\n");
1352 terminx 87
        return -1;
88
    }
89
 
90
    // check for illegal characters in name
91
    for (cp = cvar->name; *cp; cp++)
92
    {
93
        if ((cp == cvar->name) && (*cp >= '0') && (*cp <= '9'))
94
        {
95
            OSD_Printf("OSD_RegisterCvar(): first character of cvar name \"%s\" must not be a numeral\n", cvar->name);
96
            return -1;
97
        }
98
        if ((*cp < '0') ||
1357 terminx 99
                (*cp > '9' && *cp < 'A') ||
100
                (*cp > 'Z' && *cp < 'a' && *cp != '_') ||
101
                (*cp > 'z'))
1352 terminx 102
        {
103
            OSD_Printf("OSD_RegisterCvar(): illegal character in cvar name \"%s\"\n", cvar->name);
104
            return -1;
105
        }
106
    }
107
 
4536 terminx 108
    osd->cvars = (osdcvar_t *)Xrealloc(osd->cvars, (osd->numcvars + 1) * sizeof(osdcvar_t));
1657 terminx 109
 
4536 terminx 110
    hash_add(&h_cvars, cvar->name, osd->numcvars, 1);
1657 terminx 111
 
112
    switch (cvar->type & (CVAR_BOOL|CVAR_INT|CVAR_UINT|CVAR_FLOAT|CVAR_DOUBLE))
113
    {
114
    case CVAR_BOOL:
115
    case CVAR_INT:
4536 terminx 116
        osd->cvars[osd->numcvars].dval.i = *(int32_t *)cvar->vptr;
1657 terminx 117
        break;
118
    case CVAR_UINT:
4536 terminx 119
        osd->cvars[osd->numcvars].dval.uint = *(uint32_t *)cvar->vptr;
1657 terminx 120
        break;
121
    case CVAR_FLOAT:
4536 terminx 122
        osd->cvars[osd->numcvars].dval.f = *(float *)cvar->vptr;
1657 terminx 123
        break;
124
    case CVAR_DOUBLE:
4536 terminx 125
        osd->cvars[osd->numcvars].dval.d = *(double *)cvar->vptr;
1657 terminx 126
        break;
127
    }
1762 terminx 128
 
4536 terminx 129
    Bmemcpy(&osd->cvars[osd->numcvars++], cvar, sizeof(cvar_t));
1352 terminx 130
 
131
    return 0;
132
}
133
 
1657 terminx 134
static int32_t OSD_CvarModified(const osdcvar_t *cvar)
135
{
4536 terminx 136
    if (!osd)
1657 terminx 137
        return 0;
138
 
3350 terminx 139
    if (!cvar->c.vptr)
1657 terminx 140
    {
141
        OSD_Printf("OSD_CvarModified(): null cvar?!\n");
142
        return 0;
143
    }
144
 
5065 terminx 145
    int rv = 0;
146
 
147
    switch (cvar->c.type & (CVAR_BOOL|CVAR_INT|CVAR_UINT|CVAR_FLOAT|CVAR_DOUBLE|CVAR_STRING))
1657 terminx 148
    {
149
    case CVAR_BOOL:
150
    case CVAR_INT:
5065 terminx 151
        rv = (cvar->dval.i != *(int32_t *)cvar->c.vptr); break;
1657 terminx 152
    case CVAR_UINT:
5065 terminx 153
        rv = (cvar->dval.uint != *(uint32_t *)cvar->c.vptr); break;
1657 terminx 154
    case CVAR_FLOAT:
5065 terminx 155
        rv = (cvar->dval.f != *(float *)cvar->c.vptr); break;
1657 terminx 156
    case CVAR_DOUBLE:
5065 terminx 157
        rv = (cvar->dval.d != *(double *)cvar->c.vptr); break;
158
    case CVAR_STRING:
159
        rv = 1; break;
1657 terminx 160
    default:
5065 terminx 161
        EDUKE32_UNREACHABLE_SECTION(break);
1657 terminx 162
    }
5065 terminx 163
 
164
    return rv;
1657 terminx 165
}
166
 
1625 terminx 167
// color code format is as follows:
168
// ^## sets a color, where ## is the palette number
169
// ^S# sets a shade, range is 0-7 equiv to shades 0-14
170
// ^O resets formatting to defaults
171
 
1762 terminx 172
const char *OSD_StripColors(char *out, const char *in)
821 terminx 173
{
1625 terminx 174
    const char *ptr = out;
821 terminx 175
 
3727 helixhorne 176
    while (*in)
821 terminx 177
    {
929 terminx 178
        if (*in == '^' && isdigit(*(in+1)))
821 terminx 179
        {
929 terminx 180
            in += 2;
181
            if (isdigit(*in))
182
                in++;
821 terminx 183
            continue;
184
        }
929 terminx 185
        if (*in == '^' && (Btoupper(*(in+1)) == 'S') && isdigit(*(in+2)))
867 terminx 186
        {
929 terminx 187
            in += 3;
869 terminx 188
            continue;
189
        }
929 terminx 190
        if (*in == '^' && (Btoupper(*(in+1)) == 'O'))
869 terminx 191
        {
929 terminx 192
            in += 2;
867 terminx 193
            continue;
194
        }
1657 terminx 195
        *(out++) = *(in++);
1017 terminx 196
    }
1015 terminx 197
 
929 terminx 198
    *out = '\0';
3727 helixhorne 199
    return ptr;
821 terminx 200
}
201
 
1205 terminx 202
int32_t OSD_Exec(const char *szScript)
821 terminx 203
{
4660 terminx 204
    int32_t i, len, err = 0;
205
    char *buf = NULL, *cp;
821 terminx 206
 
4660 terminx 207
 
208
    if ((i = kopen4load(szScript, 0)) == -1) err = 1;
209
    if (!err && (len = kfilelength(i)) <= 0) err = 2; // blank file
210
    if (!err && (buf = (char *)Xmalloc(len + 1)) == NULL) err = 3;
211
 
4678 terminx 212
    if (!err || err == 3)
213
        OSD_Printf("Executing \"%s\"\n", szScript);
214
 
4660 terminx 215
    if (err || kread(i, buf, len) != len)
821 terminx 216
    {
4678 terminx 217
        if (!err || err == 3) // no error message for blank file
4660 terminx 218
            OSD_Printf("Error executing \"%s\"!\n", szScript);
219
        if (i != -1) kclose(i);
220
        if (buf != NULL) Bfree(buf);
221
        return 1;
222
    }
821 terminx 223
 
4660 terminx 224
    osd->execdepth++;
225
 
226
    buf[len] = 0;
227
    cp = strtok(buf, "\r\n");
228
 
229
    while (cp != NULL)
230
    {
231
        OSD_Dispatch(cp);
232
        cp = strtok(NULL, "\r\n");
821 terminx 233
    }
4660 terminx 234
 
235
    osd->execdepth--;
236
    kclose(i);
237
    Bfree(buf);
238
    return 0;
821 terminx 239
}
240
 
1205 terminx 241
int32_t OSD_ParsingScript(void)
891 terminx 242
{
4536 terminx 243
    return osd->execdepth;
891 terminx 244
}
245
 
1205 terminx 246
int32_t OSD_OSDKey(void)
891 terminx 247
{
4536 terminx 248
    return osd->keycode;
891 terminx 249
}
250
 
1205 terminx 251
int32_t OSD_GetCols(void)
987 terminx 252
{
4536 terminx 253
    return osd->draw.cols;
987 terminx 254
}
255
 
1644 helixhorne 256
int32_t OSD_IsMoving(void)
257
{
4536 terminx 258
    return (osdrowscur!=-1 && osdrowscur!=osd->draw.rows);
1644 helixhorne 259
}
260
 
1901 helixhorne 261
int32_t OSD_GetRowsCur(void)
262
{
263
    return osdrowscur;
264
}
265
 
1205 terminx 266
int32_t OSD_GetTextMode(void)
891 terminx 267
{
4536 terminx 268
    return osd->draw.mode;
891 terminx 269
}
270
 
4136 helixhorne 271
void OSD_GetShadePal(const char *ch, int32_t *shadeptr, int32_t *palptr)
272
{
4536 terminx 273
    // Use format buffer when 'ch' falls inside osd->text.buf[] bounds (well,
4136 helixhorne 274
    // almost).
275
    // TODO: when is this false?
4536 terminx 276
    if (ch > osd->text.buf && ch < osd->text.buf + OSDBUFFERSIZE)
4136 helixhorne 277
    {
4536 terminx 278
        *shadeptr = (osd->text.fmt[ch-osd->text.buf] & ~0x1F) >> 4;
279
        *palptr = osd->text.fmt[ch-osd->text.buf] & ~0xE0;
4136 helixhorne 280
    }
281
}
282
 
4139 helixhorne 283
// XXX: well, converting function pointers to "data pointers" (void *) is
284
// undefined behavior. See
285
//  http://blog.frama-c.com/index.php?post/2013/08/24/Function-pointers-in-C
286
// Then again, my GCC just crashed (any kept on crashing until after a reboot!)
287
// when I tried to rewrite this into something different.
3321 helixhorne 288
static inline void swapptr(void *a, void *b)
289
{
290
        intptr_t t = *(intptr_t*)a;
291
        *(intptr_t*)a = *(intptr_t*)b;
292
        *(intptr_t*)b = t;
293
}
294
 
4536 terminx 295
static inline void swaposdptrs(void)
296
{
297
    swapptr(&_drawosdchar, &drawosdchar);
298
    swapptr(&_drawosdstr, &drawosdstr);
299
    swapptr(&_drawosdcursor, &drawosdcursor);
300
    swapptr(&_getcolumnwidth, &getcolumnwidth);
301
    swapptr(&_getrowheight, &getrowheight);
302
}
303
 
1205 terminx 304
void OSD_SetTextMode(int32_t mode)
891 terminx 305
{
4536 terminx 306
    osd->draw.mode = (mode != 0);
3823 helixhorne 307
 
4536 terminx 308
    if (osd->draw.mode && drawosdchar != _internal_drawosdchar)
309
            swaposdptrs();
310
    else if (!osd->draw.mode && drawosdchar == _internal_drawosdchar)
311
        swaposdptrs();
3823 helixhorne 312
 
313
    if (in3dmode())
891 terminx 314
        OSD_ResizeDisplay(xdim, ydim);
315
}
316
 
1205 terminx 317
static int32_t _internal_osdfunc_exec(const osdfuncparm_t *parm)
821 terminx 318
{
319
    char fn[BMAX_PATH];
320
 
321
    if (parm->numparms != 1) return OSDCMD_SHOWHELP;
322
    Bstrcpy(fn,parm->parms[0]);
323
 
324
    if (OSD_Exec(fn))
325
    {
909 terminx 326
        OSD_Printf(OSD_ERROR "exec: file \"%s\" not found.\n", fn);
821 terminx 327
        return OSDCMD_OK;
328
    }
329
    return OSDCMD_OK;
330
}
331
 
1635 terminx 332
static int32_t _internal_osdfunc_echo(const osdfuncparm_t *parm)
333
{
4660 terminx 334
    OSD_Printf("%s\n", parm->raw + 5);
1635 terminx 335
 
336
    return OSDCMD_OK;
337
}
338
 
339
static int32_t _internal_osdfunc_fileinfo(const osdfuncparm_t *parm)
340
{
4638 terminx 341
    uint32_t crc = 0, length;
1635 terminx 342
    int32_t i,j;
343
    char buf[256];
4387 terminx 344
    void *xxh;
345
    uint32_t xxhash;
346
    int32_t crctime, xxhtime;
1635 terminx 347
 
348
    if (parm->numparms != 1) return OSDCMD_SHOWHELP;
349
 
350
    if ((i = kopen4load((char *)parm->parms[0],0)) < 0)
351
    {
352
        OSD_Printf("fileinfo: File \"%s\" not found.\n", parm->parms[0]);
353
        return OSDCMD_OK;
354
    }
355
 
356
    length = kfilelength(i);
357
 
4387 terminx 358
    crctime = getticks();
1635 terminx 359
    do
360
    {
361
        j = kread(i,buf,256);
4642 terminx 362
        crc = Bcrc32((uint8_t *)buf,j,crc);
1635 terminx 363
    }
364
    while (j == 256);
4387 terminx 365
    crctime = getticks() - crctime;
1635 terminx 366
 
4387 terminx 367
    klseek(i, 0, BSEEK_SET);
368
 
369
    xxhtime = getticks();
370
    xxh = XXH32_init(0x1337);
371
    do
372
    {
373
        j = kread(i, buf, 256);
374
        XXH32_update(xxh, (uint8_t *) buf, j);
375
    }
376
    while (j == 256);
377
    xxhash = XXH32_digest(xxh);
378
    xxhtime = getticks() - xxhtime;
379
 
1635 terminx 380
    kclose(i);
381
 
382
    OSD_Printf("fileinfo: %s\n"
1762 terminx 383
               "  File size: %d\n"
4387 terminx 384
               "  CRC-32:    %08X (%g sec)\n"
385
               "  xxHash:    %08X (%g sec)\n",
386
               parm->parms[0], length,
387
               crc, (double)crctime/gettimerfreq(),
388
               xxhash, (double)xxhtime/gettimerfreq());
1635 terminx 389
 
390
    return OSDCMD_OK;
391
}
392
 
1205 terminx 393
static void _internal_drawosdchar(int32_t x, int32_t y, char ch, int32_t shade, int32_t pal)
5 Plagman 394
{
109 terminx 395
    char st[2] = { 0,0 };
5 Plagman 396
 
655 terminx 397
    UNREFERENCED_PARAMETER(shade);
398
    UNREFERENCED_PARAMETER(pal);
399
 
109 terminx 400
    st[0] = ch;
5 Plagman 401
 
109 terminx 402
    printext256(4+(x<<3),4+(y<<3), white, -1, st, 0);
5 Plagman 403
}
404
 
3321 helixhorne 405
static void _internal_drawosdstr(int32_t x, int32_t y, const char *ch, int32_t len, int32_t shade, int32_t pal)
5 Plagman 406
{
109 terminx 407
    char st[1024];
5 Plagman 408
 
655 terminx 409
    UNREFERENCED_PARAMETER(shade);
410
 
109 terminx 411
    if (len>1023) len=1023;
1425 terminx 412
    Bmemcpy(st,ch,len);
109 terminx 413
    st[len]=0;
5 Plagman 414
 
4137 helixhorne 415
    OSD_GetShadePal(ch, &shade, &pal);
416
 
417
    {
418
        int32_t colidx = white >= 0 ? palookup[(uint8_t)pal][white] : white;
419
        printext256(4+(x<<3),4+(y<<3), colidx, -1, st, 0);
420
    }
5 Plagman 421
}
422
 
1205 terminx 423
static void _internal_drawosdcursor(int32_t x, int32_t y, int32_t type, int32_t lastkeypress)
5 Plagman 424
{
109 terminx 425
    char st[2] = { '_',0 };
5 Plagman 426
 
655 terminx 427
    UNREFERENCED_PARAMETER(lastkeypress);
428
 
109 terminx 429
    if (type) st[0] = '#';
5 Plagman 430
 
1625 terminx 431
    if (white > -1)
584 terminx 432
    {
1625 terminx 433
        printext256(4+(x<<3),4+(y<<3)+2, white, -1, st, 0);
434
        return;
435
    }
436
 
437
    {
4137 helixhorne 438
        int32_t i, k;
439
        // Find the palette index closest to Duke3D's brightest blue
440
        // "foreground" color.  (Index 79, or the last column of the 5th row,
441
        // if the palette is laid out in a 16x16 pattern.)
442
        k = INT32_MAX;
1229 terminx 443
        for (i=0; i<256; i++)
109 terminx 444
        {
4137 helixhorne 445
            int32_t j =
446
                klabs(curpalette[i].r - 4*47) +
447
                klabs(curpalette[i].g - 4*55) +
448
                klabs(curpalette[i].b - 4*63);
449
            if (j < k) { k = j; white = i; }
109 terminx 450
        }
451
    }
5 Plagman 452
 
453
}
454
 
1205 terminx 455
static int32_t _internal_getcolumnwidth(int32_t w)
5 Plagman 456
{
109 terminx 457
    return w/8 - 1;
5 Plagman 458
}
459
 
1205 terminx 460
static int32_t _internal_getrowheight(int32_t w)
5 Plagman 461
{
109 terminx 462
    return w/8;
5 Plagman 463
}
464
 
1205 terminx 465
static void _internal_clearbackground(int32_t cols, int32_t rows)
5 Plagman 466
{
655 terminx 467
    UNREFERENCED_PARAMETER(cols);
468
    UNREFERENCED_PARAMETER(rows);
5 Plagman 469
}
470
 
1205 terminx 471
static int32_t _internal_gettime(void)
5 Plagman 472
{
109 terminx 473
    return 0;
5 Plagman 474
}
475
 
1205 terminx 476
static void _internal_onshowosd(int32_t a)
5 Plagman 477
{
655 terminx 478
    UNREFERENCED_PARAMETER(a);
5 Plagman 479
}
480
 
481
////////////////////////////
482
 
1205 terminx 483
static int32_t _internal_osdfunc_alias(const osdfuncparm_t *parm)
817 terminx 484
{
485
    symbol_t *i;
486
 
487
    if (parm->numparms < 1)
488
    {
1205 terminx 489
        int32_t j = 0;
817 terminx 490
        OSD_Printf("Alias listing:\n");
491
        for (i=symbols; i!=NULL; i=i->next)
1625 terminx 492
            if (i->func == OSD_ALIAS)
833 terminx 493
            {
494
                j++;
821 terminx 495
                OSD_Printf("     %s \"%s\"\n", i->name, i->help);
833 terminx 496
            }
497
        if (j == 0)
498
            OSD_Printf("No aliases found.\n");
817 terminx 499
        return OSDCMD_OK;
500
    }
501
 
818 terminx 502
    for (i=symbols; i!=NULL; i=i->next)
817 terminx 503
    {
819 terminx 504
        if (!Bstrcasecmp(parm->parms[0],i->name))
818 terminx 505
        {
819 terminx 506
            if (parm->numparms < 2)
818 terminx 507
            {
1625 terminx 508
                if (i->func == OSD_ALIAS)
818 terminx 509
                    OSD_Printf("alias %s \"%s\"\n", i->name, i->help);
510
                else OSD_Printf("%s is a function, not an alias\n",i->name);
819 terminx 511
                return OSDCMD_OK;
818 terminx 512
            }
1857 terminx 513
 
1625 terminx 514
            if (i->func != OSD_ALIAS && i->func != OSD_UNALIASED)
819 terminx 515
            {
516
                OSD_Printf("Cannot override function \"%s\" with alias\n",i->name);
517
                return OSDCMD_OK;
518
            }
818 terminx 519
        }
817 terminx 520
    }
521
 
4491 helixhorne 522
    OSD_RegisterFunction(Xstrdup(parm->parms[0]), Xstrdup(parm->parms[1]), OSD_ALIAS);
4536 terminx 523
 
524
    if (!osd->execdepth)
821 terminx 525
        OSD_Printf("%s\n",parm->raw);
4536 terminx 526
 
817 terminx 527
    return OSDCMD_OK;
528
}
529
 
1205 terminx 530
static int32_t _internal_osdfunc_unalias(const osdfuncparm_t *parm)
820 terminx 531
{
532
    symbol_t *i;
533
 
534
    if (parm->numparms < 1)
535
        return OSDCMD_SHOWHELP;
536
 
537
    for (i=symbols; i!=NULL; i=i->next)
538
    {
539
        if (!Bstrcasecmp(parm->parms[0],i->name))
540
        {
541
            if (parm->numparms < 2)
542
            {
1625 terminx 543
                if (i->func == OSD_ALIAS)
820 terminx 544
                {
821 terminx 545
                    OSD_Printf("Removed alias %s (\"%s\")\n", i->name, i->help);
1625 terminx 546
                    i->func = OSD_UNALIASED;
820 terminx 547
                }
548
                else OSD_Printf("Invalid alias %s\n",i->name);
549
                return OSDCMD_OK;
550
            }
551
        }
552
    }
553
    OSD_Printf("Invalid alias %s\n",parm->parms[0]);
554
    return OSDCMD_OK;
555
}
556
 
1205 terminx 557
static int32_t _internal_osdfunc_listsymbols(const osdfuncparm_t *parm)
5 Plagman 558
{
109 terminx 559
    symbol_t *i;
1205 terminx 560
    int32_t maxwidth = 0;
5 Plagman 561
 
3990 terminx 562
    if (parm->numparms > 1)
563
        return OSDCMD_SHOWHELP;
655 terminx 564
 
109 terminx 565
    for (i=symbols; i!=NULL; i=i->next)
1625 terminx 566
        if (i->func != OSD_UNALIASED)
821 terminx 567
            maxwidth = max((unsigned)maxwidth,Bstrlen(i->name));
109 terminx 568
 
821 terminx 569
    if (maxwidth > 0)
570
    {
1205 terminx 571
        int32_t x = 0, count = 0;
821 terminx 572
        maxwidth += 3;
3990 terminx 573
 
574
        if (parm->numparms > 0)
575
            OSD_Printf(OSDTEXT_RED "Symbol listing for %s:\n", parm->parms[0]);
576
        else
577
            OSD_Printf(OSDTEXT_RED "Symbol listing:\n");
578
 
821 terminx 579
        for (i=symbols; i!=NULL; i=i->next)
580
        {
3990 terminx 581
            if (i->func == OSD_UNALIASED || (parm->numparms == 1 && Bstrncmp(parm->parms[0], i->name, Bstrlen(parm->parms[0]))))
1857 terminx 582
                continue;
583
 
821 terminx 584
            {
1657 terminx 585
                int32_t j = hash_find(&h_cvars, i->name);
586
 
4536 terminx 587
                if (j != -1 && OSD_CvarModified(&osd->cvars[j]))
1657 terminx 588
                {
589
                    OSD_Printf(OSDTEXT_RED "*");
590
                    OSD_Printf("%-*s",maxwidth-1,i->name);
591
                }
592
                else OSD_Printf("%-*s",maxwidth,i->name);
593
 
821 terminx 594
                x += maxwidth;
922 terminx 595
                count++;
821 terminx 596
            }
1857 terminx 597
 
4536 terminx 598
            if (x > osd->draw.cols - maxwidth)
821 terminx 599
            {
600
                x = 0;
601
                OSD_Printf("\n");
602
            }
603
        }
922 terminx 604
        if (x) OSD_Printf("\n");
605
        OSD_Printf(OSDTEXT_RED "Found %d symbols\n",count);
821 terminx 606
    }
109 terminx 607
    return OSDCMD_OK;
5 Plagman 608
}
609
 
1205 terminx 610
static int32_t _internal_osdfunc_help(const osdfuncparm_t *parm)
5 Plagman 611
{
109 terminx 612
    symbol_t *symb;
5 Plagman 613
 
4536 terminx 614
    if (parm->numparms != 1)
615
        return OSDCMD_SHOWHELP;
616
 
109 terminx 617
    symb = findexactsymbol(parm->parms[0]);
4536 terminx 618
 
584 terminx 619
    if (!symb)
1762 terminx 620
        OSD_Printf("Error: no help for undefined symbol \"%s\"\n", parm->parms[0]);
584 terminx 621
    else
109 terminx 622
        OSD_Printf("%s\n", symb->help);
623
 
624
    return OSDCMD_OK;
5 Plagman 625
}
626
 
1205 terminx 627
static int32_t _internal_osdfunc_clear(const osdfuncparm_t *parm)
443 terminx 628
{
4536 terminx 629
    osdtext_t *t = &osd->text;
655 terminx 630
    UNREFERENCED_PARAMETER(parm);
4536 terminx 631
 
632
    Bmemset(t->buf, 0, OSDBUFFERSIZE);
633
    Bmemset(t->fmt, osd->draw.textpal + (osd->draw.textshade<<5), OSDBUFFERSIZE);
634
    t->lines = 1;
635
 
443 terminx 636
    return OSDCMD_OK;
637
}
5 Plagman 638
 
1205 terminx 639
static int32_t _internal_osdfunc_history(const osdfuncparm_t *parm)
842 terminx 640
{
1205 terminx 641
    int32_t i, j = 0;
4536 terminx 642
    osdhist_t *h = &osd->history;
842 terminx 643
    UNREFERENCED_PARAMETER(parm);
4536 terminx 644
 
989 terminx 645
    OSD_Printf(OSDTEXT_RED "Command history:\n");
4536 terminx 646
 
647
    for (i=osd->history.maxlines-1; i>=0; i--)
648
        if (h->buf[i])
649
            OSD_Printf("%4d \"%s\"\n", h->total - h->lines + (++j), h->buf[i]);
650
 
842 terminx 651
    return OSDCMD_OK;
652
}
653
 
5 Plagman 654
////////////////////////////
655
 
656
 
657
//
658
// OSD_Cleanup() -- Cleans up the on-screen display
659
//
660
void OSD_Cleanup(void)
661
{
109 terminx 662
    symbol_t *s;
4536 terminx 663
    int32_t i;
5 Plagman 664
 
1625 terminx 665
    hash_free(&h_osd);
666
    hash_free(&h_cvars);
1025 terminx 667
 
584 terminx 668
    for (; symbols; symbols=s)
669
    {
109 terminx 670
        s=symbols->next;
671
        Bfree(symbols);
672
    }
5 Plagman 673
 
4536 terminx 674
    MAYBE_FCLOSE_AND_NULL(osdlog);
675
    DO_FREE_AND_NULL(osd->cvars);
676
    DO_FREE_AND_NULL(osd->editor.buf);
677
    for (i=0; i<OSDMAXHISTORYDEPTH; i++)
678
        DO_FREE_AND_NULL(osd->history.buf[i]);
679
    DO_FREE_AND_NULL(osd->text.buf);
680
    DO_FREE_AND_NULL(osd->text.fmt);
681
    DO_FREE_AND_NULL(osd);
5 Plagman 682
}
683
 
684
 
1357 terminx 685
static int32_t osdcmd_cvar_set_osd(const osdfuncparm_t *parm)
686
{
687
    int32_t r = osdcmd_cvar_set(parm);
688
 
689
    if (r == OSDCMD_OK)
690
    {
691
        if (!Bstrcasecmp(parm->name, "osdrows"))
692
        {
4536 terminx 693
            if (osd->draw.rows > osdmaxrows) osd->draw.rows = osdmaxrows;
694
            if (osdrowscur!=-1) osdrowscur = osd->draw.rows;
1357 terminx 695
            return r;
696
        }
697
        else if (!Bstrcasecmp(parm->name, "osdtextmode"))
698
        {
4536 terminx 699
            OSD_SetTextMode(osd->draw.mode);
1357 terminx 700
            return r;
701
        }
4536 terminx 702
        else if (!Bstrcasecmp(parm->name, "osdhistorydepth"))
703
        {
704
            int32_t i;
705
 
706
            for (i=OSDMAXHISTORYDEPTH-1; i>=osd->history.maxlines; i--)
707
                DO_FREE_AND_NULL(osd->history.buf[i]);
708
 
709
            return r;
710
        }
1357 terminx 711
    }
712
    return r;
713
}
714
 
1657 terminx 715
static int32_t _internal_osdfunc_toggle(const osdfuncparm_t *parm)
716
{
717
    int32_t i;
718
 
719
    if (parm->numparms != 1) return OSDCMD_SHOWHELP;
720
 
721
    i = hash_find(&h_cvars, parm->parms[0]);
722
 
723
    if (i == -1)
4536 terminx 724
        for (i = osd->numcvars-1; i >= 0; i--)
725
            if (!Bstrcasecmp(parm->parms[0], osd->cvars[i].c.name)) break;
1657 terminx 726
 
4536 terminx 727
    if (i == -1 || (osd->cvars[i].c.type & CVAR_BOOL) != CVAR_BOOL)
1657 terminx 728
    {
729
        OSD_Printf("Bad cvar name or cvar not boolean\n");
730
        return OSDCMD_OK;
731
    }
732
 
4536 terminx 733
    *(int32_t *)osd->cvars[i].c.vptr = 1 - *(int32_t *)osd->cvars[i].c.vptr;
1657 terminx 734
    return OSDCMD_OK;
735
}
736
 
5 Plagman 737
//
627 terminx 738
// OSD_Init() -- Initializes the on-screen display
5 Plagman 739
//
740
void OSD_Init(void)
741
{
1357 terminx 742
    uint32_t i;
743
 
4536 terminx 744
    osd = (osdmain_t *)Bcalloc(1, sizeof(osdmain_t));
1658 terminx 745
 
4536 terminx 746
    mutex_init(&osd->mutex);
1025 terminx 747
 
4536 terminx 748
    if (!osd->keycode) osd->keycode = sc_Tilde;
1025 terminx 749
 
4536 terminx 750
    osd->text.buf = (char *) Bmalloc(OSDBUFFERSIZE);
751
    osd->text.fmt = (char *) Bmalloc(OSDBUFFERSIZE);
752
    osd->editor.buf = (char *) Bmalloc(OSDEDITLENGTH);
753
    osd->editor.tmp = (char *) Bmalloc(OSDEDITLENGTH);
754
 
755
    Bmemset(osd->text.buf, asc_Space, OSDBUFFERSIZE);
756
    Bmemset(osd->text.fmt, osd->draw.textpal + (osd->draw.textshade<<5), OSDBUFFERSIZE);
757
    Bmemset(osd->symbptrs, 0, sizeof(osd->symbptrs));
758
 
759
    osd->numsymbols = osd->numcvars = 0;
760
    osd->text.lines = 1;
761
    osd->text.maxlines = OSDDEFAULTMAXLINES; // overwritten later
762
    osd->draw.rows = OSDDEFAULTROWS;
763
    osd->draw.cols = OSDDEFAULTCOLS;
764
    osd->log.cutoff = OSDLOGCUTOFF;
765
    osd->history.maxlines = OSDMINHISTORYDEPTH;
766
 
1625 terminx 767
    hash_init(&h_osd);
768
    hash_init(&h_cvars);
1025 terminx 769
 
1357 terminx 770
    {
4536 terminx 771
        cvar_t cvars_osd [] =
772
        {
773
            { "osdeditpal", "sets the palette of the OSD input text", (void *) &osd->draw.editpal, CVAR_INT, 0, MAXPALOOKUPS-1 },
774
            { "osdpromptpal", "sets the palette of the OSD prompt", (void *) &osd->draw.promptpal, CVAR_INT, 0, MAXPALOOKUPS-1 },
775
            { "osdtextpal", "sets the palette of the OSD text", (void *) &osd->draw.textpal, CVAR_INT, 0, MAXPALOOKUPS-1 },
776
            { "osdeditshade", "sets the shade of the OSD input text", (void *) &osd->draw.editshade, CVAR_INT, 0, 7 },
777
            { "osdtextshade", "sets the shade of the OSD text", (void *) &osd->draw.textshade, CVAR_INT, 0, 7 },
778
            { "osdpromptshade", "sets the shade of the OSD prompt", (void *) &osd->draw.promptshade, CVAR_INT, INT8_MIN, INT8_MAX },
779
            { "osdrows", "sets the number of visible lines of the OSD", (void *) &osd->draw.rows, CVAR_INT|CVAR_FUNCPTR, 1, MAXPALOOKUPS-1 },
780
            { "osdtextmode", "set OSD text mode (0:graphical, 1:fast)", (void *) &osd->draw.mode, CVAR_BOOL|CVAR_FUNCPTR, 0, 1 },
781
            { "osdlogcutoff", "sets the maximal line count of the log file", (void *) &osd->log.cutoff, CVAR_INT, 0, 262144 },
782
            { "osdhistorydepth", "sets the history depth, in lines", (void *) &osd->history.maxlines, CVAR_INT|CVAR_FUNCPTR, OSDMINHISTORYDEPTH, OSDMAXHISTORYDEPTH },
783
        };
1625 terminx 784
 
4536 terminx 785
        for (i=0; i<ARRAY_SIZE(cvars_osd); i++)
786
        {
787
            if (OSD_RegisterCvar(&cvars_osd[i]))
788
                continue;
789
 
790
            OSD_RegisterFunction(cvars_osd[i].name, cvars_osd[i].desc,
791
                cvars_osd[i].type & CVAR_FUNCPTR ? osdcmd_cvar_set_osd : osdcmd_cvar_set);
792
        }
1357 terminx 793
    }
5 Plagman 794
 
847 terminx 795
    OSD_RegisterFunction("alias","alias: creates an alias for calling multiple commands",_internal_osdfunc_alias);
796
    OSD_RegisterFunction("clear","clear: clears the console text buffer",_internal_osdfunc_clear);
1635 terminx 797
    OSD_RegisterFunction("echo","echo [text]: echoes text to the console", _internal_osdfunc_echo);
847 terminx 798
    OSD_RegisterFunction("exec","exec <scriptfile>: executes a script", _internal_osdfunc_exec);
1635 terminx 799
    OSD_RegisterFunction("fileinfo","fileinfo <file>: gets a file's information", _internal_osdfunc_fileinfo);
847 terminx 800
    OSD_RegisterFunction("help","help: displays help for the specified cvar or command; \"listsymbols\" to show all commands",_internal_osdfunc_help);
801
    OSD_RegisterFunction("history","history: displays the console command history",_internal_osdfunc_history);
1635 terminx 802
    OSD_RegisterFunction("listsymbols","listsymbols: lists all registered functions, cvars and aliases",_internal_osdfunc_listsymbols);
1657 terminx 803
    OSD_RegisterFunction("toggle","toggle: toggles the value of a boolean cvar",_internal_osdfunc_toggle);
1625 terminx 804
    OSD_RegisterFunction("unalias","unalias: removes a command alias",_internal_osdfunc_unalias);
5 Plagman 805
 
4536 terminx 806
//    atexit(OSD_Cleanup);
5 Plagman 807
}
808
 
809
 
810
//
811
// OSD_SetLogFile() -- Sets the text file where printed text should be echoed
812
//
2796 helixhorne 813
void OSD_SetLogFile(const char *fn)
5 Plagman 814
{
4660 terminx 815
#ifdef DEBUGGINGAIDS
816
    const int bufmode = _IONBF;
817
#else
818
    const int bufmode = _IOLBF;
819
#endif
820
 
4718 terminx 821
    MAYBE_FCLOSE_AND_NULL(osdlog);
4821 hendricks2 822
    osdlogfn = NULL;
1762 terminx 823
 
4718 terminx 824
    if (!fn)
825
        return;
4660 terminx 826
 
4718 terminx 827
    osdlog = Bfopen(fn, "w");
828
 
4660 terminx 829
    if (osdlog)
4821 hendricks2 830
    {
4718 terminx 831
        setvbuf(osdlog, (char *)NULL, bufmode, BUFSIZ);
4821 hendricks2 832
        osdlogfn = fn;
833
    }
5 Plagman 834
}
835
 
836
 
837
//
838
// OSD_SetFunctions() -- Sets some callbacks which the OSD uses to understand its world
839
//
840
void OSD_SetFunctions(
1205 terminx 841
    void (*drawchar)(int32_t,int32_t,char,int32_t,int32_t),
3321 helixhorne 842
    void (*drawstr)(int32_t,int32_t,const char *,int32_t,int32_t,int32_t),
1205 terminx 843
    void (*drawcursor)(int32_t,int32_t,int32_t,int32_t),
844
    int32_t (*colwidth)(int32_t),
845
    int32_t (*rowheight)(int32_t),
846
    void (*clearbg)(int32_t,int32_t),
847
    int32_t (*gtime)(void),
848
    void (*showosd)(int32_t)
109 terminx 849
)
5 Plagman 850
{
4536 terminx 851
    drawosdchar = drawchar ? drawchar : _internal_drawosdchar;
852
    drawosdstr = drawstr ? drawstr : _internal_drawosdstr;
853
    drawosdcursor = drawcursor ? drawcursor : _internal_drawosdcursor;
854
    getcolumnwidth = colwidth ? colwidth : _internal_getcolumnwidth;
855
    getrowheight = rowheight ? rowheight : _internal_getrowheight;
856
    clearbackground = clearbg ? clearbg : _internal_clearbackground;
857
    gettime = gtime ? gtime : _internal_gettime;
858
    onshowosd = showosd ? showosd : _internal_onshowosd;
5 Plagman 859
}
860
 
861
 
862
//
863
// OSD_SetParameters() -- Sets the parameters for presenting the text
864
//
865
void OSD_SetParameters(
1205 terminx 866
    int32_t promptshade, int32_t promptpal,
867
    int32_t editshade, int32_t editpal,
868
    int32_t textshade, int32_t textpal
109 terminx 869
)
5 Plagman 870
{
4536 terminx 871
    osd->draw.promptshade = promptshade;
872
    osd->draw.promptpal   = promptpal;
873
    osd->draw.editshade   = editshade;
874
    osd->draw.editpal     = editpal;
875
    osd->draw.textshade   = textshade;
876
    osd->draw.textpal     = textpal;
5 Plagman 877
}
878
 
879
 
880
//
881
// OSD_CaptureKey() -- Sets the scancode for the key which activates the onscreen display
882
//
1205 terminx 883
void OSD_CaptureKey(int32_t sc)
5 Plagman 884
{
4536 terminx 885
    osd->keycode = sc;
5 Plagman 886
}
887
 
888
//
828 terminx 889
// OSD_FindDiffPoint() -- Finds the length of the longest common prefix of 2 strings, stolen from ZDoom
890
//
1205 terminx 891
static int32_t OSD_FindDiffPoint(const char *str1, const char *str2)
830 terminx 892
{
1205 terminx 893
    int32_t i;
830 terminx 894
 
895
    for (i = 0; Btolower(str1[i]) == Btolower(str2[i]); i++)
896
        if (str1[i] == 0 || str2[i] == 0)
897
            break;
898
 
899
    return i;
900
}
901
 
845 terminx 902
static void OSD_HistoryPrev(void)
903
{
4536 terminx 904
    if (osd->history.pos >= osd->history.lines-1) return;
847 terminx 905
 
4536 terminx 906
    Bmemcpy(osd->editor.buf, osd->history.buf[++osd->history.pos], OSDEDITLENGTH);
1625 terminx 907
 
4536 terminx 908
    osd->editor.pos = 0;
909
    while (osd->editor.buf[osd->editor.pos]) osd->editor.pos++;
910
    osd->editor.len = osd->editor.pos;
1625 terminx 911
 
4536 terminx 912
    if (osd->editor.pos<osd->editor.start)
845 terminx 913
    {
4536 terminx 914
        osd->editor.end = osd->editor.pos;
915
        osd->editor.start = osd->editor.end-editlinewidth;
845 terminx 916
 
4536 terminx 917
        if (osd->editor.start<0)
1625 terminx 918
        {
4536 terminx 919
            osd->editor.end-=osd->editor.start;
920
            osd->editor.start=0;
1625 terminx 921
        }
845 terminx 922
    }
4536 terminx 923
    else if (osd->editor.pos>=osd->editor.end)
1625 terminx 924
    {
4536 terminx 925
        osd->editor.start+=(osd->editor.pos-osd->editor.end);
926
        osd->editor.end+=(osd->editor.pos-osd->editor.end);
1625 terminx 927
    }
845 terminx 928
}
929
 
930
static void OSD_HistoryNext(void)
931
{
4536 terminx 932
    if (osd->history.pos < 0) return;
847 terminx 933
 
4536 terminx 934
    if (osd->history.pos == 0)
845 terminx 935
    {
4536 terminx 936
        osd->editor.len=0;
937
        osd->editor.pos=0;
938
        osd->editor.start=0;
939
        osd->editor.end=editlinewidth;
940
        osd->history.pos = -1;
847 terminx 941
        return;
942
    }
943
 
4536 terminx 944
    Bmemcpy(osd->editor.buf, osd->history.buf[--osd->history.pos], OSDEDITLENGTH);
1625 terminx 945
 
4536 terminx 946
    osd->editor.pos = 0;
947
    while (osd->editor.buf[osd->editor.pos]) osd->editor.pos++;
948
    osd->editor.len = osd->editor.pos;
1625 terminx 949
 
4536 terminx 950
    if (osd->editor.pos<osd->editor.start)
847 terminx 951
    {
4536 terminx 952
        osd->editor.end = osd->editor.pos;
953
        osd->editor.start = osd->editor.end-editlinewidth;
847 terminx 954
 
4536 terminx 955
        if (osd->editor.start<0)
1625 terminx 956
        {
4536 terminx 957
            osd->editor.end-=osd->editor.start;
958
            osd->editor.start=0;
1625 terminx 959
        }
845 terminx 960
    }
4536 terminx 961
    else if (osd->editor.pos>=osd->editor.end)
1625 terminx 962
    {
4536 terminx 963
        osd->editor.start+=(osd->editor.pos-osd->editor.end);
964
        osd->editor.end+=(osd->editor.pos-osd->editor.end);
1625 terminx 965
    }
845 terminx 966
}
967
 
1625 terminx 968
//
969
// OSD_HandleKey() -- Handles keyboard input when capturing input.
970
//  Returns 0 if the key was handled internally, or the scancode if it should
971
//  be passed on to the game.
972
//
973
 
1205 terminx 974
int32_t OSD_HandleChar(char ch)
5 Plagman 975
{
1205 terminx 976
    int32_t i,j;
109 terminx 977
    symbol_t *tabc = NULL;
978
    static symbol_t *lastmatch = NULL;
5 Plagman 979
 
4536 terminx 980
    if (!osd || (osd->flags & OSD_CAPTURE) != OSD_CAPTURE)
1625 terminx 981
        return ch;
5 Plagman 982
 
1625 terminx 983
    if (ch != 9)    // tab
984
        lastmatch = NULL;
985
 
986
    switch (ch)
584 terminx 987
    {
1625 terminx 988
    case 1:    // control a. jump to beginning of line
4536 terminx 989
        osd->editor.pos=0;
990
        osd->editor.start=0;
991
        osd->editor.end=editlinewidth;
1625 terminx 992
        return 0;
993
    case 2:   // control b, move one character left
4536 terminx 994
        if (osd->editor.pos > 0) osd->editor.pos--;
1625 terminx 995
        return 0;
996
    case 3:   // control c
4536 terminx 997
        osd->editor.buf[osd->editor.len] = 0;
998
        OSD_Printf("%s\n",osd->editor.buf);
999
        osd->editor.len=0;
1000
        osd->editor.pos=0;
1001
        osd->editor.start=0;
1002
        osd->editor.end=editlinewidth;
1003
        osd->editor.buf[0] = 0;
1625 terminx 1004
        return 0;
1005
    case 5:   // control e, jump to end of line
4536 terminx 1006
        osd->editor.pos = osd->editor.len;
1007
        osd->editor.end = osd->editor.pos;
1008
        osd->editor.start = osd->editor.end-editlinewidth;
1009
        if (osd->editor.start<0)
845 terminx 1010
        {
4536 terminx 1011
            osd->editor.start=0;
1012
            osd->editor.end = editlinewidth;
845 terminx 1013
        }
1625 terminx 1014
        return 0;
1015
    case 6:   // control f, move one character right
4536 terminx 1016
        if (osd->editor.pos < osd->editor.len) osd->editor.pos++;
1625 terminx 1017
        return 0;
1018
    case 8:
1905 helixhorne 1019
#ifdef __APPLE__
1020
    case 127:      // control h, backspace
1021
#endif
4536 terminx 1022
        if (!osd->editor.pos || !osd->editor.len) return 0;
1023
        if ((osd->flags & OSD_OVERTYPE) == 0)
584 terminx 1024
        {
4536 terminx 1025
            if (osd->editor.pos < osd->editor.len)
1026
                Bmemmove(osd->editor.buf+osd->editor.pos-1, osd->editor.buf+osd->editor.pos, osd->editor.len-osd->editor.pos);
1027
            osd->editor.len--;
584 terminx 1028
        }
4536 terminx 1029
        osd->editor.pos--;
1030
        if (osd->editor.pos<osd->editor.start) osd->editor.start--,osd->editor.end--;
1905 helixhorne 1031
#ifndef __APPLE__
1644 helixhorne 1032
    case 127:  // handled in OSD_HandleScanCode (delete)
1905 helixhorne 1033
#endif
1625 terminx 1034
        return 0;
1035
    case 9:   // tab
1762 terminx 1036
    {
1037
        int32_t commonsize = 512;
1038
 
1039
        if (!lastmatch)
584 terminx 1040
        {
4536 terminx 1041
            for (i=osd->editor.pos; i>0; i--) if (osd->editor.buf[i-1] == ' ') break;
4963 helixhorne 1042
            for (j=0; i < osd->editor.len && osd->editor.buf[i] != ' '; j++,i++)
4536 terminx 1043
                osd->editor.tmp[j] = osd->editor.buf[i];
1044
            osd->editor.tmp[j] = 0;
828 terminx 1045
 
1762 terminx 1046
            if (j > 0)
584 terminx 1047
            {
4536 terminx 1048
                tabc = findsymbol(osd->editor.tmp, NULL);
5 Plagman 1049
 
4536 terminx 1050
                if (tabc && tabc->next && findsymbol(osd->editor.tmp, tabc->next))
401 terminx 1051
                {
1762 terminx 1052
                    symbol_t *symb=tabc;
1053
                    int32_t maxwidth = 0, x = 0, num = 0, diffpt;
847 terminx 1054
 
1762 terminx 1055
                    while (symb && symb != lastmatch)
401 terminx 1056
                    {
1762 terminx 1057
                        num++;
401 terminx 1058
 
1762 terminx 1059
                        if (lastmatch)
847 terminx 1060
                        {
1762 terminx 1061
                            diffpt = OSD_FindDiffPoint(symb->name,lastmatch->name);
1062
                            if (diffpt < commonsize)
1063
                                commonsize = diffpt;
1064
                        }
1625 terminx 1065
 
1762 terminx 1066
                        maxwidth = max((unsigned)maxwidth,Bstrlen(symb->name));
1067
                        lastmatch = symb;
1068
                        if (!lastmatch->next) break;
4536 terminx 1069
                        symb=findsymbol(osd->editor.tmp, lastmatch->next);
1762 terminx 1070
                    }
4536 terminx 1071
                    OSD_Printf(OSDTEXT_RED "Found %d possible completions for \"%s\":\n",num,osd->editor.tmp);
1762 terminx 1072
                    maxwidth += 3;
1073
                    symb = tabc;
1074
                    OSD_Printf("  ");
1075
                    while (symb && (symb != lastmatch))
1076
                    {
1077
                        tabc = lastmatch = symb;
1078
                        OSD_Printf("%-*s",maxwidth,symb->name);
1079
                        if (!lastmatch->next) break;
4536 terminx 1080
                        symb=findsymbol(osd->editor.tmp, lastmatch->next);
1762 terminx 1081
                        x += maxwidth;
4536 terminx 1082
                        if (x > (osd->draw.cols - maxwidth))
847 terminx 1083
                        {
1762 terminx 1084
                            x = 0;
1085
                            OSD_Printf("\n");
1086
                            if (symb && (symb != lastmatch))
1087
                                OSD_Printf("  ");
847 terminx 1088
                        }
1089
                    }
1762 terminx 1090
                    if (x) OSD_Printf("\n");
1091
                    OSD_Printf(OSDTEXT_RED "Press TAB again to cycle through matches\n");
401 terminx 1092
                }
584 terminx 1093
            }
1762 terminx 1094
        }
1095
        else
1096
        {
4536 terminx 1097
            tabc = findsymbol(osd->editor.tmp, lastmatch->next);
1762 terminx 1098
            if (!tabc && lastmatch)
4536 terminx 1099
                tabc = findsymbol(osd->editor.tmp, NULL);    // wrap */
1762 terminx 1100
        }
1101
 
1102
        if (tabc)
1103
        {
4536 terminx 1104
            for (i=osd->editor.pos; i>0; i--) if (osd->editor.buf[i-1] == ' ') break;
1105
            osd->editor.len = i;
1106
            for (j=0; tabc->name[j] && osd->editor.len <= OSDEDITLENGTH-1
1107
                    && (osd->editor.len < commonsize); i++,j++,osd->editor.len++)
1108
                osd->editor.buf[i] = tabc->name[j];
1109
            osd->editor.pos = osd->editor.len;
1110
            osd->editor.end = osd->editor.pos;
1111
            osd->editor.start = osd->editor.end-editlinewidth;
1112
            if (osd->editor.start<0)
1625 terminx 1113
            {
4536 terminx 1114
                osd->editor.start=0;
1115
                osd->editor.end = editlinewidth;
1625 terminx 1116
            }
838 terminx 1117
 
1762 terminx 1118
            lastmatch = tabc;
584 terminx 1119
        }
1762 terminx 1120
    }
1121
    return 0;
1625 terminx 1122
    case 11:      // control k, delete all to end of line
4536 terminx 1123
        Bmemset(osd->editor.buf + osd->editor.pos, 0, OSDBUFFERSIZE - osd->editor.pos);
1625 terminx 1124
        return 0;
1125
    case 12:      // control l, clear screen
4536 terminx 1126
        Bmemset(osd->text.buf, 0, OSDBUFFERSIZE);
1127
        Bmemset(osd->text.fmt, osd->draw.textpal + (osd->draw.textshade<<5), OSDBUFFERSIZE);
1128
        osd->text.lines = 1;
1625 terminx 1129
        return 0;
1130
    case 13:      // control m, enter
4536 terminx 1131
        if (osd->editor.len>0)
584 terminx 1132
        {
4536 terminx 1133
            osd->editor.buf[osd->editor.len] = 0;
1134
            if (!osd->history.buf[0] || Bstrcmp(osd->history.buf[0], osd->editor.buf))
842 terminx 1135
            {
4536 terminx 1136
                DO_FREE_AND_NULL(osd->history.buf[osd->history.maxlines-1]);
1137
 
1138
                Bmemmove(&osd->history.buf[1], &osd->history.buf[0], sizeof(intptr_t) * osd->history.maxlines-1);
1139
 
4725 helixhorne 1140
                OSD_SetHistory(0, osd->editor.buf);
4536 terminx 1141
 
1142
                if (osd->history.lines < osd->history.maxlines)
1143
                    osd->history.lines++;
1144
 
1145
                osd->history.total++;
1146
 
1147
                if (osd->history.exec == osd->history.maxlines)
842 terminx 1148
                    OSD_Printf("Command Buffer Warning: Failed queueing command "
4536 terminx 1149
                               "for execution. Buffer full. Consider increasing \"osdhistorydepth\".\n");
842 terminx 1150
                else
4536 terminx 1151
                    osd->history.exec++;
842 terminx 1152
            }
838 terminx 1153
            else
842 terminx 1154
            {
4536 terminx 1155
                if (osd->history.exec == osd->history.maxlines)
842 terminx 1156
                    OSD_Printf("Command Buffer Warning: Failed queueing command "
4536 terminx 1157
                               "for execution. Buffer full. Consider increasing \"osdhistorydepth\".\n");
842 terminx 1158
                else
4536 terminx 1159
                    osd->history.exec++;
842 terminx 1160
            }
4536 terminx 1161
            osd->history.pos=-1;
584 terminx 1162
        }
838 terminx 1163
 
4536 terminx 1164
        osd->editor.len=0;
1165
        osd->editor.pos=0;
1166
        osd->editor.start=0;
1167
        osd->editor.end=editlinewidth;
1625 terminx 1168
        return 0;
1169
    case 14:      // control n, next (ie. down arrow)
845 terminx 1170
        OSD_HistoryNext();
1625 terminx 1171
        return 0;
1172
    case 16:      // control p, previous (ie. up arrow)
845 terminx 1173
        OSD_HistoryPrev();
1625 terminx 1174
        return 0;
1175
    case 21:      // control u, delete all to beginning
4536 terminx 1176
        if (osd->editor.pos>0 && osd->editor.len)
584 terminx 1177
        {
4536 terminx 1178
            if (osd->editor.pos<osd->editor.len)
1179
                Bmemmove(osd->editor.buf, osd->editor.buf+osd->editor.pos, osd->editor.len-osd->editor.pos);
1180
            osd->editor.len-=osd->editor.pos;
1181
            osd->editor.pos = 0;
1182
            osd->editor.start = 0;
1183
            osd->editor.end = editlinewidth;
584 terminx 1184
        }
1625 terminx 1185
        return 0;
1186
    case 23:      // control w, delete one word back
4536 terminx 1187
        if (osd->editor.pos>0 && osd->editor.len>0)
584 terminx 1188
        {
4536 terminx 1189
            i=osd->editor.pos;
1190
            while (i>0 && osd->editor.buf[i-1]==asc_Space) i--;
1191
            while (i>0 && osd->editor.buf[i-1]!=asc_Space) i--;
1192
            if (osd->editor.pos<osd->editor.len)
1193
                Bmemmove(osd->editor.buf+i, osd->editor.buf+osd->editor.pos, osd->editor.len-osd->editor.pos);
1194
            osd->editor.len -= (osd->editor.pos-i);
1195
            osd->editor.pos = i;
1196
            if (osd->editor.pos < osd->editor.start)
584 terminx 1197
            {
4536 terminx 1198
                osd->editor.start=osd->editor.pos;
1199
                osd->editor.end=osd->editor.start+editlinewidth;
109 terminx 1200
            }
584 terminx 1201
        }
1625 terminx 1202
        return 0;
1203
    default:
1204
        if (ch >= asc_Space)      // text char
584 terminx 1205
        {
4536 terminx 1206
            if ((osd->flags & OSD_OVERTYPE) == 0)
1625 terminx 1207
            {
4536 terminx 1208
                if (osd->editor.len == OSDEDITLENGTH) // buffer full, can't insert another char
1625 terminx 1209
                    return 0;
4536 terminx 1210
                if (osd->editor.pos < osd->editor.len)
1211
                    Bmemmove(osd->editor.buf+osd->editor.pos+1, osd->editor.buf+osd->editor.pos, osd->editor.len-osd->editor.pos);
1212
                osd->editor.len++;
1625 terminx 1213
            }
4536 terminx 1214
            else if (osd->editor.pos == osd->editor.len)
1215
                osd->editor.len++;
1625 terminx 1216
 
4536 terminx 1217
            osd->editor.buf[osd->editor.pos++] = ch;
1625 terminx 1218
 
4536 terminx 1219
            if (osd->editor.pos > osd->editor.end)
1220
                osd->editor.start++, osd->editor.end++;
109 terminx 1221
        }
1625 terminx 1222
        return 0;
109 terminx 1223
    }
831 terminx 1224
    return 0;
1225
}
109 terminx 1226
 
1205 terminx 1227
int32_t OSD_HandleScanCode(int32_t sc, int32_t press)
831 terminx 1228
{
4536 terminx 1229
    if (!osd)
4269 hendricks2 1230
        return 1;
831 terminx 1231
 
4536 terminx 1232
    if (sc == osd->keycode)
831 terminx 1233
    {
1234
        if (press)
1235
        {
1236
            osdscroll = -osdscroll;
1237
            if (osdrowscur == -1)
1238
                osdscroll = 1;
4536 terminx 1239
            else if (osdrowscur == osd->draw.rows)
831 terminx 1240
                osdscroll = -1;
1241
            osdrowscur += osdscroll;
1242
            OSD_CaptureInput(osdscroll == 1);
1243
            osdscrtime = getticks();
1244
        }
4269 hendricks2 1245
        return -1;
831 terminx 1246
    }
4536 terminx 1247
    else if ((osd->flags & OSD_CAPTURE) == 0)
4269 hendricks2 1248
        return 2;
831 terminx 1249
 
1250
    if (!press)
1251
    {
1625 terminx 1252
        if (sc == sc_LeftShift || sc == sc_RightShift)
4536 terminx 1253
            osd->flags &= ~OSD_SHIFT;
1625 terminx 1254
        if (sc == sc_LeftControl || sc == sc_RightControl)
4536 terminx 1255
            osd->flags &= ~OSD_CTRL;
1625 terminx 1256
        return 0;
831 terminx 1257
    }
1258
 
1259
    keytime = gettime();
1260
 
1625 terminx 1261
    switch (sc)
584 terminx 1262
    {
1625 terminx 1263
    case sc_Escape:
584 terminx 1264
        //        OSD_ShowDisplay(0);
1265
        osdscroll = -1;
1625 terminx 1266
        osdrowscur--;
584 terminx 1267
        OSD_CaptureInput(0);
1268
        osdscrtime = getticks();
1625 terminx 1269
        break;
1270
    case sc_PgUp:
4536 terminx 1271
        if (osd->draw.head < osd->text.lines-1)
1272
            osd->draw.head++;
1625 terminx 1273
        break;
1274
    case sc_PgDn:
4536 terminx 1275
        if (osd->draw.head > 0)
1276
            osd->draw.head--;
1625 terminx 1277
        break;
1278
    case sc_Home:
4536 terminx 1279
        if (osd->flags & OSD_CTRL)
1280
            osd->draw.head = osd->text.lines-1;
584 terminx 1281
        else
1282
        {
4536 terminx 1283
            osd->editor.pos = 0;
1284
            osd->editor.start = osd->editor.pos;
1285
            osd->editor.end = osd->editor.start+editlinewidth;
109 terminx 1286
        }
1625 terminx 1287
        break;
1288
    case sc_End:
4536 terminx 1289
        if (osd->flags & OSD_CTRL)
1290
            osd->draw.head = 0;
584 terminx 1291
        else
1292
        {
4536 terminx 1293
            osd->editor.pos = osd->editor.len;
1294
            osd->editor.end = osd->editor.pos;
1295
            osd->editor.start = osd->editor.end-editlinewidth;
1296
            if (osd->editor.start<0)
584 terminx 1297
            {
4536 terminx 1298
                osd->editor.start=0;
1299
                osd->editor.end = editlinewidth;
109 terminx 1300
            }
1301
        }
1625 terminx 1302
        break;
1303
    case sc_Insert:
4536 terminx 1304
        osd->flags = (osd->flags & ~OSD_OVERTYPE) | (-((osd->flags & OSD_OVERTYPE) == 0) & OSD_OVERTYPE);
1644 helixhorne 1305
        break;
1625 terminx 1306
    case sc_LeftArrow:
4536 terminx 1307
        if (osd->editor.pos>0)
584 terminx 1308
        {
4536 terminx 1309
            if (osd->flags & OSD_CTRL)
584 terminx 1310
            {
4536 terminx 1311
                while (osd->editor.pos>0)
584 terminx 1312
                {
4536 terminx 1313
                    if (osd->editor.buf[osd->editor.pos-1] != asc_Space)
1625 terminx 1314
                        break;
4536 terminx 1315
                    osd->editor.pos--;
109 terminx 1316
                }
4536 terminx 1317
                while (osd->editor.pos>0)
584 terminx 1318
                {
4536 terminx 1319
                    if (osd->editor.buf[osd->editor.pos-1] == asc_Space)
1625 terminx 1320
                        break;
4536 terminx 1321
                    osd->editor.pos--;
109 terminx 1322
                }
584 terminx 1323
            }
4536 terminx 1324
            else osd->editor.pos--;
109 terminx 1325
        }
4536 terminx 1326
        if (osd->editor.pos<osd->editor.start)
1625 terminx 1327
        {
4536 terminx 1328
            osd->editor.end-=(osd->editor.start-osd->editor.pos);
1329
            osd->editor.start-=(osd->editor.start-osd->editor.pos);
1625 terminx 1330
        }
1331
        break;
1332
    case sc_RightArrow:
4536 terminx 1333
        if (osd->editor.pos<osd->editor.len)
584 terminx 1334
        {
4536 terminx 1335
            if (osd->flags & OSD_CTRL)
584 terminx 1336
            {
4536 terminx 1337
                while (osd->editor.pos<osd->editor.len)
584 terminx 1338
                {
4536 terminx 1339
                    if (osd->editor.buf[osd->editor.pos] == asc_Space)
1625 terminx 1340
                        break;
4536 terminx 1341
                    osd->editor.pos++;
109 terminx 1342
                }
4536 terminx 1343
                while (osd->editor.pos<osd->editor.len)
584 terminx 1344
                {
4536 terminx 1345
                    if (osd->editor.buf[osd->editor.pos] != asc_Space)
1625 terminx 1346
                        break;
4536 terminx 1347
                    osd->editor.pos++;
109 terminx 1348
                }
584 terminx 1349
            }
4536 terminx 1350
            else osd->editor.pos++;
109 terminx 1351
        }
4536 terminx 1352
        if (osd->editor.pos>=osd->editor.end)
1625 terminx 1353
        {
4536 terminx 1354
            osd->editor.start+=(osd->editor.pos-osd->editor.end);
1355
            osd->editor.end+=(osd->editor.pos-osd->editor.end);
1625 terminx 1356
        }
1357
        break;
1358
    case sc_UpArrow:
845 terminx 1359
        OSD_HistoryPrev();
1625 terminx 1360
        break;
1361
    case sc_DownArrow:
845 terminx 1362
        OSD_HistoryNext();
1625 terminx 1363
        break;
1364
    case sc_LeftShift:
1365
    case sc_RightShift:
4536 terminx 1366
        osd->flags |= OSD_SHIFT;
1625 terminx 1367
        break;
1368
    case sc_LeftControl:
1369
    case sc_RightControl:
4536 terminx 1370
        osd->flags |= OSD_CTRL;
1625 terminx 1371
        break;
1372
    case sc_CapsLock:
4536 terminx 1373
        osd->flags = (osd->flags & ~OSD_CAPS) | (-((osd->flags & OSD_CAPS) == 0) & OSD_CAPS);
1625 terminx 1374
        break;
1375
    case sc_Delete:
4536 terminx 1376
        if (osd->editor.pos == osd->editor.len || !osd->editor.len)
1625 terminx 1377
            return 0;
4536 terminx 1378
        if (osd->editor.pos <= osd->editor.len-1)
1379
            Bmemmove(osd->editor.buf+osd->editor.pos, osd->editor.buf+osd->editor.pos+1, osd->editor.len-osd->editor.pos-1);
1380
        osd->editor.len--;
1625 terminx 1381
        break;
109 terminx 1382
    }
1383
    return 0;
5 Plagman 1384
}
1385
 
1386
 
1387
//
1388
// OSD_ResizeDisplay() -- Handles readjustment of the display when the screen resolution
1007 hnt_ts 1389
//  changes on us.
5 Plagman 1390
//
1205 terminx 1391
void OSD_ResizeDisplay(int32_t w, int32_t h)
5 Plagman 1392
{
4536 terminx 1393
    int32_t newcols, newmaxlines;
1394
    char *newtext, *newfmt;
1205 terminx 1395
    int32_t i,j,k;
5 Plagman 1396
 
109 terminx 1397
    newcols = getcolumnwidth(w);
4536 terminx 1398
    newmaxlines = OSDBUFFERSIZE / newcols;
5 Plagman 1399
 
4536 terminx 1400
    j = min(newmaxlines, osd->text.maxlines);
1401
    k = min(newcols, osd->draw.cols);
5 Plagman 1402
 
4536 terminx 1403
    newtext = (char *)Bmalloc(OSDBUFFERSIZE);
1404
    newfmt = (char *)Bmalloc(OSDBUFFERSIZE);
1405
 
1406
    Bmemset(newtext, asc_Space, OSDBUFFERSIZE);
1407
 
1229 terminx 1408
    for (i=j-1; i>=0; i--)
584 terminx 1409
    {
4536 terminx 1410
        Bmemcpy(newtext+newcols*i, osd->text.buf+osd->draw.cols*i, k);
1411
        Bmemcpy(newfmt+newcols*i, osd->text.fmt+osd->draw.cols*i, k);
109 terminx 1412
    }
5 Plagman 1413
 
4536 terminx 1414
    Bfree(osd->text.buf);
1415
    osd->text.buf = newtext;
1416
 
1417
    Bfree(osd->text.fmt);
1418
    osd->text.fmt = newfmt;
1419
 
1420
    osd->text.maxlines = newmaxlines;
1421
 
1422
    osd->draw.cols = newcols;
109 terminx 1423
    osdmaxrows = getrowheight(h)-2;
1424
 
4536 terminx 1425
    if (osd->draw.rows > osdmaxrows) osd->draw.rows = osdmaxrows;
109 terminx 1426
 
4536 terminx 1427
    osd->text.pos = 0;
1428
    osd->draw.head = 0;
1429
    osd->editor.start = 0;
1430
    osd->editor.end = editlinewidth;
109 terminx 1431
    white = -1;
5 Plagman 1432
}
1433
 
1434
 
1435
//
402 terminx 1436
// OSD_CaptureInput()
5 Plagman 1437
//
1205 terminx 1438
void OSD_CaptureInput(int32_t cap)
5 Plagman 1439
{
4536 terminx 1440
    osd->flags = (osd->flags & ~(OSD_CAPTURE|OSD_CTRL|OSD_SHIFT)) | (-cap & OSD_CAPTURE);
5 Plagman 1441
 
4738 hendricks2 1442
    grabmouse(cap == 0 ? AppMouseGrab : 0);
1625 terminx 1443
    onshowosd(cap);
1444
 
1445
    if (cap)
1446
        releaseallbuttons();
1447
 
404 terminx 1448
    bflushchars();
5 Plagman 1449
}
1450
 
1625 terminx 1451
 
402 terminx 1452
//
1453
// OSD_ShowDisplay() -- Shows or hides the onscreen display
1454
//
1205 terminx 1455
void OSD_ShowDisplay(int32_t onf)
402 terminx 1456
{
4536 terminx 1457
    osd->flags = (osd->flags & ~OSD_DRAW) | (-onf & OSD_DRAW);
1625 terminx 1458
    OSD_CaptureInput(onf);
402 terminx 1459
}
5 Plagman 1460
 
402 terminx 1461
 
5 Plagman 1462
//
1463
// OSD_Draw() -- Draw the onscreen display
1464
//
441 terminx 1465
 
5 Plagman 1466
void OSD_Draw(void)
1467
{
1399 terminx 1468
    uint32_t topoffs;
1205 terminx 1469
    int32_t row, lines, x, len;
5 Plagman 1470
 
4536 terminx 1471
    if (!osd)
1625 terminx 1472
        return;
5 Plagman 1473
 
404 terminx 1474
    if (osdrowscur == 0)
4536 terminx 1475
        OSD_ShowDisplay(osd->flags & OSD_DRAW ? 0 : 1);
401 terminx 1476
 
4536 terminx 1477
    if (osdrowscur == osd->draw.rows)
401 terminx 1478
        osdscroll = 0;
1479
    else
1480
    {
1205 terminx 1481
        int32_t j;
584 terminx 1482
 
4536 terminx 1483
        if ((osdrowscur < osd->draw.rows && osdscroll == 1) || osdrowscur < -1)
449 terminx 1484
        {
450 terminx 1485
            j = (getticks()-osdscrtime);
449 terminx 1486
            while (j > -1)
1487
            {
1488
                osdrowscur++;
4658 terminx 1489
                j -= tabledivide32_noinline(200, osd->draw.rows);
4536 terminx 1490
                if (osdrowscur > osd->draw.rows-1)
449 terminx 1491
                    break;
1492
            }
1493
        }
4536 terminx 1494
        if ((osdrowscur > -1 && osdscroll == -1) || osdrowscur > osd->draw.rows)
449 terminx 1495
        {
450 terminx 1496
            j = (getticks()-osdscrtime);
449 terminx 1497
            while (j > -1)
1498
            {
1499
                osdrowscur--;
4658 terminx 1500
                j -= tabledivide32_noinline(200, osd->draw.rows);
449 terminx 1501
                if (osdrowscur < 1)
1502
                    break;
1503
            }
1504
        }
1505
        osdscrtime = getticks();
441 terminx 1506
    }
584 terminx 1507
 
4536 terminx 1508
    if ((osd->flags & OSD_DRAW) == 0 || !osdrowscur) return;
401 terminx 1509
 
4536 terminx 1510
    topoffs = osd->draw.head * osd->draw.cols;
401 terminx 1511
    row = osdrowscur-1;
4536 terminx 1512
    lines = min(osd->text.lines-osd->draw.head, osdrowscur);
5 Plagman 1513
 
109 terminx 1514
    begindrawing();
5 Plagman 1515
 
4536 terminx 1516
    clearbackground(osd->draw.cols,osdrowscur+1);
584 terminx 1517
 
1518
    for (; lines>0; lines--, row--)
1519
    {
4210 helixhorne 1520
        // XXX: May happen, which would ensue an oob if not checked.
4536 terminx 1521
        // Last char accessed is osd->text.buf[topoffs + osd->draw.cols-1].
4210 helixhorne 1522
        // Reproducible by running test.lua with -Lopts=diag
1523
        // and scrolling to the top.
4536 terminx 1524
        if (topoffs + osd->draw.cols-1 >= OSDBUFFERSIZE)
4210 helixhorne 1525
            break;
4536 terminx 1526
        drawosdstr(0,row,osd->text.buf+topoffs,osd->draw.cols,osd->draw.textshade,osd->draw.textpal);
1527
        topoffs+=osd->draw.cols;
109 terminx 1528
    }
1529
 
1095 terminx 1530
    {
4536 terminx 1531
        int32_t offset = ((osd->flags & (OSD_CAPS|OSD_SHIFT)) == (OSD_CAPS|OSD_SHIFT) && osd->draw.head > 0);
1532
        int32_t shade = osd->draw.promptshade?osd->draw.promptshade:(sintable[(totalclock<<4)&2047]>>11);
109 terminx 1533
 
4536 terminx 1534
        if (osd->draw.head == osd->text.lines-1) drawosdchar(0,osdrowscur,'~',shade,osd->draw.promptpal);
1535
        else if (osd->draw.head > 0) drawosdchar(0,osdrowscur,'^',shade,osd->draw.promptpal);
1536
        if (osd->flags & OSD_CAPS) drawosdchar(0+(osd->draw.head > 0),osdrowscur,'C',shade,osd->draw.promptpal);
1537
        if (osd->flags & OSD_SHIFT) drawosdchar(1+(osd->flags & OSD_CAPS && osd->draw.head > 0),osdrowscur,'H',shade,osd->draw.promptpal);
109 terminx 1538
 
4536 terminx 1539
        drawosdchar(2+offset,osdrowscur,'>',shade,osd->draw.promptpal);
584 terminx 1540
 
4536 terminx 1541
        len = min(osd->draw.cols-1-3-offset, osd->editor.len-osd->editor.start);
1095 terminx 1542
        for (x=len-1; x>=0; x--)
4536 terminx 1543
            drawosdchar(3+x+offset,osdrowscur,osd->editor.buf[osd->editor.start+x],osd->draw.editshade<<1,osd->draw.editpal);
1095 terminx 1544
 
4536 terminx 1545
        offset += 3+osd->editor.pos-osd->editor.start;
1652 terminx 1546
 
4536 terminx 1547
        drawosdcursor(offset,osdrowscur,osd->flags & OSD_OVERTYPE,keytime);
1652 terminx 1548
 
4536 terminx 1549
        if (osd->verstr.buf)
1550
            drawosdstr(osd->draw.cols - osd->verstr.len, osdrowscur - (offset >= osd->draw.cols - osd->verstr.len),
1551
                       osd->verstr.buf, osd->verstr.len, (sintable[(totalclock<<4)&2047]>>11), osd->verstr.pal);
1095 terminx 1552
    }
1553
 
109 terminx 1554
    enddrawing();
5 Plagman 1555
}
1556
 
1557
 
1558
//
4555 hendricks2 1559
// OSD_Printf() -- Print a formatted string to the onscreen display
5 Plagman 1560
//   and write it to the log file
1561
//
1562
 
4555 hendricks2 1563
void OSD_Printf(const char *fmt, ...)
1564
{
1565
    static char tmpstr[8192];
1566
    va_list va;
1567
 
1568
    va_start(va, fmt);
1569
    Bvsnprintf(tmpstr, sizeof(tmpstr), fmt, va);
1570
    va_end(va);
1571
 
1572
    OSD_Puts(tmpstr);
1573
}
1574
 
1575
 
1576
//
1577
// OSD_Puts() -- Print a string to the onscreen display
1578
//   and write it to the log file
1579
//
1580
 
1625 terminx 1581
static inline void OSD_LineFeed(void)
5 Plagman 1582
{
4536 terminx 1583
    Bmemmove(osd->text.buf+osd->draw.cols, osd->text.buf, OSDBUFFERSIZE-osd->draw.cols);
1584
    Bmemset(osd->text.buf, asc_Space, osd->draw.cols);
1585
    Bmemmove(osd->text.fmt+osd->draw.cols, osd->text.fmt, OSDBUFFERSIZE-osd->draw.cols);
1586
    Bmemset(osd->text.fmt, osd->draw.textpal, osd->draw.cols);
1587
    if (osd->text.lines < osd->text.maxlines) osd->text.lines++;
5 Plagman 1588
}
4555 hendricks2 1589
 
1007 hnt_ts 1590
#define MAX_ERRORS 4096
4555 hendricks2 1591
 
1592
void OSD_Puts(const char *tmpstr)
5 Plagman 1593
{
4555 hendricks2 1594
    const char *chp;
1595
    char p=osd->draw.textpal, s=osd->draw.textshade;
5 Plagman 1596
 
4536 terminx 1597
    mutex_lock(&osd->mutex);
1658 terminx 1598
 
3318 helixhorne 1599
    if (tmpstr[0]==0)
1600
    {
4536 terminx 1601
        mutex_unlock(&osd->mutex);
3318 helixhorne 1602
        return;
1603
    }
1604
 
4536 terminx 1605
    if (tmpstr[0]=='^' && tmpstr[1]=='1' && tmpstr[2]=='0' && ++osd->log.errors > MAX_ERRORS)
1007 hnt_ts 1606
    {
4536 terminx 1607
        if (osd->log.errors == MAX_ERRORS + 1)
4555 hendricks2 1608
            tmpstr = "\nToo many errors. Logging errors stopped.\n";
1017 terminx 1609
        else
1610
        {
4536 terminx 1611
            osd->log.errors = MAX_ERRORS + 2;
1612
            mutex_unlock(&osd->mutex);
1017 terminx 1613
            return;
1614
        }
1007 hnt_ts 1615
    }
1616
 
4536 terminx 1617
    if (osd->log.lines < osd->log.cutoff)
591 plagman 1618
    {
4536 terminx 1619
        if (osdlog && (!osd->log.cutoff || osd->log.lines < osd->log.cutoff))
929 terminx 1620
        {
4555 hendricks2 1621
            char *chp2 = Xstrdup(tmpstr);
1622
            Bfputs(OSD_StripColors(chp2, tmpstr), osdlog);
1623
            Bprintf("%s", chp2);
1624
            Bfree(chp2);
929 terminx 1625
        }
591 plagman 1626
    }
4536 terminx 1627
    else if (osd->log.lines == osd->log.cutoff)
591 plagman 1628
    {
4555 hendricks2 1629
        Bfputs("\nMaximal log size reached. Logging stopped.\nSet the \"osdlogcutoff\" console variable to a higher value if you need a longer log.\n", osdlog);
4536 terminx 1630
        osd->log.lines = osd->log.cutoff + 1;
591 plagman 1631
    }
109 terminx 1632
 
1015 terminx 1633
    chp = tmpstr;
1634
    do
584 terminx 1635
    {
1015 terminx 1636
        if (*chp == '\n')
864 terminx 1637
        {
4536 terminx 1638
            osd->text.pos=0;
1639
            osd->log.lines++;
1625 terminx 1640
            OSD_LineFeed();
1015 terminx 1641
            continue;
1642
        }
1762 terminx 1643
 
1015 terminx 1644
        if (*chp == '\r')
1645
        {
4536 terminx 1646
            osd->text.pos=0;
1015 terminx 1647
            continue;
1648
        }
1762 terminx 1649
 
1015 terminx 1650
        if (*chp == '^')
1651
        {
864 terminx 1652
            if (isdigit(*(chp+1)))
1653
            {
1015 terminx 1654
                char smallbuf[4];
1019 terminx 1655
                if (!isdigit(*(++chp+1)))
1015 terminx 1656
                {
1657
                    smallbuf[0] = *(chp);
1658
                    smallbuf[1] = '\0';
2374 helixhorne 1659
                    p = Batol(smallbuf);
1019 terminx 1660
                    continue;
1015 terminx 1661
                }
1762 terminx 1662
 
1019 terminx 1663
                smallbuf[0] = *(chp++);
1664
                smallbuf[1] = *(chp);
1665
                smallbuf[2] = '\0';
2374 helixhorne 1666
                p = Batol(smallbuf);
1015 terminx 1667
                continue;
864 terminx 1668
            }
1762 terminx 1669
 
1015 terminx 1670
            if (Btoupper(*(chp+1)) == 'S')
864 terminx 1671
            {
1015 terminx 1672
                chp++;
1673
                if (isdigit(*(++chp)))
1674
                    s = *chp;
1675
                continue;
864 terminx 1676
            }
1762 terminx 1677
 
1015 terminx 1678
            if (Btoupper(*(chp+1)) == 'O')
1679
            {
1680
                chp++;
4536 terminx 1681
                p = osd->draw.textpal;
1682
                s = osd->draw.textshade;
1015 terminx 1683
                continue;
1684
            }
864 terminx 1685
        }
1762 terminx 1686
 
4536 terminx 1687
        osd->text.buf[osd->text.pos] = *chp;
1688
        osd->text.fmt[osd->text.pos++] = p+(s<<5);
1762 terminx 1689
 
4536 terminx 1690
        if (osd->text.pos == osd->draw.cols)
865 terminx 1691
        {
4536 terminx 1692
            osd->text.pos = 0;
1625 terminx 1693
            OSD_LineFeed();
584 terminx 1694
        }
1017 terminx 1695
    }
1696
    while (*(++chp));
1658 terminx 1697
 
4536 terminx 1698
    mutex_unlock(&osd->mutex);
5 Plagman 1699
}
1700
 
1701
 
1702
//
1703
// OSD_DispatchQueued() -- Executes any commands queued in the buffer
1704
//
1705
void OSD_DispatchQueued(void)
1706
{
1205 terminx 1707
    int32_t cmd;
5 Plagman 1708
 
4536 terminx 1709
    if (!osd->history.exec) return;
5 Plagman 1710
 
4536 terminx 1711
    cmd=osd->history.exec-1;
1712
    osd->history.exec=0;
109 terminx 1713
 
584 terminx 1714
    for (; cmd>=0; cmd--)
4536 terminx 1715
        OSD_Dispatch((const char *)osd->history.buf[cmd]);
5 Plagman 1716
}
1717
 
1718
 
1719
//
1720
// OSD_Dispatch() -- Executes a command string
1721
//
1722
 
1205 terminx 1723
static char *strtoken(char *s, char **ptrptr, int32_t *restart)
5 Plagman 1724
{
109 terminx 1725
    char *p, *p2, *start;
1726
 
1727
    *restart = 0;
1728
    if (!ptrptr) return NULL;
1729
 
1730
    // if s != NULL, we process from the start of s, otherwise
1731
    // we just continue with where ptrptr points to
1732
    if (s) p = s;
1733
    else p = *ptrptr;
1734
 
1735
    if (!p) return NULL;
1736
 
1737
    // eat up any leading whitespace
1738
    while (*p != 0 && *p != ';' && *p == ' ') p++;
1739
 
1740
    // a semicolon is an end of statement delimiter like a \0 is, so we signal
1741
    // the caller to 'restart' for the rest of the string pointed at by *ptrptr
584 terminx 1742
    if (*p == ';')
1743
    {
109 terminx 1744
        *restart = 1;
1745
        *ptrptr = p+1;
1746
        return NULL;
1747
    }
1748
    // or if we hit the end of the input, signal all done by nulling *ptrptr
584 terminx 1749
    else if (*p == 0)
1750
    {
109 terminx 1751
        *ptrptr = NULL;
1752
        return NULL;
1753
    }
1754
 
584 terminx 1755
    if (*p == '\"')
1756
    {
109 terminx 1757
        // quoted string
1758
        start = ++p;
1759
        p2 = p;
584 terminx 1760
        while (*p != 0)
1761
        {
1762
            if (*p == '\"')
1763
            {
109 terminx 1764
                p++;
1765
                break;
584 terminx 1766
            }
1767
            else if (*p == '\\')
1768
            {
1769
                switch (*(++p))
1770
                {
331 terminx 1771
                case 'n':
1772
                    *p2 = '\n'; break;
1773
                case 'r':
1774
                    *p2 = '\r'; break;
1775
                default:
1776
                    *p2 = *p; break;
109 terminx 1777
                }
584 terminx 1778
            }
1779
            else
1780
            {
109 terminx 1781
                *p2 = *p;
1782
            }
1783
            p2++, p++;
1784
        }
1785
        *p2 = 0;
584 terminx 1786
    }
1787
    else
1788
    {
109 terminx 1789
        start = p;
1790
        while (*p != 0 && *p != ';' && *p != ' ') p++;
1791
    }
1792
 
1793
    // if we hit the end of input, signal all done by nulling *ptrptr
584 terminx 1794
    if (*p == 0)
1795
    {
109 terminx 1796
        *ptrptr = NULL;
1797
    }
1798
    // or if we came upon a semicolon, signal caller to restart with the
1799
    // string at *ptrptr
584 terminx 1800
    else if (*p == ';')
1801
    {
109 terminx 1802
        *p = 0;
1803
        *ptrptr = p+1;
1804
        *restart = 1;
1805
    }
1806
    // otherwise, clip off the token and carry on
584 terminx 1807
    else
1808
    {
109 terminx 1809
        *(p++) = 0;
1810
        *ptrptr = p;
1811
    }
1812
 
1813
    return start;
5 Plagman 1814
}
1815
 
1816
#define MAXPARMS 512
1205 terminx 1817
int32_t OSD_Dispatch(const char *cmd)
5 Plagman 1818
{
109 terminx 1819
    char *workbuf, *wp, *wtp, *state;
1634 terminx 1820
    int32_t restart = 0;
5 Plagman 1821
 
4491 helixhorne 1822
    workbuf = state = Xstrdup(cmd);
5 Plagman 1823
 
584 terminx 1824
    do
1825
    {
1634 terminx 1826
        int32_t numparms = 0;
1827
        symbol_t *symb;
1828
        osdfuncparm_t ofp;
1829
        char *parms[MAXPARMS];
1830
 
109 terminx 1831
        Bmemset(parms, 0, sizeof(parms));
1634 terminx 1832
 
1833
        if ((wp = strtoken(state, &wtp, &restart)) == NULL)
584 terminx 1834
        {
109 terminx 1835
            state = wtp;
1836
            continue;
1837
        }
1838
 
1634 terminx 1839
        if ((symb = findexactsymbol(wp)) == NULL)
814 terminx 1840
        {
1649 helixhorne 1841
            if ((wp[0] != '/' || wp[1] != '/') && !m32_osd_tryscript) // cheap hack for comments in cfgs
1842
            {
1634 terminx 1843
                OSD_Printf(OSDTEXT_RED "\"%s\" is not a valid command or cvar\n", wp);
1649 helixhorne 1844
            }
1845
            else if (m32_osd_tryscript)
1846
            {
1847
                M32RunScript(cmd);
1848
            }
1527 terminx 1849
            Bfree(workbuf);
814 terminx 1850
            return -1;
1851
        }
1852
 
109 terminx 1853
        ofp.name = wp;
584 terminx 1854
        while (wtp && !restart)
1855
        {
109 terminx 1856
            wp = strtoken(NULL, &wtp, &restart);
1857
            if (wp && numparms < MAXPARMS) parms[numparms++] = wp;
1858
        }
1859
        ofp.numparms = numparms;
1860
        ofp.parms    = (const char **)parms;
1861
        ofp.raw      = cmd;
1634 terminx 1862
 
3116 hendricks2 1863
        if ((intptr_t)symb->func == (intptr_t)OSD_ALIAS)
817 terminx 1864
            OSD_Dispatch(symb->help);
3116 hendricks2 1865
        else if ((intptr_t)symb->func != (intptr_t)OSD_UNALIASED)
818 terminx 1866
            switch (symb->func(&ofp))
1867
            {
1868
            case OSDCMD_OK:
1869
                break;
1870
            case OSDCMD_SHOWHELP:
1871
                OSD_Printf("%s\n", symb->help);
1872
                break;
1873
            }
109 terminx 1874
 
1875
        state = wtp;
584 terminx 1876
    }
1877
    while (wtp && restart);
109 terminx 1878
 
1527 terminx 1879
    Bfree(workbuf);
109 terminx 1880
 
1881
    return 0;
5 Plagman 1882
}
1883
 
1884
 
1885
//
1886
// OSD_RegisterFunction() -- Registers a new function
1887
//
1762 terminx 1888
int32_t OSD_RegisterFunction(const char *name, const char *help, int32_t (*func)(const osdfuncparm_t *))
5 Plagman 1889
{
109 terminx 1890
    symbol_t *symb;
1891
    const char *cp;
5 Plagman 1892
 
4536 terminx 1893
    if (!osd)
1625 terminx 1894
        OSD_Init();
5 Plagman 1895
 
1632 terminx 1896
    if (!name || !name[0])
584 terminx 1897
    {
1632 terminx 1898
        OSD_Printf("OSD_RegisterFunction(): can't register function with null name\n");
109 terminx 1899
        return -1;
1900
    }
1632 terminx 1901
 
1902
    if (!func)
584 terminx 1903
    {
1632 terminx 1904
        OSD_Printf("OSD_RegisterFunction(): can't register null function\n");
109 terminx 1905
        return -1;
1906
    }
5 Plagman 1907
 
109 terminx 1908
    // check for illegal characters in name
584 terminx 1909
    for (cp = name; *cp; cp++)
1910
    {
1911
        if ((cp == name) && (*cp >= '0') && (*cp <= '9'))
1912
        {
817 terminx 1913
            OSD_Printf("OSD_RegisterFunction(): first character of function name \"%s\" must not be a numeral\n", name);
109 terminx 1914
            return -1;
1915
        }
1916
        if ((*cp < '0') ||
1917
                (*cp > '9' && *cp < 'A') ||
1918
                (*cp > 'Z' && *cp < 'a' && *cp != '_') ||
584 terminx 1919
                (*cp > 'z'))
1920
        {
817 terminx 1921
            OSD_Printf("OSD_RegisterFunction(): illegal character in function name \"%s\"\n", name);
109 terminx 1922
            return -1;
1923
        }
1924
    }
5 Plagman 1925
 
109 terminx 1926
    if (!help) help = "(no description for this function)";
5 Plagman 1927
 
109 terminx 1928
    symb = findexactsymbol(name);
1632 terminx 1929
 
817 terminx 1930
    if (symb) // allow this now for reusing an alias name
584 terminx 1931
    {
1762 terminx 1932
        /*
1933
                if (symb->func != OSD_ALIAS && symb->func != OSD_UNALIASED)
1934
                {
1935
                    OSD_Printf("OSD_RegisterFunction(): \"%s\" is already defined\n", name);
1936
                    return -1;
1937
                }
1938
        */
1666 terminx 1939
//        Bfree((char *)symb->help);
817 terminx 1940
        symb->help = help;
820 terminx 1941
        symb->func = func;
819 terminx 1942
        return 0;
109 terminx 1943
    }
5 Plagman 1944
 
109 terminx 1945
    symb = addnewsymbol(name);
1632 terminx 1946
 
584 terminx 1947
    if (!symb)
1948
    {
817 terminx 1949
        OSD_Printf("OSD_RegisterFunction(): Failed registering function \"%s\"\n", name);
109 terminx 1950
        return -1;
1951
    }
5 Plagman 1952
 
109 terminx 1953
    symb->name = name;
1954
    symb->help = help;
1955
    symb->func = func;
1956
 
1957
    return 0;
5 Plagman 1958
}
1959
 
403 terminx 1960
//
1961
// OSD_SetVersionString()
1962
//
1625 terminx 1963
void OSD_SetVersion(const char *version, int32_t shade, int32_t pal)
403 terminx 1964
{
4536 terminx 1965
    osdstr_t *v = &osd->verstr;
1966
    DO_FREE_AND_NULL(v->buf);
1967
    v->buf = Bstrdup(version);
1968
    v->len = Bstrlen(version);
1969
    v->shade = shade;
1970
    v->pal = pal;
403 terminx 1971
}
1972
 
5 Plagman 1973
//
1974
// addnewsymbol() -- Allocates space for a new symbol and attaches it
1975
//   appropriately to the lists, sorted.
1976
//
1025 terminx 1977
 
5 Plagman 1978
static symbol_t *addnewsymbol(const char *name)
1979
{
109 terminx 1980
    symbol_t *newsymb, *s, *t;
5 Plagman 1981
 
4536 terminx 1982
    if (osd->numsymbols >= OSDMAXSYMBOLS) return NULL;
4491 helixhorne 1983
    newsymb = (symbol_t *)Xmalloc(sizeof(symbol_t));
109 terminx 1984
    Bmemset(newsymb, 0, sizeof(symbol_t));
5 Plagman 1985
 
109 terminx 1986
    // link it to the main chain
584 terminx 1987
    if (!symbols)
1988
    {
109 terminx 1989
        symbols = newsymb;
584 terminx 1990
    }
1991
    else
1992
    {
1993
        if (Bstrcasecmp(name, symbols->name) <= 0)
1994
        {
109 terminx 1995
            t = symbols;
1996
            symbols = newsymb;
1997
            symbols->next = t;
584 terminx 1998
        }
1999
        else
2000
        {
109 terminx 2001
            s = symbols;
584 terminx 2002
            while (s->next)
2003
            {
109 terminx 2004
                if (Bstrcasecmp(s->next->name, name) > 0) break;
2005
                s=s->next;
2006
            }
2007
            t = s->next;
2008
            s->next = newsymb;
2009
            newsymb->next = t;
2010
        }
2011
    }
4536 terminx 2012
    hash_add(&h_osd, name, osd->numsymbols, 1);
4491 helixhorne 2013
    name = Bstrtolower(Xstrdup(name));
4536 terminx 2014
    hash_add(&h_osd, name, osd->numsymbols, 1);
1625 terminx 2015
    Bfree((void *)name);
4536 terminx 2016
    osd->symbptrs[osd->numsymbols++] = newsymb;
109 terminx 2017
    return newsymb;
5 Plagman 2018
}
2019
 
2020
 
2021
//
2022
// findsymbol() -- Finds a symbol, possibly partially named
109 terminx 2023
//
5 Plagman 2024
static symbol_t *findsymbol(const char *name, symbol_t *startingat)
2025
{
109 terminx 2026
    if (!startingat) startingat = symbols;
2027
    if (!startingat) return NULL;
5 Plagman 2028
 
109 terminx 2029
    for (; startingat; startingat=startingat->next)
1625 terminx 2030
        if (startingat->func != OSD_UNALIASED && !Bstrncasecmp(name, startingat->name, Bstrlen(name))) return startingat;
5 Plagman 2031
 
109 terminx 2032
    return NULL;
5 Plagman 2033
}
2034
 
2035
//
2036
// findexactsymbol() -- Finds a symbol, complete named
109 terminx 2037
//
5 Plagman 2038
static symbol_t *findexactsymbol(const char *name)
2039
{
1205 terminx 2040
    int32_t i;
4491 helixhorne 2041
    char *lname = Xstrdup(name);
109 terminx 2042
    if (!symbols) return NULL;
5 Plagman 2043
 
1625 terminx 2044
    i = hash_find(&h_osd,lname);
1026 terminx 2045
    if (i > -1)
2046
    {
1625 terminx 2047
//        if ((symbol_t *)osdsymbptrs[i]->func == OSD_UNALIASED)
1032 terminx 2048
//            return NULL;
1101 terminx 2049
        Bfree(lname);
4536 terminx 2050
        return osd->symbptrs[i];
1026 terminx 2051
    }
1197 terminx 2052
 
2053
    // try it again
1642 terminx 2054
    Bstrtolower(lname);
1625 terminx 2055
    i = hash_find(&h_osd,lname);
1101 terminx 2056
    Bfree(lname);
1197 terminx 2057
 
2058
    if (i > -1)
4536 terminx 2059
        return osd->symbptrs[i];
109 terminx 2060
    return NULL;
5 Plagman 2061
}
2062
 
1352 terminx 2063
int32_t osdcmd_cvar_set(const osdfuncparm_t *parm)
2064
{
2065
    int32_t showval = (parm->numparms == 0);
2066
    int32_t i;
2067
 
1625 terminx 2068
    i = hash_find(&h_cvars, parm->name);
1352 terminx 2069
 
2070
    if (i < 0)
4536 terminx 2071
        for (i = osd->numcvars-1; i >= 0; i--)
2072
            if (!Bstrcasecmp(parm->name, osd->cvars[i].c.name)) break;
1352 terminx 2073
 
2074
    if (i > -1)
2075
    {
4536 terminx 2076
        if (osd->cvars[i].c.type & CVAR_LOCKED)
1352 terminx 2077
        {
2078
            // sound the alarm
4536 terminx 2079
            OSD_Printf("Cvar \"%s\" is read only.\n",osd->cvars[i].c.name);
1352 terminx 2080
            return OSDCMD_OK;
2081
        }
1358 terminx 2082
 
4536 terminx 2083
        switch (osd->cvars[i].c.type&(CVAR_FLOAT|CVAR_DOUBLE|CVAR_INT|CVAR_UINT|CVAR_BOOL|CVAR_STRING))
1358 terminx 2084
        {
2085
        case CVAR_FLOAT:
1440 terminx 2086
        {
2087
            float val;
2088
            if (showval)
1357 terminx 2089
            {
4536 terminx 2090
                OSD_Printf("\"%s\" is \"%f\"\n%s: %s\n",osd->cvars[i].c.name,*(float *)osd->cvars[i].c.vptr,osd->cvars[i].c.name,(char *)osd->cvars[i].c.desc);
1440 terminx 2091
                return OSDCMD_OK;
2092
            }
1352 terminx 2093
 
1440 terminx 2094
            sscanf(parm->parms[0], "%f", &val);
1352 terminx 2095
 
4536 terminx 2096
            if (val < osd->cvars[i].c.min || val > osd->cvars[i].c.max)
1440 terminx 2097
            {
4536 terminx 2098
                OSD_Printf("%s value out of range\n",osd->cvars[i].c.name);
1440 terminx 2099
                return OSDCMD_OK;
1357 terminx 2100
            }
4536 terminx 2101
            *(float *)osd->cvars[i].c.vptr = val;
1440 terminx 2102
            if (!OSD_ParsingScript())
4536 terminx 2103
                OSD_Printf("%s %f",osd->cvars[i].c.name,val);
1440 terminx 2104
        }
2105
        break;
1358 terminx 2106
        case CVAR_DOUBLE:
1440 terminx 2107
        {
2108
            double val;
2109
            if (showval)
1357 terminx 2110
            {
4536 terminx 2111
                OSD_Printf("\"%s\" is \"%f\"\n%s: %s\n",osd->cvars[i].c.name,*(double *)osd->cvars[i].c.vptr,osd->cvars[i].c.name,(char *)osd->cvars[i].c.desc);
1440 terminx 2112
                return OSDCMD_OK;
2113
            }
1358 terminx 2114
 
1440 terminx 2115
            sscanf(parm->parms[0], "%lf", &val);
1358 terminx 2116
 
4536 terminx 2117
            if (val < osd->cvars[i].c.min || val > osd->cvars[i].c.max)
1440 terminx 2118
            {
4536 terminx 2119
                OSD_Printf("%s value out of range\n",osd->cvars[i].c.name);
1440 terminx 2120
                return OSDCMD_OK;
1358 terminx 2121
            }
4536 terminx 2122
            *(double *)osd->cvars[i].c.vptr = val;
1440 terminx 2123
            if (!OSD_ParsingScript())
4536 terminx 2124
                OSD_Printf("%s %f",osd->cvars[i].c.name,val);
1440 terminx 2125
        }
2126
        break;
1358 terminx 2127
        case CVAR_INT:
2128
        case CVAR_UINT:
2129
        case CVAR_BOOL:
1440 terminx 2130
        {
2131
            int32_t val;
2132
            if (showval)
1358 terminx 2133
            {
4536 terminx 2134
                OSD_Printf("\"%s\" is \"%d\"\n%s: %s\n",osd->cvars[i].c.name,*(int32_t *)osd->cvars[i].c.vptr,osd->cvars[i].c.name,(char *)osd->cvars[i].c.desc);
1440 terminx 2135
                return OSDCMD_OK;
2136
            }
1352 terminx 2137
 
2374 helixhorne 2138
            val = Batoi(parm->parms[0]);
4536 terminx 2139
            if (osd->cvars[i].c.type & CVAR_BOOL) val = val != 0;
1352 terminx 2140
 
4536 terminx 2141
            if (val < osd->cvars[i].c.min || val > osd->cvars[i].c.max)
1440 terminx 2142
            {
4536 terminx 2143
                OSD_Printf("%s value out of range\n",osd->cvars[i].c.name);
1440 terminx 2144
                return OSDCMD_OK;
1357 terminx 2145
            }
4536 terminx 2146
            *(int32_t *)osd->cvars[i].c.vptr = val;
1440 terminx 2147
            if (!OSD_ParsingScript())
4536 terminx 2148
                OSD_Printf("%s %d",osd->cvars[i].c.name,val);
1440 terminx 2149
        }
2150
        break;
1358 terminx 2151
        case CVAR_STRING:
1440 terminx 2152
        {
2153
            if (showval)
1357 terminx 2154
            {
4536 terminx 2155
                OSD_Printf("\"%s\" is \"%s\"\n%s: %s\n",osd->cvars[i].c.name,(char *)osd->cvars[i].c.vptr,osd->cvars[i].c.name, (char *)osd->cvars[i].c.desc);
1440 terminx 2156
                return OSDCMD_OK;
2157
            }
1355 terminx 2158
 
4536 terminx 2159
            Bstrncpy((char *)osd->cvars[i].c.vptr, parm->parms[0], osd->cvars[i].c.max-1);
2160
            ((char *)osd->cvars[i].c.vptr)[osd->cvars[i].c.max-1] = 0;
1440 terminx 2161
            if (!OSD_ParsingScript())
4536 terminx 2162
                OSD_Printf("%s %s",osd->cvars[i].c.name,(char *)osd->cvars[i].c.vptr);
1440 terminx 2163
        }
2164
        break;
1358 terminx 2165
        default:
4702 terminx 2166
            EDUKE32_UNREACHABLE_SECTION(break);
1358 terminx 2167
        }
3757 terminx 2168
 
2169
#ifdef USE_OPENGL
2170
        if (!OSD_ParsingScript())
2171
        {
4536 terminx 2172
            switch (osd->cvars[i].c.type&(CVAR_RESTARTVID|CVAR_INVALIDATEALL|CVAR_INVALIDATEART))
3757 terminx 2173
            {
2174
            case CVAR_RESTARTVID:
2175
                osdcmd_restartvid(NULL);
2176
                break;
3758 terminx 2177
            case CVAR_INVALIDATEALL:
3765 terminx 2178
                gltexinvalidatetype(INVALIDATE_ALL);
3758 terminx 2179
            case CVAR_INVALIDATEART:
3765 terminx 2180
                gltexinvalidatetype(INVALIDATE_ART);
3757 terminx 2181
#ifdef POLYMER
2182
                if (getrendermode() == REND_POLYMER)
2183
                    polymer_texinvalidate();
2184
#endif
2185
                break;
2186
            }
2187
        }
2188
#endif
1352 terminx 2189
    }
1358 terminx 2190
 
1355 terminx 2191
    if (!OSD_ParsingScript())
2192
        OSD_Printf("\n");
1358 terminx 2193
 
1352 terminx 2194
    return OSDCMD_OK;
2195
}
2196
 
4213 helixhorne 2197
void OSD_WriteAliases(FILE *fp)
2198
{
2199
    symbol_t *symb;
2200
    for (symb=symbols; symb!=NULL; symb=symb->next)
2201
        if (symb->func == (void *)OSD_ALIAS)
2202
            Bfprintf(fp, "alias \"%s\" \"%s\"\n", symb->name, symb->help);
2203
}
2204
 
1358 terminx 2205
void OSD_WriteCvars(FILE *fp)
1355 terminx 2206
{
2207
    uint32_t i;
2208
 
1625 terminx 2209
    if (!fp)
2210
        return;
2211
 
4536 terminx 2212
    for (i=0; i<osd->numcvars; i++)
1355 terminx 2213
    {
4536 terminx 2214
        if (!(osd->cvars[i].c.type & CVAR_NOSAVE) && OSD_CvarModified(&osd->cvars[i]))
2215
            switch (osd->cvars[i].c.type&(CVAR_FLOAT|CVAR_DOUBLE|CVAR_INT|CVAR_UINT|CVAR_BOOL|CVAR_STRING))
1762 terminx 2216
            {
1625 terminx 2217
            case CVAR_FLOAT:
4536 terminx 2218
                fprintf(fp,"%s \"%f\"\n",osd->cvars[i].c.name,*(float *)osd->cvars[i].c.vptr);
1625 terminx