home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / io / io_23 / io23unit.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-03-20  |  36.7 KB  |  1,063 lines

  1. { IO23UNIT.PAS -- Global I/O procedures to include in programs generally
  2.   by Bill Meacham
  3.   Ver 2.0 -- includes prev_page and next_page, changes where pause text
  4.              is displayed -- 2/26/86.
  5.              Cosmetic improvements -- 4/16/86.
  6.   Ver 2.l -- Add function Pad -- 10/12/86.
  7.   Ver 2.2 -- Add ability to move cursor within input line -- 5/24/87.
  8.   Ver 2.3 -- Add proc buzz, error_buzz; add buzzes to read routines.
  9.              Converted to Turbo 4.0 -- 12/2/87
  10.              Converted to a Unit -- 12/2/87
  11.              Fixed bug in ReadReal -- 1/3/88 -- TP4 cannot handle a trailing
  12.              decimal point where TP3 could
  13.              Added home-key and end_key -- 1/24/88
  14.              Fixed bug in Read_Int -- 2/18/88
  15.              Added Read_longint and write_longint -- 3/19/88 }
  16.  
  17. { -------------------------------------------------------------------------- }
  18.  
  19. unit io23unit ;
  20. {$v-}
  21. interface
  22.  
  23. uses
  24.     crt ;
  25.  
  26. const
  27.                        { ASCII values of cursor control keys, like WordStar. }
  28.     null      = $00 ;
  29.     prev_char = $13 ;  { ^S }
  30.     next_char = $04 ;  { ^D }
  31.     home_key  = $01 ;  { ^A }
  32.     end_key   = $06 ;  { ^F }
  33.     prev_fld  = $05 ;  { ^E }
  34.     next_fld  = $18 ;  { ^X }
  35.     prev_page = $12 ;  { ^R }
  36.     next_page = $03 ;  { ^C }
  37.     del_char  = $07 ;  { ^G }
  38.     del_left  = $08 ;  { ^H (Backspace) }
  39.     del_fld   = $19 ;  { ^Y }
  40.     del       = $7F ;  { Delete }
  41.     escape    = $1B ;
  42.     carr_rtn  = $0D ;
  43.     space     = $20 ;
  44.     filler    = $5F ;  { _ }
  45.  
  46. type
  47.     str1      = string[1] ;
  48.     str14     = string[14] ;
  49.     str_type  = string[80] ;
  50.  
  51.     intset = set of $00 .. $FF ;
  52.  
  53. const  { Turbo typed constants -- initialized variables }
  54.     terminating : intset = [carr_rtn,next_fld,prev_fld,escape,next_page,prev_page] ;
  55.     adjusting   : intset = [prev_char,next_char,home_key,end_key,del_char,del_fld,del_left] ;
  56.  
  57. var
  58.     fld, scrn   : integer ; { For field & screen cursor control }
  59.  
  60. procedure clrline (col,row : byte) ;
  61.   { clears to end of line }
  62. procedure beep ;
  63.   { sounds bell }
  64. procedure buzz (pitch,duration : integer) ;
  65.   { makes a sound }
  66. procedure error_buzz ;
  67.   { makes a particular sound }
  68. procedure do_fld_ctl (key : integer) ;
  69.   { Adjusts global FLD based on value of key, ORD of last key pressed }
  70. procedure do_scrn_ctl ;
  71.   { Checks value of FLD and adjusts value of SCRN accordingly }
  72. procedure write_str (st:str_type ; col,row:byte) ;
  73.   { writes a string on screen at column and row specified }
  74. procedure write_int (int:integer ; width,col,row:byte) ;
  75.   { writes an integer }
  76. procedure write_longint (lint:longint ; width,col,row:byte) ;
  77.   { writes a long integer }
  78. procedure set_bool (var bool : boolean) ;
  79.   { sets boolean to undefined, neither true nor false }
  80. function defined (bool : boolean) : boolean ;
  81.   { whether boolean is defined }
  82. procedure write_bool (bool:boolean ; col, row:byte) ;
  83.   { writes a boolean as 'YES' or 'NO' }
  84. procedure write_real (r:real ; width,frac,col,row:byte) ;
  85.   { writes a real }
  86. procedure keyin (var ch:char) ;
  87.   { Reads a single character from keyboard without echoing it back.
  88.     Maps function key scan codes to single keyboard keys. }
  89. function build_str (ch : char ; n : integer) : str_type ;
  90.   { returns a string of length n of the character ch }
  91. function pad (st : str_type ; ch : char ; i : integer) : str_type ;
  92.   { Pad string with ch to length of i.
  93.     Do not let i exceed 80 (length of str_type! }
  94. function purgech (instr : str_type ; inchar : char) : str_type ;
  95.   { Purges all instances of the character from the string }
  96. function stripch (instr:str_type ; inchar:char) : str_type ;
  97.   { Strips leading instances of the character from the string }
  98. function chopch (instr:str_type ; inchar:char) : str_type ;
  99.   { Chops trailing instances of the character from the string }
  100. procedure read_str (var st:str_type ; maxlen, col, row:byte) ;
  101.   { Read String.  This procedure gets input from the keyboard one
  102.     character at a time and edits on the fly, rejecting invalid
  103.     characters.  COL and ROW tell where to begin the data input
  104.     field, and MAXLEN is the maximum length of the string to be
  105.     returned. }
  106. procedure read_int (var int:integer ; maxlen, col, row:byte) ;
  107.   { Read Integer.  This procedure gets input from the keyboard
  108.     one character at a time and edits on the fly, rejecting
  109.     invalid characters.  COL and ROW tell where to begin the data
  110.     input field, and MAXLEN is the maximum length of the integer
  111.     to be returned. }
  112. procedure read_longint (var lint:longint ; maxlen, col, row:byte) ;
  113.   { Read Long Integer.  Just like read_int. }
  114. function equal (r1,r2 : real) : boolean ;
  115.   { Tests functional equality of two real numbers.
  116.     True if r1 = r2. }
  117. function greater (r1,r2 : real) : boolean ;
  118.   { Tests functional inequality of two real numbers.
  119.     True if r1 > r2. }
  120. procedure read_real (var r:real ; maxlen,frac,col,row:byte) ;
  121.   { Read Real.  This procedure gets input from the keyboard
  122.     one character at a time and edits on the fly, rejecting
  123.     invalid characters.  COL and ROW tell where to begin the data
  124.     input field; MAXLEN is the maximum length of the string
  125.     representation of the real number, including sign and decimal
  126.     point; FRAC is the fractional part, the number of digits to
  127.     right of the decimal point. }
  128. procedure read_yn (var bool:boolean; col,row:byte) ;
  129.   { Inputs "Y" OR "N" to boolean at column and row specified,
  130.     prints "YES" or "NO."
  131.     Note -- use this when the screen control will not return
  132.     to the question and the boolean IS NOT defined before the
  133.     user answers the question.  Does not affect global FLD. }
  134. procedure read_bool (var bool:boolean; col,row:byte) ;
  135.   { Displays boolean at column and row specified, inputs "Y"
  136.     or "N" to set new value of boolean, prints "YES" or "NO."
  137.     Boolean is "forced;" user cannot cursor forward past undefined
  138.     boolean.  Pressing "Y" or "N" terminates entry. }
  139. procedure pause ;
  140.   { Prints message on bottom line, waits for user response. }
  141. procedure hard_pause ;
  142.   { Like Pause, but only accepts space bar or Escape and only goes forward }
  143. procedure show_msg (msg : str_type) ;
  144.   { Beeps, displays message centered on line 23, pauses }
  145.  
  146. { ========================================================================== }
  147.  
  148. implementation
  149.  
  150. { procedure gotoxy (col,row) ; -- Built-in proc in Turbo to place
  151.   cursor on screen.  Upper left is (1,1) not (0,0)! }
  152.  
  153. { procedure clrscr ; -- Built-in proc in Turbo to clear screen. }
  154.  
  155. { procedure clreol ; -- built-in proc in Turbo to clear to end of line }
  156.  
  157. { -------------------------------------------------------------------------- }
  158.  
  159. procedure clrline (col,row : byte) ;
  160.     begin
  161.         gotoxy (col,row) ;
  162.         clreol
  163.     end ;
  164.  
  165. { -------------------------------------------------------------------------- }
  166.  
  167. procedure beep ;
  168.     begin
  169.         write (chr(7))
  170.     end ;
  171.  
  172. { -------------------------------------------------------------------------- }
  173.  
  174. procedure buzz (pitch,duration : integer) ;
  175.   begin
  176.     sound(pitch) ;
  177.     delay(duration) ;
  178.     nosound
  179.   end ;
  180.  
  181. { -------------------------------------------------------------------------- }
  182.  
  183. procedure error_buzz ;
  184.   begin
  185.     buzz (50,100)
  186.   end ;
  187.  
  188. { -------------------------------------------------------------------------- }
  189.  
  190. procedure do_fld_ctl (key : integer) ;
  191.   { Adjusts global FLD based on value of key, the ordinal value of last key pressed }
  192.   { global
  193.         fld : integer -- for field cursor control }
  194.     begin
  195.         case key of
  196.           carr_rtn, next_fld : fld := succ(fld) ;
  197.           prev_fld           : fld := pred(fld) ;
  198.           next_page          : fld := 999 ;
  199.           prev_page          : fld := -999 ;
  200.           escape             : fld := maxint ;
  201.         end  { case }
  202.     end ;  { proc do_fld_ctl }
  203.  
  204. { ------------------------------------------------------------ }
  205.  
  206. procedure do_scrn_ctl ;
  207.   { Checks value of FLD and adjusts value of SCRN accordingly }
  208.   { Global
  209.         fld, scrn : integer -- For field and screen cursor control }
  210.     begin
  211.         if fld < 1 then
  212.                 scrn := pred(scrn)
  213.         else if fld = maxint then
  214.                 scrn := maxint
  215.         else
  216.                 scrn := succ(scrn)
  217.     end ;
  218.  
  219. { ------------------------------------------------------------ }
  220.  
  221. procedure write_str (st:str_type ; col,row:byte) ;
  222.     begin
  223.         gotoxy (col,row) ;
  224.         write (st)
  225.     end ;
  226.  
  227. { -------------------------------------------------------------------------- }
  228.  
  229. procedure write_int (int:integer ; width,col,row:byte) ;
  230.     begin
  231.         gotoxy (col,row) ;
  232.         write (int:width)
  233.     end ;
  234.  
  235. { -------------------------------------------------------------------------- }
  236.  
  237. procedure write_longint (lint:longint ; width,col,row:byte) ;
  238.     begin
  239.         gotoxy (col,row) ;
  240.         write (lint:width)
  241.     end ;
  242.  
  243. { -------------------------------------------------------------------------- }
  244.  
  245. procedure set_bool (var bool : boolean) ;
  246.   { Sets boolean to be undefined, neither true nor false.
  247.     Boolean is stored as one byte:
  248.         $80 = undefined
  249.         $01 = true
  250.         $00 = false.
  251.     Note : Turbo interprets $80 as true because it is greater than zero! }
  252.  
  253.     var
  254.         b : byte absolute bool ;
  255.     begin
  256.         b := $80
  257.     end ;  { proc set_bool }
  258.  
  259. { -------------------------------------------------------------------------- }
  260.  
  261. function defined (bool : boolean) : boolean ;
  262.   { Determines whether the boolean is defined or not }
  263.     var
  264.         b : byte absolute bool ;
  265.     begin
  266.         defined := not (b = $80)
  267.     end ;  { function defined }
  268.  
  269. { -------------------------------------------------------------------------- }
  270.  
  271. procedure write_bool (bool:boolean ; col, row:byte) ;
  272.     begin
  273.         gotoxy (col,row) ;
  274.         if not defined(bool) then
  275.             write ('___')
  276.         else if bool then
  277.             write ('YES')
  278.         else
  279.             write ('NO ')
  280.     end ;
  281.  
  282. { -------------------------------------------------------------------------- }
  283.  
  284. procedure write_real (r:real ; width,frac,col,row:byte) ;
  285.     begin
  286.         gotoxy (col,row) ;
  287.         write (r:width:frac)
  288.     end ;
  289.  
  290. { -------------------------------------------------------------------------- }
  291.  
  292. procedure keyin (var ch:char) ;
  293. { Reads a single character from keyboard without echoing it back.
  294.   Maps function key scan codes to single keyboard keys.
  295.   From Turbo 3.0 manual, page 360 -- 5/29/85
  296.   Modified for IO20 -- 2/26/86
  297.   Modified for IO23 -- 5/24/87
  298.   Modified for Turbo 4.0 -- 11/26/87 }
  299.  
  300.     var
  301.         func : boolean ;     { Whether function key or not }
  302.            c : char ;        { Character read }
  303.          key : integer ;     { ORD of character returned }
  304.  
  305.     begin
  306.         func := false ;
  307.         c := readkey ;                    { Get first char }
  308.         if  (ord(c) = null) then          { If there is a second ... }
  309.           begin
  310.             c := readkey ;                { Get 2nd char }
  311.             func := true
  312.           end ;
  313.         key := ord(c) ;
  314.  
  315.         if func then                      { Translate function keys }
  316.             case key of
  317.               63,75 : key := prev_char ;  { F5, left-arrow }
  318.               64,77 : key := next_char ;  { F6, right-arrow }
  319.               71    : key := home_key ;   { Home }
  320.               79    : key := end_key ;    { End }
  321.               61,72 : key := prev_fld ;   { F3, up-arrow }
  322.               62,80 : key := next_fld ;   { F4, down-arrow }
  323.               65,73 : key := prev_page ;  { F7, PgUp }
  324.               66,81 : key := next_page ;  { F8, PgDn }
  325.               59,83 : key := del_char ;   { F1, DEL }
  326.               60    : key := del_fld ;    { F2 }
  327.             else      key := 00 ;
  328.             end  { case }
  329.         else  { not a function key }
  330.             case key of                   { CP/M-like control keys }
  331.               $0B   : key := prev_fld ;   { ^K }
  332.               $0A   : key := next_fld ;   { ^J }
  333.               $0C   : key := next_char ;  { ^L }
  334.             end ;  { case }
  335.  
  336.         ch := chr(key)                    { finally, return the character }
  337.     end ; { procedure keyin }
  338.  
  339. { ------------------------------------------------------------ }
  340.  
  341. function build_str (ch : char ; n : integer) : str_type ;
  342.   { returns a string of length n of the character ch }
  343.     var
  344.         st : str_type ;
  345.     begin
  346.         if n < 0 then
  347.             n := 0 ;
  348.         st[0] := chr(n) ;
  349.         fillchar (st[1],n,ch) ;
  350.         build_str := st
  351.     end ;  { function build_str) ;
  352.  
  353. { -------------------------------------------------------------------------- }
  354.  
  355. function pad (st : str_type ; ch : char ; i : integer) : str_type ;
  356. { Pad string with ch to length of i.  Do not let i exceed 80 (length of str_type! }
  357.   var
  358.     l : integer ;
  359.   begin
  360.     l := length(st) ;
  361.     if l < i then
  362.       begin
  363.         fillchar (st[l+1],i-l,ch) ;
  364.         st[0] := chr(i)
  365.       end ;
  366.     pad := st
  367.   end;
  368.  
  369. { ------------------------------------------------------------ }
  370.  
  371. procedure adjust_str (var st : str_type ;
  372.                       var  p : byte ;     { position of char to left of cursor }
  373.                          key,             { ord of adjusting character }
  374.             maxlen, col, row : byte ) ;
  375.   { Adjusts position of cursor within string, deletes characters, etc. }
  376.     begin
  377.       case key of
  378.         home_key  : p := 0 ;
  379.         end_key   : p := length(st) ;
  380.         prev_char : if p > 0 then
  381.                         p := pred(p)
  382.                     else
  383.                         error_buzz ;
  384.         next_char : if p < length(st) then
  385.                         p := succ(p)
  386.                     else
  387.                         error_buzz ;
  388.         del_left  : if p > 0 then
  389.                       begin
  390.                         delete (st,p,1) ;
  391.                         write (^H,copy(st,p,maxlen),chr(filler)) ;
  392.                         p := pred(p)
  393.                       end
  394.                     else
  395.                         error_buzz ;
  396.         del_char  : if p < length(st) then
  397.                       begin
  398.                         delete (st,p+1,1) ;
  399.                         write (copy(st,p+1,maxlen),chr(filler))
  400.                       end
  401.                     else
  402.                         error_buzz ;
  403.         del_fld   : begin
  404.                       st := '' ;
  405.                       p := 0  ;
  406.                       write_str (build_str(chr(filler),maxlen),col,row)
  407.                     end
  408.       end  { case }
  409.     end ; { proc adjust_str }
  410.  
  411. { -------------------------------------------------------------------------- }
  412.  
  413. function purgech (instr : str_type ; inchar : char) : str_type ;
  414.     {Purges all instances of the character from the string}
  415.     var
  416.         n      : integer ;  {Loop counter}
  417.         outstr : str_type ; {Result string}
  418.  
  419.     begin
  420.         outstr := '' ;
  421.         for n := 1 to length (instr) do
  422.                 if not (instr[n] = inchar) then
  423.                         outstr := concat (outstr, instr[n]) ;
  424.         purgech := outstr
  425.     end ;
  426.  
  427. { -------------------------------------------------------------------------- }
  428.  
  429. function stripch (instr:str_type ; inchar:char) : str_type ;
  430.     {Strips leading instances of the character from the string}
  431.     begin
  432.         while not (length(instr) = 0)
  433.         and (instr[1] = inchar) do
  434.                 delete (instr, 1, 1) ;
  435.         stripch := instr
  436.     end ;
  437.  
  438. { -------------------------------------------------------------------------- }
  439.  
  440. function chopch (instr:str_type ; inchar:char) : str_type ;
  441.     {Chops trailing instances of the character from the string}
  442.     begin
  443.         while not (length(instr) = 0)
  444.         and (instr[length(instr)] = inchar) do
  445.                 delete (instr, length(instr), 1) ;
  446.         chopch := instr
  447.     end ;
  448.  
  449. { -------------------------------------------------------------------------- }
  450.  
  451. procedure read_str (var st:str_type ; maxlen, col, row:byte) ;
  452.  
  453.   { Read String.  This procedure gets input from the keyboard one
  454.     character at a time and edits on the fly, rejecting invalid
  455.     characters.  COL and ROW tell where to begin the data input
  456.     field, and MAXLEN is the maximum length of the string to be
  457.     returned.
  458.  
  459.     Revised 6/04/85 -- WPM }
  460.  
  461.     var
  462.         ch   : char ;     { character from keyboard }
  463.         key  : integer ;  { ord(ch) }
  464.         p    : byte ;     { position of char to left of cursor }
  465.  
  466.     procedure add_to_str ;
  467.         begin
  468.           if not (length(st) = maxlen) then
  469.             begin
  470.               p := p + 1 ;
  471.               insert (ch,st,p) ;
  472.               write (copy(st,p,maxlen))
  473.             end
  474.           else
  475.               error_buzz
  476.         end ; {--- of add_to_str ---}
  477.  
  478.     begin {--- read_str ---}
  479.         write_str (st, col, row) ;
  480.         write (build_str(chr(filler),maxlen - length(st))) ;
  481.         p := length(st) ;
  482.         repeat
  483.             gotoxy (col + p, row) ;
  484.             keyin (ch) ;
  485.             key := ord(ch) ;
  486.             if key in [$20 .. $7E] then  { printable character }
  487.                 add_to_str
  488.             else if key in adjusting then
  489.                 adjust_str (st,p,key,maxlen,col,row)
  490.             else if key in terminating then
  491.                 do_fld_ctl (key)
  492.             else
  493.                 error_buzz
  494.         until key in terminating ;
  495.         gotoxy (col + length(st), row) ;
  496.         write ('':maxlen - length(st))
  497.     end ; {--- of read_str ---}
  498.  
  499. { -------------------------------------------------------------------------- }
  500.  
  501. procedure read_int (var int:integer ; maxlen, col, row:byte) ;
  502.  
  503.   { Read Integer.  This procedure gets input from the keyboard
  504.     one character at a time and edits on the fly, rejecting
  505.     invalid characters.  COL and ROW tell where to begin the data
  506.     input field, and MAXLEN is the maximum length of the integer
  507.     to be returned.
  508.  
  509.     Revised 6/04/85 -- WPM }
  510.  
  511.     const
  512.         maxst : string[5] = '32767' ;  { string representation of maxint }
  513.  
  514.     var
  515.         ch    : char ;       { character from keyboard }
  516.         key   : integer ;    { ord(ch) }
  517.         p     : byte ;       { position of char to left of cursor }
  518.         st    : string[5] ;  { string representation of integer }
  519.         code  : integer ;    { result of string to integer conversion }
  520.  
  521.     procedure add_to_str ;
  522.         begin
  523.           if not (length(st) = maxlen) then
  524.             begin
  525.               p := p + 1 ;
  526.               insert (ch,st,p) ;
  527.               write (copy(st,p,maxlen))
  528.             end
  529.           else
  530.               error_buzz
  531.         end ; {--- of add_to_str---}
  532.  
  533.     begin {--- read_int ---}
  534.         str (int:maxlen, st) ;          { convert integer into string }
  535.         st := purgech (st, ' ') ;
  536.         st := stripch (st, '0') ;
  537.         write_str (st, col, row) ;
  538.         write (build_str(chr(filler),maxlen - length(st))) ;
  539.         p := length(st) ;
  540.         repeat
  541.             gotoxy (col + p, row) ;
  542.             keyin (ch) ;
  543.             key := ord(ch) ;
  544.             if key = $2D then                 { minus sign }
  545.               begin
  546.                 if  (pos('-',st) = 0)
  547.                 and (length(st) < maxlen)
  548.                 and (p = 0) then
  549.                     add_to_str
  550.                 else
  551.                     error_buzz
  552.               end
  553.             else if key in [$30 .. $39] then  {digits 0 - 9}
  554.               begin
  555.                 add_to_str ;
  556.                 if (length(st) = 5)
  557.                 and (st > maxst) then
  558.                   begin
  559.                     delete (st,p,1) ;
  560.                     write (^H,copy(st,p,maxlen),chr(filler)) ;
  561.                     p := p - 1 ;
  562.                     error_buzz
  563.                   end
  564.               end
  565.             else if key in adjusting then
  566.                 adjust_str (st,p,key,maxlen,col,row)
  567.             else if key in terminating then
  568.                 do_fld_ctl (key)
  569.             else
  570.                 error_buzz
  571.         until key in terminating ;
  572.         if (st = '')
  573.         or (st = '-') then
  574.           begin
  575.             int := 0 ;
  576.             code := 0
  577.           end
  578.         else
  579.             val (st, int, code) ;              {Make string into integer}
  580.  
  581.         if code = 0 then                       {Conversion worked OK}
  582.           begin
  583.             gotoxy (col, row) ;
  584.             write (int:maxlen)
  585.           end
  586.         else
  587.           begin
  588.             gotoxy (col+maxlen,row) ;
  589.             write ('** CONVERSION ERROR ', code) ;
  590.             halt
  591.           end
  592. end ; {--- of read_int ---}
  593.  
  594. { -------------------------------------------------------------------------- }
  595.  
  596. procedure read_longint (var lint:longint ; maxlen, col, row:byte) ;
  597.  
  598.   { Read Long Integer.  Just like read_int.
  599.  
  600.     Revised 3/19/88 -- WPM }
  601.  
  602.     const
  603.         maxst : string[10] = '2147483647' ;  { string representation
  604.                                                of maximum longint }
  605.  
  606.     var
  607.         ch    : char ;       { character from keyboard }
  608.         key   : integer ;    { ord(ch) }
  609.         p     : byte ;       { position of char to left of cursor }
  610.         st    : string[10] ; { string representation of longint }
  611.         code  : integer ;    { result of string to integer conversion }
  612.  
  613.     procedure add_to_str ;
  614.         begin
  615.           if not (length(st) = maxlen) then
  616.             begin
  617.               p := p + 1 ;
  618.               insert (ch,st,p) ;
  619.               write (copy(st,p,maxlen))
  620.             end
  621.           else
  622.               error_buzz
  623.         end ; {--- of add_to_str---}
  624.  
  625.     begin {--- read_longint ---}
  626.         str (lint:maxlen, st) ;          { convert integer into string }
  627.         st := purgech (st, ' ') ;
  628.         st := stripch (st, '0') ;
  629.         write_str (st, col, row) ;
  630.         write (build_str(chr(filler),maxlen - length(st))) ;
  631.         p := length(st) ;
  632.         repeat
  633.             gotoxy (col + p, row) ;
  634.             keyin (ch) ;
  635.             key := ord(ch) ;
  636.             if key = $2D then                 { minus sign }
  637.               begin
  638.                 if  (pos('-',st) = 0)
  639.                 and (length(st) < maxlen)
  640.                 and (p = 0) then
  641.                     add_to_str
  642.                 else
  643.                     error_buzz
  644.               end
  645.             else if key in [$30 .. $39] then  {digits 0 - 9}
  646.               begin
  647.                 add_to_str ;
  648.                 if (length(st) = 10)
  649.                 and (st > maxst) then
  650.                   begin
  651.                     delete (st,p,1) ;
  652.                     write (^H,copy(st,p,maxlen),chr(filler)) ;
  653.                     p := p - 1 ;
  654.                     error_buzz
  655.                   end
  656.               end
  657.             else if key in adjusting then
  658.                 adjust_str (st,p,key,maxlen,col,row)
  659.             else if key in terminating then
  660.                 do_fld_ctl (key)
  661.             else
  662.                 error_buzz
  663.         until key in terminating ;
  664.         if (st = '')
  665.         or (st = '-') then
  666.           begin
  667.             lint := 0 ;
  668.             code := 0
  669.           end
  670.         else
  671.             val (st, lint, code) ;             {Make string into integer}
  672.  
  673.         if code = 0 then                       {Conversion worked OK}
  674.           begin
  675.             gotoxy (col, row) ;
  676.             write (lint:maxlen)
  677.           end
  678.         else
  679.           begin
  680.             gotoxy (col+maxlen,row) ;
  681.             write ('** CONVERSION ERROR ', code) ;
  682.             halt
  683.           end
  684. end ; {--- of read_longint ---}
  685.  
  686. { -------------------------------------------------------------------------- }
  687.  
  688. function equal (r1,r2 : real) : boolean ;
  689.   { tests functional equality of two real numbers -- 4/30/85 }
  690.     begin
  691.         equal := abs(r1 - r2) < 1.0e-5
  692.     end ;  { function equal }
  693.  
  694. { -------------------------------------------------------------------------- }
  695.  
  696. function greater (r1,r2 : real) : boolean ;
  697.   { tests functional inequality of two real numbers -- 5/1/85 }
  698.     begin
  699.         greater := (r1 - r2) > 1.0e-5
  700.     end ;  { function greater }
  701.  
  702. { -------------------------------------------------------------------------- }
  703.  
  704. procedure read_real (var r:real ; maxlen,frac,col,row:byte) ;
  705.  
  706.   { Read Real.  This procedure gets input from the keyboard
  707.     one character at a time and edits on the fly, rejecting
  708.     invalid characters.  COL and ROW tell where to begin the data
  709.     input field; MAXLEN is the maximum length of the string
  710.     representation of the real number, including sign and decimal
  711.     point; FRAC is the fractional part, the number of digits to
  712.     right of the decimal point.
  713.  
  714.     Note -- In Turbo the maximum number of significant digits in
  715.     decimal (not scientific) representation is 11.  In TurboBCD,
  716.     the maximum number of significant digits is 18.  It is the
  717.     programmer's responsibility to limit input and computed output
  718.     to the maximum significant digits.
  719.  
  720.     Define MAXLEN as at least two more than FRAC.  When a real
  721.     less than one is written, Turbo puts a leading zero on it.  If
  722.     it is negative, Turbo puts a leading minus sign and zero.  This
  723.     can corrupt your display unless you allow space for the extra
  724.     characters.
  725.  
  726.     Revised 12/08/87 -- WPM }
  727.  
  728.     var
  729.         ch   : char ;       { Input character }
  730.         key  : integer ;    { ord(ch) }
  731.         p    : byte ;       { position of char to left of cursor }
  732.         st   : string[21] ; { String representation of real number -- }
  733.                             { max digits + minus sign + dec point + one extra }
  734.         code : integer ;    { Result of VAL conversion }
  735.         rlen,               { Current length of st to right of dec. pt. }
  736.         llen,               { Current length to left, including dec. pt. }
  737.         maxl,               { Max allowable to left, including dec. pt. }
  738.         posdec : byte ;     { position of decimal point in string }
  739.  
  740.   { +++++++++++++++++++++++++++++++++++++ }
  741.  
  742.     procedure compute_length ;
  743.       { Compute length of left and right portions of string }
  744.         begin
  745.             posdec := pos('.',st) ;
  746.             if posdec = 0 then                { If no dec. pt. ... }
  747.                 begin
  748.                     llen := length(st) ;      { the whole string is Left }
  749.                     rlen := 0                 { and none is Right }
  750.                 end
  751.             else    {There is a decimal point ...}
  752.                 begin
  753.                     llen := posdec ;          { Left is all up to and incl. dec. pt. }
  754.                     rlen := length(st) - llen { Right is the rest }
  755.                 end
  756.         end ; { proc compute_length }
  757.  
  758.   { +++++++++++++++++++++++++++++++++++++ }
  759.  
  760.     procedure add_to_str ;
  761.  
  762.         procedure add_it ;
  763.             begin
  764.               p := p + 1 ;
  765.               insert (ch,st,p) ;
  766.               write (copy(st,p,maxlen))
  767.             end ;
  768.  
  769.         begin {add_to_str}
  770.             posdec := pos ('.',st) ;
  771.             if ch = '.' then        { Decimal point; if room, add it }
  772.               begin
  773.                 if  (posdec = 0)
  774.                 and (length(st) - p <= frac) then
  775.                     add_it
  776.               end
  777.                                     { else it's not a decimal point }
  778.                                     { see if digit fits in whole part }
  779.             else if  (    (posdec = 0)
  780.                       and (llen < maxl - 1)  { only dec. pt. allowed in pos. maxl }
  781.                      )
  782.                  or  (    (posdec > 0)
  783.                       and (llen < maxl)
  784.                       and (p < posdec)
  785.                      ) then
  786.  
  787.                 add_it
  788.  
  789.                                     { digit is candidate for fractional part }
  790.             else if  (not(posdec = 0))
  791.                  and (p >= posdec)
  792.                  and (rlen < frac) then
  793.  
  794.                 add_it
  795.             else
  796.                 error_buzz
  797.  
  798.         end ; {--- of add_to_str---}
  799.  
  800.   { +++++++++++++++++++++++++++++++++++++ }
  801.  
  802.     begin {--- read_real ---}
  803.                               {Initialize}
  804.         maxl  := maxlen - frac ;
  805.  
  806.                               {Set up string representation of real and }
  807.                               {determine length of left & right portions}
  808.  
  809.         str(r:maxlen:frac,st) ;           {Make real into string}
  810.         st := purgech (st, ' ') ;         {Purge all blanks}
  811.         st := stripch (st, '0') ;         {Strip leading zeroes}
  812.         if not (pos('.', st) = 0) then    {If there is a dec. pt ... }
  813.             begin
  814.                 st := chopch (st, '0') ;  {Chop trailing zeroes}
  815.                 st := chopch (st, '.')    {and trailing dec. pt.}
  816.             end ;
  817.         compute_length ;
  818.  
  819.                               {Write string on console}
  820.  
  821.         write_str (st, col, row) ;
  822.         write (build_str(chr(filler),maxlen - length(st))) ;
  823.         p := length(st) ;
  824.  
  825.                               {Get input a character at a time & edit it}
  826.  
  827.         repeat
  828.             gotoxy (col + p, row) ;
  829.             compute_length ;
  830.             if (    (posdec = 0)
  831.                 and (llen > maxl - 1)
  832.                )
  833.             or (    (not (posdec = 0))
  834.                 and (llen > maxl)
  835.                )
  836.             or (rlen > frac) then                   { if number is larger than }
  837.               begin                                 { spec then delete it all }
  838.                 key := del_fld ;
  839.                 adjust_str (st,p,key,maxlen,col,row) ;
  840.                 gotoxy (col,row) ;
  841.                 beep
  842.               end ;
  843.             keyin (ch) ;
  844.             key := ord(ch) ;
  845.             if key = $2D  then                      { minus sign }
  846.               begin
  847.                 if  (pos('-',st) = 0)
  848.                 and (p = 0)
  849.                 and (  (    (posdec = 0)
  850.                         and (llen < maxl - 1)
  851.                        )
  852.                     or (    (not (posdec = 0))
  853.                         and (llen < maxl)
  854.                        )
  855.                     ) then
  856.  
  857.                     add_to_str
  858.                 else
  859.                     error_buzz
  860.               end
  861.             else if key in [$2E, $30 .. $39] then   { decimal point, numeric digits }
  862.                 add_to_str
  863.             else if key in adjusting then
  864.                 adjust_str (st,p,key,maxlen,col,row)
  865.             else if key in terminating then
  866.                 do_fld_ctl (key)
  867.             else
  868.                 error_buzz
  869.         until key in terminating ;
  870.  
  871.                               {Done getting input, now convert back to real}
  872.         code := -1 ;                             {Use Code as a flag}
  873.         if (st = '')                             {If null string ... }
  874.         or (st = '.')
  875.         or (st = '-')
  876.         or (st = '-.') then
  877.           begin
  878.             r := 0.0 ;                           {Make real zero}
  879.             code := 0
  880.           end
  881.         else if (pos ('.',st) = 1) then          {If not null string, we must }
  882.             insert ('0',st,1)                    {check for a decimal point   }
  883.         else if (pos ('.',st) = 2)               {before any digits, which is }
  884.         and     (pos ('-',st) = 1) then          {OK in Turbo 3.0 but not 4.0.}
  885.             insert ('0',st,2)                    {If we find one, we insert a }
  886.                                                  {0 so conversion will work.  }
  887.  
  888.         else if (pos('.', st) = length(st)) then {If there is a trailing dec. }
  889.             delete (st,length(st),1) ;           {point we must get rid of it.}
  890.                                                  {Yet another incompatibility }
  891.                                                  {with Turbo 3.0!             }
  892.  
  893.         if code = -1 then                        {Real is not zero, so }
  894.             val (st,r,code) ;                    {convert string into real}
  895.  
  896.         if code = 0 then                         {Conversion worked OK}
  897.           begin
  898.             gotoxy (col, row) ;
  899.             write (r:maxlen:frac)                {Write the real on screen}
  900.           end
  901.         else
  902.           begin
  903.             gotoxy (col+maxlen,row) ;
  904.             write ('** CONVERSION ERROR ', code) ;
  905.             halt
  906.           end
  907. end ; {--- of read_real ---}
  908.  
  909. { -------------------------------------------------------------------------- }
  910.  
  911. procedure read_yn (var bool:boolean; col,row:byte) ;
  912.   { Inputs "Y" OR "N" to boolean at column and row specified,
  913.     prints "YES" or "NO."
  914.  
  915.     Note -- use this when the screen control will not return
  916.     to the question and the boolean IS NOT defined before the
  917.     user answers the question.  Does not affect global FLD. }
  918.  
  919.     var ch:char ;
  920.     begin
  921.         gotoxy (col,row) ;
  922.         write ('   ') ;
  923.         gotoxy (col,row) ;
  924.         repeat
  925.             keyin (ch) ;
  926.             ch := upcase(ch) ;
  927.             if not (ch in ['Y','N']) then error_buzz
  928.         until (ch in ['Y','N']) ;
  929.         if (ch = 'Y') then
  930.             begin
  931.                 write ('YES') ;
  932.                 bool := true
  933.             end
  934.         else
  935.             begin
  936.                 write ('NO ') ;
  937.                 bool := false
  938.             end
  939.     end ; { proc read_yn }
  940.  
  941. { ------------------------------------------------------------ }
  942.  
  943. procedure read_bool (var bool:boolean; col,row:byte) ;
  944.   { Displays boolean at column and row specified, inputs "Y"
  945.     or "N" to set new value of boolean, prints "YES" or "NO."
  946.     Boolean is "forced;" user cannot cursor forward past undefined
  947.     boolean.  Pressing "Y" or "N" terminates entry.
  948.  
  949.     Boolean is stored as one byte:
  950.         $80 = undefined
  951.         $01 = true
  952.         $00 = false.
  953.     Note : Turbo interprets $80 as true because it is greater than zero! }
  954.  
  955.     var
  956.         ch  : char ;
  957.         key : integer ;
  958.  
  959.     begin
  960.         write_bool (bool, col, row) ;
  961.         gotoxy (col, row) ;
  962.         repeat
  963.             keyin (ch) ;
  964.             key := ord(ch) ;
  965.             if key in [$59,$79] then          { 'Y','y' }
  966.               begin
  967.                 bool := true ;
  968.                 key  := next_fld ;
  969.                 do_fld_ctl(key)
  970.               end
  971.             else if key in [$4E, $6E] then    { 'N','n' }
  972.               begin
  973.                 bool := false ;
  974.                 key  := next_fld ;
  975.                 do_fld_ctl(key)
  976.               end
  977.             else if key in terminating then
  978.               begin
  979.                 if  (not defined(bool))
  980.                 and (key in [carr_rtn, next_fld, next_page]) then
  981.                   begin
  982.                     key := $00 ;
  983.                     error_buzz
  984.                   end
  985.                 else
  986.                     do_fld_ctl (key)
  987.               end
  988.             else
  989.                 error_buzz
  990.         until key in terminating ;
  991.         write_bool (bool, col, row)
  992.     end ; {--- of read_bool ---}
  993.  
  994. { -------------------------------------------------------------------------- }
  995.  
  996. procedure pause ;
  997.     {Prints message on bottom line, waits for user response}
  998.     var
  999.         ch   : char ;
  1000.         key : integer ;
  1001.     begin
  1002.         clrline (1,24) ;
  1003.         write_str ('PRESS SPACE BAR TO CONTINUE OR UP-ARROW TO GO BACK',14,24) ;
  1004.         repeat
  1005.                 keyin (ch) ;
  1006.                 key := ord(ch) ;
  1007.                 case key of
  1008.                   $20      : fld := succ(fld) ;
  1009.                   prev_fld : fld := pred(fld) ;
  1010.                   prev_page : fld := -999 ;
  1011.                   escape   : fld := maxint
  1012.                   else
  1013.                       error_buzz
  1014.                 end ;
  1015.         until key in [$20, prev_fld, prev_page, escape] ;
  1016.         clrline (1,24)
  1017.     end ; { proc pause }
  1018.  
  1019. { ------------------------------------------------------------ }
  1020.  
  1021. procedure hard_pause ;
  1022.   { Like Pause, but only accepts space bar or Escape and only goes forward }
  1023.     var
  1024.         ch   : char ;
  1025.         key : integer ;
  1026.     begin
  1027.         clrline (1,24) ;
  1028.         write_str ('PRESS SPACE BAR TO CONTINUE',26,24) ;
  1029.         repeat
  1030.                 keyin (ch) ;
  1031.                 key := ord(ch) ;
  1032.                 case key of
  1033.                   $20      : fld := succ(fld) ;
  1034.                   escape   : fld := maxint ;
  1035.                   else
  1036.                       error_buzz
  1037.                 end ;
  1038.         until key in [$20, escape] ;
  1039.         clrline (1,24)
  1040.     end ; { proc hard_pause }
  1041.  
  1042. { ------------------------------------------------------------ }
  1043.  
  1044. procedure show_msg (msg : str_type) ;
  1045.   { Beeps, displays message centered on line 23, pauses }
  1046.  
  1047.     var
  1048.         savefld : integer ;
  1049.  
  1050.     begin
  1051.         savefld := fld ;
  1052.         beep ;
  1053.         clrline (1,23) ;
  1054.         write_str (msg,((80-length(msg)) div 2),23) ;
  1055.         hard_pause ;
  1056.         clrline (1,23) ;
  1057.         fld := savefld ;
  1058.     end ; { proc show_msg }
  1059.  
  1060. end. { implementation }
  1061.  
  1062. { ----- EOF IO23UNIT.PAS ------------------------------------------------ }
  1063.