fix(tcl-wasm): register magic:: Tcl commands after C initialization completes

magic_wasm_init() called Tclmagic_Init() and magicMainInit() but never
ran the command-registration loop in _magic_initialize(), so magic::tech,
magic::load, magic::gds and all other Magic commands were missing from
the Tcl interpreter.

Add TclmagicRegisterCommands() in tclmagic.c containing the
WindNextClient/WindGetCommandTable loop and call it from magic_wasm_init()
after magicMainInit() succeeds.

Also change magic_wasm_source_file() to use Tcl_EvalFile in MAGIC_WRAPPER
mode so scripts with magic:: commands are evaluated through the Tcl
interpreter instead of the plain text dispatcher.
This commit is contained in:
Intubun 2026-05-21 10:25:51 +02:00
parent 4eb8a4da40
commit 8fdd2eec20
3 changed files with 66 additions and 20 deletions

View File

@ -98,7 +98,18 @@ magic_wasm_init(void)
}
#endif
return magicMainInit(5, argv);
{
static int commandsRegistered = FALSE;
int rc = magicMainInit(5, argv);
#ifdef MAGIC_WRAPPER
if (rc == 0 && !commandsRegistered)
{
TclmagicRegisterCommands(magicinterp);
commandsRegistered = TRUE;
}
#endif
return rc;
}
}
EMSCRIPTEN_KEEPALIVE int
@ -134,7 +145,6 @@ magic_wasm_run_command(const char *command)
EMSCRIPTEN_KEEPALIVE int
magic_wasm_source_file(const char *path)
{
FILE *f;
int status;
status = magic_wasm_init();
@ -144,27 +154,30 @@ magic_wasm_source_file(const char *path)
if ((path == NULL) || (*path == '\0'))
return -1;
f = PaOpen((char *)path, "r", (char *)NULL, ".", (char *)NULL,
(char **)NULL);
if (f == NULL)
{
TxError("Unable to open command file \"%s\".\n", path);
return -1;
}
/* Set the current point to the centre of the screen so that
* WindSendCommand routes all commands from the file to the layout
* window client, just as magic_wasm_run_command does for single
* commands. Without this, commands arrive with point (0,0) and
* end up in the border/windClient context where most commands are
* unknown.
*/
TxSetPoint(GrScreenRect.r_xtop / 2, GrScreenRect.r_ytop / 2,
WIND_UNKNOWN_WINDOW);
TxDispatch(f);
fclose(f);
return 0;
#ifdef MAGIC_WRAPPER
/* In wrapper mode the file contains Tcl; evaluate it through the
* Tcl interpreter so that magic:: commands are dispatched via
* _tcl_dispatch just like magic_wasm_run_command does for strings. */
if (magicinterp == NULL)
return -1;
return Tcl_EvalFile(magicinterp, path);
#else
{
FILE *f = PaOpen((char *)path, "r", (char *)NULL, ".", (char *)NULL,
(char **)NULL);
if (f == NULL)
{
TxError("Unable to open command file \"%s\".\n", path);
return -1;
}
TxDispatch(f);
fclose(f);
return 0;
}
#endif
}
EMSCRIPTEN_KEEPALIVE void

View File

@ -656,6 +656,37 @@ process_rlimit_startup_check(void)
#endif /* HAVE_GETRLIMIT */
}
/*------------------------------------------------------*/
/* Register magic:: commands with the Tcl interpreter. */
/* Called after Magic's C subsystems are fully */
/* initialized (i.e. after magicMainInit returns 0) */
/* so that WindNextClient / WindGetCommandTable return */
/* populated tables. */
/*------------------------------------------------------*/
void
TclmagicRegisterCommands(Tcl_Interp *interp)
{
WindClient client;
int n;
char keyword[100];
char *kwptr = keyword + 7;
const char * const *commandTable;
sprintf(keyword, "magic::");
client = (WindClient)NULL;
while ((client = WindNextClient(client)) != NULL)
{
commandTable = WindGetCommandTable(client);
for (n = 0; commandTable[n] != NULL; n++)
{
sscanf(commandTable[n], "%s ", kwptr);
Tcl_CreateCommand(interp, keyword, (Tcl_CmdProc *)_tcl_dispatch,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
}
}
}
/*------------------------------------------------------*/
/* Main startup procedure */
/*------------------------------------------------------*/

View File

@ -32,5 +32,7 @@ extern void MakeWindowCommand();
extern const char *Tclmagic_InitStubsVersion;
extern void TclmagicRegisterCommands(Tcl_Interp *interp);
#endif /* MAGIC_WRAPPER */
#endif /* _MAGIC__TCLTK__TCLMAGIC_H */