// BSHELL 2.00 //

#define DEBUG2       // Enable BSDEBUGs.

// Copyright 1992, Alfred J. Heyman and Spectrum Research, Inc.


//----------------------------------------------------------------------------//
// BigShell responds to the following environment variables.                  //
//                                                                            //
// SHELL_EMM=XXX                   ;Where XXX is in Kilobytes.                //
// SHELL_PROG=d:\path\filename.ext ;d:\path\file.ext is the program to run.   //
// SHELL_SWAP=d:\path              ;d:\path is the path to use for swap files.//
// SHELL_DEBUG=1                   ;If it exists, Big-Shell BSDEBUGs are used.//
//                                                                            //
//----------------------------------------------------------------------------//

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#pragma check_stack(off)

union REGS inregs,outregs;
struct SREGS segregs;

struct system_desc
{ int  size;
  char model;
  char submodel;
  char bios_release;
  char features;
} far *sys_desc;

int  far *hpid;

char *ems2use;       // Storage for "SHELL_EMM=" environment variable.
int  emspagecnt=0;   // Translated amount of EMM to use.

// External char definitions in SHELL.ASM //

extern  char psp_ascii[5];
extern  int  orig_psp;
extern  char thisprog[];
extern  char runname[];
extern  char swapfile[];
extern  char shelldir[];
extern  char acadname[];
extern  char program[];
extern  int  fh1;
extern  int  emm_load_flag;         // 1=Expanded Mem Manager is loaded.
extern  int  emm_use_flag;          // 1=Use EMM Memory if emm_load_flag set.
extern  int  machine;               // 0x11 = HP-VECTRA / 0x20 = IBM-PS2
extern  unsigned long  biggestl;    // Size of biggest Shell in EMS.
//extern  int  swap_size_h;

// External char definitions in either ACS.C or SPECTECH.C //

extern  char wderror[];
extern  char rderror[];
extern  char FNAMEX[];
extern  char EXTX[];
extern  char abortmsg[];
extern  char copyr[];

int  cadkeyflag;
int  keyhit,vmode,textmode;
int  bsdebugvar;                       // 1=Enable Debug Messages.
char far *beep;                        // Will hold pointer to SHELL_DEBUG=>
char far *temp;                        // Will hold pointer to SHELL_SWAP=>

char drive[5];
char dir[80];
char fname[20];
char ext[10];


char msg4[] = { "Press any key to attempt a normal shell." };

struct find_t fbuffer;

struct mb
{ char block;
  int  psp;
  int  size;
  char space[11];
}*mem_block;

int free_tsr_ram = 0;

// #define DEBUG //

//----------------------------------------------------//
exec()
{  int xpos,ypos;
   int disk;

   if(test_hwlock() == -1)
    { setretry();
      goto ABORT3;
    };

   switch(get_vmode())
     {  case 0:     ;
        case 1:     ;
        case 2:     ;
        case 3:     ;
        case 7:  textmode = 1;  break;
        default: textmode = 0;  break;
     };

   if(cadkeyflag == 1)  { textmode = 0; };
   clrretry();               // Clear normal retry attempt                //
   sti();                    // Enable interrupts                         //
   save_psp();               // Save current PSP and DTA                  //
   save_dta();

   new_psp();                // Do a dos task switch                      //
   new_dta();
   f88_i15();                // Get currently available extended mem size //
   cli();                    // interrupts off                            //
   save_cur_blks();          // Save current blocks before & after us.    //
   swapvects();              // Restore interrupt vectors                 //
   sti();                    // interrupts back on                        //
   if(test_acadl() != 0)
     { setretry();
       clr_tskip();
       goto ABORT1;
     };

   if(textmode)
     { xpos = wherex();
       ypos = wherey();
       open_bigshell();                        // Display message on screen //
       setcolor(7);
       gotoxy(xpos,ypos);
     };
   gen_swapname();

   if(rollout() == -1)       // Save ACAD to disk          //
     { clearwindow(0,0,79,24,7);
       setretry();
       gotoxy(0,0);
       sprintstr(wderror);
       gotoxy(0,1); sprintstr("SWAPFILE NAME.: ");  sprintstr(swapfile);
       gotoxy(0,2); sprintstr("POSSIBLE CAUSE: Disk Full or write protect fault.");
       gotoxy(0,4); sprintstr(msg4);
       getakey();
       clearwindow(0,0,79,24,7);
       gotoxy(0,0);
       goto ABORT1;
     }
    else
     { if(textmode)  { clearwindow(0,0,79,0,0x7); };
     };

   cli();                    // interrupts off             //

   rest_old_blks();          // Restore old blocks as when 1st loaded.   //
   sti();                    // interrupts back on         //
   acadshell();              // Run command.com            //
   if(machine != 0x20)
     { enable_a20(); }
    else
     { restore_ps2r(); };
   cli();                    // Interrupts off             //
   rest_cur_blks();          // Reset to prev current cond //
   sti();                    // enable interrupts          //
   if(textmode)
     { xpos = wherex();
       ypos = wherey();
       close_bigshell();     // Display message on CRT     //
       setcolor(7);
       gotoxy(xpos,ypos);
     };
   if(rollin() == -1)        // Restore Pharlap from disk  //
     { clearwindow(0,0,79,24,7);
       gotoxy(0,0); sprintstr(rderror);
       gotoxy(0,1); sprintstr("SWAPFILE NAME.: ");  sprintstr(swapfile);
       gotoxy(0,2); sprintstr("POSSIBLE CAUSE: UNKNOWN");
       gotoxy(0,4); sprintstr("Press any key to continue - System crash/lockup is likely.");
       getakey();
       clearwindow(0,0,79,24,7);
       gotoxy(0,0);
       goto ABORT1;
     }
    else
     { if(textmode) { clearwindow(0,0,79,0,0x7); }; };

ABORT1:

   cli();                    // Interrupts off             //
   swapvects();              // Restore interrupt vectors  //
   sti();                    // enable interrupts          //

ABORT2:

   restore_psp();            // Task switch back           //
   restore_dta();

ABORT3: ;

};

