/*
 * MAIN.C
 *
 * Matthew Dillon, 24 Feb 1986
 * (c)1986 Matthew Dillon     9 October 1986
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
 * Version 5.00L by Urban Mueller 17-Feb-91
 *
 */

#include "shell.h"

void breakreset(void);
struct Window *getwindow (void);

char shellname[]   ="CShell V5.00L";
char shellversion[]="500";
char shellvers[]   ="5.00";
char shellctr []   ="CshCounter";
char shellres []   ="CshResident";
char shellv   []   ="\0$VER: csh 5.00";

static void add_residents(void);

char *oldtitle;
char trueprompt[100];
char Inline[260];
struct IntuitionBase *IntuitionBase;
struct Window *Win;
struct ArpBase *ArpBase;
int    oldtaskpri=-999;

static char *defset[]={
	v_histnum,  "0",
	v_titlebar, shellname,
	v_hist,     "50",
	v_lasterr,  "0",
	v_stat,     "0",
	v_path,     "RAM:,RAM:c,df0:c,df1:c,sys:system",
	v_rxpath,   "REXX:",
	v_scroll,   "3",
	v_minrows,  "34",
	v_hilite,   "c7",
	v_lcd,      "",
	v_qcd,      "s:csh-qcd",
	"_terminal","",
	"_man",     "shell.doc",
	"_insert",  "1",
	"_version", shellversion,
	"f1",       "cdir df0:\15",
	"F1",       "cdir df1:\15",
	"f3",       "cdir RAM:\15",
	"F3",       "cdir vd0:\15",
	"f4",       "cd df0:\15",
	"F4",       "cd df1:\15",
	"f5",       "cls; ls\15",
	"F5",       "cdir ",
	"f6",       "ls -s\15",
	"f7",       "info\15",
	"F7",       "assign \15",
	"f8",       "window -lf\15",
	"F8",       "window -sb\15",
	"f10",      "cls\15",
	"F10",      "exit\15",
	NULL,       NULL
};

static char *defalias[]={
	"cdir", "%q cd $q; cls; dir",
	"cls",  "echo -n ^l",
	"diffdir","dir -u",
	"dswap","cd $_lcd",
	"exit", "endcli;quit",
	"fg",   "pri 0 1",
	"kr",   "rm -r RAM:* >NIL:",
	"nice", "pri 0 -1",
	"lp",   "cat >PRT:",
	"q",    "quit",
	"manlist", "sea -qwnl $_man \"    *\"",
	NULL,   NULL
};

#ifndef AZTEC_C
chkabort()
{
	return 0;
}
#endif

extern struct Library *DosBase;

