{$MODE OBJFPC}
{$MODESWITCH RESULT}
{$MODESWITCH AUTODEREF}
unit dstrings;

interface

uses
  dansiview,
  strings,
  dexception,
  dtypes;

type
TString = AnsiString;
TChar = AnsiChar;

TUnicode = UnicodeString;
TUnicodeChar = UnicodeChar;

// TODO Use advanced record
// TODO use dansiview.TAnsiView
TAnsiBuf = dansiview.TAnsiView;
PAnsiBuf = ^TAnsiBuf;
//TAnsiBuf = object
//  P: Pointer;
//  S: Integer;
//
//  // TODO It's not actually constructors/destructors, rename it
//  procedure Init(_P: Pointer; _S: Integer); inline;
//  procedure Init(_P: PAnsiChar);
//  procedure Init(_P, _Q: PAnsiChar); inline;
//  procedure Init(const A: AnsiString); inline;
//  procedure Done; inline;
//
//  procedure Allocate(_S: Integer); inline;
//  procedure Allocate(_P: Pointer; _S: Integer);
//  procedure Allocate(const Other: TAnsiBuf); inline;
//  procedure Dealloc; inline;
//
//  function ToString: TString; inline;
//
//  function First: Char; inline;
//  function Last: Char; inline;
//
//  function Split(C: Char; var Left, Right: TAnsiBuf): Boolean;
//
//  function Sub(Start, Count: LongInt): TAnsiBuf; inline;
//  function FromTo(Start, Finish: LongInt): TAnsiBuf; inline;
//  function FirstChars(Count: LongInt): TAnsiBuf; inline;
//
//  function Skipped(Count: Integer): TAnsiBuf;
//  function CutedOff(Count: Integer): TAnsiBuf;
//  function SkipToCloseBrace(O: Char = '('; C: Char = ')'): TAnsiBuf;
//  function ParseBraces(out Inside: TAnsiBuf; O: Char = '('; C: Char = ')'): TAnsiBuf;
//
//  // must be Count <= Size
//  procedure Skip(Count: Integer);
//  procedure CutOff(Count: Integer);
//
//  procedure SkipSpaces;
//  procedure CutOffSpaces;
//
//  procedure Trim;
//
//  function GetChar(Index: LongInt): AnsiChar; inline;
//
//  property Chars[Index: LongInt]: AnsiChar read GetChar; default;
//
//public const
//  Empty: TAnsiBuf = (P: nil; S: 0);
//end;

PAnsiView = PAnsiBuf;
TAnsiView = dansiview.TAnsiView;

// example:
//    I.Init(Buf, ',');
//    while I.Next do
//      DoSomething(I.Item);
//    I.Done;
//TAnsiListIterator = object
//  Item: TAnsiBuf;
//  Rest: TAnsiBuf;
//  C: Char;
//  procedure Init(const Buf: TAnsiBuf; TheC: Char);
//  procedure Done;
//  function Next: Boolean; inline;
//end;

function AnsiBuf(P: PAnsiChar; S: Int64 = 0): TAnsiBuf; overload;
function AnsiBuf(const S: AnsiString): TAnsiBuf; inline; overload;
function AnsiView(const S: array of AnsiChar): TAnsiView; inline;
operator := (const S: TString): TAnsiBuf; inline;
operator := (P: PAnsiChar): TAnsiBuf; inline;
operator := (const S: array of AnsiChar): TAnsiBuf; inline;
operator = (const A, B: TAnsiBuf): Boolean;

// D := A[B->C], Result := D <> A
function Substitute(const A, B, C: TString; out D: TString): Boolean;
function SubstituteAll(A: TString; const B, C: TString): TString;

function StartsWith(const S, Prefix: TAnsiBuf): Boolean; overload;
function StartsWith(const S, Prefix: AnsiString): Boolean; overload;

implementation

//procedure TAnsiBuf.Init(_P: Pointer; _S: Integer);
//begin
//  P := _P;
//  S := _S;
//end;

