/*
 * COMM3.C
 *
 * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
 *
 */

do_assign() {
switch(ac) {
	case 1:  assignlist();
		 break;
	case 2:  doassign(av[1], NULL);
		 break;
	case 3:  doassign(av[1], av[2]);
		 break;
	default: ierror(NULL, 500);
		 break;
	}
return 0;
}

char *assign_errors[4]={
	"",
	"Name %s is not valid\n",
	"Weird error\n",
	"Can't cancel %s\n"
	};

doassign(log, phy)
char *log, *phy;
{
int last=strlen(log) - 1;

if (log[last] != ':') fprintf(stderr, "Bad name %s\n", log);
else {
	log[last] = 0;
	fprintf(stderr,assign_errors[Assign(log, phy)],phy);
	}
}

assignlist()
{
struct DirectoryEntry *de_head=NULL, *de;
char buf[256];
BPTR lock;
int ctr=0;

AddDADevs(&de_head, DLF_DEVICES | DLF_VOLUMES | DLF_DIRS);
printf("Devices:\n");
for (de=de_head; de && de->de_Type==DLX_DEVICE; de=de->de_Next) {
	printf("%-8s",de->de_Name);
	if (ctr++ == 5) { ctr=0; printf("\n"); }
	}
printf("\n\nVolumes:\n");
for (	;
	de && (de->de_Type==DLX_VOLUME || de->de_Type==DLX_UNMOUNTED);
	de=de->de_Next
	)
	printf( "%-16s %s\n",
		de->de_Name,
		de->de_Type == DLX_VOLUME ? "[Mounted]" : ""
		);
printf("\nDirectories:\n");
for (; de && de->de_Type==DLX_ASSIGN; de=de->de_Next) {
	if (lock=Lock(de->de_Name, ACCESS_READ)) {
		PathName(lock, buf, 256L);
		UnLock(lock);
		}
	else
		strcpy(buf,"Unexisting lock");
	printf("%-20s%s\n",de->de_Name,buf);
	}
FreeDAList(&de_head);
}

do_join()
{
BPTR sou, dest;
char *buffer;
unsigned int i;
long n;
char *namedest=av[--ac];

get_opt("r", &i);
if (options==0 && exists(namedest)) { ierror(namedest,203); return 20; }
if ( (buffer=malloc(8192)) == NULL ) { ierror(NULL,103); return 20; }
if ( (dest=Open(namedest, MODE_NEWFILE)) == NULL )
	{ pError(namedest); goto fail1; }
for (i=1; i<ac; i++) {
	if ( (sou=Open(av[i], MODE_OLDFILE)) == NULL ) pError(av[i]);
	else
		while( (n=Read(sou, buffer, 8192L)) > 0 )
			if (Write(dest, buffer, n) != n)
				{ pError(namedest); Close(sou); goto fail2; }
	Close(sou);
	}
fail2:
	Close(dest);
fail1:
	free(buffer);
	return 0;
}

#define BUFDIM 512L
#define MAXSTR 256

int minstr;

strings_in_file(s)
char *s;
{
char c;
char readbuf[BUFDIM+1], strbuf[MAXSTR+1];
register unsigned int i, strctr=0;
BPTR fh;
int out, n;

if ( fh=Open(s, MODE_OLDFILE) ) {
	fprintf(stderr, "Strings in %s (len>=%d):\n",s,minstr);
	while ( (n=(int)Read(fh, readbuf, BUFDIM)) > 0 && !CHECKBREAK() )
	    for (i=0; i<n; i++) {
		c=readbuf[i];
		if (c<0x20 || c>0x7f) {
			out=(strctr>=minstr);
			if (!out) strctr=0;
			}
		else {
			strbuf[strctr++]=c;
			out=(strctr>=BUFDIM);
			}
		if (out) {
			strbuf[strctr]='\0';
			puts(strbuf);
			strctr=0;
			}
		}
	Close(fh);
	}
else pError(s);
}

do_strings()
{
minstr=myatoi(av[--ac],1,255);
all_args("r", strings_in_file, 0);
return 0;
}

BPTR myfile[MAXMYFILES];

do_open()
{
long mode;
unsigned int n;

switch (toupper(av[2][0])) {
	case 'R': mode=MODE_OLDFILE; break;
	case 'W': mode=MODE_NEWFILE; break;
	default : ierror(NULL,500); return;
	}
n=(unsigned int)myatoi(av[3],0,MAXMYFILES-1); if (atoierr) return 20;
if (myfile[n]) myclose(n);
myfile[n]=Open(av[1],mode);
return (myfile[n]==NULL);
}

