
{*******************************************************}
{                                                       }
{       Turbo Pascal Runtime Library                    }
{       String Handling Unit                            }
{                                                       }
{       Copyright (C) 1990,92 Borland International     }
{                                                       }
{*******************************************************}

unit Strings;

{$S-}

interface

{ StrLen returns the number of characters in Str, not counting  }
{ the null terminator.                                          }

function StrLen(Str: PChar): Word;

{ StrEnd returns a pointer to the null character that           }
{ terminates Str.                                               }

function StrEnd(Str: PChar): PChar;

{ StrMove copies exactly Count characters from Source to Dest   }
{ and returns Dest. Source and Dest may overlap.                }

function StrMove(Dest, Source: PChar; Count: Word): PChar;

{ StrCopy copies Source to Dest and returns Dest.               }

function StrCopy(Dest, Source: PChar): PChar;

{ StrECopy copies Source to Dest and returns StrEnd(Dest).      }

function StrECopy(Dest, Source: PChar): PChar;

{ StrLCopy copies at most MaxLen characters from Source to Dest }
{ and returns Dest.                                             }

function StrLCopy(Dest, Source: PChar; MaxLen: Word): PChar;

{ StrPCopy copies the Pascal style string Source into Dest and  }
{ returns Dest.                                                 }

function StrPCopy(Dest: PChar; Source: String): PChar;

{ StrCat appends a copy of Source to the end of Dest and        }
{ returns Dest.                                                 }

function StrCat(Dest, Source: PChar): PChar;

{ StrLCat appends at most MaxLen - StrLen(Dest) characters from }
{ Source to the end of Dest, and returns Dest.                  }

function StrLCat(Dest, Source: PChar; MaxLen: Word): PChar;

{ StrComp compares Str1 to Str2. The return value is less than  }
{ 0 if Str1 < Str2, 0 if Str1 = Str2, or greater than 0 if      }
{ Str1 > Str2.                                                  }

function StrComp(Str1, Str2: PChar): Integer;

{ StrIComp compares Str1 to Str2, without case sensitivity. The }
{ return value is the same as StrComp.                          }

function StrIComp(Str1, Str2: PChar): Integer;

{ StrLComp compares Str1 to Str2, for a maximum length of       }
{ MaxLen characters. The return value is the same as StrComp.   }

function StrLComp(Str1, Str2: PChar; MaxLen: Word): Integer;

{ StrLIComp compares Str1 to Str2, for a maximum length of      }
{ MaxLen characters, without case sensitivity. The return value }
{ is the same as StrComp.                                       }

function StrLIComp(Str1, Str2: PChar; MaxLen: Word): Integer;

{ StrScan returns a pointer to the first occurrence of Chr in   }
{ Str. If Chr does not occur in Str, StrScan returns NIL. The   }
{ null terminator is considered to be part of the string.       }

function StrScan(Str: PChar; Chr: Char): PChar;

{ StrRScan returns a pointer to the last occurrence of Chr in   }
{ Str. If Chr does not occur in Str, StrRScan returns NIL. The  }
{ null terminator is considered to be part of the string.       }

function StrRScan(Str: PChar; Chr: Char): PChar;

{ StrPos returns a pointer to the first occurrence of Str2 in   }
{ Str1. If Str2 does not occur in Str1, StrPos returns NIL.     }

function StrPos(Str1, Str2: PChar): PChar;

{ StrUpper converts Str to upper case and returns Str.          }

function StrUpper(Str: PChar): PChar;

{ StrLower converts Str to lower case and returns Str.          }

function StrLower(Str: PChar): PChar;

{ StrPas converts Str to a Pascal style string.                 }

function StrPas(Str: PChar): String;

