Contributor: EDDY THILLEMAN
{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X-,Y-}
{$M 16384,0,655360}
{$DEFINE Kort}
Program Extract;
 { extract filenames and accompanying descriptions from bbs files listings }
 { Author: Eddy Thilleman, 19 mei 1994 }
 { written in Borland Pascal version 7.01 }
 { modified: augustus 1994 - choose between long vs. short directory name }
 { modified: januari 1995 - keep only filenames with entries found on screen
 - total number of found entries
 - delete destination directory if no entries found }
Uses
 Dos;
Type
 TypeNotAllowed = set of char; { filter out (some) header lines }
Const
 NotAllowed : TypeNotAllowed = [''..' ','*',':'..'?','|','ー'..'?'];
 NoFAttr : word = 1ドルC; { dir-, volume-, system attributen }
 FAttr : word = 23ドル; { readonly-, hidden-, archive attributes }
 BufSizeBig = 49152; { 48 KB }
 BufSizeSmall = 8192; { 8 KB }
 Cannot = 'Cannot create destination ';
 MaxNrLines = 20; { max # of lines for one entry }
 MaxNrSearch = 18; { max # of words to search for }
Type
 BufTypeSource = array [1..BufSizeBig ] of char;
 BufTypeDest = array [1..BufSizeSmall] of char;
 string3 = string[03];
 String12 = string[12];
 String16 = string[16];
 String25 = string[25];
 String65 = string[65];
 TypeLine = array [1..MaxNrLines] of string;
Var
 Line : TypeLine; { filename and description }
 Tmp1, Tmp2 : string; { temporary hold lines here }
 FileName : String12; { filename in files listing }
 SearchText : array [1..MaxNrSearch] of String65;
 Count, TotalCount: word; { # of found entries }
 SourceFile, DestFile : text; { sourcefile and dest. file }
 SourceBuf : BufTypeSource; { source text buffer }
 DestBuf : BufTypeDest; { destination text buffer }
{$IFDEF Kort}
 DestListing : string16; { name of destination file }
 DestDir : string3 ; { name of destination directory }
{$ELSE}
 DestListing : string25; { name of destination file }
 DestDir : string12; { name of destination directory }
{$ENDIF}
 FR : SearchRec; { FileRecord }
 FMask, DirName : String12;
 Exists : boolean;
 nr, { nr: points to element# where
 to put the next read-in line }
 NrLines : byte; { NrLines: number of lines belonging
 to this entry }
 found, Header : boolean;
 T : byte; { points to char in line: allowed? }
 NrSearch, { current word to search for }
 TotalNrSearch : byte; { total # of words to search for }
procedure LowerFast( var Str: String );
 { 52 Bytes by Bob Swart, 11-6-1993, '80XXX' FASTEST! }
InLine(
 8ドルC/$DA/ { mov DX,DS }
 $BB/Ord('A')/
 Ord('Z')-Ord('A')/ { mov BX,'Z'-'A'/'A' }
 5ドルE/ { pop SI }
 1ドルF/ { pop DS }
 $FC/ { cld }
 $AC/ { lodsb }
 88ドル/$C1/ { mov CL,AL }
 30ドル/$ED/ { xor CH,CH }
 $D1/$E9/ { shr CX,1 }
 73ドル/0ドルB/ { jnc @Part1 }
 $AC/ { lodsb }
 28ドル/$D8/ { sub AL,BL }
 38ドル/$F8/ { cmp AL,BH }
 77ドル/04ドル/ { ja @Part1 }
 80ドル/44ドル/$FF/
 Ord('a')-Ord('A')/ {@Loop: ADD Byte Ptr[SI-1],'a'-'A'}
 $E3/14ドル/ {@Part1:jcxz @Exit }
 $AD/ { lodsw }
 28ドル/$D8/ { sub AL,BL }
 38ドル/$F8/ { cmp AL,BH }
 77ドル/04ドル/ { ja @Part2 }
 80ドル/44ドル/$FE/
 Ord('a')-Ord('A')/ { ADD Byte Ptr[SI-2],'a'-'A'}
 49ドル/ {@Part2:dec CX }
 28ドル/$DC/ { sub AH,BL }
 38ドル/$FC/ { cmp AH,BH }
 77ドル/$EC/ { ja @Part1 }
 $EB/$E6/ { jmp @Loop }
 8ドルE/$DA {@Exit: mov DS,DX }
) { LowerFast };
procedure CopySubStr( Str1: string; start, nrchars: byte; var Str2: string );
assembler;
 { copy part of Str1 (beginning at start for nrchars) to Str2
 if start> length of Str1, Str2 will contain a empty string.
 if nrchars specifies more characters than remain starting at the
 start position, Str2 will contain just that remainder of Str1. }
asm { setup }
 lds si, str1 { load in DS:SI pointer to str1 }
 cld { string operations forward }
 les di, str2 { load in ES:DI pointer to str2 }
 mov ah, [si] { length str1 --> AH }
 and ah, ah { length str1 = 0? }
 je @null { yes, empty string in Str2 }
 mov bl, [start] { starting position --> BL }
 cmp ah, bl { start> length str1? }
 jb @null { yes, empty string in Str2 }
 { start + nrchars - 1> length str1? }
 mov al, [nrchars]{ nrchars --> AL }
 mov dh, al { nrchars --> DH }
 add dh, bl { add start }
 dec dh
 cmp ah, dh { nrchars> rest of str1? }
 jb @rest { yes, copy rest of str1 }
 jmp @copy
@null: xor ax, ax { return a empty string }
 jmp @done
@rest: sub ah, bl { length str1 - start }
 inc ah
 mov al, ah
@copy: mov cl, al { how many chars to copy }
 xor ch, ch { clear CH }
 xor bh, bh { clear BH }
 add si, bx { starting position }
 mov dx, di { save pointer to str2 }
 inc di
 rep movsb { copy part str1 to str2 }
 mov di, dx { restore pointer to str2 }
@done: mov [di], al { overwrite length byte of str2 }
@exit:
end { CopySubStr };
procedure StrCopy( var Str1, Str2: string ); assembler;
 { copy str1 to str2 }
asm
 lds si, str1 { load in DS:SI pointer to str1 }
 cld { string operations forward }
 les di, str2 { load in ES:DI pointer to str2 }
 xor ch, ch { clear CH }
 mov cl, [si] { length str1 --> CX }
 inc cx { include length byte }
 rep movsb { copy str1 to str2 }
@exit:
end { StrCopy };
function StrPos( var str1, str2: string ): byte; assembler;
 { returns position of the first occurrence of str1 in str2 }
 { str1 - string to search for }
 { str2 - string to search in }
 { return value in AX }
asm
 cld { string operations forward }
 les di, str2 { load in ES:DI pointer to str2 }
 xor cx, cx { clear cx }
 mov cl, [di] { length str2 --> CL }
 jcxz @not { if length str2 = 0, nothing to search in }
 mov bh, cl { length str2 --> BH }
 inc di { di point to 1st char of str2 }
 lds si, str1 { load in DS:SI pointer to str1 }
 lodsb { load in AL length str1 }
 and al, al { length str1 = 0? }
 jz @not { length str1 = 0, nothing to search for }
 dec al { 1st char need not be compared again }
 sub cl, al { length str2 - length str1 }
 jbe @not { length str2 < length str1 } mov ah, al { length str1 --> AH }
 lodsb { load in AL 1st character of str1 }
@start:
 repne scasb { scan for next occurrence 1st char in str2 }
 jne @not { no success }
 mov dx, si { pointer to 2nd char in str1 --> DX }
 mov bl, cl { number of chars in str2 to go --> BL }
 mov cl, ah { length str1 --> CL }
 repe cmpsb { compare until characters don't match }
 je @pos { full match }
 sub si, dx { current SI - prev. SI = # of chars moved }
 sub di, si { current DI - # of chars moved = prev. DI }
 mov si, dx { restore pointer to 2nd char in str1 }
 mov cl, bl { number of chars in str2 to go --> BL }
 jmp @start { scan for next occurrence 1st char in str2 }
@not: xor ax, ax { str1 is not in str2, result 0 }
 jmp @exit
@pos: add bl, ah { number of chars in str2 left }
 mov al, bh { length str2 --> AX }
 sub al, bl { start position of str1 in str2 }
@exit: { we are finished. }
end { StrPos };
procedure Trim( var Str: string ); assembler;
 { remove leading and trailing white space from str }
 { white space = all ASCII chars 0h - 20h }
asm { setup }
 lds si, str { load in DS:SI pointer to Str }
 xor cx, cx { clear cx }
 mov cl, [si] { length Str --> cx }
 jcxz @exit { if length Str = 0, exit }
 mov bx, si { save pointer to length byte of Str }
 add si, cx { last character }
 { look for trailing space }
@loop1: mov al, [si] { load character }
 cmp al, ' ' { no white space }
 ja @stop1 { first non-blank character found }
 dec si { next character }
 dec cx { count down }
 jcxz @done { if no more characters left, done }
 jmp @loop1 { try again }
@stop1: mov si, bx { point to start of Str }
 inc si { point to 1st character }
 mov di, si { pointer to Str --> DI }
 { look for leading white space }
@loop2: mov al, [si] { load character }
 cmp al, ' ' { no white space }
 ja @stop2 { first non-blank character found }
 inc si { next character }
 dec cx { count down }
 jcxz @done { if no more characters left, done }
 jmp @loop2 { try again }
 { remove leading white space }
@stop2: cld { string operations forward }
 mov dx, cx { save new length Str }
 rep movsb { move remaining part of Str }
 mov cx, dx { restore new length Str }
@done: mov [bx], cl { new length of Str }
@exit:
end { Trim };
function InSet25(var _Set; OrdElement: Byte): Boolean;
 { I got this function from Bob Swart }
InLine(
 58ドル/ { pop AX }
 30ドル/$E4/ { xor AH,AH }
 5ドルF/ { pop DI }
 07ドル/ { pop ES }
 89ドル/$C3/ { mov BX,AX }
 $B1/03ドル/ { mov CL,3 }
 $D3/$EB/ { shr BX,CL }
 88ドル/$C1/ { mov CL,AL }
 80ドル/$E1/07ドル/ { and CL,07ドル }
 $B0/01ドル/ { mov AL,1 }
 $D2/$E0/ { shl AL,CL }
 26ドル/ { ES: }
 22ドル/01ドル/ { and AL,BYTE PTR [DI+BX] }
 $D2/$E8); { shr AL,CL }
{ InSet25 }
function OpenTextFile (var InF: text; const name: string; var buffer: BufTypeSource): boolean;
begin
 Assign( InF, Name );
 SetTextBuf( InF, buffer );
 Reset( InF );
 OpenTextFile := (IOResult = 0);
end { OpenTextFile };
function CreateTextFile (var OutF: text; const name: string; var buffer: BufTypeDest): boolean;
begin
 Assign( OutF, Name );
 SetTextBuf( OutF, buffer );
 Rewrite( OutF );
 CreateTextFile := (IOResult = 0);
end { CreateTextFile };
function Exist( Name : string ) : Boolean;
 { Return true if directory or file with the same name is found}
var
 F : file;
 Attr : Word;
begin
 Assign( F, Name );
 GetFAttr( F, Attr );
 Exist := (DosError = 0)
end;
{$IFDEF Kort}
procedure UniekeEntry( var Naam : string3 );
const
 max = 39ドル; { '0'..'9' = 30ドル..39ドル }
var
 Nbyte : array [0..3] of byte absolute Naam;
 Exists : boolean;
begin
 Nbyte [0] := 3; { FileName of 3 characters }
 Exists := True;
 Nbyte [1] := 30ドル;
 while (Nbyte [1] <= max) and Exists do begin Nbyte [2] := 30ドル; while (Nbyte [2] <= max) and Exists do begin Nbyte [3] := 30ドル; while (Nbyte [3] <= max) and Exists do begin Exists := Exist( Naam ); if Exists then inc( Nbyte [3] ); end; if Exists then inc( Nbyte [2] ); end; if Exists then inc( Nbyte [1] ); end; end; { end procedure UniekeEntry } {$ELSE} procedure UniekeEntry( var Naam : string12 ); const max = 39ドル; { '0'..'9' = 30ドル..39ドル } var Nbyte : array [0..12] of byte absolute Naam; Exists : boolean; begin Nbyte [0] := 12; { FileName of 12 characters (8+3+".") } Nbyte [9] := 2ドルE; { '.' as 9e character } Exists := True; Nbyte [1] := 30ドル; while (Nbyte [1] <= max) and Exists do begin Nbyte [2] := 30ドル; while (Nbyte [2] <= max) and Exists do begin Nbyte [3] := 30ドル; while (Nbyte [3] <= max) and Exists do begin Nbyte [4] := 30ドル; while (Nbyte [4] <= max) and Exists do begin Nbyte [5] := 30ドル; while (Nbyte [5] <= max) and Exists do begin Nbyte [6] := 30ドル; while (Nbyte [6] <= max) and Exists do begin Nbyte [7] := 30ドル; while (Nbyte [7] <= max) and Exists do begin Nbyte [8] := 30ドル; while (Nbyte [8] <= max) and Exists do begin Nbyte [10] := 30ドル; while (Nbyte [10] <= max) and Exists do begin Nbyte [11] := 30ドル; while (Nbyte [11] <= max) and Exists do begin Nbyte [12] := 30ドル; while (Nbyte [12] <= max) and Exists do begin Exists := Exist( Naam ); if Exists then inc( Nbyte [12] ); end; if Exists then inc( Nbyte [11] ); end; if Exists then inc( Nbyte [10] ); end; if Exists then inc( Nbyte [8] ); end; if Exists then inc( Nbyte [7] ); end; if Exists then inc( Nbyte [6] ); end; if Exists then inc( Nbyte [5] ); end; if Exists then inc( Nbyte [4] ); end; if Exists then inc( Nbyte [3] ); end; if Exists then inc( Nbyte [2] ); end; if Exists then inc( Nbyte [1] ); end; end; { end procedure UniekeEntry } {$ENDIF} procedure Search; begin found := False; NrSearch := 1; while (NrSearch <= TotalNrSearch) and not found do begin nr := 1; while (nr <= NrLines) and not found do begin { search wanted text } StrCopy( Line[nr], Tmp1 ); LowerFast( Tmp1 ); { convert to lower case } if StrPos( SearchText[NrSearch], Tmp1 )> 0 then found := True;
 inc( nr );
 end;
 inc( NrSearch );
 end;
 if found then { at least one of the wanted words found }
 begin
 for nr := 1 to NrLines do WriteLn( DestFile, Line[nr] );
 inc( Count );
 end;
end;
procedure Process( var SourceListing : string12 );
begin
 Count := 0;
 DestListing := DestDir + '\' + SourceListing;
 if OpenTextFile( SourceFile, SourceListing, SourceBuf ) then
 begin
 if CreateTextFile( DestFile, DestListing, DestBuf ) then
 begin
 write( SourceListing:12 );
 Header := False;
 FileName := '';
 NrLines := 0;
 nr := 1;
 ReadLn( SourceFile, Line[nr] );
 while not Eof(SourceFile) and (IOResult = 0) do
 begin
 StrCopy( Line[nr], Tmp1 );
 Trim( Tmp1 );
 if Length( Tmp1 )> 0 then { no empty lines }
 begin
 CopySubStr( Line[nr], 1, 12, FileName );
 Trim( FileName );
 T := 1;
 while (T <= Length( FileName )) and not InSet25( NotAllowed, Byte( FileName[T] ) ) do inc( T ); { look out for headers } { } Header := (T <= Length( FileName )) or ((Length( FileName )> 0) and (Line[nr][1]=' ')); { header? }
 if Header then
 FileName := '' { read next line }
 else { no header }
 begin
 if (Length( FileName ) = 0) then { more description }
 begin
 inc( nr );
 inc( NrLines );
 end
 else
 begin
 StrCopy( Line[nr], Tmp2 ); { save new textline }
 Search;
 { setup for next entry }
 NrLines := 1; { already got one line }
 nr := 2; { so next line in #2 }
 StrCopy( Tmp2, Line[1] ); { restore new textline }
 FileName := ''; { make sure a new line is read }
 end; { endif (Length( FileName ) = 0)) }
 end; { if Header }
 end; { if Length( Tmp1 )> 0 }
 if (Length( FileName ) = 0) then
 ReadLn( SourceFile, Line[nr] );
 { }
 end; { while not Eof(SourceFile) and (IOResult = 0) }
 inc( NrLines ); { include the last line in the search }
 Search;
 Close( DestFile );
 if (Count = 0) then
 begin
 Erase( DestFile );
 Write( #13 );
 end
 else
 begin
 writeln( Count:7, ' in ', DestListing );
 TotalCount := TotalCount + Count;
 end
 end { if CreateTextFile }
 else
 writeln( Cannot, 'file ', DestListing );
 { }
 Close( SourceFile );
 end { if OpenTextFile }
 else
 writeln( 'Cannot open sourcefile ', SourceListing );
 { }
end;
begin
 if ParamCount> 1 then { parameters: listing catchwords }
 begin
 TotalCount := 0;
 TotalNrSearch := ParamCount - 1;
 if (TotalNrSearch> MaxNrSearch) then
 TotalNrSearch := MaxNrSearch; { no more catchwords than maximum }
 UniekeEntry( DestDir );
 if not Exists then
 begin
 MkDir( DestDir );
 if (IOResult=0) then
 begin
 Write( 'Searching:' );
 FMask := ParamStr( 1 ); { filemask }
 for NrSearch := 1 to TotalNrSearch do { all catchwords }
 begin
 SearchText[NrSearch] := ParamStr( NrSearch+1 ); { each catchword }
 LowerFast( SearchText[NrSearch] ); { translate to lower case }
 Write(' ', SearchText[NrSearch] );
 end;
 WriteLn;
 FindFirst(FMask, FAttr, FR);
 while DosError = 0 do
 begin
 Process(FR.Name);
 FindNext(FR);
 end;
 WriteLn( 'Total found ', TotalCount, ' entries.' );
 if (TotalCount = 0) then RmDir( DestDir );
 end; { if not IOResult }
 end { if not Exists }
 else
 writeln( Cannot, 'directory ', DestListing );
 { }
 end { if ParamCount> 1 }
 else
 WriteLn( 'Extract filename word(s)' );
end.


AltStyle によって変換されたページ (->オリジナル) /