home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / pas / passmpl.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  38.8 KB  |  1,094 lines

  1.  \SAMPCODE
  2.  \SAMPCODE\PASCAL
  3.  \SAMPCODE\PASCAL\DEMOEXEC.PAS
  4.  
  5.  {*      DEMOEXEC.PAS - demonstration progam for calling C library functions
  6.   *
  7.   *      Microsoft Pascal release 3.32 can call large model C functions.
  8.   *      Please read PASEXEC.INC for more details on interlanguage calling.
  9.   *
  10.   *      To compile and link DEMOEXEC.PAS
  11.   *
  12.   *      pas1 demoexec;
  13.   *      pas2
  14.   *      link demoexec,,,cexec;          (must search CEXEC.LIB)
  15.   *}
  16.  
  17.  program demoexec(input,output);
  18.  
  19.  {$include : 'pasexec.inc'}
  20.  
  21.  var
  22.          i : integer;
  23.          NULL : integer4;
  24.  
  25.  value
  26.          NULL := 0;
  27.  
  28.  begin
  29.  
  30.  {*      invoke command.com with a command line
  31.   *
  32.   *              dir *.pas
  33.   *}
  34.          i := system(ads('dir *.pas'*chr(0)));
  35.          writeln (output,'system return code = ',i);
  36.          writeln (output,' ');
  37.  
  38.  {*      invoke a child process
  39.   *
  40.   *              exemod          (display usage line only)
  41.   *}
  42.          i := spawnlp(0,ads('exemod'*chr(0)),ads('exemod'*chr(0)),NULL);
  43.          writeln (output,'spawnlp return code =',i);
  44.          writeln (output,' ');
  45.  
  46.  {*      invoke an overlay process (chaining)
  47.   *
  48.   *              exemod demoexec.exe
  49.   *}
  50.          i := spawnlp(_p_overlay,ads('exemod'*chr(0)),ads('exemod'*chr(0)),
  51.                       ads('demoexec.exe'*chr(0)),NULL);
  52.  
  53.  {*      we should never see this if spawnlp (overlay) is successful
  54.   *}
  55.          writeln (output,'spawnlp return code =',i);
  56.          writeln (output,' ');
  57.  
  58.  end.
  59.  
  60.  \SAMPCODE\PASCAL\PRIMES.PAS
  61.  
  62.  { Prime number generator }
  63.  { Generates all the primes between 0 and 10000 }
  64.  program primes(output);
  65.  
  66.    var
  67.      prime:      integer;
  68.      rprime:     real4;
  69.      i:          integer;
  70.      sqrtp:      integer;
  71.      notprime:   boolean;
  72.  
  73.    begin
  74.      writeln('      2');
  75.      writeln('      3');
  76.      prime := 5;
  77.      repeat
  78.        rprime := prime;
  79.        sqrtp := trunc(sqrt(rprime) + 1.0);
  80.        i := 1;
  81.        notprime := false;
  82.        while (i < sqrtp) and (not notprime) do
  83.          begin
  84.            i := i + 2;
  85.            notprime := (prime mod i = 0);
  86.          end;
  87.        if (not notprime) then writeln(prime:6);
  88.        prime := prime + 2;
  89.      until (prime > 10000);
  90.    end.
  91.  \SAMPCODE\PASCAL\SORT.PAS
  92.  
  93.  { Bubble Sort Demonstration Program }
  94.  {       Microsoft Pascal 3.1        }
  95.  
  96.  { The main routine reads from the terminal an array  }
  97.  { of ten real numbers and calls the procedure BUBBLE }
  98.  { to sort them.                                      }
  99.  
  100.  program BubbleSort(input,output);
  101.  
  102.    const
  103.      TABLEN = 10;                    { Length of reals table }
  104.  
  105.    type
  106.      TABLE = array[1 .. TABLEN] of real4;
  107.                                      { Table of reals type }
  108.    var
  109.      R:          TABLE;              { The table itself }
  110.      i:          integer;            { Table index }
  111.  
  112.    procedure Bubble(var t: TABLE);   { The sorting routine }
  113.      var
  114.        i:        integer;            { Index variable }
  115.        j:        integer;            { Index variable }
  116.        temp:     real4;              { Exchange variable }
  117.      begin
  118.        for i := 1 to 9 do            { Outer loop }
  119.          begin
  120.            for j := i + 1 to 10 do   { Inner loop }
  121.              begin
  122.                if (t[i] > t[j]) then { Sort in ascending order }
  123.                  begin
  124.                    temp := t[i];     { Perform the }
  125.                    t[i] := t[j];     { exchange of }
  126.                    t[j] := temp;     { table elememts }
  127.                  end;
  128.              end;
  129.          end;
  130.      end;
  131.  
  132.    begin
  133.      writeln(' Bubble Sort Demonstration Program.');
  134.      for i := 1 to 10 do             { Loop to read in reals }
  135.        begin
  136.          writeln(' Please input real number no. ',i:2);
  137.                                      { Prompt user }
  138.          readln(R[i]);               { Read response }
  139.        end;
  140.      Bubble(R);                      { Sort the array }
  141.      writeln;                        { Skip a line }
  142.      writeln(' The sorted ordering from lowest to highest is:');
  143.                                      { Print a header }
  144.      for i := 1 to 10 do             { Loop to print array }
  145.        begin
  146.          write(R[i]);                { Write a number }
  147.          if (i mod 5 = 0) then writeln;
  148.                                      { Five numbers per line }
  149.        end;
  150.    end.
  151.  \SAMPCODE\PASCAL\SORTDEMO.PAS
  152.  
  153.  (*                                 SORTDEMO
  154.   * This program graphically demonstrates six common sorting algorithms.  It
  155.   * prints 25 or 43 horizontal bars, all of different lengths and all in rando
  156.   * order, then sorts the bars from smallest to longest.
  157.   *
  158.   * The program also uses sound statements to generate different pitches,
  159.   * depending on the location of the bar being printed. Note that the sound
  160.   * statements delay the speed of each sorting algorithm so you can follow
  161.   * the progress of the sort. Therefore, the times shown are for comparison
  162.   * only. They are not an accurate measure of sort speed.
  163.   *
  164.   * If you use these sorting routines in your own programs, you may notice
  165.   * a difference in their relative speeds (for example, the exchange
  166.   * sort may be faster than the shell sort) depending on the number of
  167.   * elements to be sorted and how "scrambled" they are to begin with.
  168.   *)
  169.  
  170.  PROGRAM SortDemo;
  171.  
  172.  CONST
  173.      INCL_SUB           = 1;        (* Include KBD, VIO, and MOU definitions *
  174.      INCL_DOSDATETIME   = 1;        (* DOS date/time definitions *)
  175.      INCL_DOSPROCESS    = 1;        (* Some DOS process definitions *)
  176.      INCL_NOCOM         = 1;        (* Don't include default sections of DOS *
  177.  
  178.  (*
  179.   * Define the data type used to hold the information for each colored bar:
  180.   *)
  181.  TYPE
  182.      SortType = RECORD
  183.                  Length: BYTE;   (* Bar length (the element compared
  184.                                   * in the different sorts)             *)
  185.                  ColorVal: BYTE; (* Bar color                           *)
  186.                 END;
  187.  
  188.      CELLINFO = RECORD
  189.              Char: BYTE;
  190.              Attr: BYTE;
  191.             END;
  192.  
  193.  (* Declare global constants:
  194.   *)
  195.  CONST
  196.      BLOCK = 223;
  197.      ESC = CHR(27);
  198.      FIRSTMENU = 1;
  199.      LEFTCOLUMN = 48;
  200.      NLINES = 18;
  201.      NULL = 0;
  202.      SPACE = 32;
  203.      WIDTH = 80 - LEFTCOLUMN;
  204.      WHITE = 15;
  205.  
  206.  (* Declare global variables, and allocate storage space for them.  SortArray
  207.   * and SortBackup are both arrays of the data type SortType defined above:
  208.   *)
  209.  VAR
  210.      sTime,wTime: _DATETIME;
  211.      KeyInfo: _KBDKEYINFO;
  212.      wMode: _VIOMODEINFO;
  213.      SortArray, SortBackup: ARRAY[1..43] OF SortType;
  214.      Menu: ARRAY[1..NLINES] OF LSTRING(30);
  215.      Sound: BOOLEAN;
  216.      curSelect, MaxBars, MaxColors: INTEGER;
  217.      oTime, nTime, Pause, RandSeed: INTEGER4;
  218.      ret: WORD;
  219.  
  220.  (* Data statements for the different options printed in the sort menu:
  221.   *)
  222.  
  223.  VALUE
  224.      Menu[1] := '     PASCAL Sorting Demo';
  225.      Menu[2] := ' ';
  226.      Menu[3] := 'Insertion';
  227.      Menu[4] := 'Bubble';
  228.      Menu[5] := 'Heap';
  229.      Menu[6] := 'Exchange';
  230.      Menu[7] := 'Shell';
  231.      Menu[8] := 'Quick';
  232.      Menu[9] := ' ';
  233.      Menu[10] := 'Toggle Sound: ';
  234.      Menu[11] := ' ';
  235.      Menu[12] := 'Pause Factor: ';
  236.      Menu[13] := '<   (Slower)';
  237.      Menu[14] := '>   (Faster)';
  238.      Menu[15] := ' ';
  239.      Menu[16] := 'Type first character of';
  240.      Menu[17] := 'choice ( I B H E S Q T < > )';
  241.      Menu[18] := 'or ESC key to end program: ';
  242.      wMode.cb := SIZEOF(wMode);
  243.  
  244.  FUNCTION GETMQQ (Wants:WORD):ADSMEM; EXTERN;
  245.  FUNCTION RandInt (Lower,Upper:INTEGER):INTEGER; FORWARD;
  246.  PROCEDURE BoxInit; FORWARD;
  247.  PROCEDURE BubbleSort; FORWARD;
  248.  PROCEDURE DrawFrame (Top,Left,Width,Height:INTEGER); FORWARD;
  249.  PROCEDURE ElapsedTime (CurrentRow:INTEGER); FORWARD;
  250.  PROCEDURE ExchangeSort; FORWARD;
  251.  PROCEDURE HeapSort; FORWARD;
  252.  PROCEDURE Initialize; FORWARD;
  253.  PROCEDURE InsertionSort; FORWARD;
  254.  PROCEDURE PercolateDown (MaxLevel:INTEGER); FORWARD;
  255.  PROCEDURE PercolateUp (MaxLevel:INTEGER); FORWARD;
  256.  PROCEDURE PrintOneBar (Row:INTEGER); FORWARD;
  257.  PROCEDURE QuickSort (Low,High:INTEGER); FORWARD;
  258.  PROCEDURE Reinitialize; FORWARD;
  259.  PROCEDURE ShellSort; FORWARD;
  260.  FUNCTION Screen (ACTION:BYTE):BOOLEAN; FORWARD;
  261.  PROCEDURE SortMenu; FORWARD;
  262.  PROCEDURE SwapBars (Row1,Row2:INTEGER); FORWARD;
  263.  PROCEDURE cls; FORWARD;
  264.  PROCEDURE swaps (VAR one, two:SortType); FORWARD;
  265.  
  266.  (* =============================== BoxInit ==================================
  267.   *    Calls the DrawFrame procedure to draw the frame around the sort menu,
  268.   *    then prints the different options stored in the Menu array.
  269.   * ==========================================================================
  270.   *)
  271.  PROCEDURE BoxInit;
  272.  VAR
  273.      Color: BYTE;
  274.      i: INTEGER;
  275.      Factor: LSTRING(3);
  276.  
  277.  BEGIN
  278.      Color := WHITE;
  279.      DrawFrame(1, LEFTCOLUMN - 3, WIDTH + 3, 22);
  280.  
  281.      FOR i := 1 TO NLINES DO
  282.          ret := VioWrtCharStrAtt(ads Menu[i,1], Menu[i].len,
  283.                                 FIRSTMENU + i, LEFTCOLUMN, Color, 0);
  284.  
  285.     (* Print the current value for Sound:
  286.      *)
  287.      IF (Sound) THEN
  288.          ret := VioWrtCharStrAtt(ads 'ON ',3, 11, LEFTCOLUMN + 14, Color, 0)
  289.      ELSE
  290.          ret := VioWrtCharStrAtt(ads 'OFF',3, 11, LEFTCOLUMN + 14, Color, 0);
  291.  
  292.      EVAL(ENCODE(Factor,Pause DIV 30:3));
  293.      ret := VioWrtCharStrAtt(ads Factor[1], 3, 13, LEFTCOLUMN + 14, Color, 0);
  294.  
  295.     (* Erase the speed option if the length of the Pause is at a limit
  296.      *)
  297.      IF (Pause = 900) THEN
  298.          ret := VioWrtCharStrAtt(ads '            ',12,14,LEFTCOLUMN,Color,0)
  299.      ELSE IF (Pause = 0) THEN
  300.          ret := VioWrtCharStrAtt(ads '            ',12,15,LEFTCOLUMN,Color,0);
  301.  
  302.  END;
  303.  
  304.  (* ============================== BubbleSort ================================
  305.   *    The BubbleSort algorithm cycles through SortArray, comparing adjacent
  306.   *    elements and swapping pairs that are out of order.  It continues to
  307.   *    do this until no pairs are swapped.
  308.   * ==========================================================================
  309.   *)
  310.  PROCEDURE BubbleSort;
  311.  VAR
  312.      Row, Switch, Limit: INTEGER;
  313.  
  314.  BEGIN
  315.      Limit := MaxBars;
  316.      REPEAT
  317.          Switch := 0;
  318.          FOR Row := 1 TO Limit - 1 DO BEGIN
  319.  
  320.             (* Two adjacent elements are out of order, so swap their values
  321.              * and redraw those two bars: *)
  322.              IF (SortArray[Row].Length > SortArray[Row + 1].Length) THEN BEGIN
  323.                  swaps (SortArray[Row], SortArray[Row + 1]);
  324.                  SwapBars (Row, Row + 1);
  325.                  Switch := Row;
  326.              END;
  327.          END;
  328.  
  329.      (* Sort on next pass only to where the last switch was made: *)
  330.      Limit := Switch;
  331.      UNTIL Switch = 0;
  332.  END;
  333.  
  334.  (* ============================== DrawFrame =================================
  335.   *   Draws a rectangular frame using the high-order ASCII characters ╔ (201)
  336.   *   ╗ (187) , ╚ (200) , ╝ (188) , ║ (186) , and ═ (205). The parameters
  337.   *   TopSide, BottomSide, LeftSide, and RightSide are the row and column
  338.   *   arguments for the upper-left and lower-right corners of the frame.
  339.   * ==========================================================================
  340.   *)
  341.  PROCEDURE DrawFrame {(Top, Left, Width, Height)};
  342.  CONST
  343.      ULEFT = 201;
  344.      URIGHT = 187;
  345.      LLEFT = 200;
  346.      LRIGHT = 188;
  347.      VERTICAL = 186;
  348.      HORIZONTAL = 205;
  349.      SPACE = ' ';
  350.  
  351.  VAR
  352.      Attr: BYTE;
  353.      CellAttr, i, bottom, right: INTEGER;
  354.      TempStr: STRING(80);
  355.  
  356.  BEGIN
  357.        Attr := WHITE;
  358.        CellAttr := Attr * 256;
  359.        bottom := Top+Height-1;
  360.        right := Left+Width-1;
  361.  
  362.        ret := VioWrtNCell(ads (CellAttr OR ULEFT),1,Top,Left,0);
  363.        ret := VioWrtNCell(ads (CellAttr OR HORIZONTAL),Width-2,Top,Left+1,0);
  364.        ret := VioWrtNCell(ads (CellAttr OR URIGHT),1,Top,right,0);
  365.  
  366.        FILLSC(ads Tempstr,Width,CHR(SPACE));
  367.        Tempstr[1] := CHR(VERTICAL);
  368.        Tempstr[Width] := CHR(VERTICAL);
  369.        FOR i := 1 TO Height-2 DO
  370.            ret := VioWrtCharStrAtt(ads Tempstr,Width,i+Top,Left,Attr,0);
  371.  
  372.        ret := VioWrtNCell(ads (CellAttr OR LLEFT),1,bottom,Left,0);
  373.        ret := VioWrtNCell(ads (CellAttr OR HORIZONTAL),Width-2,bottom,Left+1,0
  374.        ret := VioWrtNCell(ads (CellAttr OR LRIGHT),1,bottom,right,0);
  375.  END;
  376.  
  377.  (* ============================= ElapsedTime ================================
  378.   *    Prints seconds elapsed since the given sorting routine started.
  379.   *    Note that this time includes both the time it takes to redraw the
  380.   *    bars plus the pause while the SOUND statement plays a note, and
  381.   *    thus is not an accurate indication of sorting speed.
  382.   * ==========================================================================
  383.   *)
  384.  PROCEDURE ElapsedTime {(CurrentRow)};
  385.  VAR
  386.      Color: BYTE;
  387.      Timing: LSTRING(80);
  388.  
  389.  BEGIN
  390.      Color := WHITE;
  391.  
  392.      ret := DosGetDateTime(ads wTime);
  393.  
  394.      nTime := (wTime.hours * 360000) +
  395.              (wTime.minutes * 6000) +
  396.              (wTime.seconds * 100) +
  397.               wTime.hundredths;
  398.  
  399.      EVAL(ENCODE(Timing,(nTime - oTime) / 100:7:2));
  400.  
  401.      (* Print the number of seconds elapsed *)
  402.      ret := VioWrtCharStrAtt(ads Timing[1], 7, curSelect + FIRSTMENU + 3,
  403.          LEFTCOLUMN + 15, Color, 0);
  404.  
  405.      IF (Sound) THEN
  406.          ret := DosBeep(60 * CurrentRow, 32);    (* Play a note. *)
  407.      ret := DosSleep(Pause);                     (* Pause. *)
  408.  
  409.  END;
  410.  
  411.  (* ============================= ExchangeSort ===============================
  412.   *   The ExchangeSort compares each element in SortArray - starting with
  413.   *   the first element - with every following element.  If any of the
  414.   *   following elements is smaller than the current element, it is exchanged
  415.   *   with the current element and the process is repeated for the next
  416.   *   element in SortArray.
  417.   * ==========================================================================
  418.   *)
  419.  PROCEDURE ExchangeSort;
  420.  VAR
  421.      Row, SmallestRow, j: INTEGER;
  422.  
  423.  BEGIN
  424.      FOR Row := 1 TO MaxBars - 1 DO BEGIN
  425.          SmallestRow := Row;
  426.          FOR j := Row + 1 TO MaxBars DO BEGIN
  427.              IF (SortArray[j].Length < SortArray[SmallestRow].Length) THEN BEG
  428.                  SmallestRow := j;
  429.                  ElapsedTime(j);
  430.              END;
  431.          END;
  432.         (* Found a row shorter than the current row, so swap those
  433.          * two array elements: *)
  434.          IF (SmallestRow > Row) THEN BEGIN
  435.              swaps (SortArray[Row], SortArray[SmallestRow]);
  436.              SwapBars (Row, SmallestRow);
  437.          END;
  438.      END;
  439.  
  440.  END;
  441.  
  442.  (* =============================== HeapSort =================================
  443.   *  The HeapSort procedure works by calling two other procedures - PercolateU
  444.   *  and PercolateDown.  PercolateUp turns SortArray into a "heap," which has
  445.   *  the properties outlined in the diagram below:
  446.   *
  447.   *                               SortArray(1)
  448.   *                               /          \
  449.   *                    SortArray(2)           SortArray(3)
  450.   *                   /          \            /          \
  451.   *         SortArray(4)   SortArray(5)   SortArray(6)  SortArray(7)
  452.   *          /      \       /       \       /      \      /      \
  453.   *        ...      ...   ...       ...   ...      ...  ...      ...
  454.   *
  455.   *
  456.   *  where each "parent node" is greater than each of its "child nodes"; for
  457.   *  example, SortArray(1) is greater than SortArray(2) or SortArray(3),
  458.   *  SortArray(3) is greater than SortArray(6) or SortArray(7), and so forth.
  459.   *
  460.   *  Therefore, once the first FOR...NEXT loop in HeapSort is finished, the
  461.   *  largest element is in SortArray(1).
  462.   *
  463.   *  The second FOR...NEXT loop in HeapSort swaps the element in SortArray(1)
  464.   *  with the element in MaxRow, rebuilds the heap (with PercolateDown) for
  465.   *  MaxRow - 1, then swaps the element in SortArray(1) with the element in
  466.   *  MaxRow - 1, rebuilds the heap for MaxRow - 2, and continues in this way
  467.   *  until the array is sorted.
  468.   * ==========================================================================
  469.   *)
  470.  PROCEDURE HeapSort;
  471.  VAR
  472.      i: INTEGER;
  473.  
  474.  BEGIN
  475.      FOR i := 2 TO MaxBars DO
  476.          PercolateUp (i);
  477.  
  478.      FOR i := MaxBars DOWNTO 2 DO BEGIN
  479.          swaps (SortArray[1], SortArray[i]);
  480.          SwapBars (1, i);
  481.          PercolateDown (i - 1);
  482.      END;
  483.  END;
  484.  
  485.  (* ============================== Initialize ================================
  486.   *    Initializes the SortBackup array.  It also calls the BoxInit procedure.
  487.   * ==========================================================================
  488.   *)
  489.  PROCEDURE Initialize;
  490.  VAR
  491.      iTime: _DATETIME;
  492.      i, MaxIndex, Index, BarLength: INTEGER;
  493.      TempArray: ARRAY [1..43] OF INTEGER;
  494.  
  495.  BEGIN
  496.      FOR i := 1 TO MaxBars DO
  497.          TempArray[i] := i;
  498.  
  499.     (* If monochrome or color burst disabled, use one color *)
  500.      IF (((wMode.fbType AND VGMT_OTHER) <> 0) AND
  501.          ((wMode.fbType AND VGMT_DISABLEBURST) = 0))
  502.          MaxColors := 15;
  503.      ELSE
  504.          MaxColors := 1;
  505.  
  506.     (* Seed the random-number generator. *)
  507.      ret := DosGetDateTime(ads iTime);
  508.      RandSeed := (iTime.hours * 3600) +
  509.                  (iTime.minutes * 60) +
  510.                   iTime.seconds;
  511.      RandSeed := TRUNC4(RandSeed / 86400.0 * 259199.0);
  512.  
  513.      MaxIndex := MaxBars;
  514.      FOR i := 1 TO MaxBars DO BEGIN
  515.  
  516.         (* Find a random element in TempArray between 1 and MaxIndex,
  517.          * then assign the value in that element to BarLength: *)
  518.          Index := RandInt(1,MaxIndex);
  519.          BarLength := TempArray[Index];
  520.  
  521.         (* Overwrite the value in TempArray[Index] with the value in
  522.          * TempArray[MaxIndex] so the value in TempArray[Index] is
  523.          * chosen only once: *)
  524.          TempArray[Index] := TempArray[MaxIndex];
  525.  
  526.         (* Decrease the value of MaxIndex so that TempArray[MaxIndex] can't
  527.          * be chosen on the next pass through the loop: *)
  528.          MaxIndex := MaxIndex - 1;
  529.  
  530.          SortBackup[i].Length := BarLength;
  531.  
  532.          IF (MaxColors = 1) THEN
  533.              SortBackup[i].ColorVal := 7;
  534.          ELSE
  535.              SortBackup[i].ColorVal := (BarLength MOD MaxColors) + 1;
  536.      END;
  537.  
  538.      cls;
  539.      Reinitialize;      (* Assign values in SortBackup to SortArray and draw *
  540.                           (* unsorted bars on the screen. *)
  541.      Sound := TRUE;
  542.      Pause := 30;           (* Initialize Pause. *)
  543.      BoxInit;           (* Draw frame for the sort menu and print options. *)
  544.  
  545.  END;
  546.  
  547.  (* ============================= InsertionSort ==============================
  548.   *   The InsertionSort procedure compares the length of each successive
  549.   *   element in SortArray with the lengths of all the preceding elements.
  550.   *   When the procedure finds the appropriate place for the new element, it
  551.   *   inserts the element in its new place, and moves all the other elements
  552.   *   down one place.
  553.   * ==========================================================================
  554.   *)
  555.  PROCEDURE InsertionSort;
  556.  VAR
  557.      j, Row, TempLength: INTEGER;
  558.      TempVal: SortType;
  559.  
  560.  BEGIN
  561.      FOR Row := 2 TO MaxBars DO BEGIN
  562.          TempVal := SortArray[Row];
  563.          TempLength := TempVal.Length;
  564.          FOR j := Row DOWNTO 2 DO BEGIN
  565.  
  566.             (* As long as the length of the j-1st element is greater than the
  567.              * length of the original element in SortArray(Row), keep shifting
  568.              * the array elements down: *)
  569.              IF (SortArray[j - 1].Length > TempLength) THEN BEGIN
  570.                  SortArray[j] := SortArray[j - 1];
  571.                  PrintOneBar(j);             (* Print the new bar. *)
  572.                  ElapsedTime(j);             (* Print the elapsed time. *)
  573.  
  574.               (* Otherwise, exit: *)
  575.               END
  576.               ELSE
  577.                  break;
  578.          END;
  579.  
  580.          (* Insert the original value of SortArray(Row) in SortArray(j): *)
  581.          SortArray[j] := TempVal;
  582.          PrintOneBar(j);
  583.          ElapsedTime(j);
  584.      END;
  585.  END;
  586.  
  587.  (* ============================ PercolateDown ===============================
  588.   *   The PercolateDown procedure restores the elements of SortArray from 1 to
  589.   *   MaxLevel to a "heap" (see the diagram with the HeapSort procedure).
  590.   * ==========================================================================
  591.   *)
  592.  PROCEDURE PercolateDown {(MaxLevel)};
  593.  VAR
  594.      i, Child: INTEGER;
  595.  
  596.  BEGIN
  597.      i := 1;
  598.     (* Move the value in SortArray(1) down the heap until it has reached
  599.      * its proper node (that is, until it is less than its parent node
  600.      * or until it has reached MaxLevel, the bottom of the current heap): *)
  601.      WHILE TRUE DO BEGIN
  602.          Child := 2 * i;            (* Get the subscript for the child node. *
  603.  
  604.          (* Reached the bottom of the heap, so exit this procedure: *)
  605.          IF (Child > MaxLevel) THEN
  606.              break;
  607.  
  608.          (* If there are two child nodes, find out which one is bigger: *)
  609.          IF (Child + 1 <= MaxLevel) THEN
  610.              IF (SortArray[Child + 1].Length > SortArray[Child].Length) THEN
  611.                  Child := Child+1;
  612.  
  613.         (* Move the value down if it is still not bigger than either one of
  614.          * its children: *)
  615.          IF (SortArray[i].Length < SortArray[Child].Length) THEN BEGIN
  616.              swaps (SortArray[i], SortArray[Child]);
  617.              SwapBars (i, Child);
  618.              i := Child;
  619.  
  620.         (* Otherwise, SortArray has been restored to a heap from 1 to
  621.          * MaxLevel, so exit: *)
  622.          END
  623.          ELSE
  624.              break;
  625.      END;
  626.  END;
  627.  
  628.  (* ============================== PercolateUp ===============================
  629.   *   The PercolateUp procedure converts the elements from 1 to MaxLevel in
  630.   *   SortArray into a "heap" (see the diagram with the HeapSort procedure).
  631.   * ==========================================================================
  632.   *)
  633.  PROCEDURE PercolateUp {(MaxLevel)};
  634.  VAR
  635.      i, Parent: INTEGER;
  636.  
  637.  BEGIN
  638.      i := MaxLevel;
  639.     (* Move the value in SortArray(MaxLevel) up the heap until it has
  640.      * reached its proper node (that is, until it is greater than either
  641.      * of its child nodes, or until it has reached 1, the top of the heap): *)
  642.      WHILE (i <> 1) DO BEGIN
  643.          Parent := i DIV 2;           (* Get the subscript for the parent node
  644.  
  645.         (* The value at the current node is still bigger than the value at
  646.          * its parent node, so swap these two array elements: *)
  647.          IF (SortArray[i].Length > SortArray[Parent].Length) THEN BEGIN
  648.              swaps (SortArray[Parent], SortArray[i]);
  649.              SwapBars (Parent, i);
  650.              i := Parent;
  651.  
  652.         (* Otherwise, the element has reached its proper place in the heap,
  653.          * so exit this procedure: *)
  654.          END
  655.          ELSE
  656.              break;
  657.      END;
  658.  END;
  659.  
  660.  (* ============================== PrintOneBar ===============================
  661.   *  Prints SortArray(Row).BarString at the row indicated by the Row
  662.   *  parameter, using the color in SortArray(Row).ColorVal.
  663.   * ==========================================================================
  664.   *)
  665.  PROCEDURE PrintOneBar {(Row)};
  666.  VAR
  667.      Cell: CELLINFO;
  668.      NumSpaces: INTEGER;
  669.  
  670.  BEGIN
  671.      Cell.Attr := SortArray[Row].ColorVal;
  672.      Cell.Char := BLOCK;
  673.      ret := VioWrtNCell(ads Cell,SortArray[Row].Length,Row,1,0);
  674.      NumSpaces := MaxBars - SortArray[Row].Length;
  675.      IF NumSpaces > 0 THEN
  676.          Cell.Char := SPACE;
  677.          ret := VioWrtNCell(ads Cell,NumSpaces,Row,SortArray[Row].Length+1,0);
  678.  END;
  679.  
  680.  (* ============================== QuickSort =================================
  681.   *   QuickSort works by picking a random "pivot" element in SortArray, then
  682.   *   moving every element that is bigger to one side of the pivot, and every
  683.   *   element that is smaller to the other side.  QuickSort is then called
  684.   *   recursively with the two subdivisions created by the pivot.  Once the
  685.   *   number of elements in a subdivision reaches two, the recursive calls end
  686.   *   and the array is sorted.
  687.   * ==========================================================================
  688.   *)
  689.  PROCEDURE QuickSort {(Low, High)};
  690.  VAR
  691.      i, j, RandIndex, Partition: INTEGER;
  692.  
  693.  BEGIN
  694.      IF (Low < High) THEN BEGIN
  695.  
  696.         (* Only two elements in this subdivision; swap them if they are out of
  697.          * order, then end recursive calls: *)
  698.          IF ((High - Low) = 1) THEN BEGIN
  699.              IF (SortArray[Low].Length > SortArray[High].Length) THEN BEGIN
  700.                  swaps (SortArray[Low], SortArray[High]);
  701.                  SwapBars (Low, High);
  702.              END;
  703.          END
  704.          ELSE BEGIN
  705.              Partition := SortArray[High].Length;
  706.              i := Low;
  707.              j := High;
  708.              WHILE i < j DO BEGIN
  709.  
  710.                  (* Move in from both sides towards the pivot element: *)
  711.                  WHILE ((i < j) AND (SortArray[i].Length <= Partition)) DO
  712.                      i := i + 1;
  713.  
  714.                  WHILE ((j > i) AND (SortArray[j].Length >= Partition)) DO
  715.                      j := j - 1;
  716.  
  717.                 (* If we haven't reached the pivot element, it means that two
  718.                  * elements on either side are out of order, so swap them: *)
  719.                  IF (i < j) THEN BEGIN
  720.                      swaps (SortArray[i], SortArray[j]);
  721.                      SwapBars (i, j);
  722.                  END;
  723.              END;
  724.  
  725.             (* Move the pivot element back to its proper place in the array: *
  726.              swaps (SortArray[i], SortArray[High]);
  727.              SwapBars (i, High);
  728.  
  729.             (* Recursively call the QuickSort procedure (pass the smaller
  730.              * subdivision first to use less stack space): *)
  731.              IF ((i - Low) < (High - i)) THEN BEGIN
  732.                  QuickSort (Low, i - 1);
  733.                  QuickSort (i + 1, High);
  734.              END
  735.              ELSE BEGIN
  736.                  QuickSort (i + 1, High);
  737.                  QuickSort (Low, i - 1);
  738.              END;
  739.          END;
  740.      END;
  741.  END;
  742.  
  743.  (* =============================== RandInt ==================================
  744.   *   Returns a random integer greater than or equal to the Lower parameter
  745.   *   and less than or equal to the Upper parameter.
  746.   * ==========================================================================
  747.   *)
  748.  FUNCTION RandInt {(Lower, Upper)};
  749.  BEGIN
  750.      RandSeed := (RandSeed*7141+54773) MOD 259200;
  751.      RandInt := ORD(Lower + ((Upper - Lower + 1) * RandSeed) DIV 259200);
  752.  END;
  753.  
  754.  (* ============================== Reinitialize ==============================
  755.   *   Restores the array SortArray to its original unsorted state, then
  756.   *   prints the unsorted color bars.
  757.   * ==========================================================================
  758.   *)
  759.  PROCEDURE Reinitialize;
  760.  VAR
  761.      Row: INTEGER;
  762.  BEGIN
  763.      FOR Row := 1 TO MaxBars DO BEGIN
  764.          SortArray[Row] := SortBackup[Row];
  765.          PrintOneBar(Row);
  766.      END;
  767.  
  768.      ret := DosGetDateTime(ads sTime);
  769.      oTime := (sTime.hours * 360000) +
  770.              (sTime.minutes * 6000) +
  771.              (sTime.seconds * 100) +
  772.               sTime.hundredths;
  773.  END;
  774.  
  775.  FUNCTION Screen {(ACTION)};
  776.  VAR [STATIC]
  777.      Mode: _VIOMODEINFO;
  778.      CellStr: ADSMEM;
  779.      Row,Col,Length: WORD;
  780.  BEGIN
  781.      if(ACTION=1) THEN BEGIN
  782.          Mode.cb := sizeof(Mode);
  783.          ret := VioGetMode(ads Mode,0);
  784.          Length := 2*Mode.row*Mode.col;
  785.          CellStr := GETMQQ(Length);
  786.          if(CellStr.r = NULL) THEN BEGIN Screen := FALSE;return;END;
  787.          ret := VioReadCellStr(CellStr,Length,0,0,0);
  788.          ret := VioGetCurPos(Row,Col,0);
  789.      END
  790.      ELSE BEGIN
  791.          ret := VioSetMode(ads Mode,0);
  792.          if(CellStr.r = NULL) THEN BEGIN Screen := FALSE;return;END;
  793.          ret := VioWrtCellStr(CellStr,Length,0,0,0);
  794.          ret := VioSetCurPos(Row,Col,0);
  795.      END;
  796.      Screen := TRUE;
  797.  END;
  798.  
  799.  (* =============================== ShellSort ================================
  800.   *  The ShellSort procedure is similar to the BubbleSort procedure.  However,
  801.   *  ShellSort begins by comparing elements that are far apart (separated by
  802.   *  the value of the Offset variable, which is initially half the distance
  803.   *  between the first and last element), then comparing elements that are
  804.   *  closer together (when Offset is one, the last iteration of this procedure
  805.   *  is merely a bubble sort).
  806.   * ==========================================================================
  807.   *)
  808.  PROCEDURE ShellSort;
  809.  VAR
  810.      Offset, Switch, Limit, Row: INTEGER;
  811.  
  812.  BEGIN
  813.      (* Set comparison offset to half the number of records in SortArray: *)
  814.      Offset := MaxBars DIV 2;
  815.  
  816.      WHILE (Offset>0) DO BEGIN     (* Loop until offset gets to zero. *)
  817.          Limit := MaxBars - Offset;
  818.          REPEAT
  819.              Switch := 0;        (* Assume no switches at this offset. *)
  820.  
  821.           (* Compare elements and switch ones out of order: *)
  822.              FOR Row := 1 TO Limit DO
  823.                  IF (SortArray[Row].Length > SortArray[Row + Offset].Length) T
  824.                      swaps (SortArray[Row], SortArray[Row + Offset]);
  825.                      SwapBars (Row, Row + Offset);
  826.                      Switch := Row;
  827.                  END;
  828.  
  829.              (* Sort on next pass only to where last switch was made: *)
  830.              Limit := Switch - Offset;
  831.          UNTIL Switch = 0;
  832.  
  833.         (* No switches at last offset, try one half as big: *)
  834.          Offset := Offset DIV 2;
  835.      END;
  836.  END;
  837.  
  838.  (* =============================== SortMenu =================================
  839.   *   The SortMenu procedure first calls the Reinitialize procedure to make
  840.   *   sure the SortArray is in its unsorted form, then prompts the user to
  841.   *   make one of the following choices:
  842.   *
  843.   *               * One of the sorting algorithms
  844.   *               * Toggle sound on or off
  845.   *               * Increase or decrease speed
  846.   *               * End the program
  847.   * ==========================================================================
  848.   *)
  849.  PROCEDURE SortMenu;
  850.  BEGIN
  851.      WHILE TRUE DO BEGIN
  852.  
  853.          ret := VioSetCurPos(FIRSTMENU + NLINES, LEFTCOLUMN + Menu[NLINES].len
  854.  
  855.          ret := KbdCharIn(ads KeyInfo, 0, 0);
  856.          IF (CHR(KeyInfo.chChar) >= 'a') AND (CHR(KeyInfo.chChar) <= 'z') THEN
  857.              KeyInfo.chChar := KeyInfo.chChar - 32;
  858.  
  859.          (* Branch to the appropriate procedure depending on the key typed: *)
  860.          CASE CHR(KeyInfo.chChar) OF
  861.  
  862.              'I': BEGIN
  863.                      curSelect := 0;
  864.                      Reinitialize;
  865.                      InsertionSort;
  866.                      ElapsedTime(0);     (* Print final time. *)
  867.                   END;
  868.  
  869.              'B': BEGIN
  870.                      curSelect := 1;
  871.                      Reinitialize;
  872.                      BubbleSort;
  873.                      ElapsedTime(0);     (* Print final time. *)
  874.                   END;
  875.  
  876.              'H': BEGIN
  877.                      curSelect := 2;
  878.                      Reinitialize;
  879.                      HeapSort;
  880.                      ElapsedTime(0);     (* Print final time. *)
  881.                   END;
  882.  
  883.              'E': BEGIN
  884.                      curSelect := 3;
  885.                      Reinitialize;
  886.                      ExchangeSort;
  887.                      ElapsedTime(0);     (* Print final time. *)
  888.                   END;
  889.  
  890.              'S': BEGIN
  891.                      curSelect := 4;
  892.                      Reinitialize;
  893.                      ShellSort;
  894.                      ElapsedTime(0);     (* Print final time. *)
  895.                   END;
  896.  
  897.              'Q': BEGIN
  898.                      curSelect := 5;
  899.                      Reinitialize;
  900.                      QuickSort (1, MaxBars);
  901.                      ElapsedTime(0);     (* Print final time. *)
  902.                   END;
  903.  
  904.              '>': BEGIN
  905.                     (* Decrease pause length to speed up sorting time,
  906.                      * then redraw the menu to clear any timing results
  907.                      * (since they won't compare with future results): *)
  908.                      IF (Pause <> 0) THEN
  909.                          Pause := Pause - 30;
  910.                      BoxInit;
  911.                   END;
  912.  
  913.              '<': BEGIN
  914.                     (* Increase pause length to slow down sorting time,
  915.                      * then redraw the menu to clear any timing results
  916.                      * (since they won't compare with future results): *)
  917.                      IF (Pause <> 900) THEN
  918.                          Pause := Pause + 30;
  919.                      BoxInit;
  920.                   END;
  921.  
  922.              'T': BEGIN
  923.                      Sound := NOT Sound;
  924.                      BoxInit;
  925.                   END;
  926.  
  927.              ESC: return; (* User pressed ESC, so exit and return to main: *)
  928.  
  929.              OTHERWISE
  930.  
  931.          END;
  932.      END;
  933.  END;
  934.  
  935.  (* =============================== SwapBars =================================
  936.   *   Calls PrintOneBar twice to switch the two bars in Row1 and Row2,
  937.   *   then calls the ElapsedTime procedure.
  938.   * ==========================================================================
  939.   *)
  940.  PROCEDURE SwapBars {(Row1, Row2)};
  941.  BEGIN
  942.      PrintOneBar (Row1);
  943.      PrintOneBar (Row2);
  944.      ElapsedTime (Row1);
  945.  END;
  946.  
  947.  PROCEDURE cls;
  948.  BEGIN
  949.      ret := VioScrollDn (0, 0, -1, -1, -1, ads 1824, 0);
  950.  END;
  951.  
  952.  PROCEDURE swaps {(one, two)};
  953.  VAR
  954.      temp: SortType;
  955.  
  956.  BEGIN
  957.      temp := one;
  958.      one := two;
  959.      two := temp;
  960.  
  961.  END;
  962.  
  963.  (* Main program *)
  964.  BEGIN
  965.      if(NOT Screen(1)) THEN cls;
  966.      ret := VioGetMode(ads wMode,0);
  967.      IF (wMode.row <> 43) THEN BEGIN     (* Use 43-line mode if available *)
  968.          wMode.row := 43;
  969.          wmode.hres := 640;              (* Try EGA *)
  970.          wmode.vres := 350;
  971.          IF (VioSetMode(ads wMode,0) <> 0) THEN BEGIN
  972.              wmode.hres := 720;          (* Try VGA *)
  973.              wmode.vres := 400;
  974.              IF (VioSetMode(ads wMode,0) <> 0) THEN BEGIN
  975.                  ret = VioGetMode(ads wMode,0)
  976.                  wMode.row := 25;        (* Use 25 lines *)
  977.                  ret = VioSetMode(ads wMode,0)
  978.              END
  979.          END;
  980.      END;
  981.      MaxBars := ORD(wMode.row);
  982.      Initialize;          (* Initialize data values. *)
  983.      SortMenu;            (* Print sort menu. *)
  984.      if(NOT Screen(0)) THEN cls;
  985.  END.
  986.  
  987.  \SAMPCODE\PASCAL\PASEXEC.INC
  988.  
  989.  {   PASEXEC.INC - interface file for C library routines
  990.  
  991.      This include file along with the CEXEC.LIB library has been included
  992.      with your Pascal 3.32 to show you how easy it is to call routines
  993.      written in our new C 4.00 release.  The CEXEC.LIB contains several
  994.      routines from the C library which we think you will find useful in
  995.      extending the power of your Pascal programs.
  996.  
  997.      The memory model that Pascal uses is basically medium model (16-bit
  998.      data pointers) with some extensions for large model addressing
  999.      (32-bit data pointers).  The CEXEC.LIB routines are from the large
  1000.      model C library.  This means that you should be careful interfacing
  1001.      to these routines.  You should use ADS or VARS instead of ADR or VAR
  1002.      so that 32-bit addressed get constructed.
  1003.  
  1004.      The Microsoft FORTRAN 3.3x, PASCAL 3.32, and C 4.00 releases
  1005.      have been designed so that libraries or subprograms can be written
  1006.      in any one of these languages and used in any other.
  1007.  
  1008.      Try compiling and running the demonstration program DEMOEXEC.PAS
  1009.      to see some actual examples.
  1010.  }
  1011.  
  1012.  {   C function
  1013.  
  1014.              int system(string)
  1015.                      char *string;
  1016.  
  1017.      The system() function passes the given C string (00hex terminated)
  1018.      to the DOS command interpreter (COMMAND.COM), which interprets and
  1019.      executes the string as an MS-DOS command.  This allows MS-DOS commands
  1020.      (i.e., DIR or DEL), batch files, and programs to be executed.
  1021.  
  1022.      Example usage in Pascal
  1023.  
  1024.      i := system(ads('dir *.for'*chr(0)));
  1025.  
  1026.      The interface to system is given below.  The [c] attribute is given
  1027.      after the function return type.  The [varying] attribute says the
  1028.      function has an undetermined number of parameters; in this case, 1.
  1029.  }
  1030.  
  1031.      function system : integer [c,varying]; extern;
  1032.  
  1033.  {   C function
  1034.  
  1035.      int spawnlp(mode,path,arg0,arg1,...,argn)
  1036.              int mode;               /* spawn mode */
  1037.              char *path;             /* pathname of program to execute */
  1038.              char *arg0;             /* should be the same as path */
  1039.              char *arg1,...,*argn;   /* command line arguments */
  1040.                                      /* argn must be NULL */
  1041.  
  1042.      The spawnlp creates and executes a new child process.  There must be
  1043.      enough memory to load and execute the child process.  The mode
  1044.      argument determines which form of spawnlp is executed as follows:
  1045.  
  1046.          Value       Action
  1047.  
  1048.            0         Suspend parent program and execute the child program.
  1049.                      When the child program terminates, the parent program
  1050.                      resumes execution.  The return value from spawnlp is -1
  1051.                      if an error has occured or if the child process has
  1052.                      run, the return value is the child processes return
  1053.                      code.
  1054.  
  1055.          _p_overlay  Overlay parent program with the child program.  The
  1056.                      child program is now the running process and the
  1057.                      parent process is terminated.  spawnlp only returns
  1058.                      a value if there has been a recoverable error.  Some
  1059.                      errors can not be recovered from and execution will
  1060.                      terminate by safely returning to DOS.  This might
  1061.                      happen if there is not enough memory to run the new
  1062.                      process.
  1063.  
  1064.      The path argument specifies the file to be executed as the child
  1065.      process.  The path can specify a full path name (from the root
  1066.      directory \), a partial path name (from the current working directory),
  1067.      or just a file name.  If the path argument does not have a filename
  1068.      extension or end with a period (.), the spawnlp call first appends
  1069.      the extension ".COM" and searches for the file; if unsuccessful, the
  1070.      extension ".EXE" is tried.  The spawnlp routine will also search for
  1071.      the file in any of the directories specified in the PATH environment
  1072.      variable (using the same procedure as above).
  1073.  
  1074.      Example usage in Pascal
  1075.  
  1076.      var     NULL : integer4;
  1077.      value   NULL := 0;
  1078.      ...
  1079.      i := spawnlp(0, ads('exemod'*chr(0)), ads('exemod'*chr(0)),
  1080.                   ads('demoexec.exe'*chr(0)), NULL);
  1081.  
  1082.      The C spawnlp function is expecting the addresses of the strings
  1083.      (not the actual characters), so we use the ADS() function to pass
  1084.      the address of the strings.  The last parameter to the spawnlp
  1085.      routine must be a C NULL pointer which is a 32-bit integer 0, so
  1086.      we use an INTEGER4 variable NULL set to 0 as the last parameter.
  1087.  }
  1088.  
  1089.      var _p_overlay [c,extern] :integer;
  1090.      function spawnlp : integer [c,varying]; extern;
  1091.  
  1092.  
  1093.  
  1094.