//--------------------------------------------------------------------------- UnicodeString TFileMasks::ComposeMaskStr( TStrings * MasksStr, bool Directory) { UnicodeString Result; UnicodeString ResultNoDirMask; for (intptr_t I = 0; I < MasksStr->GetCount(); ++I) { UnicodeString Str = MasksStr->GetString(I).Trim(); if (!Str.IsEmpty()) { for (intptr_t P = 1; P <= Str.Length(); P++) { if (Str.IsDelimiter(AllFileMasksDelimiters, P)) { Str.Insert(Str[P], P); P++; } } UnicodeString StrNoDirMask; if (Directory) { StrNoDirMask = Str; Str = MakeDirectoryMask(Str); } else { while (Str.IsDelimiter(DirectoryMaskDelimiters, Str.Length())) { Str.SetLength(Str.Length() - 1); } StrNoDirMask = Str; } AddToList(Result, Str, FileMasksDelimiterStr); AddToList(ResultNoDirMask, StrNoDirMask, FileMasksDelimiterStr); } } // For directories, the above will add slash ay the end of masks, // breaking size and time masks and thus circumverting their validation. // This performes as hoc validation to cover the scenario. // For files this makes no difference, but no harm either TFileMasks Temp(Directory ? 1 : 0); Temp = ResultNoDirMask; return Result; }
void TOptions::Add(const UnicodeString & Value) { if (!FNoMoreSwitches && (Value.Length() == 2) && (Value[1] == Value[2]) && (FSwitchMarks.Pos(Value[1]) > 0)) { FNoMoreSwitches = true; } else { bool Switch = false; intptr_t Index = 0; // shut up if (!FNoMoreSwitches && (Value.Length() >= 2) && (FSwitchMarks.Pos(Value[1]) > 0)) { Index = 2; Switch = true; while (Switch && (Index <= Value.Length())) { if (Value.IsDelimiter(FSwitchValueDelimiters, Index)) { break; } // this is to treat /home/martin as parameter, not as switch else if ((Value[Index] != L'?') && !IsLetter(Value[Index])) { Switch = false; break; } ++Index; } } if (Switch) { TOption Option; Option.Type = otSwitch; Option.Name = Value.SubString(2, Index - 2); Option.Value = Value.SubString(Index + 1, Value.Length()); Option.Used = false; FOptions.push_back(Option); } else { TOption Option; Option.Type = otParam; Option.Value = Value; Option.Used = false; FOptions.push_back(Option); ++FParamCount; } } FOriginalOptions = FOptions; }
//--------------------------------------------------------------------------- intptr_t LastDelimiter(const UnicodeString & Delimiters, const UnicodeString & Str) { if (Str.Length()) { for (intptr_t I = Str.Length(); I >= 1; --I) { if (Str.IsDelimiter(Delimiters, I)) { return I; } } } return 0; }
//--------------------------------------------------------------------------- intptr_t FirstDelimiter(const UnicodeString & Delimiters, const UnicodeString & Str) { if (Str.Length()) { for (intptr_t I = 1; I <= Str.Length(); ++I) { if (Str.IsDelimiter(Delimiters, I)) { return I; } } } return 0; }
//--------------------------------------------------------------------------- UnicodeString TFileMasks::MakeDirectoryMask(const UnicodeString & Str) { assert(!Str.IsEmpty()); UnicodeString Result = Str; if (Result.IsEmpty() || !Result.IsDelimiter(DirectoryMaskDelimiters, Result.Length())) { intptr_t D = Result.LastDelimiter(DirectoryMaskDelimiters); // if there's any [back]slash anywhere in str, // add the same [back]slash at the end, otherwise add slash wchar_t Delimiter = (D > 0) ? Result[D] : DirectoryMaskDelimiters[1]; Result += Delimiter; } return Result; }
//--------------------------------------------------------------------------- UnicodeString TCustomCommand::Complete(const UnicodeString & Command, bool LastPass) { UnicodeString Result; intptr_t Index = 1; while (Index <= Command.Length()) { intptr_t Len; wchar_t PatternCmd; GetToken(Command, Index, Len, PatternCmd); if (PatternCmd == TEXT_TOKEN) { Result += Command.SubString(Index, Len); } else if (PatternCmd == L'!') { if (LastPass) { Result += L'!'; } else { Result += Command.SubString(Index, Len); } } else { wchar_t Quote = NoQuote; if ((Index > 1) && (Index + Len - 1 < Command.Length()) && Command.IsDelimiter(Quotes, Index - 1) && Command.IsDelimiter(Quotes, Index + Len) && (Command[Index - 1] == Command[Index + Len])) { Quote = Command[Index - 1]; } UnicodeString Pattern = Command.SubString(Index, Len); UnicodeString Replacement; bool Delimit = true; if (PatternReplacement(Pattern, Replacement, Delimit)) { if (!LastPass) { Replacement = StringReplace(Replacement, L"!", L"!!", TReplaceFlags() << rfReplaceAll); } if (Delimit) { DelimitReplacement(Replacement, Quote); } Result += Replacement; } else { Result += Pattern; } } Index += Len; } return Result; }
//--------------------------------------------------------------------------- void TFileMasks::CreateMask( const UnicodeString & MaskStr, intptr_t MaskStart, intptr_t /*MaskEnd*/, bool Include) { bool Directory = false; // shut up TMask Mask; Mask.MaskStr = MaskStr; Mask.UserStr = MaskStr; Mask.FileNameMask.Kind = TMaskMask::Any; Mask.FileNameMask.Mask = nullptr; Mask.DirectoryMask.Kind = TMaskMask::Any; Mask.DirectoryMask.Mask = nullptr; Mask.HighSizeMask = TMask::None; Mask.LowSizeMask = TMask::None; Mask.HighModificationMask = TMask::None; Mask.LowModificationMask = TMask::None; wchar_t NextPartDelimiter = L'\0'; intptr_t NextPartFrom = 1; while (NextPartFrom <= MaskStr.Length()) { wchar_t PartDelimiter = NextPartDelimiter; intptr_t PartFrom = NextPartFrom; UnicodeString PartStr = CopyToChars(MaskStr, NextPartFrom, L"<>", false, &NextPartDelimiter, true); intptr_t PartStart = MaskStart + PartFrom - 1; intptr_t PartEnd = MaskStart + NextPartFrom - 1 - 2; TrimEx(PartStr, PartStart, PartEnd); if (PartDelimiter != L'\0') { bool Low = (PartDelimiter == L'>'); TMask::TMaskBoundary Boundary; if ((PartStr.Length() >= 1) && (PartStr[1] == L'=')) { Boundary = TMask::Close; PartStr.Delete(1, 1); } else { Boundary = TMask::Open; } TFormatSettings FormatSettings = TFormatSettings::Create(GetDefaultLCID()); FormatSettings.DateSeparator = L'-'; FormatSettings.TimeSeparator = L':'; FormatSettings.ShortDateFormat = L"yyyy/mm/dd"; FormatSettings.ShortTimeFormat = L"hh:nn:ss"; TDateTime Modification; if (TryStrToDateTime(PartStr, Modification, FormatSettings) || TryRelativeStrToDateTime(PartStr, Modification)) { TMask::TMaskBoundary & ModificationMask = (Low ? Mask.LowModificationMask : Mask.HighModificationMask); if ((ModificationMask != TMask::None) || Directory) { // include delimiter into size part ThrowError(PartStart - 1, PartEnd); } ModificationMask = Boundary; (Low ? Mask.LowModification : Mask.HighModification) = Modification; } else { TMask::TMaskBoundary & SizeMask = (Low ? Mask.LowSizeMask : Mask.HighSizeMask); __int64 & Size = (Low ? Mask.LowSize : Mask.HighSize); if ((SizeMask != TMask::None) || Directory) { // include delimiter into size part ThrowError(PartStart - 1, PartEnd); } SizeMask = Boundary; Size = ParseSize(PartStr); } } else if (!PartStr.IsEmpty()) { intptr_t D = PartStr.LastDelimiter(DirectoryMaskDelimiters); Directory = (D > 0) && (D == PartStr.Length()); if (Directory) { do { PartStr.SetLength(PartStr.Length() - 1); Mask.UserStr.Delete(PartStart - MaskStart + D, 1); D--; } while (PartStr.IsDelimiter(DirectoryMaskDelimiters, PartStr.Length())); D = PartStr.LastDelimiter(DirectoryMaskDelimiters); if (FForceDirectoryMasks == 0) { Directory = false; Mask.MaskStr = Mask.UserStr; } } else if (FForceDirectoryMasks > 0) { Directory = true; Mask.MaskStr.Insert(DirectoryMaskDelimiters[1], PartStart - MaskStart + PartStr.Length()); } if (D > 0) { // make sure sole "/" (root dir) is preserved as is CreateMaskMask( UnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))), PartStart, PartStart + D - 1, false, Mask.DirectoryMask); CreateMaskMask( PartStr.SubString(D + 1, PartStr.Length() - D), PartStart + D, PartEnd, true, Mask.FileNameMask); } else { CreateMaskMask(PartStr, PartStart, PartEnd, true, Mask.FileNameMask); } } } FMasks[MASK_INDEX(Directory, Include)].push_back(Mask); }