Wire up headless / WASM mode at module boundaries
Glue between the null display driver and the rest of Magic so that running with -d null does not require any process-level resources (signals, timers, stdin, an X display, or a Tcl interpreter). * utils/signals.c — gate setitimer, fcntl-based file watches, kill and the legacy sigsetmask/sigaction setup behind #ifdef __EMSCRIPTEN__. Every signals path becomes a no-op in WASM. Also fixes DBWriteBackup() being called with one argument when its real prototype takes three. * windows/windDisp.c — WindUpdate() returns immediately when GrDisplayStatus == DISPLAY_SUSPEND. This is the runtime counterpart to the null driver's DISPLAY_SUSPEND state. * extflat/EFargs.c — EFArgs() with a missing input name no longer jumps to "usage:" in headless WASM (which would call MainExit and kill the process); it sets *err_result and returns NULL so the caller can decide what to do. Native MAGIC_WRAPPER and native non-MAGIC_WRAPPER builds keep their original behavior. * dbwind/DBWcommands.c — registers exttosim / ext2sim / exttospice / ext2spice in non-MAGIC_WRAPPER builds. Without this, WASM users could not invoke these commands at all (they were previously inside an #ifdef MAGIC_WRAPPER block). The C implementations (CmdExtToSim / CmdExtToSpice) are linked unconditionally outside modular builds. * textio/txCommands.c, textio/textio.h — TxDispatchString(), a new library-style command entry point that parses a single string, dispatches it through WindSendCommand and returns a status code. This is what magic_wasm_run_command() calls from JavaScript.
This commit is contained in:
parent
b63f83ac0f
commit
9dcb9681f6
|
|
@ -149,6 +149,9 @@ extern void CmdAutoExtToSpice();
|
|||
#else
|
||||
extern void CmdExtToSpice();
|
||||
#endif
|
||||
#else /* !MAGIC_WRAPPER */
|
||||
extern void CmdExtToSim();
|
||||
extern void CmdExtToSpice();
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -568,8 +571,26 @@ DBWInitCommands()
|
|||
"ext2spice [args] convert extracted file(s) to a SPICE format file;"
|
||||
" type\n\t\t\t\"ext2spice help\" for information on options",
|
||||
CmdExtToSpice, FALSE);
|
||||
#endif /* EXT2SPICE_AUTO */
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
#endif /* EXT2SPICE_AUTO */
|
||||
#else /* !MAGIC_WRAPPER */
|
||||
/* In non-Tcl builds (e.g. WASM), register the C implementations directly */
|
||||
WindAddCommand(DBWclientID,
|
||||
"exttosim [args] convert extracted file(s) to a sim format file;"
|
||||
" type\n\t\t\t\"exttosim help\" for information on options",
|
||||
CmdExtToSim, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"ext2sim [args] convert extracted file(s) to a sim format file;"
|
||||
" type\n\t\t\t\"ext2sim help\" for information on options",
|
||||
CmdExtToSim, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"exttospice [args] convert extracted file(s) to a SPICE format file;"
|
||||
" type\n\t\t\t\"exttospice help\" for information on options",
|
||||
CmdExtToSpice, FALSE);
|
||||
WindAddCommand(DBWclientID,
|
||||
"ext2spice [args] convert extracted file(s) to a SPICE format file;"
|
||||
" type\n\t\t\t\"ext2spice help\" for information on options",
|
||||
CmdExtToSpice, FALSE);
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
|
||||
|
||||
#ifdef USE_READLINE
|
||||
|
|
|
|||
|
|
@ -307,6 +307,12 @@ EFArgs(argc, argv, err_result, argsProc, cdata)
|
|||
if (inname == NULL)
|
||||
#ifdef MAGIC_WRAPPER
|
||||
return NULL;
|
||||
#elif defined(EMSCRIPTEN)
|
||||
{
|
||||
/* Headless WASM: signal error via err_result, no goto usage path */
|
||||
if (err_result != NULL) *err_result = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
goto usage;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ extern char TxInterruptChar; /* The current interrupt character */
|
|||
|
||||
/* command procedures */
|
||||
extern void TxDispatch(FILE *f);
|
||||
extern int TxDispatchString(const char *str, bool quiet);
|
||||
|
||||
/* C99 compat */
|
||||
extern void TxMore(const char *mesg);
|
||||
|
|
|
|||
|
|
@ -1751,6 +1751,47 @@ done:
|
|||
DQFree(&inputCommands);
|
||||
}
|
||||
|
||||
int
|
||||
TxDispatchString(
|
||||
const char *str,
|
||||
bool quiet)
|
||||
{
|
||||
int result = 0;
|
||||
DQueue inputCommands;
|
||||
|
||||
DQInit(&inputCommands, 4);
|
||||
TxParseString_internal(str, &inputCommands, (TxInputEvent *) NULL);
|
||||
|
||||
while (!DQIsEmpty(&inputCommands))
|
||||
{
|
||||
TxCommand *cmd;
|
||||
|
||||
cmd = (TxCommand *) DQPopFront(&inputCommands);
|
||||
|
||||
if (txHaveCurrentPoint)
|
||||
{
|
||||
cmd->tx_p = txCurrentPoint;
|
||||
cmd->tx_wid = txCurrentWindowID;
|
||||
txHaveCurrentPoint = FALSE;
|
||||
}
|
||||
|
||||
result = WindSendCommand((MagWindow *) NULL, cmd, quiet);
|
||||
TxFreeCommand(cmd);
|
||||
TxCommandNumber++;
|
||||
|
||||
if (result != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
WindUpdate();
|
||||
|
||||
while (!DQIsEmpty(&inputCommands))
|
||||
TxFreeCommand((TxCommand *) DQPopFront(&inputCommands));
|
||||
DQFree(&inputCommands);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !MAGIC_WRAPPER */
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#endif
|
||||
|
||||
/* specially imported */
|
||||
extern bool DBWriteBackup();
|
||||
/* DBWriteBackup declared in database/database.h */
|
||||
|
||||
/* macs support BSD4.2 signals, so turn off the SYSV flag for this module */
|
||||
#ifdef __APPLE__
|
||||
|
|
@ -123,6 +123,10 @@ static int sigNumDisables = 0;
|
|||
void
|
||||
SigSetTimer(int secs)
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(void)secs;
|
||||
return;
|
||||
#else
|
||||
struct itimerval subsecond; /* one-quarter second interval */
|
||||
|
||||
/*
|
||||
|
|
@ -139,6 +143,7 @@ SigSetTimer(int secs)
|
|||
subsecond.it_value.tv_usec = (secs == 0) ? 250000 : 0;
|
||||
|
||||
setitimer(ITIMER_REAL, &subsecond, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------*/
|
||||
|
|
@ -148,6 +153,9 @@ SigSetTimer(int secs)
|
|||
void
|
||||
SigRemoveTimer()
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return;
|
||||
#else
|
||||
struct itimerval zero; /* zero time to stop the timer */
|
||||
|
||||
/* fprintf(stderr, "Timer stop\n"); fflush(stderr); */
|
||||
|
|
@ -158,6 +166,7 @@ SigRemoveTimer()
|
|||
zero.it_interval.tv_usec = 0;
|
||||
|
||||
setitimer(ITIMER_REAL, &zero, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
sigRetVal
|
||||
|
|
@ -256,11 +265,16 @@ bool
|
|||
SigCheckProcess(pid)
|
||||
int pid;
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(void)pid;
|
||||
return FALSE;
|
||||
#else
|
||||
int result;
|
||||
result = kill((pid_t)pid, SIGCONT);
|
||||
|
||||
if (result == 0) return TRUE;
|
||||
else return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------
|
||||
|
|
@ -334,6 +348,11 @@ SigWatchFile(filenum, filename)
|
|||
* calls (such as windows: /dev/winXX).
|
||||
*/
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(void)filenum;
|
||||
(void)filename;
|
||||
return;
|
||||
#else
|
||||
int flags;
|
||||
bool iswindow;
|
||||
|
||||
|
|
@ -383,6 +402,7 @@ SigWatchFile(filenum, filename)
|
|||
# endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -409,6 +429,11 @@ SigUnWatchFile(filenum, filename)
|
|||
* calls (such as windows: /dev/winXX).
|
||||
*/
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
(void)filenum;
|
||||
(void)filename;
|
||||
return;
|
||||
#else
|
||||
int flags;
|
||||
|
||||
flags = fcntl(filenum, F_GETFL, 0);
|
||||
|
|
@ -429,6 +454,7 @@ SigUnWatchFile(filenum, filename)
|
|||
perror("(Magic) SigWatchFile3");
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -475,7 +501,7 @@ sigOnInterrupt(int signo)
|
|||
sigRetVal
|
||||
sigOnTerm(int signo)
|
||||
{
|
||||
DBWriteBackup(NULL);
|
||||
DBWriteBackup(NULL, FALSE, FALSE);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
|
@ -614,6 +640,13 @@ void
|
|||
SigInit(batchmode)
|
||||
int batchmode;
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
SigInterruptOnSigIO = (batchmode) ? -1 : 0;
|
||||
SigInterruptPending = FALSE;
|
||||
SigIOReady = FALSE;
|
||||
SigGotSigWinch = FALSE;
|
||||
return;
|
||||
#else
|
||||
/* fprintf(stderr, "Establishing signal handlers.\n"); fflush(stderr); */
|
||||
|
||||
if (batchmode)
|
||||
|
|
@ -669,6 +702,7 @@ SigInit(batchmode)
|
|||
#if !defined(SYSV) && !defined(CYGWIN) && !defined(EMSCRIPTEN)
|
||||
sigsetmask(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -795,6 +795,10 @@ WindUpdate()
|
|||
SigSetTimer(0);
|
||||
#endif
|
||||
|
||||
/* For headless/no-display mode: skip if display is suspended */
|
||||
if (GrDisplayStatus == DISPLAY_SUSPEND)
|
||||
return;
|
||||
|
||||
TTMaskSetOnlyType(&windTileMask, TT_ERROR_P);
|
||||
|
||||
/* Make a scan through each of the windows, in order from top
|
||||
|
|
|
|||
Loading…
Reference in New Issue