home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1986 / 12 / shammas.dec < prev   
Text File  |  1986-12-31  |  29KB  |  955 lines

  1.  
  2. Listing 1.  Contents of Turbo Pascal included ProcParm.INC file.
  3.  
  4. {                              ProcParm.INC           Version 1.1   86/05/07
  5.  
  6.  See ProcParm.PAS for an explanation.
  7.  
  8.  Author: Mike Babulic    Compuserve ID: 72307,314   FIDO: 134/1
  9.          3827 Charleswood Dr. N.W.
  10.          Calgary, Alberta,
  11.          CANADA
  12.          T2L 2C7
  13.  
  14. }
  15.  
  16. procedure Call_ProcParm;
  17.   begin
  18.   Inline
  19.    ($89/$EC/        {     MOV  SP,BP        ;Drop down one level }
  20.     $5D/            {     POP  BP        }
  21.     $8B/$66/$02/    {  SS:MOV  SP,[BP+2] ;Exchange Return Addr & Procedure Ptr}
  22.     $87/$66/$04/    {  SS:XCHG SP,[BP+4] }
  23.     $89/$66/$02     {  SS:MOV  [BP+2],SP }
  24.     )
  25.   end;
  26.  
  27. _____________________________________________________________________
  28.  
  29. Listing 2.  Contents of file ProcPar.QK.
  30.  
  31. {                           ProcParm.QK               Version 1.0   86/04/22
  32.  
  33.  
  34.  Author: Mike Babulic    Compuserve ID: 72307,314   FIDO: 134/1
  35.          3827 Charleswood Dr. N.W.
  36.          Calgary, Alberta,
  37.          CANADA
  38.          T2L 2C7
  39. }
  40.   Inline(
  41.     $8B/$66/$02/    {  SS:MOV  SP,[BP+2]    ;Exchange Return Addr & Procedure Ptr}
  42.     $87/$66/$04/    {  SS:XCHG SP,[BP+4] }
  43.     $89/$66/$02/    {  SS:MOV  [BP+2],SP }
  44.     $89/$EC/        {     MOV  SP,BP        ;Standard Turbo Return (if no Parameters)}
  45.     $5D/            {     POP  BP        }
  46.     $C3             {     RET               ;Near Return }
  47.     )
  48.  
  49. _____________________________________________________________________
  50.  
  51.  
  52. Listing 3.  Turbo Pascal demo program for procedural parameters.
  53.  
  54. program proc_param_demo;
  55.  
  56. CONST FIRST = 1;
  57.       LAST = 1000;
  58.  
  59.  
  60. TYPE Vector =  ARRAY [FIRST..LAST] OF INTEGER;
  61.  
  62. VAR A : Vector;
  63.     I, Start, Finish : INTEGER;
  64.  
  65. (*-------------------------------------------- Shell_Sort -------*)
  66.  
  67.  
  68. PROCEDURE Shell_Sort(VAR A : Vector);
  69.  
  70. VAR I, J, Offset, Skip, Tempo, NData : INTEGER;
  71.     In_Order : BOOLEAN;
  72.  
  73. BEGIN
  74.     NDATA := LAST - FIRST + 1;
  75.     Skip := NDATA;
  76.     WHILE Skip > 1 DO BEGIN
  77.         Skip := Skip DIV 2;
  78.         REPEAT
  79.             In_Order := TRUE;
  80.             FOR J := FIRST TO LAST - Skip DO BEGIN
  81.                 I := J + Skip;
  82.                 IF A[J] > A[I] THEN  BEGIN
  83.                     In_Order := FALSE;
  84.                     Tempo := A[I];
  85.                     A[I] := A[J];
  86.                     A[J] := Tempo
  87.                 END; (* IF *)
  88.             END; (* FOR *)
  89.         UNTIL In_Order;
  90.     END; (* WHILE *)
  91. END; (* Shell_Sort *)
  92.  
  93. (*-------------------------------------------- QuickSort -------*)
  94.  
  95. PROCEDURE QuickSort(VAR A : Vector);
  96.  
  97.     PROCEDURE Sort(Left, Right : INTEGER);
  98.     
  99.     VAR I, J, 
  100.         Pivot, Tempo : INTEGER;
  101.  
  102.     BEGIN
  103.         I := Left; J := Right;
  104.         Pivot := A[(Left + Right) DIV 2];
  105.         REPEAT
  106.             WHILE A[I] < Pivot DO I := I + 1;
  107.             WHILE Pivot < A[J] DO J := J - 1;
  108.             IF I <= J THEN BEGIN
  109.                 Tempo := A[I];
  110.                 A[I] := A[J];
  111.                 A[J] := Tempo;
  112.                 I := I + 1;
  113.                 J := J - 1
  114.             END; (* IF *)
  115.         UNTIL I > J;
  116.         IF Left < J THEN Sort(Left,J);
  117.         IF I < Right THEN Sort(I,Right);
  118.     END; (* Sort *)
  119.  
  120. BEGIN
  121.     Sort(FIRST, LAST)
  122. END; (* QuickSort *)    
  123.  
  124.  
  125. (*----------------- Use the ProcParm Procedure -----------------*)
  126.  
  127. {$I PROCPARM.INC}
  128.  
  129. PROCEDURE Dummy1(VAR A : Vector; P : INTEGER);
  130.  
  131. BEGIN
  132.   Call_ProcParm;
  133. END; (* Dummy1 *)
  134.  
  135.  
  136. PROCEDURE Sort1(VAR A : Vector; P : INTEGER);
  137.  
  138. BEGIN
  139.     Dummy1(A,P);
  140. END; (* Sort1 *)
  141.  
  142.  
  143. (*------------------------- Use Procparm.qk ---------------------*)
  144.  
  145. PROCEDURE Dummy2(VAR A : Vector; P : INTEGER);
  146.  
  147. BEGIN
  148.     {$I PROCPARM.QK}
  149. END; (* Dummy2 *)
  150.  
  151.  
  152. PROCEDURE Sort2(VAR A : Vector; P : INTEGER);
  153.  
  154. BEGIN
  155.     Dummy2(A, P)
  156. END; (* Sort2 *)
  157.  
  158. (*-------------------------------------------- Create_Array -------*)
  159.  
  160. PROCEDURE Create_Array(VAR A : Vector; Start, Finish : INTEGER);
  161. (* Create a reverse sorted array *)
  162.  
  163. VAR I : INTEGER;
  164.  
  165. BEGIN
  166.    FOR I := Start TO Finish DO
  167.         A[I] := Finish + 1 - I
  168. END; (* Create_Array *)
  169.  
  170.  
  171. (*-------------------------------------------- Display_Array -------*)
  172.  
  173. PROCEDURE Display_Array(VAR A : Vector; Start, Finish : INTEGER);
  174.  
  175. VAR I : INTEGER;
  176.     Dummy : CHAR;
  177.  
  178. BEGIN
  179.     WRITE('Press <CR> to view array members '); READLN(Dummy); WRITELN;
  180.     FOR I := Start TO Finish DO
  181.         WRITE(A[I]:8);
  182.  
  183.     WRITELN; WRITELN;
  184. END; (* Display_Array *)
  185.  
  186.  
  187. (*------------------------------------------------- Show_Time -------*)
  188.  
  189. PROCEDURE Show_Time;
  190. (* Procedure to dislplay time *)
  191. TYPE REGTYPE = record
  192.                  AX,BX,CX,DX,BP,
  193.                  DI,SI,DS,ED,FLAGS  : INTEGER
  194.                END;
  195.  
  196.      TIME_REC = RECORD
  197.                  HOUR, MIN, SEC, HSEC : BYTE
  198.               END;
  199.  
  200.  
  201. VAR REGISTER : REGTYPE;
  202.     AH       : BYTE;
  203.     TIME     : TIME_REC;
  204.  
  205. BEGIN
  206.  
  207.   AH  :=  $2C;
  208.  
  209.      WITH REGISTER, TIME DO BEGIN
  210.         AX:= AH SHL 8;
  211.         MSDOS(REGISTER);
  212.         HOUR :=  Hi(CX);
  213.         MIN  :=  Lo(CX);
  214.         SEC  :=  Hi(DX);
  215.         HSEC :=  Lo(DX);
  216.         WRITELN(' at  ',HOUR,' : ',MIN,' : ',SEC,'.',HSEC);
  217.       END;
  218. END; (* Show_Time *)
  219.  
  220.  
  221.  
  222. BEGIN
  223.    ClrScr;
  224.    WRITELN('Array has index range of ',FIRST,' to ',LAST);
  225.    WRITE('Enter index of first element to view '); READLN(Start); WRITELN;
  226.    WRITE('Enter index of last  element to view '); READLN(Finish); WRITELN;
  227.    IF Start < FIRST THEN Start := FIRST;
  228.    IF (Finish > LAST) THEN Finish := LAST;
  229.    IF Finish < Start THEN Finish := Start + (LAST - FIRST + 1) DIV 10;
  230.  
  231.    WRITELN('Using ProcParm Procedure '); WRITELN; WRITELN;
  232.    Create_Array(A, FIRST, LAST);
  233.    WRITELN('Using Shell Sort');
  234.    WRITE('Start '); Show_Time;
  235.    Sort1(A,Ofs(Shell_Sort));
  236.    WRITE('Finish'); Show_Time;
  237.    Display_Array(A,Start,Finish);
  238.  
  239.    Create_Array(A, FIRST, LAST);
  240.    WRITELN('Using QuickSort');
  241.    WRITE('Start '); Show_Time;
  242.    Sort1(A,Ofs(QuickSort));
  243.    WRITE('Finish'); Show_Time;
  244.    Display_Array(A,Start,Finish);
  245.  
  246.  
  247.    WRITELN('Using ProcParm.QK  '); WRITELN; WRITELN;
  248.    Create_Array(A, FIRST, LAST);
  249.    WRITELN('Using Shell Sort');
  250.    WRITE('Start '); Show_Time;
  251.    Sort2(A,Ofs(Shell_Sort));
  252.    WRITE('Finish'); Show_Time;
  253.    Display_Array(A,Start,Finish);
  254.  
  255.    Create_Array(A, FIRST, LAST);
  256.    WRITELN('Using QuickSort');
  257.    WRITE('Start '); Show_Time;
  258.    Sort2(A,Ofs(QuickSort));
  259.    WRITE('Finish'); Show_Time;
  260.    Display_Array(A,Start,Finish);
  261.  
  262. END.
  263.  
  264. _____________________________________________________________________
  265.  
  266. Listing 4.  Definition and implementation modules for BestFit library which 
  267. uses a local model InnerWorking.
  268.  
  269. DEFINITION MODULE BestFit;
  270.  
  271. EXPORT QUALIFIED Regression, Slope, Intercept, R2;
  272.  
  273. PROCEDURE Regression(VAR X, Y : ARRAY OF REAL; (* input *)
  274.                      N, LowerBound : CARDINAL  (* input *));
  275. (* Procedure to process arrays X and Y *)
  276.  
  277. PROCEDURE Slope() : REAL;
  278. (* Function that returns the slope of the best fit line *)
  279.  
  280. PROCEDURE Intercept() : REAL;
  281. (* Function that returns the intercept of the best fit line *)
  282.  
  283. PROCEDURE R2() : REAL;
  284. (* Function that returns the goodness of the best fit line *)
  285.  
  286. END BestFit.
  287.  
  288.  
  289. IMPLEMENTATION MODULE BestFit;
  290.  
  291. FROM MathLib0 IMPORT sqrt;
  292.  
  293. MODULE InnerWorking;
  294.  
  295. IMPORT sqrt;
  296. EXPORT Regression, Slope, Intercept, R2;
  297.  
  298. VAR Sum, SumX, SumXX, SumY, SumYY, SumXY, (* Stat summation *)
  299.     MeanX, MeanY, SdevX, SdevY : REAL;
  300.  
  301.  
  302. PROCEDURE Regression(VAR X, Y : ARRAY OF REAL; (* input *)
  303.                      N, LowerBound : CARDINAL  (* input *));
  304. (* Procedure to process arrays X and Y *)
  305.  
  306. VAR i : CARDINAL;
  307.     Xs, Ys : REAL;
  308.  
  309. BEGIN
  310.     (* Loop for stat summation *)
  311.     FOR i := 0 TO N-LowerBound DO
  312.         Xs := X[i]; Ys := Y[i];
  313.         Sum := Sum + 1.0;
  314.         SumX := SumX + Xs;
  315.         SumY := SumY + Ys;
  316.         SumXX := SumXX + Xs * Xs;
  317.         SumYY := SumYY + Ys * Ys;
  318.         SumXY := SumXY + Xs * Ys;
  319.     END;
  320.     (* Calculate intermediate results *)
  321.     MeanX := SumX / Sum;
  322.     MeanY := SumY / Sum;
  323.     SdevX := sqrt((SumXX - SumX * SumX / Sum)/(Sum - 1.0));
  324.     SdevY := sqrt((SumYY - SumY * SumY / Sum)/(Sum - 1.0));
  325. END Regression;
  326.  
  327. PROCEDURE Slope() : REAL;
  328. (* Function that returns the slope of the best fit line *)
  329.  
  330. BEGIN
  331.     IF Sum > 1.0 THEN 
  332.         RETURN (SumXY - MeanX * MeanY * Sum) / (SdevX * SdevX * (Sum - 1.0)) 
  333.     ELSE RETURN 0.0 (* default value for insufficient data *)
  334.     END;
  335. END Slope;
  336.  
  337. PROCEDURE Intercept() : REAL;
  338. (* Function that returns the intercept of the best fit line *)
  339. BEGIN
  340.     IF Sum > 1.0 THEN 
  341.         RETURN MeanY - Slope() * MeanX
  342.     ELSE RETURN 0.0 (* default value for insufficient data *)
  343.     END;
  344. END Intercept;
  345.  
  346. PROCEDURE R2() : REAL;
  347. (* Function that returns the goodness of the best fit line *)
  348.  
  349. VAR R : REAL;
  350.  
  351. BEGIN
  352.     IF Sum > 1.0 THEN 
  353.         R := SdevX / SdevY * Slope();
  354.         RETURN R * R
  355.     ELSE RETURN 0.0 (* default value for insufficient data *)
  356.     END;
  357. END R2;
  358.  
  359. BEGIN 
  360. (* Initilaize inner module by setting stat summation equal to zero *)
  361.     Sum := 0.0; SumXY := 0.0;
  362.     SumX := 0.0; SumXX := 0.0;
  363.     SumY := 0.0; SumYY := 0.0;
  364. END InnerWorking;
  365.  
  366. END BestFit.
  367.  
  368.  
  369. _____________________________________________________________________
  370.  
  371. Listing  5. Turbo Pascal program to demosntrate the first method for
  372. external menu storage.
  373.  
  374. program test_method1;
  375.  
  376. (* Program to test first method for external menu storage *)
  377.  
  378. TYPE
  379.      STRING14 = STRING[14];
  380.      STRING80 = STRING[80];
  381.      Screen_Image = ARRAY [0..24] OF STRING80;
  382.  
  383. VAR  Shift_Row, Shift_Col, Screen_Line_Count : INTEGER;
  384.      Screen_Line : Screen_Image;
  385.      MenuFile : STRING14;
  386.  
  387. PROCEDURE Read_Menu(Menu_Filename : STRING14;
  388.                     VAR Shift_Row, Shift_Col,
  389.                         Screen_Line_Count : INTEGER;
  390.                     VAR Screen_Line : Screen_Image);
  391. (* Procedure to read menu image from text file.  If file is *)
  392. (* nonexistant the program will halt.                       *)
  393.  
  394. CONST MAX_SYMBOL = 255;
  395.  
  396. TYPE CharSet = Set OF CHAR;
  397.      Symbol_Table = ARRAY [0..MAX_SYMBOL] OF INTEGER;
  398.  
  399.  
  400. VAR FileVar : TEXT;
  401.     Line : STRING80;
  402.     Table : Symbol_Table;
  403.     I, K, Error_Code  : INTEGER;
  404.     Symbol_Char : CHAR;
  405.     Operation_Set : CharSet;
  406.     Duplicate : BOOLEAN;
  407.  
  408. (*--------------------------------------------------------*)
  409.  
  410. PROCEDURE INC(VAR A : INTEGER);
  411. (* Increment integer by one *)
  412. BEGIN
  413.     A := A + 1
  414. END; (* INC *)
  415.  
  416. (*--------------------------------------------------------*)
  417.  
  418.  
  419. PROCEDURE Upcase_Str(VAR S : STRING80);
  420. (* Convert string to upercase *)
  421. VAR I : INTEGER;
  422. BEGIN
  423.     FOR I := 1 TO Length(S) DO
  424.         S[I] := Upcase(S[I]);
  425.  
  426. END; (* Upcase_Str *)
  427.  
  428. (*--------------------------------------------------------*)
  429.  
  430.  
  431. FUNCTION Extract_Number(Line : STRING80; Skip : INTEGER;
  432.                         VAR ErrorCode : INTEGER) : INTEGER;
  433. (* Function to extract an integer from a text line *)
  434. VAR J : INTEGER;
  435.  
  436. BEGIN
  437.     IF Skip > 0 THEN Delete(Line,1,Skip); (* Remove chars from string *)
  438.     (* Remove blanks *)
  439.     WHILE Line[1] = ' ' DO
  440.         Delete(Line,1,1);
  441.     (* END WHILE *)
  442.     Line := Line[1] + Line[2] + Line[3];
  443.     VAL(Line,J,Error_Code);
  444.     Extract_Number := J
  445. END; (* Extract_Number *)
  446.  
  447.  
  448. (*--------------------------------------------------------*)
  449.  
  450. PROCEDURE Build_Screen(Line : STRING80;
  451.                        VAR Screen_Line_Count : INTEGER;
  452.                        VAR Screen_Line : Screen_Image);
  453.  
  454. VAR J : INTEGER;
  455.     Ch : CHAR;
  456.  
  457. BEGIN
  458.     IF Length(Line) > 0 THEN BEGIN
  459.         FOR J := 1 TO Length(Line) DO BEGIN
  460.             Ch := Line[J];
  461.             IF Ch IN Operation_Set THEN
  462.                 Line[J] := CHR(Table[ORD(Ch)]);
  463.         END; (* FOR *)
  464.         Screen_Line[Screen_Line_Count] := Line;
  465.         INC(Screen_Line_Count);
  466.     END;
  467. END; (* Build_Screen *)
  468.  
  469.  
  470. BEGIN
  471.     Assign(FileVar, Menu_Filename);
  472.     Reset(FileVar);
  473.     IF (IOResult = 0)
  474.     THEN BEGIN
  475.         Operation_Set := ['!','@','#','$','%','^','&','/','\','|','-','_'];
  476.         (* Initialize screen line strings *)
  477.         FOR I := 0 TO 24 DO
  478.             Screen_Line[I] := '';
  479.         (* Initialize symbol table entries *)
  480.         FOR I := 0 TO MAX_SYMBOL DO
  481.             Table[I] := I;
  482.  
  483.         (* Read first line *)
  484.         READLN(FileVar, Line);
  485.         Upcase_Str(Line);
  486.         WHILE (NOT Eof(FIleVar)) AND (Line <> 'START') DO BEGIN
  487.             IF Line[1] IN Operation_set
  488.             THEN BEGIN
  489.                 Symbol_Char := Line[1];
  490.                 K := ORD(Symbol_Char);
  491.                 Table[K] := Extract_Number(Line,1,Error_code);
  492.                 IF (Error_Code > 0) OR
  493.                    (NOT (Table[K] IN [0..255])) THEN
  494.                         Table[K] := Ord('*');
  495.             END;
  496.             (* Read next line *)
  497.             READLN(FileVar, Line);
  498.         END; (* WHILE *)
  499.  
  500.         Screen_Line_Count := 0;
  501.         Shift_Col := 0;
  502.         Shift_Row := 0;
  503.         (* Read next line that may contain row/column offset *)
  504.         FOR I := 1 TO 2 DO BEGIN
  505.             READLN(FileVar, Line);
  506.             Upcase_Str(Line);
  507.             IF Pos('SHIFTROW',Line) > 0 THEN BEGIN
  508.                 Shift_Row := Extract_Number(Line,8,Error_Code);
  509.                 IF Error_Code > 0 THEN Shift_Row := 0;
  510.             END
  511.             ELSE IF Pos('SHIFTCOL',Line) > 0 THEN BEGIN
  512.                 Shift_Col := Extract_Number(Line,8,Error_Code);
  513.                 IF Error_Code > 0 THEN Shift_Col := 0;
  514.             END
  515.             ELSE Build_Screen(Line,Screen_Line_Count,Screen_Line);
  516.         END; (* FOR *)
  517.  
  518.         WHILE NOT EOF(FileVar) AND (Screen_Line_Count < 25) DO BEGIN
  519.             READLN(FileVar, Line);
  520.             Build_Screen(Line,Screen_Line_Count,Screen_Line);
  521.         END; (* WHILE *)
  522.         Close(FileVar);
  523.     END
  524.     ELSE Halt;
  525.  
  526. END; (* Read_Menu *)
  527.  
  528.  
  529. (*----------------------------------------------------------------*)
  530.  
  531. PROCEDURE DISP_STR(S : STRING80; Row, Col : INTEGER);
  532. (* Procedure to write a string to the screen memory *)
  533.  
  534. TYPE SCREEN80 = ARRAY [1..25,1..80,1..2] OF CHAR;
  535.  
  536. VAR MONODISP : SCREEN80 Absolute $B000:0000;
  537.     COLODISP : SCREEN80 Absolute $B800:0000;
  538.     I, J, Mode : INTEGER;
  539.  
  540. BEGIN
  541.     J := Length(S);
  542.     Mode := MEM[$0040:$0049];
  543.     IF Mode IN [2..3] THEN
  544.         FOR I := 1 TO J DO
  545.             COLODISP[Row,Col + I - 1,1] := S[I];
  546.     IF Mode = 7 THEN
  547.         FOR I := 1 TO J DO
  548.             MONODISP[Row,Col + I -1,1] := S[I];
  549. END;
  550.  
  551. (*----------------------------------------------------------------*)
  552.  
  553.  
  554. PROCEDURE Show_Menu(VAR Shift_Row, Shift_Col, Screen_Line_Count : INTEGER;
  555.                     VAR Screen_Line : Screen_Image);
  556.  
  557. VAR I : INTEGER;
  558.  
  559. BEGIN
  560.     FOR I := 0 TO Screen_Line_Count DO
  561.         DISP_STR(Screen_Line[I],(I+Shift_Row+1),(1+Shift_Col));
  562.  
  563. END; (* Show_Menu *)
  564.  
  565. BEGIN
  566.    ClrScr;
  567.    WRITE('Enter filename '); READLN(MenuFile); WRITELN;
  568.    Read_Menu(MenuFile, Shift_Row, Shift_Col, 
  569.              Screen_Line_Count,  Screen_Line);
  570.    Show_Menu(Shift_Row, Shift_Col,Screen_Line_Count,  Screen_Line);
  571.    REPEAT UNTIL KeyPressed;
  572. END.
  573.  
  574.  
  575.  
  576.  
  577. _____________________________________________________________________
  578.  
  579. Listing 6. Turbo Pascal program to demosntrate the second method for
  580. external menu storage.
  581.  
  582. program test_method2;
  583.  
  584. (* Program to test the second method for external menu storage *)
  585.  
  586. TYPE
  587.      STRING14 = STRING[14];
  588.      LSTRING = STRING[255];
  589.      Screen_Image = ARRAY [0..24] OF LSTRING;
  590.  
  591. VAR  Shift_Row, Shift_Col, Screen_Line_Count : INTEGER;
  592.      Screen_Line : Screen_Image;
  593.      MenuFile : STRING14;
  594.  
  595. PROCEDURE Read_Menu(Menu_Filename : STRING14;
  596.                     VAR Shift_Row, Shift_Col,
  597.                         Screen_Line_Count : INTEGER;
  598.                     VAR Screen_Line : Screen_Image);
  599. (* Procedure to read menu image from text file.  If file is *)
  600. (* nonexistant the program will halt.                       *)
  601.  
  602. CONST MAX_SYMBOL = 255;
  603.  
  604. TYPE CharSet = Set OF CHAR;
  605.      Symbol_Table = ARRAY [0..MAX_SYMBOL] OF INTEGER;
  606.  
  607.  
  608. VAR FileVar : TEXT;
  609.     Line : LSTRING;
  610.     Table : Symbol_Table;
  611.     I, K, Error_Code,
  612.     Upper_Left_Corner, Upper_Right_Corner, Lower_Left_Corner,
  613.     Lower_Right_Corner, Horizontal_Line, Vertical_Line,
  614.     Cross_Bar, Left_Tee, Right_Tee,
  615.     Up_Tee, Down_Tee,
  616.     Left_Edge, Right_Edge,
  617.     Vertical_Frames, Horizontal_Frames, Frame_Code,
  618.     Number : INTEGER;
  619.     Symbol_Char : CHAR;
  620.  
  621. (*--------------------------------------------------------*)
  622.  
  623. PROCEDURE INC(VAR A : INTEGER);
  624. (* Increment integer by one *)
  625. BEGIN
  626.     A := A + 1
  627. END; (* INC *)
  628.  
  629. (*--------------------------------------------------------*)
  630.  
  631.  
  632. PROCEDURE Upcase_Str(VAR S : LSTRING);
  633. (* Convert string to upercase *)
  634. VAR I : INTEGER;
  635. BEGIN
  636.     FOR I := 1 TO Length(S) DO
  637.         S[I] := Upcase(S[I]);
  638.  
  639. END; (* Upcase_Str *)
  640.  
  641. (*--------------------------------------------------------*)
  642.  
  643.  
  644. FUNCTION Extract_Number(Line : LSTRING; Skip : INTEGER) : INTEGER;
  645. (* Function to extract an integer from a text line *)
  646. VAR J, SUM : INTEGER;
  647.  
  648. BEGIN
  649.     IF Skip > 0 THEN Delete(Line,1,Skip); (* Remove chars from string *)
  650.     (* Remove blanks *)
  651.     WHILE Line[1] = ' ' DO
  652.         Delete(Line,1,1);
  653.     (* END WHILE *)
  654.     SUM := 0;
  655.     J := 1;
  656.     WHILE (J <= Length(Line)) AND (Line[J] IN ['0'..'9']) DO BEGIN
  657.         SUM := 10 * SUM + ORD(Line[J]) - ORD('0');
  658.         INC(J)
  659.     END;
  660.  
  661.     Extract_Number := SUM
  662. END; (* Extract_Number *)
  663.  
  664.  
  665. (*--------------------------------------------------------*)
  666.  
  667. FUNCTION Get_Char_Code(S : LSTRING) : INTEGER;
  668. (* Function to interpret frame symbol and return its ASCII code *)
  669.  
  670. VAR I, ASCII_Code : INTEGER;
  671.  
  672. BEGIN
  673.     IF S = 'ULC' THEN  ASCII_Code := Upper_Left_Corner
  674.     ELSE IF S = 'URC' THEN  ASCII_Code := Upper_Right_Corner
  675.     ELSE IF S = 'LLC' THEN  ASCII_Code := Lower_Left_Corner
  676.     ELSE IF S = 'LRC' THEN  ASCII_Code := Lower_Right_Corner
  677.     ELSE IF S = 'HLN' THEN  ASCII_Code := Horizontal_Line
  678.     ELSE IF S = 'VLN' THEN  ASCII_Code := Vertical_Line
  679.     ELSE IF S = 'CRS' THEN  ASCII_Code := Cross_Bar
  680.     ELSE IF S = 'LFT' THEN  ASCII_Code := Left_Tee
  681.     ELSE IF S = 'RTT' THEN  ASCII_Code := Right_Tee
  682.     ELSE IF S = 'UPT' THEN  ASCII_Code := Up_Tee
  683.     ELSE IF S = 'DNT' THEN  ASCII_Code := Down_Tee
  684.     ELSE ASCII_Code := ORD('-'); (* error value return 'A' *)
  685.     Get_Char_Code := ASCII_Code;
  686. END; (* Get_Char_Code *)
  687.  
  688.  
  689. (*--------------------------------------------------------*)
  690.  
  691. PROCEDURE Build_Screen(Line : LSTRING;
  692.                        VAR Screen_Line_Count : INTEGER;
  693.                        VAR Screen_Line : Screen_Image);
  694.  
  695. VAR I, J, K, Long, Count : INTEGER;
  696.     Ch, Symbol : CHAR;
  697.     Build_Line, Sub_String : LSTRING;
  698.  
  699.  
  700. BEGIN
  701.     IF Length(Line) > 0 THEN BEGIN
  702.         J := 1;
  703.         Long := Length(Line);
  704.         Build_Line := '';
  705.         Count := 0;
  706.         WHILE J <= Long DO BEGIN
  707.             Ch := UpCase(Line[J]);
  708.             CASE Ch OF
  709.                 '@' : BEGIN
  710.                         Sub_String := '';
  711.                         FOR I := 1 TO 3 DO
  712.                             Sub_String := Sub_String + Line[J+I];
  713.                         J := J + 3; (* advance character pointer *)
  714.                         Symbol := CHR(Get_Char_Code(Sub_String));
  715.                         Build_Line := Build_Line + Symbol;
  716.                         INC(Count);
  717.                       END;
  718.                 'D' : BEGIN (* Duplicate a frame character *)
  719.                         Sub_String := Line[J+1] + Line[J+2] + Line[J+3];
  720.                         J := J + 4; (* advance character pointer *)
  721.                         Symbol := CHR(Get_Char_Code(Sub_String));
  722.                         Sub_String := Line[J] + Line[J+1];
  723.                         J := J + 1;
  724.                         K := Extract_Number(Sub_String,0);
  725.                         IF (K > 0) THEN BEGIN
  726.                             Count := Count + K;
  727.                             FOR I := 1 TO K DO
  728.                                 Build_Line := Build_Line + Symbol;
  729.                         END; (* IF *)
  730.                       END;
  731.                 'S' : BEGIN (* Skip # column positions *)
  732.                         Sub_String := Line[J+1] + Line[J+2];
  733.                         J := J + 2; (* advance character pointer *)
  734.                         K := Extract_Number(Sub_String,0);
  735.                         IF (K > 0) THEN BEGIN
  736.                             Count := Count + K;
  737.                             FOR I  := 1 TO K DO
  738.                                 Build_Line := Build_Line + ' ';
  739.                         END; (* IF*)
  740.                       END;
  741.                 '"' : BEGIN (* Display text *)
  742.                         INC(J);
  743.                         WHILE (Line[J] <> '|') AND (J <= Long) DO BEGIN
  744.                             Build_Line := Build_Line + Line[J];
  745.                             INC(J); INC(Count)
  746.                         END; (* WHILE *)
  747.                         Count := COunt - 1;
  748.                       END;
  749.                 '#' : BEGIN
  750.                         Sub_String := Line[J+1] + Line[J+2];
  751.                         J := J + 2; (* advance character pointer *)
  752.                         K := Extract_Number(Sub_String,0);
  753.                         IF (K < Right_Edge) AND (Count < K) THEN BEGIN
  754.                             FOR I := 1 TO K - Count DO
  755.                                 Build_Line := Build_Line + ' ';
  756.                             Count := K;
  757.                         END; (* IF *)
  758.                       END;
  759.                 'V' : BEGIN (* Draw vertical edges *)
  760.                         Build_Line := CHR(Vertical_Line);
  761.                         FOR I := Left_Edge+1 TO Right_Edge-1 DO
  762.                             Build_Line := Build_Line + ' ';
  763.                         Build_Line := Build_Line + CHR(Vertical_Line);
  764.                       END;
  765.                 'H' : BEGIN (* Draw horizontal edge *)
  766.                         Symbol := CHR(Horizontal_Line);
  767.                         FOR I := Left_Edge+1 TO Right_Edge-1 DO
  768.                             Build_Line := Build_Line + Symbol;
  769.                       END;
  770.             END; (* CASE *)
  771.             INC(J);
  772.             WHILE Line[J] = ' ' DO   INC(J);
  773.         END; (* FOR *)
  774.         Screen_Line[Screen_Line_Count] := Build_Line;
  775.         INC(Screen_Line_Count);
  776.     END;
  777. END; (* Build_Screen *)
  778.  
  779.  
  780. BEGIN
  781.     Assign(FileVar, Menu_Filename);
  782.     (*$I-*) Reset(FileVar); (*$I+*)
  783.     IF (IOResult = 0)
  784.     THEN BEGIN
  785.         (* Initialize screen line strings *)
  786.         FOR I := 0 TO 24 DO
  787.             Screen_Line[I] := '';
  788.         Left_Edge := 1;
  789.         Right_Edge := 80;
  790.         Vertical_Frames := 2;
  791.         Horizontal_Frames := 2;
  792.  
  793.         (* Read first line *)
  794.         READLN(FileVar, Line);
  795.         Upcase_Str(Line);
  796.         WHILE (NOT Eof(FileVar)) AND (Line <> 'START') DO BEGIN
  797.             Symbol_Char := Line[1];
  798.             K := ORD(Symbol_Char);
  799.             IF Symbol_Char IN ['R','L','H','V'] THEN BEGIN
  800.                 Number := Extract_Number(Line,1);
  801.                 IF (Error_Code = 0) THEN
  802.                     CASE Symbol_Char OF
  803.                         'R' : Right_Edge := Number;
  804.                         'L' : Left_Edge  := Number;
  805.                         'H' : IF (Number IN [1..2]) THEN
  806.                                 Horizontal_Frames := Number;
  807.                         'V' : IF (Number IN [1..2]) THEN
  808.                                 Vertical_Frames := Number;
  809.                     END; (* CASE *)
  810.             END; (* IF *)
  811.             (* Read next line *)
  812.             READLN(FileVar, Line);
  813.         END; (* WHILE *)
  814.  
  815.         (* Check edges *)
  816.         IF (Right_Edge - Left_Edge) <= 4 THEN BEGIN
  817.             Left_Edge := 1;
  818.             Right_Edge := 80;
  819.         END; (* IF *)
  820.  
  821.         Frame_Code := 10 * Horizontal_Frames + Vertical_Frames;
  822.         (* Select frame type *)
  823.         CASE Frame_Code OF
  824.             11 : BEGIN
  825.                     Upper_Left_Corner := 218;
  826.                     Upper_Right_Corner := 191;
  827.                     Lower_Left_Corner := 192;
  828.                     Lower_Right_Corner := 217;
  829.                     Horizontal_Line := 196;
  830.                     Vertical_Line := 179;
  831.                     Cross_Bar := 197;
  832.                     Left_Tee := 195;
  833.                     Right_Tee := 180;
  834.                     Up_Tee := 193;
  835.                     Down_Tee := 194;
  836.                  END;
  837.             12 : BEGIN
  838.                     Upper_Left_Corner := 214;
  839.                     Upper_Right_Corner := 183;
  840.                     Lower_Left_Corner := 211;
  841.                     Lower_Right_Corner := 189;
  842.                     Horizontal_Line := 196;
  843.                     Vertical_Line := 186;
  844.                     Cross_Bar := 215;
  845.                     Left_Tee := 199;
  846.                     Right_Tee := 182;
  847.                     Up_Tee := 208;
  848.                     Down_Tee := 210;
  849.                  END;
  850.             21 : BEGIN
  851.                     Upper_Left_Corner := 213;
  852.                     Upper_Right_Corner := 184;
  853.                     Lower_Left_Corner := 212;
  854.                     Lower_Right_Corner := 190;
  855.                     Horizontal_Line := 205;
  856.                     Vertical_Line := 179;
  857.                     Cross_Bar := 216;
  858.                     Left_Tee := 198;
  859.                     Right_Tee := 181;
  860.                     Up_Tee := 207;
  861.                     Down_Tee := 209;
  862.                  END;
  863.             22 : BEGIN
  864.                     Upper_Left_Corner := 201;
  865.                     Upper_Right_Corner := 187;
  866.                     Lower_Left_Corner := 200;
  867.                     Lower_Right_Corner := 188;
  868.                     Horizontal_Line := 205;
  869.                     Vertical_Line := 186;
  870.                     Cross_Bar := 206;
  871.                     Left_Tee := 204;
  872.                     Right_Tee := 185;
  873.                     Up_Tee := 202;
  874.                     Down_Tee := 203;
  875.                  END;
  876.         END; (* CASE *)
  877.  
  878.         Screen_Line_Count := 0;
  879.         Shift_Col := 0;
  880.         Shift_Row := 0;
  881.         (* Read next line that may contain row/column offset *)
  882.         FOR I := 1 TO 2 DO BEGIN
  883.             READLN(FileVar, Line);
  884.             Upcase_Str(Line);
  885.             IF Pos('SHIFTROW',Line) > 0 THEN BEGIN
  886.                 Shift_Row := Extract_Number(Line,8);
  887.                 IF Error_Code > 0 THEN Shift_Row := 0;
  888.             END
  889.             ELSE IF Pos('SHIFTCOL',Line) > 0 THEN BEGIN
  890.                 Shift_Col := Extract_Number(Line,8);
  891.                 IF Error_Code > 0 THEN Shift_Col := 0;
  892.             END
  893.             ELSE Build_Screen(Line,Screen_Line_Count,Screen_Line);
  894.         END; (* FOR *)
  895.  
  896.         WHILE NOT EOF(FileVar) AND (Screen_Line_Count < 25) DO BEGIN
  897.             READLN(FileVar, Line);
  898.             Build_Screen(Line,Screen_Line_Count,Screen_Line);
  899.         END; (* WHILE *)
  900.         Screen_Line_Count := Screen_Line_Count - 1;
  901.         Close(FileVar);
  902.     END
  903.     ELSE BEGIN
  904.         WRITE(^G^G);
  905.         Halt;
  906.     END;
  907. END; (* Read_Menu *)
  908.  
  909.  
  910. (*----------------------------------------------------------------*)
  911.  
  912. PROCEDURE DISP_STR(S : LSTRING; Row, Col : INTEGER);
  913. (* Procedure to write a string to the screen memory *)
  914.  
  915. TYPE SCREEN80 = ARRAY [1..25,1..80,1..2] OF CHAR;
  916.  
  917. VAR MONODISP : SCREEN80 Absolute $B000:0000;
  918.     COLODISP : SCREEN80 Absolute $B800:0000;
  919.     I, J, Mode : INTEGER;
  920.  
  921. BEGIN
  922.     J := Length(S);
  923.     Mode := MEM[$0040:$0049];
  924.     IF Mode IN [2..3] THEN
  925.         FOR I := 1 TO J DO
  926.             COLODISP[Row,Col + I - 1,1] := S[I];
  927.     IF Mode = 7 THEN
  928.         FOR I := 1 TO J DO
  929.             MONODISP[Row,Col + I -1,1] := S[I];
  930. END; (* DISP_STR *)
  931.  
  932. (*----------------------------------------------------------------*)
  933.  
  934.  
  935. PROCEDURE Show_Menu(VAR Shift_Row, Shift_Col, Screen_Line_Count : INTEGER;
  936.                     VAR Screen_Line : Screen_Image);
  937.  
  938. VAR I : INTEGER;
  939.  
  940. BEGIN
  941.     FOR I := 0 TO Screen_Line_Count DO
  942.         DISP_STR(Screen_Line[I],(I+Shift_Row+1),(1+Shift_Col));
  943.  
  944. END; (* Show_Menu *)
  945.  
  946. (*----------------------------------------------------------------*)
  947.  
  948. BEGIN (*-------------- M A I N ----------------*)
  949.    ClrScr;
  950.    WRITE('Enter filename '); READLN(MenuFile); WRITELN;
  951.    Read_Menu(MenuFile, Shift_Row, Shift_Col, 
  952.              Screen_Line_Count,  Screen_Line);
  953.    Show_Menu(Shift_Row, Shift_Col,Screen_Line_Count,  Screen_Line);
  954.    REPEAT UNTIL KeyPressed;
  955. END.