/*****************************************************************
 *                                                               *
 *    XICON V2.01                                                *
 *                                                               *
 *   Runs Command Script Files from an Icon                      *
 *                                                               *
 *   copyright 1986, 1987, 1988 by Pete Goodeve                  *
 *      -- All Rights Reserved                                   *
 *                                                               *
 *    Compile with pass2 -v option (Lattice)                     *
 *    Link with c.o, amiga.lib, lc.lib                           *
 *                                                               *
 * vers 88:2:14                                                  *
 *****************************************************************/

#include "exec/types.h"
#include "exec/exec.h"
#include "workbench/startup.h"
#include "workbench/workbench.h"
#include "workbench/icon.h"
#include "libraries/dosextens.h"

LONG IntuitionBase;
short V1_2 = FALSE;
LONG IconBase;


extern struct Window  *findwindow();

extern struct WBStartup *WBenchMsg;

struct WBArg *argptr;
short nargs;
short autoclose=TRUE, /* will be FALSEified by non-use of 'closewindow' */
    usescript=TRUE, usewindow = TRUE, istext = FALSE;
short abortmark = FALSE;

#define MAXDESCR 120
char ConDescr[MAXDESCR+4] = "CON:0/10/640/185/XICON 2.01";
                         /* available for later fiddling */
#define MAXTITLE 100
char Title[MAXTITLE];

LONG outfile = NULL;
extern struct Window *conWindow;
extern struct ConUnit *conUnit;
LONG windowsig;

/** Close Gadget structure */

LONG Close_Data[] = { /* move to chip ram before use */
 0x3FFFFC80,
 0x30000C80,
 0x33FFCC80,
 0x33FFCC80,
 0x33C3CC80,
 0x33C3CC80,
 0x33FFCC80,
 0x33FFCC80,
 0x30000C80,
 0x3FFFFC80,

 0x00000000,
 0x00000000,
 0x00000000,
 0x00000000,
 0x003C0000,
 0x003C0000,
 0x00000000,
 0x00000000,
 0x00000000,
 0x00000000
};


struct Image Close_Image = {
 0, 0, /* Left, Top  */
 0x0019, 0x000A, 2, /* Width, Height, Depth */
 NULL, /* filled in to point to image in chip ram */
 3, 0,
 NULL
};

struct Gadget Close_Gadg = {
   NULL,    /* pointer to Next Gadget */
   4, 0, 0x019, 0x0A,  /* (Left Top Width Height) Hit Box */
   GADGHCOMP | GADGIMAGE,   /* Flags */
   /* Activation flags */
   RELVERIFY,
   SYSGADGET | CLOSE,       /* Type (!) */
   (APTR)&Close_Image,    /* pointer to GadgetRender */
   NULL,             /* no pointer to SelectRender */
   NULL,             /* no pointer to GadgetText */
   0,                /* no MutualExclude */
   NULL,             /* no pointer to SpecialInfo */
   0,                /* no ID */
   NULL              /* no pointer to special data */
};

/* Continue Gadget structure */

struct IntuiText Cont_Text = {
   3,0,         /* front, back pens */
   JAM2,        /* draw mode */
   10,1,        /* left, top edge */
   NULL,        /* default font */
   NULL,        /* text string -- filled in before use */
   NULL         /* no next */
};

struct Gadget Cont_Gadg = {
   NULL,    /* pointer to Next Gadget */
   0, -9, 0, 9,  /* (Left Top Full-Width Height) Hit Box */
   GADGHCOMP | GRELWIDTH | GRELBOTTOM ,   /* Flags */
   /* Activation flags */
   RELVERIFY,
   BOOLGADGET,       /* Type */
   NULL,            /* no pointer to GadgetRender */
   NULL,             /* no pointer to SelectRender */
   &Cont_Text,       /*  pointer to GadgetText */
   0,                /* no MutualExclude */
   NULL,             /* no pointer to SpecialInfo */
   0,                /* no ID */
   NULL              /* no pointer to special data */
};

