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