
/*
 * SET.C
 *
 * (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"

static char *sys_expand( char *str, char *t );
static void set_sys_var( char *name );

#define MAXLEVELS (4+MAXSRC)

ROOT _Mbase[MAXLEVELS], *Mbase[ MAXLEVELS ];

void
init_mbase(void)
{
	int i;
	for( i=0; i<MAXLEVELS; i++ )
		Mbase[i]=&_Mbase[i];
}

void
set_var( int level, char *name, char *str )
{
	NODE **first, *node;
	char *t, c;
	int  truelevel=level;

	if( !str ) str="";

	for( t=name; isalphanum(*t); t++ ) ;
	c=*t; *t=0;

	if( level==LEVEL_SET ) level=LEVEL_LOCAL;

	for( ;; ) {
		first=&Mbase[level]->first[*name & MAXHASH-1];
		for( node=*first; node; node=node->next )
			if( !strcmp( node->name, name) ) {
				free( node->text );
				goto copy;
			}
		if( truelevel!=LEVEL_SET )
			break;
		level=LEVEL_SET, truelevel=-1;
	}

	if(!(node=malloc(sizeof(NODE) + strlen(name)))) {
		ierror(NULL,512);
		return;
	}
	node->next=*first;
	*first=node;
	strcpy( node->name, name );

copy:
	if(!(node->text=malloc(strlen(str)+1))) {
		ierror(NULL,512);
		return;
	}
	strcpy( node->text, str );
	*t=c;
	if( *name=='_' )
		set_sys_var( name );
}


void *
get_var( int level, void *varname )
{
	NODE *node;
	char *t, c, *name=varname;
	int  truelevel=level;

	if( level==LEVEL_SET ) level=LEVEL_LOCAL;

	for ( t= name; (signed char)*t>0; t++ ) ;
	c=*t; *t=0;

	for( ;; ) {
		node=Mbase[level]->first[*name & MAXHASH-1];

		for( ; node; node=node->next )
			if( !strcmp(node->name,name) )
				{ *t=c; return node->text; }
		if( truelevel!=LEVEL_SET )
			break;
		level=LEVEL_SET, truelevel=-1;
	}

	*t=c;

	return NULL;
}

void
unset_level( int level )
{
	NODE *node;
	int i;

	for( i=0; i<MAXHASH; i++ ) {
		for( node=Mbase[level]->first[i]; node; node=node->next ) {
			Free ( node->text );
			Free ( node );
		}
		Mbase[level]->first[i] = NULL;
	}
}

void
unset_var( int level, char *name )
{
	NODE **first=&Mbase[level]->first[*name & MAXHASH-1], *node, *prev;
	char *t, c;

	for( t=name; isalphanum(*t); t++ ) ;
	c=*t; *t=0;

	for( node=*first, prev=NULL; node; prev=node, node=node->next )
		if( !strcmp( node->name, name) ) {
			if( prev ) prev->next=node->next; else *first=node->next;
			Free( node->text );
			Free( node );
			if( *name=='_' )
				set_sys_var( name );
			break;
		}
	*t=c;
}


void
set_var_n( int level, char *name, char *str, int n )
{
	char c, len=strlen(str);

	if( n>len )
		n=len;

	if( n>=0 ) {
		c=str[n]; str[n]=0;
		set_var( level, name, str );
		str[n]=c;
	} else 
		set_var( level, name, "" );
}

int
do_unset_var( char *str, int level )
{
	int i;

	for (i = 1; i < ac; ++i)
		unset_var (level, av[i]);
	return 0;
}

int
do_set_var( char *command, int level )
{
	ROOT *root = Mbase[level];
	NODE *node;
	int i;
	char *str;

	switch (ac) {
	case 1:
		for( i=0; i<MAXHASH && !breakcheck(); i++ )
			for( node=root->first[i]; node && !dobreak(); node=node->next )
				printf ("%s%-10s %s\n", o_lolite, node->name, node->text);
		break;
	case 2:
		if (str=get_var(level,av[1])) printf ("%-10s %s\n", av[1], str);
		break;
	default:
		set_var (level, av[1], next_word (next_word (command)));
		break;
	}
	return 0;
}


extern char shellvers[];
extern char shellctr[];

static char *
sys_expand( char *str, char *t )
{
	struct DateStamp dss;
	char *u,buf[10];
	DateStamp(&dss);

	if( !str ) {
		*t=0;
		return t;
	}

	while (*str)
		if (*str=='%') {
			str+=2;
			switch( str[-1] ) {
			case 'p': t+=sprintf(t,"%s", get_var(LEVEL_SET, "_cwd"));  break;
			case 'm': t+=sprintf(t,"%d", AvailMem( 0 )/1024);          break;
			case 't': t+=sprintf(t,"%s", next_word(dates(&dss,0)));    break;
			case 'c': t+=sprintf(t,"%s", o_hilite);                    break;
			case 'v': t+=sprintf(t,"%s", shellvers );                  break;
			case 'n': t+=sprintf(t,"%s", get_var(LEVEL_SET,"_clinumber"));break;
			case 'h': t+=sprintf(t,"%s", get_var(LEVEL_SET, v_histnum));  break;
			case 'd':    sprintf(t,"%s", dates(&dss,0));if(u=index(t,' '))t=u;break;
			case 'f': t+=sprintf(t,"%s", oneinfo(get_var(LEVEL_SET,v_cwd),4));break;
			case 'r': t+=sprintf(t,"%d", (SBYTE)Myprocess->pr_Task.tc_Node.ln_Pri);break;
			case 's': t+=sprintf(t,"%s", (u=Getenv(shellctr,buf,10)?buf:"?"));break;
			default : *t++=str[-2]; *t++=str[-1]; break;
			}
		}
		else *t++=*str++;
	*t=0;
	return t;
}

void
push_locals( ROOT *newroot )
{
	int i;
	NODE **nodeptr;

	newroot->prev=Mbase[ LEVEL_LOCAL ];
	Mbase[ LEVEL_LOCAL ]=newroot;

	nodeptr=newroot->first;
	for( i=MAXHASH; i>0; --i )
		*nodeptr++=NULL;

}

void
pop_locals( void )
{
	ROOT *prev=Mbase[ LEVEL_LOCAL ]->prev;
	unset_level( LEVEL_LOCAL );
	Mbase[ LEVEL_LOCAL ]=prev;
}

int
do_local(void)
{
	int i;

	if( ac==1 )
		do_set_var( "", LEVEL_LOCAL);
	else 
		for( i=1; i<ac; i++ )
			set_var(LEVEL_LOCAL,av[i],"");
	return 0;
}


char truetitle[200];

char o_rback[12]="rback";
char o_hilite[24], o_lolite[8], *o_csh_qcd, o_kick20, o_nobreak;
char o_minrows, o_scroll, o_nowindow, o_noraw, o_vt100, o_nofastscr;
char o_bground, o_resident, o_internal, o_pipe[16]="T:", o_datefmt;
char o_abbrev=1;
long o_noreq;

extern char trueprompt[100];

static void
set_sys_var( char *name )
{
	char *get, *str, c=name[1], col;

	if( c==v_debug  [1] ) debug  =  get_var(LEVEL_SET,v_debug  )!=NULL;
	if( c==v_nobreak[1] ) o_nobreak=get_var(LEVEL_SET,v_nobreak)!=NULL;
	if( c==v_rback  [1] && (str=get_var(LEVEL_SET,v_rback)))strcpy(o_rback,str);
	if( c==v_abbrev [1] && (str=get_var(LEVEL_SET,v_abbrev)))o_abbrev=*str!='n';
	if( c==v_verbose[1] ) {
		Verbose=0;
		if( str=get_var(LEVEL_SET,v_verbose)) {
			if( index(str,'s' )) Verbose|= VERBOSE_SOURCE;
			if( index(str,'a' )) Verbose|= VERBOSE_ALIAS;
			if( index(str,'h' )) Verbose|= VERBOSE_HILITE;
		}
	}
	if( c==v_pipe   [1] ) {
		strcpy(o_pipe,"t:");
		if( str=get_var(LEVEL_SET,v_pipe) )
			strcpy(o_pipe,str);
		appendslash(o_pipe);
	}
	if( c==v_hilite [1] && !strcmp( name, v_hilite)) {
		o_hilite[0]=o_lolite[0]=0;
		get= get_var(LEVEL_SET,v_hilite);
		str= o_hilite;
		while( get && *get ) {
			switch( *get++ ) {
			case 'b': str+=sprintf( str, "\033[1m" ); break;
			case 'i': str+=sprintf( str, "\033[3m" ); break;
			case 'u': str+=sprintf( str, "\033[4m" ); break;
			case 'r': str+=sprintf( str, "\033[7m" ); break;
			case 'c': str+=strlen(str);
			          if( *get>='0' && *get<='9' ) {
			             col=*get++;
			             if( *get==',' && get[1]>='0' && get[1]<='9' ) {
			                 str+=sprintf( str,"\033[3%cm\033[4%cm",col,get[1]);
			                 get+=2;
			             } else 
			                 str+=sprintf( str,"\033[3%cm",col );
			          }
			          break;
			}
		}
		*str=0;
		if( *o_hilite )
			strcpy(o_lolite,"\033[m");
		strcpy(sys_expand(str,trueprompt),o_lolite);
	}
	if( c==v_scroll[1] ) {
		o_scroll=0;
		if( (str= get_var(LEVEL_SET,v_scroll))) {
			o_scroll=atoi( str );
			if( o_scroll<2 ) o_scroll=0;
			if( o_scroll>8 ) o_scroll=8;
		}
	}
	if( c==v_datefmt[1] ) {
		o_datefmt=(str=get_var(LEVEL_SET,v_datefmt)) && !strcmp(str,"subst");
	}
	if( c==v_minrows[1] ) {
		o_minrows=34;
		if( (str= get_var(LEVEL_SET,v_minrows))) {
			o_minrows=atoi( str );
			if( o_minrows<8 )   o_minrows=8;
			if( o_minrows>100 ) o_minrows=100, o_scroll=0;
		}
	}
	if( c==v_qcd[1] ) o_csh_qcd=get_var(LEVEL_SET,v_qcd);

	if( c==v_noreq[1] ) {
		o_noreq= get_var(LEVEL_SET,v_noreq ) ? -1 : 0;
		Myprocess->pr_WindowPtr = (APTR)o_noreq;
	}
	if( c==v_hist[1] )
		S_histlen=(str= get_var(LEVEL_SET, v_hist)) ? atoi(str) : 0;
	if( c==v_titlebar[1] )
		update_sys_var( v_titlebar );
}

void
update_sys_var( char *name )
{
	char c=name[1], *str, buf[250];

	if( c==v_prompt[1] ) {
		if( (str=get_var(LEVEL_SET,v_prompt) ) ==NULL) str="$ ";
		strcpy(sys_expand(str,trueprompt),o_lolite);
	}
	if( c==v_titlebar[1] && !o_nowindow && Win ) {
		sys_expand( get_var(LEVEL_SET, v_titlebar), buf);
		if (strcmp((char*)Win->Title, buf)) {
			strcpy(truetitle,buf);
			SetWindowTitles(Win, truetitle, (char *)-1);
		}
	}
}
