/* this should of been a rexx program but it couldn't be because we need to
indicate our success/failure return with the dos error code (IoErr) instead
of the return value, and rx can't do that!  Later I wrote R2E and frx, either
of which could have solved this problem and allowed me to use a regular rexx
script, but since this was already written I keep using it ... it's faster
anyway.

The command line argument is a CLI command that will start Uedit; this
command will be executed if Uedit's rexx port is not present.  Typically this
would be something like "runback UE".  Frinstance, you would set CCEDIT to
be "quikfix runback ue".  */

/* What this does is use Uedit for Aztec QuikFix editing.  Most of the real
work is done by Uedit stuff, this only handles communication between Uedit
and cc.  It's basically an ARexx program written in C. */


#include <exec/exec.h>
#include <libraries/dosextens.h>
#include <rexx/rxslib.h>
#include <rexx/storage.h>
#include <paul.h>


struct RxsLib *RexxSysBase;


ubyte *          CreateArgstring(char *string, long length);
void             DeleteArgstring(ubyte *argstring);
struct RexxMsg * CreateRexxMsg(struct MsgPort *reply, str extension, str host);
void             DeleteRexxMsg(struct RexxMsg *message);
long             IsRexxMsg(struct RexxMsg *message);

#pragma amicall(RexxSysBase, 0x7E, CreateArgstring(a0, d0))
#pragma amicall(RexxSysBase, 0x84, DeleteArgstring(a0))
#pragma amicall(RexxSysBase, 0x90, CreateRexxMsg(a0, a1, d0))
#pragma amicall(RexxSysBase, 0x96, DeleteRexxMsg(a0))
#pragma amicall(RexxSysBase, 0xA8, IsRexxMsg(a0))



void spew(str s)
{
    register BPTR o = ThisProcess()->pr_COS;
    if (o) Write(o, s, (long) strlen(s));
}



bool SendStringFile(struct RexxMsg *mess, struct MsgPort *zex,
				struct MsgPort *duh, str sf, long *air)
{
    struct RexxMsg *m2;
    if (!(mess->rm_Args[0] = CreateArgstring(sf, strlen(sf)))) {
	spew("QuikFix:  Can't create argstring!\n");
	*air = ERROR_NO_FREE_STORE;
	return false;
    }
    mess->rm_Action = RXCOMM | RXFF_STRING;
    PutMsg(zex, (adr) mess);
    WaitPort(duh);
    while (!(m2 = (adr) GetMsg(duh)) || m2 != mess)
	if (!m2) WaitPort(duh);
    DeleteArgstring(mess->rm_Args[0]);
    if (mess->rm_Result1) {
	spew("QuikFix:  ARexx or Uedit indicates error!\n");
	*air = ERROR_ACTION_NOT_KNOWN;
	return false;
    }
    return true;
}



long _main(long alen, str aptr)
{
    struct Process *me = ThisProcess();
    struct MsgPort *duh, *zex, *urp;
    struct RexxMsg *mess, *m2;
    long air = 0;
    struct FileLock *ul, *ml = gbip(me->pr_CurrentDir);
    str command;

    if (!(zex = FindPort("REXX")) ||
		!(RexxSysBase = (adr) OpenLibrary("rexxsyslib.library", 0))) {
	spew("QuikFix:  No ARexx!\n");
	air = ERROR_INVALID_RESIDENT_LIBRARY;
	goto quit4;
    }
    if (!(duh = CreatePort("QUIKFIX", 0))) {
	spew("QuikFix:  Can't open message port!\n");
	air = ERROR_NO_FREE_STORE;
	goto quit3;
    }
    if (!(urp = FindPort("URexx"))) {
	aptr[--alen] = 0;			/* trim final newline */
	spew("QuikFix:  starting Uedit.\n");
	Execute(aptr, 0, me->pr_COS);
	while (!FindPort("URexx")) {
	    if (SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) {
		spew("QuikFix:  Abandoning wait for Uedit to start.\n");
		air = ERROR_ACTION_NOT_KNOWN;
		goto quit2;
	    }
	    Delay(20);
	    spew("\r");			/* notice ^C (bit of a kluge) */
	}
    }
    if (!(mess = CreateRexxMsg(duh, null, null))) {
	spew("QuikFix:  Can't create RexxMsg!\n");
	air = ERROR_NO_FREE_STORE;
	goto quit2;
    }
    ul = gbip(((struct Process *) urp->mp_SigTask)->pr_CurrentDir);
    if (ul->fl_Volume != ml->fl_Volume || ul->fl_Key != ml->fl_Key)
	command = "address 'URexx' 'quikfix' pragma('D'); return rc";
    else command = "address 'URexx' 'quikfix'; return rc";
    if (!SendStringFile(mess, zex, duh, command , &air))
	goto quit1;
    WaitPort(duh);			/* the user is editing now */
    while (!(m2 = (adr) GetMsg(duh)) || !IsRexxMsg(m2)) {
	if (m2) ReplyMsg((adr) m2);
	WaitPort(duh);
    }
    if (strcmp((str) m2->rm_Args[0], "OK"))
	air = -1;			/* Uedit says do not recompile */
    else air = 0;			/* Uedit says YES, recompile */
    m2->rm_Result1 = 0;
    ReplyMsg((adr) m2);
quit1:
    DeleteRexxMsg(mess);
quit2:
    DeletePort(duh);
quit3:
    CloseLibrary((adr) RexxSysBase);
quit4:
    me->pr_Result2 = air;	/* tell compiler whether to go ahead */
    return air ? 20 : 0;	/*  (it goes by IoErr, not return value) */
}
