(*[72457,2131]
RESTRT.PAS                28-Jan-86 4680

    Keywords: MSDOS PCDOS RESTART GOTO JUMP RESET INCLUDE

    This snippet demonstrates a technique to restart your Turbo program from
    any scope level. Instead of exiting out of multiple procedures by setting
    flags, this allows you to jump in one step to any desired location in the
    main block. Holds the seeds for a general purpose inter-procedure GOTO
    statement, or various exception handling mechanisms.
*)

{
Demonstrates the capability to restart a program from any place
in the program.

Call the procedure StoreRestartPoint from the main block of the
program after executing whatever initialization code is desired.
Subsequent restarts will return to the point immediately after
the call to StoreRestartPoint.

Whenever you would like to restart the program, call the
procedure RestartProgram. This will return you to the point
saved by StoreRestartPoint, and will restore the stack space
to what it was originally. Note that RestartProgram can be
called at any nesting level (that's the good part!).

This capability supports multiple code segment programs
generated by BIGTURBO, and allows restarts from any code segment.
In this case, StoreRestartPoint and RestartProgram should be exported
to all modules. Alternatively, they can be implemented in all modules
by incorporating their source code in the program's .GLO file.

It would be straightforward to extend this concept to multiple
restart points, and to allow restart points to reside in procedures
rather than just within the main block. If this is done, it would
effectively extend Turbo Pascal to support interblock GOTOs. Anyone
needing this feature is invited to GO FOR IT. I would appreciate
hearing about it if you make it work.

written 1/25/86, Kim Kokkonen, TurboPower Software.
telephone 408-378-3672. Compuserve 72457,2131.
}

PROGRAM demo;
  {-demonstrate the ability to jump to a restart point in the program}

  {**************include the following in your program********************}

VAR
  {store the registers to restore on a reset jump - MUST BE GLOBAL VARIABLES}
  restart_address : ^Integer;
  restart_sp : Integer;

  PROCEDURE StoreRestartPoint;
    {-store those registers needed for a return to the main reset point}
    {CALL ONLY FROM THE MAIN BLOCK OF YOUR PROGRAM}
  BEGIN
    INLINE(
      $BE/restart_address/    {MOV    SI,offset(restart_address)}
      $8C/$C8/                {MOV    AX,CS}
      $89/$44/$02/            {MOV    [SI+02],AX}
      $8B/$46/$02/            {MOV    AX,[BP+02]}
      $89/$04/                {MOV    [SI],AX}
      $8B/$C4/                {MOV    AX,SP}
      $05/$06/$00/            {ADD    AX,0006}
      $A3/restart_sp          {MOV    restart_sp,AX}
      );
  END;                        {StoreRestartPoint}

  PROCEDURE RestartProgram;
    {-restore the stack(s) and jump to the stored Restart point}
  BEGIN
    {BIGTURBO stack pointer - activate if BIGTURBO program}
    {LocalStackPtr:=MaxStackSize;}
    INLINE(
      $A1/restart_sp/         {MOV    AX,restart_sp}
      $8B/$E0/                {MOV    SP,AX}
      $8B/$EC/                {MOV    BP,SP}
      $FF/$2E/restart_address {JMP    FAR restart_address}
      );
  END;                        {RestartProgram}

  {************************demonstration follows*****************************}

VAR
  i : Integer;
  ch : Char;

  PROCEDURE Dummy;

    PROCEDURE NestedDummy;
    BEGIN
      WriteLn('in nested dummy');
      Write('press a key to restart... ');
      Read(Kbd, ch);
      WriteLn;
      WriteLn('restarting program from nested dummy');
      RestartProgram;
    END;                      {NestedDummy}

  BEGIN
    WriteLn('in dummy');
    WriteLn('choose from menu: ');
    WriteLn('  1.run nested dummy procedure');
    WriteLn('  2.exit dummy normally');
    WriteLn('  3.restart');
    Write('Enter choice: ');
    REPEAT
      Read(Kbd, ch);
    UNTIL (ch IN ['1', '2', '3']);
    WriteLn(ch);
    CASE ch OF
      '1' : NestedDummy;
      '3' : RestartProgram;
    END;
    WriteLn('normal dummy exit');
  END;                        {Dummy}

BEGIN
  WriteLn('Entered main block');
  {put any desired initialization code here}

  WriteLn('storing restart point');
  StoreRestartPoint;
  WriteLn('after restart point');
  WriteLn('choose from menu: ');
  WriteLn('  1.run dummy procedure');
  WriteLn('  2.write some integers');
  WriteLn('  3.restart');
  WriteLn('  4.terminate');
  Write('Enter choice: ');
  REPEAT
    Read(Kbd, ch);
  UNTIL (ch IN ['1', '2', '3', '4']);
  WriteLn(ch);
  CASE ch OF
    '1' : Dummy;
    '2' : BEGIN
            FOR i := 1 TO 10 DO WriteLn(i);
            Write('press a key to restart... ');
            Read(Kbd, ch);
            WriteLn;
            WriteLn('restarting program');
            RestartProgram;
          END;
    '3' : BEGIN
            WriteLn('restarting program');
            RestartProgram;
          END;
    '4' : ;
  END;
  WriteLn('normal program exit');

END.