_main() /* bypasses standard C startup code */
{

   if (!WBenchMsg)
      return 0;

   if (IntuitionBase = OpenLibrary("intuition.library",33)) V1_2 = TRUE;
    else IntuitionBase = OpenLibrary("intuition.library",0);
   IconBase = OpenLibrary(ICONNAME,1); /* doesn't matter much if not there */


   argptr = WBenchMsg->sm_ArgList;
   nargs = WBenchMsg->sm_NumArgs;
   /* Skip the first arg (the program itself) and process the rest */
   for(argptr++, nargs--; nargs; argptr++, nargs--)
      if (!doito(argptr)) goto clean_exit; /* sometimes a goto is good */

   SetSignal(0, SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | windowsig);
   if (usewindow && !autoclose) {
      Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | windowsig);
   }

clean_exit:
   dump_window();

   if (outfile) Close(outfile);
   if (IconBase) CloseLibrary(IconBase);
   CloseLibrary(IntuitionBase); /* this is in "ROM" (so no check needed) */
}
/*** end main ***/

/************************************************************
 * In the code below, I don't follow the usual method of    *
 * passing each command string in turn to Execute.  Instead *
 * I pass the entire command file as the new input stream,  *
 * which Execute accepts after processing the null string   *
 * it gets as a "command".  This avoids the system having   *
 * to reload the DOS "RUN" module for every line of the     *
 * command file, though on the other hand it does lock out  *
 * the possibility of redirecting keyboard input through    *
 * the "current window" to the command.  I thought the      *
 * trade-off was worth it.                                  *
 ************************************************************/

doito(argp) struct WBArg *argp;
{
   LONG oldir;

   oldir = CurrentDir(argp->wa_Lock);
   if (!readtt(argp) || abortmark) return FALSE;
   if (istext) dispfile(argp->wa_Name);
   else if (usescript)
      if (!execfile(argp->wa_Name)) return FALSE;
            /* I don't see how that could happen, but...*/
   CurrentDir(oldir);
   return TRUE;
}


execfile(fname) char *fname;
{
   LONG infile;
   infile = Open(fname, MODE_OLDFILE);
   if (!infile) return FALSE;
   Execute("", infile, outfile);
   Close(infile);
   return TRUE;
}


/* Read ToolTypes of current icon */

readtt(argp) struct WBArg *argp;
{
   struct DiskObject *iconobj=NULL, *GetDiskObject();
   char **toolarray, *FindToolType();
   char *modes, *windowstring, *titlestring, *locdir;
   LONG dirfile;

   if (!IconBase) {
      if (!get_window(ConDescr)) return FALSE;
      display("Icon Library not found -- ignoring ToolTypes\n");
      return TRUE; /* just soldier on...*/
   }
   /* we don't do any checks here for icon type -- probably should...*/
   if (!(iconobj = GetDiskObject(argp->wa_Name))) {
      display("COULDN'T GET INFO FOR ICON!!\n");
      return TRUE;
   }
   toolarray = iconobj->do_ToolTypes;
   modes = FindToolType(toolarray,"MODE");
   autoclose &= MatchToolValue(modes,"closewindow");
                 /* ALL must agree to close the window automatically */
   usescript = !MatchToolValue(modes,"noscript");
   istext = MatchToolValue(modes,"text");

   if (windowstring = FindToolType(toolarray,"WINDOW"))
        strncpy(&ConDescr[4], windowstring, MAXDESCR); /* append to 'CON:' */
        /* the above is probably a Lattice special...*/
   if (!outfile) {
    usewindow = !MatchToolValue(modes,"nowindow");
    if (usewindow)
      get_window(ConDescr);
    else
      outfile = Open("NIL:", MODE_OLDFILE);
   }
   if (!outfile) return FALSE;

   if (conWindow && (titlestring = FindToolType(toolarray,"TITLE"))) {
        strncpy(Title, titlestring, MAXTITLE);
        /* Note that SetWindowTitles does NOT copy the string! */
        SetWindowTitles(conWindow, Title, -1);
   }
   if ((locdir = FindToolType(toolarray,"LOCDIR")) &&
       (dirfile = Open(locdir,MODE_NEWFILE)))
   {
        Write(dirfile,"\"",1);
        traverse(argp->wa_Lock, dirfile);
        Write(dirfile,"\"\n",2);
        Close(dirfile);
   }
   dotoolcmds(toolarray); /* some tooltypes may be commands */
   FreeDiskObject(iconobj);
   return TRUE;
}