do_close()
{
register unsigned int i;
int n;

if (ac==1)
	for (i=1; i<MAXMYFILES; i++)
		myclose(i);
for (i=1; i<ac; i++) {
	n=myatoi(av[i],0,MAXMYFILES-1); if (atoierr) return 20;
	myclose(n);
	}
return 0;
}

myclose(n)
{
if (myfile[n]) { Close(myfile[n]); myfile[n]=NULL; }
}

do_fileslist()
{
register unsigned short i;
int flag=0;

printf("Open files:");
for (i=0; i<MAXMYFILES; i++)
	if (myfile[i]) { printf(" %d",i); flag=1; }
if (!flag) printf(" None!");
printf("\n");
return 0;
}

BPTR extOpen(name,mode)
char *name;
long mode;
{
if (name[0]=='.') return myfile[atoi(name+1)];
return Open(name,mode);
}

extClose(fh)
BPTR fh;
{
register unsigned short i;

for (i=0; i<MAXMYFILES; i++)
	if (myfile[i]==fh) return;
Close(fh);
}

do_basename()
{
set_var(LEVEL_SET, av[1], BaseName(av[2]));
return 0;
}

do_tackon()
{
char buf[256];

strcpy(buf, av[2]);
TackOn(buf, av[3]);
set_var(LEVEL_SET, av[1], buf);
return 0;
}

do_resident()
{
unsigned int i;
register struct ResidentProgramNode *p;
char buf[256];

get_opt("ard", &i);
if (options==0 && ac>1) options=1;
switch (options) {
    case 0:
	ObtainSemaphore (& (ArpBase->ResPrgProtection) );
	if (p=ArpBase->ResidentPrgList) {
		printf("Name             Users Access\n");
		for (; p; p=p->rpn_Next)
			printf("%-17s%5d%6d\n",
				p->rpn_Name, p->rpn_Usage, p->rpn_AccessCnt);
		}
	else printf("No resident program(s)\n");
	ReleaseSemaphore(& (ArpBase->ResPrgProtection) );
	break;
    case 1:
	for (; i<ac; i++)
		if (loadres(av[i]))
			printf("OK! %s is now resident\n", BaseName(av[i]));
		else pError(av[i]);
	break;
    case 2:
	for (; i<ac; i++)
		if (RemResidentPrg(av[i])) ierror(av[i],202);
		else printf("Removed %s\n",av[i]);
	break;
    case 4:
	for (; i<ac; i++) {
		sprintf(buf,"res_%s",av[i]);
		Setenv(buf,"1");
		}
	break;
    default:
	ierror(NULL,500);
	break;
    }
return 0;
}

int loadres(s)
char *s;
{
BPTR seg;

if (seg=(BPTR)LoadPrg(s)) AddResidentPrg(seg,BaseName(s));
return (seg != NULL);
}

struct ProcessControlBlock pcb={
	4000,		/* pcb_StackSize	*/
	0,		/* pcb_Pri		*/
	};
/* remaining field are NULL */
	
do_truerun(avline, backflag)
char *avline;
{
char name[200];
char *FindIt();

if (backflag) {
	pcb.pcb_Control=NULL;
	pcb.pcb_Input=pcb.pcb_Output=Open("NIL:",MODE_OLDFILE);
	}
else {
	pcb.pcb_Control=NULL;
	pcb.pcb_Input=pcb.pcb_Output =NULL;
	}
if (FindIt(av[1], "", name))
	ASyncRun(name,next_word(next_word(avline)),&pcb);
else
	ierror(av[1],205);
return 0;
}

int exists(name)
char *name;
{
BPTR lock;

if (lock=Lock(name,ACCESS_READ)) {
	UnLock(lock);
	return 1;
	}
return 0;
}

do_aset()
{
Setenv(av[1],av[2]);
return 0;
}

#define HTYPELINE 16L

htype_a_file(s)
char *s;
{
BPTR fh;
long n, filesize=0;
char buf[HTYPELINE+1];
register unsigned short i;

if ( (fh=Open(s,MODE_OLDFILE))==NULL ) { pError(s); return 20; }
while ( (n=Read(fh,buf,HTYPELINE))>0 && !dobreak()) {
	printf("%06lx: ",filesize);
	filesize+=n;
	for (i=0; i<n; i++) {
		printf( (i&3) ? "%02x" : " %02x",(int)(unsigned char)buf[i]);
		if (buf[i]<0x20) buf[i]='.';
		}
	for ( ; i<HTYPELINE; i++) {
		printf( (i&3) ? "  " : "   ");
		buf[i]=' ';
		}
	buf[i]=0;
	printf("    %s\n",buf);
	}
Close(fh);
return 0;
}

