[Back to MISC SWAG index] [Back to Main SWAG index] [Original]
{$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 = $1C; { 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(
$8C/$DA/ { mov DX,DS }
$BB/Ord('A')/
Ord('Z')-Ord('A')/ { mov BX,'Z'-'A'/'A' }
$5E/ { pop SI }
$1F/ { pop DS }
$FC/ { cld }
$AC/ { lodsb }
$88/$C1/ { mov CL,AL }
$30/$ED/ { xor CH,CH }
$D1/$E9/ { shr CX,1 }
$73/$0B/ { 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 }
$8E/$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 }
$5F/ { 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] := $2E; { '.' 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.
[Back to MISC SWAG index] [Back to Main SWAG index] [Original]