emu: added console commands to reset ZX virtual keyboard and AY
[zymosis.git] / src / ZXEmuT / jimapi.c
blobad0a157f411bc932b5b8c8ff22ceacb497f4234f
1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2022 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 #include <dirent.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
28 #include "jimapi.h"
29 #include "libvideo/video.h"
30 #include "console.h"
31 #include "debugger.h"
32 #include "memview.h"
33 #include "sprview.h"
34 #include "emuutils.h"
35 #include "lssnap.h"
36 #include "tapes.h"
37 #include "snd_alsa.h"
38 #include "zxkeyinfo.h"
39 #include "emuexec.h"
41 #include "libboots/libboots.h"
44 ////////////////////////////////////////////////////////////////////////////////
45 #define JIMAPI_FN(name) static int jim_##name (Jim_Interp *interp, int argc, Jim_Obj *const *argv)
46 #define JIMAPI_REGISTER(name) Jim_CreateCommand(jim, #name, jim_##name, NULL, NULL)
49 ////////////////////////////////////////////////////////////////////////////////
50 #include "jimapi_utils.c"
51 #include "jimapi_sdlkeys.c"
54 ////////////////////////////////////////////////////////////////////////////////
55 // consetstr
56 JIMAPI_FN(consetstr) {
57 if (argc != 2) {
58 Jim_WrongNumArgs(interp, 1, argv, "string");
59 return JIM_ERR;
61 conSetInputString(Jim_String(argv[1]));
62 Jim_SetResultBool(interp, 1);
63 return JIM_OK;
67 // cputs
68 JIMAPI_FN(cputs) {
69 if (argc < 2) {
70 Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
71 return JIM_ERR;
73 int argp = 1;
74 int donl = 1;
75 if (Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) { donl = 0; ++argp; }
76 for (; argp < argc; ++argp) cprintf("%s", Jim_String(argv[argp]));
77 if (donl) cprintf("\n");
78 Jim_SetResultBool(interp, 1);
79 return JIM_OK;
83 // errputs
84 JIMAPI_FN(errputs) {
85 if (argc < 2) {
86 Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
87 return JIM_ERR;
89 int argp = 1;
90 int donl = 1;
91 if (Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) { donl = 0; ++argp; }
92 for (; argp < argc; ++argp) cprintf("%s", Jim_String(argv[argp]));
93 if (donl) cprintf("\n");
94 // and now to stderr
95 for (; argp < argc; ++argp) fprintf(stderr, "%s", Jim_String(argv[argp]));
96 if (donl) fprintf(stderr, "\n");
97 Jim_SetResultBool(interp, 1);
98 return JIM_OK;
102 // load name
103 JIMAPI_FN(load) {
104 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
105 if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
106 jimEvalFile(Jim_String(argv[1]), 0);
107 Jim_SetResultBool(interp, 1);
108 return JIM_OK;
111 // softload name
112 // won't fail if the file is absent
113 JIMAPI_FN(softload) {
114 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
115 if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
116 jimEvalFile(Jim_String(argv[1]), 1);
117 Jim_SetResultBool(interp, 1);
118 return JIM_OK;
122 ////////////////////////////////////////////////////////////////////////////////
123 // vid_scale num
124 JIMAPI_FN(vid_scale) {
125 if (jimapiWantsCompletion(interp, argc, argv)) {
126 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
127 //char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "keep", NULL);
128 jimapiStrAppendAbbrev(interp, res, "");
129 //free(a0);
130 jimapiAppendRestArgs(res, 2);
131 Jim_SetResult(interp, res);
132 return JIM_OK;
135 if (argc > 2) {
136 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
137 return JIM_ERR;
140 // return old value
141 Jim_SetResultInt(interp, vidScale);
143 // set new value
144 if (argc > 1) {
145 int newval = jimGetIntVal(interp, argv[1]);
146 if (newval == JIM_INVALID_INTVAL) {
147 jim_SetResStrf(interp, "%s: invalid numeric value: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
148 return JIM_ERR;
150 if (newval < 1 || newval > 4) {
151 jim_SetResStrf(interp, "%s: scale value out of bounds: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
152 return JIM_ERR;
154 vidScale = newval;
155 updateScale();
158 return JIM_OK;
162 ////////////////////////////////////////////////////////////////////////////////
163 // vid_rescaler num
164 JIMAPI_FN(vid_rescaler) {
165 if (jimapiWantsCompletion(interp, argc, argv)) {
166 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
167 //char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "keep", NULL);
168 jimapiStrAppendAbbrev(interp, res, "");
169 //free(a0);
170 jimapiAppendRestArgs(res, 2);
171 Jim_SetResult(interp, res);
172 return JIM_OK;
175 if (argc > 2) {
176 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
177 return JIM_ERR;
180 // return old value
181 Jim_SetResultInt(interp, vid_scaler_type);
183 // set new value
184 if (argc > 1) {
185 int newval = jimGetIntVal(interp, argv[1]);
186 if (newval == JIM_INVALID_INTVAL) {
187 jim_SetResStrf(interp, "%s: invalid numeric value: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
188 return JIM_ERR;
191 if (newval < 0 || newval >= VID_SCALER_MAX) {
192 jim_SetResStrf(interp, "%s: scale value out of bounds: '%s' (max is %d)",
193 Jim_String(argv[0]), Jim_String(argv[1]), VID_SCALER_MAX-1);
194 return JIM_ERR;
196 vid_scaler_type = newval;
199 return JIM_OK;
203 // quit
204 JIMAPI_FN(quit) {
205 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
206 //if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "no args expected"); return JIM_ERR; }
207 postQuitMessage();
208 Jim_SetResultBool(interp, 1);
209 return JIM_OK;
213 // reset [forced] [model] [issue] [memory] [trdos]
214 // plus2
215 // 48k: [issue2|issue3|2|3]
216 // pentagon: [128|512|1024]
217 JIMAPI_FN(reset) {
218 int was_penta = 0;
220 if (jimapiWantsCompletion(interp, argc, argv)) {
221 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
222 if (argc == 1) Jim_AppendString(interp, res, " ", -1);
223 for (int f = 1; f < argc; ++f) {
224 char *a0;
225 if (was_penta) {
226 a0 = completeAbbrev(Jim_String(argv[f]), "48k", "pentagon", "scorpion", "trdos", "forced", NULL);
227 } else {
228 a0 = completeAbbrev(Jim_String(argv[f]), "48k", "128k", "plus2", "plus2a", "plus3", "pentagon", "scorpion", "issue2", "issue3", "trdos", "forced", NULL);
229 if (strEqu(a0, "pentagon")) was_penta = 1;
231 jimapiStrAppendAbbrev(interp, res, a0);
232 free(a0);
234 Jim_SetResult(interp, res);
235 return JIM_OK;
238 int model = -1, forced = 0, issue = optZXIssue, pmem = -1/*128*//*zxPentagonMemory*/, trdos = 0;
240 //if (argc < 1) { Jim_WrongNumArgs(interp, 1, argv, "string"); return JIM_ERR; }
241 for (int f = 1; f < argc; ++f) {
242 const char *a0;
243 long val;
244 if (was_penta) {
245 a0 = parseAbbrev(Jim_String(argv[f]), "48k", "pentagon", "scorpion", NULL);
246 } else {
247 a0 = parseAbbrev(Jim_String(argv[f]), "48k", "128k", "plus2", "plus2a", "plus3", "pentagon", "scorpion", NULL);
249 if (a0 != NULL) {
250 if (model < 0) {
251 if (strEqu(a0, "48k")) model = ZX_MACHINE_48K;
252 else if (strEqu(a0, "128k")) model = ZX_MACHINE_128K;
253 else if (strEqu(a0, "plus2")) model = ZX_MACHINE_PLUS2;
254 else if (strEqu(a0, "plus2a")) model = ZX_MACHINE_PLUS2A;
255 else if (strEqu(a0, "plus3")) model = ZX_MACHINE_PLUS3;
256 else if (strEqu(a0, "pentagon")) {
257 model = ZX_MACHINE_PENTAGON;
258 if (pmem < 0) pmem = 128;
259 was_penta = 1;
260 } else if (strEqu(a0, "scorpion")) model = ZX_MACHINE_SCORPION;
261 continue;
262 } else {
263 jim_SetResStrf(interp, "%s: duplicate model name: '%s'", Jim_String(argv[0]), Jim_String(argv[f]));
264 return JIM_ERR;
268 if ((a0 = parseAbbrev(Jim_String(argv[f]), "forced", NULL)) != NULL) {
269 forced = 1;
270 continue;
273 if ((a0 = parseAbbrev(Jim_String(argv[f]), "trdos", NULL)) != NULL) {
274 trdos = 1;
275 continue;
278 if ((a0 = parseAbbrev(Jim_String(argv[f]), "issue2", "issue3", NULL)) != NULL) {
279 issue = a0[5]-'0'-2;
280 continue;
283 if (Jim_GetLong(interp, argv[f], &val) == JIM_OK) {
284 if (val == 2 || val == 3) { issue = val-2; continue; }
285 if (val == 128 || val == 512 || val == 1024) { pmem = val; continue; }
288 jim_SetResStrf(interp, "%s: invalid option: '%s'", Jim_String(argv[0]), Jim_String(argv[f]));
289 return JIM_ERR;
292 if (model < 0) model = zxModel;
293 if (pmem < 0) pmem = zxPentagonMemory;
294 if (model == ZX_MACHINE_PENTAGON && pmem != zxPentagonMemory) forced = 1;
296 optZXIssue = issue;
297 zxPentagonMemory = pmem;
298 emuSetModel(model, forced);
299 emuReset(trdos);
301 switch (zxModel) {
302 case ZX_MACHINE_48K: jim_SetResStrf(interp, "48k (issue %d)", optZXIssue+2); break;
303 case ZX_MACHINE_128K: Jim_SetResultString(interp, "128k", -1); break;
304 case ZX_MACHINE_PLUS2: Jim_SetResultString(interp, "128k+2", -1); break;
305 case ZX_MACHINE_PLUS2A: Jim_SetResultString(interp, "128k+2a", -1); break;
306 case ZX_MACHINE_PLUS3: Jim_SetResultString(interp, "128k+3", -1); break;
307 case ZX_MACHINE_PENTAGON: jim_SetResStrf(interp, "pentagon%d", zxPentagonMemory); break;
308 case ZX_MACHINE_SCORPION: Jim_SetResultString(interp, "scorpion", -1); break;
309 default: Jim_SetResultBool(interp, 0); break;
311 return JIM_OK;
315 // model
316 JIMAPI_FN(model) {
317 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
318 if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "too many args"); return JIM_ERR; }
319 switch (zxModel) {
320 case ZX_MACHINE_48K: jim_SetResStrf(interp, "48k (issue %d), %d tstates per frame", optZXIssue+2, machineInfo.tsperframe); break;
321 case ZX_MACHINE_128K: jim_SetResStrf(interp, "128k, %d tstates per frame", machineInfo.tsperframe); break;
322 case ZX_MACHINE_PLUS2: jim_SetResStrf(interp, "128k+2, %d tstates per frame", machineInfo.tsperframe); break;
323 case ZX_MACHINE_PLUS2A: jim_SetResStrf(interp, "128k+2a, %d tstates per frame", machineInfo.tsperframe); break;
324 case ZX_MACHINE_PLUS3: jim_SetResStrf(interp, "128k+3, %d tstates per frame", machineInfo.tsperframe); break;
325 case ZX_MACHINE_PENTAGON: jim_SetResStrf(interp, "pentagon%d, %d tstates per frame", zxPentagonMemory, machineInfo.tsperframe); break;
326 case ZX_MACHINE_SCORPION: jim_SetResStrf(interp, "scorpion, %d tstates per frame", machineInfo.tsperframe); break;
327 default: Jim_SetResultString(interp, "unknown", -1); break;
329 return JIM_OK;
333 // nmi
334 JIMAPI_FN(nmi) {
335 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
336 if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "too many args"); return JIM_ERR; }
337 z80GenerateNMI = 1;
338 Jim_SetResultBool(interp, 1);
339 return JIM_OK;
343 // grab [set|reset|toggle]
344 JIMAPI_FN(grab) {
345 int v = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON);
346 int res = jim_onoff_option(&v, interp, argc, argv, "set", "reset", 1);
347 if (res != JIM_ERR) {
348 SDL_WM_GrabInput(v ? SDL_GRAB_ON : SDL_GRAB_OFF);
349 emuRealizeRealMouseCursorState();
351 return res;
355 // maxspeedugly [on|off|toogle]
356 JIMAPI_FN(maxspeedugly) {
357 int v = optMaxSpeedBadScreen;
358 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
359 optMaxSpeedBadScreen = v;
360 return res;
364 // fps [on|off|toogle]
365 JIMAPI_FN(fps) {
366 int v = optDrawFPS;
367 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
368 emuSetDrawFPS(v);
369 return res;
373 // trdos [on|off|toggle]
374 JIMAPI_FN(trdos) {
375 int da = !!optTRDOSenabled;
376 int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", 1);
377 if (!da) zxTRDOSpageout();
378 optTRDOSenabled = da;
379 return res;
383 // swapbuttons [on|off|toggle]
384 JIMAPI_FN(swapbuttons) {
385 int da = optKMouseSwapButtons;
386 int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", 1);
387 optKMouseSwapButtons = da;
388 return res;
392 //FIXME: separate to two commands
393 // kmouse [on|off|toggle|sens]
394 JIMAPI_FN(kmouse) {
396 int da = optKMouse;
397 int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", 1);
398 optKMouse = da;
399 return res;
401 int res = jim_AlphaArg(&optKMouse, &zxKMouseSpeed, interp, argc, argv);
402 if (zxKMouseSpeed < 1) zxKMouseSpeed = 1; else if (zxKMouseSpeed > 255) zxKMouseSpeed = 255;
403 return res;
407 // kspanish [on|off|toggle]
408 // toggles kempston mouse between strict (on) or normal (off)
409 JIMAPI_FN(kspanish) {
410 int da = optKMouseStrict;
411 int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", 1);
412 optKMouseStrict = da;
413 return res;
417 // kjoystick [on|off|toggle]
418 JIMAPI_FN(kjoystick) {
419 int da = optKJoystick;
420 int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", 1);
421 optKJoystick = da;
422 return res;
426 // speed [max|normal|toggle|percents|shade|noshade]
427 JIMAPI_FN(speed) {
428 if (!jimapiWantsCompletion(interp, argc, argv)) {
429 if (argc == 2 && strEquCI(Jim_String(argv[1]), "shade")) {
430 optSlowShade = 1;
431 Jim_SetResultBool(interp, 1);
432 return JIM_OK;
434 if (argc == 2 && strEquCI(Jim_String(argv[1]), "noshade")) {
435 optSlowShade = 0;
436 Jim_SetResultBool(interp, 1);
437 return JIM_OK;
439 // try number
440 if (argc == 2) {
441 int val = jimGetIntLitVal(interp, argv[1]);
442 if (val != JIM_INVALID_INTVAL) {
443 emuSetMaxSpeed(0);
444 if (val < 1) val = 1; else if (val > 1000) val = 1000;
445 emuSetSpeed(val);
446 if (val > 0) {
447 if (jimapiFromConsole(interp)) cprintf("speed: %d%%\n", optSpeed);
448 jim_SetResStrf(interp, "%d", optSpeed);
449 return JIM_OK;
455 int v = optMaxSpeed;
456 int res = jim_onoff_option(&v, interp, argc, argv, "max", "normal", 0);
457 emuSetMaxSpeed(v);
458 return res;
462 // pause [set|reset|toggle]
463 JIMAPI_FN(pause) {
464 int v = ((optPaused&PAUSE_PERMANENT_MASK) != 0);
465 int res = jim_onoff_option(&v, interp, argc, argv, "set", "reset", 1);
466 emuSetPaused(v ? PAUSE_PERMANENT_SET : PAUSE_PERMANENT_RESET);
467 return res;
471 // temppause [set|reset|toggle]
472 JIMAPI_FN(temppause) {
473 int v = ((optPaused&PAUSE_TEMPORARY_MASK) != 0);
474 int res = jim_onoff_option(&v, interp, argc, argv, "set", "reset", 1);
475 emuSetPaused(v ? PAUSE_TEMPORARY_SET : PAUSE_TEMPORARY_RESET);
476 return res;
480 // timings [early|late|toggle]
481 JIMAPI_FN(timings) {
482 int v = zxLateTimings;
483 int res = jim_onoff_option(&v, interp, argc, argv, "late", "early", 0);
484 emuSetLateTimings(v);
485 return res;
489 // console [show|hide|toggle|<alpha>]
490 JIMAPI_FN(console) {
491 return jim_AlphaArg(&conVisible, &conAlpha, interp, argc, argv);
495 // kbleds [on|off|toggle|<alpha>]
496 JIMAPI_FN(kbleds) {
497 return jim_AlphaArg(&optDrawKeyLeds, &klAlpha, interp, argc, argv);
501 // debugger [on|off|toggle|<alpha>]
502 //TODO: add 'debugger traps on|off' -- for optAllowZXEmuTraps
503 JIMAPI_FN(debugger) {
504 int da = debuggerActive;
505 int res = jim_AlphaArg(&da, &dbgAlpha, interp, argc, argv);
506 if (da) { memviewSetActive(0); sprviewSetActive(0); }
507 dbgSetActive(da);
508 return res;
512 // memview [on|off|toggle|hex|text|32|42|51|64|max|7bit|cp-866|cp-1251]
513 JIMAPI_FN(memview) {
514 if (jimapiWantsCompletion(interp, argc, argv)) {
515 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
516 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""),
517 "on", "off", "toggle",
518 "hex", "text",
519 "32", "42", "51", "64", "max",
520 "7bit", "cp866", "cp1251",
521 "blue", "red", "magenta", "green", "cyan",
522 "yellow", "white", "gray", "bright",
523 NULL);
524 jimapiStrAppendAbbrev(interp, res, a0);
525 free(a0);
526 jimapiAppendRestArgs(res, 2);
527 Jim_SetResult(interp, res);
528 return JIM_OK;
531 if (argc < 1) { Jim_WrongNumArgs(interp, 1, argv, "option"); return JIM_ERR; }
533 int onoff = -1;
534 int bright = -1;
536 for (int f = 1; f < argc; ++f) {
537 const char *a0 = parseAbbrev(Jim_String(argv[f]),
538 "on", "off", "tan", "ona", "toggle",
539 "hex", "text",
540 "32", "42", "51", "64", "max",
541 "7bit", "cp866", "cp1251",
542 "blue", "red", "magenta", "green", "cyan",
543 "yellow", "white", "gray", "grey", "bright",
544 NULL);
545 if (a0 != NULL) {
546 if (strEquCI(a0, "on") || strEquCI(a0, "tan")) onoff = 1;
547 else if (strEquCI(a0, "off") || strEquCI(a0, "ona")) onoff = 0;
548 else if (strEquCI(a0, "toggle")) onoff = !memviewActive;
549 else if (strEquCI(a0, "hex")) mv_viewmode = MV_MODE_HEX;
550 else if (strEquCI(a0, "text")) mv_viewmode = MV_MODE_TEXT;
551 else if (strEquCI(a0, "32")) mv_textwidth = 32;
552 else if (strEquCI(a0, "42")) mv_textwidth = 42;
553 else if (strEquCI(a0, "51")) mv_textwidth = 51;
554 else if (strEquCI(a0, "64")) mv_textwidth = 64;
555 else if (strEquCI(a0, "max")) mv_textwidth = MV_MAX_TEXT_WIDTH;
556 else if (strEquCI(a0, "7bit")) mv_encoding = MV_ENC_7BIT;
557 else if (strEquCI(a0, "cp866")) mv_encoding = MV_ENC_866;
558 else if (strEquCI(a0, "cp1251")) mv_encoding = MV_ENC_1251;
559 else if (strEquCI(a0, "blue")) { if (bright < 0) bright = 0; mv_textcolor = 1; }
560 else if (strEquCI(a0, "red")) { if (bright < 0) bright = 0; mv_textcolor = 2; }
561 else if (strEquCI(a0, "magenta")) { if (bright < 0) bright = 0; mv_textcolor = 3; }
562 else if (strEquCI(a0, "green")) { if (bright < 0) bright = 0; mv_textcolor = 4; }
563 else if (strEquCI(a0, "cyan")) { if (bright < 0) bright = 0; mv_textcolor = 5; }
564 else if (strEquCI(a0, "yellow")) { if (bright < 0) bright = 0; mv_textcolor = 6; }
565 else if (strEquCI(a0, "white")) { if (bright < 0) bright = 0; mv_textcolor = 7; }
566 else if (strEquCI(a0, "gray")) { if (bright < 0) bright = 0; mv_textcolor = 7; }
567 else if (strEquCI(a0, "grey")) { if (bright < 0) bright = 0; mv_textcolor = 7; }
568 else if (strEquCI(a0, "bright")) bright = 1;
569 else {
570 jim_SetResStrf(interp, "%s: invalid mode: '%s'", Jim_String(argv[0]), Jim_String(argv[f]));
571 return JIM_ERR;
573 } else {
574 int addr = jimGetIntValEx(interp, argv[f], 1/*allowpgaddr*/);
575 //FIXME: this check is wrong
576 //FIXME: write correct page parsing
577 if (addr >= 0 && addr < (zxMaxMemoryBank+4)<<14) {
578 mv_staddr = (uint32_t)addr;
579 continue;
581 jim_SetResStrf(interp, "%s: wtf is '%s'?", Jim_String(argv[0]), Jim_String(argv[f]));
582 return JIM_ERR;
586 if (bright >= 0) {
587 if (bright) mv_textcolor |= 8; else mv_textcolor &= 7;
590 if (onoff >= 0) {
591 if (onoff > 0) { dbgSetActive(0); sprviewSetActive(0); }
592 memviewSetActive(onoff);
595 Jim_SetResultInt(interp, memviewActive);
596 return JIM_OK;
600 // sprview [on|off|toggle]
601 JIMAPI_FN(sprview) {
602 if (jimapiWantsCompletion(interp, argc, argv)) {
603 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
604 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""),
605 "on", "off", "toggle",
606 NULL);
607 jimapiStrAppendAbbrev(interp, res, a0);
608 free(a0);
609 jimapiAppendRestArgs(res, 2);
610 Jim_SetResult(interp, res);
611 return JIM_OK;
614 if (argc < 1) { Jim_WrongNumArgs(interp, 1, argv, "option"); return JIM_ERR; }
616 int onoff = -1;
618 for (int f = 1; f < argc; ++f) {
619 const char *a0 = parseAbbrev(Jim_String(argv[f]),
620 "on", "off", "tan", "ona", "toggle",
621 NULL);
622 if (a0 != NULL) {
623 if (strEquCI(a0, "on") || strEquCI(a0, "tan")) onoff = 1;
624 else if (strEquCI(a0, "off") || strEquCI(a0, "ona")) onoff = 0;
625 else if (strEquCI(a0, "toggle")) onoff = !sprviewActive;
626 else {
627 jim_SetResStrf(interp, "%s: invalid mode: '%s'", Jim_String(argv[0]), Jim_String(argv[f]));
628 return JIM_ERR;
630 } else {
631 int addr = jimGetIntValEx(interp, argv[f], 1/*allowpgaddr*/);
632 //FIXME: this check is wrong
633 //FIXME: write correct page parsing
634 if (addr >= 0 && addr < (zxMaxMemoryBank+4)<<14) {
635 spr_staddr = (uint32_t)addr;
636 continue;
638 jim_SetResStrf(interp, "%s: wtf is '%s'?", Jim_String(argv[0]), Jim_String(argv[f]));
639 return JIM_ERR;
643 if (onoff >= 0) {
644 if (onoff > 0) { dbgSetActive(0); memviewSetActive(0); }
645 sprviewSetActive(onoff);
648 Jim_SetResultInt(interp, sprviewActive);
649 return JIM_OK;
653 // useplus3 [on|off|toggle]
654 JIMAPI_FN(useplus3) {
655 if (machineInfo.origContention) {
656 int v = machineInfo.usePlus3Contention;
657 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
658 if (machineInfo.usePlus3Contention != v) {
659 machineInfo.usePlus3Contention = v;
660 emuBuildContentionTable();
662 return res;
664 Jim_SetResultBool(interp, machineInfo.usePlus3Contention);
665 return JIM_OK;
669 // genuine [on|off|toggle]
670 JIMAPI_FN(genuine) {
671 int v = machineInfo.genuine;
672 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
673 if (machineInfo.genuine != v) {
674 machineInfo.genuine = v;
675 emuReset(0);
677 Jim_SetResultBool(interp, machineInfo.genuine);
678 return res;
682 // contention [on|off|toggle]
683 JIMAPI_FN(contention) {
684 if (machineInfo.origContention) {
685 int v = machineInfo.contention;
686 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
687 machineInfo.contention = v;
688 if (machineInfo.origIOContention) machineInfo.iocontention = v;
689 return res;
691 Jim_SetResultBool(interp, machineInfo.contention);
692 return JIM_OK;
696 // memcontention [on|off|toggle]
697 JIMAPI_FN(memcontention) {
698 if (machineInfo.origContention) {
699 int v = machineInfo.contention;
700 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
701 machineInfo.contention = v;
702 return res;
704 Jim_SetResultBool(interp, machineInfo.contention);
705 return JIM_OK;
709 // iocontention [on|off|toggle]
710 JIMAPI_FN(iocontention) {
711 if (machineInfo.origIOContention) {
712 int v = machineInfo.iocontention;
713 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
714 machineInfo.iocontention = v;
715 return res;
717 Jim_SetResultBool(interp, machineInfo.iocontention);
718 return JIM_OK;
722 // snow [on|off|toggle]
723 JIMAPI_FN(snow) {
724 int v = optEmulateSnow;
725 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
726 if (v != optEmulateSnow) {
727 optEmulateSnow = v;
728 memset(zxUlaSnow, 0, sizeof(zxUlaSnow));
729 zxWasUlaSnow = 0;
731 return res;
735 // noflic [on|off|toggle]
736 JIMAPI_FN(noflic) {
737 //int da = optNoFlic;
738 //int res = jim_onoff_option(&da, interp, argc, argv, "on", "off", "detect", 1);
740 if (jimapiWantsCompletion(interp, argc, argv)) {
741 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
742 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "on", "off", "detect", NULL);
743 jimapiStrAppendAbbrev(interp, res, a0);
744 free(a0);
745 jimapiAppendRestArgs(res, 2);
746 Jim_SetResult(interp, res);
747 return JIM_OK;
750 if (argc < 1 || argc > 2) { Jim_WrongNumArgs(interp, 1, argv, "string"); return JIM_ERR; }
751 if (argc > 1) {
752 const char *a0 = parseAbbrev(Jim_String(argv[1]), "on", "off", "detect", "tan", "ona", NULL);
753 if (a0 != NULL) {
754 if (strEqu(a0, "on") || strEqu(a0, "yes") || strEqu(a0, "tan")) optNoFlic = 1;
755 else if (strEqu(a0, "off") || strEqu(a0, "no") || strEqu(a0, "ona")) optNoFlic = 0;
756 else if (strEqu(a0, "detect")) optNoFlic = -1;
757 } else {
758 jim_SetResStrf(interp, "%s: invalid mode: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
759 return JIM_ERR;
761 } else {
762 if (jimapiFromConsole(interp)) cprintf("%s: %d\n", Jim_String(argv[0]), optNoFlic);
764 Jim_SetResultInt(interp, optNoFlic);
765 return JIM_OK;
769 // brightblack [on|off|toggle|value]
770 JIMAPI_FN(brightblack) {
771 const int da = optBrightBlack;
772 const int ovv = optBrightBlackValue;
773 int res = jim_AlphaArg(&optBrightBlack, &optBrightBlackValue, interp, argc, argv);
774 if (optBrightBlackValue < 0) optBrightBlackValue = 0; else if (optBrightBlackValue > 255) optBrightBlackValue = 255;
775 if (res == JIM_OK) {
776 if (optBrightBlack != da || optBrightBlackValue != ovv) {
777 if (optBrightBlack) {
778 zxPalette[8*3+0] = zxPalette[8*3+1] = zxPalette[8*3+2] = optBrightBlackValue;
779 } else {
780 zxPalette[8*3+0] = zxPalette[8*3+1] = zxPalette[8*3+2] = 0;
782 rebuildPalette();
785 return res;
789 // zxpalcolor index [#rrggbb]
790 JIMAPI_FN(zxpalcolor) {
791 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
792 if (argc < 2 || argc > 3) {
793 jim_SetResStrf(interp, "%s: expected index and optional #rrggbb color", Jim_String(argv[0]));
794 return JIM_ERR;
797 int idx = jimGetIntLitVal(interp, argv[1]);
798 if (idx < 0 || idx > 15) {
799 jim_SetResStrf(interp, "%s: invalid color index %s", Jim_String(argv[0]), Jim_String(argv[1]));
800 return JIM_ERR;
803 // return old color
804 char stbuf[64];
805 snprintf(stbuf, sizeof(stbuf), "#%02x%02x%02x", zxPalette[idx*3+0], zxPalette[idx*3+1], zxPalette[idx*3+2]);
806 Jim_SetResultString(interp, stbuf, -1);
807 if (jimapiFromConsole(interp)) {
808 cprintf("zx palette %d is %s\n", idx, stbuf);
811 // try to set new color
812 if (argc > 2) {
813 const char *cc = Jim_String(argv[2]);
814 uint32_t clr = 0;
815 if (cc[0] == '#') {
816 size_t slen = strlen(cc);
817 if (slen == 4) {
818 for (unsigned f = 1; f < 4; ++f) {
819 int dig = digitInBase(cc[f], 16);
820 if (dig < 0) { clr = 0xffffffffU; break; }
821 clr = clr*256u+((unsigned)dig)*16+(unsigned)dig;
823 } else if (slen == 7) {
824 for (unsigned f = 1; f < 7; ++f) {
825 int dig = digitInBase(cc[f], 16);
826 if (dig < 0) { clr = 0xffffffffU; break; }
827 clr = clr*16u+(unsigned)dig;
829 } else {
830 clr = 0xffffffffU;
832 } else {
833 clr = 0xffffffffU;
835 if (clr == 0xffffffffU) {
836 jim_SetResStrf(interp, "%s: invalid color value %s", Jim_String(argv[0]), cc);
837 return JIM_ERR;
839 zxPalette[idx*3+0] = (clr>>16)&0xffU;
840 zxPalette[idx*3+1] = (clr>>8)&0xffU;
841 zxPalette[idx*3+2] = clr&0xffU;
842 rebuildPalette();
844 return JIM_OK;
848 // fullscreen [on|off|toggle]
849 JIMAPI_FN(fullscreen) {
850 int v = optFullscreen;
851 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
852 if (v != optFullscreen) {
853 switchFullScreen();
854 emuFullScreenChanged();
856 return res;
860 // keyhelp [on|off|toggle]
861 JIMAPI_FN(keyhelp) {
862 return jim_onoff_option(&optKeyHelpVisible, interp, argc, argv, "on", "off", 1);
866 // allowother128 [on|off|toggle]
867 JIMAPI_FN(allowother128) {
868 return jim_onoff_option(&optAllowOther128, interp, argc, argv, "on", "off", 1);
872 // keymatrix [on|off|toggle]
873 JIMAPI_FN(keymatrix) {
874 return jim_onoff_option(&optEmulateMatrix, interp, argc, argv, "on", "off", 1);
878 // bad7ffd [on|off|toggle]
879 JIMAPI_FN(bad7ffd) {
880 return jim_onoff_option(&optFDas7FFD, interp, argc, argv, "on", "off", 1);
884 // ay [on|off|toggle]
885 JIMAPI_FN(ay) {
886 int prevAY = optAYEnabled;
887 int res = jim_onoff_option(&optAYEnabled, interp, argc, argv, "on", "off", 1);
888 if (!optAYEnabled && prevAY) emuResetAY();
889 return res;
893 // autofire
894 // [on|off|toggle]
895 // [hold num]
896 // [delay num]
897 // [key zxkeyname]
898 JIMAPI_FN(autofire) {
899 if (jimapiWantsCompletion(interp, argc, argv)) {
900 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
901 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "hold", "delay", "on", "off", "toggle", "key", NULL);
902 jimapiStrAppendAbbrev(interp, res, a0);
903 free(a0);
904 jimapiAppendRestArgs(res, 2);
905 Jim_SetResult(interp, res);
906 return JIM_OK;
909 const char *a0 = parseAbbrev(Jim_String(argv[1]), "hold", "delay", "on", "off", "toggle", "key", "query", NULL);
910 if (a0 == NULL) {
911 jim_SetResStrf(interp, "%s: invalid autofire command: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
912 Jim_SetResultBool(interp, 0);
913 return JIM_OK;
915 if (strEqu(a0, "on")) {
916 optAutofire = 1;
917 afireDown = 0;
918 afireLeft = 0;
919 } else if (strEqu(a0, "off")) {
920 optAutofire = 0;
921 } else if (strEqu(a0, "toggle")) {
922 optAutofire = !optAutofire;
923 afireDown = 0;
924 afireLeft = 0;
925 } else if (strEqu(a0, "hold") || strEqu(a0, "delay")) {
926 long val;
927 if (argc < 3 || Jim_GetLong(interp, argv[2], &val) != JIM_OK) {
928 cprintf("autofire: number expected for '%s'!", a0);
929 Jim_SetResultBool(interp, 0);
930 return JIM_OK;
932 if (a0[0] == 'h') {
933 optAutofireHold = (val < 1 ? 1 : val);
934 } else {
935 optAutofireDelay = (val < 0 ? 0 : val);
937 afireDown = 0;
938 afireLeft = 0;
939 } else if (strEqu(a0, "key")) {
940 int kn;
941 if (argc != 3 || (kn = zxFindKeyByName(Jim_String(argv[2]))) < 0) {
942 cprintf("autofire: zx key name expected for '%s'!", a0);
943 Jim_SetResultBool(interp, 0);
944 return JIM_OK;
946 afirePortBit = (zxKeyInfo[kn].port<<8)|zxKeyInfo[kn].mask;
947 } else if (strEqu(a0, "query")) {
948 int kn = zxFindKeyByWord(afirePortBit);
949 cprintf("autofire is %s, hold: %d, delay: %d, key: %s", (optAutofire ? "on" : "off"), optAutofireHold, optAutofireDelay, (kn >= 0 ? zxKeyInfo[kn].name : "unknown"));
951 Jim_SetResultBool(interp, 1);
952 return JIM_OK;
956 // usesound [on|off|toggle]
957 JIMAPI_FN(usesound) {
958 if (sndAllowUseToggle) {
959 int v = (sndSampleRate != 0);
960 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
961 if (v != (sndSampleRate != 0)) {
962 if (v) {
963 sndSampleRate = -1;
964 if (initSound() == 0) {
965 cprintf("ALSA: %dHz, %d channels, %d bps\n", sndSampleRate, sndBytesPerSample, sndChannels);
966 } else {
967 cprintf("WARNING: can't initialize sound!\n");
969 } else {
970 deinitSound();
971 sndSampleRate = 0;
974 return res;
976 jim_SetResStrf(interp, "%s: disabled", Jim_String(argv[0]));
977 return JIM_ERR;
981 // filter [off|tv2x]
982 JIMAPI_FN(filter) {
983 if (jimapiWantsCompletion(interp, argc, argv)) {
984 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
985 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "off", "none", "tv", NULL);
986 jimapiStrAppendAbbrev(interp, res, a0);
987 free(a0);
988 jimapiAppendRestArgs(res, 2);
989 Jim_SetResult(interp, res);
990 return JIM_OK;
993 if (argc > 1) {
994 const char *a0 = parseAbbrev(Jim_String(argv[1]), "off", "none", "tv", "forcetv", NULL);
995 if (a0 != NULL) {
996 if (strEqu(a0, "tv")) optTVScaler = 1;
997 else if (strEqu(a0, "forcetv")) optTVScaler = 2;
998 else optTVScaler = 0;
999 } else {
1000 jim_SetResStrf(interp, "%s: invalid filter: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
1001 return JIM_ERR;
1004 jim_SetResStrf(interp, "%s", (optTVScaler ? "tv" : "off"));
1005 return JIM_OK;
1009 // screenofs [none|0..16|speccy]
1010 JIMAPI_FN(screenofs) {
1011 if (jimapiWantsCompletion(interp, argc, argv)) {
1012 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1013 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "normal", "speccy", NULL);
1014 jimapiStrAppendAbbrev(interp, res, a0);
1015 free(a0);
1016 jimapiAppendRestArgs(res, 2);
1017 Jim_SetResult(interp, res);
1018 return JIM_OK;
1021 if (argc > 1) {
1022 const char *a0 = parseAbbrev(Jim_String(argv[1]), "none", "normal", "speccy", NULL);
1023 if (a0 != NULL) {
1024 if (strEqu(a0, "normal") || strEqu(a0, "none")) zxScreenOfs = 0;
1025 else if (strEqu(a0, "speccy")) zxScreenOfs = 4;
1026 } else {
1027 // try number
1028 long val;
1029 if (Jim_GetLong(interp, argv[1], &val) != JIM_OK) {
1030 jim_SetResStrf(interp, "%s: numeric value expected", Jim_String(argv[0]));
1031 return JIM_ERR;
1033 if (val < 0 || val > 16) {
1034 jim_SetResStrf(interp, "%s: numeric value in range [0..16] expected", Jim_String(argv[0]));
1035 return JIM_ERR;
1037 zxScreenOfs = val;
1041 switch (zxScreenOfs) {
1042 case 0: Jim_SetResultString(interp, "normal", -1); break;
1043 case 8: Jim_SetResultString(interp, "speccy", -1); break;
1044 default: Jim_SetResultInt(interp, zxScreenOfs); break;
1046 return JIM_OK;
1050 // colormode [0..4]|normal|monochrome|green
1051 JIMAPI_FN(colormode) {
1052 if (jimapiWantsCompletion(interp, argc, argv)) {
1053 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1054 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""),
1055 "normal", "monochrome", "green", "yellow",
1056 "cyan", "magenta", "red",
1057 NULL);
1058 jimapiStrAppendAbbrev(interp, res, a0);
1059 free(a0);
1060 jimapiAppendRestArgs(res, 2);
1061 Jim_SetResult(interp, res);
1062 return JIM_OK;
1065 if (argc > 1) {
1066 const char *a0 = parseAbbrev(Jim_String(argv[1]),
1067 "normal", "monochrome", "green", "yellow",
1068 "cyan", "magenta", "red",
1069 NULL);
1070 if (a0 != NULL) {
1071 if (strEqu(a0, "normal")) vidColorMode = 0;
1072 else if (strEqu(a0, "monochrome")) vidColorMode = 1;
1073 else if (strEqu(a0, "green")) vidColorMode = 2;
1074 else if (strEqu(a0, "yellow")) vidColorMode = 3;
1075 else if (strEqu(a0, "cyan")) vidColorMode = 4;
1076 else if (strEqu(a0, "magenta")) vidColorMode = 5;
1077 else if (strEqu(a0, "red")) vidColorMode = 6;
1078 } else {
1079 // try number
1080 long val;
1081 if (Jim_GetLong(interp, argv[1], &val) != JIM_OK) {
1082 jim_SetResStrf(interp, "%s: numeric value expected", Jim_String(argv[0]));
1083 return JIM_ERR;
1085 if (val < 0 || val > 6+8) {
1086 jim_SetResStrf(interp, "%s: numeric value in range [0..4] expected", Jim_String(argv[0]));
1087 return JIM_ERR;
1089 vidColorMode = val;
1093 switch (vidColorMode) {
1094 case 0: Jim_SetResultString(interp, "normal", -1); break;
1095 case 1: Jim_SetResultString(interp, "monochrome", -1); break;
1096 case 2: Jim_SetResultString(interp, "green", -1); break;
1097 default: Jim_SetResultInt(interp, vidColorMode); break;
1099 return JIM_OK;
1103 // brightborder [0|5|6|7]
1104 JIMAPI_FN(brightborder) {
1105 if (jimapiWantsCompletion(interp, argc, argv)) {
1106 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1107 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "off", NULL);
1108 jimapiStrAppendAbbrev(interp, res, a0);
1109 free(a0);
1110 jimapiAppendRestArgs(res, 2);
1111 Jim_SetResult(interp, res);
1112 return JIM_OK;
1115 if (argc > 1) {
1116 const char *a0 = parseAbbrev(Jim_String(argv[1]), "off", NULL);
1117 if (a0 != NULL) {
1118 if (strEqu(a0, "off")) optBrightBorder = 0;
1119 } else {
1120 // try number
1121 long val;
1122 if (Jim_GetLong(interp, argv[1], &val) != JIM_OK) {
1123 jim_SetResStrf(interp, "%s: numeric value expected", Jim_String(argv[0]));
1124 return JIM_ERR;
1126 if (val < 5 || val > 7) {
1127 jim_SetResStrf(interp, "%s: numeric value in range [5..7] expected", Jim_String(argv[0]));
1128 return JIM_ERR;
1130 optBrightBorder = val;
1134 switch (optBrightBorder) {
1135 case 0: Jim_SetResultString(interp, "off", -1); break;
1136 default: Jim_SetResultInt(interp, optBrightBorder); break;
1138 return JIM_OK;
1142 // sound [off|beeper|ay|on|volume]
1143 // sound volume [ay|beeper] [percents]
1144 // sound ay <mono|acb|abc|on|off|query>
1145 // sound filter <tv|beeper|none>
1146 // sound restart
1147 JIMAPI_FN(sound) {
1148 int isvol = 0;
1150 if (jimapiWantsCompletion(interp, argc, argv)) {
1151 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1152 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "on", "off", "ay", "beeper", "volume", "filter", "restart", NULL);
1153 jimapiStrAppendAbbrev(interp, res, a0);
1154 const char *a5 = parseAbbrev(a0, "ay", "volume", "filter", NULL);
1155 if (a5 && strEqu(a5, "volume")) {
1156 if (argc > 2) {
1157 free(a0);
1158 a0 = completeAbbrev(Jim_String(argv[2]), "ay", "beeper", NULL);
1159 jimapiStrAppendAbbrev(interp, res, a0);
1160 jimapiAppendRestArgs(res, 3);
1161 } else {
1162 jimapiAppendRestArgs(res, 2);
1164 } else if (a5 && strEqu(a5, "ay")) {
1165 free(a0);
1166 a0 = completeAbbrev((argc > 2 ? Jim_String(argv[2]) : ""), "on", "off", "mono", "acb", "abc", "melodik", "pentagon", "query", NULL);
1167 jimapiStrAppendAbbrev(interp, res, a0);
1168 jimapiAppendRestArgs(res, 3);
1169 } else if (a5 && strEqu(a5, "filter")) {
1170 free(a0);
1171 a0 = completeAbbrev((argc > 2 ? Jim_String(argv[2]) : ""), "tv", "beeper", "none", "query", NULL);
1172 jimapiStrAppendAbbrev(interp, res, a0);
1173 jimapiAppendRestArgs(res, 3);
1174 } else {
1175 jimapiAppendRestArgs(res, 2);
1177 free(a0);
1178 Jim_SetResult(interp, res);
1179 return JIM_OK;
1182 if (argc > 1) {
1183 const char *a0 = parseAbbrev(Jim_String(argv[1]), "off", "no", "beeper", "ay", "on", "yes", "disabled", "enabled", "volume", "filter", "restart", NULL);
1184 if (a0 != NULL) {
1185 if (strEqu(a0, "off") || strEqu(a0, "ona") || strEqu(a0, "disabled")) {
1186 optSoundBeeper = 0;
1187 optSoundAY = 0;
1188 } else if (strEqu(a0, "filter")) {
1189 if (argc > 2) {
1190 const char *a3 = parseAbbrev(Jim_String(argv[2]), "tv", "beeper", "default", "flat", "crisp", "query", NULL);
1191 if (a3) {
1192 if (strEqu(a3, "tv")) soundSetFilter(SOUND_FILTER_TV);
1193 else if (strEqu(a3, "beeper")) soundSetFilter(SOUND_FILTER_BEEPER);
1194 else if (strEqu(a3, "none")) soundSetFilter(SOUND_FILTER_DEFAULT);
1195 else if (strEqu(a3, "default")) soundSetFilter(SOUND_FILTER_DEFAULT);
1196 else if (strEqu(a3, "flat")) soundSetFilter(SOUND_FILTER_FLAT);
1197 else if (strEqu(a3, "crisp")) soundSetFilter(SOUND_FILTER_CRISP);
1200 const char *fltname;
1201 switch (soundGetFilter()) {
1202 case SOUND_FILTER_TV: fltname = "tv"; break;
1203 case SOUND_FILTER_BEEPER: fltname = "beeper"; break;
1204 case SOUND_FILTER_DEFAULT: fltname = "default"; break;
1205 case SOUND_FILTER_FLAT: fltname = "flat"; break;
1206 case SOUND_FILTER_CRISP: fltname = "crisp"; break;
1207 default: fltname = "fucked"; break;
1209 if (jimapiFromConsole(interp)) cprintf("sound filter: %s\n", fltname);
1210 jim_SetResStrf(interp, "%s", fltname);
1211 return JIM_OK;
1212 } else if (strEqu(a0, "on") || strEqu(a0, "tan") || strEqu(a0, "enabled")) {
1213 optSoundBeeper = 1;
1214 optSoundAY = 1;
1215 } else if (strEqu(a0, "beeper")) {
1216 optSoundBeeper = 1;
1217 optSoundAY = 0;
1218 } else if (strEqu(a0, "ay")) {
1219 if (argc > 2) {
1220 const char *a3 = parseAbbrev(Jim_String(argv[2]), "mono", "acb", "abc", "melodik", "pentagon", "query", NULL);
1221 if (a3) {
1222 if (strEqu(a3, "mono")) soundSetAYStereo(SOUND_STEREO_AY_NONE);
1223 else if (strEqu(a3, "acb") || strEqu(a3, "melodik")) soundSetAYStereo(SOUND_STEREO_AY_ACB);
1224 else if (strEqu(a3, "abc") || strEqu(a3, "pentagon")) soundSetAYStereo(SOUND_STEREO_AY_ABC);
1226 const char *fltname;
1227 switch (soundGetAYStereo()) {
1228 case SOUND_STEREO_AY_NONE: fltname = "mono"; break;
1229 case SOUND_STEREO_AY_ACB: fltname = "acb"; break;
1230 case SOUND_STEREO_AY_ABC: fltname = "abc"; break;
1231 default: fltname = "wutafuck"; break;
1233 if (jimapiFromConsole(interp)) cprintf("AY mode: %s\n", fltname);
1234 jim_SetResStrf(interp, "%s", fltname);
1235 return JIM_OK;
1237 optSoundBeeper = 0;
1238 optSoundAY = 1;
1239 } else if (strEqu(a0, "volume")) {
1240 isvol = 1;
1241 if (argc > 2) {
1242 int doRestart = 0;
1243 long val = 0;
1244 if ((a0 = parseAbbrev(Jim_String(argv[2]), "beeper", "ay", NULL)) != NULL) {
1245 // beeper or ay volume
1246 if (argc > 3) {
1247 if (Jim_GetLong(interp, argv[3], &val) != JIM_OK) {
1248 jim_SetResStrf(interp, "%s: invalid sound volume: '%s'", Jim_String(argv[0]), Jim_String(argv[3]));
1249 return JIM_ERR;
1251 if (val < 0) val = 0; else if (val > 500) val = 500;
1253 if (strEqu(a0, "beeper")) {
1254 if (argc > 3) {
1255 doRestart = (optSoundVolumeBeeper != val);
1256 optSoundVolumeBeeper = val;
1258 jim_SetResStrf(interp, "%d", optSoundVolumeBeeper);
1259 } else if (strEqu(a0, "ay")) {
1260 if (argc > 3) {
1261 doRestart = (optSoundVolumeAY != val);
1262 optSoundVolumeAY = val;
1264 jim_SetResStrf(interp, "%d", optSoundVolumeAY);
1266 } else {
1267 // overal volume
1268 if (Jim_GetLong(interp, argv[2], &val) != JIM_OK) {
1269 jim_SetResStrf(interp, "%s: invalid sound volume: '%s'", Jim_String(argv[0]), Jim_String(argv[3]));
1270 return JIM_ERR;
1272 if (val < 0) val = 0; else if (val > 500) val = 500;
1273 doRestart = (optSoundVolume != val);
1274 optSoundVolume = val;
1275 jim_SetResStrf(interp, "%d", optSoundVolume);
1277 if (doRestart) soundApplyNewVolumes();
1278 } else {
1279 jim_SetResStrf(interp, "%d", optSoundVolume);
1281 if (jimapiFromConsole(interp)) cprintf("sound volume: %d%% (beeper:%d%%; ay:%d%%)\n", optSoundVolume, optSoundVolumeBeeper, optSoundVolumeAY);
1282 } else if (strEqu(a0, "restart")) {
1283 if (jimapiFromConsole(interp)) cprintf("restarting sound system...\n");
1284 soundFullRestart();
1285 Jim_SetResultBool(interp, 1);
1286 return JIM_OK;
1288 } else {
1289 jim_SetResStrf(interp, "%s: invalid sound mode: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
1290 return JIM_ERR;
1293 Jim_SetResultBool(interp, 1);
1295 if (!isvol) {
1296 if (optSoundBeeper && optSoundAY) Jim_SetResultString(interp, "on", -1);
1297 else if (optSoundBeeper) Jim_SetResultString(interp, "beeper", -1);
1298 else if (optSoundAY) Jim_SetResultString(interp, "ay", -1);
1299 else Jim_SetResultString(interp, "off", -1);
1300 //jim_SetResStrf(interp, "%s", (optSoundBeeper ? (optSoundAY ? "on" : "beeper") : (optSoundAY ? "ay" : "off")));
1301 if (argc > 1 && jimapiFromConsole(interp)) cprintf("sound: %s\n", Jim_String(Jim_GetResult(interp)));
1303 return JIM_OK;
1307 // issue [2|3]
1308 JIMAPI_FN(issue) {
1309 if (jimapiWantsCompletion(interp, argc, argv)) {
1310 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1311 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "2", "3", NULL);
1312 jimapiStrAppendAbbrev(interp, res, a0);
1313 free(a0);
1314 jimapiAppendRestArgs(res, 2);
1315 Jim_SetResult(interp, res);
1316 return JIM_OK;
1319 long val = optZXIssue+2;
1320 if (argc < 1 || argc > 2) { Jim_WrongNumArgs(interp, 1, argv, "issue"); return JIM_ERR; }
1321 if (argc > 1) {
1322 if (Jim_GetLong(interp, argv[1], &val) != JIM_OK) {
1323 jim_SetResStrf(interp, "%s: issue number expected", Jim_String(argv[0]));
1324 return JIM_ERR;
1326 if (val < 2 || val > 3) {
1327 jim_SetResStrf(interp, "%s: invalid issue number: %d", Jim_String(argv[0]), (int)val);
1328 return JIM_ERR;
1331 optZXIssue = val-2;
1332 Jim_SetResultInt(interp, val);
1333 return JIM_OK;
1337 ////////////////////////////////////////////////////////////////////////////////
1338 // snapshot <load|save|clear|reset> [name]
1339 JIMAPI_FN(snapshot) {
1340 if (jimapiWantsCompletion(interp, argc, argv)) {
1341 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1342 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "load", "save", "clear", "setmodel", NULL);
1343 jimapiStrAppendAbbrev(interp, res, a0);
1344 const char *a1 = parseAbbrev(a0, "load", "save", "setmodel", NULL);
1345 if (a1 != NULL) {
1346 if (strEqu(a1, "setmodel")) {
1347 free(a0);
1348 a0 = completeAbbrev((argc > 2 ? Jim_String(argv[2]) : ""), "yes", "no", "on", "off", "toggle", NULL);
1349 jimapiStrAppendAbbrev(interp, res, a0);
1350 jimapiAppendRestArgs(res, 3);
1351 } else {
1352 // load/save
1353 free(a0);
1354 a0 = completeFilesWithExts((argc > 2 ? Jim_String(argv[2]) : ""), snapshotExtensions);
1355 jimapiStrAppendAbbrev(interp, res, a0);
1356 jimapiAppendRestArgs(res, 3);
1358 } else {
1359 jimapiAppendRestArgs(res, 2);
1361 free(a0);
1362 Jim_SetResult(interp, res);
1363 return JIM_OK;
1366 const char *a0;
1367 int res = 0;
1369 if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "action name"); return JIM_ERR; }
1370 if ((a0 = parseAbbrev(Jim_String(argv[1]), "load", "save", "clear", "reset", "setmodel", NULL)) == NULL) {
1371 jim_SetResStrf(interp, "%s: invalid action: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
1372 return JIM_ERR;
1375 if (strEqu(a0, "load")) {
1376 if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "action name"); return JIM_ERR; }
1377 res = (loadSnapshot(Jim_String(argv[2]), SNAPLOAD_ANY) == 0);
1378 if (res) cprintf("'%s' loaded\n", Jim_String(argv[2])); else cprintf("failed to load '%s'\n", Jim_String(argv[2]));
1379 } else if (strEqu(a0, "save")) {
1380 if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "action name"); return JIM_ERR; }
1381 res = (saveSnapshot(Jim_String(argv[2])) == 0);
1382 if (res) cprintf("'%s' saved\n", Jim_String(argv[2])); else cprintf("failed to save '%s'\n", Jim_String(argv[2]));
1383 } else if (strEqu(a0, "setmodel")) {
1384 //int v = optSnapSetModel, res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
1385 if (argc > 2) {
1386 if ((a0 = parseAbbrev(Jim_String(argv[2]), "on", "off", "yes", "no", "toggle", NULL)) != NULL) {
1387 if (strEqu(a0, "on") || strEqu(a0, "yes")) {
1388 optSnapSetModel = 1;
1389 } else if (strEqu(a0, "toggle")) {
1390 optSnapSetModel = !optSnapSetModel;
1391 } else {
1392 optSnapSetModel = 0;
1396 //optSnapSetModel = v;
1397 if (jimapiFromConsole(interp)) cprintf("optSnapSetModel: %d\n", optSnapSetModel);
1398 return JIM_OK;
1399 } else {
1400 if (zxSLT != NULL) { if (jimapiFromConsole(interp)) cprintf("snapshot cleared\n"); }
1401 lssnap_rzx_stop();
1402 lssnap_slt_clear();
1403 res = 1;
1405 Jim_SetResultBool(interp, res);
1406 return JIM_OK;
1410 ////////////////////////////////////////////////////////////////////////////////
1411 // rzx <stop>
1412 JIMAPI_FN(rzx) {
1413 if (jimapiWantsCompletion(interp, argc, argv)) {
1414 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1415 char *a0 = completeAbbrev((argc > 2 ? Jim_String(argv[2]) : ""), "stop", NULL);
1416 jimapiStrAppendAbbrev(interp, res, a0);
1417 free(a0);
1418 jimapiAppendRestArgs(res, 2);
1419 Jim_SetResult(interp, res);
1420 return JIM_OK;
1423 const char *a0;
1424 int res = 0;
1425 if (argc < 2) {
1426 //Jim_WrongNumArgs(interp, 1, argv, "action name");
1427 //return JIM_ERR;
1428 cprintf("%sRZX is playing now.\n", (zxRZX != NULL ? "" : "no "));
1429 Jim_SetResultBool(interp, 1);
1430 return JIM_OK;
1432 if ((a0 = parseAbbrev(Jim_String(argv[1]), "stop", NULL)) == NULL) {
1433 jim_SetResStrf(interp, "%s: invalid action: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
1434 return JIM_ERR;
1436 if (strEqu(a0, "stop")) {
1437 if (zxRZX != NULL) cprintf("RZX playback aborted!\n");
1438 lssnap_rzx_stop();
1439 res = 1;
1441 Jim_SetResultBool(interp, res);
1442 return JIM_OK;
1446 // peek addr [bank-not-yet]
1447 JIMAPI_FN(peek) {
1448 if (jimapiWantsCompletion(interp, argc, argv)) {
1449 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1450 jim_completeAddr(interp, res, argc, argv);
1451 Jim_SetResult(interp, res);
1452 return JIM_OK;
1455 int addr;
1456 if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "addr"); return JIM_ERR; }
1457 if ((addr = jim_AddrArg(interp, argv[0], argv[1])) < 0) return JIM_ERR;
1458 Jim_SetResultInt(interp, z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER));
1459 return JIM_OK;
1463 // wpeek addr [bank-not-yet]
1464 JIMAPI_FN(wpeek) {
1465 if (jimapiWantsCompletion(interp, argc, argv)) {
1466 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1467 jim_completeAddr(interp, res, argc, argv);
1468 Jim_SetResult(interp, res);
1469 return JIM_OK;
1472 int addr;
1473 uint16_t res;
1474 if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "addr"); return JIM_ERR; }
1475 if ((addr = jim_AddrArg(interp, argv[0], argv[1])) < 0) return JIM_ERR;
1476 res = z80.mem_read(&z80, addr, ZYM_MEMIO_OTHER);
1477 res |= ((uint16_t)z80.mem_read(&z80, (addr+1)&0xffff, ZYM_MEMIO_OTHER))<<8;
1478 Jim_SetResultInt(interp, res);
1479 return JIM_OK;
1483 // poke addr value
1484 JIMAPI_FN(poke) {
1485 if (jimapiWantsCompletion(interp, argc, argv)) {
1486 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1487 jim_completeAddr(interp, res, argc, argv);
1488 Jim_SetResult(interp, res);
1489 return JIM_OK;
1492 int addr, val;
1493 if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "addr"); return JIM_ERR; }
1494 if ((addr = jim_AddrArg(interp, argv[0], argv[1])) < 0) return JIM_ERR;
1495 if ((val = jim_BWArg(interp, argv[0], argv[2], 1)) < 0) return JIM_ERR;
1496 z80.mem_write(&z80, addr, val, ZYM_MEMIO_OTHER);
1497 Jim_SetResultBool(interp, 1);
1498 return JIM_OK;
1502 // wpoke addr value
1503 JIMAPI_FN(wpoke) {
1504 if (jimapiWantsCompletion(interp, argc, argv)) {
1505 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1506 jim_completeAddr(interp, res, argc, argv);
1507 Jim_SetResult(interp, res);
1508 return JIM_OK;
1511 int addr, val;
1512 if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "addr"); return JIM_ERR; }
1513 if ((addr = jim_AddrArg(interp, argv[0], argv[1])) < 0) return JIM_ERR;
1514 if ((val = jim_BWArg(interp, argv[0], argv[2], 2)) < 0) return JIM_ERR;
1515 z80.mem_write(&z80, addr, val&0xff, ZYM_MEMIO_OTHER);
1516 z80.mem_write(&z80, (addr+1)&0xffff, (val>>8)&0xff, ZYM_MEMIO_OTHER);
1517 Jim_SetResultBool(interp, 1);
1518 return JIM_OK;
1522 // scrattrfill value
1523 JIMAPI_FN(scrattrfill) {
1524 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
1526 long val;
1527 if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "value"); return JIM_ERR; }
1528 if ((val = jim_BWArg(interp, argv[0], argv[1], 1)) < 0) return JIM_ERR;
1529 for (int f = 22528; f < 22528+768; ++f) z80.mem_write(&z80, f, val&0xff, ZYM_MEMIO_OTHER);
1530 Jim_SetResultBool(interp, 1);
1531 return JIM_OK;
1535 ////////////////////////////////////////////////////////////////////////////////
1536 #include "autotape_128.c"
1537 #include "autotape_48.c"
1538 #include "autotape_p128.c"
1539 #include "autotape_p2a.c"
1540 #include "autotape_p3.c"
1543 static void tape_do_autoload (void) {
1544 FILE *fl = NULL;
1545 switch (zxModel) {
1546 case ZX_MACHINE_48K: fl = fmemopen((void *)autotape_48, sizeof(autotape_48), "rb"); break;
1547 case ZX_MACHINE_128K:
1548 case ZX_MACHINE_PLUS2:
1549 fl = fmemopen((void *)autotape_128, sizeof(autotape_128), "rb");
1550 break;
1551 case ZX_MACHINE_PLUS2A:
1552 fl = fmemopen((void *)autotape_p2a, sizeof(autotape_p2a), "rb");
1553 break;
1554 case ZX_MACHINE_PLUS3:
1555 fl = fmemopen((void *)autotape_p3, sizeof(autotape_p3), "rb");
1556 break;
1557 case ZX_MACHINE_PENTAGON: fl = fmemopen((void *)autotape_p128, sizeof(autotape_p128), "rb"); break;
1558 case ZX_MACHINE_SCORPION: /* nothing */
1559 default: return;
1561 if (fl != NULL) {
1562 szxLoad(fl);
1563 fclose(fl);
1568 ////////////////////////////////////////////////////////////////////////////////
1569 // tape cmd [args...]
1570 // insert filename
1571 // save filename (not yet)
1572 // eject
1573 // clear
1574 // start
1575 // stop
1576 // rewind (doesn't stop the tape)
1577 // list (not yet)
1578 // option
1579 // _autoload
1581 JIMAPI_FN(tape) {
1582 if (jimapiWantsCompletion(interp, argc, argv)) {
1583 //fprintf(stderr, "ARGC=%d\n", argc); for (int f = 0; f < argc; ++f) fprintf(stderr, " #%d: <%s>\n", f, Jim_String(argv[f]));
1584 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1585 int argp = 1;
1586 char *a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "insert", "eject", "clear", "start", "stop", "rewind", "option", NULL);
1587 jimapiStrAppendAbbrev(interp, res, a0);
1588 const char *a1 = (isFullyCompleted(a0) ? parseAbbrev(a0, "insert", "save", "option", NULL) : NULL);
1589 if (a1 != NULL) {
1590 // fill/autocomplete command args
1591 if (strEqu(a1, "insert") || strEqu(a1, "save")) {
1592 // insert/save
1593 free(a0);
1594 a0 = completeFilesWithExts((argc > argp ? Jim_String(argv[argp++]) : ""), snapshotExtensions);
1595 jimapiStrAppendAbbrev(interp, res, a0);
1596 } else if (strEqu(a1, "option")) {
1597 free(a0);
1598 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "maxspeed", "detectloader", "flashload", "sound", "ugly", NULL);
1599 jimapiStrAppendAbbrev(interp, res, a0);
1600 if (isFullyCompleted(a0)) {
1601 a1 = parseAbbrev(a0, "maxspeed", "detectloader", "flashload", "sound", "ugly", NULL);
1602 if (a1 != NULL) {
1603 free(a0);
1604 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "on", "off", "toggle", NULL);
1605 jimapiStrAppendAbbrev(interp, res, a0);
1610 free(a0);
1611 jimapiAppendRestArgs(res, argp);
1612 Jim_SetResult(interp, res);
1613 return JIM_OK;
1616 int res = 1;
1618 if (argc < 2) {
1619 //Jim_WrongNumArgs(interp, 1, argv, "cmd");
1620 cprintf(
1621 "tape commands:\n"
1622 " insert filename\n"
1623 " save filename (not yet)\n"
1624 " eject\n"
1625 " clear\n"
1626 " start\n"
1627 " stop\n"
1628 " rewind (doesn't stop the tape)\n"
1629 " list (not yet)\n"
1630 " option\n"
1632 return JIM_OK;
1635 if (strEquCI(Jim_String(argv[1]), "_autoload")) {
1636 tape_do_autoload();
1637 goto done;
1640 const char *a0 = parseAbbrev(Jim_String(argv[1]), "insert", "eject", "clear", "start", "go", "stop", "rewind", "list", "save", "option", NULL);
1642 if (a0 == NULL) {
1643 jim_SetResStrf(interp, "%s: invalid tape command: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
1644 goto done;
1647 if (strEqu(a0, "insert")) {
1648 if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
1649 if (loadSnapshot(Jim_String(argv[2]), SNAPLOAD_TAPES) != 0) {
1650 cprintf("tape: can't insert '%s'\n", Jim_String(argv[2]));
1651 res = 0;
1652 } else {
1653 cprintf("tape: inserted '%s'\n", Jim_String(argv[2]));
1655 } else if (strEqu(a0, "eject")) {
1656 emuUnloadTape();
1657 cprintf("tape: unloaded\n");
1658 } else if (strEqu(a0, "clear")) {
1659 emuClearTape();
1660 cprintf("tape: cleared\n");
1661 } else if (strEqu(a0, "start") || strEqu(a0, "go")) {
1662 emuStartTape();
1663 cprintf("tape: started\n");
1664 } else if (strEqu(a0, "stop")) {
1665 emuStopTape();
1666 cprintf("tape: stopped\n");
1667 } else if (strEqu(a0, "rewind")) {
1668 emuRewindTape();
1669 cprintf("tape: rewound\n");
1670 } else if (strEqu(a0, "list")) {
1671 cprintf("tape: no listing yet...\n");
1672 } else if (strEqu(a0, "save")) {
1673 cprintf("tape: no saving yet...\n");
1674 } else if (strEqu(a0, "option")) {
1675 int *opt = NULL;
1676 if (argc < 3) {
1677 cprintf(
1678 "tape options:\n"
1679 " maxspeed on/off/toggle\n"
1680 " detectloader on/off/toggle\n"
1681 " autopause on/off/toggle\n"
1682 " sound on/off/toggle\n"
1683 " ugly on/off/toggle\n"
1685 goto done;
1687 a0 = parseAbbrev(Jim_String(argv[2]), "maxspeed", "detectloader", "autopause", "flashload", "sound", "ugly", NULL);
1688 if (a0 == NULL) {
1689 jim_SetResStrf(interp, "%s: invalid tape option: '%s'", Jim_String(argv[0]), Jim_String(argv[2]));
1690 return JIM_ERR;
1692 if (strEqu(a0, "maxspeed")) opt = &optTapeMaxSpeed;
1693 else if (strEqu(a0, "detectloader")) opt = &optTapeDetector;
1694 else if (strEqu(a0, "autopause")) opt = &optTapeAutoPauseEmu;
1695 else if (strEqu(a0, "flashload")) opt = &optFlashLoad;
1696 else if (strEqu(a0, "sound")) opt = &optTapeSound;
1697 else if (strEqu(a0, "ugly")) opt = &optTapeAllowMaxSpeedUgly;
1699 if (argc > 3) {
1700 Jim_Obj *xargv[2];
1701 xargv[0] = argv[0];
1702 xargv[1] = argv[3];
1703 if (jim_onoff_option(opt, interp, 2, xargv, "on", "off", 1) != JIM_OK) {
1704 jim_SetResStrf(interp, "%s: invalid mode for '%s': '%s'", Jim_String(argv[0]), a0, Jim_String(argv[1]));
1705 return JIM_ERR;
1708 cprintf("tape: %s: %s\n", a0, (*opt ? "on" : "off"));
1711 done:
1712 Jim_SetResultBool(interp, res);
1713 return JIM_OK;
1717 ////////////////////////////////////////////////////////////////////////////////
1718 // disk cmd [args...]
1719 // insert filename
1720 // save filename
1721 // eject
1722 // format [il=interleave] [sofs=sector_offset]
1723 // option autoadd_boot
1724 // boot add [name] | remove | replace [name]
1725 // protect
1726 // unprotect
1727 // info
1728 // list
1729 // extract
1730 // add
1732 JIMAPI_FN(disk) {
1733 int diskno = 0;
1735 if (jimapiWantsCompletion(interp, argc, argv)) {
1736 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
1737 int argp = 1;
1738 const char *a1;
1740 if (argp < argc) {
1741 a1 = Jim_String(argv[argp]);
1742 if (strlen(a1) == 2 && a1[1] == ':' && strchr("abcdABCD", a1[0]) != NULL) {
1743 ++argp;
1744 diskno = tolower(a1[0])-'a';
1745 jimapiStrAppendSpace(interp, res);
1746 jimapiStrAppendCStr(interp, res, a1, -1);
1747 jimapiStrAppendSpace(interp, res);
1751 char *a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "insert", "save", "eject", "format", "boot", "option", "protect", "unprotect", "list", "extract", "add", NULL);
1752 jimapiStrAppendAbbrev(interp, res, a0);
1754 a1 = (isFullyCompleted(a0) ? parseAbbrev(a0, "insert", "save", "boot", "option", "extract", "add", "format", NULL) : NULL);
1755 if (a1 != NULL) {
1756 // fill/autocomplete command args
1757 if (strEqu(a1, "boot")) {
1758 free(a0);
1759 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "add", "remove", "replace", NULL);
1760 jimapiStrAppendAbbrev(interp, res, a0);
1761 if (isFullyCompleted(a0) && (strEqu(a0, "add ") || strEqu(a0, "replace "))) {
1762 free(a0);
1763 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "stealth32", "stealth54", "onesector", "phantom", "kmouse", "ugly", NULL);
1764 jimapiStrAppendAbbrev(interp, res, a0);
1766 } else if (strEqu(a1, "option")) {
1767 free(a0);
1768 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "autoadd_boot", "turbo", "traps", NULL);
1769 jimapiStrAppendAbbrev(interp, res, a0);
1770 if (isFullyCompleted(a0) && (strEqu(a0, "autoadd_boot ") || strEqu(a0, "traps "))) {
1771 free(a0);
1772 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "yes", "no", "on", "off", "toggle", NULL);
1773 jimapiStrAppendAbbrev(interp, res, a0);
1774 } else if (isFullyCompleted(a0) && strEqu(a0, "turbo ")) {
1775 free(a0);
1776 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "yes", "no", "on", "off", "normal", "toggle", NULL);
1777 jimapiStrAppendAbbrev(interp, res, a0);
1779 } else if (strEqu(a1, "extract")) {
1780 free(a0);
1781 //fprintf(stderr, "argc=%d; argp=%d; <%s>\n", argc, argp, (argc > argp ? Jim_String(argv[argp]) : ""));
1782 a0 = completeTRDiskFiles((argc > argp ? Jim_String(argv[argp++]) : ""), beta_get_disk(diskno));
1783 jimapiStrAppendAbbrev(interp, res, a0);
1784 } else if (strEqu(a1, "format")) {
1785 free(a0);
1786 a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "il=", "sofs=", NULL);
1787 jimapiStrAppendAbbrev(interp, res, a0);
1788 } else if (strEqu(a1, "insert") || strEqu(a1, "save")) {
1789 // insert/save
1790 free(a0);
1791 a0 = completeFilesWithExts((argc > argp ? Jim_String(argv[argp++]) : ""), snapshotExtensions);
1792 jimapiStrAppendAbbrev(interp, res, a0);
1795 free(a0);
1796 jimapiAppendRestArgs(res, argp);
1797 Jim_SetResult(interp, res);
1798 return JIM_OK;
1801 const char *a0;
1802 int argp = 1;
1804 if (argc > 1) {
1805 a0 = Jim_String(argv[1]);
1806 if (strlen(a0) == 2 && a0[1] == ':' && strchr("abcdABCD", a0[0]) != 0) {
1807 ++argp;
1808 diskno = tolower(a0[0])-'a';
1812 int res = 1;
1813 disk_t *flp = beta_get_disk(diskno);
1815 if (argp >= argc) {
1816 //Jim_WrongNumArgs(interp, 1, argv, "cmd");
1817 return JIM_OK;
1820 if ((a0 = parseAbbrev(Jim_String(argv[argp++]), "insert", "eject", "format", "list", "save", "option", "boot", "protect", "unprotect", "list", "extract", "add", NULL)) == NULL) {
1821 jim_SetResStrf(interp, "%s: invalid disk command: '%s'", Jim_String(argv[0]), Jim_String(argv[argp-1]));
1822 goto done;
1825 // insert
1826 if (strEqu(a0, "insert")) {
1827 if (argp >= argc) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
1828 if (loadSnapshot(Jim_String(argv[argp]), SNAPLOAD_DISKS|(diskno<<SNAPLOAD_FLPNOSHIFT)) != 0) {
1829 cprintf("disk: can't insert '%s'\n", Jim_String(argv[argp]));
1830 res = 0;
1831 } else {
1832 cprintf("disk: inserted '%s'\n", Jim_String(argv[argp]));
1834 goto done;
1837 // eject
1838 if (strEqu(a0, "eject")) {
1839 emuDiskEject(diskno);
1840 cprintf("disk: ejected\n");
1841 goto done;
1844 // format
1845 if (strEqu(a0, "format")) {
1846 emuDiskEject(diskno);
1847 if (emuIsUPD765()) {
1848 int fres = p3dskFormatDisk(flp, P3DSK_PCW_SS);
1849 flp->dirty = 0;
1850 if (fres == FLPERR_OK) {
1851 emuDiskInsert(diskno);
1852 cprintf("disk: formated +3DOS disk\n");
1853 } else {
1854 cprintf("disk: +3DOS formatting error!\n");
1856 } else {
1857 int fres = flpFormatTRD(flp);
1858 flp->dirty = 0;
1859 if (fres == FLPERR_OK) {
1860 emuDiskInsert(diskno);
1861 cprintf("disk: formated TR-DOS disk\n");
1862 } else {
1863 cprintf("disk: TR-DOS formatting error!\n");
1866 goto done;
1869 // save
1870 if (strEqu(a0, "save")) {
1871 if (argp >= argc) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
1872 const char *fname = Jim_String(argv[argp++]);
1873 const int wres = emuSaveDiskToFile(diskno, fname);
1874 if (wres != DISK_OK) {
1875 cprintf("\4ERROR: can't save disk to file: '%s' (%s)\n", fname, disk_strerror(wres));
1876 } else {
1877 cprintf("saved disk to file: '%s'\n", fname);
1879 res = (wres == 0);
1880 goto done;
1883 // boot
1884 if (strEqu(a0, "boot")) {
1885 if (argp >= argc) { Jim_WrongNumArgs(interp, 1, argv, "action"); return JIM_ERR; }
1886 if ((a0 = parseAbbrev(Jim_String(argv[argp++]), "add", "remove", "replace", NULL)) != NULL) {
1887 if (strEqu(a0, "add") || strEqu(a0, "replace")) {
1888 int rep = (strEqu(a0, "replace"));
1889 const char *bootname = (argp >= argc ? "phantom" : Jim_String(argv[argp++]));
1890 a0 = parseAbbrev(bootname, "stealth32", "stealth54", "onesector", "phantom", "kmouse", "ugly", NULL);
1891 if (a0 != NULL) {
1892 const uint8_t *b = NULL;
1893 int bootsz = 0;
1894 if (strEqu(a0, "stealth32")) { b = sboot32; bootsz = (int)sizeof(sboot32); }
1895 else if (strEqu(a0, "stealth54")) { b = sboot54; bootsz = (int)sizeof(sboot54); }
1896 else if (strEqu(a0, "onesector")) { b = bootsmall; bootsz = (int)sizeof(bootsmall); }
1897 else if (strEqu(a0, "phantom")) { b = bootph; bootsz = (int)sizeof(bootph); }
1898 else if (strEqu(a0, "kmouse")) { b = kmboot; bootsz = (int)sizeof(kmboot); }
1899 else if (strEqu(a0, "ugly")) { b = unrealboot; bootsz = (int)sizeof(unrealboot); }
1900 if (flp->data) {
1901 if (flpDetectDiskType(flp) == FLP_DISK_TYPE_TRDOS) {
1902 FILE *fl = fmemopen((void *)b, bootsz, "rb");
1903 res = flpSetBootTRD(flp, fl, rep);
1904 fclose(fl);
1905 if (res == 0) {
1906 res = 1;
1907 cprintf("disk: boot '%s' added\n", a0);
1908 } else {
1909 cprintf("disk: can't add boot '%s'\n", a0);
1910 res = 0;
1912 } else {
1913 res = 0;
1914 cprintf("disk: not a TR-DOS disk!\n");
1916 } else {
1917 res = 0;
1918 cprintf("disk: no disk in drive!\n");
1920 } else {
1921 jim_SetResStrf(interp, "%s: invalid disk boot name: '%s'", Jim_String(argv[0]), bootname);
1922 goto done;
1924 } else if (strEqu(a0, "remove")) {
1925 if (flpRemoveBootTRD(flp) == 0) {
1926 cprintf("disk: boot removed\n");
1929 } else {
1930 jim_SetResStrf(interp, "%s: invalid disk boot command: '%s'", Jim_String(argv[0]), Jim_String(argv[argp-1]));
1932 goto done;
1935 // protect
1936 if (strEqu(a0, "protect")) {
1937 if (upd765_fdc && upd765_fdc->drive[diskno]) {
1938 fdd_wrprot(upd765_fdc->drive[diskno], 1);
1940 if (beta_get_fdd(diskno)) {
1941 fdd_wrprot(beta_get_fdd(diskno), 1);
1943 cprintf("disk: write-protection set\n");
1944 goto done;
1947 // unprotect
1948 if (strEqu(a0, "unprotect")) {
1949 if (upd765_fdc && upd765_fdc->drive[diskno]) {
1950 fdd_wrprot(upd765_fdc->drive[diskno], 0);
1952 if (beta_get_fdd(diskno)) {
1953 fdd_wrprot(beta_get_fdd(diskno), 0);
1955 cprintf("disk: write-protection reset\n");
1956 goto done;
1959 // option
1960 if (strEqu(a0, "option")) {
1961 if (argp >= argc) { Jim_WrongNumArgs(interp, 1, argv, "option"); return JIM_ERR; }
1962 if ((a0 = parseAbbrev(Jim_String(argv[argp++]), "autoadd_boot", "turbo", "traps", NULL)) != NULL) {
1963 if (strEqu(a0, "autoadd_boot")) {
1964 if (argp < argc) {
1965 if ((a0 = parseAbbrev(Jim_String(argv[argp++]), "yes", "no", "on", "off", "toggle", NULL)) != NULL) {
1966 if (strEqu(a0, "yes") || strEqu(a0, "on")) optAutoaddBoot = 1;
1967 else if (strEqu(a0, "toggle")) optAutoaddBoot = !optAutoaddBoot;
1968 else optAutoaddBoot = 0;
1969 } else {
1970 cprintf("disk: invalid 'autoadd_boot' option argument: '%s'!\n", Jim_String(argv[argp]));
1971 goto done;
1974 if (jimapiFromConsole(interp)) cprintf("disk autoadd_boot: %s\n", (optAutoaddBoot ? "yes" : "no"));
1975 res = !!optAutoaddBoot;
1976 } else if (strEqu(a0, "turbo")) {
1977 if (argp < argc) {
1978 if ((a0 = parseAbbrev(Jim_String(argv[argp]), "yes", "no", "on", "off", "normal", "toggle", NULL)) != NULL) {
1979 if (strEqu(a0, "yes") || strEqu(a0, "on")) {
1980 fdd_turbo = FDD_TURBO_SUPER;
1981 } else if (strEqu(a0, "toggle")) {
1982 fdd_turbo = (fdd_turbo ? FDD_TURBO_NONE : FDD_TURBO_SUPER);
1983 } else if (strEqu(a0, "normal")) {
1984 fdd_turbo = FDD_TURBO_TURBO;
1985 } else {
1986 fdd_turbo = FDD_TURBO_NONE;
1988 if (upd765_fdc) {
1989 upd_fdc_alloc_fdc_set_clock(upd765_fdc, (fdd_turbo ? UPD_CLOCK_8MHZ : UPD_CLOCK_4MHZ));
1991 } else {
1992 cprintf("disk: invalid 'turbo' option argument: '%s'!\n", Jim_String(argv[argp]));
1993 goto done;
1996 res = (fdd_turbo != FDD_TURBO_NONE);
1997 if (jimapiFromConsole(interp)) {
1998 cprintf("disk turbo: %s\n", (fdd_turbo == FDD_TURBO_NONE ? "none" : fdd_turbo == FDD_TURBO_TURBO ? "normal" : "super"));
2000 } else if (strEqu(a0, "traps")) {
2001 if (argp < argc) {
2002 if ((a0 = parseAbbrev(Jim_String(argv[argp]), "yes", "no", "on", "off", "toggle", "debug", "nodebug", NULL)) != NULL) {
2003 if (strEqu(a0, "yes") || strEqu(a0, "on")) optTRDOSTraps = 1;
2004 else if (strEqu(a0, "toggle")) optTRDOSTraps = !optTRDOSTraps;
2005 else if (strEqu(a0, "debug")) optTRDOSTrapDebug = 1;
2006 else if (strEqu(a0, "nodebug")) optTRDOSTrapDebug = 0;
2007 else optTRDOSTraps = 0;
2008 } else {
2009 cprintf("disk: invalid 'traps' option argument: '%s'!\n", Jim_String(argv[argp]));
2010 goto done;
2013 if (jimapiFromConsole(interp)) cprintf("disk traps: %s\n", (optTRDOSTraps ? "yes" : "no"));
2014 res = !!optTRDOSTraps;
2015 //cprintf("\1WARNING: TR-DOS traps are not implemented yet!\n");
2016 //res = 0;
2018 } else {
2019 cprintf("disk: invalid option: '%s'!\n", Jim_String(argv[argp-1]));
2021 goto done;
2024 // list
2025 if (strEqu(a0, "list")) {
2026 int wantsizes = 0;
2027 if (argp < argc) wantsizes = strEquCI(Jim_String(argv[argp++]), "size");
2028 int count;
2029 FloppyFileInfo *dir = anyDiskBuildDir(flp, &count);
2030 Jim_Obj *rlist = Jim_NewListObj(interp, NULL, 0);
2031 if (count < 1) {
2032 if (jimapiFromConsole(interp)) cprintf("no files\n");
2033 } else {
2034 if (jimapiFromConsole(interp)) cprintf("\2=================\n");
2035 for (int f = 0; f < count; ++f) {
2036 if (jimapiFromConsole(interp)) cprintf("\3%-8s%-4s %8u\n", dir[f].name, dir[f].ext, dir[f].size);
2037 if (!wantsizes) {
2038 char *ss = strprintf("%s%s", dir[f].name, dir[f].ext);
2039 Jim_Obj *fnstr = Jim_NewStringObj(interp, ss, -1);
2040 free(ss);
2041 Jim_ListAppendElement(interp, rlist, fnstr);
2042 } else {
2043 Jim_Obj *fnsize = Jim_NewIntObj(interp, (jim_wide)dir[f].size);
2044 Jim_ListAppendElement(interp, rlist, fnsize);
2047 if (conpos >= CON_WIDTH/2) {
2048 cprintf("\n");
2049 } else {
2050 while (conpos < CON_WIDTH/2) conPutChar(' ');
2054 //if (conpos != CON_WIDTH) cprintf("\n");
2056 if (dir) free(dir);
2057 Jim_SetResult(interp, rlist);
2058 return JIM_OK;
2061 // extract
2062 if (strEqu(a0, "extract")) {
2063 //cprintf("\4EXTRACTOR IS BROKEN FOR NOW\n");
2064 if (argp >= argc) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; }
2065 const FloppyDiskType dtype = flpDetectDiskType(flp);
2066 if (dtype == FLP_DISK_TYPE_TRDOS) {
2067 int count;
2068 FloppyFileInfo *dir = anyDiskBuildDir(flp, &count);
2069 for (int f = 0; f < count; ++f) {
2070 char *fname = strprintf("%s%s", dir[f].name, dir[f].ext);
2071 int n;
2072 for (n = argp; n < argc; ++n) {
2073 if (strcasecmp(Jim_String(argv[n]), fname) == 0) break;
2075 // try glob masks
2076 if (n >= argc) {
2077 for (n = argp; n < argc; ++n) {
2078 if (p3dskGlobMatch(fname, Jim_String(argv[n]), P3DSK_GLOB_DEFAULT)) break;
2081 // is found?
2082 if (n < argc) {
2083 FILE *fo = fopen(fname, "wb");
2084 if (fo != NULL) {
2085 int wres = flpSaveHoBeta(flp, fo, dir[f].index);
2086 fclose(fo);
2087 if (wres != FLPERR_OK) {
2088 unlink(fname);
2089 cprintf("disk: error extracting '%s'!\n", fname);
2090 } else {
2091 cprintf("disk: extracted '%s'!\n", fname);
2093 } else {
2094 cprintf("disk: can't create '%s'!\n", fname);
2097 // done with this name
2098 free(fname);
2100 free(dir);
2101 } else if (dtype == FLP_DISK_TYPE_P3DOS) {
2102 P3DiskInfo p3d;
2103 p3d.flp = flp;
2104 if (p3dskDetectGeom(p3d.flp, &p3d.geom) == FLPERR_OK) {
2105 P3DskFileInfo nfo;
2106 if (p3dskFindInit(&p3d, &nfo, "*.*") == FLPERR_OK) {
2107 while (p3dskFindNext(&nfo) > 0) {
2108 if (nfo.name[0]) {
2109 int n;
2110 for (n = argp; n < argc; ++n) {
2111 if (strcasecmp(Jim_String(argv[n]), nfo.name) == 0) break;
2113 // try glob masks
2114 if (n >= argc) {
2115 for (n = argp; n < argc; ++n) {
2116 if (p3dskGlobMatch(nfo.name, Jim_String(argv[n]), P3DSK_GLOB_DEFAULT)) break;
2119 // is found?
2120 if (n < argc) {
2121 FILE *fo = fopen(nfo.name, "wb");
2122 if (fo != NULL) {
2123 int rd = 0;
2124 if (nfo.size) {
2125 uint8_t *buf = malloc(nfo.size);
2126 rd = p3dskReadFile(&nfo, buf, 0, (int)nfo.size);
2127 if (rd > 0) {
2128 if (fwrite(buf, (size_t)rd, 1, fo) != 1) rd = -1;
2130 free(buf);
2132 fclose(fo);
2133 if (rd < 0) {
2134 unlink(nfo.name);
2135 cprintf("disk: error extracting '%s'!\n", nfo.name);
2136 } else {
2137 cprintf("disk: extracted '%s'!\n", nfo.name);
2139 } else {
2140 cprintf("disk: can't create '%s'!\n", nfo.name);
2150 done:
2151 Jim_SetResultBool(interp, res);
2152 return JIM_OK;
2156 ////////////////////////////////////////////////////////////////////////////////
2157 // fldebug [on|off|toggle]
2158 JIMAPI_FN(fldebug) {
2159 int v = optDebugFlashLoad;
2160 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
2161 optDebugFlashLoad = v;
2162 Jim_SetResultBool(interp, v);
2163 return res;
2167 ////////////////////////////////////////////////////////////////////////////////
2168 // opense [on|off|toggle]
2169 JIMAPI_FN(opense) {
2170 int v = optOpenSE;
2171 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
2172 optOpenSE = v;
2173 Jim_SetResultBool(interp, v);
2174 return res;
2178 // gluck [on|off|toggle]
2179 JIMAPI_FN(gluck) {
2180 int v = optUseGluck;
2181 int res = jim_onoff_option(&v, interp, argc, argv, "on", "off", 1);
2182 optUseGluck = v;
2183 Jim_SetResultBool(interp, v);
2184 return res;
2188 // kbreset
2189 JIMAPI_FN(kbreset) {
2190 emuResetKeyboard();
2191 cprintf("ZX keyboard reset.\n");
2192 return JIM_OK;
2196 // ayreset
2197 JIMAPI_FN(ayreset) {
2198 emuResetAY();
2199 cprintf("AY reset.\n");
2200 return JIM_OK;
2204 // curblink mstime
2205 JIMAPI_FN(curblink) {
2206 if (jimapiDisableCompletion(interp, argc, argv)) return JIM_OK;
2207 if (argc < 1 || argc > 2) {
2208 jim_SetResStrf(interp, "%s: expected cursor blink time (only)", Jim_String(argv[0]));
2209 return JIM_ERR;
2212 if (argc > 1) {
2213 int idx = jimGetIntLitVal(interp, argv[1]);
2214 if (idx <= 0) idx = 0; else if (idx > 10000) idx = 10000;
2215 optCurBlinkMS = idx;
2218 Jim_SetResultInt(interp, optCurBlinkMS);
2219 return JIM_OK;
2223 ////////////////////////////////////////////////////////////////////////////////
2224 // bp [type] cmd [args...]
2225 // types: exec read write in out
2226 // set addrlist
2227 // unset addrlist
2228 // toggle addrlist
2229 // clear
2230 // load fname
2231 // xsave fname
2233 JIMAPI_FN(bp) {
2234 uint8_t type = DBG_BP_EXEC;
2235 int deftype = 1;
2236 int argp = 1;
2237 int needfname = 0;
2238 // 0x01u: type; 0x02u: action
2239 unsigned wasctype = 0;
2241 const char *allcms[] = { "set", "unset", "toggle", "clear", "xsave", "load", "exec", "read", "write", "in", "out", NULL };
2242 const char *typecmds[] = { "exec", "read", "write", "in", "out", NULL };
2243 const char *actioncmds[] = { "set", "unset", "toggle", "clear", "xsave", "load", NULL };
2245 if (jimapiWantsCompletion(interp, argc, argv)) {
2246 const char *bpExtensions[] = { ".bpx", NULL };
2248 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
2249 while (argp < argc) {
2250 // commands
2251 const char **ctype;
2252 if (wasctype == 0) ctype = allcms;
2253 else if (wasctype == 1) ctype = actioncmds;
2254 else ctype = typecmds;
2256 char *a0 = completeAbbrevArray(Jim_String(argv[argp]), ctype, ABBREV_CI);
2257 if (!isFullyCompleted(a0)) {
2258 free(a0);
2259 break;
2261 jimapiStrAppendAbbrev(interp, res, a0);
2263 const char *a1 = parseAbbrevArray(a0, ctype, ABBREV_CI, NULL);
2264 const char cmdch = a1[0];
2265 free(a0);
2267 if (cmdch == 'x' || cmdch == 'l') needfname = 1;
2268 else if (cmdch == 'c') needfname = -1;
2270 if (strchr("erwio", cmdch)) wasctype |= 0x01u;
2271 else if (strchr("sutcxl", cmdch)) wasctype |= 0x02u;
2273 ++argp;
2276 while (argp < argc && needfname >= 0) {
2277 char *a0;
2278 if (needfname) {
2279 a0 = completeFilesWithExts(Jim_String(argv[argp++]), bpExtensions);
2280 } else {
2281 a0 = completeLabelName(Jim_String(argv[argp++]));
2283 jimapiStrAppendAbbrev(interp, res, a0);
2284 free(a0);
2285 if (needfname) break;
2288 jimapiAppendRestArgs(res, argp);
2289 Jim_SetResult(interp, res);
2290 return JIM_OK;
2293 int res = 1;
2294 char command = 0;
2296 while (argp < argc) {
2297 // commands
2298 const char **ctype;
2299 if (wasctype == 0) ctype = allcms;
2300 else if (wasctype == 1) ctype = actioncmds;
2301 else ctype = typecmds;
2303 //cprintf("wasctype=%u; argp=%d; argc=%d; <%s>\n", wasctype, argp, argc, Jim_String(argv[argp]));
2304 int fullcmd = 0;
2305 const char *a0 = parseAbbrevArray(Jim_String(argv[argp]), ctype, ABBREV_CI, &fullcmd);
2306 if (!fullcmd) break;
2308 const char cmdch = a0[0];
2309 if (cmdch == 'x' || cmdch == 'l') needfname = 1;
2310 else if (cmdch == 'c') needfname = -1;
2311 else if (cmdch == 'e') { deftype = 0; type = DBG_BP_EXEC; }
2312 else if (cmdch == 'r') { deftype = 0; type = DBG_BP_READ; }
2313 else if (cmdch == 'w') { deftype = 0; type = DBG_BP_WRITE; }
2314 else if (cmdch == 'i') { deftype = 0; type = DBG_BP_PORTIN; }
2315 else if (cmdch == 'o') { deftype = 0; type = DBG_BP_PORTOUT; }
2317 if (strchr("erwio", cmdch)) wasctype |= 0x01u;
2318 else if (strchr("sutcxl", cmdch)) { command = cmdch; wasctype |= 0x02u; }
2320 ++argp;
2323 if (!command) {
2324 jim_SetResStrf(interp, "%s: bp action expected", Jim_String(argv[0]));
2325 return JIM_ERR;
2328 if (needfname >= 0 && argp >= argc) {
2329 jim_SetResStrf(interp, "%s: bp action argument expected", Jim_String(argv[0]));
2330 return JIM_ERR;
2333 // clear
2334 if (command == 'c') {
2335 dbgBPClear();
2336 if (jimapiFromConsole(interp)) cprintf("breakpoints cleared\n");
2337 Jim_SetResultBool(interp, res);
2338 return JIM_OK;
2341 if (needfname > 0) {
2342 res = 0;
2343 const char *name = Jim_String(argv[argp]);
2344 if (name && name[0]) {
2345 char *fname = NULL;
2346 const char *ext = strrchr(name, '.');
2347 if (!ext || strcasecmp(ext, ".bpx") != 0) {
2348 fname = malloc(strlen(name)+8);
2349 strcpy(fname, name);
2350 strcat(fname, ".bpx");
2351 } else {
2352 fname = strdup(name);
2354 if (command == 'l') {
2355 // load
2356 if (dbgBPLoadFromFile(fname) == 0) {
2357 cprintf("breakpoints loaded from '%s'\n", fname);
2358 } else {
2359 cprintf("\4ERROR loading breakpoints from '%s'\n", fname);
2361 } else {
2362 // save
2363 if (dbgBPSaveToFile(fname) == 0) {
2364 cprintf("breakpoints saved to '%s'\n", fname);
2365 } else {
2366 cprintf("\4ERROR saving breakpoints to '%s'\n", fname);
2369 free(fname);
2371 } else if (needfname == 0) {
2372 // set, unset, toggle
2373 if (command == 'u' && deftype) type = 0xffu; /* clear all */
2374 while (argp < argc) {
2375 int addr = jimGetAddrOrLabel(interp, argv[argp]);
2376 if (addr < 0) {
2377 cprintf("\x4%s: cannot understand '%s'\n", Jim_String(argv[0]), Jim_String(argv[argp]));
2378 } else {
2379 switch (command) {
2380 case 's': dbgSetBPType(addr, dbgGetBPType(addr)|type); break;
2381 case 'u': dbgSetBPType(addr, dbgGetBPType(addr)&(~type)); break;
2382 case 't': dbgSetBPType(addr, dbgGetBPType(addr)^type); break;
2384 if (dbgGetBPType(addr)) {
2385 if (jimapiFromConsole(interp)) cprintf("changed breakpoint at #%04X (%s)\n", (unsigned)(addr&0xffffu), dbgGetBPTypeStr(dbgGetBPType(addr)));
2386 } else {
2387 if (jimapiFromConsole(interp)) cprintf("cleared breakpoint at #%04X\n", (unsigned)(addr&0xffffu));
2390 ++argp;
2394 Jim_SetResultBool(interp, res);
2395 return JIM_OK;
2399 ////////////////////////////////////////////////////////////////////////////////
2400 // label cmd [args...]
2401 // set name addr
2402 // del addr-or-name
2403 // goto addr-or-name
2404 // get addr-or-name
2405 // clear
2407 JIMAPI_FN(label) {
2408 const char *commands[7] = { "set", "del", "goto", "get", "remove", "clear", NULL };
2410 if (jimapiWantsCompletion(interp, argc, argv)) {
2411 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
2412 jimapiStrAppendSpace(interp, res);
2413 int argp = 1;
2414 char *a0 = completeAbbrevArray((argc > argp ? Jim_String(argv[argp++]) : ""), commands, ABBREV_CI);
2415 jimapiStrAppendAbbrev(interp, res, a0);
2416 if (argc > argp && isFullyCompleted(a0)) {
2417 const char *astr = parseAbbrevArray(a0, commands, ABBREV_CI, NULL);
2418 if (astr && !strEqu(astr, "clear")) {
2419 free(a0);
2420 a0 = completeLabelName(Jim_String(argv[argp++]));
2421 jimapiStrAppendAbbrev(interp, res, a0);
2424 free(a0);
2425 jimapiAppendRestArgs(res, argp);
2426 Jim_SetResult(interp, res);
2427 return JIM_OK;
2430 const char *a0;
2431 int argp = 1;
2432 if (argc < 2) {
2433 //Jim_WrongNumArgs(interp, 1, argv, "cmd");
2434 return JIM_OK;
2437 if ((a0 = parseAbbrevArray(Jim_String(argv[argp++]), commands, ABBREV_CI, NULL)) == NULL) {
2438 jim_SetResStrf(interp, "%s: unknown command: '%s'", Jim_String(argv[0]), Jim_String(argv[argp-1]));
2439 return JIM_ERR;
2442 if (strEqu(a0, "clear")) {
2443 dbgClearLabels();
2444 if (jimapiFromConsole(interp)) cprintf("labels cleared\n");
2445 Jim_SetResultBool(interp, 1);
2446 return JIM_OK;
2449 if (argp >= argc) {
2450 jim_SetResStrf(interp, "%s: invalid command: '%s'", Jim_String(argv[0]), Jim_String(argv[argp-1]));
2451 return JIM_ERR;
2454 if (a0[0] == 'd' || a0[0] == 'r') {
2455 // remove label
2456 while (argp < argc) {
2457 long addr = -1;
2458 if (Jim_GetLong(interp, argv[argp], &addr) != JIM_OK) {
2459 const char *lbl = Jim_String(argv[argp]);
2460 addr = dbgFindLabelByName(lbl);
2461 if (addr < 0) {
2462 cprintf("\x4%s: cannot understand '%s'\n", Jim_String(argv[0]), lbl);
2463 } else {
2464 dbgRemoveLabel(lbl);
2465 if (jimapiFromConsole(interp)) cprintf("removed label '%s' at #%04X\n", lbl, (unsigned)(addr&0xffffu));
2467 } else {
2468 if (addr < 0 || addr > 65535) {
2469 cprintf("\x4%s: invalid address %d\n", Jim_String(argv[0]), (int)addr);
2470 } else {
2471 const char *lbl = dbgFindLabelByVal(addr, 0/*asoffset*/);
2472 if (lbl) {
2473 dbgRemoveLabel(lbl);
2474 if (jimapiFromConsole(interp)) cprintf("removed label '%s' at #%04X\n", lbl, (unsigned)(addr&0xffffu));
2478 ++argp;
2480 Jim_SetResultBool(interp, 1);
2481 return JIM_OK;
2484 if (a0[0] == 'g') {
2485 // goto label / get label
2486 if (argc != 3) {
2487 jim_SetResStrf(interp, "expects one argument");
2488 return JIM_ERR;
2490 int addr = jimGetAddrOrLabel(interp, argv[2]);
2491 if (addr < 0) {
2492 if (a0[1] == 'e') {
2493 // get
2494 cprintf("\4ERROR: no label '%s'!\n", Jim_String(argv[2]));
2495 Jim_SetResultString(interp, "", -1);
2496 return JIM_OK;
2498 jim_SetResStrf(interp, "expects addr or name");
2499 return JIM_ERR;
2501 if (a0[1] != 'e') dbgSetUnasmAddr((uint16_t)(addr&0xffffu));
2502 if (jimapiFromConsole(interp)) cprintf("label '%s' is %d\n", Jim_String(argv[2]), addr);
2503 Jim_SetResultInt(interp, addr);
2504 return JIM_OK;
2507 if (a0[0] == 's') {
2508 // set
2509 if (argc != 4) {
2510 jim_SetResStrf(interp, "expects two args");
2511 return JIM_ERR;
2513 const char *lname = Jim_String(argv[2]);
2514 int addr = jimGetAddrOrLabel(interp, argv[3]);
2515 if (addr < 0) {
2516 jim_SetResStrf(interp, "expects addr and name");
2517 return JIM_ERR;
2519 if (lname && lname[0] && lname[0] != '#' && lname[0] != '$' && digitInBase(lname[0], 10) < 0) {
2520 dbgAddLabel(addr&0xffffu, lname, 0/*asoffset*/);
2521 if (jimapiFromConsole(interp)) cprintf("set label '%s' at address #%04X\n", lname, (unsigned)(addr&0xffffu));
2523 Jim_SetResultInt(interp, (unsigned)(addr&0xffffu));
2524 return JIM_OK;
2527 Jim_SetResultBool(interp, 0);
2528 return JIM_OK;
2532 ////////////////////////////////////////////////////////////////////////////////
2533 // reffile <load|save|clear> [name]
2534 // "reference file" (urasm generates those)
2535 JIMAPI_FN(reffile) {
2536 const char *refExtensions[] = { ".ref", NULL };
2538 // autocompletion
2539 if (jimapiWantsCompletion(interp, argc, argv)) {
2540 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
2541 int argp = 1;
2542 char *a0 = completeAbbrev((argc > argp ? Jim_String(argv[argp++]) : ""), "load", "save", "clear", NULL);
2543 jimapiStrAppendAbbrev(interp, res, a0);
2544 if (isFullyCompleted(a0)) {
2545 const char *a1 = parseAbbrev(a0, "load", "save", NULL);
2546 if (a1 != NULL) {
2547 // load/save
2548 free(a0);
2549 a0 = completeFilesWithExts((argc > argp ? Jim_String(argv[argp++]) : ""), refExtensions);
2550 jimapiStrAppendAbbrev(interp, res, a0);
2553 free(a0);
2554 jimapiAppendRestArgs(res, argp);
2555 Jim_SetResult(interp, res);
2556 return JIM_OK;
2559 const char *a0;
2560 int res = 0;
2562 if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "action name"); return JIM_ERR; }
2563 if ((a0 = parseAbbrev(Jim_String(argv[1]), "load", "save", "clear", NULL)) == NULL) {
2564 jim_SetResStrf(interp, "%s: invalid action: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
2565 return JIM_ERR;
2568 if (strEqu(a0, "load")) {
2569 if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "file name"); return JIM_ERR; }
2570 res = (dbgLoadRefFile(Jim_String(argv[2])) == 0);
2571 if (res) cprintf("'%s' loaded\n", Jim_String(argv[2])); else cprintf("failed to load '%s'\n", Jim_String(argv[2]));
2572 } else if (strEqu(a0, "save")) {
2573 if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "file name"); return JIM_ERR; }
2574 res = (dbgSaveRefFile(Jim_String(argv[2])) == 0);
2575 if (res) cprintf("'%s' saved\n", Jim_String(argv[2])); else cprintf("failed to save '%s'\n", Jim_String(argv[2]));
2576 } else if (strEqu(a0, "clear")) {
2577 dbgClearLabels();
2578 cprintf("labels cleared\n");
2579 res = 1;
2581 Jim_SetResultBool(interp, res);
2582 return JIM_OK;
2586 ////////////////////////////////////////////////////////////////////////////////
2587 // tsmark [force]
2588 JIMAPI_FN(tsmark) {
2589 if (jimapiWantsCompletion(interp, argc, argv)) {
2590 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
2591 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "force", NULL);
2592 jimapiStrAppendAbbrev(interp, res, a0);
2593 free(a0);
2594 jimapiAppendRestArgs(res, 2);
2595 Jim_SetResult(interp, res);
2596 return JIM_OK;
2599 if (argc > 2) {
2600 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
2601 return JIM_ERR;
2604 if (argc > 1) {
2605 const char *a0 = parseAbbrev(Jim_String(argv[1]), "force", NULL);
2606 if (a0 == NULL) {
2607 jim_SetResStrf(interp, "%s: invalid option: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
2608 return JIM_ERR;
2610 tsmark_active = 0;
2613 if (tsmark_active) {
2614 cprintf("\4tstate counter is already active!\n");
2615 Jim_SetResultBool(interp, 0);
2616 } else {
2617 tsmark_active = 1;
2618 tsmark_frames = 0;
2619 tsmark_tstart = z80.tstates;
2620 if (jimapiFromConsole(interp)) cprintf("\1tstate counter started... (ts=%d)\n", z80.tstates);
2621 Jim_SetResultBool(interp, 1);
2624 return JIM_OK;
2628 ////////////////////////////////////////////////////////////////////////////////
2629 // tsdiff [keep]
2630 JIMAPI_FN(tsdiff) {
2631 if (jimapiWantsCompletion(interp, argc, argv)) {
2632 Jim_Obj *res = Jim_NewStringObj(interp, Jim_String(argv[0]), -1);
2633 char *a0 = completeAbbrev((argc > 1 ? Jim_String(argv[1]) : ""), "keep", NULL);
2634 jimapiStrAppendAbbrev(interp, res, a0);
2635 free(a0);
2636 jimapiAppendRestArgs(res, 2);
2637 Jim_SetResult(interp, res);
2638 return JIM_OK;
2641 if (argc > 2) {
2642 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
2643 return JIM_ERR;
2646 int doreset = 1;
2648 if (argc > 1) {
2649 const char *a0 = parseAbbrev(Jim_String(argv[1]), "keep", NULL);
2650 if (a0 == NULL) {
2651 jim_SetResStrf(interp, "%s: invalid option: '%s'", Jim_String(argv[0]), Jim_String(argv[1]));
2652 return JIM_ERR;
2654 doreset = 0;
2657 if (tsmark_active) {
2658 if (doreset) tsmark_active = 0;
2659 const int tstotal = (machineInfo.tsperframe ? machineInfo.tsperframe-tsmark_tstart+(tsmark_frames-1)*machineInfo.tsperframe+z80.tstates : z80.tstates-tsmark_tstart);
2660 const int fullfrm = tstotal/machineInfo.tsperframe;
2661 if (doreset) { if (jimapiFromConsole(interp)) cprintf("counter stopped!\n"); }
2662 if (jimapiFromConsole(interp)) {
2663 cprintf("\1tstate counter: %d\n", tstotal);
2664 cprintf("\2(%d full frame%s, %d in last frame)\n", fullfrm, (fullfrm != 1 ? "s" : ""), tstotal-fullfrm*machineInfo.tsperframe);
2666 Jim_SetResultInt(interp, tstotal);
2667 } else {
2668 cprintf("\4tstate counter is not active!\n");
2669 Jim_SetResultInt(interp, 0);
2671 return JIM_OK;
2675 ////////////////////////////////////////////////////////////////////////////////
2676 // z80 -- various command to manipulate Z80 CPU from Tcl
2677 // always returns old register value
2678 // getreg <name> -- get register
2679 // setreg <name> <value> -- set register
2680 // this is not a console command (yet), so we don't need any autocompletion here
2681 JIMAPI_FN(z80) {
2682 if (argc < 3 || argc > 4) {
2683 jim_SetResStrf(interp, "%s: wut?!", Jim_String(argv[0]));
2684 return JIM_ERR;
2687 const char *cmd = Jim_String(argv[1]);
2688 int cmdread = (strEquCI(cmd, "getreg") ? 1 : strEquCI(cmd, "setreg") ? 0 : -1);
2689 if (cmdread < 0) {
2690 jim_SetResStrf(interp, "%s: invalid command: '%s'", Jim_String(argv[0]), cmd);
2691 return JIM_ERR;
2694 int bytes;
2695 void *regptr = strFindZ80RegPtr(Jim_String(argv[2]), &bytes);
2696 if (!regptr) {
2697 jim_SetResStrf(interp, "%s: invalid register: '%s'", Jim_String(argv[2]), cmd);
2698 return JIM_ERR;
2701 if (!cmdread && argc != 4) {
2702 jim_SetResStrf(interp, "%s: missing value for command: '%s'", Jim_String(argv[0]), cmd);
2703 return JIM_ERR;
2706 // return old value
2707 int val = (bytes == 2 ? *((uint16_t *)regptr) : *((uint8_t *)regptr));
2708 Jim_SetResultInt(interp, val);
2710 // set new value
2711 if (!cmdread) {
2712 int newval = jimGetIntVal(interp, argv[3]);
2713 if (newval == JIM_INVALID_INTVAL) {
2714 jim_SetResStrf(interp, "%s: invalid register value: '%s'", Jim_String(argv[0]), Jim_String(argv[3]));
2715 return JIM_ERR;
2717 if ((bytes == 2 && (newval < -32768 || newval > 65535)) || (bytes == 1 && (newval < -128 || newval > 127))) {
2718 jim_SetResStrf(interp, "%s: register value out of bounds: '%s'", Jim_String(argv[0]), Jim_String(argv[3]));
2719 return JIM_ERR;
2721 if (bytes == 2) *((uint16_t *)regptr) = newval&0xffff; else *((uint8_t *)regptr) = newval&0xff;
2724 return JIM_OK;
2728 ////////////////////////////////////////////////////////////////////////////////
2729 #include "jimapi_uiovl.c"
2732 ////////////////////////////////////////////////////////////////////////////////
2733 void jimInit (void) {
2734 if ((jim = Jim_CreateInterp()) == NULL) { fprintf(stderr, "FATAL: can't init jim-tcl!\n"); exit(1); }
2735 Jim_SetGlobalVariableStr(jim, "jim_unsafe_allowed", Jim_NewIntObj(jim, Jim_GetAllowUnsafeExtensions()));
2736 Jim_RegisterCoreCommands(jim);
2737 Jim_InitStaticExtensions(jim);
2739 //Jim_SetVariableStrWithStr(jim, "emudir", binMyDir);
2740 Jim_SetGlobalVariableStr(jim, "emudir", Jim_NewStringObj(jim, binMyDir, -1));
2742 #ifdef JIM_INTERNAL
2743 Jim_SetGlobalVariableStr(jim, "jim_internal", Jim_NewIntObj(jim, 1));
2744 #else
2745 Jim_SetGlobalVariableStr(jim, "jim_internal", Jim_NewIntObj(jim, 0));
2746 #endif
2748 // set by Tcl code when it neeeds to autocomplete a console command
2749 Jim_SetGlobalVariableStr(jim, "con::autocompletion", Jim_NewIntObj(jim, 0));
2750 // set by Tcl code when it executes a console command (via `conexec`)
2751 Jim_SetGlobalVariableStr(jim, "con::executing", Jim_NewIntObj(jim, 0));
2753 JIMAPI_REGISTER(cputs);
2754 JIMAPI_REGISTER(errputs);
2755 JIMAPI_REGISTER(load);
2756 JIMAPI_REGISTER(softload);
2757 JIMAPI_REGISTER(consetstr);
2759 #ifdef JIM_INTERNAL
2760 jimEvalFile("jimstd/0init.tcl", 0);
2761 #endif
2763 JIMAPI_REGISTER(vid_scale);
2764 JIMAPI_REGISTER(vid_rescaler);
2766 JIMAPI_REGISTER(quit);
2767 JIMAPI_REGISTER(zxbind);
2768 JIMAPI_REGISTER(zxunbind);
2769 JIMAPI_REGISTER(bind);
2770 JIMAPI_REGISTER(unbind);
2772 JIMAPI_REGISTER(reset);
2773 JIMAPI_REGISTER(model);
2775 JIMAPI_REGISTER(snow);
2776 JIMAPI_REGISTER(speed);
2777 JIMAPI_REGISTER(pause);
2778 JIMAPI_REGISTER(temppause);
2779 JIMAPI_REGISTER(timings);
2780 JIMAPI_REGISTER(console);
2781 JIMAPI_REGISTER(kbleds);
2782 JIMAPI_REGISTER(debugger);
2783 JIMAPI_REGISTER(memview);
2784 JIMAPI_REGISTER(sprview);
2785 JIMAPI_REGISTER(screenofs);
2786 JIMAPI_REGISTER(fullscreen);
2787 JIMAPI_REGISTER(noflic);
2788 JIMAPI_REGISTER(brightblack);
2789 JIMAPI_REGISTER(zxpalcolor);
2790 JIMAPI_REGISTER(keyhelp);
2791 JIMAPI_REGISTER(usesound);
2792 JIMAPI_REGISTER(sound);
2793 JIMAPI_REGISTER(filter);
2794 JIMAPI_REGISTER(allowother128);
2795 JIMAPI_REGISTER(keymatrix);
2796 JIMAPI_REGISTER(issue);
2797 JIMAPI_REGISTER(nmi);
2798 JIMAPI_REGISTER(grab);
2799 JIMAPI_REGISTER(swapbuttons);
2800 JIMAPI_REGISTER(maxspeedugly);
2801 JIMAPI_REGISTER(trdos);
2802 JIMAPI_REGISTER(fps);
2803 JIMAPI_REGISTER(kmouse);
2804 JIMAPI_REGISTER(kspanish);
2805 JIMAPI_REGISTER(kjoystick);
2806 JIMAPI_REGISTER(bad7ffd);
2807 JIMAPI_REGISTER(ay);
2808 JIMAPI_REGISTER(autofire);
2809 JIMAPI_REGISTER(genuine);
2810 JIMAPI_REGISTER(colormode);
2811 JIMAPI_REGISTER(brightborder);
2812 JIMAPI_REGISTER(memcontention);
2813 JIMAPI_REGISTER(iocontention);
2814 JIMAPI_REGISTER(contention);
2815 JIMAPI_REGISTER(useplus3);
2816 JIMAPI_REGISTER(genuine);
2818 JIMAPI_REGISTER(curblink);
2820 JIMAPI_REGISTER(rzx);
2821 JIMAPI_REGISTER(snapshot);
2822 JIMAPI_REGISTER(tape);
2823 JIMAPI_REGISTER(disk);
2825 JIMAPI_REGISTER(peek);
2826 JIMAPI_REGISTER(wpeek);
2827 JIMAPI_REGISTER(poke);
2828 JIMAPI_REGISTER(wpoke);
2829 JIMAPI_REGISTER(scrattrfill);
2831 JIMAPI_REGISTER(fldebug);
2832 JIMAPI_REGISTER(opense);
2833 JIMAPI_REGISTER(gluck);
2834 JIMAPI_REGISTER(kbreset);
2835 JIMAPI_REGISTER(ayreset);
2837 JIMAPI_REGISTER(bp);
2838 JIMAPI_REGISTER(label);
2839 JIMAPI_REGISTER(reffile);
2841 JIMAPI_REGISTER(tsmark);
2842 JIMAPI_REGISTER(tsdiff);
2844 JIMAPI_REGISTER(z80);
2846 jimRegisterUIOverlayAPI();
2850 void jimDeinit (void) {
2851 sdlClearBindings(jim, sdlJimBindings);
2852 sdlJimBindings = NULL;
2853 Jim_FreeInterp(jim);
2857 ////////////////////////////////////////////////////////////////////////////////
2858 int jimEvalFile (const char *fname, int okifabsent) {
2859 if (fname && fname[0]) {
2860 char *filename;
2861 if (fname[0] == '/' || access(fname, R_OK) == 0) {
2862 filename = strdup(fname);
2863 } else {
2864 filename = strprintf("%s/tcl/%s", binMyDir, fname);
2867 if (okifabsent) {
2868 if (access(filename, R_OK) != 0) {
2869 free(filename);
2870 return 0;
2874 cprintf("JIM: loading: '%s'\n", filename);
2875 if (Jim_EvalFile(jim, filename) == JIM_OK) {
2876 free(filename);
2877 return 0;
2878 } else {
2879 Jim_MakeErrorMessage(jim);
2880 cprintf("\4JIM ERROR: %s\n", Jim_GetString(Jim_GetResult(jim), NULL));
2882 free(filename);
2885 return -1;
2889 int jimEvalFile1 (const char *fname) {
2890 if (fname != NULL && fname[0] && access(fname, R_OK) == 0) {
2891 cprintf("JIM: loading: '%s'\n", fname);
2892 if (Jim_EvalFile(jim, fname) == JIM_OK) return 0;
2893 Jim_MakeErrorMessage(jim);
2894 cprintf("\4JIM ERROR: %s\n", Jim_GetString(Jim_GetResult(jim), NULL));
2896 return -1;
2900 ////////////////////////////////////////////////////////////////////////////////
2901 void emuInitBindings (void) {
2902 jimEvalFile("init/zxbind.tcl", 0);
2903 jimEvalFile("init/bind.tcl", 0);