
/*
 *  AUTOSTART.C
 *
 *  AUTOSTART [-s basename] [dir]
 *
 *  This program runs through specified volumes and executes any scripts
 *  named boot-sequence or <dir>/boot-sequence	(that is,
 *  it scans all top level directories as well as root)
 *
 *  If first line in the boot-sequence script file is '; PRI=<priority>'
 *  then it will be executed according to the specified priority
 *
 *  default base-name is 'boot-sequence' but may be changed with the -s
 *  option.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>

typedef struct Process		Process;
typedef struct FileInfoBlock	FileInfoBlock;
typedef struct Node		Node;
typedef struct List		List;

typedef struct SNode {
    Node    sn_Node;
    char    *sn_Script;
    long    sn_Bytes;
} SNode;

APTR SavePtr;
List RunList;
char *BaseName = "boot-sequence";

void myexit(void);
void AutoStart(char *, short);
void AutoRunScripts(void);
int  AddBootFile(char *, char *, char *);
char *DirectoryOf(char *);

main(ac, av)
char *av[];
{
    short i;
    short n = 0;
    Process *proc = (Process *)FindTask(NULL);

    atexit(myexit);
    SavePtr = proc->pr_WindowPtr;
    proc->pr_WindowPtr = (APTR)-1;

    NewList(&RunList);

    for (i = 1; i < ac; ++i) {
	char *ptr = av[i];
	if (*ptr == '-') {
	    ptr += 2;
	    av[i] = NULL;

	    switch(ptr[-1]) {
	    case 's':   /*  specify script base name    */
		if (*ptr) {
		    BaseName = ptr;
		} else {
		    BaseName = av[++i];
		    av[i] = NULL;
		}
		break;
	    default:
		fprintf(stderr, "Bad Option: %s\n", ptr - 2);
		break;
	    }
	}
    }

    for (i = 1; i < ac; ++i) {
	if (av[i])
	    AutoStart(av[i], 1);
    }

    if (n == 0) {
	if (system("Info >ram:info.tmp") == 0) {
	    FILE *fi;
	    char buf[128];
	    short state = 0;

	    if (fi = fopen("ram:info.tmp", "r")) {
		while (fgets(buf, sizeof(buf), fi)) {
		    if (state == 0) {
			if (strnicmp(buf, "Unit", 4) == 0)
			    state = 1;
		    } else {
			if (buf[0] == '\n')
			    break;
			AutoStart(strtok(buf, " \t\n"), 1);
		    }
		}
		fclose(fi);
	    }
	    DeleteFile("ram:info.tmp");
	}
    }
    AutoRunScripts();
    return(0);
}

void
myexit(void)
{
    Process *proc = (Process *)FindTask(NULL);

    proc->pr_WindowPtr = SavePtr;

    {
	SNode *snode;
	while (snode = RemHead(&RunList)) {
	    if (snode->sn_Bytes)
		FreeMem(snode->sn_Script, snode->sn_Bytes + 1);
	    FreeMem(snode, sizeof(SNode) + strlen(snode->sn_Node.ln_Name) + 1);
	}
    }
}

void
AutoStart(vol, trytop)
char *vol;
short trytop;
{
    __aligned FileInfoBlock fib;
    long lock;

    printf("; AutoStart %s\n", vol);

    if (trytop)
	AddBootFile(vol, BaseName, NULL);

    if (lock = Lock(vol, SHARED_LOCK)) {
	if (Examine(lock, &fib)) {
	    while (ExNext(lock, &fib)) {
		if (fib.fib_DirEntryType > 0) {
		    if (AddBootFile(vol, fib.fib_FileName, BaseName) == 0) {
			char *path;

			if (path = malloc(strlen(vol) + strlen(fib.fib_FileName) + 2)) {
			    sprintf(path, "%s%s/", vol, fib.fib_FileName);
			    AutoStart(path, 0);
			    free(path);
			}
		    }
		}
	    }
	}
	UnLock(lock);
    }
}

int
AddBootFile(vol, elm1, elm2)
char *vol;
char *elm1;
char *elm2;
{
    static char Tmp[256];
    static char Buf[256];
    int n;
    int r = -1;
    FILE *fi;

    n = sprintf(Tmp, "%s%s", vol, elm1);
    if (elm2)
	n += sprintf(Tmp + n, "/%s", elm2);
    sprintf(Tmp + n, ".1");

    while (fi = fopen(Tmp, "r")) {
	SNode *snode = AllocMem(sizeof(SNode) + strlen(Tmp) + 1, MEMF_PUBLIC|MEMF_CLEAR);
	char *ptr;

	r = 0;
	snode->sn_Node.ln_Name = (char *)(snode + 1);
	strcpy(snode->sn_Node.ln_Name, Tmp);

	if (fgets(Buf, sizeof(Buf), fi)) {
	    if (ptr = strstr(Buf, "PRI="))
		snode->sn_Node.ln_Pri = atoi(ptr + 4);
	}
	fseek(fi, 0L, 2);
	if ((snode->sn_Bytes = ftell(fi)) > 0) {
	    if (snode->sn_Script = AllocMem(snode->sn_Bytes + 1, MEMF_PUBLIC|MEMF_CLEAR)) {
		fseek(fi, 0L, 0);
		fread(snode->sn_Script, snode->sn_Bytes, 1, fi);
	    }
	}
	if (snode->sn_Script == NULL)
	    snode->sn_Bytes = 0;
	fclose(fi);
	Forbid();
	Enqueue(&RunList, &snode->sn_Node);
	Permit();

	if (++Tmp[strlen(Tmp)-1] == '9' + 1)
	    break;
    }
    return(r);
}


/*
 *  Paste scripts together into an output file
 */

void
AutoRunScripts(void)
{
    SNode *snode;

    for (;;) {
	Forbid();
	snode = RemHead(&RunList);
	Permit();
	if (snode == NULL)
	    break;
	if (snode->sn_Bytes) {
	    printf("; autostart %+-3d %s\n", snode->sn_Node.ln_Pri, snode->sn_Node.ln_Name);
	    printf("CD %s\n", DirectoryOf(snode->sn_Node.ln_Name));
	    fwrite(snode->sn_Script, snode->sn_Bytes, 1, stdout);
	    FreeMem(snode->sn_Script, snode->sn_Bytes + 1);
	}
	FreeMem(snode, sizeof(SNode) + strlen(snode->sn_Node.ln_Name) + 1);
    }
}

/*
 *  delete last element from path
 */

char *
DirectoryOf(path)
char *path;
{
    static char Tmp[256];
    char *ptr;

    strcpy(Tmp, path);
    for (ptr = Tmp + strlen(Tmp); ptr >= Tmp; --ptr) {
	if (*ptr == '/') {
	    ptr[0] = 0;
	    break;
	}
	if (*ptr == ':') {
	    ptr[1] = 0;
	    break;
	}
    }
    return(Tmp);
}