//----------------------------------------------------//

#ifdef DEBUG

print(mess)
char mess[];
{ int x;

  for(x=0 ; x != -1 ; x++)
    { if(mess[x]==0)
         { _bios_printer(_PRINTER_WRITE,0,0x0d);
           _bios_printer(_PRINTER_WRITE,0,0x0a);
           return(0);
         }
      else
         { _bios_printer(_PRINTER_WRITE,0,mess[x]);
         };
    };
};

#endif

//----------------------------------------------------//
// void _setargv() {}; //
// void _setenvp() {}; //
//----------------------------------------------------------------------//
prepare_ems()
{ int workvar;
  char *temp;

  ems2use=NULL;
  getenva(&ems2use,"SHELL_EMM=");       // Get shell-emm amount to use.
//ems2use  = getenv("SHELL_EMM");       // Get Shell-Emm amount to use.
  emspagecnt = atoi(ems2use);           // Convert ASCII to integer.
  emspagecnt+=15;
  emspagecnt=(emspagecnt/16);

  if(emspagecnt)
     { emm_use_flag = emm_loaded(); };   // See if EMM Loaded. (if necessary).

  if(emm_use_flag)
    { workvar=ems_open(emspagecnt);     // Allocate EMS handle if needed. 256K.
      if(workvar != 0)                  // If OPEN failed,
        { emm_use_flag=0;               //  ZAP emm_use_flag.
          emm_load_flag=0;              //  ZAP emm_load_flag.
        };
    };
};
    
//----------------------------------------------------------------------//

#ifdef DEBUG2
int BSDEBUG(int gostop,int number)
{ char dvalue[5];
  int x,y;

  if(gostop==0) { return(0); };
  itoa(number,dvalue,10);

  x=wherex();
  y=wherey();
  gotoxy(0,24);
  sprintstr(" SHELL DEBUG: [");
  sprintstr(dvalue);
  sprintstr("] ");
  gotoxy(x,y);
  delay(5);
};
#else
int BSDEBUG(int gostop,int number) {};
#endif


//----------------------------------------------------------------------//
finish(int retval)
{ char retstr[5];

  retval &= 255;                                // Ret code fits in char[4].
  itoa(retval,retstr,10);                       // Get return code to ascii.

  setcolor(7);                                  // Color to black & white.

  gotoxy(0,22);                                 // Cursor to end of screen.
  sprintstr("EMS Used by biggest shell: ");
  ltoa(biggestl,retstr,10);
  sprintstr(retstr);
  sprintstr(" Bytes");
  gotoxy(0,24);

  fin(retval);
};

//----------------------------------------------------------------------//
cvtpsp2ascii()
{ itoa(orig_psp,psp_ascii,16);
  strupr(psp_ascii);
};

