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 >
C/C++ Source or Header  |  1990-03-20  |  14KB  |  689 lines

  1. /************************************************
  2. *                                                *
  3. *    NutShell, an accessory for mouse-haters.    *
  4. *                                                *
  5. *    written by                                    *
  6. *        Geert Jan van Oldenborgh,                *
  7. *        Ank van der Moerstraat 24,                *
  8. *        NL-2331 HS Leiden,                        *
  9. *        tel 071-317512.                            *
  10. *        t19@nikhefh.hep.nl                        *
  11. *                                                *
  12. *    and free for anyone.                        *
  13. *                                                *
  14. ************************************************/
  15. /*    #[ header:                                     */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <aes.h>
  19. #include <tos.h>
  20. #include <string.h>
  21. #include <ext.h>
  22.  
  23. /* REDRAW: no separate screen, save only menu bar, 
  24. no REDRAW: save whole screen. */
  25. #define  REDRAW
  26.  
  27. #define MOUSE_ON    graf_mouse( M_ON, (void *)0 )
  28. #define MOUSE_OFF    graf_mouse( M_OFF, (void *)0 )
  29.  
  30. #define BYTE unsigned char
  31.  
  32. #define VT52_LEFT        'D'
  33. #define VT52_RIGHT        'C'
  34. #define VT52_CLRLINE     'K'
  35. #define VT52_CUR_ON     'e'
  36. #define VT52_CUR_OFF    'f'
  37. #define VT52_HOME        'H'
  38. #define VT52_CLEAR        "E<-H"[0]
  39. #define CRETURN '\x0D'
  40.  
  41. #define PROMPT        "$ "
  42.  
  43. /* prototypes */
  44.  
  45. int getscreen(void);
  46. void redrawscreen(void);
  47. void eventloop(void);
  48. void putstring(char *string);
  49. void getstring(BYTE *string, int length);
  50. void putletter(char letter);
  51. void putescape(char letter);
  52. void clearcursor(void);
  53. void newline(void);
  54. void backspace(int n);
  55. void putenvparent(char *entry, char *env);
  56. void setshell(void);
  57. int mysystem(char *string);
  58. void zero_shell_p(void);
  59.  
  60. /*    #] header:                                     */
  61. /*    #[ globals:                                 */
  62.  
  63. /* AES garbage */
  64. int appl_id;
  65. int menu_id;
  66. int buffer[16];
  67.  
  68. extern int _app;
  69.  
  70. /* Basepage */
  71. extern BASPAG *_BasPag;
  72.  
  73. /* screen info */
  74. #ifndef REDRAW
  75. long    screensize = 5 + 32256L;
  76. #else
  77. int        screensize;
  78. #endif
  79. int        res,screenh,screenw;
  80. void    *oldLogbase, *oldPhysbase, *newBase;
  81. char    *screen_mem, *extra_mem,
  82.         motd[] = "NutShell version 0.1, "\
  83.                 __DATE__\
  84.                 ", use 'lo' to exit",
  85.         shell[] = "d:\\shell.prg\0<- your shell",
  86.         home[]  = "HOME=e:\\\0<- your home",
  87.         error[] = "cannot execute or find shell",
  88.         magic[] = "GJvO",
  89.         st[] = "unset tosonly";
  90. long    extra_size = 0L;
  91. int     extra_allocated = 0,
  92.         screen_allocated = 0,
  93.         busy = 0,
  94.         no_shell;
  95. BYTE    string[79],
  96.         oudstring[78] = "lo";
  97.  
  98. /*    #] globals:                                 */
  99. /*    #[ main:                                    */
  100.  
  101. int
  102. main(void)
  103. /********************************************************
  104. *                                                        *
  105. *    NutShell: passes commends to any running shell        *
  106. *    which accepts system() calls over _shell_p            *
  107. *                                                        *
  108. ********************************************************/
  109. {
  110.     /* go through the all the formalities */
  111.  
  112.     if ( !_app ) 
  113.     {
  114.         appl_id = appl_init();
  115.         if ( appl_id == -1 ) return(0);
  116.         menu_id = menu_register( appl_id, "  NutShell");
  117.         if ( menu_id == -1 ) return(-1);
  118.     
  119. #ifdef REDRAW
  120.         /*    find ot the resolution, set some globals accordingly (will not 
  121.             work on a 19" screen) */
  122.         res = Getrez();
  123.         switch ( res )
  124.         {
  125.         case 2:
  126.             screenh = 400;
  127.             screenw = 640;
  128.             screensize = 19*80 + 5;
  129.             break;
  130.         case 1:
  131.             screenh = 400;
  132.             screenw = 320;
  133.             screensize = 19*40 + 5;
  134.             break;
  135.         case 0:
  136.             screenh = 200;
  137.             screenw = 320;
  138.             screensize = 10*40 + 5;
  139.             break;
  140.         }
  141. #endif
  142.  
  143.         /*    if an accessory, hit _shell_p to 0 (there cannot be a shell) */
  144.         Supexec(zero_shell_p);
  145.     }
  146.     
  147.     /* and GO */
  148.     eventloop();
  149.     
  150.     return(0);
  151. }
  152.  
  153. /*    #] main:                                    */
  154. /*    #[ eventloop:                                */
  155. void
  156. eventloop(void)
  157. {
  158. /*    #[         loop:                                */
  159.     /*    the main (unending) loop: if an accesory, wait for an AC_OPEN or
  160.         AC_CLOSE */
  161.  
  162.     while ( 1 ) {
  163.  
  164.         if ( !_app ) evnt_mesag(buffer);
  165.         if ( busy ) continue;
  166.  
  167. /*    #]         loop:                                */
  168. /*    #[         open:                                */
  169.         if ( _app || buffer[0] == AC_OPEN && buffer[4] == menu_id )
  170.         {
  171.             /* set a flag to indicate that we are being called
  172.             recursively */
  173.             busy = 1;
  174.  
  175.             /*    The first thing to do is to free the memory we stole
  176.                 during startop of the .prg program (or desktop) */
  177.             if ( extra_allocated )
  178.             {
  179.                 extra_allocated = 0;
  180.                 if ( ! strcmp(extra_mem,magic) )
  181.                 {
  182.                     #ifdef DEBUG
  183.                     puts("freed extra_mem ");
  184.                     #endif
  185.                     Mfree( extra_mem );
  186.                 }
  187.                 else
  188.                     #ifdef DEBUG
  189.                     puts("lost extra_mem ");
  190.                     #endif
  191.                     ;
  192.             }
  193.             /* check whether we still own the screen */
  194.             if ( screen_allocated )
  195.             {
  196.                 if ( strcmp(screen_mem,magic) )
  197.                 {
  198.                     #ifdef DEBUG
  199.                     puts("lost screen ");
  200.                     #endif
  201.                     screen_allocated = 0;
  202.                 }
  203.                 else
  204.                 {
  205.                     #ifdef DEBUG
  206.                     puts("screen still OK ");
  207.                     #endif
  208.                 }
  209.             }
  210.             if ( getscreen() ) continue;
  211.  
  212.             if ( system("free") )
  213.             {
  214.                 no_shell = 1;
  215.                 if ( mysystem("free") )
  216.                 {
  217.                     putstring(error);
  218.                     newline();
  219.                 }
  220.             }
  221.             else
  222.                 no_shell = 0;
  223.             /* make doubly sure we only execute TOS progs (not much use)*/
  224.             if ( !_app ) system(st+2);
  225.  
  226.             while ( 1 )
  227.             {
  228.                 putstring(PROMPT);
  229.                 clearcursor();
  230.                 getstring(string,78);
  231.                 if ( ! strcmp(string,"lo") ) break;
  232.                 else if ( ! strncmp(string,"malloc",6) )
  233.                 {
  234.                     if ( (int)strlen(string) <= 7 )
  235.                         putstring("Usage: malloc extra_size[kB]");
  236.                     else
  237.                     {
  238.                         extra_size = 1024L * atol( string + 6 );
  239.                         if ( extra_size )
  240.                             putstring("trying");
  241.                         else
  242.                             putstring("given");
  243.                     }
  244.                     newline();
  245.                 }
  246.                 else 
  247.                 {
  248.                     if ( no_shell ) 
  249.                         mysystem(string);
  250.                     else
  251.                         system(string);
  252.                 }
  253.             }
  254.  
  255.             /* clean up */
  256.             if ( _app ) 
  257.             {
  258.                 MOUSE_ON;
  259.                 putescape(VT52_CUR_OFF);
  260.                 break;
  261.             }
  262.  
  263.             system(st);
  264.             redrawscreen();
  265.  
  266.             if ( extra_size )
  267.             {
  268.                 if ( ( extra_mem = Malloc( extra_size ) ) > NULL )
  269.                 {
  270.                     #ifdef DEBUG
  271.                     puts("allocated extra_mem ");
  272.                     #endif
  273.                     strcpy(extra_mem,magic);
  274.                     extra_allocated = 1;
  275.                 }
  276.             }
  277.             else
  278.             {
  279.                 /* give up everything */
  280.                 #ifdef DEBUG
  281.                 puts("freed screen ");
  282.                 #endif
  283.                 Mfree( screen_mem );
  284.                 screen_allocated = 0;
  285.             }
  286.  
  287.             busy = 0;
  288.         }
  289. /*    #]         open:                                */
  290. /*    #[         close:                                */
  291.         if ( buffer[0] == AC_CLOSE )
  292.         {
  293.             /*    Just for safety if we happen to receive an AC_CLOSE within one
  294.                 application.  Note that we rely heavily on the zeroing of
  295.                 memory when an application starts */
  296.  
  297.                 if ( screen_allocated && ! strcmp(screen_mem,magic) )
  298.                 {
  299.                     #ifdef DEBUG
  300.                     puts("freed screen ");
  301.                     #endif
  302.                     Mfree(screen_mem);
  303.                 }
  304.                 if ( extra_allocated && ! strcmp(extra_mem,magic) )
  305.                 {
  306.                     #ifdef DEBUG
  307.                     puts("freed extra_mem ");
  308.                     #endif
  309.                     Mfree(extra_mem);
  310.                 }
  311.                 extra_allocated = 0;
  312.                 screen_allocated = 0;
  313.  
  314.             /*    This may look strange, but remember that when running a shell
  315.                 the AC_CLOSE does not arrive until we start a GEM application
  316.                 which does an appl_init() or evnt_time(0,0).  The result is
  317.                 that we steal (extra_size + screensize) bytes from every .prg
  318.                 application, but NOT from .tos or .ttp jobs like TeX and tcc.
  319.             */
  320.             /*    I should check that I am not in the desktop, does anyone know 
  321.                 a trick on how to do this??? */
  322.  
  323.             if ( extra_size )
  324.             {
  325.                 if ( ( screen_mem = Malloc( screensize )) > NULL )
  326.                 {
  327.                     #ifdef DEBUG
  328.                     puts("allocated screen ");
  329.                     #endif
  330.                     screen_allocated = 2;
  331.                     strcpy(screen_mem,magic);
  332.                     if ( ( extra_mem = Malloc( extra_size )) > NULL )
  333.                     {
  334.                         #ifdef DEBUG
  335.                         puts("allocated extra ");
  336.                         #endif
  337.                         extra_allocated = 1;
  338.                         strcpy(extra_mem,magic);
  339.                     }
  340.                 }
  341.             }
  342.         }
  343.     }
  344. /*    #]         close:                                */
  345. }
  346. /*    #] eventloop:                                 */
  347. /*    #[ getscreen:                                 */
  348.  
  349. int
  350. getscreen(void)
  351. {
  352.     if ( !_app )
  353.     {
  354.         if ( !screen_allocated )
  355.         {
  356.             screen_mem = Malloc( screensize + 17000L );
  357.             if ( screen_mem <= NULL )
  358.             {
  359.                 form_alert(1,"[3][| Not enough | memory left ][ Back to GEM ]");
  360.                 busy = 0;
  361.                 return(1);
  362.             }
  363.             Mshrink( 0, screen_mem, screensize );
  364.             #ifdef DEBUG
  365.             puts("Allocated screen");
  366.             #endif
  367.         }
  368.         oldPhysbase = Physbase();
  369.         oldLogbase  = Logbase();
  370. #ifdef REDRAW
  371.         /*    copy the menubar to own memory */
  372.         memcpy(screen_mem + 5, oldPhysbase, screensize - 5);
  373. #else
  374.         /*  switch to new screen */
  375.         newBase = (void *)( (long)(screen_mem + 260) & 0xFFFFFF00L);
  376.         Setscreen( newBase, newBase, -1 );
  377.         Vsync();
  378. #endif
  379.     }
  380.     /* cursor on and clear screen */
  381.     MOUSE_OFF;
  382.     putescape(VT52_CUR_ON);
  383.     putescape(VT52_HOME);
  384.     if ( screen_allocated != 1 )
  385.     {
  386. #ifndef REDRAW
  387.         putescape(VT52_CLEAR);
  388. #endif
  389.         putstring(motd);
  390.         newline();
  391.         if ( !_app )
  392.         {
  393.             screen_allocated = 1;
  394.             strcpy(screen_mem,magic);
  395.         }
  396.     }
  397.     return(0);
  398. }
  399. /*    #] getscreen:                                 */
  400. /*    #[ redrawscreen:                             */
  401.  
  402. void
  403. redrawscreen(void)
  404. {
  405.     /* cursor off */
  406.     putescape(VT52_CUR_OFF);
  407. #ifdef REDRAW
  408.     /*    copy the menubar back */
  409.     memcpy(oldPhysbase, screen_mem + 5, screensize - 5);
  410.     /*  send a redraw to all windows */
  411.     form_dial(FMD_FINISH, 0, 0, 0, 0, 0, 0, screenw, screenh);
  412. #else
  413.     /* set back the old screen */
  414.     Setscreen( oldLogbase, oldPhysbase, -1 );
  415.     Vsync();
  416. #endif
  417.     MOUSE_ON;
  418. }
  419.  
  420. /*    #] redrawscreen:                             */
  421. /*    #[ getstring:                                 */
  422.  
  423. void getstring(BYTE *string, int length)
  424. {
  425.     BYTE *current, *end;
  426.     long key;
  427.     BYTE ascii, scan;
  428.     int i,echo;
  429.     char let10[] = "1234567890";
  430.  
  431.     current = end = string;
  432.     *current = '\0';
  433.  
  434.     while ( 1 )
  435.     {
  436.         /*    first use the GemDos buffer (we use the Bios, but a repeat or
  437.         typeahead may have filled this).  Hope nobody presses ^c in this time. 
  438.         */
  439.         if ( Cconis() )
  440.         {
  441.             key = Cconin();
  442.             if ( key == 0L ) key = 0x00610000L; /*undo*/
  443.             echo = 0;
  444.         }
  445.         else
  446.         {
  447.             key = Bconin(2);
  448.             echo = 1;
  449.         }
  450.         ascii = (char)(key & 0x000000FFl);
  451.         scan = (char)( ( key >> 16 ) & 0x000000FFl);
  452.         if ( ascii == '\x00' )
  453.         {
  454.             switch ( scan )
  455.             {
  456.             case 0x61:
  457.             case 0x5d:
  458.                 strcpy(string,"lo");
  459.                 return;
  460.             case 0x48:
  461.                 strcpy(string,oudstring);
  462.                 backspace((int)(current-string));
  463.                 if ( string != end ) putescape(VT52_CLRLINE);
  464.                 putstring(string);
  465.                 current = end = string + (int)strlen(string);
  466.                 break;
  467.             case 0x50:
  468.                 if ( string != end )
  469.                 {
  470.                     backspace((int)(current-string));
  471.                     putescape(VT52_CLRLINE);
  472.                     current = end = string;
  473.                     *current = '\0';
  474.                 }
  475.                 break;
  476.             case 0x4b:
  477.                 if ( current > string )
  478.                 {
  479.                     --current;
  480.                     putletter('\b');
  481.                 }
  482.                 break;
  483.             case 0x4d:
  484.                 if ( current < end )
  485.                 {
  486.                     current++;
  487.                     putescape(VT52_RIGHT);
  488.                 }
  489.                 break;
  490.             case 0x47:
  491.                 if ( current == string )
  492.                 {
  493.                     strcpy(string,"clear");
  494.                     return;
  495.                 }
  496.             case 0x62:
  497.                 if ( current == string )
  498.                 {
  499.                     putstring(motd);
  500.                     newline();
  501.                     putstring(PROMPT);
  502.                 }
  503.                 break;
  504.             }
  505.             if ( current == string && scan >= 0x3b && scan < 0x44 )
  506.             {
  507.                 strcpy(string,"if($?PF1 )echo $PF1 ;$PF1 ");
  508.                 string[7] = string[18] = string[24] = let10[scan - 0x3b];
  509.                 return;
  510.             }
  511.             if ( current == string && scan >= 0x54 && scan < 0x5d )
  512.             {
  513.                 strcpy(string,"if($?PF1 )echo $PF1 ;$PF1 ");
  514.                 string[8] = string[19] = string[25] = let10[scan - 0x3b];
  515.                 return;
  516.             }
  517.         }
  518.         else
  519.         {
  520.             switch( scan )
  521.             {
  522.             case 0x4b:
  523.                 if ( !echo ) putletter('\b');
  524.                 backspace((int)(current-string));
  525.                 current = string;
  526.                 continue;
  527.             case 0x4d:
  528.                 if ( !echo ) putletter('\b');
  529.                 for ( i=(int)(end-current); i; --i) putescape(VT52_RIGHT);
  530.                 current = end;
  531.                 continue;
  532.             }
  533.             switch ( ascii )
  534.             {
  535.             case '\b':
  536.                 if ( current == string ) break;
  537.                 if ( echo ) putescape(VT52_LEFT);
  538.                 --current;
  539.             case '\x7f':
  540.                 if ( current == end ) break;
  541.                 memcpy(current, current+1, (int)(end-current));
  542.                 putstring(current);
  543.                 putletter(' ');
  544.                 backspace((int)(--end - current + 1));
  545.                 break;
  546.             case '\x0d':
  547.                 if ( scan == 0x72 ) current = end;
  548.                 *current = '\0';
  549.                 if ( current != end ) putescape(VT52_CLRLINE);
  550.                 strcpy(oudstring,string);
  551.                 newline();
  552.                 return;
  553.             case '\x15':
  554.                 backspace((int)(current-string));
  555.                 putescape(VT52_CLRLINE);
  556.                 current = end = string;
  557.                 *current = '\0';
  558.                 break;
  559.             case '\x14':
  560.                 if ( current - string > 1 )
  561.                 {
  562.                     scan = *(current-2);
  563.                     *(current - 2) = *(current - 1);
  564.                     *(current - 1) = scan;
  565.                     backspace(2);
  566.                     putstring(current - 2);
  567.                     backspace(end-current); 
  568.                 }
  569.                 break;
  570.             default:
  571.                 if ( (int)(end-string) < length-2 )
  572.                 {
  573.                     memcpy(current + 1, current, (int)(end-current)+1);
  574.                     *current = ascii;
  575.                     end++;
  576.                     if ( echo ) putstring(current);
  577.                     backspace((int)(end - ++current));
  578.                 }
  579.                 else
  580.                     putletter('\a');
  581.             }
  582.         }
  583.         if ( current == end ) clearcursor();
  584.     }
  585. }
  586. /*    #] getstring:                                 */
  587. /*    #[ putthings:                                 */
  588.  
  589. void
  590. putstring(char *string)
  591. {
  592.     char *p;
  593.     p = string;
  594.     while ( *p ) Bconout(5,(int)(*p++));
  595. }
  596. void
  597. putletter(char letter)
  598. {
  599.     Bconout(2,(int)letter);
  600. }
  601. void
  602. putescape(char letter)
  603. {
  604.     Bconout(2,0x1b);
  605.     Bconout(2,(int)letter);
  606. }
  607. void
  608. clearcursor(void)
  609. {
  610.     putletter(' ');
  611.     putescape(VT52_LEFT);
  612. }
  613. void
  614. newline(void)
  615. {
  616.     putletter('\x0d');
  617.     putletter('\n');
  618. }
  619. void
  620. backspace(int n)
  621. {
  622.     int i;
  623.     for( i=n; i; --i) putescape(VT52_LEFT);
  624. }
  625. /*    #] putthings:                                 */
  626. /*    #[ mysystem:                                */
  627. int mysystem(char *string)
  628. {
  629.     char arg[82],env[200],*p,*q;
  630.     long l;
  631.     int i,j;
  632.  
  633.     strcpy(arg,"x-c ");
  634.     strcat(arg,string);
  635.     arg[0] = strlen(arg+1);
  636. #ifdef DEBUG
  637.     printf("mysytem calls Pexec with argument %s\n",arg+1);
  638. #endif
  639.     p = env;
  640.     q = "unixpath=";
  641.     while ( *p++ = *q++ );
  642.     q = home;
  643.     while ( *p++ = *q++ );
  644.     q = "_PBP=";
  645.     while ( *p++ = *q++ );
  646.     l = (long)_BasPag;
  647.     p += 7;
  648.     for( i=0; i<8; i++)
  649.     {
  650.         j = l & 0x0000000FL;
  651.         *--p = "0123456789ABCDEF"[j];
  652.         l >>= 4;
  653.     }
  654.     p += 8;
  655.     *p++ = 0;
  656.     q = "ARGV=CCC?????????????????????????";
  657.     while ( *p++ = *q++ );
  658.     q = shell;
  659.     while ( *p++ = *q++ );
  660.     q = "-c";
  661.     while ( *p++ = *q++ );
  662.     q = string;
  663.     while ( *p++ = *q++ );
  664.     *p = 0;
  665. #ifdef DEBUG
  666.     p = env;
  667.     putstring("environment:");
  668.     newline();
  669.     while (*p)
  670.     {
  671.         while(*p++) putletter(*p);
  672.         newline();
  673.     }
  674. #endif
  675.     l = Pexec(0, shell, arg, env);
  676.     putescape(VT52_CUR_ON);
  677.     return( (int)l);
  678. }
  679. /*    #] mysystem:                                */
  680. /*    #[ zero_shell_p:                            */
  681.     void zero_shell_p(void)
  682.     {
  683.         long *p;
  684.         p = 0x4f6;
  685.         *p = 0L;
  686.     }
  687. /*    #] zero_shell_p:                            */
  688.  
  689.