📄 ststrs.pas
字号:
pop edi
end;
function BMSearchS(var Buffer; BufLength : Cardinal; var BT : BTable;
const MatchString : ShortString ; var Pos : Cardinal) : Boolean; assembler;
{-Use the Boyer-Moore search method to search a buffer for a string.}
register;
var
BufPtr : Pointer;
asm
push edi { Save registers since we will be changing }
push esi
push ebx
mov BufPtr, eax { Copy Buffer to local variable and EDI }
mov edi, eax
mov ebx, ecx { Copy BT ptr to EBX }
mov ecx, edx { Length of buffer to ECX }
mov esi, MatchString { Set ESI to beginning of MatchString }
xor eax, eax { Zero EAX }
mov dl, [esi] { Length of MatchString in EDX }
inc esi
and edx, 0FFh
cmp dl, 1 { Check to see if we have a trivial case }
ja @@BMSInit { If Length(MatchString) > 1 do BM search }
jb @@BMSNotFound { If Length(MatchString) = 0 we're done }
mov al,[esi] { If Length(MatchString) = 1 do a REPNE SCASB }
mov ebx, edi
repne scasb
jne @@BMSNotFound { No match during REP SCASB }
mov esi, Pos { Set position in Pos }
{dec edi} { Found, calculate position }
sub edi, ebx
mov eax, 1 { Set result to True }
mov [esi], edi
jmp @@BMSDone { We're done }
@@BMSInit:
dec edx { Set up for BM Search }
add esi, edx { Set ESI to end of MatchString }
add ecx, edi { Set ECX to end of buffer }
add edi, edx { Set EDI to first check point }
std { Backward string ops }
mov dh, [esi] { Set DH to character we'll be looking for }
dec esi { Dec ESI in prep for BMSFound loop }
jmp @@BMSComp { Jump to first comparison }
@@BMSNext:
mov al, [ebx+eax] { Look up skip distance from table }
add edi, eax { Skip EDI ahead to next check point }
@@BMSComp:
cmp edi, ecx { Have we reached end of buffer? }
jae @@BMSNotFound { If so, we're done }
mov al, [edi] { Move character from buffer into AL for comparison }
cmp dh, al { Compare }
jne @@BMSNext { If not equal, go to next checkpoint }
push ecx { Save ECX }
dec edi
xor ecx, ecx { Zero ECX }
mov cl, dl { Move Length(MatchString) to ECX }
repe cmpsb { Compare MatchString to buffer }
je @@BMSFound { If equal, string is found }
mov al, dl { Move Length(MatchString) to AL }
sub al, cl { Calculate offset that string didn't match }
add esi, eax { Move ESI back to end of MatchString }
add edi, eax { Move EDI to pre-string compare location }
inc edi
mov al, dh { Move character back to AL }
pop ecx { Restore ECX }
jmp @@BMSNext { Do another compare }
@@BMSFound: { EDI points to start of match }
mov edx, BufPtr { Move pointer to buffer into EDX }
mov esi, Pos
sub edi, edx { Calculate position of match }
mov eax, edi
inc eax
inc eax { Pos is one based }
mov [esi], eax { Set Pos to position of match }
mov eax, 1 { Set result to True }
pop ecx { Restore ESP }
jmp @@BMSDone
@@BMSNotFound:
xor eax, eax { Set result to False }
@@BMSDone:
cld { Restore direction flag }
pop ebx { Restore registers }
pop esi
pop edi
end;
function BMSearchUCS(var Buffer; BufLength : Cardinal; var BT : BTable;
const MatchString : ShortString ; var Pos : Cardinal) : Boolean; assembler;
{-Use the Boyer-Moore search method to search a buffer for a string. This
search is not case sensitive.}
register;
var
BufPtr : Pointer;
asm
push edi { Save registers since we will be changing }
push esi
push ebx
mov BufPtr, eax { Copy Buffer to local variable and ESI }
mov edi, eax
mov ebx, ecx { Copy BT ptr to EBX }
mov ecx, edx { Length of buffer to ECX }
mov esi, MatchString { Set ESI to beginning of MatchString }
xor eax, eax { Zero EAX }
mov dl, byte ptr [esi] { Length of MatchString in EDX }
and edx, 0FFh { Clean up EDX }
inc esi { Set ESI to first character }
or dl, dl { Check to see if we have a trivial case }
jz @@BMSNotFound { If Length(MatchString) = 0 we're done }
@@BMSInit:
dec edx { Set up for BM Search }
add esi, edx { Set ESI to end of MatchString }
add ecx, edi { Set ECX to end of buffer }
add edi, edx { Set EDI to first check point }
std { Backward string ops }
mov dh, [esi] { Set DH to character we'll be looking for }
dec esi { Dec ESI in prep for BMSFound loop }
jmp @@BMSComp { Jump to first comparison }
@@BMSNext:
mov al, [ebx+eax] { Look up skip distance from table }
add edi, eax { Skip EDI ahead to next check point }
@@BMSComp:
cmp edi, ecx { Have we reached end of buffer? }
jae @@BMSNotFound { If so, we're done }
push ebx { Save registers }
push ecx
push edx
mov al, [edi] { Move character from buffer into AL for comparison }
push eax { Push Char onto stack for CharUpper }
cld
call CharUpper
std
pop edx { Restore registers }
pop ecx
pop ebx
cmp dh, al { Compare }
jne @@BMSNext { If not equal, go to next checkpoint }
push ecx { Save ECX }
dec edi
xor ecx, ecx { Zero ECX }
mov cl, dl { Move Length(MatchString) to ECX }
jecxz @@BMSFound { If ECX is zero, string is found }
@@StringComp:
xor eax, eax
mov al, [edi] { Get char from buffer }
dec edi { Dec buffer index }
push ebx { Save registers }
push ecx
push edx
push eax { Push Char onto stack for CharUpper }
cld
call CharUpper
std
pop edx { Restore registers }
pop ecx
pop ebx
mov ah, al { Move buffer char to AH }
mov al, [esi] { Get MatchString char }
dec esi
cmp ah, al { Compare }
loope @@StringComp { OK? Get next character }
je @@BMSFound { Matched! }
xor ah, ah { Zero AH }
mov al, dl { Move Length(MatchString) to AL }
sub al, cl { Calculate offset that string didn't match }
add esi, eax { Move ESI back to end of MatchString }
add edi, eax { Move EDI to pre-string compare location }
inc edi
mov al, dh { Move character back to AL }
pop ecx { Restore ECX }
jmp @@BMSNext { Do another compare }
@@BMSFound: { EDI points to start of match }
mov edx, BufPtr { Move pointer to buffer into EDX }
mov esi, Pos
sub edi, edx { Calculate position of match }
mov eax, edi
inc eax
inc eax { Pos is one based }
mov [esi], eax { Set Pos to position of match }
mov eax, 1 { Set result to True }
pop ecx { Restore ESP }
jmp @@BMSDone
@@BMSNotFound:
xor eax, eax { Set result to False }
@@BMSDone:
cld { Restore direction flag }
pop ebx { Restore registers }
pop esi
pop edi
end;
{--------------- DOS pathname parsing -----------------}
function DefaultExtensionS(const Name, Ext : ShortString) : ShortString;
{-Return a file name with a default extension attached.}
var
DotPos : Cardinal;
begin
if HasExtensionS(Name, DotPos) then
Result := Name
else if Name = '' then
Result := ''
else
Result := Name + '.' + Ext;
end;
function ForceExtensionS(const Name, Ext : ShortString) : ShortString;
{-Force the specified extension onto the file name.}
var
DotPos : Cardinal;
begin
if HasExtensionS(Name, DotPos) then
Result := Copy(Name, 1, DotPos) + Ext
else if Name = '' then
Result := ''
else
Result := Name + '.' + Ext;
end;
function JustFilenameS(const PathName : ShortString) : ShortString;
{-Return just the filename and extension of a pathname.}
var
I : Longint;
begin
Result := '';
if PathName = '' then
Exit;
I := Succ(Length(PathName));
repeat
Dec(I);
until (I = 0) or (PathName[I] in DosDelimSet); {!!.01}
Result := Copy(PathName, Succ(I), StMaxFileLen);
end;
function JustNameS(const PathName : ShortString) : ShortString;
{-Return just the filename (no extension, path, or drive) of a pathname.}
var
DotPos : Cardinal;
begin
Result := JustFileNameS(PathName);
if HasExtensionS(Result, DotPos) then
Result := Copy(Result, 1, DotPos-1);
end;
function JustExtensionS(const Name : ShortString) : ShortString;
{-Return just the extension of a pathname.}
var
DotPos : Cardinal;
begin
if HasExtensionS(Name, DotPos) then
Result := Copy(Name, Succ(DotPos), StMaxFileLen)
else
Result := '';
end;
function JustPathnameS(const PathName : ShortString) : ShortString;
{-Return just the drive and directory portion of a pathname.}
var
I : Longint;
begin
I := Succ(Length(PathName));
repeat
Dec(I);
until (I = 0) or (PathName[I] in DosDelimSet); {!!.01}
if I = 0 then
{Had no drive or directory name}
Result [0] := #0
else if I = 1 then
{Either the root directory of default drive or invalid pathname}
Result := PathName[1]
else if (PathName[I] = '\') then begin
if PathName[Pred(I)] = ':' then
{Root directory of a drive, leave trailing backslash}
Result := Copy(PathName, 1, I)
else
{Subdirectory, remove the trailing backslash}
Result := Copy(PathName, 1, Pred(I));
end else
{Either the default directory of a drive or invalid pathname}
Result := Copy(PathName, 1, I);
end;
function AddBackSlashS(const DirName : ShortString) : ShortString;
{-Add a default backslash to a directory name}
begin
Result := DirName;
if (Length(Result) = 0) then
Exit;
if ((Length(Result) = 2) and (Result[2] = ':')) or
((Length(Result) > 2) and (Result[Length(Result)] <> '\')) then
Result := Result + '\';
end;
function CleanFileNameS(const FileName : ShortString) : ShortString;
{-Return filename with at most 8 chars of name and 3 of extension}
var
DotPos : Cardinal;
NameLen : Cardinal;
begin
if HasExtensionS(FileName, DotPos) then begin
{Take the first 8 chars of name and first 3 chars of extension}
NameLen := Pred(DotPos);
if NameLen > 8 then
NameLen := 8;
Result := Copy(FileName, 1, NameLen)+Copy(FileName, DotPos, 4);
end else
{Take the first 8 chars of name}
Result := Copy(FileName, 1, 8);
end;
function CleanPathNameS(const PathName : ShortString) : ShortString;
{-Return a pathname cleaned up as DOS does it.}
var
I : Longint;
S : ShortString;
begin
Result[0] := #0;
S := PathName;
I := Succ(Length(S));
repeat
dec(I);
if I > 2 then
if (S[I] = '\') and (S[I-1] = '\') then
if (S[I-2] <> ':') then
Delete(S, I, 1);
until I <= 0;
I := Succ(Length(S));
repeat
{Get the next directory or drive portion of pathname}
repeat
Dec(I);
until (I = 0) or (S[I] in DosDelimSet); {!!.02}
{Clean it up and prepend it to output string}
Result := CleanFileNameS(Copy(S, Succ(I), StMaxFileLen)) + Result;
if I > 0 then begin
Result := S[I] + Result;
Delete(S, I, 255);
end;
until I <= 0;
end;
function HasExtensionS(const Name : ShortString; var DotPos : Cardinal) : Boolean;
{-Determine if a pathname contains an extension and, if so, return the
position of the dot in front of the extension.}
var
I : Cardinal;
begin
DotPos := 0;
for I := Length(Name) downto 1 do
if (Name[I] = '.') and (DotPos = 0) then
DotPos := I;
Result := (DotPos > 0)
{and (Pos('\', Copy(Name, Succ(DotPos), MaxFileLen)) = 0);}
and not CharExistsS(Copy(Name, Succ(DotPos), StMaxFileLen), '\');
end;
{------------------ Formatting routines --------------------}
function CommaizeChS(L : Longint; Ch : AnsiChar) : ShortString;
{-Convert a long integer to a string with Ch in comma positions}
var
NumCommas, I, Len : Cardinal;
Neg : Boolean;
begin
if L < 0 then begin
Neg := True;
L := Abs(L);
end else
Neg := False;
Result := Long2StrS(L);
Len := Length(Result);
NumCommas := (Len - 1) div 3;
for I := 1 to NumCommas do
System.Insert(Ch, Result, Len-(I * 3)+1);
if Neg then
System.Insert('-', Result, 1);
end;
function CommaizeS(L : LongInt) : ShortString;
{-Convert a long integer to a string w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -