home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / FIBMCM.ZIP / SCRN_MGR.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1989-05-09  |  27.6 KB  |  861 lines

  1. {$UNDEF MEMORY_METER} unit SCRN_MGR;
  2.   (* Various utility functions for dealing with strings and a timer,
  3.    together so that time spent waiting for a user response is not
  4.    charged to the executing program. *)
  5.  
  6.   interface
  7.     uses
  8.       DOS (* dirstr, extstr, FSplit, GetTime, namestr, pathstr *);
  9.  
  10.     const
  11.       nullstring = '';
  12.  
  13.       DOWN_ARROW_KEY  = #128;
  14.       END_KEY         = #129;
  15.       LEFT_ARROW_KEY  = #130;
  16.       HOME_KEY        = #131;
  17.       PAGE_DOWN_KEY   = #132;
  18.       PAGE_UP_KEY     = #133;
  19.       RIGHT_ARROW_KEY = #134;
  20.       UP_ARROW_KEY    = #135;
  21.  
  22.     type
  23.       ch_set = set of char;
  24.  
  25.       color_scheme = record
  26.         FOREGROUND, BACKGROUND: byte
  27.         end (* color_scheme *);
  28.       
  29.     var
  30.       OLD_SCHEME (* on entry to program           *): color_scheme;
  31.       DEBUG      (* controls loquacity everywhere *): integer;
  32.  
  33.     procedure BEEP;
  34.     function EQUAL(var STRUCT1, STRUCT2; SIZE: word): boolean;
  35.     procedure ERROR_EXIT(S: string);
  36.     function FILE_EXISTS(FNAME: pathstr): boolean;
  37.     function GET_CHAR(ACCEPTABLE: ch_set): char;
  38.     procedure HOLD_TIMER;
  39.     procedure IGNORE_Q(LEGEND: string);
  40.     procedure INIT_SCRN_MGR;
  41.     procedure LOUD_WRITE(S: string);
  42.     procedure OUT_OF_MEMORY;
  43.     function OWN_PATH: pathstr;
  44.     function OWN_TITLE: pathstr;
  45.     procedure PAUSE;
  46.     function POS_INT_VALUE(S: string): integer;
  47.     procedure READ_STRING(LEGEND: string; var S: string);
  48.     function READ_TIMER: longint;
  49.     procedure REWRITE_STRING(PROMPT, REPLACED: string);
  50.     procedure RESUME_TIMER;
  51.     function STR_FN(N: longint): string;
  52.     function YES: boolean;
  53.     procedure ZERO_TIMER;
  54.  
  55.       (* eject *)
  56.   implementation
  57.     uses
  58.       CRT (* Black, ClrEol, ClrScr, Delay, GotoXY, LightGray, NoSound,
  59.                ReadKey, Sound, TextAttr, TextBackground, TextColor, WhereX,
  60.                WhereY, White, WindMax, WindMin *);
  61.  
  62.     const
  63.       BACKSLASH  = '\';
  64.       BLANK      = ' ';
  65.       COLON      = ':';
  66.       DOWN_ARROW = #25;
  67.       ESCAPE     = #27;
  68.       HORIZONTAL = #196;
  69.       L_CORNER   = #218;
  70.       LPAR       = '(';
  71.       R_CORNER   = #191;
  72.       RPAR       = ')';
  73.       SHARP      = '#';
  74.       T_PIECE    = #194;
  75.       VERTICAL   = #179;
  76.  
  77.       DB_TRIGGER =  5 (* speak when DEBUG mod this is 1 *);
  78.       MIDNIGHT = 86400;
  79.       
  80.       TEST_PATTERN = 314159265;
  81.       VERSION_AT_COMPILE = 420505;
  82.       
  83.     type
  84.       color_record = record
  85.         VERSION_AT_RUN: longint;
  86.         LOUD_SCHEME, NORMAL_SCHEME: color_scheme;
  87.         BEEP_DURATION, BEEP_FREQUENCY: word
  88.         end (* color_record *);
  89.           
  90.     var
  91.       INITIALIZED    (* not twice                          *): boolean;
  92.       COLOR_OPTIONS  (* set in INIT_SCRN_MGR               *): color_record;
  93.       REWRITE_FROM_X (* from READ_STRING to REWRITE_STRING *),
  94.       REWRITE_FROM_Y (* from READ_STRING to REWRITE_STRING *): integer;
  95.       LAST_ZERO_TIME (* clock value, last time we looked   *),
  96.       TIME_PAST      (* time accumulated before timeout    *): longint;
  97.       SAVE_EXIT      (* for the great exit chain           *): pointer;
  98.       {$IFDEF MEMORY_METER}
  99.       RUNNER_SEG     (* MEM subscript for heap-use test    *): word;
  100.       {$ENDIF}
  101.     
  102.     procedure SET_COLOR_SCHEME(SCHEME: color_scheme); forward;
  103.     function TIME_NOW: longint;                       forward;
  104.  
  105.     procedure BEEP;
  106.       (* avoid irritating use of BEL character *)
  107.  
  108.       begin (* BEEP *)
  109.         with COLOR_OPTIONS do
  110.           begin (* with *)
  111.             Sound(BEEP_FREQUENCY);
  112.             Delay(BEEP_DURATION);
  113.             NoSound
  114.           end   (* with *)
  115.       end   (* BEEP *);
  116.  
  117.     function ELAPSED_TIME: longint;
  118.       (* returns time since LAST_ZERO_TIME *)
  119.  
  120.       var
  121.         MY_TIME: longint;
  122.  
  123.       begin (* ELAPSED_TIME *)
  124.         MY_TIME := TIME_NOW - LAST_ZERO_TIME;
  125.         if MY_TIME < 0 then
  126.           MY_TIME := MY_TIME + MIDNIGHT;
  127.         ELAPSED_TIME := MY_TIME
  128.       end   (* ELAPSED_TIME *);
  129.  
  130.       (* eject *)
  131.     {$F+}
  132.     procedure EPILOGUE;
  133.     {$F-}
  134.       (* Part of the great exit chain *)
  135.       
  136.       var
  137.         IN_PI_BLOCK: boolean;
  138.         LENGTH_ZENITH, THIS_LENGTH: longint;
  139.         I, RUNNER_SEG: word;
  140.       
  141.       begin (* EPILOGUE *)
  142.         {$IFDEF MEMORY_METER}
  143.           if DEBUG mod DB_TRIGGER = 1 then
  144.             begin (* nondegenerate *)
  145.               I := 0;
  146.               
  147.               while I < sptr do
  148.                 if mem[sseg:I] <> $AA then
  149.                   begin (* found untouched stack *)
  150.                     writeln(I:8, ' bytes of stack space unused.');
  151.                     I := sptr
  152.                   end   (* found untouched stack *)
  153.                 else
  154.                   inc(I);
  155.               
  156.               IN_PI_BLOCK := false;
  157.               LENGTH_ZENITH := 0;
  158.               for RUNNER_SEG := succ(seg(heapptr^)) to pred(seg(freeptr^)) do
  159.                 if (meml[RUNNER_SEG:0] = TEST_PATTERN) and
  160.                    (meml[RUNNER_SEG:4] = TEST_PATTERN) and
  161.                    (meml[RUNNER_SEG:8] = TEST_PATTERN) and
  162.                    (meml[RUNNER_SEG:12] = TEST_PATTERN) then
  163.                   if IN_PI_BLOCK then
  164.                     begin (* extend *)
  165.                       inc(THIS_LENGTH, 16);
  166.                       if THIS_LENGTH > LENGTH_ZENITH then
  167.                         LENGTH_ZENITH := THIS_LENGTH
  168.                     end   (* extend *)
  169.                   else
  170.                     begin (* start *)
  171.                       IN_PI_BLOCK := true;
  172.                       THIS_LENGTH := 16
  173.                     end   (* start *)
  174.                 else
  175.                   IN_PI_BLOCK := false;
  176.               
  177.               writeln(LENGTH_ZENITH:8, ' bytes of heap space unused.')
  178.             end   (* nondegenerate *);
  179.         {$ENDIF}
  180.           
  181.         ExitProc := SAVE_EXIT
  182.       end   (* EPILOGUE *);
  183.       
  184.       (* eject *)
  185.     function EQUAL(var STRUCT1, STRUCT2; SIZE: word): boolean;
  186.       (* Cribbed from Turbo Pascal manual, p. 268 *)
  187.  
  188.       type
  189.         bytes = array[0 .. maxint] of byte;
  190.  
  191.       var
  192.         I: integer;
  193.  
  194.       begin (* EQUAL *)
  195.         I := 0;
  196.         while (I < SIZE) and (bytes(STRUCT1)[I] = bytes(STRUCT2)[I]) do
  197.           inc(I);
  198.         EQUAL := (I = SIZE)
  199.       end   (* EQUAL *);
  200.  
  201.     procedure ERROR_EXIT(S: string);
  202.       (* Write S to console, then die *)
  203.  
  204.       begin (* ERROR_EXIT *)
  205.         if length(S) > 0 then
  206.           begin (* error message *)
  207.             writeln;
  208.             ClrEol;
  209.             LOUD_WRITE(S)
  210.           end   (* error message *);
  211.         PAUSE;
  212.         halt(1)
  213.       end   (* ERROR_EXIT *);
  214.  
  215.     function FILE_EXISTS(FNAME: pathstr): boolean;
  216.       (* No promise that file is of NZ length. *)
  217.  
  218.       var
  219.         F: file;
  220.  
  221.       begin (* FILE_EXISTS *)
  222.         FILE_EXISTS := false;
  223.         if length(FNAME) > 0 then
  224.           begin (* nondegenerate *)
  225.             {$I-}
  226.             assign(F, FNAME);
  227.             reset(F);
  228.             if ioresult = 0 then
  229.               begin (* success *)
  230.                 FILE_EXISTS := true;
  231.                 close(F)
  232.               end   (* success *)
  233.             {$I+}
  234.           end   (* nondegenerate *)
  235.       end   (* FILE_EXISTS *);
  236.  
  237.     function GET_CHAR(ACCEPTABLE: ch_set): char;
  238.       (* Return an upper-case character from ACCEPTABLE, or abort on <esc> *)
  239.  
  240.       var
  241.         CH: char;
  242.  
  243.       begin (* GET_CHAR *)
  244.         repeat (* get a character *)
  245.           HOLD_TIMER;
  246.           CH := upcase(ReadKey);
  247.           case CH of
  248.             #0: case ReadKey of
  249.                   #71: CH := HOME_KEY;
  250.                   #72: CH := UP_ARROW_KEY;
  251.                   #73: CH := PAGE_UP_KEY;
  252.                   #75: CH := LEFT_ARROW_KEY;
  253.                   #77: CH := RIGHT_ARROW_KEY;
  254.                   #79: CH := END_KEY;
  255.                   #80: CH := DOWN_ARROW_KEY;
  256.                   #81: CH := PAGE_DOWN_KEY
  257.                   end (* case on ReadKey *);
  258.             #8: CH := LEFT_ARROW_KEY
  259.             end (* case on CH *);
  260.           RESUME_TIMER
  261.         until  (* get a character *) CH in ACCEPTABLE;
  262.  
  263.         GET_CHAR := CH
  264.       end   (* GET_CHAR *);
  265.  
  266.     {$F+}
  267.     function HEAP_FUNCTION(SIZE: word): integer;
  268.     {$F-}
  269.       (* regain control on heap overflow *)
  270.  
  271.       begin  (* HEAP_FUNCTION *)
  272.         HEAP_FUNCTION := 1
  273.       end    (* HEAP_FUNCTION *);
  274.  
  275.     procedure HOLD_TIMER;
  276.       (* Until a call to RESUME_TIMER, time seen by READ_TIMER will
  277.       not accumulate *)
  278.  
  279.       begin (* HOLD_TIMER *)
  280.         TIME_PAST := TIME_PAST + ELAPSED_TIME
  281.       end   (* HOLD_TIMER *);
  282.  
  283.     procedure IGNORE_Q(LEGEND: string);
  284.       (* Tell user what you are ignoring. *)
  285.       
  286.       var
  287.         SAVED_X: integer;
  288.  
  289.       begin (* IGNORE_Q *)
  290.         SAVED_X := WhereX;
  291.         writeln;
  292.         LOUD_WRITE(LEGEND);
  293.         writeln;
  294.         LOUD_WRITE('Type <space> to continue, <esc> to abort: ');
  295.         if GET_CHAR([BLANK, ESCAPE]) = ESCAPE then
  296.           ERROR_EXIT(nullstring);
  297.          
  298.         GotoXY(1, pred(WhereY));
  299.         ClrEol;
  300.         writeln;
  301.         ClrEol;
  302.         GotoXY(SAVED_X, WhereY-2)
  303.       end   (* IGNORE_Q *);
  304.  
  305.     procedure INIT_SCRN_MGR;
  306.       (* Initialize private variables, effectively starting the clock.
  307.       Set the colors of text and loud text *)
  308.       
  309.       const
  310.         COLOR_FILE_NAME = 'HUES_TO.USE';
  311.       
  312.       var
  313.         COLORS_SET: boolean;
  314.         COLOR_FILE: file of color_record;
  315.       
  316.       procedure CREATE_COLOR_FILE;
  317.         (* Allow user to select colors of normal & loud text *)
  318.  
  319.         const
  320.           INTENSITY = 8;
  321.  
  322.         procedure CHOOSE_BEEP;
  323.           (* Kludge to shorten CREATE_COLOR_FILE *)
  324.           
  325.           var
  326.             CHANGES_MADE: boolean;
  327.             LINE: string;
  328.             NEW_DURATION, NEW_FREQUENCY: word;
  329.           
  330.           begin (* CHOOSE_BEEP *)
  331.             writeln;
  332.             writeln('  (Iterated until you stop making changes)');
  333.  
  334.             with COLOR_OPTIONS do
  335.               repeat (* let user choose beep *)
  336.                 CHANGES_MADE := false;
  337.                 BEEP;
  338.                 LOUD_WRITE('Beep duration in milliseconds ['+
  339.                            STR_FN(BEEP_DURATION) +
  340.                            ']: ');
  341.                 readln(LINE);
  342.                 if length(LINE) > 0 then
  343.                   begin (* suggestion made *)
  344.                     NEW_DURATION := POS_INT_VALUE(LINE);
  345.                     if NEW_DURATION <> BEEP_DURATION then
  346.                       begin (* got one *)
  347.                         BEEP_DURATION := NEW_DURATION;
  348.                         CHANGES_MADE := true
  349.                       end   (* got one *);
  350.                   end   (* suggestion made *);
  351.  
  352.                 BEEP;
  353.                 LOUD_WRITE('Beep frequency in Hertz [' +
  354.                            STR_FN(BEEP_FREQUENCY) +
  355.                            ']: ');
  356.                 readln(LINE);
  357.                 if length(LINE) > 0 then
  358.                   begin (* suggestion made *)
  359.                     NEW_FREQUENCY := POS_INT_VALUE(LINE);
  360.                     if NEW_FREQUENCY <> BEEP_FREQUENCY then
  361.                       begin (* got one *)
  362.                         BEEP_FREQUENCY := NEW_FREQUENCY;
  363.                         CHANGES_MADE := true
  364.                       end   (* got one *)
  365.                   end   (* suggestion made *)
  366.               until  (* let user choose beep *) not CHANGES_MADE
  367.           end   (* CHOOSE_BEEP *);
  368.         
  369.         procedure CHOOSE_COLORS;
  370.           (* Kludge to shorten CREATE_COLOR_FILE *)
  371.           
  372.           const
  373.             SAMPLE_LINE = 15 (* after palette *);
  374.             ASK_LINE    = 18 (* after sample *);
  375.  
  376.           var
  377.             SATISFIED (* no changes *): boolean;
  378.             Y         (* coordinate *): integer;
  379.           
  380.           procedure GET_BYTE(FOREBACK, LEGEND: string;
  381.                              CTX: byte;
  382.                              var VAL: byte);
  383.             (* pursue user *)
  384.         
  385.             var
  386.               LOOKING: boolean;
  387.               LIMIT, TRY: byte;
  388.               LINE: string;
  389.         
  390.             begin (* GET_BYTE *)
  391.               LOOKING := true;
  392.               if FOREBACK = 'fore' then
  393.                 LIMIT := 16
  394.               else
  395.                 LIMIT := 8;
  396.               with COLOR_OPTIONS do
  397.                 while LOOKING do
  398.                   begin (* keep looking *)
  399.                     SET_COLOR_SCHEME(NORMAL_SCHEME);
  400.                     ClrEol;
  401.                     SET_COLOR_SCHEME(LOUD_SCHEME);
  402.                     if length(LEGEND) = 6 then
  403.                       write('  ');
  404.                     write('New ', LEGEND, BLANK, FOREBACK, 'ground [',
  405.                           VAL, ']: ');
  406.                     SET_COLOR_SCHEME(NORMAL_SCHEME);
  407.                     readln(LINE);
  408.                     if length(LINE) = 0 then
  409.                       LOOKING := false
  410.                     else
  411.                       begin (* new offer *)
  412.                         TRY := POS_INT_VALUE(LINE);
  413.                         if (TRY < LIMIT) and (TRY <> CTX) then
  414.                           begin (* got one *)
  415.                             LOOKING := false;
  416.                             if TRY <> VAL then
  417.                               begin (* nondegenerate *)
  418.                                 SATISFIED := false;
  419.                                 VAL := TRY
  420.                               end   (* nondegenerate *)
  421.                           end   (* got one *)
  422.                         else
  423.                           GotoXY(1, pred(WhereY))
  424.                       end   (* new offer *)
  425.                   end   (* keep looking *)
  426.             end   (* GET_BYTE *);
  427.  
  428.           procedure PALETTE;
  429.             (* Menu of colors *)
  430.         
  431.             var
  432.               BKGD (* runner *),
  433.               FGD  (* runner *): byte;
  434.   
  435.             begin (* PALETTE *)
  436.               writeln('        One-time choice of text colors');
  437.               writeln;
  438.               writeln(BLANK, L_CORNER, HORIZONTAL, HORIZONTAL, 'Background');
  439.               write(BLANK, VERTICAL, nullstring:5, L_CORNER);
  440.               for FGD := 1 to 6 do
  441.                 write(HORIZONTAL, HORIZONTAL, HORIZONTAL, T_PIECE);
  442.               write(HORIZONTAL, 'Foreground', T_PIECE);
  443.               for FGD := 10 to 14 do
  444.                 write(HORIZONTAL, HORIZONTAL, HORIZONTAL, T_PIECE);
  445.               writeln(HORIZONTAL, HORIZONTAL, HORIZONTAL, R_CORNER);
  446.               write(BLANK, DOWN_ARROW, BLANK, BLANK);
  447.               for FGD := BLACK to WHITE do
  448.                 write(DOWN_ARROW:4);
  449.               writeln;
  450.               for BKGD := Black to LightGray do
  451.                 begin (* BKGD *)
  452.                   write(BKGD:2, ': ');
  453.                   TextBackground(BKGD);
  454.                   for FGD := Black to White do
  455.                     begin (* FGD *)
  456.                       TextColor(FGD);
  457.                       write(FGD:4)
  458.                     end   (* FGD *);
  459.                   SET_COLOR_SCHEME(OLD_SCHEME);
  460.                   ClrEol;
  461.                   writeln
  462.                 end   (* BKGD *)
  463.             end   (* PALETTE *);
  464.       
  465.           begin (* CHOOSE_COLORS *)
  466.             ClrScr;
  467.             GotoXY(1, 1);
  468.             PALETTE;
  469.  
  470.             with COLOR_OPTIONS do
  471.               repeat (* elicit choice *)
  472.                 SATISFIED := true;
  473.                 GotoXY(1, SAMPLE_LINE);
  474.                 ClrEol;
  475.                 SET_COLOR_SCHEME(NORMAL_SCHEME);
  476.                 with NORMAL_SCHEME do
  477.                   write('            Ordinary text (', FOREGROUND,
  478.                         ' on ', BACKGROUND, ')  ');
  479.                 SET_COLOR_SCHEME(LOUD_SCHEME);
  480.                 with LOUD_SCHEME do
  481.                   writeln('     Urgent text (', FOREGROUND,
  482.                           ' on ', BACKGROUND, RPAR);
  483.  
  484.                 SET_COLOR_SCHEME(NORMAL_SCHEME);
  485.                 for Y := succ(SAMPLE_LINE) to ASK_LINE+3 do
  486.                   begin (* clear old lines *)
  487.                     ClrEol;
  488.                     writeln
  489.                   end   (* clear old lines *);
  490.                 GotoXY(1, pred(ASK_LINE));
  491.                 writeln('  (Iterated until you stop making changes)');
  492.  
  493.                 with NORMAL_SCHEME do
  494.                   begin (* new values *)
  495.                     GET_BYTE('back', 'ordinary', FOREGROUND, BACKGROUND);
  496.                     GET_BYTE('fore', 'ordinary', BACKGROUND, FOREGROUND)
  497.                   end   (* new values *);
  498.                 with LOUD_SCHEME do
  499.                   begin (* new values *)
  500.                     GET_BYTE('back', 'urgent', FOREGROUND, BACKGROUND);
  501.                     GET_BYTE('fore', 'urgent', BACKGROUND, FOREGROUND)
  502.                   end   (* new values *)
  503.               until  (* elicit choice *) SATISFIED
  504.           end   (* CHOOSE_COLORS *);
  505.         
  506.         begin (* CREATE_COLOR_FILE *)
  507.           with COLOR_OPTIONS do
  508.             begin (* with *)
  509.               VERSION_AT_RUN := VERSION_AT_COMPILE;
  510.               NORMAL_SCHEME := OLD_SCHEME;
  511.               LOUD_SCHEME := NORMAL_SCHEME;
  512.               with LOUD_SCHEME do
  513.                 begin (* minimal change *)
  514.                   FOREGROUND := FOREGROUND xor INTENSITY;
  515.                   if FOREGROUND = BACKGROUND then
  516.                     FOREGROUND := succ(FOREGROUND) mod 16
  517.                 end   (* minimal change *);
  518.               BEEP_DURATION := 500;
  519.               BEEP_FREQUENCY := 150;
  520.               
  521.               CHOOSE_COLORS;
  522.               CHOOSE_BEEP;
  523.  
  524.               assign(COLOR_FILE, OWN_PATH + COLOR_FILE_NAME);
  525.               rewrite(COLOR_FILE);
  526.               write(COLOR_FILE, COLOR_OPTIONS);
  527.               close(COLOR_FILE)
  528.             end   (* with *);
  529.         end   (* CREATE_COLOR_FILE *);
  530.         
  531.         (* eject *)
  532.       begin (* INIT_SCRN_MGR *)
  533.         if not INITIALIZED then
  534.           begin (* nondegenerate case *)
  535.             with OLD_SCHEME do
  536.               begin (* colors on entry *)
  537.                 BACKGROUND := (TextAttr shr 4) mod 8;
  538.                 FOREGROUND := TextAttr mod 16
  539.               end   (* colors on entry *);
  540.     
  541.             COLORS_SET := false;
  542.             assign(COLOR_FILE, OWN_PATH + COLOR_FILE_NAME);
  543.             repeat (* seek or create file *)
  544.               {$I-}
  545.               reset(COLOR_FILE);
  546.               if ioresult <> 0 then
  547.                 CREATE_COLOR_FILE
  548.               else if eof(COLOR_FILE) then
  549.                 begin (* short file *)
  550.                   close(COLOR_FILE);
  551.                   CREATE_COLOR_FILE
  552.                 end   (* short file *)
  553.               else
  554.                 with COLOR_OPTIONS do
  555.                   begin (* try to use it *)
  556.                     read(COLOR_FILE, COLOR_OPTIONS);
  557.                     close(COLOR_FILE);
  558.                     if VERSION_AT_RUN <> VERSION_AT_COMPILE then
  559.                       erase(COLOR_FILE)
  560.                     else
  561.                       begin (* looks good *)
  562.                         SET_COLOR_SCHEME(NORMAL_SCHEME);
  563.                         COLORS_SET := true
  564.                       end   (* looks good *)
  565.                   end   (* try to use it *)
  566.               {$I+}
  567.             until  (* seek or create file *) COLORS_SET;
  568.             
  569.             ZERO_TIMER;
  570.             INITIALIZED := true
  571.           end   (* nondegenerate case *)
  572.       end   (* INIT_SCRN_MGR *);
  573.      
  574.     procedure LOUD_WRITE(S: string);
  575.       (* Write the string S to the console, using whatever means of
  576.       emphasis are available. *)
  577.  
  578.       begin (* LOUD_WRITE *)
  579.         with COLOR_OPTIONS do
  580.           begin (* with *)
  581.             SET_COLOR_SCHEME(LOUD_SCHEME);
  582.             write(S);
  583.             SET_COLOR_SCHEME(NORMAL_SCHEME)
  584.           end   (* with *)
  585.       end   (* LOUD_WRITE *);
  586.  
  587.     procedure OUT_OF_MEMORY;
  588.       (* Common exit for various heap-exhausted conditions *)
  589.  
  590.       begin (* OUT_OF_MEMORY *)
  591.         ERROR_EXIT('Out of memory')
  592.       end   (* OUT_OF_MEMORY *);
  593.  
  594.     function OWN_PATH: pathstr;
  595.       (* Return DOS directory in which this .EXE file was found *)
  596.  
  597.       var
  598.         RESULT: dirstr;
  599.         EXT: extstr;
  600.         I: integer;
  601.         NAME: namestr;
  602.  
  603.       begin (* OWN_PATH *)
  604.         FSplit(paramstr(0), RESULT, NAME, EXT);
  605.         OWN_PATH := RESULT
  606.       end   (* OWN_PATH *);
  607.  
  608.       (* eject *)
  609.     function OWN_TITLE: pathstr;
  610.       (* Return name of the executing .EXE file *)
  611.  
  612.       var
  613.         PATH: dirstr;
  614.         EXT: extstr;
  615.         NAME: namestr;
  616.     
  617.       begin (* OWN_TITLE *)
  618.         FSplit(paramstr(0), PATH, NAME, EXT);
  619.         OWN_TITLE := NAME + EXT
  620.       end   (* OWN_TITLE *);
  621.       
  622.     procedure PAUSE;
  623.       (* Make sure user has read the last message *)
  624.  
  625.       begin (* PAUSE *)
  626.         writeln;
  627.         ClrEol;
  628.         while KeyPressed do
  629.           if ReadKey = #0 then
  630.             (* loop will get 2nd portion *);
  631.  
  632.         LOUD_WRITE('Type <space> to continue');
  633.  
  634.         repeat (* wait for <space> *)
  635.         until  (* wait for <space> *) ReadKey = BLANK;
  636.  
  637.         GotoXY(1, WhereY);
  638.         ClrEol
  639.       end   (* PAUSE *);
  640.  
  641.     function POS_INT_VALUE(S: string): integer;
  642.       (* Return the natural number represented by the string S *)
  643.  
  644.       var
  645.         I, RESULT: integer;
  646.         
  647.       begin (* POS_INT_VALUE *)
  648.         RESULT := 0;
  649.         
  650.         for I := 1 to length(S) do
  651.           case S[I] of
  652.             '0' .. '9': if RESULT < maxint div 10 then
  653.                           RESULT := 10 * RESULT + ord(S[I]) - ord('0')
  654.             end (* case on S[I] *);
  655.  
  656.         POS_INT_VALUE := RESULT
  657.       end   (* POS_INT_VALUE *);
  658.       
  659.       (* eject *)
  660.     procedure READ_STRING(LEGEND: string; var S: string);
  661.       (* LOUD_WRITE(LEGEND (or <esc> to abort))
  662.          If ESC received then
  663.            exit(program)
  664.          else
  665.            build S
  666.       *)
  667.       const
  668.         DEL_KEY = #83;
  669.         LEFT_ARROW_KEY = #75;
  670.  
  671.         BS = #8;
  672.         CR = #13;
  673.  
  674.       var
  675.         CH: char;
  676.  
  677.         S_RECORD: record
  678.           case boolean of
  679.             false: (S_STRING: string);
  680.              true: (S_ARRAY: packed array[0 .. 255] of char)
  681.           end (* S_RECORD *);
  682.  
  683.           (* eject *)
  684.       procedure BACKSPACE;
  685.         (* Destructive version of SC_LEFT *)
  686.  
  687.         procedure LEFT;
  688.           (* SC_LEFT, with reverse wraparound if needed *)
  689.  
  690.           begin (* LEFT *)
  691.             if WhereX = 1 then
  692.               GotoXY(succ(lo(WindMax) - lo(WindMin)), WhereY-1)
  693.             else
  694.               GotoXY(WhereX-1, WhereY)
  695.           end   (* LEFT *);
  696.  
  697.         begin (* BACKSPACE *)
  698.           LEFT;
  699.           write(BLANK);
  700.           LEFT;
  701.           with S_RECORD do
  702.             S_ARRAY[0] := pred(S_ARRAY[0])
  703.         end   (* BACKSPACE *);
  704.  
  705.         (* eject *)
  706.       begin (* READ_STRING *)
  707.         REWRITE_FROM_X := WhereX;
  708.         REWRITE_FROM_Y := WhereY;
  709.         LOUD_WRITE(LEGEND + ' (or <esc> to abort): ');
  710.  
  711.         with S_RECORD do
  712.           begin (* with *)
  713.             S_STRING := nullstring;
  714.  
  715.             repeat (* get line *)
  716.               HOLD_TIMER;
  717.               CH := ReadKey;
  718.               RESUME_TIMER;
  719.               
  720.               case CH of
  721.                          #0: begin (* special key *)
  722.                                CH := ReadKey;
  723.                                case CH of
  724.                                         DEL_KEY: while length(S_STRING) > 0 do
  725.                                                    BACKSPACE;
  726.                                  LEFT_ARROW_KEY: if length(S_STRING) > 0 then
  727.                                                    BACKSPACE
  728.                                  end (* case on CH *)
  729.                              end   (* special key *);
  730.                          
  731.                          BS: if length(S_STRING) > 0 then
  732.                                BACKSPACE;
  733.  
  734.                          CR: S := S_STRING;
  735.                          
  736.                      ESCAPE: halt(2);
  737.                 
  738.                 #32 .. #126: if length(S_STRING) < 255 then
  739.                                begin (* extend S *)
  740.                                  S_ARRAY[0] := succ(S_ARRAY[0]);
  741.                                  S_ARRAY[ord(S_ARRAY[0])] := CH;
  742.                                  write(CH)
  743.                                end   (* extend S *)
  744.                 end (* outer case on CH *)
  745.             until  (* get line *) CH = CR
  746.           end   (* with *);
  747.         
  748.         writeln;
  749.         if WhereY = REWRITE_FROM_Y then (* scrolled *)
  750.           dec(REWRITE_FROM_Y)
  751.       end   (* READ_STRING *);
  752.       
  753.     function READ_TIMER: longint;
  754.       (* returns time since last call to ZERO_TIMER in longints *)
  755.       
  756.       begin (* READ_TIMER *)
  757.         READ_TIMER := TIME_PAST + ELAPSED_TIME
  758.       end   (* READ_TIMER *);
  759.     
  760.       (* eject *)
  761.     procedure RESUME_TIMER;
  762.       (* Restart the clock after waiting for keyboard *)
  763.       
  764.       begin (* RESUME_TIMER *)
  765.         LAST_ZERO_TIME := TIME_NOW
  766.       end   (* RESUME_TIMER *);
  767.  
  768.     procedure REWRITE_STRING(PROMPT, REPLACED: string);
  769.       (* Following call to READ_STRING, overwrite offering with interpretation
  770.       *)
  771.       
  772.       begin (* REWRITE_STRING *)
  773.         GotoXY(REWRITE_FROM_X, REWRITE_FROM_Y);
  774.         ClrEol;
  775.         write(PROMPT, ': ', REPLACED)
  776.       end   (* REWRITE_STRING *);
  777.     
  778.     procedure SET_COLOR_SCHEME(SCHEME: color_scheme);
  779.       (* isolate Turbo dependencies *)
  780.       
  781.       begin (* SET_COLOR_SCHEME *)
  782.         TextBackground(SCHEME.BACKGROUND);
  783.         TextColor(SCHEME.FOREGROUND)
  784.       end   (* SET_COLOR_SCHEME *);
  785.     
  786.     function STR_FN(N: longint): string;
  787.       (* function version of STR intrinsic *)
  788.       
  789.       var
  790.         RESULT: string;
  791.       
  792.       begin (* STR_FN *)
  793.         str(N, RESULT);
  794.         STR_FN := RESULT
  795.       end   (* STR_FN *);
  796.     
  797.     function TIME_NOW: longint;
  798.       (* Returns time (seconds since midnight) as longint. *)
  799.        
  800.       var
  801.         HOUR, MINUTE, SECOND, SEC100: word;
  802.  
  803.       begin (* TIME_NOW *)
  804.         GetTime(HOUR, MINUTE, SECOND, SEC100);
  805.         TIME_NOW := 3600*longint(HOUR) + 60*MINUTE + SECOND + (SEC100 div 50)
  806.       end   (* TIME_NOW *);
  807.       
  808.     function YES;
  809.       (* Get Yes or No from the console *)
  810.       
  811.       begin (* YES *)
  812.         case GET_CHAR([ESCAPE, 'Y', 'N']) of
  813.           ESCAPE: ERROR_EXIT(nullstring);
  814.           
  815.              'N': begin (* no *)
  816.                     writeln('No');
  817.                     YES := false
  818.                   end   (* no *);
  819.              
  820.              'Y': begin (* yes *)
  821.                     writeln('Yes');
  822.                     YES := true
  823.                   end   (* yes *)
  824.           end (* case *)
  825.       end   (* YES *);
  826.  
  827.     procedure ZERO_TIMER;
  828.       (* Start timer now *)
  829.       
  830.       begin (* ZERO_TIMER *)
  831.         LAST_ZERO_TIME := TIME_NOW;
  832.         TIME_PAST := 0
  833.       end   (* ZERO_TIMER *);
  834.     
  835.       (* eject *)
  836.     begin (* SCREEN_MGR *)
  837.       DEBUG := 0;
  838.       INITIALIZED := false;
  839.       SAVE_EXIT := ExitProc;
  840.       ExitProc := @EPILOGUE;
  841.       heaperror := @HEAP_FUNCTION;
  842.  
  843.       {$IFDEF MEMORY_METER}
  844.         fillchar(mem[sseg:0], sptr-20, $AA);
  845.         
  846.         for RUNNER_SEG := seg(heapptr^)+3 to seg(freeptr^)-3 do
  847.           begin (* fill with test pattern *)
  848.             meml[RUNNER_SEG:0] := TEST_PATTERN;
  849.             meml[RUNNER_SEG:4] := TEST_PATTERN;
  850.             meml[RUNNER_SEG:8] := TEST_PATTERN;
  851.             meml[RUNNER_SEG:12] := TEST_PATTERN
  852.           end   (* fill with test pattern *)
  853.       {$ENDIF}
  854.     end   (* SCREEN_MGR *) .
  855.  
  856. END
  857. T-------T-------T-------T-------T-------T-------T-------T-------T-------T-------T
  858. $cursor=28167,20;$tag=11112,24;$last=19602,24;a=22378,9;
  859. FTL0R79P5.F0B7
  860.  
  861.