home *** CD-ROM | disk | FTP | other *** search
- #include "SimpleRexx.h"
- #include <proto/exec.h>
- #undef NULL
- #include "config.h"
- #include "lisp.h"
-
- #include "amiga.h"
-
- static AREXXCONTEXT far handle;
-
- #define REXXSIZE 32
-
- static struct {
- int rc; /* 0 for commands, <> 0, for errors */
- union {
- struct { int id; int code; } error; /* Of failed messages */
- struct RexxMsg *msg; /* Received command */
- } u;
- } pending_rexx_msgs[REXXSIZE];
- static int pending_rexx_num, pending_rexx_in, pending_rexx_out;
- static int amiga_arexx_initialized;
-
- static struct {
- struct RexxMsg *msg;
- int id;
- } sent_rexx_msg[REXXSIZE];
- static int sent_rexx_id;
-
- int check_arexx(int force, int kbd)
- {
- struct RexxMsg *rmsg;
- int msg_received = FALSE;
-
- while (rmsg = GetARexxMsg(handle))
- {
- msg_received = TRUE;
-
- if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
- {
- int i;
-
- /* The message has been returned, remove it from sent messages */
- for (i = 0; i < REXXSIZE && sent_rexx_msg[i].msg != rmsg; i++) ;
- if (i < REXXSIZE) sent_rexx_msg[i].msg = 0;
-
- if (rmsg->rm_Result1)
- {
- /* There was an error, add it to pending_rexx_msgs */
- if (pending_rexx_num != REXXSIZE)
- {
- pending_rexx_num++;
- pending_rexx_msgs[pending_rexx_in].u.error.id =
- i < REXXSIZE ? sent_rexx_msg[i].id : 0;
- pending_rexx_msgs[pending_rexx_in].u.error.code = rmsg->rm_Result2;
- pending_rexx_msgs[pending_rexx_in].rc = rmsg->rm_Result1;
- pending_rexx_in = (pending_rexx_in + 1) % REXXSIZE;
- }
- /* else ignore this error */
- }
- DeleteARexxMsg(handle, rmsg);
- }
- else
- {
- if (pending_rexx_num == REXXSIZE)
- {
- /* Oops! Throw out message */
- SetARexxLastError(handle, rmsg, "Emacs too busy");
- ReplyARexxMsg(handle, rmsg, 0, 20);
- }
- else
- {
- pending_rexx_num++;
- pending_rexx_msgs[pending_rexx_in].u.msg = rmsg;
- pending_rexx_msgs[pending_rexx_in].rc = 0;
- pending_rexx_in = (pending_rexx_in + 1) % REXXSIZE;
- }
- }
- }
- if (kbd && amiga_arexx_initialized && (msg_received || force && pending_rexx_num > 0))
- {
- enque(AMIGASEQ, FALSE); enque('X', FALSE);
- }
- return msg_received;
- }
-
- DEFUN ("amiga-arexx-wait", Famiga_arexx_wait, Samiga_arexx_wait, 0, 0, 0,
- "Wait for an ARexx event (command or reply) before proceeding.")
- ()
- {
- while (!check_arexx(FALSE, FALSE)) Wait(ARexxSignal(handle));
- }
-
- DEFUN ("amiga-arexx-check-command",
- Famiga_arexx_check_command, Samiga_arexx_check_command, 1, 1, 0,
- "Return t if command ID has finished, nil otherwise.")
- (id)
- {
- int i, nid;
-
- CHECK_NUMBER (id, 0);
- nid = XUINT (id);
-
- for (i = 0; i < REXXSIZE && (!sent_rexx_msg[i].msg || nid != sent_rexx_msg[i].id);
- i++) ;
-
- return i == REXXSIZE ? Qnil : Qt;
- }
-
- DEFUN ("amiga-arexx-get-event", Famiga_arexx_get_event, Samiga_arexx_get_event,
- 0, 0, 0,
- "Returns next arexx event, either an error or a command to execute.\n\
- If no event is waiting, nil is returned.\n\
- Errors are returned as a (id-of-failed-command severity error-code) list\n\
- (Don't answer these events!).\n\
- Commands are strings sent by an arexx process. They should be answered via\n\
- amiga-arexx-reply. amiga-arexx-get-event will always return the same command\n\
- till you do so.")
- ()
- {
- struct RexxMsg *rmsg;
-
- check_arexx(FALSE, FALSE);
- if (pending_rexx_num)
- if (pending_rexx_msgs[pending_rexx_out].rc)
- {
- Lisp_Object id, error, rc;
- Lisp_Object res;
-
- XSET (id, Lisp_Int, pending_rexx_msgs[pending_rexx_out].u.error.id);
- XSET (error, Lisp_Int,
- pending_rexx_msgs[pending_rexx_out].u.error.code & VALMASK);
- XSET (rc, Lisp_Int, pending_rexx_msgs[pending_rexx_out].rc & VALMASK);
- res = Fcons (id, Fcons (rc, Fcons (error, Qnil)));
-
- pending_rexx_out = (pending_rexx_out + 1) % REXXSIZE;
- pending_rexx_num--;
-
- return res;
- }
- else return build_string(ARG0(pending_rexx_msgs[pending_rexx_out].u.msg));
-
- return Qnil;
- }
-
- DEFUN ("amiga-arexx-reply", Famiga_arexx_reply, Samiga_arexx_reply,
- 2, 2, 0,
- "Replies to the first arexx message (the one got via amiga-arexx-get-event)\n\
- with RC as return code.\n\
- If RC=0, TEXT is the result, otherwise it is the error text. It can be nil.")
- (rc, text)
- {
- int retcode;
- char *result;
- struct RexxMsg *rmsg;
- int ok = TRUE;
-
- if (!pending_rexx_num) error("No ARexx message to reply to.");
- CHECK_NUMBER(rc, 0);
- retcode = XINT(rc);
-
- if (!NULL (text))
- {
- CHECK_STRING(text, 0);
- result = XSTRING (text)->data;
- }
- else result = 0;
-
- if (pending_rexx_msgs[pending_rexx_out].rc)
- error("You can't answer an error !");
- rmsg = pending_rexx_msgs[pending_rexx_out].u.msg;
- pending_rexx_out = (pending_rexx_out + 1) % REXXSIZE;
- pending_rexx_num--;
-
- if (retcode && result)
- ok = SetARexxLastError(handle, rmsg, result);
- ReplyARexxMsg(handle, rmsg, result, retcode);
-
- if (!ok) error("Failed to set ARexx error message.");
-
- return Qnil;
- }
-
- DEFUN ("amiga-arexx-send-command", Famiga_arexx_send_command, Samiga_arexx_send_command,
- 1, 2, "sARexx command: \n\
- P",
- "Sends a command to ARexx for execution.\n\
- If the second arg is non-nil, the command is directly interpreted.\n\
- Returns an integer that uniquely identifies this message (for use in ???).")
- (str, as_file)
- {
- struct ARexxMsg *rmsg;
- int i;
- Lisp_Object id;
-
- /* Find a free slot for message */
- for (i = 0; i < REXXSIZE && sent_rexx_msg[i].msg; i++) ;
- if (i == REXXSIZE) error("Too many arexx commands pending (max %d)", REXXSIZE);
-
- CHECK_STRING (str, 0);
- if (!(rmsg = SendARexxMsg(handle, XSTRING (str)->data, !NULL (as_file))))
- error("Failed to send command to ARexx.");
-
- sent_rexx_msg[i].msg = rmsg;
- sent_rexx_id = (sent_rexx_id + 1) & VALMASK;
- sent_rexx_msg[i].id = sent_rexx_id;
-
-
- XSET (id, Lisp_Int, sent_rexx_id);
- return id;
- }
-
- void init_amiga_rexx(void)
- {
- extern ULONG inputsig;
- int i;
-
- handle = InitARexx("Emacs", "elx");
- inputsig |= ARexxSignal(handle);
- pending_rexx_num = pending_rexx_in = pending_rexx_out = 0;
- for (i = 0; i < REXXSIZE; i++) sent_rexx_msg[i].msg = 0;
- sent_rexx_id = 0;
- }
-
- void cleanup_amiga_rexx(void)
- {
- FreeARexx(handle);
- }
-
- void syms_of_amiga_rexx(void)
- {
- DEFVAR_BOOL ("amiga-arexx-initialized", &amiga_arexx_initialized,
- "Set this to t when Emacs is ready to respond to ARexx messages.\n\
- (ie C-\ X causes all pending ARexx messages to be answered)");
- amiga_arexx_initialized = 0;
- defsubr(&Samiga_arexx_send_command);
- defsubr(&Samiga_arexx_reply);
- defsubr(&Samiga_arexx_get_event);
- defsubr(&Samiga_arexx_check_command);
- defsubr(&Samiga_arexx_wait);
- }
-