
/*
 * COMM2.C
 *
 *
 * (c)1986 Matthew Dillon     Feb 1987
 *
 *    ABORTLINE
 *    RETURN
 *    STRHEAD
 *    STRTAIL
 *    IF
 *    LABEL
 *    GOTO
 *    INC
 *    INPUT
 *    VER
 *    CP
 *    SHELLSTAT
 *    SETENV
 *    UNSETENV
 *    IPC
 *    CLDRES
 *
 */

#include "shell.h"
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <local/ipc.h>

typedef struct CommandLineInterface CLI;

extern LOCK *CurrentDir(), *Lock(), *CreateDir();
extern IPCMSG *SendIPC();

do_cldres()
{
    if (DResBase)
	CloseLibrary(DResBase);
    DResBase = NULL;
}

/*
 *  do_ipc appname[.project] command
 */

do_ipc(command)
char *command;
{
    IPCMSG *msg;
    char *str = next_word(next_word(command));
    char *ptr;
    char appname[64];
    char *cmd;
    long result;

    if (!DResBase)
	DResBase = (long)OpenLibrary("dres.library", 0);
    if (!DResBase) {
	puts("Unable to open dres.library");
	return(-1);
    }
    for (ptr = av[1]; *ptr && *ptr != '.'; ++ptr);
    if (*ptr == '.') {
	if (cmd = malloc(strlen(ptr+1)+strlen(str)+2)) {
	    strcpy(cmd, ptr+1);
	    strcpy(cmd + strlen(cmd) + 1, str);
	}
    } else {
	if (cmd = malloc(strlen(str)+2)) {
	    cmd[0] = 0;
	    strcpy(cmd+1, str);
	}
    }
    if (!cmd)
	return(-1);
    strcpy(appname, av[1]);
    appname[ptr - av[1]] = 0;
    strcat(appname, ".CMD");

    msg = SendIPC(appname, cmd, strlen(cmd)+strlen(str)+2, 0);
    free(cmd);
    if (!msg)
	return(-1);
    WaitMsg(msg);
    if (msg->RFlags & IF_ERROR) {
	if (msg->RFlags & IF_NOAPP)
	    printf("Application not found");
	else
	    printf("Operation Failed");
	if (msg->RBuf)
	    printf(": %s\n", msg->RBuf);
	puts("");
	if (!msg->Error)
	    msg->Error = 20;
    } else {
	if (msg->RBuf)
	    Oputs(msg->RBuf);
    }
    result = msg->Error;
    FreeIPC(msg);
    return(result);
}

do_abortline()
{
    Exec_abortline = 1;
    return (0);
}

do_return()
{
    Exec_abortline = 1;
    if (Src_stack) {
	fseek (Src_base[Src_stack - 1], 0, 2);
	return ((ac < 2) ? 0 : atoi(av[1]));
    } else {
	main_exit ((ac < 2) ? 0 : atoi(av[1]));
    }
}

/*
 * STRHEAD
 *
 * place a string into a variable removing everything after and including
 * the 'break' character or until a space is found in the string.
 *
 * strhead varname breakchar string
 *
 */

do_strhead()
{
    register char *str = av[3];
    register char bc = *av[2];

    while (*str && *str != bc)
	++str;
    *str = '\0';
    set_var (LEVEL_SET, av[1], av[3]);
    return (0);
}

do_strtail()
{
    register char *str = av[3];
    register char bc = *av[2];

    while (*str && *str != bc)
	++str;
    if (*str)
	++str;
    set_var (LEVEL_SET, av[1], str);
    return (0);
}

/*
 * if A < B   <, >, =, <=, >=, !=, where A and B are either:
 * nothing
 * a string
 * a value (begins w/ number)
 *
 *  if -[!]f file
 *
 */

