home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TP5WIO.ZIP / TP5WIO.INC < prev    next >
Encoding:
Text File  |  1989-07-07  |  43.6 KB  |  1,372 lines

  1. const
  2.    vno = '4.10';      { Package version Number }
  3.    { ASCII values of cursor control keys, like WordStar. }
  4.    prev_char = $13 ;  { ^S }
  5.    next_char = $04 ;  { ^D }
  6.    prev_fld  = $05 ;  { ^E }
  7.    next_fld  = $18 ;  { ^X }
  8.    prev_page = $12 ;  { ^R }
  9.    next_page = $03 ;  { ^C }
  10.    del_char  = $07 ;  { ^G }
  11.    del_left  = $08 ;  { ^H (Backspace) }
  12.    del_fld   = $19 ;  { ^Y }
  13.    del       = $7F ;  { Delete }
  14.    escape    = $1B ;
  15.    carr_rtn  = $0D ;
  16.    space     = $20 ;
  17.    filler    = $2E ;  { $2E = . $5F = _ }
  18.  
  19.    { the extended key codes from the keyboard }
  20.    HOME      = 199;
  21.    UP        = 200;
  22.    PGUP      = 201;
  23.    BS        = 203;
  24.    FWD       = 205;
  25.    END_C     = 207;
  26.    DN        = 208;
  27.    PGDN      = 209;
  28.    INS       = 210;
  29.    DEL_C     = 211;
  30.  
  31.    CTRL_HOME = 247;
  32.    CTRL_BS   = 243;
  33.    CTRL_FWD  = 244;
  34.    CTRL_END  = 245;
  35.  
  36.    { The function keys return a value which is the index 187..196
  37.      used by subtracting 186 from the value and into the user array
  38.      of strings to insert into a field. }
  39.    f1 = 187;
  40.    f2 = 188;
  41.    f3 = 189;
  42.    f4 = 190;
  43.    f5 = 191;
  44.    f6 = 192;
  45.    f7 = 193;
  46.    f8 = 194;
  47.    f9 = 195;
  48.    f10= 196;
  49.  
  50.    monthtotal : montharray = (0,31,59,90,120,151,181,212,243,273,304,334,365);
  51.                 { used to convert julian date to gregorian and back }
  52.  
  53. type
  54.    { the following variant record is used to map a longint to two integers }
  55.    intlong = record
  56.       case integer of
  57.          0 :(lint:longint);
  58.          1 :(lowint,highint:integer);
  59.       end;
  60.  
  61.    intset = set of $00 .. $FF ;
  62.  
  63.    const  { Turbo typed constants -- initialized variables }
  64.    terminating : intset = [carr_rtn, next_fld, prev_fld, escape,
  65.                             next_page, prev_page,PGUP,PGDN,UP,DN] ;
  66.    adjusting   : intset = [prev_char, next_char, del_char, del_fld,
  67.                            del_left,DEL_C,FWD,BS] ;
  68.  
  69. { --------------- local definitions for the window procedures -------------- }
  70. const
  71.    maxwindows = 10;     { maximum # on screen windows }
  72.  
  73. type
  74.    pointer = ^integer;
  75.    windowtype = record
  76.       xl,yl,xr,yr :integer;   { cordinates or corners }
  77.       bufrptr     :pointer;   { pointer to buffer location }
  78.       cursorx,cursory :integer; { cursor position brfore opening }
  79.       screenattr  :byte;      { text attributes before opening }
  80.    end;
  81.  
  82. var
  83.    windowstack   :array[0..maxwindows] of windowtype;
  84.    maxcols,maxrows :byte;  { # rows and columns for initial video mode }
  85.    numwindows :0..maxwindows; { # windows currently open }
  86.    vidstart   :word;          { location of video memory }
  87.    regs       :registers;
  88.    aw_fore,
  89.    aw_back,
  90.    old_fore,
  91.    old_back   :byte;    { active window fore and background colors }
  92.  
  93. { ---------------------------------------------------------------- }
  94.  
  95. procedure beep;
  96. { this procedure is called if any routine causes an error }
  97. begin
  98.    sound(200); delay(100);
  99.    sound(350); delay(100);
  100.    sound(100); delay(100);
  101.    nosound;
  102. end; { procedure beep }
  103.  
  104. { ---------------------------------------------------------------- }
  105.  
  106. procedure save_colors;
  107. { saves the present screen colors to restore later }
  108. begin
  109.    old_fore := aw_fore;
  110.    old_back := aw_back;
  111. end;
  112.  
  113. { ---------------------------------------------------------------- }
  114.  
  115. procedure restore_colors;
  116. { restores the old colors back to the active colors }
  117. begin
  118.    aw_fore := old_fore;
  119.    aw_back := old_back;
  120. end;
  121.  
  122. { ---------------------------------------------------------------- }
  123.  
  124. procedure SetColor(Fore, Back : byte);
  125. begin
  126.   TextColor(Fore);
  127.   TextBackground(Back);
  128. end; { SetColor }
  129.  
  130. { ---------------------------------------------------------------- }
  131.  
  132. function Center(Len, Left, Right : integer) : integer;
  133. { find the location to position (x) for title }
  134. begin
  135.    center := (left + ((right-left) div 2) - (len div 2));
  136. end;
  137.  
  138. { ---------------------------------------------------------------- }
  139.  
  140. procedure drawframe(wtitle:string;x1,y1,x2,y2:byte);
  141. { draws a rectangular frame on the screen with upper left hand corner
  142.   at x1,y1 and lower right hand corner at x2,y2 }
  143. var
  144.    k  :integer;
  145.    currentattr :byte;
  146. begin
  147.    currentattr := textattr;  { save the current text attributes }
  148.    if(col_inv_flag) then
  149.       Textattr := framefgnd + numwindows + 16 * framebkgnd { change attributes for frame }
  150.    else
  151.       Textattr := framefgnd + 16 * framebkgnd; { change attributes for frame }
  152.    gotoxy(x1,y1);
  153.    write(chr(201));
  154.    for k := (x1 + 1) to (x2 -1) do  { top border line }
  155.       write(chr(205));
  156.    write(chr(187));
  157.    for k := (y1 + 1) to (y2 - 1) do
  158.       begin
  159.       gotoxy(x1,k); write(chr(186));
  160.       gotoxy(x2,k); write(chr(186));
  161.    end;
  162.    gotoxy(x1,y2);
  163.    write(chr(200));
  164.    for k := (x1 + 1) to (x2 - 1) do
  165.       write(chr(205));
  166.    write(chr(188));
  167.    { ---- put the title in the center of the window border if there is
  168.      a title, if length(wtitle) > 0 ----- }
  169.    if(length(wtitle) > 0) then
  170.       begin
  171.       if(length(wtitle) > (x2-x1-4)) then  { if title too long, clip it }
  172.          wtitle := copy(wtitle,1,(x2-x1-4));
  173.       GotoXY(Center(Length(WTitle) + 2, X1, X2), y1);
  174.       if(col_inv_flag) then
  175.          TextColor(title_color + numwindows + 1)
  176.       else
  177.          TextColor(title_color);
  178.       Write(' ', WTitle, ' ');
  179.    end;
  180.    textattr := currentattr;  { restore previous text attributes }
  181. end;  { procedure drawframe }
  182.  
  183. { ---------------------------------------------------------------- }
  184.  
  185. procedure saveregion(x1,y1,x2,y2:byte;
  186.                      var startaddr :pointer);
  187. { saves the contents of the screen rectangle with coordinates x1,y1,x2,y2
  188.   on the heap starting at address startaddr. }
  189. var
  190.    tempptr, lineptr :pointer;
  191.    k,linelength     :integer;
  192. begin
  193.    linelength := (x2 - x1 + 1) * 2; { # bytes per line in rectangel }
  194.    { allocate space on heap }
  195.    getmem(startaddr,linelength * (y2 - y1 + 1));
  196.    tempptr := startaddr; {tempptr points to copy destination on heap }
  197.    for k := y1 to y2 do
  198.       begin { make lineptr point to screen position x=s1, y=k }
  199.       lineptr := ptr(vidstart, (k -1) * maxcols * 2 + (x1 - 1) * 2);
  200.       { move the line from screen to heap }
  201.       move(lineptr^,tempptr^,linelength);
  202.       { increment the screen pointer }
  203.       tempptr := ptr(seg(tempptr^),ofs(tempptr^)+linelength);
  204.    end;
  205. end;  {procedure saveregion }
  206.  
  207. { ---------------------------------------------------------------- }
  208.  
  209. procedure recallregion(x1,y1,x2,y2 :integer;
  210.                        hpptr :pointer);
  211. { moves the contents of a previously saved region from the heap back
  212.   to the screen. }
  213. var
  214.    tempptr,lineptr  :pointer;
  215.    k,linelength     :integer;
  216. begin
  217.    linelength := (x2 - x1 + 1) * 2; { # bytes per line in rectangle }
  218.    tempptr := hpptr;    { tempptr gives the source location for copy }
  219.    for k := y1 to y2 do
  220.       begin { make lineptr point to screen position x=x1, y=k }
  221.       lineptr := ptr(vidstart,(k - 1) * maxcols * 2 + (x1 -1) * 2);
  222.       move(tempptr^,lineptr^,linelength);
  223.       tempptr := ptr(seg(tempptr^),ofs(tempptr^)+linelength);
  224.    end;
  225. end; { procedure recallregion }
  226.  
  227. { ---------------------------------------------------------------- }
  228.  
  229. procedure closewindow;
  230. var  x,y :integer;
  231. begin
  232.    if numwindows > 0 then
  233.       begin
  234.       with windowstack[numwindows] do
  235.          begin
  236.          recallregion(xl,yl,xr,yr,bufrptr);  { restore underlying text }
  237.          freemem(bufrptr,(xr -xl + 1) * (yr -yl + 1) * 2); { free heap }
  238.          x := cursorx;
  239.          y := cursory;   { prepare to restore cursor position }
  240.          textattr := screenattr;  { restore screen attributes }
  241.       end;
  242.       { activate the underlying window }
  243.       numwindows := numwindows -1;
  244.       with windowstack[numwindows] do
  245.          window(xl+1,yl+1,xr -1,yr -1);
  246.       gotoxy(x,y);     { restore cursor position }
  247.    end;
  248.    if numwindows = 0 then in_window := false;
  249. end; { procedure closewindow }
  250.  
  251. { ---------------------------------------------------------------- }
  252.  
  253. procedure endwindows;
  254. { close any open windows when exiting the windows system.  Use as the
  255.   last statment in program to insure return to enviroment you came from.
  256.   The global variable is normally set to 0 but may be set to a reserved
  257.   number of windows if using a multi file window system.
  258. }
  259. begin
  260.    while (numwindows > reserv_wind) do
  261.       closewindow;
  262. end;  { procedure endwindows }
  263.  
  264. { ---------------------------------------------------------------- }
  265.  
  266. procedure wind_err(msg : string);
  267. { Beeps, displays open window error message.  Can not do it right
  268.   as the window system is broke when this is called so will just
  269.   try to put something on the screen.
  270. }
  271. var
  272.    i  : integer ;
  273.    ch :char;
  274.  
  275. begin
  276.    beep ;
  277.    window(1,1,79,24);   { make sure we have some screen space }
  278.    write_str('+==========================================================+',10,10);
  279.    for i := 1 to 9 do
  280.    write_str('|                                                          |',10,10+i);
  281.    write_str('+=========== Any key to exit to DOS =======================+',10,20);
  282.    if length(msg) > 76 then msg := copy(msg,1,76);
  283.    write_str(msg,((76-length(msg)) div 2),13);
  284.    ch := readkey;
  285.    reserv_wind := 0;    { be sure we get them all }
  286.    endwindows;          { close them all before exit }
  287. end ; { wind_err }
  288.  
  289. { ---------------------------------------------------------------- }
  290.  
  291. procedure openwindow(wtitle       :string;
  292.                      x1,y1,x2,y2  :byte;
  293.                      fgnd,bkgnd   :byte
  294.                     );
  295. { creates a blank window with the given coordinates, and saves the contents
  296.   of the underlying region on the heap.  If an error occurs in attemping to
  297.   open the window, a message is displayed on the screen before exiting the
  298.   program a message is put on the screen. then the exit procedure returns
  299.   the following error codes: 1 = too many windows, 2 = out of heap memory,
  300.   3 = wrong window dimensions.
  301.   }
  302. var pntr :pointer;
  303. begin
  304.    if(numwindows = 0) then
  305.       begin  { determine current screen parameters }
  306.       maxcols := lo(windmax) + 1;  { add 1 since numbering begins with 0 }
  307.       maxrows := hi(windmax) + 1;
  308.       with windowstack[0] do  { windowstack[0] is the entire screen }
  309.          begin
  310.          xl := 0;
  311.          yl := 0;
  312.          xr := maxcols + 1;
  313.          yr := maxrows + 1;
  314.       end;
  315.    end;
  316.    { check for possible error conditions }
  317.    if(numwindows = maxwindows) then
  318.       begin
  319.       wind_err('Sorry, too may windows requested.');
  320.       halt(1);
  321.    end
  322.    else if(maxavail < (x2 - x1 + 1) * (y2 - y1 + 1) * 2) then
  323.       begin
  324.       wind_err('Sorry, No more Heap storage available.');
  325.       halt(2);
  326.    end
  327.    else if(not ((x1 in [1..maxcols-2]) and (x2 in [3..maxcols]) and
  328.                 (x2-x1> 1) and (y1 in [1..maxrows-2]) and
  329.                 (y2 in [3..maxrows]) and (y2 - y1 > 1))) then
  330.       begin
  331.       wind_err('Sorry, Invalid window dimensions.');
  332.       halt(3);
  333.    end
  334.    else
  335.       begin  { successful request }
  336.       saveregion(x1,y1,x2,y2,pntr);
  337.       numwindows := numwindows + 1;
  338.       with windowstack[numwindows] do
  339.          begin
  340.          xl := x1;
  341.          yl := y1;
  342.          xr := x2;
  343.          yr := y2;
  344.          bufrptr := pntr;
  345.          cursorx := wherex;
  346.          cursory := wherey;
  347.          screenattr := textattr;
  348.       end;
  349.       window(1,1,maxcols,maxrows);   { make the whole screen a window }
  350.       drawframe(wtitle,x1,y1,x2,y2);
  351.       window(x1+1,y1+1,x2-1,y2-1);  { create the requested window }
  352.       textcolor(fgnd);
  353.       textbackground(bkgnd);
  354.       aw_back := bkgnd;     { save the active window colors }
  355.       aw_fore := fgnd;
  356.       clrscr;
  357.    end;
  358.    in_window := true;
  359. end; { procedure openwindow }
  360.  
  361. { ---------------------------------------------------------------- }
  362.  
  363. procedure openwind(wtitle       :string;
  364.                      x1,y1,x2,y2  :byte);
  365.  
  366. { Just a shell which calls the openwindow procedure with the default
  367.   text colors }
  368. begin
  369.    openwindow(wtitle,x1,y1,x2,y2,text_fg,text_bg);
  370. end; {procedure openwind}
  371.  
  372. { ------- End window unit ----- }
  373.  
  374. { procedure gotoxy (col,row); -- Built-in proc in Turbo to place
  375.   cursor on screen.  Upper left is (1,1) not (0,0)! }
  376.  
  377. { procedure clrscr ; -- Built-in proc in Turbo to clear screen. }
  378.  
  379. { procedure clreol ; -- built-in proc in Turbo to clear to end of line }
  380.  
  381. { -------------------------------------------------------------------------- }
  382.  
  383. procedure clrline(col,row : integer);
  384. begin
  385.    gotoxy (col,row);
  386.    clreol
  387. end ;
  388.  
  389. { -------------------------------------------------------------------------- }
  390.  
  391. procedure do_fld_ctl(key : integer);
  392. { Adjusts global FLD based on value of key, the ordinal value
  393.   of last key pressed }
  394. { global fld : integer -- for field cursor control }
  395. begin
  396.    case key of
  397.       carr_rtn, next_fld,
  398.       DN                 : fld := succ(fld);
  399.       prev_fld,UP        : fld := pred(fld);
  400.       next_page,PGDN     : fld := 999 ;
  401.       prev_page,PGUP     : fld := -999 ;
  402.       escape             : fld := maxint ;
  403.    end  { case }
  404. end ;  { proc do_fld_ctl }
  405.  
  406. { ------------------------------------------------------------ }
  407.  
  408. procedure do_scrn_ctl ;
  409. { Checks value of FLD and adjusts value of SCRN accordingly }
  410. { Global fld, scrn : integer -- For field and screen cursor control }
  411. begin
  412.    if fld < 1 then
  413.       scrn := pred(scrn)
  414.    else if fld = maxint then
  415.       scrn := maxint
  416.    else
  417.       scrn := succ(scrn)
  418. end ;
  419.  
  420. { ------------------------------------------------------------ }
  421.  
  422. procedure write_str(st:string ; col,row:integer);
  423. begin
  424.    gotoxy (col,row);
  425.    if((in_window) and (inv_flag)) then
  426.       begin
  427.       if(col_inv_flag) then
  428.          setcolor(inv_color,aw_back)
  429.       else
  430.          setcolor(aw_back,aw_fore);
  431.       write (st);
  432.       setcolor(aw_fore,aw_back);
  433.    end
  434.    else
  435.       write(st);
  436. end ;
  437.  
  438. { -------------------------------------------------------------------------- }
  439. procedure write_temp(var ln:string;tmp:string;x,y:integer);
  440. { writes a string using a template.  the string (ln) is printed
  441.   left justified in the template using the filler locations.
  442.   quits when the template is complete on the screen.  Fills unused
  443.   template filler locations with space. }
  444. var
  445.    p,t  :integer;
  446. begin
  447.    p := 1;
  448.    t := 1;
  449.    gotoxy(x,y);
  450.    if((in_window) and (inv_flag)) then
  451.       if(col_inv_flag) then
  452.          setcolor(inv_color,aw_back)
  453.       else
  454.          setcolor(aw_back,aw_fore);
  455.    for t := 1 to length(tmp) do
  456.       begin
  457.       if(tmp[t] <> chr(filler)) then
  458.          write(tmp[t])
  459.       else
  460.          begin
  461.          if(p > length(ln)) then
  462.             write(' ')
  463.          else
  464.             begin
  465.             write(ln[p]);
  466.             p := p + 1;
  467.          end;
  468.       end;
  469.    end;
  470.    if((in_window) and (inv_flag)) then
  471.       setcolor(aw_fore,aw_back);
  472. end;  { procedure write_temp }
  473.  
  474. { -------------------------------------------------------------------------- }
  475.  
  476. procedure write_int(i:integer ; width,col,row:integer);
  477. begin
  478.    gotoxy (col,row);
  479.    if((in_window) and (inv_flag)) then
  480.       begin
  481.       if(col_inv_flag) then
  482.          setcolor(inv_color,aw_back)
  483.       else
  484.          setcolor(aw_back,aw_fore);
  485.       write(i:width);
  486.       setcolor(aw_fore,aw_back);
  487.    end
  488.    else
  489.       write (i:width)
  490. end ;
  491.  
  492. { -------------------------------------------------------------------------- }
  493.  
  494. procedure write_lint(lint:longint ; width,col,row:integer);
  495. begin
  496.    gotoxy (col,row);
  497.    if((in_window) and (inv_flag)) then
  498.       begin
  499.       if(col_inv_flag) then
  500.          setcolor(inv_color,aw_back)
  501.       else
  502.          setcolor(aw_back,aw_fore);
  503.       write (lint:width);
  504.       setcolor(aw_fore,aw_back);
  505.    end
  506.    else
  507.       write (lint:width)
  508. end ;
  509.  
  510. { -------------------------------------------------------------------------- }
  511. PROCEDURE WRITE_WORD(i:word; width,col,row:integer);
  512. begin
  513.    gotoxy (col,row);
  514.    if((in_window) and (inv_flag)) then
  515.       begin
  516.       if(col_inv_flag) then
  517.          setcolor(inv_color,aw_back)
  518.       else
  519.          setcolor(aw_back,aw_fore);
  520.       write (i:width);
  521.       setcolor(aw_fore,aw_back);
  522.    end
  523.    else
  524.       write (i:width)
  525. end ;
  526.  
  527. { -------------------------------------------------------------------------- }
  528. PROCEDURE WRITE_BYTE(i:byte;width,col,row:integer);
  529. begin
  530.    gotoxy (col,row);
  531.    if((in_window) and (inv_flag)) then
  532.       begin
  533.       if(col_inv_flag) then
  534.          setcolor(inv_color,aw_back)
  535.       else
  536.          setcolor(aw_back,aw_fore);
  537.       write (i:width);
  538.       setcolor(aw_fore,aw_back);
  539.    end
  540.    else
  541.       write (i:width)
  542. end ;
  543.  
  544. { -------------------------------------------------------------------------- }
  545.  
  546. procedure set_bool(var bool : boolean);
  547.   { Sets boolean to be undefined, neither true nor false.
  548.     Boolean is stored as one byte:
  549.         $80 = undefined
  550.         $01 = true
  551.         $00 = false.
  552.     Note : Turbo interprets $80 as true because it is greater than zero! }
  553.  
  554. var
  555.    b : byte absolute bool ;
  556. begin
  557.    b := $80
  558. end ;  { proc set_bool }
  559.  
  560. { -------------------------------------------------------------------------- }
  561.  
  562. function defined(bool : boolean) : boolean;
  563. { Determines whether the boolean is defined or not }
  564. var
  565.    b : byte absolute bool ;
  566. begin
  567.    defined := not (b = $80)
  568. end ;  { function defined }
  569.  
  570. { -------------------------------------------------------------------------- }
  571.  
  572. procedure write_bool(bool:boolean ; col, row:integer);
  573. begin
  574.    gotoxy (col,row);
  575.    if((in_window) and (inv_flag)) then
  576.       if(col_inv_flag) then
  577.          setcolor(inv_color,aw_back)
  578.       else
  579.          setcolor(aw_back,aw_fore);
  580.    if not defined(bool) then
  581.       write ('___')
  582.    else if bool then
  583.       write ('YES')
  584.    else
  585.       write ('NO ');
  586.    if((in_window) and (inv_flag)) then
  587.       setcolor(aw_fore,aw_back);
  588. end ;
  589.  
  590. { -------------------------------------------------------------------------- }
  591.  
  592. procedure write_real(r:real ; width,frac,col,row:integer);
  593. begin
  594.    gotoxy (col,row);
  595.    if((in_window) and (inv_flag)) then
  596.       begin
  597.       if(col_inv_flag) then
  598.          setcolor(inv_color,aw_back)
  599.       else
  600.          setcolor(aw_back,aw_fore);
  601.       write (r:width:frac);
  602.       setcolor(aw_fore,aw_back);
  603.    end
  604.    else
  605.       write (r:width:frac)
  606. end ;
  607.  
  608. { -------------------------------------------------------------------------- }
  609.  
  610. { This is for IBM PC-DOS only  !!}
  611.  
  612. procedure keyin (var ch:char);
  613. { Reads a single character from keyboard without echoing it back.
  614.   Maps function key scan codes to single keyboard keys.
  615.   From Turbo 3.0 manual, page 360 -- 5/29/85
  616.   Modified for IO20 -- 2/26/86
  617.   Modified for IO22 -- 5/24/87
  618.   Modified to return different codes for the function keys than
  619.   the keypad keys.  Used to allow special entry for the function
  620.   keys.  10 Dec 87 gbr.
  621.   Changed to use the actual scan codes, key + 128 if extended key.
  622. }
  623. var
  624.       c : char ;                  { Character read }
  625.  
  626. begin
  627.    c := readkey;                  { Get first char }
  628.    if(c = #0) and keypressed then { If there is a second ... }
  629.       begin
  630.       c := readkey;                { Get 2nd char }
  631.       c := chr(ord(c) + 128);      { add 128 for returned key code }
  632.    end ;
  633.    ch := c;                        { finally, return the character }
  634. end ;
  635.  
  636. { ------------------------------------------------------------ }
  637.  
  638. function build_str(ch : char ; n : integer) : string;
  639. { returns a string of length n of the character ch }
  640. var
  641.    st : string ;
  642. begin
  643.    if n < 0 then
  644.       n := 0 ;
  645.    st[0] := chr(n);
  646.    fillchar (st[1],n,ch);
  647.    build_str := st
  648. end ;  { function build_str);
  649.  
  650. { ---------------------------------------------------------------- }
  651.  
  652. procedure adjust_str (var st : string ;
  653.                       var  p : integer ;  { position of char to left of cursor }
  654.                          key,             { ord of adjusting character }
  655.             maxlen, col, row : integer );
  656. { Adjusts position of cursor within string, deletes characters, etc. }
  657. begin
  658.    case key of
  659.       prev_char,BS
  660.                 :if p > 0 then
  661.                     p := pred(p);
  662.       next_char,FWD
  663.                 :if p < length(st) then
  664.                     p := succ(p);
  665.       del_left  :if p > 0 then
  666.                     begin
  667.                     delete (st,p,1);
  668.                     write (^H,copy(st,p,maxlen),chr(filler));
  669.                     p := pred(p)
  670.                  end ;
  671.       del_char,DEL_C
  672.                 :if p < length(st) then
  673.                     begin
  674.                     delete (st,p+1,1);
  675.                     write (copy(st,p+1,maxlen),chr(filler))
  676.                  end ;
  677.       del_fld   :begin
  678.                     st := '' ;
  679.                     p := 0  ;
  680.                     gotoxy(col,row);
  681.                     write(build_str(chr(filler),maxlen))
  682.                  end
  683.    end  { case }
  684. end ; { proc adjust_str }
  685.  
  686. { -------------------------------------------------------------------------- }
  687.  
  688. function purgech (instr : string ; inchar : char) : string ;
  689. {Purges all instances of the character from the string}
  690. var
  691.    n      : integer ;  {Loop counter}
  692.    outstr : string ; {Result string}
  693. begin
  694.    outstr := '' ;
  695.    for n := 1 to length (instr) do
  696.       if not (instr[n] = inchar) then
  697.          outstr := concat (outstr, instr[n]);
  698.    purgech := outstr
  699. end ;
  700.  
  701. { -------------------------------------------------------------------------- }
  702.  
  703. procedure read_str(var st:string ; maxlen, col, row:integer);
  704.  
  705. { Read String.  This procedure gets input from the keyboard one
  706.   character at a time and edits on the fly, rejecting invalid
  707.   characters.  COL and ROW tell where to begin the data input
  708.   field, and MAXLEN is the maximum length of the string to be
  709.   returned.
  710.   Revised 6/04/85 -- WPM
  711.   Only use the Function keys for string input data, for other
  712.   types of input will beep.
  713.   10 Dec 87 gbr}
  714.  
  715. var
  716.    ch   : char ;     { character from keyboard }
  717.    key,              { ord(ch) }
  718.    p    : integer ;  { position of char to left of cursor }
  719.  
  720.    procedure add_to_str ;
  721.    begin
  722.       if not (length(st) = maxlen) then
  723.          begin
  724.          p := p + 1 ;
  725.          insert(ch,st,p);
  726.          write (copy(st,p,maxlen))
  727.       end
  728.    end ; {--- of add_to_str ---}
  729.  
  730. begin {--- read_str ---}
  731.    write_str (st, col, row);
  732.    write (build_str(chr(filler),maxlen - length(st)));
  733.    p := length(st);
  734.    repeat
  735.       gotoxy (col + p, row);
  736.       keyin (ch);          {^^^^ read keyboard here ^^^^}
  737.       key := ord(ch);
  738.       if key in [$20 .. $7E] then  { printable character }
  739.          add_to_str
  740.       else if key in adjusting then
  741.          adjust_str (st,p,key,maxlen,col,row)
  742.       else if key in terminating then
  743.          do_fld_ctl (key)
  744.       else if key in [f1..f10] then { Function key pressed }
  745.          begin
  746.             st := copy(macro[key-f1 + 1],1,maxlen);  { put macro string in st }
  747.             key := carr_rtn;            { cr to terminate entry }
  748.          end
  749.       else
  750.          beep
  751.    until key in terminating ;
  752.    gotoxy (col + length(st), row);
  753.    write_str(st,col,row);              { rewrite for display characteristics }
  754.    write ('':maxlen - length(st))      { delete the filler characters on screen}
  755. end ; {--- of read_str ---}
  756.  
  757. { ------------------------------------------------------------ }
  758.  
  759. function bld_tmp_str(st:string;  { input string so far }
  760.                     tmp:string;  { template to put it in }
  761.                     ch : char    { filler character }
  762.                     ) : string ;
  763. { returns a string of template filled in with the input string }
  764. var
  765.    i,t : integer;
  766.    stt :string;
  767. begin
  768.    stt := tmp;
  769.    t := 1;
  770.    for i := 1 to length(st) do
  771.       begin
  772.       while(stt[t] <> ch) do t := t + 1;
  773.    stt[t] := st[i];
  774.    end;
  775.    bld_tmp_str := stt
  776. end ;  { function bld_tmp_str);
  777.  
  778. { -------------------------------------------------------------------------- }
  779. procedure read_temp(var st:string;tmp:string;col, row:integer);
  780. { Read string with a template.  This procedure gets input from
  781.   the keyboard one character at a time and edits on the fly,
  782.   rejecting invalid characters.  tmp is a template which is filled
  783.   in where filler characters exist, any other characters are displayed
  784.   on the screen.  Returned string does NOT have the template imbeded in
  785.   it.  COL and ROW tell where to begin the data input
  786.   field, Max length of the string is the max length of the template.
  787. }
  788. var
  789.    ch   : char ;     { character from keyboard }
  790.    key,              { ord(ch) }
  791.    t,                { position in template }
  792.    maxlen,           { max length of the template }
  793.    maxline,          { max length of returned string }
  794.    p,i     : integer ; { position in input string }
  795.  
  796.    procedure add_to_str ;
  797.    begin
  798.       if(length(st) < maxline) then
  799.          begin
  800.          p := p + 1 ;
  801.          t := t + 1;
  802.          insert(ch,st,p);
  803.          gotoxy(col,row);
  804.          write(bld_tmp_str(st,tmp,chr(filler)));
  805.          while(tmp[t] <> chr(filler)) and (t < length(tmp)) do t := succ(t);
  806.       end
  807.    end ; {--- of add_to_str ---}
  808.  
  809.    procedure adj_tmp_str;
  810.    { Adjusts position of cursor within string using a template,
  811.      deletes characters, etc. }
  812.    var
  813.       rwt_flag :boolean;  { need to rewrite line }
  814.    begin
  815.       rwt_flag := false;
  816.       case key of
  817.          prev_char,BS:if p > 0 then
  818.                        begin
  819.                        p := pred(p);
  820.                        t := pred(t);
  821.                        while(tmp[t] <> chr(filler)) and (t > 1) do t := pred(t);
  822.                     end;
  823.          next_char,FWD:if p < length(st) then
  824.                        begin
  825.                        p := succ(p);
  826.                        t := succ(t);
  827.                        while(tmp[t] <> chr(filler)) and (t < length(tmp)) do
  828.                           t := succ(t);
  829.                     end;
  830.          del_left  :if p > 0 then
  831.                        begin
  832.                        delete (st,p,1);
  833.                        rwt_flag := true;
  834.                        p := pred(p);
  835.                        t := pred(t);
  836.                        while(tmp[t] <> chr(filler)) and (t > 1) do t := pred(t);
  837.                     end ;
  838.          del_char,DEL_C:if p < length(st) then
  839.                        begin
  840.                        delete (st,p+1,1);
  841.                        rwt_flag := true;
  842.                     end ;
  843.          del_fld   :begin
  844.                        st := '' ;
  845.                        p := 0  ;
  846.                        t := 1;
  847.                        while(tmp[t] <> chr(filler)) and (t <= maxlen) do
  848.                           t := t + 1;
  849.                        rwt_flag := true;
  850.                     end
  851.       end;  { case }
  852.       if rwt_flag then
  853.          begin
  854.          gotoxy(col,row);
  855.          write(bld_tmp_str(st,tmp,chr(filler)));
  856.       end;
  857.    end ; { proc adj_tmp_str }
  858.  
  859. begin {--- read_temp ---}
  860.    maxlen := length(tmp);
  861.    maxline := 0;
  862.    for i := 1 to length(tmp) do
  863.       if(tmp[i] = chr(filler)) then maxline := maxline + 1;
  864.    p := length(st);
  865.    t := 1;
  866.    for i := 1 to p do  { find the present st length + template }
  867.       begin
  868.       while(tmp[t] <> chr(filler)) and (t <= maxlen) do t := t + 1;
  869.       t := t + 1;
  870.    end;       { check if the template character we are at is a template }
  871.    while(tmp[t] <> chr(filler)) and (t <= maxlen) do t := t + 1;
  872.    gotoxy(col,row);write(bld_tmp_str(st,tmp,chr(filler)));
  873.    p := length(st);
  874.    repeat
  875.       gotoxy (col + t-1, row);
  876.       keyin (ch);          {^^^^ read keyboard here ^^^^}
  877.       key := ord(ch);
  878.       if key in [$20 .. $7E] then  { printable character }
  879.          add_to_str
  880.       else if key in adjusting then
  881.          adj_tmp_str
  882.       else if key in terminating then
  883.          do_fld_ctl (key)
  884.       else if key in [f1..f10] then { Function key pressed }
  885.          begin
  886.          st := copy(macro[key-f1 + 1],1,maxlen);  { put macro string in st }
  887.          key := carr_rtn;            { cr to terminate entry }
  888.       end
  889.       else
  890.          beep
  891.    until key in terminating ;
  892.    write_temp(st,tmp,col,row);
  893. end ; {--- of read_temp ---}
  894.  
  895. { -------------------------------------------------------------------------- }
  896.  
  897. procedure read_int(var int:integer ; maxlen, col, row:integer);
  898.  
  899. { Read Integer.  This procedure gets input from the keyboard
  900.   one character at a time and edits on the fly, rejecting
  901.   invalid characters.  COL and ROW tell where to begin the data
  902.   input field, and MAXLEN is the maximum length of the integer
  903.   to be returned.
  904.   Revised 6/04/85 -- WPM }
  905.  
  906. const
  907.    maxst : string[5] = '32767' ;  { string representation of maxint }
  908.  
  909. var
  910.    ch    : char ;       { character from keyboard }
  911.    key,                 { ord(ch) }
  912.    p     : integer ;    { position of char to left of cursor }
  913.    st    : string;    { string representation of integer }
  914.    code  : integer ;    { result of string to integer conversion }
  915.  
  916.    procedure add_to_str ;
  917.    begin
  918.       if not (length(st) = maxlen) then
  919.          begin
  920.          p := p + 1 ;
  921.          insert (ch,st,p);
  922.          write (copy(st,p,maxlen))
  923.       end
  924.    end ; {--- of add_to_str---}
  925.  
  926. begin {--- read_int ---}
  927.    str (int:maxlen, st);          { convert integer into string }
  928.    st := purgech (st, ' ');
  929.    st := stripch (st, '0');
  930.    write_str (st, col, row);
  931.    write (build_str(chr(filler),maxlen - length(st)));
  932.    p := length(st);
  933.    repeat
  934.       gotoxy (col + p, row);
  935.       keyin (ch);
  936.       key := ord(ch);
  937.       if key = $2D then                 { minus sign }
  938.          begin
  939.          if(pos('-',st) = 0) and (length(st) < maxlen)
  940.             and (p = 0) then
  941.             add_to_str
  942.       end
  943.       else if key in [$30 .. $39] then  {digits 0 - 9}
  944.          begin
  945.          add_to_str ;
  946.          if (length(st) = 5) and (st > maxst) then
  947.             begin
  948.             delete (st,p,1);
  949.             write (^H,copy(st,p,maxlen),chr(filler));
  950.             p := p - 1
  951.          end
  952.       end
  953.       else if key in adjusting then
  954.          adjust_str (st,p,key,maxlen,col,row)
  955.       else if key in terminating then
  956.          do_fld_ctl (key)
  957.    until key in terminating ;
  958.    if st = '' then
  959.       begin
  960.       int := 0 ;
  961.       code := 0
  962.    end
  963.    else
  964.       val (st, int, code);              {Make string into integer}
  965.    gotoxy (col, row);
  966.    if code = 0 then  {Conversion worked OK}
  967.       write_int(int,maxlen,col,row)
  968.    else
  969.       begin
  970.       write ('** conversion error ', code);
  971.       halt
  972.    end
  973. end ; {--- of read_int ---}
  974.  
  975. { -------------------------------------------------------------------------- }
  976.  
  977. procedure read_lint(var lint:longint ; maxlen, col, row:integer);
  978. { Read LongInt.  This procedure gets input from the keyboard
  979.   one character at a time and edits on the fly, rejecting
  980.   invalid characters.  COL and ROW tell where to begin the data
  981.   input field, and MAXLEN is the maximum length of the long integer
  982.   to be returned.
  983. }
  984. const
  985.    maxst : string[10] = '2147483647' ;  { string representation of maxint }
  986.  
  987. var
  988.    ch    : char ;       { character from keyboard }
  989.    key,                 { ord(ch) }
  990.    p     : integer ;    { position of char to left of cursor }
  991.    st    : string;    { string representation of integer }
  992.    code  : integer ;    { result of string to integer conversion }
  993.  
  994.    procedure add_to_str ;
  995.    begin
  996.       if not (length(st) = maxlen) then
  997.          begin
  998.          p := p + 1 ;
  999.          insert (ch,st,p);
  1000.          write (copy(st,p,maxlen))
  1001.       end
  1002.    end ; {--- of add_to_str---}
  1003.  
  1004. begin {--- read_int ---}
  1005.    str (lint:maxlen, st);      { convert long integer into string }
  1006.    st := purgech (st, ' ');
  1007.    st := stripch (st, '0');
  1008.    write_str (st, col, row);
  1009.    write (build_str(chr(filler),maxlen - length(st)));
  1010.    p := length(st);
  1011.    repeat
  1012.       gotoxy (col + p, row);
  1013.       keyin (ch);
  1014.       key := ord(ch);
  1015.       if key = $2D then                 { minus sign }
  1016.          begin
  1017.          if(pos('-',st) = 0) and (length(st) < maxlen) and
  1018.             (p = 0) then
  1019.             add_to_str
  1020.       end
  1021.       else if key in [$30 .. $39] then  {digits 0 - 9}
  1022.          begin
  1023.          add_to_str ;
  1024.          if (length(st) = 10) and (st > maxst) then
  1025.             begin
  1026.             delete (st,p,1);
  1027.             write (^H,copy(st,p,maxlen),chr(filler));
  1028.             p := p - 1
  1029.          end
  1030.       end
  1031.       else if key in adjusting then
  1032.          adjust_str (st,p,key,maxlen,col,row)
  1033.       else if key in terminating then
  1034.          do_fld_ctl (key)
  1035.    until key in terminating ;
  1036.    if st = '' then
  1037.       begin
  1038.       lint := 0 ;
  1039.       code := 0
  1040.    end
  1041.    else
  1042.       val (st, lint, code);              {Make string into integer}
  1043.    gotoxy (col, row);
  1044.    if code = 0 then  {Conversion worked OK}
  1045.       write_lint(lint,maxlen,col,row)
  1046.    else
  1047.       begin
  1048.       write ('** conversion error ', code);
  1049.       halt
  1050.    end
  1051. end ; {--- of read_lint ---}
  1052.  
  1053. PROCEDURE READ_WORD(var wd:word; maxlen,col,row:integer);
  1054. { Read Word.  This procedure gets input from the keyboard
  1055.   one character at a time and edits on the fly, rejecting
  1056.   invalid characters.  COL and ROW tell where to begin the data
  1057.   input field, and MAXLEN is the maximum length of the word
  1058.   to be returned.
  1059.   Revised 6/04/85 -- WPM }
  1060.  
  1061. const
  1062.    maxst : string[5] = '65535' ;  { string representation of maxword }
  1063.  
  1064. var
  1065.    ch    : char ;       { character from keyboard }
  1066.    key,                 { ord(ch) }
  1067.    p     : integer ;    { position of char to left of cursor }
  1068.    st    : string;    { string representation of integer }
  1069.    code  :integer;       { result of string to word conversion }
  1070.  
  1071.    procedure add_to_str ;
  1072.    begin
  1073.       if not (length(st) = maxlen) then
  1074.          begin
  1075.          p := p + 1 ;
  1076.          insert (ch,st,p);
  1077.          write (copy(st,p,maxlen))
  1078.       end
  1079.    end ; {--- of add_to_str---}
  1080.  
  1081. begin {--- read_word ---}
  1082.    str (wd:maxlen, st);          { convert word into string }
  1083.    st := purgech (st, ' ');
  1084.    st := stripch (st, '0');
  1085.    write_str (st, col, row);
  1086.    write (build_str(chr(filler),maxlen - length(st)));
  1087.    p := length(st);
  1088.    repeat
  1089.       gotoxy (col + p, row);
  1090.       keyin (ch);
  1091.       key := ord(ch);
  1092.       if key = $2D then                 { minus sign }
  1093.          begin
  1094.          if(pos('-',st) = 0) and (length(st) < maxlen)
  1095.             and (p = 0) then
  1096.             add_to_str
  1097.       end
  1098.       else if key in [$30 .. $39] then  {digits 0 - 9}
  1099.          begin
  1100.          add_to_str ;
  1101.          if (length(st) = 5) and (st > maxst) then
  1102.             begin
  1103.             delete (st,p,1);
  1104.             write (^H,copy(st,p,maxlen),chr(filler));
  1105.             p := p - 1
  1106.          end
  1107.       end
  1108.       else if key in adjusting then
  1109.          adjust_str (st,p,key,maxlen,col,row)
  1110.       else if key in terminating then
  1111.          do_fld_ctl (key)
  1112.    until key in terminating ;
  1113.    if st = '' then
  1114.       begin
  1115.       wd := 0 ;
  1116.       code := 0
  1117.    end
  1118.    else
  1119.       val (st, wd, code);              {Make string into word}
  1120.    gotoxy (col, row);
  1121.    if code = 0 then  {Conversion worked OK}
  1122.       write_word(wd,maxlen,col,row)
  1123.    else
  1124.       begin
  1125.       write ('** conversion error ', code);
  1126.       halt
  1127.    end
  1128. end ; {--- of read_word ---}
  1129.  
  1130. { -------------------------------------------------------------------------- }
  1131. PROCEDURE READ_BYTE(var bt:byte; maxlen,col,row:integer);
  1132. { Read byte.  This procedure gets input from the keyboard
  1133.   one character at a time and edits on the fly, rejecting
  1134.   invalid characters.  COL and ROW tell where to begin the data
  1135.   input field, and MAXLEN is the maximum length of the byte
  1136.   to be returned.
  1137.   }
  1138.  
  1139. const
  1140.    maxst : string[5] = '255' ;  { string representation of maxbyte }
  1141.  
  1142. var
  1143.    ch    : char ;       { character from keyboard }
  1144.    key,                 { ord(ch) }
  1145.    p     : integer ;    { position of char to left of cursor }
  1146.    st    : string;    { string representation of integer }
  1147.    code  :integer;       { result of string to byte conversion }
  1148.  
  1149.    procedure add_to_str ;
  1150.    begin
  1151.       if not (length(st) = maxlen) then
  1152.          begin
  1153.          p := p + 1 ;
  1154.          insert (ch,st,p);
  1155.          write (copy(st,p,maxlen))
  1156.       end
  1157.    end ; {--- of add_to_str---}
  1158.  
  1159. begin {--- read_byte ---}
  1160.    str (bt:maxlen, st);          { convert byte into string }
  1161.    st := purgech (st, ' ');
  1162.    st := stripch (st, '0');
  1163.    write_str (st, col, row);
  1164.    write (build_str(chr(filler),maxlen - length(st)));
  1165.    p := length(st);
  1166.    repeat
  1167.       gotoxy (col + p, row);
  1168.       keyin (ch);
  1169.       key := ord(ch);
  1170.       if key = $2D then                 { minus sign }
  1171.          begin
  1172.          if(pos('-',st) = 0) and (length(st) < maxlen)
  1173.             and (p = 0) then
  1174.             add_to_str
  1175.       end
  1176.       else if key in [$30 .. $39] then  {digits 0 - 9}
  1177.          begin
  1178.          add_to_str ;
  1179.          if (length(st) = 5) and (st > maxst) then
  1180.             begin
  1181.             delete (st,p,1);
  1182.             write (^H,copy(st,p,maxlen),chr(filler));
  1183.             p := p - 1
  1184.          end
  1185.       end
  1186.       else if key in adjusting then
  1187.          adjust_str (st,p,key,maxlen,col,row)
  1188.       else if key in terminating then
  1189.          do_fld_ctl (key)
  1190.    until key in terminating ;
  1191.    if st = '' then
  1192.       begin
  1193.       bt := 0 ;
  1194.       code := 0
  1195.    end
  1196.    else
  1197.       val (st, bt, code);              {Make string into word}
  1198.    gotoxy (col, row);
  1199.    if code = 0 then  {Conversion worked OK}
  1200.       write_byte(bt,maxlen,col,row)
  1201.    else
  1202.       begin
  1203.       write ('** conversion error ', code);
  1204.       halt
  1205.    end
  1206. end ; {--- of read_byte ---}
  1207.  
  1208. { -------------------------------------------------------------------------- }
  1209.  
  1210. function equal(r1,r2 : real) : boolean;
  1211. { tests functional equality of two real numbers -- 4/30/85 }
  1212. begin
  1213.    equal := abs(r1 - r2) < 1.0e-5
  1214. end ;  { function equal }
  1215.  
  1216. { -------------------------------------------------------------------------- }
  1217.  
  1218. function greater(r1,r2 : real) : boolean;
  1219. { tests functional inequality of two real numbers -- 5/1/85 }
  1220. begin
  1221.    greater := (r1 - r2) > 1.0e-5
  1222. end ;  { function greater }
  1223.  
  1224. { -------------------------------------------------------------------------- }
  1225.  
  1226. procedure read_real(var r:real ; maxlen,frac,col,row:integer);
  1227.  
  1228. { Read Real.  This procedure gets input from the keyboard
  1229.   one character at a time and edits on the fly, rejecting
  1230.   invalid characters.  COL and ROW tell where to begin the data
  1231.   input field; MAXLEN is the maximum length of the string
  1232.   representation of the real number, including sign and decimal
  1233.   point; FRAC is the fractional part, the number of digits to
  1234.   right of the decimal point.
  1235.  
  1236.   Note -- In Turbo the maximum number of significant digits in
  1237.   decimal (not scientific) representation is 11.  In TurboBCD,
  1238.   the maximum number of significant digits is 18.  It is the
  1239.   programmer's responsibility to limit input and computed output
  1240.   to the maximum significant digits.
  1241.  
  1242.   Revised 6/04/85 -- WPM }
  1243.  
  1244. var
  1245.    ch   : char ;       { Input character }
  1246.    key,                { ord(ch) }
  1247.    p    : integer ;    { position of char to left of cursor }
  1248.    st   : string;    { String representation of real number -- }
  1249.                        { max digits plus minus sign plus decimal point }
  1250.    code : integer ;    { Result of VAL conversion }
  1251.    rlen : integer ;    { Current length of st to right of dec. pt. }
  1252.    llen : integer ;    { Current length to left, including dec. pt. }
  1253.    maxl : integer ;    { Max allowable to left, including dec. pt. }
  1254.    posdec : integer ;  { position of decimal point in string }
  1255.  
  1256.    { +++++++++++++++++++++++++++++++++++++ }
  1257.  
  1258.    procedure compute_length ;
  1259.    { Compute length of left and right portions of string }
  1260.    begin
  1261.       posdec := pos('.',st);
  1262.       if posdec = 0 then                { If no dec. pt. ... }
  1263.          begin
  1264.          llen := length(st);      { the whole string is Left }
  1265.          rlen := 0                 { and none is Right }
  1266.       end
  1267.       else    {There is a decimal point ...}
  1268.          begin
  1269.          llen := posdec ;          { Left is all up to and incl. dec. pt. }
  1270.          rlen := length(st) - llen { Right is the rest }
  1271.       end
  1272.    end ; { proc compute_length }
  1273.  
  1274.    { +++++++++++++++++++++++++++++++++++++ }
  1275.  
  1276.    procedure add_to_str ;
  1277.  
  1278.       procedure add_it ;
  1279.       begin
  1280.          p := p + 1 ;
  1281.          insert (ch,st,p);
  1282.          write (copy(st,p,maxlen))
  1283.       end ;
  1284.  
  1285.    begin {add_to_str}
  1286.       posdec := pos ('.',st);
  1287.       if ch = '.' then        { Decimal point; if room, add it }
  1288.          begin
  1289.             if(posdec = 0) and (length(st) - p <= frac) then
  1290.                add_it
  1291.          end
  1292.                                { else it's not a decimal point }
  1293.                                { see if digit fits in whole part }
  1294.          else if((posdec = 0) and (llen < maxl - 1)) or
  1295.                 ((posdec > 0) and (llen < maxl) and (p < posdec)) then
  1296.                  add_it      { only dec. pt. allowed in pos. maxl }
  1297.                              { digit is candidate for fractional part }
  1298.          else if(not(posdec = 0)) and (p >= posdec) and (rlen < frac) then
  1299.                  add_it
  1300.    end ; {--- of add_to_str---}
  1301.  
  1302.    { +++++++++++++++++++++++++++++++++++++ }
  1303.  
  1304. begin {--- read_real ---}
  1305.               {Initialize}
  1306.    maxl  := maxlen - frac ;
  1307.                             {Set up string representation of real and }
  1308.                             {determine length of left & right portions}
  1309.    str(r:maxlen:frac,st);           {Make real into string}
  1310.    st := purgech (st, ' ');         {Purge all blanks}
  1311.    st := stripch (st, '0');         {Strip leading zeroes}
  1312.    if not (pos('.', st) = 0) then    {If there is a dec. pt ... }
  1313.       begin
  1314.       st := chopch (st, '0');  {Chop trailing zeroes}
  1315.       st := chopch (st, '.')    {and trailing dec. pt.}
  1316.    end ;
  1317.    compute_length ;
  1318.                             {Write string on console}
  1319.    write_str (st, col, row);
  1320.    write (build_str(chr(filler),maxlen - length(st)));
  1321.    p := length(st);
  1322.                 {Get input a character at a time & edit it}
  1323.    repeat
  1324.       gotoxy (col + p, row);
  1325.       compute_length ;
  1326.       if((posdec = 0) and (llen > maxl - 1)) or
  1327.          ((not (posdec = 0)) and (llen > maxl)) or
  1328.          (rlen > frac) then                   { if number is larger than }
  1329.          begin                                 { spec then delete it all }
  1330.          key := del_fld ;
  1331.          adjust_str (st,p,key,maxlen,col,row);
  1332.          gotoxy (col,row)
  1333.       end ;
  1334.       keyin (ch);
  1335.       key := ord(ch);
  1336.       if key = $2D  then                      { minus sign }
  1337.          begin
  1338.          if(pos('-',st) = 0) and (p = 0) and (((posdec = 0) and
  1339.             (llen < maxl - 1)) or
  1340.             ((not (posdec = 0)) and (llen < maxl))) then
  1341.             add_to_str
  1342.          end
  1343.          else if key in [$2E, $30 .. $39] then   { decimal point, numeric digits }
  1344.             add_to_str
  1345.          else if key in adjusting then
  1346.             adjust_str (st,p,key,maxlen,col,row)
  1347.          else if key in terminating then
  1348.             do_fld_ctl (key);
  1349.    until key in terminating ;
  1350.                         {Done getting input, now convert back to real}
  1351.    if(st = '') or (st = '.') or (st = '-') or (st = '-.') then
  1352.       begin {If null string ... }
  1353.       r := 0.0 ;                       {Make real zero}
  1354.       code := 0
  1355.    end
  1356.    else    {Not a null string}
  1357.       begin  { check if leading 0, val procedure requires it!!}
  1358.       if(st[1] = '.') then st := concat('0',st);
  1359.       val (st, r, code);              {Make string into real}
  1360.    end;
  1361.    gotoxy (col, row);
  1362.    if code = 0 then  {Conversion worked OK}
  1363.       write_real(r,maxlen,frac,col,row)     {Write the real on screen}
  1364.    else
  1365.       begin
  1366.       write ('** conversion error ', code);
  1367.       halt
  1368.    end
  1369. end ; {--- of read_real ---}
  1370.  
  1371. { -------------------------------------------------------------------------- }
  1372.