home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
program
/
nutshsrc
/
nutshell.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-03-20
|
14KB
|
689 lines
/************************************************
* *
* NutShell, an accessory for mouse-haters. *
* *
* written by *
* Geert Jan van Oldenborgh, *
* Ank van der Moerstraat 24, *
* NL-2331 HS Leiden, *
* tel 071-317512. *
* t19@nikhefh.hep.nl *
* *
* and free for anyone. *
* *
************************************************/
/* #[ header: */
#include <stdio.h>
#include <stdlib.h>
#include <aes.h>
#include <tos.h>
#include <string.h>
#include <ext.h>
/* REDRAW: no separate screen, save only menu bar,
no REDRAW: save whole screen. */
#define REDRAW
#define MOUSE_ON graf_mouse( M_ON, (void *)0 )
#define MOUSE_OFF graf_mouse( M_OFF, (void *)0 )
#define BYTE unsigned char
#define VT52_LEFT 'D'
#define VT52_RIGHT 'C'
#define VT52_CLRLINE 'K'
#define VT52_CUR_ON 'e'
#define VT52_CUR_OFF 'f'
#define VT52_HOME 'H'
#define VT52_CLEAR "E<-H"[0]
#define CRETURN '\x0D'
#define PROMPT "$ "
/* prototypes */
int getscreen(void);
void redrawscreen(void);
void eventloop(void);
void putstring(char *string);
void getstring(BYTE *string, int length);
void putletter(char letter);
void putescape(char letter);
void clearcursor(void);
void newline(void);
void backspace(int n);
void putenvparent(char *entry, char *env);
void setshell(void);
int mysystem(char *string);
void zero_shell_p(void);
/* #] header: */
/* #[ globals: */
/* AES garbage */
int appl_id;
int menu_id;
int buffer[16];
extern int _app;
/* Basepage */
extern BASPAG *_BasPag;
/* screen info */
#ifndef REDRAW
long screensize = 5 + 32256L;
#else
int screensize;
#endif
int res,screenh,screenw;
void *oldLogbase, *oldPhysbase, *newBase;
char *screen_mem, *extra_mem,
motd[] = "NutShell version 0.1, "\
__DATE__\
", use 'lo' to exit",
shell[] = "d:\\shell.prg\0<- your shell",
home[] = "HOME=e:\\\0<- your home",
error[] = "cannot execute or find shell",
magic[] = "GJvO",
st[] = "unset tosonly";
long extra_size = 0L;
int extra_allocated = 0,
screen_allocated = 0,
busy = 0,
no_shell;
BYTE string[79],
oudstring[78] = "lo";
/* #] globals: */
/* #[ main: */
int
main(void)
/********************************************************
* *
* NutShell: passes commends to any running shell *
* which accepts system() calls over _shell_p *
* *
********************************************************/
{
/* go through the all the formalities */
if ( !_app )
{
appl_id = appl_init();
if ( appl_id == -1 ) return(0);
menu_id = menu_register( appl_id, " NutShell");
if ( menu_id == -1 ) return(-1);
#ifdef REDRAW
/* find ot the resolution, set some globals accordingly (will not
work on a 19" screen) */
res = Getrez();
switch ( res )
{
case 2:
screenh = 400;
screenw = 640;
screensize = 19*80 + 5;
break;
case 1:
screenh = 400;
screenw = 320;
screensize = 19*40 + 5;
break;
case 0:
screenh = 200;
screenw = 320;
screensize = 10*40 + 5;
break;
}
#endif
/* if an accessory, hit _shell_p to 0 (there cannot be a shell) */
Supexec(zero_shell_p);
}
/* and GO */
eventloop();
return(0);
}
/* #] main: */
/* #[ eventloop: */
void
eventloop(void)
{
/* #[ loop: */
/* the main (unending) loop: if an accesory, wait for an AC_OPEN or
AC_CLOSE */
while ( 1 ) {
if ( !_app ) evnt_mesag(buffer);
if ( busy ) continue;
/* #] loop: */
/* #[ open: */
if ( _app || buffer[0] == AC_OPEN && buffer[4] == menu_id )
{
/* set a flag to indicate that we are being called
recursively */
busy = 1;
/* The first thing to do is to free the memory we stole
during startop of the .prg program (or desktop) */
if ( extra_allocated )
{
extra_allocated = 0;
if ( ! strcmp(extra_mem,magic) )
{
#ifdef DEBUG
puts("freed extra_mem ");
#endif
Mfree( extra_mem );
}
else
#ifdef DEBUG
puts("lost extra_mem ");
#endif
;
}
/* check whether we still own the screen */
if ( screen_allocated )
{
if ( strcmp(screen_mem,magic) )
{
#ifdef DEBUG
puts("lost screen ");
#endif
screen_allocated = 0;
}
else
{
#ifdef DEBUG
puts("screen still OK ");
#endif
}
}
if ( getscreen() ) continue;
if ( system("free") )
{
no_shell = 1;
if ( mysystem("free") )
{
putstring(error);
newline();
}
}
else
no_shell = 0;
/* make doubly sure we only execute TOS progs (not much use)*/
if ( !_app ) system(st+2);
while ( 1 )
{
putstring(PROMPT);
clearcursor();
getstring(string,78);
if ( ! strcmp(string,"lo") ) break;
else if ( ! strncmp(string,"malloc",6) )
{
if ( (int)strlen(string) <= 7 )
putstring("Usage: malloc extra_size[kB]");
else
{
extra_size = 1024L * atol( string + 6 );
if ( extra_size )
putstring("trying");
else
putstring("given");
}
newline();
}
else
{
if ( no_shell )
mysystem(string);
else
system(string);
}
}
/* clean up */
if ( _app )
{
MOUSE_ON;
putescape(VT52_CUR_OFF);
break;
}
system(st);
redrawscreen();
if ( extra_size )
{
if ( ( extra_mem = Malloc( extra_size ) ) > NULL )
{
#ifdef DEBUG
puts("allocated extra_mem ");
#endif
strcpy(extra_mem,magic);
extra_allocated = 1;
}
}
else
{
/* give up everything */
#ifdef DEBUG
puts("freed screen ");
#endif
Mfree( screen_mem );
screen_allocated = 0;
}
busy = 0;
}
/* #] open: */
/* #[ close: */
if ( buffer[0] == AC_CLOSE )
{
/* Just for safety if we happen to receive an AC_CLOSE within one
application. Note that we rely heavily on the zeroing of
memory when an application starts */
if ( screen_allocated && ! strcmp(screen_mem,magic) )
{
#ifdef DEBUG
puts("freed screen ");
#endif
Mfree(screen_mem);
}
if ( extra_allocated && ! strcmp(extra_mem,magic) )
{
#ifdef DEBUG
puts("freed extra_mem ");
#endif
Mfree(extra_mem);
}
extra_allocated = 0;
screen_allocated = 0;
/* This may look strange, but remember that when running a shell
the AC_CLOSE does not arrive until we start a GEM application
which does an appl_init() or evnt_time(0,0). The result is
that we steal (extra_size + screensize) bytes from every .prg
application, but NOT from .tos or .ttp jobs like TeX and tcc.
*/
/* I should check that I am not in the desktop, does anyone know
a trick on how to do this??? */
if ( extra_size )
{
if ( ( screen_mem = Malloc( screensize )) > NULL )
{
#ifdef DEBUG
puts("allocated screen ");
#endif
screen_allocated = 2;
strcpy(screen_mem,magic);
if ( ( extra_mem = Malloc( extra_size )) > NULL )
{
#ifdef DEBUG
puts("allocated extra ");
#endif
extra_allocated = 1;
strcpy(extra_mem,magic);
}
}
}
}
}
/* #] close: */
}
/* #] eventloop: */
/* #[ getscreen: */
int
getscreen(void)
{
if ( !_app )
{
if ( !screen_allocated )
{
screen_mem = Malloc( screensize + 17000L );
if ( screen_mem <= NULL )
{
form_alert(1,"[3][| Not enough | memory left ][ Back to GEM ]");
busy = 0;
return(1);
}
Mshrink( 0, screen_mem, screensize );
#ifdef DEBUG
puts("Allocated screen");
#endif
}
oldPhysbase = Physbase();
oldLogbase = Logbase();
#ifdef REDRAW
/* copy the menubar to own memory */
memcpy(screen_mem + 5, oldPhysbase, screensize - 5);
#else
/* switch to new screen */
newBase = (void *)( (long)(screen_mem + 260) & 0xFFFFFF00L);
Setscreen( newBase, newBase, -1 );
Vsync();
#endif
}
/* cursor on and clear screen */
MOUSE_OFF;
putescape(VT52_CUR_ON);
putescape(VT52_HOME);
if ( screen_allocated != 1 )
{
#ifndef REDRAW
putescape(VT52_CLEAR);
#endif
putstring(motd);
newline();
if ( !_app )
{
screen_allocated = 1;
strcpy(screen_mem,magic);
}
}
return(0);
}
/* #] getscreen: */
/* #[ redrawscreen: */
void
redrawscreen(void)
{
/* cursor off */
putescape(VT52_CUR_OFF);
#ifdef REDRAW
/* copy the menubar back */
memcpy(oldPhysbase, screen_mem + 5, screensize - 5);
/* send a redraw to all windows */
form_dial(FMD_FINISH, 0, 0, 0, 0, 0, 0, screenw, screenh);
#else
/* set back the old screen */
Setscreen( oldLogbase, oldPhysbase, -1 );
Vsync();
#endif
MOUSE_ON;
}
/* #] redrawscreen: */
/* #[ getstring: */
void getstring(BYTE *string, int length)
{
BYTE *current, *end;
long key;
BYTE ascii, scan;
int i,echo;
char let10[] = "1234567890";
current = end = string;
*current = '\0';
while ( 1 )
{
/* first use the GemDos buffer (we use the Bios, but a repeat or
typeahead may have filled this). Hope nobody presses ^c in this time.
*/
if ( Cconis() )
{
key = Cconin();
if ( key == 0L ) key = 0x00610000L; /*undo*/
echo = 0;
}
else
{
key = Bconin(2);
echo = 1;
}
ascii = (char)(key & 0x000000FFl);
scan = (char)( ( key >> 16 ) & 0x000000FFl);
if ( ascii == '\x00' )
{
switch ( scan )
{
case 0x61:
case 0x5d:
strcpy(string,"lo");
return;
case 0x48:
strcpy(string,oudstring);
backspace((int)(current-string));
if ( string != end ) putescape(VT52_CLRLINE);
putstring(string);
current = end = string + (int)strlen(string);
break;
case 0x50:
if ( string != end )
{
backspace((int)(current-string));
putescape(VT52_CLRLINE);
current = end = string;
*current = '\0';
}
break;
case 0x4b:
if ( current > string )
{
--current;
putletter('\b');
}
break;
case 0x4d:
if ( current < end )
{
current++;
putescape(VT52_RIGHT);
}
break;
case 0x47:
if ( current == string )
{
strcpy(string,"clear");
return;
}
case 0x62:
if ( current == string )
{
putstring(motd);
newline();
putstring(PROMPT);
}
break;
}
if ( current == string && scan >= 0x3b && scan < 0x44 )
{
strcpy(string,"if($?PF1 )echo $PF1 ;$PF1 ");
string[7] = string[18] = string[24] = let10[scan - 0x3b];
return;
}
if ( current == string && scan >= 0x54 && scan < 0x5d )
{
strcpy(string,"if($?PF1 )echo $PF1 ;$PF1 ");
string[8] = string[19] = string[25] = let10[scan - 0x3b];
return;
}
}
else
{
switch( scan )
{
case 0x4b:
if ( !echo ) putletter('\b');
backspace((int)(current-string));
current = string;
continue;
case 0x4d:
if ( !echo ) putletter('\b');
for ( i=(int)(end-current); i; --i) putescape(VT52_RIGHT);
current = end;
continue;
}
switch ( ascii )
{
case '\b':
if ( current == string ) break;
if ( echo ) putescape(VT52_LEFT);
--current;
case '\x7f':
if ( current == end ) break;
memcpy(current, current+1, (int)(end-current));
putstring(current);
putletter(' ');
backspace((int)(--end - current + 1));
break;
case '\x0d':
if ( scan == 0x72 ) current = end;
*current = '\0';
if ( current != end ) putescape(VT52_CLRLINE);
strcpy(oudstring,string);
newline();
return;
case '\x15':
backspace((int)(current-string));
putescape(VT52_CLRLINE);
current = end = string;
*current = '\0';
break;
case '\x14':
if ( current - string > 1 )
{
scan = *(current-2);
*(current - 2) = *(current - 1);
*(current - 1) = scan;
backspace(2);
putstring(current - 2);
backspace(end-current);
}
break;
default:
if ( (int)(end-string) < length-2 )
{
memcpy(current + 1, current, (int)(end-current)+1);
*current = ascii;
end++;
if ( echo ) putstring(current);
backspace((int)(end - ++current));
}
else
putletter('\a');
}
}
if ( current == end ) clearcursor();
}
}
/* #] getstring: */
/* #[ putthings: */
void
putstring(char *string)
{
char *p;
p = string;
while ( *p ) Bconout(5,(int)(*p++));
}
void
putletter(char letter)
{
Bconout(2,(int)letter);
}
void
putescape(char letter)
{
Bconout(2,0x1b);
Bconout(2,(int)letter);
}
void
clearcursor(void)
{
putletter(' ');
putescape(VT52_LEFT);
}
void
newline(void)
{
putletter('\x0d');
putletter('\n');
}
void
backspace(int n)
{
int i;
for( i=n; i; --i) putescape(VT52_LEFT);
}
/* #] putthings: */
/* #[ mysystem: */
int mysystem(char *string)
{
char arg[82],env[200],*p,*q;
long l;
int i,j;
strcpy(arg,"x-c ");
strcat(arg,string);
arg[0] = strlen(arg+1);
#ifdef DEBUG
printf("mysytem calls Pexec with argument %s\n",arg+1);
#endif
p = env;
q = "unixpath=";
while ( *p++ = *q++ );
q = home;
while ( *p++ = *q++ );
q = "_PBP=";
while ( *p++ = *q++ );
l = (long)_BasPag;
p += 7;
for( i=0; i<8; i++)
{
j = l & 0x0000000FL;
*--p = "0123456789ABCDEF"[j];
l >>= 4;
}
p += 8;
*p++ = 0;
q = "ARGV=CCC?????????????????????????";
while ( *p++ = *q++ );
q = shell;
while ( *p++ = *q++ );
q = "-c";
while ( *p++ = *q++ );
q = string;
while ( *p++ = *q++ );
*p = 0;
#ifdef DEBUG
p = env;
putstring("environment:");
newline();
while (*p)
{
while(*p++) putletter(*p);
newline();
}
#endif
l = Pexec(0, shell, arg, env);
putescape(VT52_CUR_ON);
return( (int)l);
}
/* #] mysystem: */
/* #[ zero_shell_p: */
void zero_shell_p(void)
{
long *p;
p = 0x4f6;
*p = 0L;
}
/* #] zero_shell_p: */