//procedure TAnsiBuf.Init(_P: PAnsiChar);
//begin
//  P := _P;
//  S := StrLen(P);
//end;

//procedure TAnsiBuf.Init(_P, _Q: PAnsiChar);
//begin
//  Init(_P, PtrInt(_Q) - PtrInt(_P));
//end;

//procedure TAnsiBuf.Init(const A: AnsiString);
//begin
//  Init(@A[1], Length(A));
//end;

//procedure TAnsiBuf.Done;
//begin
//end;

//procedure TAnsiBuf.Allocate(_S: Integer); inline;
//begin
//  GetMem(P, _S);
//  S := _S;
//end;

//procedure TAnsiBuf.Allocate(_P: Pointer; _S: Integer);
//begin
//  Allocate(_S);
//  Move(_P^, P^, _S);
//end;

//procedure TAnsiBuf.Allocate(const Other: TAnsiBuf);
//begin
//  Allocate(Other.P, Other.S);
//end;

//procedure TAnsiBuf.Dealloc;
//begin
//  FreeMem(P);
//end;

//function TAnsiBuf.ToString: TString;
//begin
//  SetLength(Result, S);
//  if (P <> nil) and (S <> 0) then
//    Move(P^, Result[1], S);
//end;

//function TAnsiBuf.First: Char;
//begin
//  Result := Char(PArrayOfByte(P)^[0]);
//end;

//function TAnsiBuf.Last: Char;
//begin
//  Result := Char(PArrayOfByte(P)^[S - 1]);
//end;

//function TAnsiBuf.Split(C: Char; var Left, Right: TAnsiBuf): Boolean;
//var
//  I: Integer;
//begin
//  I := IndexChar(P^, S, C);
//  Result := I <> -1;
//  if not Result then
//    Exit;
//  Left.Init(P, I);
//  Right.Init(@PArrayOfByte(P)^[I + 1], S - I - 1);
//end;

//function TAnsiBuf.Sub(Start, Count: LongInt): TAnsiBuf;
//begin
//  Result := AnsiBuf(@PArrayOfByte(P)^[Start], Count);
//end;

//function TAnsiBuf.FromTo(Start, Finish: LongInt): TAnsiBuf;
//begin
//  Result := AnsiBuf(@PArrayOfByte(P)^[Start], Finish - Start);
//end;

//function TAnsiBuf.FirstChars(Count: LongInt): TAnsiBuf;
//begin
//  Result := AnsiBuf(P, Count);
//end;

//function TAnsiBuf.Skipped(Count: Integer): TAnsiBuf;
//begin
//  Result := AnsiBuf(@PArrayOfByte(P)^[Count], S - Count);
//end;

//function TAnsiBuf.CutedOff(Count: Integer): TAnsiBuf;
//begin
//  Result := AnsiBuf(P, S - Count);
//end;

//function TAnsiBuf.SkipToCloseBrace(O: Char = '('; C: Char = ')'): TAnsiBuf;
//var
//  I, Score: Integer;
//begin
//  I := 0;
//  Score := 1;
//  while Score > 0 do begin
//    if I = S then begin
//      RaiseException('SkipToCloseBrace');
//      Exit(TAnsiBuf(nil));
//    end;
//    if PArrayOfByte(P)^[I] = Ord(O) then
//      Inc(Score);
//    if PArrayOfByte(P)^[I] = Ord(C) then
//      Dec(Score);
//    Inc(I);
//  end;
//  Result := AnsiBuf(@PArrayOfByte(P)^[I], S - I)
//end;

//function TAnsiBuf.ParseBraces(out Inside: TAnsiBuf; O: Char = '('; C: Char = ')'): TAnsiBuf;
//var
//  I, Score: Integer;
//begin
//  I := 0;
//  Score := 1;
//  while Score > 0 do begin
//    if I = S then begin
//      RaiseException('ParseBraces');
//      Exit(TAnsiBuf(nil));
//    end;
//    if PArrayOfByte(P)^[I] = Ord(O) then
//      Inc(Score);
//    if PArrayOfByte(P)^[I] = Ord(C) then
//      Dec(Score);
//    Inc(I);
//  end;
//  Inside := AnsiBuf(P, I - 1);
//  Result := AnsiBuf(@PArrayOfByte(P)^[I], S - I)
//end;

