home *** CD-ROM | disk | FTP | other *** search
/ Between Heaven & Hell 2 / BetweenHeavenHell.cdr / 300 / 216 / io20.inc < prev    next >
Text File  |  1986-05-02  |  22KB  |  661 lines

  1. { IO20.INC -- Global I/O procedures to include in programs generally
  2.   Version 2.0 includes prev_page and next_page, changes where pause text
  3.   is displayed -- WPM -- 2/26/86.
  4.   Cosmetic improvements -- 4/16/86 }
  5.  
  6. { ------------------------------------------------------------ }
  7.  
  8. const
  9.     prev_fld  = $0B ;  { ^K -- up_arrow on Kaypro II '83 }
  10.     next_fld  = $0A ;  { ^J -- linefeed, down_arrow }
  11.     backspace = $08 ;  { ^H -- Backspace key }
  12.     del_fld   = $19 ;  { ^Y }
  13.     prev_page = $12 ;  { ^R }
  14.     next_page = $03 ;  { ^C }
  15.     escape    = $1B ;
  16.     carr_rtn  = $0D ;
  17.     del       = $7F ;
  18.     filler    = $2E ;  { . }
  19.  
  20. type
  21.     str_type = string[80] ;
  22.  
  23.     intset = set of $00 .. $ff ;
  24.  
  25. const  { Turbo typed constants -- initialized variables }
  26.     terminating : intset = [carr_rtn, next_fld, prev_fld, next_page,
  27.                             prev_page, escape] ;
  28.     adjusting   : intset = [backspace, del_fld, del] ;
  29.  
  30. var
  31.     fld, scrn   : integer ; {For field & screen cursor control}
  32.  
  33. { ------------------------------------------------------------ }
  34.  
  35. { procedure gotoxy (col,row) ; -- Built-in proc in Turbo to place
  36.   cursor on screen.  Upper left is (1,1) not (0,0)! }
  37.  
  38. { procedure clrscr ; -- Built-in proc in Turbo to clear screen. }
  39.  
  40. { procedure clreol ; -- built-in proc in Turbo to clear to end of line }
  41.  
  42. { ------------------------------------------------------------ }
  43.  
  44. procedure clrline (col,row : integer) ;
  45.     begin
  46.         gotoxy (col,row) ;
  47.         clreol
  48.     end ;
  49.  
  50. { ------------------------------------------------------------ }
  51.  
  52. procedure clreos ;
  53.     begin
  54.         write (chr($17))   {Clear to end of screen on Kaypro & ADM-3A}
  55.     end ;
  56.  
  57. { ------------------------------------------------------------ }
  58.  
  59. procedure beep ;
  60.     begin
  61.         write (chr(7))
  62.     end ;
  63.  
  64. { ------------------------------------------------------------ }
  65.  
  66. procedure do_fld_ctl (key : integer) ;
  67.   { Adjusts global FLD based on value of key, the ordinal value of last key pressed }
  68.   { global
  69.         fld : integer -- for field cursor control }
  70.     begin
  71.         case key of
  72.           carr_rtn, next_fld : fld := succ(fld) ;
  73.           prev_fld           : fld := pred(fld) ;
  74.           next_page          : fld := 999 ;
  75.           prev_page          : fld := -999 ;
  76.           escape             : fld := maxint ;
  77.         end  { case }
  78.     end ;  { proc do_fld_ctl }
  79.  
  80. { ------------------------------------------------------------ }
  81.  
  82. procedure do_scrn_ctl ;
  83.   { Checks value of FLD and adjusts value of SCRN accordingly }
  84.   { Global
  85.         fld, scrn : integer -- For field and screen cursor control }
  86.     begin
  87.         if fld < 1 then
  88.                 scrn := pred(scrn)
  89.         else if fld = maxint then
  90.                 scrn := maxint
  91.         else
  92.                 scrn := succ(scrn)
  93.     end ;
  94.  
  95. { ------------------------------------------------------------ }
  96.  
  97. procedure write_str (st:str_type ; col,row:integer) ;
  98.     begin
  99.         gotoxy (col,row) ;
  100.         write (st)
  101.     end ;
  102.  
  103. { ------------------------------------------------------------ }
  104.  
  105. procedure write_int (int:integer ; width,col,row:integer) ;
  106.     begin
  107.         gotoxy (col,row) ;
  108.         write (int:width)
  109.     end ;
  110.  
  111. { ------------------------------------------------------------ }
  112.  
  113. procedure write_bool (bool:boolean ; col, row:integer) ;
  114.     begin
  115.         gotoxy (col,row) ;
  116.         if bool then write ('YES') else write ('NO ')
  117.     end ;
  118.  
  119. { ------------------------------------------------------------ }
  120.  
  121. procedure write_real (r:real ; width,frac,col,row:integer) ;
  122.     begin
  123.         gotoxy (col,row) ;
  124.         write (r:width:frac)
  125.     end ;
  126.  
  127. { ------------------------------------------------------------ }
  128.  
  129. { This is for Kaypro CP/M -- comment it out to use IBM }
  130. (*
  131. procedure keyin (var ch:char) ;
  132. { Reads a single character from keyboard without echoing it back.
  133.   Modified to trap WordStar commands, 4/29/85 }
  134.     begin
  135.         read (kbd, ch) ;
  136.         if ch = ^S then
  137.             ch := chr(backspace)
  138.         else if ch = ^E then
  139.             ch := chr(prev_fld)
  140.         else if ch = ^X then
  141.             ch := chr(next_fld)
  142.     end ;
  143. *)
  144. { ------------------------------------------------------------ }
  145.  
  146. { This is for IBM PC-DOS -- comment it out for CP/M }
  147.  
  148. procedure keyin (var ch:char) ;
  149. { Reads a single character from keyboard without echoing it back.
  150.   Maps function key scan codes to single keyboard keys.
  151.   Modified for IBM -- from Turbo 3.0 manual, page 360 -- 5/29/85
  152.   Modified for IO20 -- 2/26/86 }
  153.  
  154.     var
  155.         func : boolean ;     { Whether function key or not }
  156.            c : char ;        { Character read }
  157.          key : integer ;     { ORD of character returned }
  158.  
  159.     begin
  160.         func := false ;
  161.         read (kbd,c) ;                       { Get first char }
  162.         if  (ord(c) = escape)                { If there is }
  163.         and keypressed then                  { a second ... }
  164.           begin
  165.             read (kbd,c) ;                   { Get 2nd char }
  166.             func := true
  167.           end ;
  168.         key := ord(c) ;
  169.  
  170.         if func then                         { Translate func. keys }
  171.             case key of
  172.               61,72 : key := prev_fld ;   { F3, up-arrow }
  173.               62,80 : key := next_fld ;   { F4, down-arrow }
  174.               65,73 : key := prev_page ;  { F7, PgUp }
  175.               66,81 : key := next_page ;  { F8, PgDn }
  176.               59,83,75 : key := backspace ;  { F1, DEL, left-arrow }
  177.               60    : key := del_fld ;    { F2 }
  178.             else      key := 00 ;
  179.             end  { case }
  180.         else  { not a function key }
  181.             case key of
  182.               $13   : key := backspace ;  { ^S -- Like WordStar }
  183.               $05   : key := prev_fld ;   { ^E }
  184.               $18   : key := next_fld ;   { ^X }
  185.             end ;  { case }
  186.  
  187.         ch := chr(key)                       { finally, return the character }
  188.     end ;
  189.  
  190. { ------------------------------------------------------------ }
  191.  
  192. function purgech (instr : str_type ; inchar : char) : str_type ;
  193.     {Purges all instances of the character from the string}
  194.     var
  195.         n      : integer ;  {Loop counter}
  196.         outstr : str_type ; {Result string}
  197.  
  198.     begin
  199.         outstr := '' ;
  200.         for n := 1 to length (instr) do
  201.                 if not (instr[n] = inchar) then
  202.                         outstr := concat (outstr, instr[n]) ;
  203.         purgech := outstr
  204.     end ;
  205.  
  206. { ------------------------------------------------------------ }
  207.  
  208. function stripch (instr:str_type ; inchar:char) : str_type ;
  209.     {Strips leading instances of the character from the string}
  210.     begin
  211.         while not (length(instr) = 0)
  212.         and (instr[1] = inchar) do
  213.                 delete (instr, 1, 1) ;
  214.         stripch := instr
  215.     end ;
  216.  
  217. { ------------------------------------------------------------ }
  218.  
  219. function chopch (instr:str_type ; inchar:char) : str_type ;
  220.     {Chops trailing instances of the character from the string}
  221.     begin
  222.         while not (length(instr) = 0)
  223.         and (instr[length(instr)] = inchar) do
  224.                 delete (instr, length(instr), 1) ;
  225.         chopch := instr
  226.     end ;
  227.  
  228. { ------------------------------------------------------------ }
  229.  
  230. procedure adjust_str (var st : str_type ; key, maxlen, col, row : integer ) ;
  231.   { deletes a character or the whole entry }
  232.     var
  233.         i : integer ;
  234.     begin
  235.       case key of
  236.         del_fld   : begin
  237.                       st := '' ;
  238.                       gotoxy (col, row) ;
  239.                       for i := 1 to maxlen do
  240.                           write (chr(filler)) ;
  241.                       gotoxy (col, row)
  242.                     end ;
  243.         backspace,
  244.         del       : if length(st) = 0 then
  245.                         beep
  246.                     else
  247.                       begin
  248.                         write (chr(backspace), chr(filler), chr(backspace)) ;
  249.                         delete (st, length(st), 1)
  250.                       end
  251.       end  { case }
  252.     end ; { proc adjust_str }
  253.  
  254. { ------------------------------------------------------------ }
  255.  
  256. procedure read_str (var st:str_type ; maxlen, col, row:integer) ;
  257.  
  258.   { Read String.  This procedure gets input from the keyboard one
  259.     character at a time and edits on the fly, rejecting invalid
  260.     characters.  COL and ROW tell where to begin the data input
  261.     field, and MAXLEN is the maximum length of the string to be
  262.     returned. }
  263.  
  264.     var
  265.         ch          : char ;
  266.         i,key       : integer ;
  267.  
  268.     procedure add_to_str ;
  269.         begin
  270.             if length(st) = maxlen then
  271.                     beep
  272.             else
  273.                 begin
  274.                     st  := concat(st, ch) ;     {concatenate char. onto str.}
  275.                     write (ch)
  276.                 end
  277.         end ; { proc add_to_str }
  278.  
  279.     begin {--- read_str ---}
  280.         write_str (st, col, row) ;
  281.         for i := (length(st)+1) to maxlen do
  282.                 write (chr(filler)) ;
  283.         gotoxy ((col + length(st)), row) ;
  284.         repeat
  285.             keyin (ch) ;
  286.             key := ord(ch) ;
  287.             if key in [$20 .. $7e] then
  288.                 add_to_str
  289.             else if key in adjusting then
  290.                 adjust_str (st,key,maxlen,col,row)
  291.             else if key in terminating then
  292.                 do_fld_ctl (key)
  293.             else
  294.               beep ;
  295.         until key in terminating ;
  296.         write ('':maxlen - length(st))
  297. end ; { proc read_str }
  298.  
  299. { ------------------------------------------------------------ }
  300.  
  301. procedure read_int (var int:integer ; maxlen, col, row:integer) ;
  302.  
  303.   { Read Integer.  This procedure gets input from the keyboard
  304.     one character at a time and edits on the fly, rejecting
  305.     invalid characters.  COL and ROW tell where to begin the data
  306.     input field, and MAXLEN is the maximum length of the integer
  307.     to be returned. }
  308.  
  309.     var
  310.         ch          : char ;
  311.         i,key       : integer ;
  312.         st          : string[5] ;
  313.         maxst       : string[5] ;
  314.         code        : integer ;
  315.  
  316.     procedure add_to_str ;
  317.         begin
  318.             if length(st) = maxlen then
  319.                     beep
  320.             else
  321.                 begin
  322.                     st  := concat(st, ch) ;     {concatenate char. onto str.}
  323.                     write (ch)
  324.                 end
  325.         end ; { proc add_to_str }
  326.  
  327.     begin {--- read_int ---}
  328.         str (maxint:5, maxst) ;                    {Make integer into string}
  329.         str (int:maxlen, st) ;
  330.         st := purgech (st, ' ') ;
  331.         st := stripch (st, '0') ;
  332.         write_str (st, col, row) ;
  333.         for i := (length(st)+1) to maxlen do
  334.                 write (chr(filler)) ;
  335.         gotoxy ((col + length(st)), row) ;
  336.         repeat
  337.             keyin (ch) ;
  338.             key := ord(ch) ;
  339.             if key = $2d then                 { minus sign }
  340.               begin
  341.                 if  length(st) = 0 then
  342.                     add_to_str
  343.                 end
  344.             else if key in [$30 .. $39] then  {digits 0 - 9}
  345.               begin
  346.                 add_to_str ;
  347.                 if (length(st) = 5)
  348.                 and (st > maxst) then
  349.                     adjust_str (st,del,maxlen,col,row)
  350.               end
  351.             else if key in adjusting then
  352.                 adjust_str (st,key,maxlen,col,row)
  353.             else if key in terminating then
  354.                 do_fld_ctl (key)
  355.             else
  356.               beep ;
  357.         until key in terminating ;
  358.  
  359.         if st = '' then
  360.             begin
  361.                 int := 0 ;
  362.                 code := 0
  363.             end
  364.         else
  365.                 val (st, int, code) ;              {Make string into integer}
  366.         gotoxy (col, row) ;
  367.         if code = 0 then  {Conversion worked OK}
  368.                 write (int:maxlen)
  369.         else
  370.             begin
  371.                 write ('** CONVERSION ERROR ', code) ;
  372.                 halt
  373.             end
  374. end ; { proc read_int }
  375.  
  376. { ------------------------------------------------------------ }
  377.  
  378. function equal (r1,r2 : real) : boolean ;
  379.   { tests functional equality of two real numbers -- 4/30/85 }
  380.     begin
  381.         equal := abs(r1 - r2) < 1.0e-5
  382.     end ;  { function equal }
  383.  
  384. { ------------------------------------------------------------ }
  385.  
  386. function greater (r1,r2 : real) : boolean ;
  387.   { tests functional inequality of two real numbers -- 5/1/85 }
  388.     begin
  389.         greater := (r1 - r2) > 1.0e-5
  390.     end ;  { function greater }
  391.  
  392. { ------------------------------------------------------------ }
  393.  
  394. procedure read_real (var r:real ; maxlen,frac,col,row:integer) ;
  395.  
  396.   { Read Real.  This procedure gets input from the keyboard
  397.     one character at a time and edits on the fly, rejecting
  398.     invalid characters.  COL and ROW tell where to begin the data
  399.     input field; MAXLEN is the maximum length of the string
  400.     representation of the real number, including sign and decimal
  401.     point; FRAC is the fractional part, the number of digits to
  402.     right of the decimal point.
  403.  
  404.     Note -- In Turbo the maximum number of significant digits in
  405.     decimal (not scientific) representation is 11.  It is the
  406.     programmer's responsibility to limit input and computed output
  407.     to 11 significant digits.  }
  408.  
  409.     var
  410.         ch          : char ;    {Input character}
  411.         i,key       : integer ; {Loop control ; ORD of CH}
  412.         st          : string[13] ; {String representation of real number}
  413.         code        : integer ; {Result of VAL conversion}
  414.         rlen        : integer ; {Current length of ST to right of dec. pt.}
  415.         llen        : integer ; {Current length to left, including dec. pt.}
  416.         maxl        : integer ; {Max allowable to left, including dec. pt.}
  417.  
  418.     procedure compute_length ;
  419.         begin
  420.             if pos ('.', st) = 0 then     { If no dec. pt. ... }
  421.               begin
  422.                 llen := length(st) ;      {the whole string is Left}
  423.                 rlen := 0                 {and none is Right}
  424.               end
  425.             else    {There is a decimal point ...}
  426.               begin
  427.                 llen := pos ('.', st) ;   {Left is all up to dec. pt.}
  428.                 rlen := length(st) - llen {Right is the rest}
  429.               end
  430.         end ; { proc compute_length }
  431.  
  432.     procedure add_to_str ;
  433.         procedure add_it ;
  434.             begin
  435.                 st  := concat(st, ch) ;
  436.                 write (ch)
  437.             end ;
  438.         begin { add_to_str }
  439.             if ch = '.' then      { Decimal point: if not one already, add it }
  440.               begin
  441.                 if pos('.', st) = 0 then
  442.                     add_it
  443.                 else
  444.                     beep
  445.               end
  446.                                   { else it's not a decimal point }
  447.             else if pos('.',st) = 0 then
  448.             { There's no dec pt in string, so digit goes on left. }
  449.               begin
  450.                 if llen = (maxl - 1) then
  451.                     beep  { Only a dec pt is allowed in pos MAXL }
  452.                 else
  453.                     add_it
  454.               end
  455.             else  { There is a dec pt in string, so digit goes on right }
  456.               begin
  457.                 if rlen = frac then
  458.                     beep
  459.                 else
  460.                     add_it
  461.               end
  462.         end ; { proc add_to_str }
  463.  
  464.     begin {--- read_real ---}
  465.                               {Initialize}
  466.         maxl  := maxlen - frac ;
  467.                               {Set up string representation of real and }
  468.                               {determine length of left & right portions}
  469.         str(r:maxlen:frac,st) ;           {Make real into string}
  470.         st := purgech (st, ' ') ;         {Purge all blanks}
  471.         st := stripch (st, '0') ;         {Strip leading zeroes}
  472.         if not (pos('.', st) = 0) then    {If there is a dec. pt ... }
  473.             begin
  474.                 st := chopch (st, '0') ;  {Chop trailing zeroes}
  475.                 st := chopch (st, '.')    {and trailing dec. pt.}
  476.             end ;
  477.  
  478.                               {Write string on console}
  479.         write_str (st, col, row) ;
  480.         for i := (length(st)+1) to maxlen do
  481.                 write (chr(filler)) ;
  482.         gotoxy ((col + length(st)), row) ;
  483.  
  484.                               {Get input a character at a time & edit it}
  485.         repeat
  486.                 compute_length ;
  487.                 keyin (ch) ;
  488.                 key := ord(ch) ;
  489.                 if ch = '-' then
  490.                   begin
  491.                     if length(st) = 0 then
  492.                         add_to_str
  493.                     else
  494.                         beep
  495.                   end
  496.                 else if (ch = '.')
  497.                      or (ch in ['0' .. '9']) then
  498.                     add_to_str
  499.                 else if key in adjusting then
  500.                     adjust_str (st,key,maxlen,col,row)
  501.                 else if key in terminating then
  502.                     do_fld_ctl (key)
  503.                 else
  504.                     beep
  505.         until key in terminating ;
  506.  
  507.                               {Done getting input, now convert back to real}
  508.         if (st = '')                             {If null string ... }
  509.         or (st = '.')
  510.         or (st = '-')
  511.         or (st = '-.') then
  512.             begin
  513.                 r := 0.0 ;                       {Make real zero}
  514.                 code := 0
  515.             end
  516.         else    {Not a null string}
  517.                 val (st, r, code) ;              {Make string into real}
  518.         gotoxy (col, row) ;
  519.         if code = 0 then  {Conversion worked OK}
  520.                 write (r:maxlen:frac)            {Write the real on screen}
  521.         else
  522.             begin
  523.                 write ('** CONVERSION ERROR ', code) ;
  524.                 halt
  525.             end
  526. end ; { proc read_real }
  527.  
  528. { ------------------------------------------------------------ }
  529.  
  530. procedure read_yn (var bool:boolean; col,row:integer) ;
  531.   { Inputs "Y" OR "N" to boolean at column and row specified,
  532.     prints "YES" or "NO."
  533.  
  534.     Note -- use this when the screen control will not return
  535.     to the question and the boolean IS NOT defined before the
  536.     user answers the question.  Does not affect global FLD. }
  537.  
  538.     var ch:char ;
  539.     begin
  540.         gotoxy (col,row) ;
  541.         write ('   ') ;
  542.         gotoxy (col,row) ;
  543.         repeat
  544.                 keyin (ch)
  545.         until (ch in ['Y', 'y', 'N', 'n']) ;
  546.         if (ch = 'Y') or (ch = 'y') then
  547.             begin
  548.                 write ('YES') ;
  549.                 bool := true
  550.             end
  551.         else
  552.             begin
  553.                 write ('NO ') ;
  554.                 bool := false
  555.             end
  556.     end ; { proc read_yn }
  557.  
  558. { ------------------------------------------------------------ }
  559.  
  560. procedure read_bool (var bool:boolean; col,row:integer) ;
  561.   { Displays boolean at column and row specified, inputs "Y"
  562.     or "N" to set new value of boolean, prints "YES" or "NO."
  563.  
  564.     Note -- use this when the screen control may return to the
  565.     question and the boolean IS defined before the user answers
  566.     the question.  Does affect global FLD. }
  567.  
  568.     var
  569.         ch         : char ;
  570.         key        : integer ;
  571.  
  572.     begin
  573.         write_bool (bool, col, row) ;
  574.         gotoxy (col, row) ;
  575.         repeat
  576.             keyin (ch) ;
  577.             key := ord(ch) ;
  578.             if key in [$59, $79] then           { 'Y', 'y' }
  579.                 begin
  580.                     bool := true ;
  581.                     key := next_fld ;
  582.                     do_fld_ctl(key)
  583.                 end
  584.             else if key in [$4E, $6E] then      { 'N', 'n' }
  585.                 begin
  586.                     bool := false ;
  587.                     key := next_fld ;
  588.                     do_fld_ctl(key)
  589.                 end
  590.             else if key in terminating then
  591.                 do_fld_ctl(key)
  592.             else
  593.                 beep ;
  594.         until key in terminating ;
  595.         write_bool (bool, col, row)
  596.     end ; { proc read_bool }
  597.  
  598. { ------------------------------------------------------------ }
  599.  
  600. procedure pause ;
  601.     {Prints message on bottom line, waits for user response}
  602.     var
  603.         ch   : char ;
  604.         key : integer ;
  605.     begin
  606.         clrline (1,24) ;
  607.         write_str ('PRESS SPACE BAR TO CONTINUE OR UP-ARROW TO GO BACK',14,24) ;
  608.         repeat
  609.                 keyin (ch) ;
  610.                 key := ord(ch) ;
  611.                 case key of
  612.                   $20      : fld := succ(fld) ;
  613.                   prev_fld : fld := pred(fld) ;
  614.                   prev_page : fld := -999 ;
  615.                   escape   : fld := maxint ;
  616.                 end ;
  617.         until key in [$20, prev_fld, prev_page, escape] ;
  618.         clrline (1,24)
  619.     end ; { proc pause }
  620.  
  621. { ------------------------------------------------------------ }
  622.  
  623. procedure hard_pause ;
  624.   { Like Pause, but only accepts space bar or Escape and only goes forward }
  625.     var
  626.         ch   : char ;
  627.         key : integer ;
  628.     begin
  629.         clrline (1,24) ;
  630.         write_str ('PRESS SPACE BAR TO CONTINUE',26,24) ;
  631.         repeat
  632.                 keyin (ch) ;
  633.                 key := ord(ch) ;
  634.                 case key of
  635.                   $20      : fld := succ(fld) ;
  636.                   escape   : fld := maxint ;
  637.                 end ;
  638.         until key in [$20, escape] ;
  639.         clrline (1,24)
  640.     end ; { proc hard_pause }
  641.  
  642. { ------------------------------------------------------------ }
  643.  
  644. procedure show_msg (msg : str_type) ;
  645.   { Beeps, displays message centered on line 23, pauses }
  646.  
  647.     var
  648.         savefld : integer ;
  649.  
  650.     begin
  651.         savefld := fld ;
  652.         beep ;
  653.         clrline (1,23) ;
  654.         write_str (msg,((80-length(msg)) div 2),23) ;
  655.         hard_pause ;
  656.         clrline (1,23) ;
  657.         fld := savefld ;
  658.     end ; { proc show_msg }
  659.  
  660. { ----- EOF IO20.INC ----------------------------------------- }
  661.