[comp.sys.amiga] WBRUN - run Workbench program from CLI

toebes@sas.UUCP (John Toebes) (11/25/86)

I wrote this little program in response to a request from a person developing
a turnkey application in AmigaBasic.  It allows you to run any workbench icon
from CLI - simulating a double click on the Icon.  This allows AmigaBasic and
TrueBasic program to be run fromm a script instead of just bringing up Basic
and asking the user to type in a run command....  Use and enjoy.

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	WBRun.doc
#	Makefile.wbrun
#	WBRun.c
# This archive created: Tue Nov 25 10:25:00 1986
# By:	John A. Toebes, VIII (The Software Distillery)
cat << \SHAR_EOF > WBRun.doc
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||    Dave Baker    Ed Burnette        Stan Chow         BBS:      */
/* |  . |//     Jay Denebeim  Gordon Keener      Jack Rouse   (919)-471-6436 */
/* ======       John Toebes   Mary Ellen Toebes  Doug Walker                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

WBRun by John Toebes - Copyright (c) 1986 The Software Distillery.
                                          All Rights Reserved
 235 Trillingham Ln, Cary, NC 27511
 
Other Freely Redistributable Products produced by the Software Distillery are:
   BLINK     - the Turbo-charged Alink replacement
   POPCLI II - Screen saver and Pop up CLI hotkey
   HACK      - The Amiga port of the famous UNIX game
   MAKE      - A software development tool one shouldn't be without
   KERMIT    - The World renown file transfer protocol brought to the Amiga
   ICONEXEC, SETALTERNATE, SETWINDOW - Icon manipulation tools
   TSIZE     - A short utility for determining directory sizes.
   MEMWATCH  - A utility to catch and correct random low memory trashing
All of these are available on our BBS.

Permission is hereby granted to distribute this program provided both this
documentation accompanies the executable and that no charge is made for its
distribution.  Contributions to the Distillery at the above address are
encouraged and go to support further development.  If you wish
to include this program in a comercial product, contact us first.

WBRun is a program designed to allow any program to be invoked from CLI yet
behave as if it were invoked from Workbench.  Note that workbench need not
be loaded!  This is a boon for people who are short on memory and do not
wish the extra overhead of workbench.

This permits running programs created with AmigaBasic and TrueBasic (or
any other application that creates a workbench project icon) from CLI
as either a turnkey application or even in a startup-sequence.

To invoke a program with WBRun you need to execute the command:
  WBRun <icon1> <icon2> ...

Where <icon1> is the primary program to be run.  The name must correspond
to a workbench Icon.  <icon2> and subsequent parameters are taken as 
workbench arguments to be passed to the primary program.

For example:
   To run Initialize:
      WBRun SYS:System/Initialize

   To run a program (call it Printit) that takes arguments (normally shift
   clicked on) you would type
      WBRin Printit Arg1 Arg2

To run an AmigaBasic Program:
  WBRun myprogram

Note that the arguments must be qualified if they are not in the current
directory.

Supressing the Copyright message:
  If you are building a turnkey application that you do not wish to have
display the WBRun copyright message, you may supress it with the CLI
redirection features:
   WBRun >NIL: MyApplication
  To autostart an application from the startup-sequence, you would want to use:
     RUN >nil: <nil: WBRun MyApplication

If you do this, you must give credit to the Software Distillery in your
application.

Known Bugs:
  Fails to compile or execute under Manx.

How it works:
  WBRun simulates a phoney workbench by building an argument list of the
locks and names corresponding to the command line arguments.  It then opens
up the disk object for the first argument to determine the tool type.  For
a TOOL it simply invokes that program, for a Project it determines the
default tool to be invoked.  Once the program to be invoked is determined,
it does a LoadSeg on it, CreateProc and sends the startup message to the
newly created task.  Finally it waits for the response message from the
task before terminating.  All resources allocated are freed upon completion
or any error.

The code is written completely in Lattice C under 3.10 taking advantage
of Blink.  There is no guarentee that it will compile under anything but
the latest version.
SHAR_EOF
cat << \SHAR_EOF > Makefile.wbrun
LC1FLAGS = -b -dTINY
LC2FLAGS = -v -s -r
WBRun: WBRun.o _main.o
SHAR_EOF
cat << \SHAR_EOF > WBRun.c
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||    Dave Baker     Ed Burnette  Stan Chow    Jay Denebeim        */
/* |  . |//     Gordon Keener  Jack Rouse   John Toebes  Doug Walker         */
/* ======          BBS:(919)-471-6436      VOICE:(919)-469-4210              */ 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <exec/types.h>
#include <exec/memory.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <workbench/startup.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

