Initial commit.
[amiga/xmodule.git] / Rexx.c
1 /*
2 **      Rexx.c
3 **
4 **      Copyright (C) 1994,95,96,97 by Bernardo Innocenti
5 **
6 **      ARexx interface handling routines
7 */
8
9 #include <exec/memory.h>
10 #include <rexx/rxslib.h>
11 #include <rexx/storage.h>
12 #include <rexx/errors.h>
13
14 #include <proto/exec.h>
15 #include <proto/dos.h>
16 #include <proto/intuition.h>
17 #include <proto/utility.h>
18 #include <proto/rexxsyslib.h>
19 #include <proto/xmodule.h>
20
21 #include "XModulePriv.h"
22 #include "Gui.h"
23
24
25
26 struct RexxCmd
27 {
28         const STRPTR Cmd;
29         const STRPTR Template;
30         LONG (*Func)(struct RexxMsg *, LONG *);
31         LONG Pad;       /* Makes each entry 16 bytes long for faster array access */
32 };
33
34
35 /* Local function prototypes */
36
37 static LONG ExecRexxCmd                 (struct RexxMsg *msg, struct RexxCmd *cmd, const UBYTE *rexxargs);
38
39 static LONG RexxActivate                (struct RexxMsg *msg, LONG *args);
40 static LONG RexxClear                   (struct RexxMsg *msg, LONG *args);
41 static LONG RexxClose                   (struct RexxMsg *msg, LONG *args);
42 static LONG RexxColumn                  (struct RexxMsg *msg, LONG *args);
43 static LONG RexxCopy                    (struct RexxMsg *msg, LONG *args);
44 static LONG RexxCursor                  (struct RexxMsg *msg, LONG *args);
45 static LONG RexxCut                             (struct RexxMsg *msg, LONG *args);
46 static LONG RexxDeactivate              (struct RexxMsg *msg, LONG *args);
47 static LONG RexxErase                   (struct RexxMsg *msg, LONG *args);
48 static LONG RexxGotoBookmark    (struct RexxMsg *msg, LONG *args);
49 static LONG RexxHelp                    (struct RexxMsg *msg, LONG *args);
50 static LONG RexxIconify                 (struct RexxMsg *msg, LONG *args);
51 static LONG RexxLine                    (struct RexxMsg *msg, LONG *args);
52 static LONG RexxLockGui                 (struct RexxMsg *msg, LONG *args);
53 static LONG RexxNew                             (struct RexxMsg *msg, LONG *args);
54 static LONG RexxOpen                    (struct RexxMsg *msg, LONG *args);
55 static LONG RexxOptimize                (struct RexxMsg *msg, LONG *args);
56 static LONG RexxPaste                   (struct RexxMsg *msg, LONG *args);
57 static LONG RexxPrint                   (struct RexxMsg *msg, LONG *args);
58 static LONG RexxQuit                    (struct RexxMsg *msg, LONG *args);
59 static LONG RexxRequestFile             (struct RexxMsg *msg, LONG *args);
60 static LONG RexxRequestResponse (struct RexxMsg *msg, LONG *args);
61 static LONG RexxRequestNotify   (struct RexxMsg *msg, LONG *args);
62 static LONG RexxSave                    (struct RexxMsg *msg, LONG *args);
63 static LONG RexxSaveInstrument  (struct RexxMsg *msg, LONG *args);
64 static LONG RexxScreenToBack    (struct RexxMsg *msg, LONG *args);
65 static LONG RexxScreenToFront   (struct RexxMsg *msg, LONG *args);
66 static LONG RexxSelectInstrument(struct RexxMsg *msg, LONG *args);
67 static LONG RexxSetBookmark             (struct RexxMsg *msg, LONG *args);
68 static LONG RexxShowMessage             (struct RexxMsg *msg, LONG *args);
69 static LONG RexxUnLockGui               (struct RexxMsg *msg, LONG *args);
70 static LONG RexxVersion                 (struct RexxMsg *msg, LONG *args);
71
72
73 static struct Library *RexxSysBase = NULL;
74
75 XDEF struct MsgPort *PubPort = NULL;
76 XDEF ULONG PubPortSig = 0L;
77 XDEF UBYTE PubPortName[16];     /* ARexx host name */
78
79
80 static struct RexxCmd RexxCmds[] =
81 {
82         { "ACTIVATE",           NULL,                           RexxActivate },
83         { "CLEAR",                      "FORCE/S",                      RexxClear },
84         { "CLOSE",                      "FORCE/S",                      RexxClose },
85         { "COLUMN",                     "/N/A",                         RexxColumn },
86         { "COPY",                       NULL,                           RexxCopy },
87         { "CURSOR",                     "UP/S,DOWN/S,LEFT/S,RIGHT/S",   RexxCursor },
88         { "CUT",                        NULL,                           RexxCut },
89         { "DEACTIVATE",         NULL,                           RexxDeactivate },
90         { "ERASE",                      "FORCE/S",                      RexxErase },
91         { "GOTOBOOKMARK",       NULL,                           RexxGotoBookmark },
92         { "HELP",                       "COMMAND,PROMPT/S",     RexxHelp },
93         { "ICONIFY",            NULL,                           RexxIconify },
94         { "LINE",                       "/N/A",                         RexxLine },
95         { "LOCKGUI",            NULL,                           RexxLockGui },
96         { "NEW",                        "PORTNAME/K",           RexxNew },
97         { "OPEN",                       "FILENAME,FORCE/S",     RexxOpen },
98         { "OPTIMIZE",           NULL,                           RexxOptimize },
99         { "PASTE",                      NULL,                           RexxPaste },
100         { "PRINT",                      "PROMPT/S",                     RexxPrint },
101         { "QUIT",                       "FORCE/S",                      RexxQuit },
102         { "REQUESTFILE",        "TITLE/K,PATH/K,FILE/K,PATTERN/K", RexxRequestFile },
103         { "REQUESTRESPONSE","TITLE/K,PROMPT/K", RexxRequestResponse },
104         { "REQUESTNOTIFY",      "PROMPT/K",                     RexxRequestNotify },
105         { "SAVE",                       "NAME,FORMAT",          RexxSave },
106         { "SAVEINSTRUMENT",     "NAME",                         RexxSaveInstrument },
107         { "SCREENTOBACK",       NULL,                           RexxScreenToBack },
108         { "SCREENTOFRONT",      NULL,                           RexxScreenToFront },
109         { "SELECTINSTRUMENT","/N/A",                    RexxSelectInstrument },
110         { "SETBOOKMARK",        NULL,                           RexxSetBookmark },
111         { "SHOWMESSAGE",        "MSG/A",                        RexxShowMessage },
112         { "UNLOCKGUI",          NULL,                           RexxUnLockGui },
113         { "VERSION",            NULL,                           RexxVersion }
114 };
115
116 #define COMMAND_CNT (sizeof (RexxCmds) / sizeof (struct RexxCmd))
117
118
119 GLOBALCALL void HandleRexxMsg (void)
120
121 /* Arexx command handler */
122 {
123         struct RexxMsg *msg;
124         LONG     compare, high, low, mid, skip, cmdlen;
125         STRPTR   arg0;
126         UBYTE    cmd[32];
127
128         while (msg = (struct RexxMsg *) GetMsg (PubPort))
129         {
130                 if (IsRexxMsg (msg))
131                 {
132                         msg->rm_Result1 = RETURN_FAIL;
133
134                         /* Find command name length */
135                         arg0 = ARG0(msg);
136                         cmdlen = 0;
137
138                         while (*arg0 && (*arg0 != ' ') && (*arg0 != '\t')
139                                 && (*arg0 != '\n') && (cmdlen < 31))
140                         {
141                                 cmd[cmdlen] = *arg0 & ~(1 << 5);        /* Fast toupper() */
142                                 cmdlen++;
143                                 arg0++;
144                         }
145                         cmd[cmdlen] = '\0';
146
147                         skip = 0;
148                         low = 0;
149                         high = COMMAND_CNT - 1;
150
151                         /* Perform an optimized binary serch to find the ARexx
152                          * command in the ARexx commands array.
153                          */
154                         do
155                         {
156                                 /* Search optimization. Skip first characters until they
157                                  * are different.
158                                  * We must test low != high because otherwise this
159                                  * loop would go past the end of the string, as the
160                                  * two strings we compare are identical).
161                                  */
162                                 if (low != high)
163                                         while ((RexxCmds[low].Cmd[skip] == RexxCmds[high].Cmd[skip])
164                                                 && (RexxCmds[low].Cmd[skip] == cmd[skip]))
165                                                 skip++;
166
167                                 mid = (low + high) >> 1;
168                                 compare = strcmp (RexxCmds[mid].Cmd + skip, cmd + skip);
169
170                                 if (compare > 0)
171                                         high = mid - 1;
172                                 else if (compare < 0)
173                                         low = mid + 1;
174                                 else
175                                 {
176                                         msg->rm_Result1 = ExecRexxCmd (msg, &RexxCmds[mid],
177                                                 ARG0(msg) + cmdlen);
178                                         break; /* Exit from loop */
179                                 }
180                         }
181                         while (low <= high);
182                 }
183
184                 ReplyMsg ((struct Message *)msg);
185         }
186 }
187
188
189
190 static LONG ExecRexxCmd (struct RexxMsg *msg, struct RexxCmd *cmd, const UBYTE *rexxargs)
191 {
192         struct RDArgs *rdargs;
193         UBYTE *argbuf;
194         ULONG arglen = strlen (rexxargs) + 1;   /* Space for newline */
195         LONG rc = RC_ERROR;
196         LONG argarray[6] = { 0L };                      /* Max 6 arguments allowed! */
197
198         ShowRequesters = FALSE;
199
200         if (!cmd->Template)
201                 rc = (cmd->Func)(msg, NULL);    /* Call command directly */
202         else if (argbuf = AllocVec (arglen, MEMF_ANY))
203         {
204                 /* Copy arguments to temporary buffer.
205                  * ReadArgs() also requires a newline.
206                  */
207                 strcpy (argbuf, rexxargs);
208                 argbuf[arglen-1] = '\n';
209
210                 if (rdargs = AllocDosObject (DOS_RDARGS, NULL))
211                 {
212                         rdargs->RDA_Source.CS_Buffer = argbuf;
213                         rdargs->RDA_Source.CS_Length = arglen;
214                         rdargs->RDA_Flags |= RDAF_NOPROMPT;
215
216                         if (ReadArgs ((volatile STRPTR)cmd->Template, argarray, rdargs))
217                         {
218                                 /* Call Command server */
219                                 rc = (cmd->Func)(msg, argarray);
220
221                                 FreeArgs (rdargs);
222                         }
223                         FreeDosObject (DOS_RDARGS, rdargs);
224                 }
225                 FreeVec (argbuf);
226         }
227
228         ShowRequesters = TRUE;
229
230         return rc;
231 }
232
233
234
235 GLOBALCALL LONG CreateRexxPort (void)
236
237 /* Setup public port for ARexx host */
238 {
239         ULONG i = 0;
240
241         if (!PubPortName[0]) return RETURN_FAIL;
242
243         if (!(RexxSysBase = OpenLibrary (RXSNAME, 36L)))
244                 return RETURN_FAIL;
245
246         if (!(PubPort = CreateMsgPort ())) return ERROR_NO_FREE_STORE;
247
248         PubPortSig = 1 << PubPort->mp_SigBit;
249         Signals |= PubPortSig;
250
251         Forbid();
252         while (FindPort (PubPortName))
253                 SPrintf (PubPortName, "XMODULE.%ld", ++i);
254
255         PubPort->mp_Node.ln_Name = PubPortName;
256         PubPort->mp_Node.ln_Pri = 1;
257         AddPort (PubPort);
258         Permit();
259
260         return RETURN_OK;
261 }
262
263
264 GLOBALCALL void DeleteRexxPort (void)
265 {
266         if (PubPort)
267         {
268                 RemPort (PubPort);
269                 KillMsgPort (PubPort); PubPort = NULL;
270         }
271
272         if (RexxSysBase)
273                 { CloseLibrary (RexxSysBase); RexxSysBase = NULL; }
274 }
275
276 /************************/
277 /* Rexx Command servers */
278 /************************/
279
280 static LONG RexxActivate                (struct RexxMsg *msg, LONG *args)
281 {
282         return RETURN_FAIL;
283 }
284
285 static LONG RexxClear                   (struct RexxMsg *msg, LONG *args)
286 {
287         return RETURN_FAIL;
288 }
289
290 static LONG RexxClose                   (struct RexxMsg *msg, LONG *args)
291 {
292         return RETURN_FAIL;
293 }
294
295 static LONG RexxColumn                  (struct RexxMsg *msg, LONG *args)
296 {
297         return RETURN_FAIL;
298 }
299
300 static LONG RexxCopy                    (struct RexxMsg *msg, LONG *args)
301 {
302         return RETURN_FAIL;
303 }
304
305 static LONG RexxCursor                  (struct RexxMsg *msg, LONG *args)
306 {
307         return RETURN_FAIL;
308 }
309
310 static LONG RexxCut                             (struct RexxMsg *msg, LONG *args)
311 {
312         return RETURN_FAIL;
313 }
314
315 static LONG RexxDeactivate              (struct RexxMsg *msg, LONG *args)
316 {
317         return RETURN_FAIL;
318 }
319
320
321
322 static LONG RexxErase                   (struct RexxMsg *msg, LONG *args)
323 {
324         return RETURN_FAIL;
325 }
326
327
328
329 static LONG RexxGotoBookmark    (struct RexxMsg *msg, LONG *args)
330 {
331         return RETURN_FAIL;
332 }
333
334
335
336 static LONG RexxHelp                    (struct RexxMsg *msg, LONG *args)
337 {
338         return RETURN_FAIL;
339 }
340
341
342
343 static LONG RexxIconify                 (struct RexxMsg *msg, LONG *args)
344 {
345         Iconify();
346         return RETURN_FAIL;
347 }
348
349
350
351 static LONG RexxLine                    (struct RexxMsg *msg, LONG *args)
352 {
353         return RETURN_FAIL;
354 }
355
356
357
358 static LONG RexxLockGui         (struct RexxMsg *msg, LONG *args)
359 {
360         LockWindows();
361
362         return RETURN_OK;
363 }
364
365
366
367 static LONG RexxNew                             (struct RexxMsg *msg, LONG *args)
368 {
369         struct SongInfo *si;
370
371         if (si = xmCreateSong (
372                 SNGA_ReadyToUse,        TRUE,
373                 XMSNG_AddToList,        -1,
374                 XMSNG_Active,           TRUE,
375                 TAG_DONE))
376         {
377                 ReleaseSemaphore (&si->Lock);
378                 return RETURN_OK;
379         }
380
381         return RETURN_FAIL;
382 }
383
384
385
386 static LONG RexxOpen (struct RexxMsg *msg, LONG *args)
387 {
388         struct SongInfo *si;
389
390         LockWindows();
391
392         if (args[0])
393         {
394                 if (si = xmLoadModule ((STRPTR)args[0],
395                         XMSNG_OldSong,          NULL,
396                         XMSNG_AddToList,        TRUE,
397                         XMSNG_Active,           TRUE,
398                         TAG_DONE))
399                         ReleaseSemaphore (&si->Lock);
400         }
401         else
402         {
403                 UBYTE filename[PATHNAME_MAX];
404
405                 filename[0] = '\0';
406
407                 if (FileRequest (FREQ_LOADMOD, filename))
408                 {
409                         if (si = xmLoadModule (filename,
410                                 XMSNG_OldSong,          NULL,
411                                 XMSNG_AddToList,        TRUE,
412                                 XMSNG_Active,           TRUE,
413                                 TAG_DONE))
414                                 ReleaseSemaphore (&si->Lock);
415                 }
416         }
417
418         UnlockWindows();
419
420         return LastErr;
421 }
422
423
424
425 static LONG RexxOptimize (struct RexxMsg *msg, LONG *args)
426 {
427         struct SongInfo *si;
428
429         if (si = xmLockActiveSong (SM_EXCLUSIVE))
430         {
431                 xmProcessSong (si, NULL,
432                         XMSNG_Optimize, XMOF_DEFAULT,
433                         TAG_DONE);
434
435                 UpdateSongInfo();
436
437                 ReleaseSemaphore (&si->Lock);
438         }
439
440         return RETURN_OK;
441 }
442
443
444
445 static LONG RexxPaste                   (struct RexxMsg *msg, LONG *args)
446 {
447         return RETURN_FAIL;
448 }
449
450
451
452 static LONG RexxPrint                   (struct RexxMsg *msg, LONG *args)
453 {
454         return RETURN_FAIL;
455 }
456
457
458
459 static LONG RexxQuit (struct RexxMsg *msg, LONG *args)
460 {
461         Quit = 1;
462         if (args[0]) GuiSwitches.AskExit = FALSE;
463
464         return RETURN_OK;
465 }
466
467
468
469 static LONG RexxRequestFile             (struct RexxMsg *msg, LONG *args)
470 {
471         return RETURN_FAIL;
472 }
473
474
475
476 static LONG RexxRequestResponse (struct RexxMsg *msg, LONG *args)
477 {
478         return ShowRequestStr ((STRPTR)args[0], (STRPTR)args[1], NULL);
479 }
480
481
482
483 static LONG RexxRequestNotify   (struct RexxMsg *msg, LONG *args)
484 {
485         ShowRequestStr ((STRPTR)args[0], NULL, NULL);
486         return RETURN_OK;
487 }
488
489
490
491 static LONG RexxSave (struct RexxMsg *msg, LONG *args)
492 {
493         struct SongInfo *si;
494
495         if (si = xmLockActiveSong (SM_SHARED))
496         {
497                 if (args[0])
498                         SetAttrs (si,
499                                 SNGA_Path, (STRPTR)args[0],
500                                 TAG_DONE);
501
502                 if (args[1])
503                 {
504                         struct XMHook *saver;
505
506                         /* Workaround for Pre-V39 ObtainSemaphoreShared() bug (see autodoc) */
507
508                         /* Try to get the shared semaphore */
509                         if (!AttemptSemaphoreShared (&XModuleBase->xm_BaseLock))
510                                 /* Check if we can get the exclusive version */
511                                 if (!AttemptSemaphore (&XModuleBase->xm_BaseLock))
512                                         /* Oh well, wait for the shared lock */
513                                         ObtainSemaphoreShared (&XModuleBase->xm_BaseLock);
514
515                         if (saver = (struct XMHook *)FindName ((struct List *)&XModuleBase->xm_Loaders, (STRPTR)args[1]))
516                                 LastErr = xmSaveModuleA (si, si->Path, saver, NULL);
517                         else
518                                 LastErr = ERROR_OBJECT_NOT_FOUND;
519
520                         ReleaseSemaphore (&XModuleBase->xm_BaseLock);
521                 }
522                 else
523                         LastErr = xmSaveModuleA (si, si->Path, NULL, NULL);
524
525                 ReleaseSemaphore (&si->Lock);
526         }
527
528         return LastErr;
529 }
530
531
532
533 static LONG RexxSaveInstrument (struct RexxMsg *msg, LONG *args)
534 {
535         struct SongInfo *si;
536
537         if (si = xmLockActiveSong (SM_SHARED))
538         {
539                 struct Instrument *instr;
540
541                 if (instr = si->Instr[si->CurrentInst])
542                 {
543                         if (args[0])
544                                 LastErr = SaveInstrument (instr, (STRPTR)args[0]);
545                         else
546                                 LastErr = SaveInstrument (instr, instr->Name);
547                 }
548                 else LastErr = ERROR_OBJECT_NOT_FOUND;
549
550                 ReleaseSemaphore (&si->Lock);
551         }
552
553         return LastErr;
554 }
555
556
557
558 static LONG RexxSelectInstrument (struct RexxMsg *msg, LONG *args)
559 {
560         struct SongInfo *si;
561
562         if (si = xmLockActiveSong (SM_SHARED))
563         {
564                 if (*((ULONG *)args[0]) >= MAXINSTRUMENTS)
565                         return RETURN_FAIL;
566
567                 si->CurrentInst = *((ULONG *)args[0]);
568
569                 ReleaseSemaphore (&si->Lock);
570
571                 UpdateInstrInfo();
572         }
573
574         return RETURN_OK;
575 }
576
577
578
579 static LONG RexxScreenToBack (struct RexxMsg *msg, LONG *args)
580 {
581         if (Scr) ScreenToBack (Scr);
582
583         return RETURN_OK;
584 }
585
586
587
588 static LONG RexxScreenToFront (struct RexxMsg *msg, LONG *args)
589 {
590         if (Scr)
591         {
592                 ScreenToFront (Scr);
593                 if (ThisTask->pr_WindowPtr) ActivateWindow (ThisTask->pr_WindowPtr);
594         }
595
596         return RETURN_OK;
597 }
598
599
600
601 static LONG RexxSetBookmark (struct RexxMsg *msg, LONG *args)
602 {
603         return RETURN_FAIL;
604 }
605
606
607
608 static LONG RexxShowMessage (struct RexxMsg *msg, LONG *args)
609 {
610         ShowString ((STRPTR)args[0], NULL);
611
612         return RETURN_OK;
613 }
614
615
616
617 static LONG RexxUnLockGui (struct RexxMsg *msg, LONG *args)
618 {
619         UnlockWindows();
620         return RETURN_OK;
621 }
622
623
624
625 static LONG RexxVersion (struct RexxMsg *msg, LONG *args)
626 {
627         UBYTE RexxVer[8];
628
629         SPrintf (RexxVer, "%ld.%ld", VERSION, REVISION);
630
631 //      SetRexxVar ((struct Message *)msg, "RESULT", RexxVer, strlen (RexxVer));
632         msg->rm_Result2=(LONG)CreateArgstring (RexxVer, (LONG)strlen(RexxVer));
633
634         return RETURN_OK;
635 }