{$I-,F+,O+}
unit PanelRec;

interface

uses Dos, Objects;

type
  PPanelRec = ^TPanelRec;
  TPanelRec = record
    Attr: Byte;
    Time: Longint;
    Size: Longint;
    Name: String[8];
    Ext: String[3];
    Selected: Boolean;
    Scanned: Boolean;
    ThePath: PString;
    Color: Byte;
    Index: Byte;
    Percent: Byte;
  end;

  PTempGroupRec = ^TTempGroupRec;
  TTempGroupRec = record
    MaskName: String[8];
    MaskExt: String[3];
    Color: Byte;
    Index: Byte;
    Dir: Boolean;
  end;

  PPanelCollection = ^TPanelCollection;
  TPanelCollection = object(TSortedCollection)
    Owner: Pointer;
    Full: Boolean;
    constructor Init(ALimit, ADelta: Integer; AOwner: Pointer);
    function Compare(Key1, Key2: Pointer): Integer; virtual;
    procedure FreeItem(Item: Pointer); virtual;
    procedure Insert(Item: Pointer); virtual;
    procedure Sort;
  end;

  PTempGroupList = ^TTempGroupList;
  TTempGroupList = object(TCollection)
    procedure FreeItem(Item: Pointer); virtual;
  end;

  PFilterRec = ^TFilterRec;
  TFilterRec = record
    Text: PString;
    Unix: Boolean;
    LoTime: Longint;
    HiTime: Longint;
    LoSize: Longint;
    HiSize: Longint;
    Attr: Byte;
    PipePos: Byte;
    UseForLists: Boolean;
    ReservedWord: Word;
  end;

const
  smName = 0;
  smExt = 1;
  smTime = 2;
  smSize = 3;
  smDescr = 4;
  smFilesBBS = 5;
  smDisk = 6;
  smNumber = 7;

  sdAscending = 0;
  sdDescending = 1;

  scFiles = 1;
  scDirs = 2;
  scDesc = 4;

  spDirsFirst = 0;
  spFilesFirst = 1;
  spMixed = 2;

  fgGroupHighlight = 1;
  fgSelectionTurnsOff = 2;
  fgSortByIndex = 4;

  TempGroups: PTempGroupList = nil;

  CopyRenameFilter: TFilterRec = (Text: nil);
  CopyRenameStates: Pointer = nil;

function NewPanelRec(SR: SearchRec; Caller: Pointer): PPanelRec;
procedure InitTempGroups;
procedure DoneTempGroups;
procedure GetGroupInfo(const Name, Ext: String; Dir: Boolean;
  var Color, Index: Byte);
procedure AddNameExt(const Path: FNameStr; P: PPanelRec; var S: FNameStr);
function PanelRecPath(P: PPanelRec): FNameStr;
function NameMatchesMultiMask(const Name, Mask: String;
  PipePos: Byte): Boolean;
function AdvancedFilterPassed(P: PFilterRec; States: Pointer;
  var SR: SearchRec; const ALongName: FNameStr): Boolean;

implementation

uses Memory, Views, App, FileMngr, FMAbort, FMGroups, DirPrim, UnixMask,
  HeapUMB, LFN, TPString, Defaults;

const
  SafetyPool = 8192;

function NewPanelRec(SR: SearchRec; Caller: Pointer): PPanelRec;
var
  P: PPanelRec;
  B: Byte;
begin
{  GetMem(P, SizeOf(TPanelRec));}
  GetMemUMB(P, SizeOf(TPanelRec));
  P^.Attr := SR.Attr;
  P^.Time := SR.Time;
  P^.Size := SR.Size;
  P^.Selected := False;
  B := Pos('.', SR.Name);
  if SR.Attr and Directory = 0 then
  begin
    if B <> 0 then
    begin
      P^.Name := System.Copy(SR.Name, 1, B - 1);
      P^.Ext  := System.Copy(SR.Name, B + 1, 3);
    end
    else
    begin
      P^.Name := SR.Name;
      P^.Ext  := '';
    end;
  end
  else
  begin
    if (B <> 0) and (SR.Name[1] <> '.') then
    begin
      P^.Name := System.Copy(SR.Name, 1, B - 1);
      P^.Ext  := System.Copy(SR.Name, B + 1, 3);
    end
    else
    begin
      P^.Name := SR.Name;
      P^.Ext  := '';
    end;
  end;
  P^.ThePath := nil;
  P^.Color := Byte(Application^.GetPalette^[141]);
  P^.Index := 0;
  if PPanel(Caller)^.GroupOptions and
    (fgGroupHighlight + fgSortByIndex) <> 0 then
      GetGroupInfo(P^.Name, P^.Ext, SR.Attr and Directory <> 0,
        P^.Color, P^.Index);
  NewPanelRec := P;