main(argc, argv)
char *argv[];
{
	int i;
	char buf[10];
	static char pipe1[32], pipe2[32];
	struct Window *getwindow();
	char nologin=0 , *mymem=malloc(4);
#ifdef AZTEC_C
	extern int Enable_Abort;
	Enable_Abort = 0;
#endif

	if( argc==0 )               /* Prevent starting from workbench */
		exit(0);

	if( !(av=malloc( max_ac*sizeof(char *)))) exit( 0 );

	initmap();

	if(!(ArpBase=(struct ArpBase *)OpenLibrary("arp.library",34L)))
		{ printf("No arp library\n"); exit(0); }

	IntuitionBase=(struct IntuitionBase *)ArpBase->IntuiBase;

	if( ArpBase->DosBase->lib_Version >= 36 )
		o_kick20=1;
	set_var( LEVEL_SET, "_kick2x", (o_kick20) ? "1" : "0" );

	if( !IsInteractive(Input()))
		o_bground=1;
	set_var( LEVEL_SET, v_bground, (o_bground) ? "1" : "0" );


	Forbid();
	i=0;
	if (Getenv(shellctr,buf,10L)) i=atoi(buf);
	if (Getenv(shellres,buf,10L)) o_resident=1;
	sprintf(buf, "%d", i+1);
	Setenv(shellctr, buf);
	Permit();

#ifdef isalphanum
	for( i='a'; i<='z'; i++ )
		isalph[i]=1;
	for( i='A'; i<='Z'; i++ )
		isalph[i]=1;
	for( i='0'; i<='9'; i++ )
		isalph[i]=1;
	isalph['_']=1;
#endif

#ifdef AZTEC_C
	stdin->_flags	|= _IONBF;	/* make sure we're set as an unbuffered tty */
	stdout->_flags	|= _IONBF;	/* in case of redirection in .login */
	Close(_devtab[2].fd);
	_devtab[2].mode |= O_STDIO;
	_devtab[2].fd = _devtab[1].fd;	/* set stderr to Output() otherwise */
					/* don't work with aux driver */
#else
	/* if( setvbuf( stdout,NULL,_IOLBF,BUFSIZ )) exit(20); */
	/* setnbf( stdout ); */
	/* Close( _ufbs[2] ); */
	/*_ufbs[2]=_ufbs[1]; */
	/* setnbf( stderr ); */
#endif

	Myprocess = (struct Process *)FindTask(0L);
	Mycli=(struct CommandLineInterface *)((long)Myprocess->pr_CLI << 2);

	if( !o_nowindow && (Win=getwindow()) && IsInteractive(Input())) {
		oldtitle=(char *)(Win->Title);
		set_menu();
	}

	Pipe1 = pipe1;
	Pipe2 = pipe2;
	sprintf(pipe1, "t:pipe1_%ld", mymem);
	sprintf(pipe2, "t:pipe2_%ld", mymem);

	sprintf(buf,"%ld",Myprocess->pr_TaskNum);
	set_var(LEVEL_SET, "_clinumber", buf);

	seterr();
	if (Myprocess->pr_CurrentDir == NULL)
		do_cd("x :");
	else do_pwd(NULL);

	o_nowindow= 1;

	set_var(LEVEL_SET,v_prompt, (IsInteractive(Input())) ? "%c%p> ":"");
	for( i=0; defset[i]; i+=2 )
		set_var( LEVEL_SET, defset[i], defset[i+1] );
	for( i=0; defalias[i]; i+=2 )
		set_var( LEVEL_ALIAS, defalias[i], defalias[i+1] );

	o_nowindow= 0;

	for (i = 1; i < argc; ++i) {
		if (*argv[i]=='-') {
			char *str=argv[1];

			if( index(str,'k') ) set_var(LEVEL_SET,v_nobreak,"1");
			if( index(str,'i') ) o_internal=1;
			if( index(str,'r') ) add_residents();
			if( index(str,'v') ) Verbose=1, set_var(LEVEL_SET,v_verbose,"1");
			if( index(str,'n') ) nologin=TRUE;
			if( index(str,'b') ) {
				oldtaskpri=Myprocess->pr_Task.tc_Node.ln_Pri;
				SetTaskPri( &Myprocess->pr_Task, -1 );
			}
			if( index(str,'f') ) {
				oldtaskpri=Myprocess->pr_Task.tc_Node.ln_Pri;
				SetTaskPri( &Myprocess->pr_Task,  1 );
			}
			if( index(str,'c') ) {
				Inline[0] = ' ';
				Inline[1] = '\0';
				while (++i < argc)
					{ strcat(Inline,argv[i]); strcat(Inline," "); }
				exec_command(Inline);
				main_exit(Lastresult);
			}
			if( index(str,'a')) {
				o_nowindow= o_noraw= 1;
				set_var( LEVEL_SET, v_hilite, "" );
			}
			if( index(str,'t')) {
				o_nowindow= o_vt100= o_nofastscr= 1;
				/*       clr     */
				set_var( LEVEL_SET, v_hilite, "r" );
				set_var( LEVEL_SET, v_noreq, "1" );
				set_var( LEVEL_SET, "_terminal", "1" );
				set_var( LEVEL_ALIAS, "cls", "e -n ^[[0\\;0H^[[J" );
			}
		} else {
			sprintf (Inline, "source %s",argv[i]);
			av[1] = argv[i];
			do_source (Inline);
		}
	}

	if (!nologin && exists(av[1] = "S:.login")) do_source("x S:.login");

	for (;;) {
		if (breakcheck())
#ifdef AZTEC_C
		while (WaitForChar(Input(), 100L) || stdin->_bp < stdin->_bend)
#else
		while (WaitForChar(Input(), 100L) || stdin->_rcnt != stdin->_wcnt )
#endif
			gets(Inline);
		clearerr(stdin);  /* prevent acidental quit */
		exec_every();
		update_sys_var(v_titlebar);
		update_sys_var(v_prompt);
		breakreset();
#if RAW_CONSOLE
		if (Quit || !rawgets(Inline, disable ? "_ " : trueprompt)) main_exit(0);
#else
		printf("%s", disable ? "_ " : trueprompt);
		fflush(stdout);
		if (Quit || !gets(Inline)) main_exit(0);
#endif
		breakreset();
		if (*Inline) exec_command(Inline);
	}
}