int setarg(struct WBArg *, char *, struct Lock *);
void msg(char *, char *);

struct IconBase *IconBase;
#define ICON_REV 0

void main(argc, argv)
register int argc;
char **argv;
{
register struct WBStartup *WBStartup;
register struct DiskObject *diskobj;
char *torun, nambuf[160];
register int stacksize, i;
struct Process *ourtask;
struct MsgPort *replyport;
register struct Lock *olddir, *lock;

/* initialize so our cleanup routine runs fine */
WBStartup = NULL;
IconBase  = NULL;
diskobj   = NULL;
replyport = NULL;
olddir    = NULL;

/* running this from workbench is ridiculous so just quit */
if (argc == 0) XCEXIT(-1);

/* issue the copyright notice - they can supress it by doing a WBRUN >NIL: */
msg(
"\x9B33mWBRun\x9B0m by John Toebes - Copyright ) 1986 \x9B4mThe Software Distillery\x9B0m\n",
"235 Trillingham Ln, Cary NC 27511   BBS:(919)-471-6436");

/* not enough parameters? - give them the usage */
if (argc < 2)
   {
   msg(
"Usage: WBRun icon(s)\nWhere icon(s) is to run as if selected from Workbench\n",
"Note: Use WBRun >NIL: icon(s)   to hide copyright message");
   goto done;
   }

/* open the libraries we will need */
if ((IconBase = (struct IconBase *)OpenLibrary(ICONNAME, ICON_REV)) == NULL)
   goto done;

/* find ourselves - if this doesn't work it deserves to die a horrible */
/* death so I will not even look at our result */
ourtask = (struct Process *)FindTask(NULL);

/* allocate storage for all the arguments on the list */
if ((WBStartup = (struct WBStartup *)
                 AllocMem(sizeof(struct WBStartup), MEMF_CLEAR)) == NULL)
   goto done;

if ((WBStartup->sm_ArgList = (struct WBArg *)
                 AllocMem(sizeof(struct WBArg)*argc, MEMF_CLEAR)) == NULL)
   goto done;

if ((replyport = (struct MsgPort *)CreatePort("PhoneyWorkbench", 0)) == NULL)
   goto done;

/* initialize the remainder of the startup fields */
WBStartup->sm_Message.mn_ReplyPort = replyport;
WBStartup->sm_NumArgs = argc-1;

/* run through all the arguments getting locks and names for them */
for (i=1; i<argc; i++)
   if (setarg(&WBStartup->sm_ArgList[i-1], argv[i],
              (struct Lock *)ourtask->pr_CurrentDir))
         goto done;

/*-- Load the code that is desired ---*/
/* to do this, first find the program to be run */
olddir = (struct Lock *)CurrentDir( WBStartup->sm_ArgList[0].wa_Lock );

if ((diskobj = (struct DiskObject *)
               GetDiskObject( WBStartup->sm_ArgList[0].wa_Name )) == NULL)
   {
   msg("Can't get icon for ", WBStartup->sm_ArgList[0].wa_Name);
   goto done;
   }

torun = argv[1];

/* once we have the object, look at the tool type */
/* for TOOLS we run the program (argv[0] in our case) */
/* For projects it has the name of the default tool to run with it */
/* all others are to be blown away */
if (diskobj->do_Type == WBPROJECT)
   {
   /* for a project, we need to insert the tool icon as the first tool */
   /* move everything over one */
   movmem(&WBStartup->sm_ArgList[0],&WBStartup->sm_ArgList[1],
              (argc-1)*sizeof(struct WBArg));
   strcpy(nambuf, diskobj->do_DefaultTool);
   torun = nambuf;

   if (setarg(&WBStartup->sm_ArgList[0], torun, olddir))
      goto done;

   FreeDiskObject(diskobj);

   if ((diskobj = (struct DiskObject *)
                  GetDiskObject( WBStartup->sm_ArgList[0].wa_Name )) == NULL)
      {
      msg("Can't get icon for ", WBStartup->sm_ArgList[0].wa_Name);
      goto done;
      }

   WBStartup->sm_NumArgs++;
   }

/* at this point if it is not a TOOL we are scrod */
if (diskobj->do_Type != WBTOOL)
   {
   msg("Icon is not runnable for ", torun);
   goto done;
   }

if ((stacksize = diskobj->do_StackSize) < 4000)
   stacksize = 4000;

/* so lets load the segment for the program to run */
if ((WBStartup->sm_Segment = (BPTR)LoadSeg(torun)) == NULL)
   {
   msg("Can't open tool ", torun);
   goto done;
   }

/* also we will need to get it going as a process */
if ((WBStartup->sm_Process = (struct MsgPort *)
           CreateProc(torun, 0, WBStartup->sm_Segment, stacksize)) == NULL)
   {
   msg("Can't create process for ", torun);
   goto done;
   }

/* we are off and running, pass it the message to get running */
WBStartup->sm_ToolWindow = diskobj->do_ToolWindow;

PutMsg(WBStartup->sm_Process, WBStartup);

/* when he is done with what he needs, we can blow everything away */
WaitPort(replyport);

/* everything is now complete so clean up and go away */
done:
if (replyport != NULL) DeletePort(replyport);
replyport = NULL;

if (diskobj != NULL) FreeDiskObject(diskobj);
diskobj = NULL;

if (olddir != NULL) CurrentDir(olddir);

if (WBStartup != NULL)
   {
   if (WBStartup->sm_Segment != NULL)
      UnLoadSeg(WBStartup->sm_Segment);
   if (WBStartup->sm_ArgList != NULL)
      {
      /* run through and free any locks we may have */
      for (i=0; i<argc; i++)
         {
         lock = (struct Lock *)WBStartup->sm_ArgList[i].wa_Lock;
         if ((lock != NULL) && (lock != (struct Lock *)ourtask->pr_CurrentDir))
            UnLock(lock);
         }
      FreeMem(WBStartup->sm_ArgList,sizeof(struct WBArg)*argc);
      }
   FreeMem(WBStartup, sizeof(struct WBStartup));
   }
WBStartup = NULL;

if (IconBase != NULL) CloseLibrary(IconBase);
IconBase = NULL;

XCEXIT(0);
}