/* Execute any commands specified in the ToolTypes */

dotoolcmds(toolarray) char **toolarray;
{
   char *holdnext, *toolstr, *FindToolType();
   LONG lock;
   while (*toolarray) {
      holdnext = toolarray[1];
      toolarray[1] = NULL;
      if (!abortmark) {
        if (toolstr=FindToolType(toolarray,"REM")) {
           display(toolstr);
           display("\n");
        }
        else if (toolstr=FindToolType(toolarray,"TEXT"))
           dispfile(toolstr);
        else if (toolstr=FindToolType(toolarray,"CMD"))
           Execute(toolstr,0,outfile);
        else if (toolstr=FindToolType(toolarray,"SCRIPT"))
           execfile(toolstr);
        else if (!strcmp(*toolarray,"PAUSE")) /*FindT-T- needs "=" */
           abortmark = pausekey();
        else if (toolstr=FindToolType(toolarray,"EXISTS")) {
           if (lock = Lock(toolstr,ACCESS_READ)) UnLock(lock);
           else abortmark = TRUE;
        }
      } /* end !abortmark */
      else /* abort has been signalled */ {
        if (toolstr=FindToolType(toolarray,"ABORT-REM")) {
           display(toolstr);
           display("\n");
        }
        else if (toolstr=FindToolType(toolarray,"ABORT-TEXT"))
           dispfile(toolstr);
        else if (toolstr=FindToolType(toolarray,"ABORT-CMD"))
           Execute(toolstr,0,outfile);
        else if (toolstr=FindToolType(toolarray,"ABORT-SCRIPT"))
           execfile(toolstr);
        else if (!strcmp(*toolarray,"ABORT-PAUSE"))
           abortmark = pausekey();
        else if (!strcmp(*toolarray,"RESTORE"))
           abortmark = FALSE;
      }
      *++toolarray = holdnext; /* restore next item & move to it */
   }
}


traverse(lock, dirfile) ULONG lock, dirfile;
{
   short level;
   ULONG pdlock;
   struct DeviceList *volp;
   struct FileLock *lockp;
   char *namep;
   struct FileInfoBlock *fib;
   if (lock) {
      fib = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC | MEMF_CLEAR);
      if (!fib) return 2; /* ...being lazy */
      level = traverse(pdlock=ParentDir(lock), dirfile);
      UnLock(pdlock);
      if (level > 1) /* there is a superior non-root directory */
           Write(dirfile, "/", 1);
      if (level == 0) /* this was the root directory */ {
                /* all this to overcome RAM: handler bug...*/
                lockp = (struct FileLock *)BADDR(lock);
                volp = (struct DeviceList *)BADDR(lockp->fl_Volume);
                namep = (char *)BADDR(volp->dl_Name);
                Write(dirfile, namep+1, *namep);
                Write(dirfile, ":", 1);
      }
      else {
              if (Examine(lock,fib))
                Write(dirfile,fib->fib_FileName,strlen(fib->fib_FileName));
      }
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return level+1;
   }
   else return 0;
}

get_window(windescr) char *windescr;
{
   if (outfile) /* already open */ return TRUE;

   outfile = Open(windescr, MODE_OLDFILE);

   if (!outfile) return FALSE;

   if (!findWindow(outfile)) return FALSE;

   if (!(Close_Image.ImageData = AllocMem(sizeof(Close_Data), MEMF_CHIP)))
        return TRUE; /* just ignore close gadget */
   /* the following may be a Lattice special..?*/
   movmem(Close_Data, Close_Image.ImageData, sizeof(Close_Data));
   ModifyIDCMP(conWindow, CLOSEWINDOW); /* Heh..again*/
   windowsig = 1<<(conWindow->UserPort->mp_SigBit);
   conWindow->Flags |= WINDOWCLOSE; /* Heh heh! */
   AddGadget(conWindow, &Close_Gadg, 0); /* Must be on TOP of drag gadget */
   if (V1_2)
        RefreshWindowFrame(conWindow);
   else {
        SetWindowTitles(conWindow, conWindow->Title, -1);
        RefreshGadgets(&Close_Gadg, conWindow, NULL);
   }
   return TRUE;
} /* get_window */