void
main_exit(n)
{
	int i;
	char buf[10];

	Getenv(shellctr,buf,10L);
	i=atoi(buf);
	sprintf(buf,"%d",i-1);
	Setenv(shellctr,buf);
	if( oldtitle )
		SetWindowTitles(Win,oldtitle,(char *)-1);
	if( oldtaskpri != -999 )
		SetTaskPri(&Myprocess->pr_Task,oldtaskpri);
	for (i=1; i<MAXMYFILES; i++) myclose(i);
	remove_menu();
	CloseLibrary((struct Library *)ArpBase);
	exit(0);
}

int
breakcheck()
{
	return !o_nobreak && SetSignal(0L,0L) & SIGBREAKF_CTRL_C;
}

void
breakreset()
{
	SetSignal(0L, SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D);
}

dobreak()
{
	if (breakcheck()) { printf("^C\n"); return(1); }
	return(0);
}

/* this routine causes manx to use this Chk_Abort() rather than it's own */
/* otherwise it resets our ^C when doing any I/O (even when Enable_Abort */
/* is zero).  Since we want to check for our own ^C's			 */

long
Chk_Abort()
{
	return(0);
}

void
_wb_parse()
{
}

do_howmany()
{
	char buf[10];

	Getenv(shellctr, buf, 10L);
	printf("Shell(s) running: %s\n",buf);
	return 0;
}

static struct Window *
getwindow()
{
	struct InfoData *infodata;
	struct Window *win;
	long args[8];

	if( o_nowindow )
		return NULL;
	infodata=(void *)AllocMem((long)sizeof(struct InfoData),MEMF_CLEAR|MEMF_PUBLIC);
	args[0]=(long)infodata >> 2;
	Write(Output(),"",1);        /* make window appear */
	SendPacket(ACTION_DISK_INFO,args,(void *)Myprocess->pr_ConsoleTask);
	win=(struct Window *)infodata->id_VolumeNode;
	FreeMem(infodata,(long)sizeof(struct InfoData));
	if( win==NULL )
		o_nowindow=1;
	newwidth();
	return win;
}

#ifndef AZTEC_C

char *
rindex( char *str , char c )
{
	char *ret=NULL;

	for( ; *str; str++ )
		if( *str==c )
			ret=str;
	return ret;
}

#endif

extern struct DosLibrary *DOSBase;

struct ResidentList {
	BPTR rl_Next;
	LONG rl_UseCount;
	BPTR rl_SegList;
	char rl_SegName[1];
};


static void
add_residents()
{
	char buf[80], *g, *p, c;
	struct RootNode *Node;
	struct DosInfo  *Info;
	struct ResidentList *res;
	struct ResidentProgramNode *rpn;

	if( ArpBase->ResidentPrgList )
		return;

	Forbid(); 
	Node=(struct RootNode *)DOSBase->dl_Root;
	Info=(struct DosInfo  *)(Node->rn_Info*4);
	res=(struct ResidentList *)((long)Info->di_NetHand*4);

	for( ; res; res=(struct ResidentList *)((long)res->rl_Next*4) ) {
		g=res->rl_SegName, p=buf;
		for( c=*g++; c>0; --c ) *p++=*g++;
		*p=0;
		if( res->rl_UseCount>=0 )
			res->rl_UseCount++;
		else
			continue;
		AddResidentPrg( res->rl_SegList, buf);
		for(rpn=ArpBase->ResidentPrgList; rpn; rpn=rpn->rpn_Next)
			if( rpn->rpn_Segment==res->rl_SegList )
				rpn->rpn_Usage++;
	}
	Permit();
}