do_if(garbage, com)
char *garbage;
{
    register char *v1, *v2, *v3, result, num;
    register int n1, n2;

    switch (com) {
    case 0:
	if (If_stack && If_base[If_stack - 1]) {
	    if (If_stack == MAXIF) {
		ierror(NULL, 510);
	    } else {
		If_base[If_stack++] = 1;
	    }
	    break;
	}
	result = num = 0;
	v1 = av[1];
	switch(ac) {
	case 2: 	     /* if $var; */
	    if (v1[0] == 0 || (v1[1] == 0 && v1[0] == ' '))
		goto do_result;
	    result = 1;      /* fall through	*/
	case 1: 	     /* if		*/
	    goto do_result;
	case 3: 	     /* if -flag name	*/
	    if (*v1 == '-')
		++v1;
	    if (*v1 == '!') {
		++v1;
		result = 1 - result;
	    }
	    switch(*v1) {
	    case 'f':
		{
		    LOCK *lock;
		    mountrequest(0);
		    if (lock = Lock(av[2], SHARED_LOCK)) {
			result = 1 - result;
			UnLock(lock);
		    }
		    mountrequest(1);
		}
		break;
	    default:
		goto splug;
	    }
	    goto do_result;
	case 4:
	    goto cond;
	}
splug:
	ierror(NULL, 500);
	goto do_result;
cond:
	v1 = av[1]; v2 = av[2]; v3 = av[3];
	while (*v1 == ' ')
	    ++v1;
	while (*v2 == ' ')
	    ++v2;
	while (*v3 == ' ')
	    ++v3;
	if (*v1 >= '0' && *v1 <= '9') {
	    num = 1;
	    n1 = atoi(v1);
	    n2 = atoi(v3);
	}
	while (*v2) {
	    switch (*v2++) {
	    case '>':
		result |= (num) ? (n1 >  n2) : (strcmp(v1, v3) > 0);
		break;
	    case '<':
		result |= (num) ? (n1 <  n2) : (strcmp(v1, v3) < 0);
		break;
	    case '=':
		result |= (num) ? (n1 == n2) : (strcmp(v1, v3) ==0);
		break;
	    default:
		ierror (NULL, 503);
		break;
	    }
	}
do_result:
	if (If_stack == MAXIF)
	    ierror(NULL,510);
	else
	    If_base[If_stack++] = !result;
	break;
    case 1:
	if (If_stack > 1 && If_base[If_stack - 2])
	    break;
	if (If_stack)
	    If_base[If_stack - 1] ^= 1;
	break;
    case 2:
	if (If_stack)
	    --If_stack;
	break;
    }
    SDisable = (If_stack) ? If_base[If_stack - 1] : 0;
    return (0);
}

do_label()
{
    char aseek[32];

    if (Src_stack == 0) {
	ierror (NULL, 502);
	return (-1);
    }
    sprintf (aseek, "%ld %ld", Src_pos[Src_stack-1], If_stack);
    set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
    return (0);
}

do_goto()
{
    register long new;
    register long pos;
    register char *lab;

    if (Src_stack == 0) {
	ierror (NULL, 502);
    } else {
	lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
	if (lab == NULL) {
	    ierror (NULL, 501);
	} else {
	    pos = atoi(lab);
	    fseek (Src_base[Src_stack - 1], pos, 0);
	    Src_pos[Src_stack - 1] = pos;
	    new = atoi(next_word(lab));
	    if (new > MAXIF)
		new = MAXIF;
	    for (; If_stack < new; ++If_stack)
		If_base[If_stack] = 0;
	    If_stack = new;
	}
    }
    Exec_abortline = 1;
    return (0);      /* Don't execute rest of this line */
}


do_inc(garbage, com)
char *garbage;
{
    register char *var;
    char num[32];

    if (ac == 3)
	com = atoi(av[2]);
    var = get_var (LEVEL_SET, av[1]);
    if (var) {
	sprintf (num, "%ld", atoi(var)+com);
	set_var (LEVEL_SET, av[1], num);
    }
    return (0);
}

do_input()
{
    char in[256];

    if (Ogets(in))
	set_var (LEVEL_SET, av[1], in);
    return (0);
}

do_ver()
{
    Oputs (VERSION);
    return (0);
}


/*
 * CP file		    (to current directory)
 * CP [-r] dir		    (to current directory)
 * CP file file
 * CP file file file... destdir
 * CP [-r] dir dir dir... destdir
 */