/***********************************************************/
/* given a null terminated name, fill in a WBArg structure */
/* with a lock and a name relative to that lock            */
/***********************************************************/
int setarg(WBArg, name, curdir)
register struct WBArg *WBArg;
char *name;
struct Lock *curdir;
{
register char *p, *lastc;
register unsigned char c;

if (name == NULL || !*name) return(1);  /* bad name to use */

/* first find the last colon or slash in the name */
lastc = NULL;
for (p = name; *p; p++)
   if (*p == ':' || *p == '/')
      lastc = p+1;

/* was there a path delimiter at all ? */
if (lastc == NULL)
   {
   /* no, use the default lock and full name */
   WBArg->wa_Lock = (BPTR)curdir;
   WBArg->wa_Name = name;
   }
else
   {
   /* must get a lock on the right directory and use part of the name */
   if (!*lastc) return(1); /* only a drawer specified */
   WBArg->wa_Name = lastc;

   /* when setting a directory, we need to include the delimiter */
   c = *lastc;
   *lastc = NULL;
   if ((WBArg->wa_Lock = (BPTR)Lock(name)) == NULL)
      {
      msg("Cannot open directory:", name);
      return(1);  /* couldn't find the director */
      }
   *lastc++ = c;
   }

/* it worked so let them continue on */
return(0);
}

void msg(str1, str2)
char *str1, *str2;
{
Write(Output(),str1,strlen(str1));
Write(Output(),str2,strlen(str2));
Write(Output(),"\n", 1);
}

void MemCleanup(){}
SHAR_EOF
#	End of shell archive
exit 0

-- 
John A. Toebes, VIII       usenet:..mcnc!rti-sel!sas!toebes
USnail: 235 Trillingham Ln, Cary NC 27511   BBS:(919)471-6436