/* * UAE - The Un*x Amiga Emulator * * ami-rexx.c * * Copyright 1996 Samuel Devulder. * Copyright 2004-2006 Richard Drummond * * History: * 05/09/97: Added UAEEXE support. * 04/03/98: Added event-hack for SOUND(). Added do_inhibit_frame(). * 03/05/98: Modified currprefs to changed_prefs where necessary. */ /****************************************************************************/ #if defined(POWERUP) # include /* sam: I've added this or else I have * warnings about missing struct def. */ #ifndef USE_CLIB # include # include # include # else # include # include # endif #else # include # include # include # include # ifndef __SASC # include # endif #endif #include #include /* this prevent a conflict between and */ #undef DT_DIR /****************************************************************************/ #include "sysconfig.h" #include "sysdeps.h" #include "uae.h" #include "options.h" #include "memory.h" #include "custom.h" #include "newcpu.h" #include "disk.h" #include "audio.h" #include "uaeexe.h" #include "xwin.h" #include "drawing.h" #include "debug.h" #include "version.h" #include /****************************************************************************/ #define UAE_PORTNAME "UAE" #define RESULT_LEN 1024 #define PORT_LEN 80 #define CMD_LEN 1024 typedef struct { char port[PORT_LEN]; char cmd_on[CMD_LEN]; char cmd_off[CMD_LEN]; } gui_rexx_s; enum { LED_POW, LED_DF0, LED_DF1, LED_DF2, LED_DF3, NAME_DF0, NAME_DF1, NAME_DF2, NAME_DF3, ON_EXIT, GUI_REXX_MAX }; /****************************************************************************/ int rexx_init (void); void rexx_exit (void); void rexx_led (int led, int on); void rexx_filename (unsigned int num, const char *name); void rexx_handle_events (void); /****************************************************************************/ #if defined __GNUC__ && !defined __amigaos4__ && !defined __morphos__ typedef struct RxsLib REXXBASE; #else typedef struct Library REXXBASE; #endif REXXBASE *RexxSysBase = NULL; #ifdef __amigaos4__ struct RexxSysIFace *IRexxSys; #endif static struct MsgPort *ARexxPort; static gui_rexx_s gui_rexx[GUI_REXX_MAX]; static char RESULT[RESULT_LEN]; static int led_state[5]; static int ADDRESS (const char *hostname, const char *cmd); static int matchstr (const char **line, const char *pat); static void extractstr (const char **line, char *result, unsigned int len); static int matchnum (const char **line); /****************************************************************************/ extern ULONG frame_num; /* ami-win.c */ /****************************************************************************/ int rexx_init (void) { RexxSysBase = (REXXBASE *) OpenLibrary ("rexxsyslib.library", 0L); if (!RexxSysBase) { write_log ("Can't find rexxsyslib.library!\n"); return 0; } #ifdef __amigaos4__ IRexxSys = (struct RexxSysIFace *) GetInterface (RexxSysBase, "main", 1, NULL); if (!IRexxSys) { CloseLibrary (RexxSysBase); RexxSysBase = 0; return 0; } #endif if (FindPort(UAE_PORTNAME)) { write_log ("Port \"%s\" already exists!\n", UAE_PORTNAME); return 0; } ARexxPort = CreatePort (UAE_PORTNAME, 0); if (!ARexxPort) { write_log ("Failed to open AREXX port \"%s\"!\n", UAE_PORTNAME); return 0; } write_log ("Rexx port \"%s\" installed.\n", UAE_PORTNAME); rexx_handle_events (); return 1; } /****************************************************************************/ void rexx_exit (void) { if (ARexxPort) { struct RexxMsg *msg; gui_rexx_s *gui = &gui_rexx[ON_EXIT]; if (gui->port[0] && gui->cmd_on[0]) { if (ADDRESS(gui->port, gui->cmd_on) != RC_OK) { write_log ("%s:%s:%s\n", gui->port, gui->cmd_on, RESULT); } gui->port[0] = '\0'; } Forbid (); while ((msg = (struct RexxMsg*)GetMsg (ARexxPort))) { msg->rm_Result1 = RC_ERROR; msg->rm_Result2 = 0; ReplyMsg ((void*)msg); } DeletePort (ARexxPort); Permit (); ARexxPort = NULL; } #ifdef __amigaos4__ if (IRexxSys) { DropInterface ((struct Interface *)IRexxSys); IRexxSys = NULL; } #endif if (RexxSysBase) { CloseLibrary ((void*)RexxSysBase); RexxSysBase = NULL; } } /****************************************************************************/ static int EJECT (const char *line) { unsigned int drive = matchnum (&line); int result = RC_WARN; if (drive < 4) { if (currprefs.dfxtype[drive] >= 0) { disk_eject (drive); sprintf (RESULT, "Drive %d ejected.", drive); result = RC_OK; } else sprintf (RESULT, "Drive %d is disabled.", drive); } return result; } /****************************************************************************/ static int INSERT (const char *line) { unsigned int drive = matchnum (&line); int result = RC_WARN; if (drive < 4) { if (currprefs.dfxtype[drive] >= 0) { char buff[256]; extractstr (&line, buff, 256); strcpy (changed_prefs.df[drive], buff); result = RC_OK; } else sprintf (RESULT, "Drive %d is disabled.", drive); } return result; } /****************************************************************************/ static void QUIT (void) { uae_quit (); } /****************************************************************************/ static int QUERY (const char *line) { const char *res = NULL; if (matchstr (&line, "LED_POW")) res = led_state[0] ? "1" : "0"; else if (matchstr (&line, "LED_DF0")) res = led_state[1] ? "1" : "0"; else if (matchstr (&line, "LED_DF1")) res = led_state[2] ? "1" : "0"; else if (matchstr (&line, "LED_DF2")) res = led_state[3] ? "1" : "0"; else if (matchstr (&line, "LED_DF3")) res = led_state[4] ? "1" : "0"; else if (matchstr (&line, "NAME_DF0")) res = currprefs.df[0]; else if (matchstr (&line, "NAME_DF1")) res = currprefs.df[1]; else if (matchstr (&line, "NAME_DF2")) res = currprefs.df[2]; else if (matchstr (&line, "NAME_DF3")) res = currprefs.df[3]; else if (matchstr (&line, "FAKEJOYSTICK")) res = 0; //res = currprefs.fake_joystick ? "1" : "0"; else if (matchstr (&line, "DISPLAY")) res = inhibit_frame ? "0" : "1"; else if (matchstr (&line, "FRAMERATE")) { sprintf (RESULT, "%d", currprefs.gfx_framerate); return RC_OK; } else if (matchstr (&line, "FRAMENUM")) { #ifdef USE_AMIGA_GFX sprintf (RESULT, "%u", frame_num); #else sprintf (RESULT, "%d", 0); #endif return RC_OK; } else if (matchstr (&line, "SOUND")) { sprintf (RESULT, "%d", sound_available ? currprefs.produce_sound : -1); return RC_OK; } else return RC_ERROR; if (res) strncpy (RESULT, res, RESULT_LEN); return RC_OK; } /****************************************************************************/ static int FEEDBACK (const char *line) { gui_rexx_s *gui = NULL; if (matchstr (&line, "LED_POW")) gui = &gui_rexx[LED_POW]; else if (matchstr (&line, "LED_DF0")) gui = &gui_rexx[LED_DF0]; else if (matchstr (&line, "LED_DF1")) gui = &gui_rexx[LED_DF1]; else if (matchstr (&line, "LED_DF2")) gui = &gui_rexx[LED_DF2]; else if (matchstr (&line, "LED_DF3")) gui = &gui_rexx[LED_DF3]; else if (matchstr (&line, "NAME_DF0")) gui = &gui_rexx[NAME_DF0]; else if (matchstr (&line, "NAME_DF1")) gui = &gui_rexx[NAME_DF1]; else if (matchstr (&line, "NAME_DF2")) gui = &gui_rexx[NAME_DF2]; else if (matchstr (&line, "NAME_DF3")) gui = &gui_rexx[NAME_DF3]; else if (matchstr (&line, "ON_EXIT")) gui = &gui_rexx[ON_EXIT]; else return RC_ERROR; while(1) { if (matchstr (&line, "ADDRESS") || matchstr (&line, "PORT")) { extractstr (&line, gui->port, PORT_LEN); } else if (matchstr (&line,"COMMAND") || matchstr (&line,"CMD") || matchstr (&line,"CMD_ON")) { extractstr (&line, gui->cmd_on, CMD_LEN); } else if (matchstr(&line,"CMD_OFF")) { extractstr(&line, gui->cmd_off, CMD_LEN); } else break; } return RC_OK; } /****************************************************************************/ static int GET_VERSION (const char *line) { if (matchstr (&line, "STRING")) { sprintf (RESULT, PACKAGE_NAME "-" PACKAGE_VERSION " by Richard Drummond & contributors, " "Amiga Port based on work by Samuel Devulder."); } else if (matchstr (&line, "NUM")) { sprintf (RESULT, "%d", UAEMAJOR * 10000 + UAEMINOR * 100 + UAESUBREV); } else if (matchstr (&line, "AUTHOR")) { sprintf (RESULT," by Richard Drummond & contributors"); } else if (matchstr (&line, "PORT")) { sprintf (RESULT, "Amiga Port based on work by Samuel Devulder"); } else return RC_ERROR; return RC_OK; } /****************************************************************************/ static int FRAMERATE (const char *line) { int num; num = matchnum (&line); if (num >= 1 && num <= 20) changed_prefs.gfx_framerate = num; else { sprintf (RESULT,"Invalid frame rate: %d\n", num); return RC_WARN; } return RC_OK; } /****************************************************************************/ static int FAKEJOYSTICK (const char *line) { /* if (matchstr(&line,"ON")) changed_prefs.fake_joystick = 2; else if(matchstr(&line,"OFF")) changed_prefs.fake_joystick = 0; else if(matchstr(&line,"TOGGLE")) changed_prefs.fake_joystick = currprefs.fake_joystick?0:2; else return RC_ERROR; return RC_OK; */ return 0; } /****************************************************************************/ static int DISPLAY (const char *line) { if (matchstr (&line, "ON")) clear_inhibit_frame (IHF_SCROLLLOCK); else if (matchstr (&line, "OFF")) set_inhibit_frame (IHF_SCROLLLOCK); else if (matchstr (&line, "TOGGLE")) toggle_inhibit_frame (IHF_SCROLLLOCK); else return RC_ERROR; return RC_OK; } /****************************************************************************/ static int SOUND (const char *line) { if (!sound_available) { sprintf (RESULT, "Sound not available!"); return RC_WARN; } if (matchstr (&line, "ON")) currprefs.produce_sound = 2; else if (matchstr (&line, "OFF")) currprefs.produce_sound = 1; else if (matchstr (&line, "BEST")) currprefs.produce_sound = 3; else if (matchstr (&line, "TOGGLE")) currprefs.produce_sound = currprefs.produce_sound <= 1 ? 2 : 1; else return RC_ERROR; /* sam: the next 2 lines is a hack and I don't like it */ /* eventtab[ev_sample].active = (changed_prefs.produce_sound>=2)?1:0; events_schedule (); */ return RC_OK; } /****************************************************************************/ static int DEBUG (void) { #ifdef DEBUGGER activate_debugger (); return RC_OK; #else return RC_ERROR; #endif } /****************************************************************************/ static int UAEEXE (const char *line) { if (uaeexe (line)) { sprintf (RESULT, "Remote CLI failed!"); return RC_WARN; } return RC_OK; } /****************************************************************************/ static int process_cmd (const char *line) { RESULT[0] = '\0'; if (matchstr (&line, "EJECT")) return EJECT (line); else if (matchstr (&line, "INSERT")) return INSERT (line); else if (matchstr (&line, "QUERY")) return QUERY (line); else if (matchstr (&line, "FEEDBACK")) return FEEDBACK (line); else if (matchstr (&line, "VERSION")) return GET_VERSION (line); else if (matchstr (&line, "BYE")) QUIT (); else if (matchstr (&line, "QUIT")) QUIT (); else if (matchstr (&line, "DEBUG")) return DEBUG (); else if (matchstr (&line, "RESET")) m68k_reset (); else if (matchstr (&line, "DISPLAY")) return DISPLAY (line); else if (matchstr (&line, "FRAMERATE")) return FRAMERATE( line); else if (matchstr (&line, "FAKEJOYSTICK")) return FAKEJOYSTICK (line); else if (matchstr (&line, "SOUND")) return SOUND (line); else if (matchstr (&line, "UAEEXE")) return UAEEXE (line); else return RC_ERROR; return RC_OK; } /****************************************************************************/ void rexx_handle_events (void) { struct RexxMsg *msg; while ((msg = (struct RexxMsg*)GetMsg (ARexxPort))) { if (!(msg->rm_Action & RXCOMM)) { write_log ("Unknown action '%08X' recieved!\n", msg->rm_Action); continue; } msg->rm_Result1 = process_cmd (msg->rm_Args[0]); msg->rm_Result2 = 0; if (msg->rm_Action & RXFF_RESULT) { int len = strlen (RESULT); /* holger: trick for powerup */ msg->rm_Result2 = (LONG)CreateArgstring (RESULT,len); } ReplyMsg ((void*)msg); } } /****************************************************************************/ void rexx_led (int led, int on) { gui_rexx_s *gui = NULL; if (led < 0 || led > 4) return; led_state[led] = on; if (led == 0) gui = &gui_rexx[LED_POW]; if (led == 1) gui = &gui_rexx[LED_DF0]; if (led == 2) gui = &gui_rexx[LED_DF1]; if (led == 3) gui = &gui_rexx[LED_DF2]; if (led == 4) gui = &gui_rexx[LED_DF3]; if (gui->port[0] && gui->cmd_on[0] && gui->cmd_off[0]) { if (ADDRESS (gui->port, on ? gui->cmd_on : gui->cmd_off) != RC_OK) { write_log ("%s:%s:%s\n", gui->port, on ? gui->cmd_on : gui->cmd_off, RESULT); } } } /****************************************************************************/ void rexx_filename (unsigned int num, const char *filename) { gui_rexx_s *gui = NULL; if (num > 3) return; gui = &gui_rexx[NAME_DF0 + num]; if (gui->port[0] && gui->cmd_on[0]) { char buf[CMD_LEN]; sprintf (buf, gui->cmd_on, filename); if (ADDRESS (gui->port, buf) != RC_OK) { write_log ("%s:%s:%s\n", gui->port, buf, RESULT); } } } /****************************************************************************/ /* send a message to an AREXX port. */ static int ADDRESS (const char *hostname, const char *cmd) { struct MsgPort *RexxPort, *ReplyPort; struct RexxMsg *HostMsg, *answer; int result = RC_WARN; if (!stricmp (hostname, "COMMAND")) return SystemTagList(cmd,NULL); if ((RexxPort = (void *)FindPort (hostname))) { if ((ReplyPort = (void *)CreateMsgPort ())) { if ((HostMsg = CreateRexxMsg (ReplyPort, NULL, hostname))) { unsigned int len = strlen (cmd); /* holger: trick for powerup */ if ((HostMsg->rm_Args[0] = CreateArgstring ((char *)cmd, len))) { HostMsg->rm_Action = RXCOMM | RXFF_RESULT; PutMsg (RexxPort, (void*)HostMsg); WaitPort (ReplyPort); while (!(answer = (void *)GetMsg (ReplyPort))); result = answer->rm_Result1; if (result == RC_OK) { if (answer->rm_Result2) { strncpy (RESULT,(char *)answer->rm_Result2, RESULT_LEN); DeleteArgstring ((char *)answer->rm_Result2); } else RESULT[0] = '\0'; } DeleteArgstring (HostMsg->rm_Args[0]); } else strcpy (RESULT, "Can't create argstring!"); DeleteRexxMsg (HostMsg); } else strcpy (RESULT, "Can't create rexx message!"); DeleteMsgPort (ReplyPort); } else strcpy (RESULT, "Can't alloc reply port!"); } else sprintf (RESULT, "Port \"%s\" not found!", hostname); return result; } /****************************************************************************/ /* argument parsing routines */ static int matchstr (const char **line, const char *pat) { const char *s = *line; char match = 0; while (isspace (*s)) ++s; if (*s == '\"' || *s == '\'') match = *s++; while (*s && (tolower (*s) == tolower (*pat)) && (!match || *s != match)) {++s;++pat;} if (match && *s == match && s[1]) ++s; if (!*pat && (!*s || isspace (*s))) { while (isspace (*s)) ++s; *line = s; return 1; } return 0; } /****************************************************************************/ static void extractstr (const char **line, char *result, unsigned int len) { const char *s = *line; char match = 0; while (isspace(*s)) ++s; if (*s == '\"' || *s == '\'') match = *s++; while (*s && *s != match) { if (*s == '\\' && (s[1] == '\'' || s[1] == '\"')) ++s; if (len > 1) { *result++ = *s; --len; } ++s; if (!match && isspace (*s)) break; } if (match && *s == match) ++s; while (isspace (*s)) ++s; *result = '\0'; *line = s; } /****************************************************************************/ static int matchnum (const char **line) { const char *s = *line; char match = 0; int sign = 1, num = 0; while (isspace (*s)) ++s; if (*s == '\"' || *s == '\'') match = *s++; if (*s == '-') { sign = -1; ++s; } if (*s == '+') ++s; while (isspace (*s)) ++s; while (*s >= '0' && *s <= '9') num = num * 10 + (*s++ - '0'); if (match && *s == match && s[1]) ++s; while (isspace (*s)) ++s; *line = s; return sign > 0 ? num : -num; } /****************************************************************************/ #ifdef POWERUP /* sam: those function should be in the ppc version of the unexisting libamiga.a */ #define NEWLIST(l) ((l)->lh_Head = (struct Node *)&(l)->lh_Tail, \ /*(l)->lh_Tail = NULL,*/ \ (l)->lh_TailPred = (struct Node *)&(l)->lh_Head) struct MsgPort *CreatePort (STRPTR name, LONG pri) { struct MsgPort *port = NULL; UBYTE portsig; if ((BYTE)(portsig = AllocSignal (-1)) >= 0) { if (!(port = PPCAllocMem (sizeof (struct MsgPort), MEMF_CLEAR | MEMF_PUBLIC))) FreeSignal(portsig); else { port->mp_Node.ln_Type = NT_MSGPORT; port->mp_Node.ln_Pri = pri; port->mp_Node.ln_Name = name; /* done via AllocMem * port->mp_Flags = PA_SIGNAL; */ port->mp_SigBit = portsig; port->mp_SigTask = FindTask (NULL); NEWLIST (&port->mp_MsgList); if (port->mp_Node.ln_Name) AddPort(port); } } return port; } void DeletePort (struct MsgPort *port) { int i; if (port->mp_Node.ln_Name != NULL) RemPort (port); i = -1; port->mp_Node.ln_Type = i; port->mp_MsgList.lh_Head = (struct Node *)i; FreeSignal (port->mp_SigBit); PPCFreeMem (port, sizeof (struct MsgPort)); } struct IORequest *CreateExtIO (struct MsgPort *port, long iosize) { struct IORequest *ioreq=NULL; if (port && (ioreq = PPCAllocMem (iosize, MEMF_CLEAR | MEMF_PUBLIC))) { ioreq->io_Message.mn_Node.ln_Type = NT_REPLYMSG; ioreq->io_Message.mn_ReplyPort = port; ioreq->io_Message.mn_Length = iosize; } return ioreq; } struct IOStdReq *CreateStdIO (struct MsgPort *port) { return (struct IOStdReq *)CreateExtIO (port, sizeof (struct IOStdReq)); } void DeleteExtIO (struct IORequest *ioreq) { int i; i=-1; ioreq->io_Message.mn_Node.ln_Type = i; ioreq->io_Device = (struct Device *)i; ioreq->io_Unit = (struct Unit *)i; PPCFreeMem (ioreq, ioreq->io_Message.mn_Length); } void DeleteStdIO (struct IORequest *ioreq) { DeleteExtIO (ioreq); } #endif