do_cp()
{
    register short recur, i, ierr;
    register char *destname;
    register char destisdir;
    register FIB *fib;
    char copysilent = (get_var(LEVEL_SET, V_COPYSILENT) != NULL);

    if (get_var(LEVEL_SET, V_COPYDATE) != NULL)
	copysilent |= 2;

    ierr = 0;
    fib = (FIB *)AllocMem(sizeof(FIB), 0);
    recur = (strncmp(av[1], "-r", 2)) ? 0 : 1;
    destname = av[ac - 1];

    if (ac < recur + 3) {
	++ac;
	destname = "";
    }
    /*
     *	ierr = 500;
     *	goto done;
     */

    destisdir = isdir(destname);
    if (ac > recur + 3 && !destisdir) {
	ierr = 507;
	goto done;
    }

    /*
     * copy set:			reduce to:
     *	  file to file			   file to file
     *	  dir  to file (NOT ALLOWED)
     *	  file to dir			   dir to dir
     *	  dir  to dir			   dir to dir
     *
     */


    for (i = recur + 1; i < ac - 1; ++i) {
	short srcisdir = isdir(av[i]);
	if (srcisdir) {
	    struct FileLock *srcdir, *destdir;
	    if (!destisdir) {        /* disallow dir to file */
		ierr = 507;
		goto done;
	    }
	    if (!(destdir = Lock(destname, ACCESS_READ))) {
		ierr = 205;
		goto done;
	    }
	    if (!(srcdir = Lock(av[i], ACCESS_READ))) {
		ierr = 205;
		UnLock(destdir);
		goto done;
	    }
	    ierr = copydir(srcdir, destdir, recur, copysilent, 1);
	    UnLock(srcdir);
	    UnLock(destdir);
	    if (ierr)
		break;
	} else {		      /* FILE to DIR,	FILE to FILE   */
	    struct FileLock *destdir, *srcdir, *tmp;
	    char *destfilename;

	    srcdir = (struct FileLock *)((PROC *)FindTask(NULL))->pr_CurrentDir;
	    if (destisdir) {
		if ((tmp = Lock(av[i], ACCESS_READ)) == NULL || !Examine(tmp,fib)){
		    if (tmp)
			UnLock(tmp);
		    ierr = 205;
		    goto done;
		}
		UnLock(tmp);
		destdir = Lock(destname, ACCESS_READ);
		destfilename = fib->fib_FileName;
	    } else {
		destdir = srcdir;
		destfilename = destname;
		copysilent |= 1;
	    }
	    ierr = copyfile(av[i], srcdir, destfilename, destdir, copysilent, 0);
	    if (destisdir)
		UnLock(destdir);
	    if (ierr)
		break;
	}
    }
done:
    FreeMem(fib, sizeof(*fib));
    if (ierr) {
	ierror("cp", ierr);
	return(20);
    }
    return(0);
}


copydir(srcdir, destdir, recur, silent, tab)
register struct FileLock *srcdir, *destdir;
{
    LOCK *cwd;
    register FIB *srcfib;
    register LOCK *destlock, *srclock;
    DATESTAMP DS;
    int ierr;

    ierr = 0;
    srcfib = (FIB *)AllocMem(sizeof(FIB), 0);
    if (Examine(srcdir, srcfib)) {
	DS = srcfib->fib_Date;
	if (!(silent & 1))
	    printf("%*s%s (DIR)\n", tab, "", srcfib->fib_FileName);
	while (ExNext(srcdir, srcfib)) {
	    if (srcfib->fib_DirEntryType < 0) {
		ierr = copyfile(srcfib->fib_FileName,srcdir,srcfib->fib_FileName,destdir,silent,tab+4);
		if (ierr)
		    break;
	    } else {
		if (recur) {
		    cwd = CurrentDir(srcdir);
		    if (srclock = Lock(srcfib->fib_FileName, ACCESS_READ)) {
			CurrentDir(destdir);
			if (!(destlock = Lock(srcfib->fib_FileName, ACCESS_READ))) {
			    if (destlock = CreateDir(srcfib->fib_FileName)) {
				UnLock(destlock);
				if (silent & 2) {
				    setfiledate(srcfib->fib_FileName, &DS);
				    if (srcfib->fib_Comment[0])
					SetComment(srcfib->fib_FileName, srcfib->fib_Comment);
				}
				destlock = Lock(srcfib->fib_FileName, ACCESS_READ);
			    }
			}
			if (destlock) {
			    ierr = copydir(srclock, destlock, recur, silent, tab+4);
			    UnLock(destlock);
			} else {
			    ierr = IoErr();
			}
			UnLock(srclock);
		    } else {
			ierr = IoErr();
		    }
		    CurrentDir(cwd);
		    if (ierr)
			break;
		}
	    }
	}
    } else {
	ierr = IoErr();
    }
    FreeMem(srcfib, sizeof(FIB));
    return(ierr);
}


copyfile(srcname, srcdir, destname, destdir, silent, tab)
char *srcname, *destname;
struct FileLock *srcdir, *destdir;
{
    LOCK *cwd;
    DATESTAMP DS;
    int i, ierr;
    char *buf;
    char *com = NULL;
    long  buflen;
    long  fhs, fhd;

    if (!(silent&1))
	printf("%*s%s\n", tab, "", srcname);
    for (buflen = 65536; buflen; buflen >>= 1) {
	if (buf = AllocMem(buflen, MEMF_PUBLIC))
	    break;
    }
    if (buf == NULL)
	return(103);    /* ERROR_NO_FREE_STORE      */
    ierr = 0;
    cwd = (LOCK *)CurrentDir(srcdir);