//----------------------------------------------------------------------//
main()
{  int  retcode;

   temp=NULL;
   beep=NULL;
   getenva(&temp,"SHELL_SWAP=");          // Get Shell Swap Directory.

   getenva(&beep,"SHELL_DEBUG=");
   if(beep==NULL)
     { bsdebugvar=0; }
    else
     { bsdebugvar=1; };

   BSDEBUG(bsdebugvar,0);
   shelldir[0]=0;
   if(temp != NULL)
     { strcpy(shelldir,temp); };         // Copy it into structure.
   BSDEBUG(bsdebugvar,1);
   // argc--;                             // Decrement command lines to look at.
   // p = argv;                           // Point to Executed file name.
   get_psp();
   BSDEBUG(bsdebugvar,2);
   cvtpsp2ascii();          // Convert PSP to ascii.                          //
   BSDEBUG(bsdebugvar,3);

   get_run_name(&thisprog);               // Get program name.
   BSDEBUG(bsdebugvar,4);
   // strcpy(thisprog,*p);
   get_box_id();                          // Identify HW platform for A20 code.
   BSDEBUG(bsdebugvar,5);
   textmode = 1;
   get_vmode();
   BSDEBUG(bsdebugvar,6);
   set_write_vpage(get_disp_vpage());

   BSDEBUG(bsdebugvar,7);
   clearwindow(0,0,79,24,7);
   BSDEBUG(bsdebugvar,8);
   botmsg(copyr);           // Display the copyright                          //
   BSDEBUG(bsdebugvar,9);
   delay(1);

// if(detect()== 0x4d)  //  // Detect a hole error.                           //
//  { hole_error(); };  //
// malloc256();         //  // Get 256 bytes for PSP that Phar-Lap will rq.   //

   BSDEBUG(bsdebugvar,10);
   if(test_hwlock() == -1)  // Test for Hardware lock.                        //
     { finish(0); };

   BSDEBUG(bsdebugvar,11);
   f88_i15();               // Get available extended memory size             //
   BSDEBUG(bsdebugvar,12);
   install23();             // Install CNT-BREAK Handler                      //
   BSDEBUG(bsdebugvar,13);
   install24();             // Install Crit-Error Handler                     //
   BSDEBUG(bsdebugvar,14);
   geti21();                // Get I21 pointer.                               //
   BSDEBUG(bsdebugvar,15);
   prepare_ems();           // Prepare to use EMS memory if needed.
   BSDEBUG(bsdebugvar,16);
   install15();             // Install INT 15 handler                         //
   BSDEBUG(bsdebugvar,17);
   storevects();            // Save interrupt vectors as they are now.        //
   BSDEBUG(bsdebugvar,18);
   hookup();                // Hook our INT 21 handler up                     //
   BSDEBUG(bsdebugvar,19);
   if(copyright2()==-1)     // Shell out to copyright program                 //
     { retcode = -1;
       goto MAIN_ABORT;
     };
   BSDEBUG(bsdebugvar,20);
   saveblocks();            // Save the data of the MCB before and after us.  //
   BSDEBUG(bsdebugvar,21);
   malloc256();             // Get 256 bytes for PSP that Phar-Lap will rq.   //
   BSDEBUG(bsdebugvar,22);
   get_acadname();          // Run ACAD as ACAD or ACAD386.EXE                //
   BSDEBUG(bsdebugvar,23);
   setcolor(7);
   BSDEBUG(bsdebugvar,24);
   ts_enable();             // Clear initial trip/skip flag.
   BSDEBUG(bsdebugvar,25);
   clear_cmdln();           // Clear any /P or /9 options on command line.    //
   BSDEBUG(bsdebugvar,26);
   run_acad();
   BSDEBUG(bsdebugvar,27);
   retcode = get_retcode() & 255;
   BSDEBUG(bsdebugvar,28);
MAIN_ABORT:
   BSDEBUG(bsdebugvar,29);
   swapvects();         // This has the effect of unhooking our INT21:    //
   BSDEBUG(bsdebugvar,30);
   uninstall15();       // Uninstall our int 15 handler                   //
   BSDEBUG(bsdebugvar,31);
   cli();               // interrupts off                                 //
   shutdown();          // Signal last run through deallocation routine   //
   rest_old_blks();     // Restore old blocks as when 1st loaded.         //
   sti();                               // interrupts back on.
   BSDEBUG(bsdebugvar,32);
   acs_cls();                           // Clear CRT on 10MENU versions.
   BSDEBUG(bsdebugvar,33);
   if(emm_load_flag && emm_use_flag)
      { BSDEBUG(bsdebugvar,34);
        ems_close(); };                 // Deallocate any EMS handle used.
   BSDEBUG(bsdebugvar,35);
   finish(trans_elevel(retcode));       // Return AutoCAD errorlevel.
   BSDEBUG(bsdebugvar,36);
};