dump_window()
{
   if (!Close_Image.ImageData) return;
   ModifyIDCMP(conWindow, 0);
   RemoveGadget(conWindow, &Close_Gadg);
   FreeMem(Close_Image.ImageData, sizeof(Close_Data));
   /* file & window are closed at a higher level */
}


display(msg) char *msg;
{
   Write(outfile, msg, strlen(msg));
}
/**************************************/


#define BUFSIZE 200

LONG textfile;
static short curmax = 0;

dispfile(fname) char *fname;
{
   char inbuf[BUFSIZE], outbuf[BUFSIZE], ansbuf[2];
   short inpos = 0, lcount = 20;
   curmax = 0;
   textfile = Open(fname, MODE_OLDFILE);
   if (!textfile || !conWindow) return FALSE;
   ModifyIDCMP(conWindow, conWindow->IDCMPFlags | RAWKEY);
   while (copyline(inbuf, &inpos, outbuf)) {
      if (!lcount-- || *outbuf == '\014' /*Formfeed*/) {
      if (pausekey()) goto cutit; /* just continues unless CLOSE */
         display(outbuf);
         lcount = 15; /* leave some overlap with previous page */
      }
      else display(outbuf);
   }
  cutit:
   Close(textfile);
   ModifyIDCMP(conWindow, conWindow->IDCMPFlags & ~RAWKEY);
}

copyline(in, pos, out) char *in, *out; short *pos;
{
   char ch, copych();
   short trunc=BUFSIZE-1;
   while ((*out++ = ch = copych(in, pos)) && ch != '\n' && --trunc)
       /*loop*/;
   *out = '\0';
   return (int) ch /* FALSE if EOF */;
}


char copych(in, pos) char *in; short *pos;
{
   if (*pos >= curmax) {
      curmax = Read(textfile,in,BUFSIZE);
      *pos = 0;
      if (!curmax) return '\0';
   }
   return in[(*pos)++];
}

pausekey()
{
    int code;
    Cont_Text.IText = "to CONTINUE -- Click here or Type any key";
    AddGadget(conWindow, &Cont_Gadg, -1);
    RefreshGadgets(&Cont_Gadg, conWindow, NULL);
    code = pause(RAWKEY | GADGETUP);
    Cont_Text.IText = "                                          ";
           /* seems crude, but it's all I can figger.. */
    RefreshGadgets(&Cont_Gadg, conWindow, NULL);
    RemoveGadget(conWindow, &Cont_Gadg);
    return code;
}

#define CODE_C 0x033

pause(evmask) ULONG evmask; /* waits for a relevant event from the window */
                  /* if it is a CLOSEWINDOW or cntrl-C it returns TRUE,
                     otherwise FALSE */
{
   struct IntuiMessage *eventmsg, *GetMsg();
   ULONG oldIDCMP, class, mark = FALSE;
   USHORT code, qual;
   if (!conWindow) return FALSE; /* only wait if there's a window */
   oldIDCMP = conWindow->IDCMPFlags;
   if (evmask) ModifyIDCMP(conWindow, conWindow->IDCMPFlags | evmask);
   do {
     Wait(windowsig);
     while(eventmsg = GetMsg(conWindow->UserPort)) {
       class = eventmsg->Class;
       code = eventmsg->Code;
       qual = eventmsg->Qualifier;
       ReplyMsg(eventmsg);
       if((class == CLOSEWINDOW) ||
          (class == RAWKEY && (qual & IEQUALIFIER_CONTROL) && code == CODE_C ))
       {
          mark = TRUE;
          break;
       }

     }
   } while ((class == RAWKEY) && (code & IECODE_UP_PREFIX));
               /* ignore left-over key-ups */
  if (evmask) ModifyIDCMP(conWindow, oldIDCMP);
   return mark;
}

/**************************************/


