home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0000 - 0009 / ibm0000-0009 / ibm0003.tar / ibm0003 / TPOWER54.ZIP / DEMOSRC.ARC / BSORT.PAS next >
Encoding:
Pascal/Delphi Source File  |  1989-07-10  |  9.8 KB  |  376 lines

  1. {$S-,R-,V-,I-,B-,F-}
  2.  
  3. {*********************************************************}
  4. {*                    BSORT.PAS 5.07                     *}
  5. {*                 File sorting utility                  *}
  6. {*     An example program for Turbo Professional 5.0     *}
  7. {*        Copyright (c) TurboPower Software 1987.        *}
  8. {* Portions copyright (c) Sunny Hill Software 1985, 1986 *}
  9. {*     and used under license to TurboPower Software     *}
  10. {*                 All rights reserved.                  *}
  11. {*********************************************************}
  12.  
  13. program BigSort;
  14.   {-DOS filter to sort text files}
  15.  
  16. uses
  17.   Dos,
  18.   TpString,
  19.   TpDos,
  20.   TpSort;
  21.  
  22. const
  23.   BufSize = 8192;
  24.  
  25. type
  26.   TextBuffer = array[1..BufSize] of Char;
  27.   PartialLineRec =
  28.     record
  29.       fpos : LongInt;        {Position of line in input file}
  30.       key : string;          {Portion of input line used as key}
  31.     end;
  32.   PartialP = ^PartialLineRec;
  33.  
  34. var
  35.   Status : SortStatus;       {Success of sort}
  36.   Start : LongInt;           {Gets time in milliseconds}
  37.   StdErr : Text;             {For status reporting}
  38.   TextBuf : TextBuffer;      {Speeds input and output}
  39.   GetProc : Pointer;         {Points to Input procedure to use}
  40.   PutProc : Pointer;         {Points to Output procedure to use}
  41.   LessFunc : Pointer;        {Points to Less function to use}
  42.   IgnoreCase : Boolean;      {True to sort ignoring case}
  43.   Reverse : Boolean;         {True to sort in reverse order}
  44.   Partial : Boolean;         {True to use partial lines as keys}
  45.   StartCol : Integer;        {First column of key}
  46.   KeyLen : Integer;          {Length of key}
  47.   ElSize : Word;             {Size of each sort element}
  48.   StdErrBuf : Char;          {Forces StdErr to write a char at a time}
  49.   Elements : Word;           {Number of elements we can sort}
  50.   SaveExitProc : Pointer;    {Saved value of ExitProc}
  51.  
  52.   function Ms2S(ms : LongInt) : string;
  53.     {-Convert milliseconds to seconds in a string}
  54.   var
  55.     s : string;
  56.   begin
  57.     Str(ms, s);
  58.     {Pad out to three decimal places}
  59.     while Length(s) < 3 do
  60.       s := '0'+s;
  61.     {Truncate to nearest tenth of a second}
  62.     Dec(s[0]);
  63.     Dec(s[0]);
  64.     {Insert decimal point}
  65.     Insert('.', s, Length(s));
  66.     {Insert leading zero}
  67.     if Length(s) = 2 then
  68.       s := '0'+s;
  69.     Ms2S := s;
  70.   end;
  71.  
  72.   procedure Error(msg : string);
  73.     {-Report error through StdErr and halt}
  74.   begin
  75.     WriteLn(StdErr, ^M^J, msg);
  76.     Close(StdErr);
  77.     Halt(1);
  78.   end;
  79.  
  80.   {$F+}
  81.  
  82.   procedure GetStr;
  83.     {-Read all of the strings from the standard input}
  84.   var
  85.     s : string;
  86.   begin
  87.     Start := TimeMs;
  88.     Write(StdErr, 'Reading ');
  89.  
  90.     SetTextBuf(Input, TextBuf, BufSize);
  91.     while not(eof) do begin
  92.       ReadLn(s);
  93.       if IoResult <> 0 then
  94.         Error('Error reading input');
  95.       {Add the element to the sort set}
  96.       if not(PutElement(s)) then
  97.         Exit;
  98.     end;
  99.  
  100.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  101.  
  102.     {Prepare for sorting phase}
  103.     Write(StdErr, 'Sorting ');
  104.     Start := TimeMs;
  105.   end;
  106.  
  107.   procedure PutStr;
  108.     {-Write the sorted strings to the standard output}
  109.   var
  110.     s : string;
  111.   begin
  112.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  113.  
  114.     {Prepare for writing phase}
  115.     Write(StdErr, 'Writing ');
  116.     Start := TimeMs;
  117.  
  118.     SetTextBuf(Output, TextBuf, BufSize);
  119.     while GetElement(s) do begin
  120.       WriteLn(s);
  121.       if IoResult <> 0 then
  122.         Error('Error writing output');
  123.     end;
  124.     Write(^Z);
  125.  
  126.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  127.   end;
  128.  
  129.   function Less(var X, Y) : Boolean;
  130.     {-Compare two strings}
  131.   var
  132.     Xs : string absolute X;
  133.     Ys : string absolute Y;
  134.   begin
  135.     if IgnoreCase then begin
  136.       if Reverse then
  137.         Less := (StUpcase(Ys) < StUpcase(Xs))
  138.       else
  139.         Less := (StUpcase(Xs) < StUpcase(Ys));
  140.     end else begin
  141.       if Reverse then
  142.         Less := (Ys < Xs)
  143.       else
  144.         Less := (Xs < Ys);
  145.     end;
  146.   end;
  147.  
  148.   procedure PartialGetStr;
  149.     {-Read all of the strings from the standard input}
  150.   var
  151.     s : string;
  152.     p : PartialP;
  153.     posn : LongInt;
  154.   begin
  155.     Start := TimeMs;
  156.     Write(StdErr, 'Reading ');
  157.  
  158.     SetTextBuf(Input, TextBuf, BufSize);
  159.     while not(eof) do begin
  160.       {Get position before reading line}
  161.       posn := textpos(Input);
  162.       if posn = -1 then
  163.         {Error getting textpos}
  164.         Error('Error reading input');
  165.       ReadLn(s);
  166.       if IoResult <> 0 then
  167.         Error('Error reading input');
  168.       {Allocate the partial line record}
  169.       GetMem(p, 5+KeyLen);
  170.       if p = nil then
  171.         Error('Insufficient memory');
  172.       with p^ do begin
  173.         {Store where the line is in the input file}
  174.         fpos := posn;
  175.         {Extract the key}
  176.         if IgnoreCase then
  177.           key := StUpcase(Copy(s, StartCol, KeyLen))
  178.         else
  179.           key := Copy(s, StartCol, KeyLen);
  180.       end;
  181.       {Add the element to the sort set}
  182.       if not(PutElement(p)) then
  183.         Exit;
  184.     end;
  185.  
  186.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  187.  
  188.     {Prepare for sorting phase}
  189.     Write(StdErr, 'Sorting ');
  190.     Start := TimeMs;
  191.   end;
  192.  
  193.   procedure PartialPutStr;
  194.     {-Write the sorted strings to the standard output}
  195.   var
  196.     s : string;
  197.     p : PartialP;
  198.   begin
  199.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  200.     {Prepare for writing phase}
  201.     Write(StdErr, 'Writing ');
  202.     Start := TimeMs;
  203.  
  204.     {Use a small buffer to avoid reading wasted bytes}
  205.     SetTextBuf(Input, TextBuf, 256);
  206.     while GetElement(p) do begin
  207.       with p^ do begin
  208.         if not(textseek(Input, fpos)) then
  209.           Error('Error writing output');
  210.         ReadLn(s);
  211.       end;
  212.       WriteLn(s);
  213.       if IoResult <> 0 then
  214.         Error('Error writing output');
  215.     end;
  216.     Write(^Z);
  217.  
  218.     WriteLn(StdErr, Ms2S(TimeMs-Start), ' seconds');
  219.   end;
  220.  
  221.   function PartialLess(var X, Y) : Boolean;
  222.     {-Compare two strings}
  223.   var
  224.     Xp : PartialP absolute X;
  225.     Yp : PartialP absolute Y;
  226.   begin
  227.     if Reverse then
  228.       PartialLess := (Yp^.key < Xp^.key)
  229.     else
  230.       PartialLess := (Xp^.key < Yp^.key);
  231.   end;
  232.  
  233.   {$F-}
  234.  
  235.   procedure Unrecognized(msg : string);
  236.     {-Report error for unrecognized command line option}
  237.   begin
  238.     Error('Unrecognized option: '+msg);
  239.   end;
  240.  
  241.   function GetArgNumber(var I : Integer) : Integer;
  242.     {-Return number following argument i}
  243.   var
  244.     Code : Word;
  245.     Num : Integer;
  246.   begin
  247.     if I >= ParamCount then
  248.       Error('Numeric value does not follow '+ParamStr(I));
  249.     Inc(I);
  250.     Val(ParamStr(I), Num, Code);
  251.     if Code <> 0 then
  252.       Error('Invalid numeric value '+ParamStr(I));
  253.     GetArgNumber := Num;
  254.   end;
  255.  
  256.   procedure GetOptions;
  257.     {-Analyze the command line for options}
  258.   var
  259.     Arg : string;
  260.     I : Integer;
  261.   begin
  262.  
  263.     {Default state}
  264.     IgnoreCase := False;
  265.     Reverse := False;
  266.     Partial := False;
  267.     StartCol := 1;
  268.     KeyLen := 255;
  269.  
  270.     I := 1;
  271.     while I <= ParamCount do begin
  272.  
  273.       Arg := ParamStr(I);
  274.       if Length(Arg) <> 2 then
  275.         Unrecognized(Arg);
  276.       if (Arg[1] <> '/') and (Arg[1] <> '-') then
  277.         Unrecognized(Arg);
  278.  
  279.       case Upcase(Arg[2]) of
  280.         'R' : Reverse := True;
  281.         'I' : IgnoreCase := True;
  282.         'B' : begin
  283.                 StartCol := GetArgNumber(I);
  284.                 Partial := True;
  285.               end;
  286.         'L' : begin
  287.                 KeyLen := GetArgNumber(I);
  288.                 Partial := True;
  289.               end;
  290.       else
  291.         Unrecognized(Arg);
  292.       end;
  293.  
  294.       Inc(I);
  295.     end;
  296.  
  297.     if Partial then begin
  298.       {Special routines for partial lines}
  299.       GetProc := @PartialGetStr;
  300.       PutProc := @PartialPutStr;
  301.       LessFunc := @PartialLess;
  302.       ElSize := SizeOf(Pointer);
  303.     end else begin
  304.       {Default user-defined routines}
  305.       GetProc := @GetStr;
  306.       PutProc := @PutStr;
  307.       LessFunc := @Less;
  308.       ElSize := 0;
  309.     end;
  310.  
  311.     {Make best use of available memory}
  312.     Elements := MaxElements;
  313.     if MemAvail < LongInt(Elements)*SizeOf(Pointer) then
  314.       Elements := MemAvail div (SizeOf(Pointer) shl 1);
  315.  
  316.   end;
  317.  
  318.   {$F+}
  319.   procedure ExitHandler;
  320.     {-Restore cooked mode for standard input/output}
  321.   begin
  322.     ExitProc := SaveExitProc;
  323.     SetRawMode(Input, False);
  324.     SetRawMode(Output, False);
  325.   end;
  326.   {$F-}
  327.  
  328. begin
  329.  
  330.   {Open StdErr for status reporting}
  331.   if not(OpenStdDev(StdErr, 2)) then begin
  332.     WriteLn('Error opening StdErr');
  333.     Halt(1);
  334.   end else
  335.     {Force buffer flush every character}
  336.     SetTextBuf(StdErr, StdErrBuf, 1);
  337.   WriteLn(StdErr, 'Big Sort. Copyright (c) 1987 by TurboPower Software. Version 5.07');
  338.  
  339.   {Make sure input was redirected}
  340.   if HandleIsConsole(0) then begin
  341.     {It wasn't, write some help}
  342.     WriteLn(StdErr);
  343.     WriteLn(StdErr, 'Usage: BSORT [Options] <InputFile >OutputFile');
  344.     WriteLn(StdErr);
  345.     WriteLn(StdErr, 'Options:');
  346.     WriteLn(StdErr, '  /R    Sort in reverse order');
  347.     WriteLn(StdErr, '  /I    Sort ignoring case');
  348.     WriteLn(StdErr, '  /B n  Sort with key starting in column n');
  349.     WriteLn(StdErr, '  /L n  Sort with maximum key length of n characters');
  350.     Error('');
  351.   end;
  352.  
  353.   {Analyze the command line and set defaults}
  354.   GetOptions;
  355.  
  356.   {install exit handler}
  357.   SaveExitProc := ExitProc;
  358.   ExitProc := @ExitHandler;
  359.  
  360.   {select raw mode for standard input/output}
  361.   SetRawMode(Input, True);
  362.   SetRawMode(Output, True);
  363.  
  364.   {Sort strings}
  365.   Status := Sort(Elements, ElSize, GetProc, LessFunc, PutProc);
  366.  
  367.   {Were we successful?}
  368.   case Status of
  369.     SortSuccess : WriteLn(StdErr, ElementsSorted, ' elements sorted');
  370.     SortOutOfMemory : Error('Insufficient memory');
  371.     SortTooManyElements : Error('Too many elements to sort');
  372.   end;
  373.  
  374.   Close(StdErr);
  375. end.
  376.