/* runbackground.c */
/* Author:  Rob Peck.  5/9/86 */

/* Modified 5/21/88 by Dan Barrett to include PATH searching; added
 * the functions FullPathOf() and FindIt(), largely taken from C.
 * Scheppner's "which.c" program.
 *
 * Also, a few "#ifdef AZTEC_C" lines had to be added.  It seems that
 * Aztec C parses the command line differently from the way Lattice
 * does with respect to arguments in quotes.  When I compiled this
 * program with Aztec, all the quotes in quoted arguments were
 * disappearing.  I re-insert them around any argument that has a
 * space character (' ') in it.
*/
/* Modified 5/12/89 by Tim Maffett to use Gunnar Nordmark's NULL:
 * device.  RunBack also Mounts the NULL: device before using.
*/

/*#define DEBUG*/       /* Uncomment this line for debugging. */

#define EQUAL(a,b)      !strcmp(a,b)

#include "exec/types.h"
#include "exec/memory.h"
#include "libraries/dosextens.h"

extern struct FileHandle *Open();
extern struct FileLock *Lock();
extern VOID *AllocMem();

main(argc, argv)
int argc;
char *argv[];
{
    LONG success, delaywillbe;
    UBYTE commandstring[255];
    char *test, *filename;
    LONG fromparm;
    LONG *port;
    struct FileInfoBlock *fib;
    struct FileHandle *nilfh;   /* NOTE: will hang around until next reset */
    struct FileLock *lock, *FullPathOf();
#ifdef AZTEC_C
    int hasSpace=0;             /* Does an string have a space in it. */
#endif

    fib = NULL;                 /* No file info block so far. */
    delaywillbe = 1;

    if(argc < 2 || EQUAL(argv[1],"?")) {
usage:
        printf("Usage: RUNBACKGROUND [ -<loaddelay>] <name> [<parm(s)>]\n");
        printf("          where optional loaddelay is 0-9,\n");
        printf("          specified in seconds for the CLI\n");
        printf("          to sleep, waiting for task to load\n");
        printf("          (minimizes inter-task disk-thrashing)\n");
        if(fib)
                FreeMem(fib, sizeof(struct FileInfoBlock));
        exit(0);
    }

    /* See if there is a delay parameter present */

    test = argv[1];

    if(*test++ == '-') {
        filename = argv[2];     /* argv[1] is delay so argv[2] is file  */
        fromparm = 3;           /* Copy parms from 3 to end             */

        if(*test >= '0' && *test <= '9')
            delaywillbe = 1 + (50 * (*test - '0'));

        if (argc < 3)
                goto usage; /* Only a delay, and no filename!! */

        argc--;         /* one less parm to copy */
    }
    else {
        filename = argv[1];
        fromparm = 2;           /* Copy parms from 2 to end             */
    }

    /* Now see if the file exists!  If not, it can crash the background
     * CLI and take the system along with it.
     */

    lock = FullPathOf(filename);
    if(!lock) {
        printf("%ls: Command not found\n",filename);
        goto usage;
    }
    else {
        /* If file exists, it better be a file and not a directory */

/*DJB*/ /* With my (Dan's) changes, a file that is not found at all
         * is falsely identified as a directory.  Irritating, but not
         * fatal.
         */

        /* Unfortunately, it is difficult to tell if it is an executable
         * file.  If not executable, we'll still get blown out of the
         * water, but that is up to the user to do it right!
         */

        fib =  (struct FileInfoBlock *)
                AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);
        if(!fib) {
            UnLock(lock);
            printf("Ran out of memory!\n");
            exit(0);
        }
        else {
            success = Examine(lock,fib);
            if(fib->fib_DirEntryType > 0) {
/*              printf("%ls is a directory, not a file!\n",filename); */
/*DJB*/         printf("Cannot open %ls... maybe a directory?\n",filename);
                goto usage;
            }
        }
        FreeMem(fib, sizeof(struct FileInfoBlock));
        UnLock(lock);
    }

    nilfh = Open("NIL:",MODE_NEWFILE); /* will always succeed */

/*TMM*/    /* Mount NULL: device
              execute "Mount >nil: <nil: null:" command
              this will ensure that null: is mounted
              who cares if we try to mount it again ? (KLUDGE)
           */

    success = Execute( "mount >nil: <nil: null:", nilfh, nilfh );

/*TMM*/ /* Run now redirected to >NULL: <NULL: ( instead of NIL: ) */
    strcpy( &commandstring[0], "RUN >NULL: <NULL: " );
    strcat( &commandstring[0], filename);

    /* REMOVE THIS NEXT LINE IF YOU WANT TO INCLUDE REDIRECTION IN
     * THE COMMAND LINE FOR RUNBACKGROUND.   (The line was installed
     * to assure that something like "RUNBACKGROUND date ?" would
     * not crash the system.  "Date ?" is expecting to have an interactive
     * CLI, and unless it is specifically told to direct its output to nil:
     * it causes a crash.  If the next line is removed, and you are careful
     * about putting only NON-interactive commands in the command line,
     * everything should be ok.  Notice that if you do not specify a
     * non-interactive file handle (named_disk_file or NIL:) for your
     * program, it may still prevent the originating CLI from going away
     * until your program ends.  Also note that specifying two instances
     * of the same redirection (">somewhere" or "<somewhere") for a
     * background task crashes.
     */

/*TMM*/ /* Run now redirected to >NULL: <NULL: ( instead of NIL: ) */
    strcat( &commandstring[0], " >NULL: <NULL: ");

    argc--;

    while(--argc > 0) {     /* Rebuild parameter string for passing it on */
        strcat( &commandstring[0], " ");        /* add a blank */

#ifdef AZTEC_C
        hasSpace = HasASpace(argv[fromparm]);   /* Quoted argument?     */
        if (hasSpace)                           /* Then quote it again! */
                strcat( &commandstring[0], "\"");
#endif

        strcat( &commandstring[0], argv[fromparm++]);

#ifdef AZTEC_C
        if (hasSpace)
                strcat( &commandstring[0], "\"");
#endif

    }

#ifdef DEBUG
    printf("Execute %s\n", &commandstring[0]);
#else
    success = Execute( &commandstring[0] , nilfh, nilfh);
#endif

        /* The full command passed to Execute now looks like this: */

/*TMM*/ /*  "RUN >NULL: <NULL: FILENAME >NULL: <NULL: PARAMETER(s)" */


    if(success) {
        printf("Started %ls as a background task\n",filename);

        /* Execute, in this case, returns IMMEDIATELY.  The process
         * that is loading the code that is to be run as a background
         * process is working to get everything in and started.
         */
    }
    /* Now, to minimize thrashing between tasks, lets put this task to
     * sleep so that the each task actually gets a chance to load.
     */
    Delay(delaywillbe);
}


struct FileLock *FullPathOf(filename)
char *filename;
{
        struct FileLock *lock;
        char realname[256], *FindIt();

        strcpy(realname, FindIt(filename));
        lock = Lock(realname,ACCESS_READ);
        return(lock);
}