end;

procedure GetKeyName(Key: Pointer; Long: Boolean; CaseSens: Byte;
  var Name, Ext: FNameStr);
var
  ForceCase: Boolean;
  SaveAPI: LAPIType;
  Dir: FNameStr;
begin
  if Long then
  begin
    SaveAPI := lAPI;
    lAPI := lWIN95;
    lFSplit(Copy(PPanelRec(Key)^.ThePath^, 2, 255), Dir, Name, Ext);
    if (Ext <> '') and (Ext[1] = '.') then Delete(Ext, 1, 1);
    lAPI := SaveAPI;
  end
  else
  begin
    Name := PPanelRec(Key)^.Name;
    Ext := PPanelRec(Key)^.Ext;
  end;
  ForceCase := not Long or (LFNOptions and loConvertNames <> 0);
  if PPanelRec(Key)^.Attr and Directory = 0 then
    if ForceCase or (CaseSens and scFiles = 0) then
    begin
      LocaseSt(Name);
      LocaseSt(Ext);
    end else
  else
    if ForceCase or (CaseSens and scDirs = 0) then
    begin
      UpcaseSt(Name);
      UpcaseSt(Ext);
    end;
end;

procedure CalcDigits(const S: String; var E: Extended);
var
  I: Integer;
begin
  for I := 1 to Length(S) do
    if S[I] in ['0'..'9'] then
    begin
      if E < 0 then E := 0;
      E := E * 10 + Byte(S[I]) - Byte('0');
    end;
end;

function GetNameNumber(const Name1, Ext1, Name2, Ext2: FNameStr): Integer;
var
  I: Integer;
  Number1, Number2: Extended;
begin
  Number1 := -1;
  CalcDigits(Name1, Number1);
  CalcDigits(Ext1, Number1);
  if Number1 < 0 then Number1 := 1.0E256;

  Number2 := -1;
  CalcDigits(Name2, Number2);
  CalcDigits(Ext2, Number2);
  if Number2 < 0 then Number2 := 1.0E256;

  if Number1 = Number2 then GetNameNumber := 0
  else if Number1 > Number2 then GetNameNumber := 1
  else GetNameNumber := -1;
end;

constructor TPanelCollection.Init(ALimit, ADelta: Integer; AOwner: Pointer);
begin
  Inherited Init(ALimit, ADelta);
  Owner := AOwner;
end;

function TPanelCollection.Compare(Key1, Key2: Pointer): Integer;
var
  Index1, Index2: Byte;
  Name, Ext, Time, Sizes, Number, Path, C: Integer;
  Mode: Word;
  Name1, Name2, Ext1, Ext2, Path1, Path2: FNameStr;
