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.