; /*
dcc -r -ms -v addpath.c -o addpath
quit
*   ^^ This is PURE code!
*/
/*
 * ADDPATH.C
 *
 * (C) Copyright 1992 by Olaf Seibert. All rights reserved.
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#include <functions.h>

struct path {
    BPTR    next;
    BPTR    lock;
};

int
samelock(BPTR lock1, BPTR lock2)
{
    struct FileLock *l1, *l2;

    l1 = BADDR(lock1);
    l2 = BADDR(lock2);

    return l1 == l2 ||
	   (l1 != NULL &&
	    l2 != NULL &&
	    l1->fl_Volume == l2-> fl_Volume &&
	    l1->fl_Key == l2->fl_Key);
}

char *
dosalloc(int bytes)
{
    long *mem;

    bytes += 4;
    mem = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR);
    if (mem) {
	*mem++ = bytes;
    }
    return (char *)mem;
}

void
dosfree(char *mem)
{
    mem -= sizeof(long);
    FreeMem(mem, *(long *)mem);
}

void
usage(void)
{
    static char blurb[] = "pends directory to path, if not already present";

    printf("Usage: addpath [-r] [-a] [-p] directory ...\n"
	   "       -r removes directory from path\n"
	   "       -a ap%s (default)\n"
	   "       -p pre%s\n", blurb, blurb);
    exit(10);
}

int
main(int argc, char **argv)
{
    struct Process *proc;
    struct CommandLineInterface *cli;
    struct path    *path;
    BPTR	   *firstpath,
		   *prevpath;
    char	   *dir;
    BPTR	   dirlock;
    enum { append, prepend, remove }
		   action;

    proc = (struct Process *)FindTask(NULL);
    if (proc->pr_Task.tc_Node.ln_Type != NT_PROCESS) {
	exit(21);
    }
    cli = BADDR(proc->pr_CLI);
    if (cli == NULL) {
	exit(20);
    }
    firstpath = &cli->cli_CommandDir;

    if (argc == 1 || argv[1][0] == '?')
	usage();

    action = append;
    for (; dir = *++argv; ) {
	if (dir[0] == '-') {
	    switch (dir[1]) {
	    case 'a':
		action = append;
		break;
	    case 'p':
		action = prepend;
		break;
	    case 'r':
		action = remove;
		break;
	    default:
		usage();
		break;
	    }
	} else if (dirlock = Lock(dir, SHARED_LOCK)) {
	    for (prevpath = firstpath; path = BADDR(*prevpath);
		 prevpath = &path->next) {
		if (samelock(path->lock, dirlock))
		    break;
	    }
	    if (path) {
		/* found it! */
		if (action == remove) {
		    Forbid();
		    *prevpath = path->next;
		    Permit();
		    UnLock(path->lock);
		    dosfree(path);
		}
	    } else if (action != remove) {
		/* didn't find it, so make it */
		path = dosalloc(sizeof(*path));
		path->lock = dirlock;
		dirlock = 0;
		if (action == prepend) {
		    prevpath = firstpath;
		}
		Forbid();
		path->next = *prevpath;
		*prevpath = ((long) path) >> 2;
		Permit();
	    }
	    if (dirlock) {
		UnLock(dirlock);
		dirlock = 0;
	    }
	} else {
	    printf("Couldn't Lock '%s', error %ld\n", dir, IoErr());
	}
    }
    return 0;
}