begin
  with PPanel(Owner)^ do
  begin
    if (Status <= stFull) and
       ((Settings and seLongNames <> 0) or (ColWidth <> 13)) then
    begin
      GetKeyName(Key1, (PPanelRec(Key1)^.ThePath <> nil) and
        (PPanelRec(Key1)^.ThePath^[1] = #0), SortCaseSens, Name1, Ext1);
      GetKeyName(Key2, (PPanelRec(Key2)^.ThePath <> nil) and
        (PPanelRec(Key2)^.ThePath^[1] = #0), SortCaseSens, Name2, Ext2);
      Name := Integer(CompString(Name1, Name2)) - 1;
      Ext := Integer(CompString(Ext1, Ext2)) - 1;
    end
    else if (PPanelRec(Key1)^.Attr and Directory = 0) and
      (PPanelRec(Key2)^.Attr and Directory = 0) then
    begin
      if SortCaseSens and scFiles = 0 then
      begin
        Name := Integer(CompLCString(
          PPanelRec(Key1)^.Name, PPanelRec(Key2)^.Name)) - 1;
        Ext := Integer(CompLCString(
          PPanelRec(Key1)^.Ext, PPanelRec(Key2)^.Ext)) - 1;
      end
      else
      begin
        Name := Integer(CompString(
          PPanelRec(Key1)^.Name, PPanelRec(Key2)^.Name)) - 1;
        Ext := Integer(CompString(
          PPanelRec(Key1)^.Ext, PPanelRec(Key2)^.Ext)) - 1;
      end;
    end
    else
    begin
      if SortCaseSens and scDirs = 0 then
      begin
        Name := Integer(CompUCString(
          PPanelRec(Key1)^.Name, PPanelRec(Key2)^.Name)) - 1;
        Ext := Integer(CompUCString(
          PPanelRec(Key1)^.Ext, PPanelRec(Key2)^.Ext)) - 1;
      end
      else
      begin
        Name := Integer(CompString(
          PPanelRec(Key1)^.Name, PPanelRec(Key2)^.Name)) - 1;
        Ext := Integer(CompString(
          PPanelRec(Key1)^.Ext, PPanelRec(Key2)^.Ext)) - 1;
      end;
    end;
    if PPanelRec(Key1)^.ThePath = nil then Path1 := ''
    else Path1 := PPanelRec(Key1)^.ThePath^;
    if PPanelRec(Key2)^.ThePath = nil then Path2 := ''
    else Path2 := PPanelRec(Key2)^.ThePath^;
    Path := Integer(CompUCString(Path1, Path2)) - 1;
    if (Name = 0) and (Ext = 0) and (Path = 0) then Compare := 0
    else if PPanelRec(Key1)^.Name[1] in [':', '.'] then Compare := -1
    else if PPanelRec(Key2)^.Name[1] in [':', '.'] then Compare := 1
    else if PPanelRec(Key1)^.Attr and VolumeID <> 0 then
      if PPanelRec(Key1)^.Name[1] = 'N' then Compare := 1
      else Compare := -1
    else if PPanelRec(Key2)^.Attr and VolumeID <> 0 then
      if PPanelRec(Key2)^.Name[1] = 'N' then Compare := -1
      else Compare := 1
    else if (PPanelRec(Key1)^.Attr and Directory <> 0) and
      (PPanelRec(Key2)^.Attr and Directory = 0) and
      (SortPriority <> spMixed) then
        if SortPriority = spFilesFirst then Compare := 1
        else Compare := -1
    else if (PPanelRec(Key2)^.Attr and Directory <> 0) and
      (PPanelRec(Key1)^.Attr and Directory = 0) and
      (SortPriority <> spMixed) then
        if SortPriority = spFilesFirst then Compare := -1
        else Compare := 1
    else
    begin
      if PPanelRec(Key1)^.Time = PPanelRec(Key2)^.Time then Time := 0
      else if PPanelRec(Key1)^.Time < PPanelRec(Key2)^.Time then Time := 1
      else Time := -1;
      if (PPanelRec(Key1)^.Size = PPanelRec(Key2)^.Size) then Sizes := 0
      else if PPanelRec(Key1)^.Size < PPanelRec(Key2)^.Size then Sizes := 1
      else Sizes := -1;
      if Options and ofValidate <> 0 then Mode := smName
      else Mode := SortMode;
      if Mode in [smDescr, smFilesBBS] then Mode := smName;
      if Mode = smName then
      begin
        if Name <> 0 then C := Name
        else if Ext <> 0 then C := Ext
        else if Time <> 0 then C := Time
        else if Sizes <> 0 then C := Sizes
        else if Path <> 0 then C := Path
        else C := -1;
      end
      else if Mode = smExt then
      begin
        if Ext <> 0 then C := Ext
        else if Name <> 0 then C := Name
        else if Time <> 0 then C := Time
        else if Sizes <> 0 then C := Sizes
        else if Path <> 0 then C := Path
        else C := -1;
      end
      else if Mode = smTime then
      begin
        if Time <> 0 then C := Time
        else if Name <> 0 then C := Name
        else if Ext <> 0 then C := Ext
        else if Sizes <> 0 then C := Sizes
        else if Path <> 0 then C := Path
        else C := 1;
      end
      else if Mode = smSize then
      begin
        if Sizes <> 0 then C := Sizes
        else if Name <> 0 then C := Name
        else if Ext <> 0 then C := Ext
        else if Time <> 0 then C := Time
        else if Path <> 0 then C := Path
        else C := 1;
      end
      else if Mode = smNumber then
      begin
	if (Status <= stFull) and
	   ((Settings and seLongNames <> 0) or (ColWidth <> 13)) then
	  Number := GetNameNumber(Name1, Ext1, Name2, Ext2)
        else Number := GetNameNumber(
          PPanelRec(Key1)^.Name, PPanelRec(Key1)^.Ext,
          PPanelRec(Key2)^.Name, PPanelRec(Key2)^.Ext);
        if Number <> 0 then C := Number
        else if Name <> 0 then C := Name
        else if Ext <> 0 then C := Ext
        else if Time <> 0 then C := Time
        else if Sizes <> 0 then C := Sizes
        else if Path <> 0 then C := Path
        else C := -1;
      end
      else if Path <> 0 then C := Path
      else C := -1;
      if GroupOptions and fgSortByIndex <> 0 then
      begin
        Index1 := PPanelRec(Key1)^.Index;
        Index2 := PPanelRec(Key2)^.Index;
        if Index1 = 0 then Index1 := 255;
        if Index2 = 0 then Index2 := 255;
        if Index1 > Index2 then C := 1
        else if Index1 < Index2 then C := -1;
      end;
      if SortSel then
      begin
        if PPanelRec(Key1)^.Selected and
          not PPanelRec(Key2)^.Selected then
            if Byte(SortSel) <> 1 then C := 1
            else C := -1
        else if not PPanelRec(Key1)^.Selected and
          PPanelRec(Key2)^.Selected then
            if Byte(SortSel) <> 1 then C := -1
            else C := 1
        else if (C <> 0) and (SortDirection = sdDescending) then C := -C;
      end
      else if (C <> 0) and (SortDirection = sdDescending) then C := -C;
      Compare := C;
    end;
  end;
end;

procedure TPanelCollection.FreeItem(Item: Pointer);
begin
{
  DisposeStr(PPanelRec(Item)^.ThePath);
  FreeMem(Item, SizeOf(TPanelRec));
}
  DisposeStrUMB(PPanelRec(Item)^.ThePath);
  FreeMemUMB(Item, SizeOf(TPanelRec));
end;

procedure TPanelCollection.Insert(Item: Pointer);
var
  CanInsert: Boolean;
  I: Integer;
  P: PPanelRec;
begin
  if not Search(Item, I) then
  begin
    if Count < Limit then CanInsert := MaxAvail > SafetyPool
    else CanInsert := MaxAvail > LongMul(Limit + Delta, 4) + SafetyPool;
    if not CanInsert then Full := True;
    if not CanInsert or
      ((PPanelRec(Item)^.Color = 0) and (Owner <> nil) and
       (PPanel(Owner)^.GroupOptions and fgGroupHighlight <> 0)) then
         FreeItem(Item)
    else AtInsert(I, Item);
  end
  else
  begin
    P := At(I);
    Move(Item^, P^, SizeOf(Byte) + SizeOf(Longint) + SizeOf(Longint));
    FreeItem(Item);
  end;
end;

procedure TPanelCollection.Sort;
var
  Abort: Boolean;
  C: CompareType;
  J, M: Integer;
  Panel: PPanel;
  P1, P2: PPanelRec;
  F1, F2: PFilesBBSRec;
  S1, S2: String;

function LessItem(N1, N2: Integer): Boolean;
begin
  if N1 = N2 then
  begin
    LessItem := False;
    Exit;
  end;
  P1 := At(N1);
  P2 := At(N2);
  if (Panel^.SortMode in [smDescr, smFilesBBS]) and
     (Panel^.FilesBBS^.Count = Count) and
     (P1^.Attr and Directory = 0) and
     (P2^.Attr and Directory = 0) and
     (not Panel^.SortSel or
       ((Byte(P1^.Selected) <> 0) = (Byte(P2^.Selected) <> 0))) then
  begin
    F1 := Panel^.FilesBBS^.At(N1);
    F2 := Panel^.FilesBBS^.At(N2);
    if Panel^.SortMode = smFilesBBS then Str(F1^.Num:5, S1)
    else if F1^.Text = nil then S1 := ''
    else S1 := Copy(F1^.Text^, Panel^.SortDescrPos, 255);
    if Panel^.SortMode = smFilesBBS then Str(F2^.Num:5, S2)
    else if F2^.Text = nil then S2 := ''
    else S2 := Copy(F2^.Text^, Panel^.SortDescrPos, 255);
    if Panel^.SortCaseSens and scDesc <> 0 then
      C := CompString(S1, S2)
    else C := CompUCString(S1, S2);
    if C = Equal then {}
    else
    begin
      LessItem := C = Less;
      Exit;
    end;
  end;
  LessItem := Compare(P1, P2) = -1;
end;

procedure QuickSort(L, R: Integer);
var
  I: Integer;
begin
  if StackOverflow then
  begin
    Abort := True;
    Exit;
  end;
  repeat
    I := L;
    J := R;
    M := (L + R) shr 1;
    repeat
      while LessItem(I, M) do Inc(I);
      while LessItem(M, J) do Dec(J);
      if I < J then
      begin
        P1 := Items^[I];
        Items^[I] := Items^[J];
        Items^[J] := P1;

        if Panel^.FilesBBS^.Count = Count then
        begin
          F1 := Panel^.FilesBBS^.Items^[I];
          Panel^.FilesBBS^.Items^[I] := Panel^.FilesBBS^.Items^[J];
          Panel^.FilesBBS^.Items^[J] := F1;
        end;
      end;

      if I <= J then
      begin
        if M = I then M := J
        else if M = J then M := I;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then QuickSort(L, J);
    L := I;
  until Abort or (I >= R);
end;

begin
  if Count <> 0 then
  begin
    Panel := Owner;
    Abort := False;
    QuickSort(0, Count - 1);
  end;
end;

procedure TTempGroupList.FreeItem(Item: Pointer);
begin
  if Item <> nil then FreeMem(Item, SizeOf(TTempGroupRec));
end;

procedure InitTempGroups;
var
  B: Byte;
  I: Integer;
  P: PGroupRec;
  R: PTempGroupRec;
  Mask: String[12];
begin
  if TempGroups <> nil then Exit;
  TempGroups := New(PTempGroupList, Init(8, 8));
  for I := 0 to Groups^.Count - 2 do
  begin
    GetMem(R, SizeOf(TTempGroupRec));
    FillChar(R^, SizeOf(TTempGroupRec), ' ');
    P := Groups^.At(I);
    R^.Dir := Byte(P^.Mask[0]) and $80 <> 0;
    if R^.Dir then Byte(P^.Mask[0]) := Byte(P^.Mask[0]) and not $80;
    Mask := StUpcase(P^.Mask);
    if R^.Dir then Byte(P^.Mask[0]) := Byte(P^.Mask[0]) or $80;
    B := Pos('.', Mask);
    if (B <> 0) and (Mask[1] <> '.') then
    begin
      R^.MaskName := Copy(Mask, 1, B - 1);
      R^.MaskExt :=  Copy(Mask, B + 1, 3);
    end
    else
    begin
      R^.MaskName := Mask;
      R^.MaskExt[0] := #3;
    end;
    ExpandName(R^.MaskName, 8);
    ExpandName(R^.MaskExt, 3);
    R^.Color := P^.Color;
    R^.Index := P^.Index;
    TempGroups^.Insert(R);
  end;
end;

procedure DoneTempGroups;
begin
  if TempGroups = nil then Exit;
  Dispose(TempGroups, Done);
  TempGroups := nil;
end;

procedure GetGroupInfo(const Name, Ext: String; Dir: Boolean;
  var Color, Index: Byte);
var
  I, II: Integer;
  P: PTempGroupRec;
  AExt: String[3];
  AName: String[8];
label
  NextRec;
begin
asm
  cld
  mov di,sp
  push ss
  pop es
  mov al,' '
  mov cx,bp
  sub cx,di
  rep stosb
end;
  AName := StUpcase(Name);
  AName[0] := #8;
  AExt := StUpcase(Ext);
  AExt[0] := #3;
  for I := 0 to TempGroups^.Count - 1 do
  begin
    P := TempGroups^.At(I);
    if P^.Dir <> Dir then Goto NextRec;
    for II := 1 to 3 do
      if (P^.MaskExt[II] <> '?') and
         not ((P^.MaskExt[II] = '+') and (AExt[II] in ['0'..'9'])) and
         (P^.MaskExt[II] <> AExt[II]) then Goto NextRec;
    for II := 1 to 8 do
      if (P^.MaskName[II] <> '?') and
         not ((P^.MaskName[II] = '+') and (AName[II] in ['0'..'9'])) and
         (P^.MaskName[II] <> AName[II]) then Goto NextRec;
    Color := P^.Color;
    Index := P^.Index;
    Exit;
NextRec:
  end;
end;

procedure AddNameExt(const Path: FNameStr; P: PPanelRec; var S: FNameStr);
begin
  if (P^.ThePath <> nil) and (P^.ThePath^[1] = #0) then
  begin
    if Pos(':', P^.ThePath^) <> 0 then
      S := Concat(Path, Copy(P^.ThePath^, 2, 255))
    else S := Concat(Path, JustFileName(Copy(P^.ThePath^, 2, 255)))
  end
  else
  begin
    S := Concat(Path, P^.Name);
    if P^.Ext <> '' then S := Concat(S, '.', P^.Ext);
  end;
end;

function PanelRecPath(P: PPanelRec): FNameStr;
begin
  if P^.ThePath = nil then PanelRecPath := ''
  else if P^.ThePath^[1] = #0 then
    PanelRecPath := ClearedSlash(JustPathName(Copy(P^.ThePath^, 2, 255)))
  else PanelRecPath := P^.ThePath^;
end;

function NameMatchesMultiMask(const Name, Mask: String;
  PipePos: Byte): Boolean;
var
  B, E, L: Byte;
begin
  L := Length(Mask);
  if PipePos <> 0 then
  begin
    E := PipePos + 1;
    repeat
      while (E <= L) and (Mask[E] in [{' ',} ';', ',']) do Inc(E);
      if E > L then Break;
      B := E;
      while (E <= L) and not (Mask[E] in [{' ',} ';', ',']) do Inc(E);
      if WildCardMatch(Name, Copy(Mask, B, E - B)) then
      begin
        NameMatchesMultiMask := False;
        Exit;
      end;
    until False;
  end;
  NameMatchesMultiMask := True;
  if PipePos = 1 then Exit;
  if PipePos <> 0 then L := PipePos - 1;
  E := 1;
  repeat
    while (E <= L) and (Mask[E] in [{' ',} ';', ',']) do Inc(E);
    if E > L then Break;
    B := E;
    while (E <= L) and not (Mask[E] in [{' ',} ';', ',']) do Inc(E);
    if WildCardMatch(Name, Copy(Mask, B, E - B)) then Exit;
  until False;
  NameMatchesMultiMask := False;
end;

function AdvancedFilterPassed(P: PFilterRec; States: Pointer;
  var SR: SearchRec; const ALongName: FNameStr): Boolean;
var
  B: Byte;
  Ext: String[3];
  Name: String[12];
begin
  if ((P^.Attr and AnyFile <> AnyFile) and (SR.Attr and P^.Attr = 0)) or
     ((P^.LoSize <> -1) and (SR.Size < P^.LoSize)) or
     ((P^.HiSize <> -1) and (SR.Size > P^.HiSize)) or
     ((P^.LoTime <> -1) and (SR.Time < P^.LoTime)) or
     ((P^.HiTime <> -1) and (SR.Time > P^.HiTime)) then
    AdvancedFilterPassed := False
  else
  begin
    if ALongName = '' then
    begin
      B := Pos('.', SR.Name);
      if B = 0 then
      begin
        Name := SR.Name;
        TrimSt(Name);
        Ext := '';
      end
      else
      begin
        Name := Copy(SR.Name, 1, B - 1);
        TrimSt(Name);
        Ext := Copy(SR.Name, B + 1, 3);
        TrimSt(Ext);
      end;
      Name := Concat(Name, '.', Ext);
    end;
    if P^.Unix then
      if ALongName <> '' then AdvancedFilterPassed :=
        IsAcceptable(ALongName, PState(States)^)
      else AdvancedFilterPassed :=
        IsAcceptable(Name, PState(States)^)
    else if ALongName <> '' then AdvancedFilterPassed :=
      NameMatchesMultiMask(ALongName, P^.Text^, P^.PipePos)
    else AdvancedFilterPassed :=
      NameMatchesMultiMask(Name, P^.Text^, P^.PipePos);
  end;
end;

end.
