/* ** Rexx.c ** ** Copyright (C) 1994,95,96,97 by Bernardo Innocenti ** ** ARexx interface handling routines */ #include #include #include #include #include #include #include #include #include #include #include "XModulePriv.h" #include "Gui.h" struct RexxCmd { const STRPTR Cmd; const STRPTR Template; LONG (*Func)(struct RexxMsg *, LONG *); LONG Pad; /* Makes each entry 16 bytes long for faster array access */ }; /* Local function prototypes */ static LONG ExecRexxCmd (struct RexxMsg *msg, struct RexxCmd *cmd, const UBYTE *rexxargs); static LONG RexxActivate (struct RexxMsg *msg, LONG *args); static LONG RexxClear (struct RexxMsg *msg, LONG *args); static LONG RexxClose (struct RexxMsg *msg, LONG *args); static LONG RexxColumn (struct RexxMsg *msg, LONG *args); static LONG RexxCopy (struct RexxMsg *msg, LONG *args); static LONG RexxCursor (struct RexxMsg *msg, LONG *args); static LONG RexxCut (struct RexxMsg *msg, LONG *args); static LONG RexxDeactivate (struct RexxMsg *msg, LONG *args); static LONG RexxErase (struct RexxMsg *msg, LONG *args); static LONG RexxGotoBookmark (struct RexxMsg *msg, LONG *args); static LONG RexxHelp (struct RexxMsg *msg, LONG *args); static LONG RexxIconify (struct RexxMsg *msg, LONG *args); static LONG RexxLine (struct RexxMsg *msg, LONG *args); static LONG RexxLockGui (struct RexxMsg *msg, LONG *args); static LONG RexxNew (struct RexxMsg *msg, LONG *args); static LONG RexxOpen (struct RexxMsg *msg, LONG *args); static LONG RexxOptimize (struct RexxMsg *msg, LONG *args); static LONG RexxPaste (struct RexxMsg *msg, LONG *args); static LONG RexxPrint (struct RexxMsg *msg, LONG *args); static LONG RexxQuit (struct RexxMsg *msg, LONG *args); static LONG RexxRequestFile (struct RexxMsg *msg, LONG *args); static LONG RexxRequestResponse (struct RexxMsg *msg, LONG *args); static LONG RexxRequestNotify (struct RexxMsg *msg, LONG *args); static LONG RexxSave (struct RexxMsg *msg, LONG *args); static LONG RexxSaveInstrument (struct RexxMsg *msg, LONG *args); static LONG RexxScreenToBack (struct RexxMsg *msg, LONG *args); static LONG RexxScreenToFront (struct RexxMsg *msg, LONG *args); static LONG RexxSelectInstrument(struct RexxMsg *msg, LONG *args); static LONG RexxSetBookmark (struct RexxMsg *msg, LONG *args); static LONG RexxShowMessage (struct RexxMsg *msg, LONG *args); static LONG RexxUnLockGui (struct RexxMsg *msg, LONG *args); static LONG RexxVersion (struct RexxMsg *msg, LONG *args); static struct Library *RexxSysBase = NULL; XDEF struct MsgPort *PubPort = NULL; XDEF ULONG PubPortSig = 0L; XDEF UBYTE PubPortName[16]; /* ARexx host name */ static struct RexxCmd RexxCmds[] = { { "ACTIVATE", NULL, RexxActivate }, { "CLEAR", "FORCE/S", RexxClear }, { "CLOSE", "FORCE/S", RexxClose }, { "COLUMN", "/N/A", RexxColumn }, { "COPY", NULL, RexxCopy }, { "CURSOR", "UP/S,DOWN/S,LEFT/S,RIGHT/S", RexxCursor }, { "CUT", NULL, RexxCut }, { "DEACTIVATE", NULL, RexxDeactivate }, { "ERASE", "FORCE/S", RexxErase }, { "GOTOBOOKMARK", NULL, RexxGotoBookmark }, { "HELP", "COMMAND,PROMPT/S", RexxHelp }, { "ICONIFY", NULL, RexxIconify }, { "LINE", "/N/A", RexxLine }, { "LOCKGUI", NULL, RexxLockGui }, { "NEW", "PORTNAME/K", RexxNew }, { "OPEN", "FILENAME,FORCE/S", RexxOpen }, { "OPTIMIZE", NULL, RexxOptimize }, { "PASTE", NULL, RexxPaste }, { "PRINT", "PROMPT/S", RexxPrint }, { "QUIT", "FORCE/S", RexxQuit }, { "REQUESTFILE", "TITLE/K,PATH/K,FILE/K,PATTERN/K", RexxRequestFile }, { "REQUESTRESPONSE","TITLE/K,PROMPT/K", RexxRequestResponse }, { "REQUESTNOTIFY", "PROMPT/K", RexxRequestNotify }, { "SAVE", "NAME,FORMAT", RexxSave }, { "SAVEINSTRUMENT", "NAME", RexxSaveInstrument }, { "SCREENTOBACK", NULL, RexxScreenToBack }, { "SCREENTOFRONT", NULL, RexxScreenToFront }, { "SELECTINSTRUMENT","/N/A", RexxSelectInstrument }, { "SETBOOKMARK", NULL, RexxSetBookmark }, { "SHOWMESSAGE", "MSG/A", RexxShowMessage }, { "UNLOCKGUI", NULL, RexxUnLockGui }, { "VERSION", NULL, RexxVersion } }; #define COMMAND_CNT (sizeof (RexxCmds) / sizeof (struct RexxCmd)) GLOBALCALL void HandleRexxMsg (void) /* Arexx command handler */ { struct RexxMsg *msg; LONG compare, high, low, mid, skip, cmdlen; STRPTR arg0; UBYTE cmd[32]; while (msg = (struct RexxMsg *) GetMsg (PubPort)) { if (IsRexxMsg (msg)) { msg->rm_Result1 = RETURN_FAIL; /* Find command name length */ arg0 = ARG0(msg); cmdlen = 0; while (*arg0 && (*arg0 != ' ') && (*arg0 != '\t') && (*arg0 != '\n') && (cmdlen < 31)) { cmd[cmdlen] = *arg0 & ~(1 << 5); /* Fast toupper() */ cmdlen++; arg0++; } cmd[cmdlen] = '\0'; skip = 0; low = 0; high = COMMAND_CNT - 1; /* Perform an optimized binary serch to find the ARexx * command in the ARexx commands array. */ do { /* Search optimization. Skip first characters until they * are different. * We must test low != high because otherwise this * loop would go past the end of the string, as the * two strings we compare are identical). */ if (low != high) while ((RexxCmds[low].Cmd[skip] == RexxCmds[high].Cmd[skip]) && (RexxCmds[low].Cmd[skip] == cmd[skip])) skip++; mid = (low + high) >> 1; compare = strcmp (RexxCmds[mid].Cmd + skip, cmd + skip); if (compare > 0) high = mid - 1; else if (compare < 0) low = mid + 1; else { msg->rm_Result1 = ExecRexxCmd (msg, &RexxCmds[mid], ARG0(msg) + cmdlen); break; /* Exit from loop */ } } while (low <= high); } ReplyMsg ((struct Message *)msg); } } static LONG ExecRexxCmd (struct RexxMsg *msg, struct RexxCmd *cmd, const UBYTE *rexxargs) { struct RDArgs *rdargs; UBYTE *argbuf; ULONG arglen = strlen (rexxargs) + 1; /* Space for newline */ LONG rc = RC_ERROR; LONG argarray[6] = { 0L }; /* Max 6 arguments allowed! */ ShowRequesters = FALSE; if (!cmd->Template) rc = (cmd->Func)(msg, NULL); /* Call command directly */ else if (argbuf = AllocVec (arglen, MEMF_ANY)) { /* Copy arguments to temporary buffer. * ReadArgs() also requires a newline. */ strcpy (argbuf, rexxargs); argbuf[arglen-1] = '\n'; if (rdargs = AllocDosObject (DOS_RDARGS, NULL)) { rdargs->RDA_Source.CS_Buffer = argbuf; rdargs->RDA_Source.CS_Length = arglen; rdargs->RDA_Flags |= RDAF_NOPROMPT; if (ReadArgs ((volatile STRPTR)cmd->Template, argarray, rdargs)) { /* Call Command server */ rc = (cmd->Func)(msg, argarray); FreeArgs (rdargs); } FreeDosObject (DOS_RDARGS, rdargs); } FreeVec (argbuf); } ShowRequesters = TRUE; return rc; } GLOBALCALL LONG CreateRexxPort (void) /* Setup public port for ARexx host */ { ULONG i = 0; if (!PubPortName[0]) return RETURN_FAIL; if (!(RexxSysBase = OpenLibrary (RXSNAME, 36L))) return RETURN_FAIL; if (!(PubPort = CreateMsgPort ())) return ERROR_NO_FREE_STORE; PubPortSig = 1 << PubPort->mp_SigBit; Signals |= PubPortSig; Forbid(); while (FindPort (PubPortName)) SPrintf (PubPortName, "XMODULE.%ld", ++i); PubPort->mp_Node.ln_Name = PubPortName; PubPort->mp_Node.ln_Pri = 1; AddPort (PubPort); Permit(); return RETURN_OK; } GLOBALCALL void DeleteRexxPort (void) { if (PubPort) { RemPort (PubPort); KillMsgPort (PubPort); PubPort = NULL; } if (RexxSysBase) { CloseLibrary (RexxSysBase); RexxSysBase = NULL; } } /************************/ /* Rexx Command servers */ /************************/ static LONG RexxActivate (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxClear (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxClose (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxColumn (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxCopy (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxCursor (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxCut (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxDeactivate (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxErase (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxGotoBookmark (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxHelp (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxIconify (struct RexxMsg *msg, LONG *args) { Iconify(); return RETURN_FAIL; } static LONG RexxLine (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxLockGui (struct RexxMsg *msg, LONG *args) { LockWindows(); return RETURN_OK; } static LONG RexxNew (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; if (si = xmCreateSong ( SNGA_ReadyToUse, TRUE, XMSNG_AddToList, -1, XMSNG_Active, TRUE, TAG_DONE)) { ReleaseSemaphore (&si->Lock); return RETURN_OK; } return RETURN_FAIL; } static LONG RexxOpen (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; LockWindows(); if (args[0]) { if (si = xmLoadModule ((STRPTR)args[0], XMSNG_OldSong, NULL, XMSNG_AddToList, TRUE, XMSNG_Active, TRUE, TAG_DONE)) ReleaseSemaphore (&si->Lock); } else { UBYTE filename[PATHNAME_MAX]; filename[0] = '\0'; if (FileRequest (FREQ_LOADMOD, filename)) { if (si = xmLoadModule (filename, XMSNG_OldSong, NULL, XMSNG_AddToList, TRUE, XMSNG_Active, TRUE, TAG_DONE)) ReleaseSemaphore (&si->Lock); } } UnlockWindows(); return LastErr; } static LONG RexxOptimize (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; if (si = xmLockActiveSong (SM_EXCLUSIVE)) { xmProcessSong (si, NULL, XMSNG_Optimize, XMOF_DEFAULT, TAG_DONE); UpdateSongInfo(); ReleaseSemaphore (&si->Lock); } return RETURN_OK; } static LONG RexxPaste (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxPrint (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxQuit (struct RexxMsg *msg, LONG *args) { Quit = 1; if (args[0]) GuiSwitches.AskExit = FALSE; return RETURN_OK; } static LONG RexxRequestFile (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxRequestResponse (struct RexxMsg *msg, LONG *args) { return ShowRequestStr ((STRPTR)args[0], (STRPTR)args[1], NULL); } static LONG RexxRequestNotify (struct RexxMsg *msg, LONG *args) { ShowRequestStr ((STRPTR)args[0], NULL, NULL); return RETURN_OK; } static LONG RexxSave (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; if (si = xmLockActiveSong (SM_SHARED)) { if (args[0]) SetAttrs (si, SNGA_Path, (STRPTR)args[0], TAG_DONE); if (args[1]) { struct XMHook *saver; /* Workaround for Pre-V39 ObtainSemaphoreShared() bug (see autodoc) */ /* Try to get the shared semaphore */ if (!AttemptSemaphoreShared (&XModuleBase->xm_BaseLock)) /* Check if we can get the exclusive version */ if (!AttemptSemaphore (&XModuleBase->xm_BaseLock)) /* Oh well, wait for the shared lock */ ObtainSemaphoreShared (&XModuleBase->xm_BaseLock); if (saver = (struct XMHook *)FindName ((struct List *)&XModuleBase->xm_Loaders, (STRPTR)args[1])) LastErr = xmSaveModuleA (si, si->Path, saver, NULL); else LastErr = ERROR_OBJECT_NOT_FOUND; ReleaseSemaphore (&XModuleBase->xm_BaseLock); } else LastErr = xmSaveModuleA (si, si->Path, NULL, NULL); ReleaseSemaphore (&si->Lock); } return LastErr; } static LONG RexxSaveInstrument (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; if (si = xmLockActiveSong (SM_SHARED)) { struct Instrument *instr; if (instr = si->Instr[si->CurrentInst]) { if (args[0]) LastErr = SaveInstrument (instr, (STRPTR)args[0]); else LastErr = SaveInstrument (instr, instr->Name); } else LastErr = ERROR_OBJECT_NOT_FOUND; ReleaseSemaphore (&si->Lock); } return LastErr; } static LONG RexxSelectInstrument (struct RexxMsg *msg, LONG *args) { struct SongInfo *si; if (si = xmLockActiveSong (SM_SHARED)) { if (*((ULONG *)args[0]) >= MAXINSTRUMENTS) return RETURN_FAIL; si->CurrentInst = *((ULONG *)args[0]); ReleaseSemaphore (&si->Lock); UpdateInstrInfo(); } return RETURN_OK; } static LONG RexxScreenToBack (struct RexxMsg *msg, LONG *args) { if (Scr) ScreenToBack (Scr); return RETURN_OK; } static LONG RexxScreenToFront (struct RexxMsg *msg, LONG *args) { if (Scr) { ScreenToFront (Scr); if (ThisTask->pr_WindowPtr) ActivateWindow (ThisTask->pr_WindowPtr); } return RETURN_OK; } static LONG RexxSetBookmark (struct RexxMsg *msg, LONG *args) { return RETURN_FAIL; } static LONG RexxShowMessage (struct RexxMsg *msg, LONG *args) { ShowString ((STRPTR)args[0], NULL); return RETURN_OK; } static LONG RexxUnLockGui (struct RexxMsg *msg, LONG *args) { UnlockWindows(); return RETURN_OK; } static LONG RexxVersion (struct RexxMsg *msg, LONG *args) { UBYTE RexxVer[8]; SPrintf (RexxVer, "%ld.%ld", VERSION, REVISION); // SetRexxVar ((struct Message *)msg, "RESULT", RexxVer, strlen (RexxVer)); msg->rm_Result2=(LONG)CreateArgstring (RexxVer, (LONG)strlen(RexxVer)); return RETURN_OK; }