mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-14 15:39:25 +02:00
593 lines
14 KiB
PHP
593 lines
14 KiB
PHP
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 1999-2000 by the Free Pascal development team
|
|
|
|
Processor dependent part of strings.pp, that can be shared with
|
|
sysutils unit.
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
|
|
{$ASMMODE ATT}
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRCOPY}
|
|
{$define FPC_UNIT_HAS_STRCOPY}
|
|
function strcopy(dest,source : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveeax,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl %edx,%edi
|
|
testl %edi,%edi
|
|
jz .LStrCopyDone
|
|
leal 3(%edi),%ecx
|
|
andl $-4,%ecx
|
|
movl %edi,%esi
|
|
subl %edi,%ecx
|
|
movl %eax,%edi
|
|
jz .LStrCopyAligned
|
|
.LStrCopyAlignLoop:
|
|
movb (%esi),%al
|
|
incl %edi
|
|
incl %esi
|
|
testb %al,%al
|
|
movb %al,-1(%edi)
|
|
jz .LStrCopyDone
|
|
decl %ecx
|
|
jnz .LStrCopyAlignLoop
|
|
.balign 16
|
|
.LStrCopyAligned:
|
|
movl (%esi),%eax
|
|
movl %eax,%edx
|
|
leal 0x0fefefeff(%eax),%ecx
|
|
notl %edx
|
|
addl $4,%esi
|
|
andl %edx,%ecx
|
|
andl $0x080808080,%ecx
|
|
jnz .LStrCopyEndFound
|
|
movl %eax,(%edi)
|
|
addl $4,%edi
|
|
jmp .LStrCopyAligned
|
|
.LStrCopyEndFound:
|
|
testl $0x0ff,%eax
|
|
jz .LStrCopyByte
|
|
testl $0x0ff00,%eax
|
|
jz .LStrCopyWord
|
|
testl $0x0ff0000,%eax
|
|
jz .LStrCopy3Bytes
|
|
movl %eax,(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopy3Bytes:
|
|
xorb %dl,%dl
|
|
movw %ax,(%edi)
|
|
movb %dl,2(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopyWord:
|
|
movw %ax,(%edi)
|
|
jmp .LStrCopyDone
|
|
.LStrCopyByte:
|
|
movb %al,(%edi)
|
|
.LStrCopyDone:
|
|
movl saveeax,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRCOPY}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRECOPY}
|
|
{$define FPC_UNIT_HAS_STRECOPY}
|
|
function strecopy(dest,source : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
movl dest,%esi
|
|
movl source,%edi
|
|
movl $0xffffffff,%ecx
|
|
xorl %eax,%eax
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
movl %esi,%edi
|
|
movl source,%esi
|
|
movl %ecx,%eax
|
|
shrl $2,%ecx
|
|
rep
|
|
movsl
|
|
movl %eax,%ecx
|
|
andl $3,%ecx
|
|
rep
|
|
movsb
|
|
decl %edi
|
|
movl %edi,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRECOPY}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRLCOPY}
|
|
{$define FPC_UNIT_HAS_STRLCOPY}
|
|
function strlcopy(dest,source : PAnsiChar;maxlen : sizeint) : PAnsiChar;assembler;
|
|
var
|
|
savedest,
|
|
saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl source,%esi
|
|
movl maxlen,%ecx
|
|
movl dest,%edi
|
|
movl %edi,savedest
|
|
orl %ecx,%ecx
|
|
jz .LSTRLCOPY2
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
.LSTRLCOPY1:
|
|
lodsb
|
|
stosb
|
|
decl %ecx // Lower maximum
|
|
jz .LSTRLCOPY2 // 0 reached ends
|
|
orb %al,%al
|
|
jnz .LSTRLCOPY1
|
|
jmp .LSTRLCOPY3
|
|
.LSTRLCOPY2:
|
|
xorb %al,%al // If cutted
|
|
stosb // add a #0
|
|
.LSTRLCOPY3:
|
|
movl savedest,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRLCOPY}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STREND}
|
|
{$define FPC_UNIT_HAS_STREND}
|
|
function strend(p : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
movl p,%edi
|
|
xorl %eax,%eax
|
|
orl %edi,%edi
|
|
jz .LStrEndNil
|
|
movl $0xffffffff,%ecx
|
|
repne
|
|
scasb
|
|
movl %edi,%eax
|
|
decl %eax
|
|
.LStrEndNil:
|
|
movl saveedi,%edi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STREND}
|
|
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRCOMP}
|
|
{$define FPC_UNIT_HAS_STRCOMP}
|
|
function strcomp(str1,str2 : pansichar) : longint;assembler;
|
|
var
|
|
saveeax,saveedx,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl %edx,saveedx
|
|
movl str2,%edi
|
|
movl $0xffffffff,%ecx
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
xorl %eax,%eax
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
movl saveedx,%edi
|
|
movl saveeax,%esi
|
|
repe
|
|
cmpsb
|
|
movb -1(%esi),%al
|
|
movzbl -1(%edi),%ecx
|
|
subl %ecx,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRCOMP}
|
|
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRLCOMP}
|
|
{$define FPC_UNIT_HAS_STRLCOMP}
|
|
function strlcomp(str1,str2 : PAnsiChar;l : sizeint) : longint;assembler;
|
|
var
|
|
saveeax,saveedx,saveecx,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl %edx,saveedx
|
|
movl %ecx,saveecx
|
|
movl str2,%edi
|
|
movl $0xffffffff,%ecx
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
xorl %eax,%eax
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
cmpl saveecx,%ecx
|
|
jl .LSTRLCOMP1
|
|
movl saveecx,%ecx
|
|
.LSTRLCOMP1:
|
|
movl saveedx,%edi
|
|
movl saveeax,%esi
|
|
repe
|
|
cmpsb
|
|
movb -1(%esi),%al
|
|
movzbl -1(%edi),%ecx
|
|
subl %ecx,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRLCOMP}
|
|
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRICOMP}
|
|
{$define FPC_UNIT_HAS_STRICOMP}
|
|
function stricomp(str1,str2 : PAnsiChar) : longint;assembler;
|
|
var
|
|
saveeax,saveedx,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl %edx,saveedx
|
|
movl str2,%edi
|
|
movl $0xffffffff,%ecx
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
xorl %eax,%eax
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
movl saveedx,%edi
|
|
movl saveeax,%esi
|
|
.LSTRICOMP2:
|
|
repe
|
|
cmpsb
|
|
jz .LSTRICOMP3 // If last reached then exit
|
|
movzbl -1(%esi),%eax
|
|
movzbl -1(%edi),%edx
|
|
cmpb $97,%al
|
|
jb .LSTRICOMP1
|
|
cmpb $122,%al
|
|
ja .LSTRICOMP1
|
|
subb $0x20,%al
|
|
.LSTRICOMP1:
|
|
cmpb $97,%dl
|
|
jb .LSTRICOMP4
|
|
cmpb $122,%dl
|
|
ja .LSTRICOMP4
|
|
subb $0x20,%dl
|
|
.LSTRICOMP4:
|
|
subl %edx,%eax
|
|
jz .LSTRICOMP2 // If still equal, compare again
|
|
.LSTRICOMP3:
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRICOMP}
|
|
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRLICOMP}
|
|
{$define FPC_UNIT_HAS_STRLICOMP}
|
|
function strlicomp(str1,str2 : PAnsiChar;l : sizeint) : longint;assembler;
|
|
var
|
|
saveeax,saveedx,saveecx,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl %edx,saveedx
|
|
movl %ecx,saveecx
|
|
movl str2,%edi
|
|
movl $0xffffffff,%ecx
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
xorl %eax,%eax
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
cmpl saveecx,%ecx
|
|
jl .LSTRLICOMP5
|
|
movl saveecx,%ecx
|
|
.LSTRLICOMP5:
|
|
movl saveedx,%edi
|
|
movl saveeax,%esi
|
|
.LSTRLICOMP2:
|
|
repe
|
|
cmpsb
|
|
jz .LSTRLICOMP3 // If last reached, exit
|
|
movzbl -1(%esi),%eax
|
|
movzbl -1(%edi),%edx
|
|
cmpb $97,%al
|
|
jb .LSTRLICOMP1
|
|
cmpb $122,%al
|
|
ja .LSTRLICOMP1
|
|
subb $0x20,%al
|
|
.LSTRLICOMP1:
|
|
cmpb $97,%dl
|
|
jb .LSTRLICOMP4
|
|
cmpb $122,%dl
|
|
ja .LSTRLICOMP4
|
|
subb $0x20,%dl
|
|
.LSTRLICOMP4:
|
|
subl %edx,%eax
|
|
jz .LSTRLICOMP2
|
|
.LSTRLICOMP3:
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRLICOMP}
|
|
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRSCAN}
|
|
{$define FPC_UNIT_HAS_STRSCAN}
|
|
function strscan(p : PAnsiChar;c : AnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
xorl %ecx,%ecx
|
|
testl %eax,%eax
|
|
jz .LSTRSCAN
|
|
// align
|
|
movb c,%cl
|
|
leal 3(%eax),%esi
|
|
andl $-4,%esi
|
|
movl %eax,%edi
|
|
subl %eax,%esi
|
|
jz .LSTRSCANALIGNED
|
|
xorl %eax,%eax
|
|
.LSTRSCANALIGNLOOP:
|
|
movb (%edi),%al
|
|
// at .LSTRSCANFOUND, one is substracted from edi to calculate the position,
|
|
// so add 1 here already (not after .LSTRSCAN, because then the test/jz and
|
|
// cmp/je can't be paired)
|
|
incl %edi
|
|
testb %al,%al
|
|
jz .LSTRSCAN
|
|
cmpb %cl,%al
|
|
je .LSTRSCANFOUND
|
|
decl %esi
|
|
jnz .LSTRSCANALIGNLOOP
|
|
.LSTRSCANALIGNED:
|
|
// fill ecx with cccc
|
|
movl %ecx,%eax
|
|
shll $8,%eax
|
|
orl %eax,%ecx
|
|
movl %ecx,%eax
|
|
shll $16,%eax
|
|
orl %eax,%ecx
|
|
.balign 16
|
|
.LSTRSCANLOOP:
|
|
// load new 4 bytes
|
|
movl (%edi),%edx
|
|
// in eax, we will check if "c" appear in the loaded dword
|
|
movl %edx,%eax
|
|
// esi will be used to calculate the mask
|
|
movl %edx,%esi
|
|
notl %esi
|
|
// in edx we will check for the end of the string
|
|
addl $0x0fefefeff,%edx
|
|
xorl %ecx,%eax
|
|
andl $0x080808080,%esi
|
|
addl $4,%edi
|
|
andl %esi,%edx
|
|
movl %eax,%esi
|
|
notl %esi
|
|
jnz .LSTRSCANLONGCHECK
|
|
addl $0x0fefefeff,%eax
|
|
andl $0x080808080,%esi
|
|
andl %esi,%eax
|
|
jz .LSTRSCANLOOP
|
|
|
|
// the position in %eax where the char was found is now $80, so keep on
|
|
// shifting 8 bits out of %eax until we find a non-zero bit.
|
|
// first char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND1
|
|
// second char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND2
|
|
// third char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND3
|
|
// fourth char
|
|
jmp .LSTRSCANFOUND
|
|
.LSTRSCANLONGCHECK:
|
|
// there's a null somewhere, but we still have to check whether there isn't
|
|
// a 'c' before it.
|
|
addl $0x0fefefeff,%eax
|
|
andl $0x080808080,%esi
|
|
andl %esi,%eax
|
|
// Now, in eax we have $80 on the positions where there were c-chars and in
|
|
// edx we have $80 on the positions where there were #0's. On all other
|
|
// positions, there is now #0
|
|
// first char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND1
|
|
shrl $8,%edx
|
|
jc .LSTRSCANNOTFOUND
|
|
// second char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND2
|
|
shrl $8,%edx
|
|
jc .LSTRSCANNOTFOUND
|
|
// third char
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND3
|
|
shrl $8,%edx
|
|
jc .LSTRSCANNOTFOUND
|
|
// we know the fourth char is now #0 (since we only jump to the long check if
|
|
// there is a #0 char somewhere), but it's possible c = #0, and than we have
|
|
// to return the end of the string and not nil!
|
|
shrl $8,%eax
|
|
jc .LSTRSCANFOUND
|
|
jmp .LSTRSCANNOTFOUND
|
|
.LSTRSCANFOUND3:
|
|
leal -2(%edi),%eax
|
|
jmp .LSTRSCAN
|
|
.LSTRSCANFOUND2:
|
|
leal -3(%edi),%eax
|
|
jmp .LSTRSCAN
|
|
.LSTRSCANFOUND1:
|
|
leal -4(%edi),%eax
|
|
jmp .LSTRSCAN
|
|
.LSTRSCANFOUND:
|
|
leal -1(%edi),%eax
|
|
jmp .LSTRSCAN
|
|
.LSTRSCANNOTFOUND:
|
|
xorl %eax,%eax
|
|
.LSTRSCAN:
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRSCAN}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRRSCAN}
|
|
{$define FPC_UNIT_HAS_STRRSCAN}
|
|
function strrscan(p : PAnsiChar;c : AnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveeax,
|
|
saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %eax,saveeax
|
|
movl p,%edi
|
|
xorl %eax,%eax
|
|
orl %edi,%edi
|
|
jz .LSTRRSCAN
|
|
movl $0xffffffff,%ecx
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
xorb %al,%al
|
|
repne
|
|
scasb
|
|
not %ecx
|
|
movb c,%al
|
|
movl saveeax,%edi
|
|
addl %ecx,%edi
|
|
decl %edi
|
|
std
|
|
repne
|
|
scasb
|
|
cld
|
|
movl $0,%eax
|
|
jnz .LSTRRSCAN
|
|
movl %edi,%eax
|
|
incl %eax
|
|
.LSTRRSCAN:
|
|
movl saveedi,%edi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRRSCAN}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRUPPER}
|
|
{$define FPC_UNIT_HAS_STRUPPER}
|
|
function strupper(p : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveeax,saveesi,saveedi : longint;
|
|
asm
|
|
movl %edi,saveedi
|
|
movl %esi,saveesi
|
|
movl %eax,saveeax
|
|
movl p,%esi
|
|
orl %esi,%esi
|
|
jz .LStrUpperNil
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
movl %esi,%edi
|
|
.LSTRUPPER1:
|
|
lodsb
|
|
cmpb $97,%al
|
|
jb .LSTRUPPER3
|
|
cmpb $122,%al
|
|
ja .LSTRUPPER3
|
|
subb $0x20,%al
|
|
.LSTRUPPER3:
|
|
stosb
|
|
orb %al,%al
|
|
jnz .LSTRUPPER1
|
|
.LStrUpperNil:
|
|
movl saveeax,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRUPPER}
|
|
|
|
|
|
{$ifndef FPC_UNIT_HAS_STRLOWER}
|
|
{$define FPC_UNIT_HAS_STRLOWER}
|
|
function strlower(p : PAnsiChar) : PAnsiChar;assembler;
|
|
var
|
|
saveeax,saveesi,saveedi : longint;
|
|
asm
|
|
movl %esi,saveesi
|
|
movl %edi,saveedi
|
|
movl %eax,saveeax
|
|
movl p,%esi
|
|
orl %esi,%esi
|
|
jz .LStrLowerNil
|
|
{$ifdef FPC_ENABLED_CLD}
|
|
cld
|
|
{$endif FPC_ENABLED_CLD}
|
|
movl %esi,%edi
|
|
.LSTRLOWER1:
|
|
lodsb
|
|
cmpb $65,%al
|
|
jb .LSTRLOWER3
|
|
cmpb $90,%al
|
|
ja .LSTRLOWER3
|
|
addb $0x20,%al
|
|
.LSTRLOWER3:
|
|
stosb
|
|
orb %al,%al
|
|
jnz .LSTRLOWER1
|
|
.LStrLowerNil:
|
|
movl saveeax,%eax
|
|
movl saveedi,%edi
|
|
movl saveesi,%esi
|
|
end;
|
|
{$endif FPC_UNIT_HAS_STRLOWER}
|
|
|