    if (silent & 2) {
	register FIB *fib = (FIB *)AllocMem(sizeof(FIB), MEMF_PUBLIC);
	register LOCK *lock = Lock(srcname, ACCESS_READ);
	if (lock && fib && Examine(lock, fib)) {
	    if (fib->fib_Comment[0]) {
		com = malloc(strlen(fib->fib_Comment)+1);
		strcpy(com, fib->fib_Comment);
	    }
	    DS = fib->fib_Date;
	} else {
	    silent &= ~2;
	}
	if (lock)
	    UnLock(lock);
	if (fib)
	    FreeMem(fib, sizeof(FIB));
    }
    fhs = Open(srcname, 1005);
    if (fhs == NULL) {
	ierr = 205;
	goto fail;
    }
    CurrentDir(destdir);
    fhd = Open(destname, 1006);
    if (fhd == NULL) {
	ierr = IoErr();
	Close(fhs);
	goto fail;
    }
    while ((i = Read(fhs, buf, buflen)) > 0) {
	if (CHECKBREAK()) {
	    ierr = 509;
	    break;
	}
	if (Write(fhd, buf, i) != i) {
	    ierr = IoErr();
	    break;
	}
	if (CHECKBREAK()) {
	    ierr = 509;
	    break;
	}
    }
    if (i < 0)
	ierr = IoErr();
    Close(fhd);
    Close(fhs);
    if (!ierr && (silent & 2)) {
	setfiledate(destname, &DS);
	if (com)
	    SetComment(destname, com);
    }
fail:
    if (com)
	free(com);
    FreeMem(buf, buflen);
    CurrentDir(cwd);
    return(ierr);
}

do_shellstat()
{
    {
	register short i = 0;
	register unsigned long mask = ((TASK *)FindTask(NULL))->tc_SigAlloc;
	printf("Signals: %08lx  ", mask);
	while (mask) {
	    if (mask & 1)
		++i;
	    mask >>= 1;
	}
	printf("(%ld)\n", i);
    }
    /*
    {
	register PROC *proc = (PROC *)FindTask(NULL);
	register CLI  *cli = (CLI *)((long)proc->pr_CLI << 2);
	if (proc) {
	    long stack;
	    printf("pr_TaskNum: %ld\n", proc->pr_TaskNum);
	    printf("pr_CIS: %08lx\n", proc->pr_CIS);
	    printf("pr_COS: %08lx\n", proc->pr_COS);
	    printf("cli_standardinput : %08lx\n", cli->cli_StandardInput);
	    printf("cli_standardoutput: %08lx\n", cli->cli_StandardOutput);
	    printf("cli_currentinput  : %08lx\n", cli->cli_CurrentInput);
	    printf("cli_currentoutput : %08lx\n", cli->cli_CurrentOutput);
	    printf("cli_Module        : %08lx\n", cli->cli_Module);
	    printf("STACK:  %ld bytes, %08lx %08lx %08lx (%ld Free)\n",
		cli->cli_DefaultStack*4,
		proc->pr_ReturnAddr - cli->cli_DefaultStack*4, &stack, proc->pr_ReturnAddr,
		(long)&stack - (long)proc->pr_ReturnAddr + cli->cli_DefaultStack*4
	    );
	}
    }
    */
    return(0);
}

do_printenv()
{
    register long lock;
    register FIB *fib = (FIB *)malloc(sizeof(FIB));
    register short i;
    char buf[256];
    long fh;

    if (lock = (long)Lock("ENV:", SHARED_LOCK)) {
	if (Examine(lock, fib)) {
	    while (ExNext(lock, fib)) {
		sprintf(buf, "%-10s ", fib->fib_FileName);
		Write(Cout, buf, strlen(buf));
		sprintf(buf, "ENV:%s", fib->fib_FileName);
		if (fh = Open(buf, 1005)) {
		    while ((i = Read(fh, buf, sizeof(buf))) > 0) {
			Write(Cout, buf, i);
		    }
		    Close(fh);
		    Oputs("");
		} else {
		    Oputs("<unable to open>");
		}
	    }
	}
	UnLock(lock);
    }
    free(fib);
    return(0);
}



do_setenv(command)
char *command;
{
    long fh;
    char buf[256];
    short ierr = 0;

    if (ac <= 2)
	return(0);
    strcpy(buf, "ENV:");
    strcat(buf, av[1]);
    if (fh = Open(buf, 1006)) {
	register char *str = next_word(next_word(command));
	Write(fh, str, strlen(str));
	Close(fh);
    } else {
	ierr = IoErr();
    }
    return(ierr);
}

do_unsetenv()
{
    char buf[256];
    short i;

    for (i = 1; i < ac; ++i) {
	strcpy(buf, "ENV:");
	strcat(buf, av[i]);
	DeleteFile(buf);
    }
    return(0);
}