do_htype()
{
all_args("", htype_a_file, 0);
return 0;
}

do_stack()
{
long n;

if (ac>1) {
	n=Atol(av[1]);
	if (!IoErr()) Mycli->cli_DefaultStack=(long)(n >> 2L);
	}
else printf("current stack size is %ld bytes\n",
				(long)Mycli->cli_DefaultStack << 2L);
return 0;
}

do_fault()
{
struct PERROR *p;
register unsigned int i;
int n;

for (i=1; i<ac; i++) {
	n=myatoi(av[i],0,32767);
	if (!atoierr) {
		for (p=Perror; p->errnum && p->errnum!=n; p++);
		if (p->errnum)
			printf("Fault %d: %s\n",n,p->errstr);
		else
			printf("Fault %d not recognized\n",n);
		}
	}
return 0;
}

struct rpncommand {
	char *str;
	int parsin, parsout;
	};

struct rpncommand rpn[]={
	"+",	2,	1,
	"-",	2,	1,
	"*",	2,	1,
	"/",	2,	1,
	"%",	2,	1,
	"&",	2,	1,
	"|",	2,	1,
	"~",	1,	1,
	">",	2,	1,
	"<",	2,	1,
	"==",	2,	1,
	"!",	1,	1,
	"DUP",	1,	2,
	"DROP",	1,	0,
	"SWAP",	2,	2,
	"HELP",	0,	0,
	NULL,	0,	1,	/* this looks for a number */
};

do_rpn(garbage,ifflag) /* ifflag!=0 if called from if */
char *garbage;
{
register long n0, n1;
long t;
unsigned int i, j;
int sp=0;
long stack[100];
struct rpncommand *temp;

i=1;
if (ifflag) get_opt("rn",&i);
for (; i<ac; i++) {
	for (j=0; rpn[j].str && Strcmp(rpn[j].str,av[i]); j++) ;
	n0=stack[sp-1];
	n1=stack[sp-2];
	sp -= (rpn[j].parsin);
	if (sp<0) { fprintf(stderr, "RPN: Empty stack\n"); return 1; }
	switch (j) {
	  case 0:	n0 += n1;		break;
	  case 1:	n0 = n1-n0;		break;
	  case 2:	n0 *= n1;		break;
	  case 3:	n0 = n1/n0;		break;
	  case 4:	n0 = n1%n0;		break;
	  case 5:	n0 &= n1;		break;
	  case 6:	n0 |= n1;		break;
	  case 7:	n0 =  ~n0;		break;
	  case 8:	n0 = (n1 > n0);		break;
	  case 9:	n0 = (n1 < n0);		break;
	  case 10:	n0 = (n0 == n1);	break;
	  case 11:	n0 = !n0;		break;
	  case 12:	n1=n0;			break;
	  case 13:	t=n0; n0=n1; n1=t;	break;
	  case 14:				break;
	  case 15:	printf("In Commands Out\n");
			for (temp=rpn; temp->str; temp++)
			    printf(" %d %-10s%d\n",
				temp->parsin,temp->str,temp->parsout);
			break;
	  default:	n0=Atol(av[i]);
			if (IoErr()) {
				fprintf(stderr, "Bad RPN cmd: %s\n",av[i]);
				return 20;
				}
			break;
	  }
	stack[sp]=n0;
	stack[sp+1]=n1;
	sp += rpn[j].parsout;
	}
if (ifflag) return (int)(stack[sp-1]);	/* called from if: return top value */
for (i=sp-1;(int)i>=0;i--) printf("%ld\n", stack[i]); /* else print stack */
return 0;
}

do_path()
{
union {	long *lp; long ll; } l;
char buf[256];

puts("Current dir");
l.lp = (long *) Mycli->cli_CommandDir;
while (l.ll) {
	l.ll <<= 2;
	PathName(l.lp[1], buf, 256L);
	puts(buf);
	l.ll = *l.lp;
	}
puts("C:");
return 0;
}

do_pri()
{
int t, pri;
struct Process *proc;

t=(int)(long)FindCLI(0L);
t=myatoi(av[1],0,t); if (atoierr) return 20;
pri=myatoi(av[2],-128,127); if (atoierr) return 20;
Forbid();
proc=(t==0 ? Myprocess : FindCLI((long)t));
if (proc==NULL) fprintf(stderr, "process not found\n");
	else SetTaskPri(proc, (long)pri);
Permit();
return 0;
}

