home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 10 / Fresh_Fish_10_2352.bin / useful / util / edit / mg / src.lzh / amiga / rexx.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  21KB  |  918 lines

  1. /*
  2.  * This file sends out and recieves REXX commands (well recieving them means
  3.  * we hand the off to excline, but...)
  4.  */
  5. #include "rexx.h"
  6.  
  7. #ifdef    REXX
  8.  
  9. #include <exec/types.h>
  10. #include <exec/ports.h>
  11. #include <rexx/storage.h>
  12. #include <rexx/rxslib.h>
  13. #ifdef LATTICE
  14. #include <proto/exec.h>
  15. #include <proto/intuition.h>
  16. #else
  17. #include <functions.h>
  18. #endif
  19.  
  20. #undef    TRUE
  21. #undef    FALSE
  22. #include "def.h"
  23. #include "line.h"
  24. #include "buffer.h"
  25. #include "window.h"
  26. #include "macro.h"
  27. #include "region.h"
  28.  
  29. #ifdef    ANSI
  30. #undef    EOF            /* Strange..., but stdio complains about it */
  31. #include <stdio.h>        /* Only if we've got sprintf in here */
  32. #include <stdlib.h>
  33. #include <fcntl.h>
  34. #undef    HUGE            /* Collides with math.h */
  35. #include <math.h>
  36. #include <string.h>
  37. #endif
  38.  
  39. /*
  40.  * The pointer to the Rexx library, which we really want when dealing with
  41.  * Rexx, and some return value for messages.
  42.  */
  43. struct Library *RexxSysBase;
  44. #define    FAIL_LOCKED    3
  45. #define FAIL_NOREXX    4
  46.  
  47. /*
  48.  * My static functions.
  49.  */
  50. static int rexxdocommand PROTO((char *, long));
  51. static int getrexxargs PROTO((struct RexxMsg *, int));
  52. static int rexxread PROTO((int));
  53. static int rexxstemint PROTO((char *, int, int));
  54. static int rexxstemstring PROTO((char *, int, char *, int));
  55. static int findline PROTO((struct line *));
  56. static struct MsgPort *lockport PROTO((char *));
  57. static int spinport PROTO((struct MsgPort *));
  58.  
  59. #ifdef    LATTICE
  60. long __stdargs SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
  61. #else
  62. long SetRexxVar PROTO((struct RexxMsg *, char *, char *, long)) ;
  63. static char *strupr PROTO((char *));
  64. #endif
  65.  
  66. struct RexxArg *CreateArgstring PROTO((char *, long)) ;
  67. long LengthArgstring PROTO((struct RexxArg *)) ;
  68. void DeleteArgstring PROTO((struct RexxArg *)) ;
  69. struct RexxMsg *CreateRexxMsg PROTO((struct MsgPort *, char *, char *)) ;
  70. void ClearRexxMsg PROTO((struct RexxMsg *, long)) ;
  71. void DeleteRexxMsg PROTO((struct RexxMsg *)) ;
  72.  
  73. /*
  74.  * Pointer to rexx macro to run on exit.
  75.  */
  76. static char    *RexxExitCmd;
  77.  
  78. /*
  79.  * Commands that return results can only do so if the RexxMsg that caused
  80.  * them to be executed is willing to take results. To make this test easy,
  81.  * the RexxMsg is stored in CurrentMsg between it's being recieved and
  82.  * sending out the reply. Any other time, it will be NULL, and the Rexx
  83.  * command check for that if they shouldn't be executed unless there is a
  84.  * RexxMsg active. In addition, rexxlock needs to reply to this message
  85.  * indicating that the lock succeeded before going into locked mode, so it
  86.  * needs access to CurrentMsg. Result strings get passed from rexx commands
  87.  * back to the script - and the other way, in the case of rexxdoregion - via
  88.  * RexxResult. It's normally NULL, unless the executed command set a result,
  89.  * or a macro that we were still locked to on exit returned a result. In
  90.  * which case, it points to the RexxArgstring for the result. The consumer is
  91.  * responsible for deleting it, and the producer is responsible for creating
  92.  * it.
  93.  * 
  94.  */
  95. static struct RexxMsg *CurrentMsg = NULL;
  96. static struct RexxArg *RexxResult = NULL;
  97.  
  98. /*
  99.  * Things for dealing with asynch REXX messages. rexxport is the port that
  100.  * those messages come in on, and it's name is mgname. Since rexxport must be
  101.  * checked for messages in the event loop, it's not static. RepliesNeeded is
  102.  * the number of reply messages we need to see on rexxport. Lockadd is the
  103.  * address of the port name that a given macro is locked to, or NULL if we're
  104.  * not locked. ADDSIZE is the size of the port name we use for dynamically
  105.  * allocated ports
  106.  */
  107. struct MsgPort *rexxport = NULL;
  108. static char     mgname[5] = "mg\0\0";
  109. static unsigned RepliesNeeded = 0;
  110. static char    *lockadd = NULL;
  111. #define ADDSIZE    8
  112.  
  113. /*
  114.  * This routine dispatches any REXX messages coming in. However, to allow for
  115.  * REXX commands that start other REXX commands, we must save and restore the
  116.  * environment (CurrentMsg).
  117.  */
  118. int
  119. disprexx(inport)
  120.     struct MsgPort *inport;
  121. {
  122.     register int    s, t;
  123.     register struct RexxMsg *savemsg;
  124.  
  125.     savemsg = CurrentMsg;
  126.  
  127.     for (;;) {
  128.         RexxResult = NULL;
  129.         /* Check for commands */
  130.         if (inport && (CurrentMsg = (struct RexxMsg *) GetMsg(inport))) {
  131.             if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
  132.                 s = excline(ARG0(CurrentMsg),
  133.                     LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
  134.         }
  135.         /* And then for replies or asynch commands */
  136.         else if (CurrentMsg = (struct RexxMsg *) GetMsg(rexxport)) {
  137.             if (CurrentMsg->rm_Node.mn_Node.ln_Type != NT_REPLYMSG)
  138.                 if (!inport)
  139.                     s = FAIL_NOREXX;
  140.                 else if (lockadd)
  141.                     s = FAIL_LOCKED;
  142.                 else
  143.                     s = excline(ARG0(CurrentMsg),
  144.                         LengthArgstring((struct RexxArg *) ARG0(CurrentMsg)));
  145.         }
  146.         if (CurrentMsg == NULL)
  147.             break;
  148.         if (CurrentMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
  149.             RepliesNeeded -= 1;
  150.             s = CurrentMsg->rm_Result1 < 2
  151.                 ? 1 - CurrentMsg->rm_Result1
  152.                 : ABORT;
  153.             t = ((char *)CurrentMsg->rm_CommAddr == lockadd);
  154.             if (s == TRUE && (CurrentMsg->rm_Action & RXFF_RESULT)
  155.                 && CurrentMsg->rm_Result2 != NULL)
  156.                 /* Aha - a result. Deal with it. */
  157.                 if (t)
  158.                     RexxResult = (struct RexxArg *) CurrentMsg->rm_Result2;
  159.                 else
  160.                     DeleteArgstring((struct RexxArg *)
  161.                             CurrentMsg->rm_Result2);
  162.             /* Free the memory for this message */
  163.             FreeMem(CurrentMsg->rm_CommAddr, ADDSIZE);
  164.             ClearRexxMsg(CurrentMsg, 16);
  165.             DeleteRexxMsg(CurrentMsg);
  166.             if (!t)
  167.                 continue;
  168.             CurrentMsg = savemsg;
  169.             lockadd = NULL;
  170.             return s;
  171.         }
  172.         if (s < 2)
  173.             s = 1 - s;
  174.         CurrentMsg->rm_Result1 = s;
  175.         CurrentMsg->rm_Result2 = (RexxResult != NULL)
  176.             ? (LONG) RexxResult
  177.             : 0L;
  178.         ReplyMsg((struct Message *) CurrentMsg);
  179.     }
  180.     CurrentMsg = savemsg;
  181.     return -1;
  182. }
  183.  
  184. void
  185. openrexx()
  186. {
  187.     register short  i, j;
  188.  
  189.     if ((RexxSysBase = OpenLibrary(RXSNAME, 0)) == NULL)
  190.         return;
  191.     srand((unsigned) &lockadd);    /* Just to make things change */
  192.     for (i = 33; i < 127; i++) {
  193.         for (j = 33; j < 127; j++) {
  194.             Forbid();
  195.             if (FindPort(mgname) == NULL)
  196.                 rexxport = CreatePort(mgname, 0L);
  197.             Permit();
  198.             if (rexxport != NULL)
  199.                 return;
  200.             mgname[2] = j;
  201.         }
  202.         mgname[3] = i;
  203.     }
  204.  
  205.     /* No port opened, so we don't do Rexx, so we close RexxSysBase */
  206.     CloseLibrary(RexxSysBase);
  207.     RexxSysBase = NULL;
  208. }
  209.  
  210. void
  211. closerexx()
  212. {
  213.  
  214.     if (!RexxSysBase)
  215.         return;        /* No Rexx to close */
  216.     if (RexxExitCmd != NULL)
  217.         rexxdocommand(RexxExitCmd, RXCOMM);
  218.     if (rexxport) {
  219.         while (RepliesNeeded) {
  220.             WaitPort(rexxport);
  221.             disprexx(NULL);
  222.         }
  223.         DeletePort(rexxport);
  224.     }
  225.     CloseLibrary(RexxSysBase);
  226. }
  227. /*
  228.  * Commands that make Rexx macros execute.
  229.  */
  230.  
  231. rexxexitcommand(f, n)
  232. {
  233.     int             s;
  234.     static char     exitcom[NLINE];
  235.  
  236.     if (!RexxSysBase)
  237.         return FALSE;
  238.     if ((s = ereply("REXX command to run on exit: ", exitcom, NLINE)) != TRUE)
  239.         return s;
  240.     RexxExitCmd = exitcom;
  241.     return TRUE;
  242. }
  243.  
  244. rexxcommand(f, n)
  245. {
  246.     int             s;
  247.     char            cmd[NLINE];
  248.  
  249.     if (!RexxSysBase)
  250.         return FALSE;
  251.     if ((s = ereply("REXX command: ", cmd, NLINE)) != TRUE)
  252.         return s;
  253.  
  254.     return rexxdocommand(cmd, f & FFUNIV ? RXCOMM | RXFF_TOKEN : RXCOMM);
  255. }
  256.  
  257. rexxcomregion(f, n)
  258.     int             f, n;
  259. {
  260.     char           *out;
  261.     register RSIZE  length, size;
  262.     register struct line *lp;
  263.     int             status, insertres;
  264.     char           *string;
  265.     struct region   reg;
  266.  
  267.     if (!RexxSysBase)
  268.         return FALSE;
  269.     if ((length = getregion(®)) != TRUE)
  270.         return length;
  271.     size = reg.r_size;
  272.  
  273.     if ((out = malloc(size + 1)) == NULL) {
  274.         ewprintf("Can't get %d bytes", size + 1);
  275.         return FALSE;
  276.     }
  277.     string = out;        /* Save the start of the thing... */
  278.  
  279.     /* Copy the region to out */
  280.     lp = reg.r_linep;
  281.     length = llength(lp) - reg.r_offset;
  282.     bcopy(<ext(lp)[reg.r_offset], out, length);
  283.     size -= length;
  284.     out += length;
  285.  
  286.     while (size > 0) {
  287.         /* Add a newline to the output string */
  288.         *out++ = '\n';
  289.         size -= 1;
  290.  
  291.         /* Add part/all of the current line to the output string */
  292.         lp = lforw(lp);
  293.         length = llength(lp);
  294.         if (length > size)
  295.             length = size;
  296.         bcopy(ltext(lp), out, length);
  297.         out += length;
  298.         size -= length;
  299.     }
  300.     *out = '\0';
  301.  
  302.     /* Figure out how many arguments we really have */
  303.     insertres = (n <= 0);
  304.     if ((f & FFARG) == 0)
  305.         n = 0;
  306.     else if (insertres)
  307.         n = -n;
  308.     if (n > MAXRMARG) {
  309.         ewprintf("Can only have