Contributor: VALERY VOTINTSEV

{-------------------------------------------------------------}
{                  Small SWAG LISTER                          }
{            (c) 1996 by Valery Votintsev                     }
{                         E-Mail: vot@infolink.tver.su        }
{                         FIDO:   2:5021/2.30                 }
{          modified slightly by Gayle Davis                   }
{-------------------------------------------------------------}
Program SWAGL;

Uses DOS;

TYPE
  SwagHeader =
    RECORD
      HeadSize : BYTE;                 {size of header}
      HeadChk  : BYTE;                 {checksum for header}
      HeadID   : ARRAY [1..5] OF CHAR; {compression type tag}
      NewSize  : LONGINT;              {compressed size}
      OrigSize : LONGINT;              {original size}
      Time     : WORD;                 {packed time}
      Date     : WORD;                 {packed date}
      Attr     : WORD;                 {file attributes and flags}
      BufCRC   : LONGINT;              {32-CRC of the Buffer }
      Swag     : STRING[12];           {stored SWAG filename}
      Subject  : STRING[40];           {snipet subject}
      Contrib  : STRING[35];           {contributor}
      Keys     : STRING[70];           {search keys, comma deliminated}
      FName    : PathStr;              {filename (variable length)}
      CRC      : WORD;                 {16-bit CRC (immediately follows FName)}
    END;

    SWAGFooter =
    RECORD
       CopyRight : String[60];         { GDSOFT copyright }
       Title     : String[65];         { SWG File Title   }
       Count     : INTEGER;
    END;

    ShortHeader =
    RECORD
      OrigSize : LONGINT;               {original size}
      Date     : WORD;                  {packed date}
      Subject  : STRING[40];            {snipet subject}
      Contrib  : STRING[35];            {contributor}
    END;

Var
   PMask,
   FMask: String;                       { SWAG files mask      }
   Buf: SwagHeader;                     { Temporary buffer     }
   Footer:SWAGFooter;                   { SWAG file footer     }
   NextPos:LongInt;                     { Next snipet position }
   fSize:LongInt;                       { File size            }
   aList:Array[1..2000] of Pointer;     { Array of snipet info }
   pShortHeader: ^ShortHeader;          { snipet info pointer  }
   ListLen:Integer;                     { Snipet array length  }
   Snipets:Integer;                     { Number of snipets    }
   AllSize:LongInt;                     { All snipets size     }
   TotalSize:LongInt;                   { Total size           }
   F:File;
   DirInfo:SearchRec;
   i:integer;
   Dir: DirStr;
   Name: NameStr;
   Ext: ExtStr;

{----------------------------------------------}
{ Convert the string to upper case             }
{(Russian conversion is excluded for simlicity)}

Function StUpcase(S:String):String;
Var
   i:integer;
   l:byte absolute S;
begin
   StUpcase[0]:=Chr(l);
   For i:=1 to l do
      StUpcase[i]:=UpCase(S[i]);
end;

{----------------------------------------------}
{ Repeat the char n times                      }
Function Replicate(C:Char;n:byte):String;
Var
   i:integer;
begin
   Replicate[0]:=Chr(n);
   For i:=1 to n do
      Replicate[i]:=C;
end;

{----------------------------------------------}
{ String Pad Right                             }
Function PadR(S:String;n:byte):String;
Var
   i:integer;
   l:byte absolute S;
begin
   PadR:=S;
   PadR[0]:=Chr(n);
   For i:=l+1 to n do
   begin
      PadR[i]:=' ';
   end;
end;

{----------------------------------------------}
{ Convert Integer to string & add leading zero }
Function LeadZero(L:Longint;n:byte):String;
Var
   i:integer;
   S:String;
begin
   STR(L:n,S);
   For i:=1 to n do
      If S[i]=' ' then S[i]:='0';
   LeadZero:=S;
end;
{-------------------------------------------}
{ Convert packed date to string }
Function Date2str(D:Word):String;
Var
   Day  :Word;
   Month:Word;
   Year :Word;
begin
   Day  := ( D and $1F);
   Month:= ( D and $1E0) shr 5;
   Year := ( D and $FE00) shr 9;
   Date2str:=LeadZero(Day,2)+'-'
            +LeadZero(Month,2)+'-'
            +LeadZero((Year+80),2);
end;


{--------- Main Routine ---------------------------------------}
begin
   FMask := ParamStr(1); { Get the file mask from command line }
   If FMask <> '' then
   begin
      FSplit(FMask, PMask, Name, Ext);

      FindFirst(FMask,ARCHIVE,DirInfo); { Search first file }

      Writeln('');
      Writeln('================= SWAG Snipets List ==================');
      Writeln('   (c) 1996 by Valery Votintsev (vot@infolink.tver.su)');
      Writeln('');
      Writeln('From                 Size   Date   Subject');
      Writeln('------------------- ----- -------- ---------------');

      TotalSize:=0;
      Snipets  :=0;

      While DOSError = 0 do   { while files exists }
      begin
         FSplit(DirInfo.Name, Dir, Name, Ext);
         If StUpcase(Ext)='.SWG' then begin    { Skip not .SWG files }
            Assign(F,Pmask + DirInfo.Name);
            Reset(F,1);

            NextPos:=0;
            FSize:=FileSize(F);
            AllSize:=0;
            ListLen:=0;

            While (nextPos+SizeOf(Buf)) < FSize do
            begin
               Seek(F,NextPos);
               BlockRead(F,Buf,SizeOf(Buf));

               New ( pShortHeader ); {Allocate memory}
               Inc(ListLen);
               aList[ListLen]:=pShortHeader;

               With pShortHeader^ do
               begin
                  OrigSize := Buf.OrigSize;
                  Date     := Buf.Date;
                  Subject  := Buf.Subject;
                  Contrib  := Buf.Contrib;

                  Inc(AllSize,OrigSize);
               end;
               NextPos:=NextPos+Buf.HeadSize+buf.NewSize+2;
            end;

            SEEK (F, FileSize(F) - SIZEOF(Footer));
            BlockRead(F,Footer,SizeOf(Footer));
            Close(F);

            { Say snipet header }
            Writeln('');
            Writeln(PadR(StUpcase(DirInfo.Name),12),' - ',Footer.Title);
            i:=Length(Footer.Title)+15;
            Writeln(Replicate('~',i));

            { List snipets in the file }
            For i:=1 to ListLen do
            begin
               pShortHeader:=aList[i];

               { Say the snipet info}
               With pShortHeader^ do
               begin
                  Write  (PadR(Contrib,19),' ');
                  Write  (OrigSize:5,' ');
                  Write  (Date2str(Date),' ');
                  Writeln(PadR(Subject,40));
               end;
               Dispose (pShortHeader); {Release memory}
            end;

            Inc(Snipets,ListLen);
            Inc(TotalSize,AllSize);

            { Say this file totals}
            Writeln('------------------- -----');
            Writeln(ListLen:13,AllSize:12);
         end; {If Ext = .SWG }
         FindNext(DirInfo);  { Search next file }
      end; {While DosError}

      { Say totals}
      Writeln('------------------- -----');
      Writeln('Total:',Snipets:7,TotalSize:12,' bytes');
      Writeln('');
   end; {If Mask <> ''}
end.