do_strleft()
{
char buf[256];
int n;

strcpy(buf,av[2]);
n=myatoi(av[3],1,strlen(buf)); if (atoierr) return 20;
buf[n]='\0';
set_var(LEVEL_SET, av[1], buf);
return 0;
}

do_strright()
{
char buf[256];
int n;

strcpy(buf, av[2]);
n=myatoi(av[3],1,strlen(buf)); if (atoierr) return 20;
set_var(LEVEL_SET, av[1], buf+strlen(buf)-n);
return 0;
}

do_strmid()
{
char buf[256];
int n1, n2;

strcpy(buf, av[2]);
n1=myatoi(av[3],1,strlen(buf))-1; if (atoierr) return 20;
if (ac>4) {
	n2=myatoi(av[4],1,strlen(buf)-n1); if (atoierr) return 20;
	buf[n1+n2]='\0';
	}
set_var(LEVEL_SET, av[1], buf+n1);
return 0;
}

do_strlen()
{
char buf[16];

sprintf(buf,"%d",strlen(av[2]));
set_var(LEVEL_SET, av[1], buf);
return 0;
}

int atoierr;

myatoi(s,min,max)
char *s;
{
int n;

n=(int)(long)Atol(s);
if (atoierr=IoErr())
	ierror(s,511);
	else if (n<min || n>max) {
		atoierr=1;
		printf("%s(%d) not in (%d,%d)\n",s,n,min,max);
		}
return n;
}

do_fltlower()
{
char buf[256], *s;

while (!CHECKBREAK() && gets(buf)) {
	for (s=buf; *s; s++) *s=tolower(*s);
	puts(buf);
	}
return 0;
}

do_fltupper()
{
char buf[256], *s;

while (!CHECKBREAK() && gets(buf)) {
	for (s=buf; *s; s++) *s=toupper(*s);
	puts(buf);
	}
return 0;
}

#define RXFB_RESULT  17

static struct rexxmsg {
	struct Message cm_Node;
	LONG   RFU1;
	LONG   RFU2;
	LONG   rm_Action;
	LONG   rm_Result1;
	LONG   rm_Result2;
	char   *cm_Args[16];
	LONG   RFU7;
	LONG   RFU8;
	LONG   RFU9;
	LONG   RFU10;
	LONG   RFU11;
	LONG   RFU12;
} mymsg;

do_rxsend()
{
int i=1, resflag;
char *result;
struct MsgPort *port, *reply;
long len;

get_opt("r", &i);
resflag=options;
if (!(port = FindPort(av[i++]))) { fprintf(stderr, "No port %s!\n", av[--i]); return 20; }
mymsg.cm_Node.mn_Node.ln_Type = NT_MESSAGE;
mymsg.cm_Node.mn_Length = sizeof(struct rexxmsg);
mymsg.rm_Action = (resflag ? 1L << RXFB_RESULT : 0);
if (!(reply = CreatePort(NULL, 0L))) {
	fprintf(stderr, "No reply port\n");
	return 20;
	}
mymsg.cm_Node.mn_ReplyPort = reply;

for ( ; i<ac; i++) {
	mymsg.cm_Args[0] = av[i];
	mymsg.rm_Result2 = 0;	/* clear out the last result. */
	PutMsg(port, &mymsg.cm_Node);
	WaitPort(reply);

	if (resflag) {
		result=(char *)mymsg.rm_Result2;
		len=*( (long *)(result-4) );
		if (len<0 || len>256)
			fprintf(stderr, "Risultato troppo lungo\n");
		else
			printf("%s\n", result);
		FreeMem(result, len);
		}
	}

if (reply) DeletePort(reply);
return 0;
}

do_rxrec()
{
struct MsgPort *port;
struct rexxmsg *msg;
char *portname, *str;

if (ac > 1)
	portname=av[1];
else
	portname="rexx_csh";

port=CreatePort(portname, 0L);
if (port==NULL) {
	fprintf(stderr, "Can't have MsgPort %s\n", portname);
	return 20;
	}
for (;;) {
	WaitPort(port);
	while (msg=(struct rexxmsg *)GetMsg(port)) {
		if ( ! Strcmp(msg->cm_Args[0], "bye")) {
			ReplyMsg((struct Message *)msg);
			DeletePort(port);
			return 0;
			}
		exec_command(msg->cm_Args[0]);
		if (msg->rm_Action & (1L << RXFB_RESULT)) {
			str = get_var(LEVEL_SET, v_lasterr);
			msg->rm_Result2=(str) ? atoi(str) : 20;
			}
		ReplyMsg((struct Message *)msg);
		}
	}
}