{ StrNew allocates a copy of Str on the heap. If Str is NIL or  }
{ points to an empty string, StrNew returns NIL and doesn't     }
{ allocate any heap space. Otherwise, StrNew makes a duplicate  }
{ of Str, obtaining space with a call to the GetMem standard    }
{ procedure, and returns a pointer to the duplicated string.    }
{ The allocated space is StrLen(Str) + 1 bytes long.            }

function StrNew(Str: PChar): PChar;

{ StrDispose disposes a string that was previously allocated    }
{ with StrNew. If Str is NIL, StrDispose does nothing.          }

procedure StrDispose(Str: PChar);

implementation

{$W-}

function StrLen(Str: PChar): Word; assembler;
asm
	CLD
	LES	DI,Str
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	MOV	AX,0FFFEH
	SUB	AX,CX
end;

function StrEnd(Str: PChar): PChar; assembler;
asm
	CLD
	LES	DI,Str
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	MOV	AX,DI
	MOV	DX,ES
	DEC	AX
end;

function StrMove(Dest, Source: PChar; Count: Word): PChar; assembler;
asm
	PUSH	DS
	CLD
	LDS	SI,Source
	LES	DI,Dest
	MOV	AX,DI
	MOV	DX,ES
	MOV	CX,Count
	CMP	SI,DI
	JAE	@@1
	STD
	ADD	SI,CX
	ADD	DI,CX
	DEC	SI
	DEC	DI
@@1:	REP	MOVSB
	CLD
	POP	DS
end;

function StrCopy(Dest, Source: PChar): PChar; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Source
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	NOT	CX
	LDS	SI,Source
	LES	DI,Dest
	MOV	AX,DI
	MOV	DX,ES
	REP	MOVSB
	POP	DS
end;

function StrECopy(Dest, Source: PChar): PChar; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Source
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	NOT	CX
	LDS	SI,Source
	LES	DI,Dest
	REP	MOVSB
	MOV	AX,DI
	MOV	DX,ES
	DEC	AX
	POP	DS
end;

function StrLCopy(Dest, Source: PChar; MaxLen: Word): PChar; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Source
	MOV	CX,MaxLen
	MOV	BX,CX
	XOR	AL,AL
	REPNE	SCASB
	SUB	BX,CX
	MOV	CX,BX
	LDS	SI,Source
	LES	DI,Dest
	MOV	BX,DI
	MOV	DX,ES
	REP	MOVSB
	STOSB
	XCHG	AX,BX
	POP	DS
end;

function StrPCopy(Dest: PChar; Source: String): PChar; assembler;
asm
	PUSH	DS
	CLD
	LDS	SI,Source
	LES	DI,Dest
	MOV	BX,DI
	MOV	DX,ES
	LODSB
	XOR	AH,AH
	XCHG	AX,CX
	REP	MOVSB
	XOR	AL,AL
	STOSB
	XCHG	AX,BX
	POP	DS
end;

function StrCat(Dest, Source: PChar): PChar; assembler;
asm
	PUSH	Dest.Word[2]
	PUSH	Dest.Word[0]
	PUSH	CS
	CALL	NEAR PTR StrEnd
	PUSH	DX
	PUSH	AX
	PUSH	Source.Word[2]
	PUSH	Source.Word[0]
	PUSH	CS
	CALL	NEAR PTR StrCopy
	MOV	AX,Dest.Word[0]
	MOV	DX,Dest.Word[2]
end;

function StrLCat(Dest, Source: PChar; MaxLen: Word): PChar; assembler;
asm
	PUSH	Dest.Word[2]
	PUSH	Dest.Word[0]
	PUSH	CS
	CALL	NEAR PTR StrEnd
	MOV	CX,Dest.Word[0]
	ADD	CX,MaxLen
	SUB	CX,AX
	JBE	@@1
	PUSH	DX
	PUSH	AX
	PUSH	Source.Word[2]
	PUSH	Source.Word[0]
	PUSH	CX
	PUSH	CS
	CALL	NEAR PTR StrLCopy
@@1:	MOV	AX,Dest.Word[0]
	MOV	DX,Dest.Word[2]
end;

function StrComp(Str1, Str2: PChar): Integer; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Str2
	MOV	SI,DI
	MOV	CX,0FFFFH
	XOR	AX,AX
	CWD
	REPNE	SCASB
	NOT	CX
	MOV	DI,SI
	LDS	SI,Str1
	REPE	CMPSB
	MOV	AL,DS:[SI-1]
	MOV	DL,ES:[DI-1]
	SUB	AX,DX
	POP	DS
end;

function StrIComp(Str1, Str2: PChar): Integer; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Str2
	MOV	SI,DI
	MOV	CX,0FFFFH
	XOR	AX,AX
	CWD
	REPNE	SCASB
	NOT	CX
	MOV	DI,SI
	LDS	SI,Str1
@@1:	REPE	CMPSB
	JE	@@4
	MOV	AL,DS:[SI-1]
	CMP	AL,'a'
	JB	@@2
	CMP	AL,'z'
	JA	@@2
	SUB	AL,20H
@@2:	MOV	DL,ES:[DI-1]
	CMP	DL,'a'
	JB	@@3
	CMP	DL,'z'
	JA	@@3
	SUB	DL,20H
@@3:	SUB	AX,DX
	JE	@@1
@@4:	POP	DS
end;

function StrLComp(Str1, Str2: PChar; MaxLen: Word): Integer; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Str2
	MOV	SI,DI
	MOV	AX,MaxLen
	MOV	CX,AX
	JCXZ	@@1
	XCHG	AX,BX
	XOR	AX,AX
	CWD
	REPNE	SCASB
	SUB	BX,CX
	MOV	CX,BX
	MOV	DI,SI
	LDS	SI,Str1
	REPE	CMPSB
	MOV	AL,DS:[SI-1]
	MOV	DL,ES:[DI-1]
	SUB	AX,DX
@@1:	POP	DS
end;

function StrLIComp(Str1, Str2: PChar; MaxLen: Word): Integer; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Str2
	MOV	SI,DI
	MOV	AX,MaxLen
	MOV	CX,AX
	JCXZ	@@4
	XCHG	AX,BX
	XOR	AX,AX
	CWD
	REPNE	SCASB
	SUB	BX,CX
	MOV	CX,BX
	MOV	DI,SI
	LDS	SI,Str1
@@1:	REPE	CMPSB
	JE	@@4
	MOV	AL,DS:[SI-1]
	CMP	AL,'a'
	JB	@@2
	CMP	AL,'z'
	JA	@@2
	SUB	AL,20H
@@2:	MOV	DL,ES:[DI-1]
	CMP	DL,'a'
	JB	@@3
	CMP	DL,'z'
	JA	@@3
	SUB	DL,20H
@@3:	SUB	AX,DX
	JE	@@1
@@4:	POP	DS
end;

function StrScan(Str: PChar; Chr: Char): PChar; assembler;
asm
	CLD
	LES	DI,Str
	MOV	SI,DI
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	NOT	CX
	MOV	DI,SI
	MOV	AL,Chr
	REPNE	SCASB
	MOV	AX,0
	CWD
	JNE	@@1
	MOV	AX,DI
	MOV	DX,ES
	DEC	AX
@@1:
end;

function StrRScan(Str: PChar; Chr: Char): PChar; assembler;
asm
	CLD
	LES	DI,Str
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	NOT	CX
	STD
	DEC	DI
	MOV	AL,Chr
	REPNE	SCASB
	MOV	AX,0
	CWD
	JNE	@@1
	MOV	AX,DI
	MOV	DX,ES
	INC	AX
@@1:	CLD
end;

function StrPos(Str1, Str2: PChar): PChar; assembler;
asm
	PUSH	DS
	CLD
	XOR	AL,AL
	LES	DI,Str2
	MOV	CX,0FFFFH
	REPNE	SCASB
	NOT	CX
	DEC	CX
	JE	@@2
	MOV	DX,CX
	MOV	BX,ES
	MOV	DS,BX
	LES	DI,Str1
	MOV	BX,DI
	MOV	CX,0FFFFH
	REPNE	SCASB
	NOT	CX
	SUB	CX,DX
	JBE	@@2
	MOV	DI,BX
@@1:	MOV	SI,Str2.Word[0]
	LODSB
	REPNE	SCASB
	JNE	@@2
	MOV	AX,CX
	MOV	BX,DI
	MOV	CX,DX
	DEC	CX
	REPE	CMPSB
	MOV	CX,AX
	MOV	DI,BX
	JNE	@@1
	MOV	AX,DI
	MOV	DX,ES
	DEC	AX
	JMP	@@3
@@2:	XOR	AX,AX
	MOV	DX,AX
@@3:	POP	DS
end;

function StrUpper(Str: PChar): PChar; assembler;
asm
	PUSH	DS
	CLD
	LDS	SI,Str
	MOV	BX,SI
	MOV	DX,DS
@@1:	LODSB
	OR	AL,AL
	JE	@@2
	CMP	AL,'a'
	JB	@@1
	CMP	AL,'z'
	JA	@@1
	SUB	AL,20H
	MOV	[SI-1],AL
	JMP	@@1
@@2:	XCHG	AX,BX
	POP	DS
end;

function StrLower(Str: PChar): PChar; assembler;
asm
	PUSH	DS
	CLD
	LDS	SI,Str
	MOV	BX,SI
	MOV	DX,DS
@@1:	LODSB
	OR	AL,AL
	JE	@@2
	CMP	AL,'A'
	JB	@@1
	CMP	AL,'Z'
	JA	@@1
	ADD	AL,20H
	MOV	[SI-1],AL
	JMP	@@1
@@2:	XCHG	AX,BX
	POP	DS
end;

function StrPas(Str: PChar): String; assembler;
asm
	PUSH	DS
	CLD
	LES	DI,Str
	MOV	CX,0FFFFH
	XOR	AL,AL
	REPNE	SCASB
	NOT	CX
	DEC	CX
	LDS	SI,Str
	LES	DI,@Result
	MOV	AL,CL
	STOSB
	REP	MOVSB
	POP	DS
end;

{$W+}

function StrNew(Str: PChar): PChar;
var
  L: Word;
  P: PChar;
begin
  StrNew := nil;
  if (Str <> nil) and (Str^ <> #0) then
  begin
    L := StrLen(Str) + 1;
    GetMem(P, L);
    if P <> nil then StrNew := StrMove(P, Str, L);
  end;
end;

procedure StrDispose(Str: PChar);
begin
  if Str <> nil then FreeMem(Str, StrLen(Str) + 1);
end;

end.