//procedure TAnsiBuf.Skip(Count: Integer);
//begin
//  Inc(PByte(P), Count);
//  Dec(S, Count);
//end;

//procedure TAnsiBuf.CutOff(Count: Integer);
//begin
//  Dec(S, Count);
//end;

//procedure TAnsiBuf.SkipSpaces;
//var
//  I: Integer;
//begin
//  I := 0;
//  while PArrayOfByte(P)^[I] <= 32 do
//    Inc(I);
//  Skip(I);
//end;

//procedure TAnsiBuf.CutOffSpaces;
//var
//  I: Integer;
//begin
//  I := 1;
//  while PArrayOfByte(P)^[S - I] <= 32 do
//    Inc(I);
//  CutOff(I - 1);
//end;

//procedure TAnsiBuf.Trim;
//begin
//  SkipSpaces;
//  CutOffSpaces;
//end;

//function TAnsiBuf.GetChar(Index: LongInt): AnsiChar;
//begin
//  Result := AnsiChar(PArrayOfByte(P)^[Index]);
//end;

//procedure TAnsiListIterator.Init(const Buf: TAnsiBuf; TheC: Char);
//begin
//  Rest := Buf;
//  C := TheC;
//end;

//procedure TAnsiListIterator.Done;
//begin
//end;

//function TAnsiListIterator.Next: Boolean;
//begin
//  if Rest.Length = 0 then
//    Exit(False);
//  Result := Rest.Split(C, Item, Rest);
//  if not Result then begin
//    Item := Rest;
//    Rest.Length := 0;
//    Result := True;
//  end;
//end;

function AnsiBuf(P: PAnsiChar; S: Int64 = 0): TAnsiBuf;
begin
  Result := dansiview.AnsiView(P, S);
end;

function AnsiBuf(const S: AnsiString): TAnsiBuf;
begin
  Result := AnsiBuf(@S[1], Length(S));
end;

function AnsiView(const S: array of AnsiChar): TAnsiView;
begin
  Result := dansiview.AnsiView(@S[0], Length(S));
end;

operator := (const S: TString): TAnsiBuf;
begin
  Result := AnsiBuf(@S[1], Length(S));
end;

operator := (P: PAnsiChar): TAnsiBuf;
begin
  Result.Init(P, StrLen(P));
end;

operator := (const S: array of AnsiChar): TAnsiBuf;
begin
  Result := dansiview.AnsiView(@S[0], Length(S));
end;

operator = (const A, B: TAnsiBuf): Boolean;
var
  I: Integer;
begin
  if A.Length <> B.Length then
    Exit(False);
  Exit(CompareByte(A.Data^, B.Data^, A.Length) = 0);
end;

function Substitute(const A, B, C: TString; out D: TString): Boolean;
var
  L: LongInt;
begin
  L := Pos(B, A);
  Result := L <> 0;
  if Result then begin
    D := Copy(A, 1, L - 1) + C + Copy(A, L + Length(B), Length(A) - L + 1 - Length(B));
  end else
    D := A;
end;

function SubstituteAll(A: TString; const B, C: TString): TString;
var
  X: TString;
begin
  X := '';
  while Substitute(A, B, C, X) do
    A := X;
  Exit(X);
end;

function StartsWith(const S, Prefix: TAnsiBuf): Boolean;
var
  I: LongInt;
begin
  if Prefix.Length > S.Length then
    Exit(False);
  for I := 0 to Prefix.Length - 1 do
    if Prefix[I] <> S[I] then
      Exit(False);
  Exit(True);
end;

function StartsWith(const S, Prefix: AnsiString): Boolean;
begin
  if Length(Prefix) > Length(S) then
    Exit(False);
  Result := Copy(S, 1, Length(Prefix)) = Prefix;
end;

end.
