FileMasks.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "FileMasks.h"
  5. #include "Common.h"
  6. #include "TextsCore.h"
  7. #include "RemoteFiles.h"
  8. #include "PuttyTools.h"
  9. #include "Terminal.h"
  10. //---------------------------------------------------------------------------
  11. __fastcall EFileMasksException::EFileMasksException(
  12. AnsiString Message, int AErrorStart, int AErrorLen) :
  13. Exception(Message)
  14. {
  15. ErrorStart = AErrorStart;
  16. ErrorLen = AErrorLen;
  17. }
  18. //---------------------------------------------------------------------------
  19. AnsiString __fastcall MaskFilePart(const AnsiString Part, const AnsiString Mask, bool& Masked)
  20. {
  21. AnsiString Result;
  22. int RestStart = 1;
  23. bool Delim = false;
  24. for (int Index = 1; Index <= Mask.Length(); Index++)
  25. {
  26. switch (Mask[Index])
  27. {
  28. case '\\':
  29. if (!Delim)
  30. {
  31. Delim = true;
  32. Masked = true;
  33. break;
  34. }
  35. case '*':
  36. if (!Delim)
  37. {
  38. Result += Part.SubString(RestStart, Part.Length() - RestStart + 1);
  39. RestStart = Part.Length() + 1;
  40. Masked = true;
  41. break;
  42. }
  43. case '?':
  44. if (!Delim)
  45. {
  46. if (RestStart <= Part.Length())
  47. {
  48. Result += Part[RestStart];
  49. RestStart++;
  50. }
  51. Masked = true;
  52. break;
  53. }
  54. default:
  55. Result += Mask[Index];
  56. RestStart++;
  57. Delim = false;
  58. break;
  59. }
  60. }
  61. return Result;
  62. }
  63. //---------------------------------------------------------------------------
  64. AnsiString __fastcall MaskFileName(AnsiString FileName, const AnsiString Mask)
  65. {
  66. if (!Mask.IsEmpty() && (Mask != "*") && (Mask != "*.*"))
  67. {
  68. bool Masked;
  69. int P = Mask.LastDelimiter(".");
  70. if (P > 0)
  71. {
  72. int P2 = FileName.LastDelimiter(".");
  73. // only dot at beginning of file name is not considered as
  74. // name/ext separator
  75. AnsiString FileExt = P2 > 1 ?
  76. FileName.SubString(P2 + 1, FileName.Length() - P2) : AnsiString();
  77. FileExt = MaskFilePart(FileExt, Mask.SubString(P + 1, Mask.Length() - P), Masked);
  78. if (P2 > 1)
  79. {
  80. FileName.SetLength(P2 - 1);
  81. }
  82. FileName = MaskFilePart(FileName, Mask.SubString(1, P - 1), Masked);
  83. if (!FileExt.IsEmpty())
  84. {
  85. FileName += "." + FileExt;
  86. }
  87. }
  88. else
  89. {
  90. FileName = MaskFilePart(FileName, Mask, Masked);
  91. }
  92. }
  93. return FileName;
  94. }
  95. //---------------------------------------------------------------------------
  96. bool __fastcall IsFileNameMask(const AnsiString Mask)
  97. {
  98. bool Masked = false;
  99. MaskFilePart("", Mask, Masked);
  100. return Masked;
  101. }
  102. //---------------------------------------------------------------------------
  103. AnsiString __fastcall DelimitFileNameMask(AnsiString Mask)
  104. {
  105. for (int i = 1; i <= Mask.Length(); i++)
  106. {
  107. if (strchr("\\*?", Mask[i]) != NULL)
  108. {
  109. Mask.Insert("\\", i);
  110. i++;
  111. }
  112. }
  113. return Mask;
  114. }
  115. //---------------------------------------------------------------------------
  116. //---------------------------------------------------------------------------
  117. TFileMasks::TParams::TParams() :
  118. Size(0)
  119. {
  120. }
  121. //---------------------------------------------------------------------------
  122. AnsiString TFileMasks::TParams::ToString() const
  123. {
  124. return AnsiString("[") + IntToStr(Size) + "]";
  125. }
  126. //---------------------------------------------------------------------------
  127. //---------------------------------------------------------------------------
  128. bool __fastcall TFileMasks::IsMask(const AnsiString Mask)
  129. {
  130. return (Mask.LastDelimiter("?*[") > 0);
  131. }
  132. //---------------------------------------------------------------------------
  133. bool __fastcall TFileMasks::IsAnyMask(const AnsiString & Mask)
  134. {
  135. return Mask.IsEmpty() || (Mask == "*.*") || (Mask == "*");
  136. }
  137. //---------------------------------------------------------------------------
  138. AnsiString __fastcall TFileMasks::NormalizeMask(const AnsiString & Mask, const AnsiString & AnyMask)
  139. {
  140. if (IsAnyMask(Mask))
  141. {
  142. return AnyMask;
  143. }
  144. else
  145. {
  146. return Mask;
  147. }
  148. }
  149. //---------------------------------------------------------------------------
  150. __fastcall TFileMasks::TFileMasks()
  151. {
  152. }
  153. //---------------------------------------------------------------------------
  154. __fastcall TFileMasks::TFileMasks(const TFileMasks & Source)
  155. {
  156. SetStr(Source.Masks, false);
  157. }
  158. //---------------------------------------------------------------------------
  159. __fastcall TFileMasks::TFileMasks(const AnsiString & AMasks)
  160. {
  161. SetStr(AMasks, false);
  162. }
  163. //---------------------------------------------------------------------------
  164. __fastcall TFileMasks::~TFileMasks()
  165. {
  166. Clear();
  167. }
  168. //---------------------------------------------------------------------------
  169. void __fastcall TFileMasks::Clear()
  170. {
  171. Clear(FIncludeMasks);
  172. Clear(FExcludeMasks);
  173. }
  174. //---------------------------------------------------------------------------
  175. void __fastcall TFileMasks::Clear(TMasks & Masks)
  176. {
  177. TMasks::iterator I = Masks.begin();
  178. while (I != Masks.end())
  179. {
  180. ReleaseMaskMask((*I).FileNameMask);
  181. ReleaseMaskMask((*I).DirectoryMask);
  182. I++;
  183. }
  184. Masks.clear();
  185. }
  186. //---------------------------------------------------------------------------
  187. void __fastcall TFileMasks::Negate()
  188. {
  189. FStr = "";
  190. FIncludeMasks.swap(FExcludeMasks);
  191. }
  192. //---------------------------------------------------------------------------
  193. bool __fastcall TFileMasks::MatchesMasks(const AnsiString FileName, bool Directory,
  194. const AnsiString Path, const TParams * Params, const TMasks & Masks)
  195. {
  196. bool Result = false;
  197. TMasks::const_iterator I = Masks.begin();
  198. while (!Result && (I != Masks.end()))
  199. {
  200. const TMask & Mask = *I;
  201. Result =
  202. (!Mask.DirectoryOnly || Directory) &&
  203. MatchesMaskMask(Mask.DirectoryMask, Path) &&
  204. MatchesMaskMask(Mask.FileNameMask, FileName);
  205. if (Result)
  206. {
  207. bool HasSize = !Directory && (Params != NULL);
  208. switch (Mask.HighSizeMask)
  209. {
  210. case TMask::None:
  211. Result = true;
  212. break;
  213. case TMask::Open:
  214. Result = HasSize && (Params->Size < Mask.HighSize);
  215. break;
  216. case TMask::Close:
  217. Result = HasSize && (Params->Size <= Mask.HighSize);
  218. break;
  219. }
  220. if (Result)
  221. {
  222. switch (Mask.LowSizeMask)
  223. {
  224. case TMask::None:
  225. Result = true;
  226. break;
  227. case TMask::Open:
  228. Result = HasSize && (Params->Size > Mask.LowSize);
  229. break;
  230. case TMask::Close:
  231. Result = HasSize && (Params->Size >= Mask.LowSize);
  232. break;
  233. }
  234. }
  235. }
  236. I++;
  237. }
  238. return Result;
  239. }
  240. //---------------------------------------------------------------------------
  241. bool __fastcall TFileMasks::Matches(const AnsiString FileName, bool Directory,
  242. const AnsiString Path, const TParams * Params) const
  243. {
  244. bool Result =
  245. (FIncludeMasks.empty() || MatchesMasks(FileName, Directory, Path, Params, FIncludeMasks)) &&
  246. !MatchesMasks(FileName, Directory, Path, Params, FExcludeMasks);
  247. return Result;
  248. }
  249. //---------------------------------------------------------------------------
  250. bool __fastcall TFileMasks::Matches(const AnsiString FileName, bool Local,
  251. bool Directory, const TParams * Params) const
  252. {
  253. bool Result;
  254. if (Local)
  255. {
  256. AnsiString Path = ExtractFilePath(FileName);
  257. if (!Path.IsEmpty())
  258. {
  259. Path = ToUnixPath(ExcludeTrailingBackslash(Path));
  260. }
  261. Result = Matches(ExtractFileName(FileName), Directory, Path, Params);
  262. }
  263. else
  264. {
  265. Result = Matches(UnixExtractFileName(FileName), Directory,
  266. UnixExcludeTrailingBackslash(UnixExtractFilePath(FileName)), Params);
  267. }
  268. return Result;
  269. }
  270. //---------------------------------------------------------------------------
  271. bool __fastcall TFileMasks::operator ==(const TFileMasks & rhm) const
  272. {
  273. return (Masks == rhm.Masks);
  274. }
  275. //---------------------------------------------------------------------------
  276. TFileMasks & __fastcall TFileMasks::operator =(const AnsiString & rhs)
  277. {
  278. Masks = rhs;
  279. return *this;
  280. }
  281. //---------------------------------------------------------------------------
  282. TFileMasks & __fastcall TFileMasks::operator =(const TFileMasks & rhm)
  283. {
  284. Masks = rhm.Masks;
  285. return *this;
  286. }
  287. //---------------------------------------------------------------------------
  288. bool __fastcall TFileMasks::operator ==(const AnsiString & rhs) const
  289. {
  290. return (Masks == rhs);
  291. }
  292. //---------------------------------------------------------------------------
  293. void __fastcall TFileMasks::ThrowError(int Start, int End)
  294. {
  295. throw EFileMasksException(
  296. FMTLOAD(MASK_ERROR, (Masks.SubString(Start, End - Start + 1))),
  297. Start, End - Start + 1);
  298. }
  299. //---------------------------------------------------------------------------
  300. void __fastcall TFileMasks::CreateMaskMask(const AnsiString & Mask, int Start, int End,
  301. bool Ex, TMaskMask & MaskMask)
  302. {
  303. try
  304. {
  305. if (Ex && IsAnyMask(Mask))
  306. {
  307. MaskMask.Kind = TMaskMask::Any;
  308. MaskMask.Mask = NULL;
  309. assert(MaskMask.Mask == NULL);
  310. }
  311. else
  312. {
  313. MaskMask.Kind = (Ex && (Mask == "*.")) ? TMaskMask::NoExt : TMaskMask::Regular;
  314. MaskMask.Mask = new Masks::TMask(Mask);
  315. }
  316. }
  317. catch(...)
  318. {
  319. ThrowError(Start, End);
  320. }
  321. }
  322. //---------------------------------------------------------------------------
  323. void __fastcall TFileMasks::ReleaseMaskMask(TMaskMask & MaskMask)
  324. {
  325. delete MaskMask.Mask;
  326. }
  327. //---------------------------------------------------------------------------
  328. void __fastcall TFileMasks::TrimEx(AnsiString & Str, int & Start, int & End)
  329. {
  330. AnsiString Buf = TrimLeft(Str);
  331. Start += Str.Length() - Buf.Length();
  332. Str = TrimRight(Buf);
  333. End -= Buf.Length() - Str.Length();
  334. }
  335. //---------------------------------------------------------------------------
  336. bool __fastcall TFileMasks::MatchesMaskMask(const TMaskMask & MaskMask, const AnsiString & Str)
  337. {
  338. bool Result;
  339. if (MaskMask.Kind == TMaskMask::Any)
  340. {
  341. Result = true;
  342. }
  343. else if ((MaskMask.Kind == TMaskMask::NoExt) && (Str.Pos(".") == 0))
  344. {
  345. Result = true;
  346. }
  347. else
  348. {
  349. Result = MaskMask.Mask->Matches(Str);
  350. }
  351. return Result;
  352. }
  353. //---------------------------------------------------------------------------
  354. void __fastcall TFileMasks::SetMasks(const AnsiString value)
  355. {
  356. if (FStr != value)
  357. {
  358. SetStr(value, false);
  359. }
  360. }
  361. //---------------------------------------------------------------------------
  362. void __fastcall TFileMasks::SetMask(const AnsiString & Mask)
  363. {
  364. SetStr(Mask, true);
  365. }
  366. //---------------------------------------------------------------------------
  367. void __fastcall TFileMasks::SetStr(const AnsiString Str, bool SingleMask)
  368. {
  369. AnsiString Backup = FStr;
  370. try
  371. {
  372. FStr = Str;
  373. Clear();
  374. int NextMaskFrom = 1;
  375. bool Include = true;
  376. while (NextMaskFrom <= Str.Length())
  377. {
  378. int MaskStart = NextMaskFrom;
  379. char NextMaskDelimiter;
  380. AnsiString MaskStr;
  381. if (SingleMask)
  382. {
  383. MaskStr = Str;
  384. NextMaskFrom = Str.Length() + 1;
  385. NextMaskDelimiter = '\0';
  386. }
  387. else
  388. {
  389. MaskStr = CopyToChars(Str, NextMaskFrom, ";,|", false, &NextMaskDelimiter);
  390. }
  391. int MaskEnd = NextMaskFrom - 1;
  392. TrimEx(MaskStr, MaskStart, MaskEnd);
  393. if (!MaskStr.IsEmpty())
  394. {
  395. TMask Mask;
  396. Mask.Str = MaskStr;
  397. Mask.DirectoryOnly = false;
  398. Mask.FileNameMask.Kind = TMaskMask::Any;
  399. Mask.FileNameMask.Mask = NULL;
  400. Mask.DirectoryMask.Kind = TMaskMask::Any;
  401. Mask.DirectoryMask.Mask = NULL;
  402. Mask.HighSizeMask = TMask::None;
  403. Mask.LowSizeMask = TMask::None;
  404. char NextPartDelimiter = '\0';
  405. int NextPartFrom = 1;
  406. while (NextPartFrom <= MaskStr.Length())
  407. {
  408. char PartDelimiter = NextPartDelimiter;
  409. int PartFrom = NextPartFrom;
  410. AnsiString PartStr = CopyToChars(MaskStr, NextPartFrom, "<>", false, &NextPartDelimiter);
  411. int PartStart = MaskStart + PartFrom - 1;
  412. int PartEnd = MaskStart + NextPartFrom - 2;
  413. TrimEx(PartStr, PartStart, PartEnd);
  414. if (PartDelimiter != '\0')
  415. {
  416. bool Low = (PartDelimiter == '>');
  417. TMask::TSizeMask & SizeMask = (Low ? Mask.LowSizeMask : Mask.HighSizeMask);
  418. __int64 & Size = (Low ? Mask.LowSize : Mask.HighSize);
  419. bool Result = (SizeMask == TMask::None);
  420. if (!Result)
  421. {
  422. // include delimiter into size part
  423. ThrowError(PartStart - 1, PartEnd);
  424. }
  425. else
  426. {
  427. if ((PartStr.Length() >= 1) && (PartStr[1] == '='))
  428. {
  429. SizeMask = TMask::Close;
  430. PartStr.Delete(1, 1);
  431. }
  432. else
  433. {
  434. SizeMask = TMask::Open;
  435. }
  436. Size = ParseSize(PartStr);
  437. }
  438. }
  439. else if (!PartStr.IsEmpty())
  440. {
  441. int D = PartStr.LastDelimiter("\\/");
  442. Mask.DirectoryOnly = (D > 0) && (D == PartStr.Length());
  443. if (Mask.DirectoryOnly)
  444. {
  445. PartStr.SetLength(PartStr.Length() - 1);
  446. D = PartStr.LastDelimiter("\\/");
  447. }
  448. if (D > 0)
  449. {
  450. // make sure sole "/" (root dir) is preserved as is
  451. CreateMaskMask(
  452. UnixExcludeTrailingBackslash(ToUnixPath(PartStr.SubString(1, D))),
  453. PartStart, PartStart + D - 1, false,
  454. Mask.DirectoryMask);
  455. CreateMaskMask(
  456. PartStr.SubString(D + 1, PartStr.Length() - D),
  457. PartStart + D, PartEnd, true,
  458. Mask.FileNameMask);
  459. }
  460. else
  461. {
  462. CreateMaskMask(PartStr, PartStart, PartEnd, true, Mask.FileNameMask);
  463. }
  464. }
  465. }
  466. (Include ? FIncludeMasks : FExcludeMasks).push_back(Mask);
  467. }
  468. if (NextMaskDelimiter == '|')
  469. {
  470. if (Include)
  471. {
  472. Include = false;
  473. }
  474. else
  475. {
  476. ThrowError(NextMaskFrom - 1, Str.Length());
  477. }
  478. }
  479. }
  480. }
  481. catch(...)
  482. {
  483. // this does not work correctly if previous mask was set using SetMask.
  484. // this should not fail (the mask was validated before),
  485. // otherwise we end in an infinite loop
  486. SetStr(Backup, false);
  487. throw;
  488. }
  489. }
  490. //---------------------------------------------------------------------------
  491. //---------------------------------------------------------------------------
  492. #define TEXT_TOKEN '\255'
  493. //---------------------------------------------------------------------------
  494. const char TCustomCommand::NoQuote = '\0';
  495. const AnsiString TCustomCommand::Quotes = "\"'";
  496. //---------------------------------------------------------------------------
  497. TCustomCommand::TCustomCommand()
  498. {
  499. }
  500. //---------------------------------------------------------------------------
  501. void __fastcall TCustomCommand::GetToken(
  502. const AnsiString & Command, int Index, int & Len, char & PatternCmd)
  503. {
  504. assert(Index <= Command.Length());
  505. const char * Ptr = Command.c_str() + Index - 1;
  506. if (Ptr[0] == '!')
  507. {
  508. PatternCmd = Ptr[1];
  509. if (PatternCmd == '!')
  510. {
  511. Len = 2;
  512. }
  513. else
  514. {
  515. Len = PatternLen(Index, PatternCmd);
  516. }
  517. if (Len < 0)
  518. {
  519. throw Exception(FMTLOAD(CUSTOM_COMMAND_UNKNOWN, (PatternCmd, Index)));
  520. }
  521. else if (Len > 0)
  522. {
  523. if ((Command.Length() - Index + 1) < Len)
  524. {
  525. throw Exception(FMTLOAD(CUSTOM_COMMAND_UNTERMINATED, (PatternCmd, Index)));
  526. }
  527. }
  528. else if (Len == 0)
  529. {
  530. const char * PatternEnd = strchr(Ptr + 1, '!');
  531. if (PatternEnd == NULL)
  532. {
  533. throw Exception(FMTLOAD(CUSTOM_COMMAND_UNTERMINATED, (PatternCmd, Index)));
  534. }
  535. Len = PatternEnd - Ptr + 1;
  536. }
  537. }
  538. else
  539. {
  540. PatternCmd = TEXT_TOKEN;
  541. const char * NextPattern = strchr(Ptr, '!');
  542. if (NextPattern == NULL)
  543. {
  544. Len = Command.Length() - Index + 1;
  545. }
  546. else
  547. {
  548. Len = NextPattern - Ptr;
  549. }
  550. }
  551. }
  552. //---------------------------------------------------------------------------
  553. AnsiString __fastcall TCustomCommand::Complete(const AnsiString & Command,
  554. bool LastPass)
  555. {
  556. AnsiString Result;
  557. int Index = 1;
  558. while (Index <= Command.Length())
  559. {
  560. int Len;
  561. char PatternCmd;
  562. GetToken(Command, Index, Len, PatternCmd);
  563. if (PatternCmd == TEXT_TOKEN)
  564. {
  565. Result += Command.SubString(Index, Len);
  566. }
  567. else if (PatternCmd == '!')
  568. {
  569. if (LastPass)
  570. {
  571. Result += '!';
  572. }
  573. else
  574. {
  575. Result += Command.SubString(Index, Len);
  576. }
  577. }
  578. else
  579. {
  580. char Quote = NoQuote;
  581. if ((Index > 1) && (Index + Len - 1 < Command.Length()) &&
  582. Command.IsDelimiter(Quotes, Index - 1) &&
  583. Command.IsDelimiter(Quotes, Index + Len) &&
  584. (Command[Index - 1] == Command[Index + Len]))
  585. {
  586. Quote = Command[Index - 1];
  587. }
  588. AnsiString Pattern = Command.SubString(Index, Len);
  589. AnsiString Replacement;
  590. bool Delimit = true;
  591. if (PatternReplacement(Index, Pattern, Replacement, Delimit))
  592. {
  593. if (!LastPass)
  594. {
  595. Replacement = StringReplace(Replacement, "!", "!!",
  596. TReplaceFlags() << rfReplaceAll);
  597. }
  598. if (Delimit)
  599. {
  600. DelimitReplacement(Replacement, Quote);
  601. }
  602. Result += Replacement;
  603. }
  604. else
  605. {
  606. Result += Pattern;
  607. }
  608. }
  609. Index += Len;
  610. }
  611. return Result;
  612. }
  613. //---------------------------------------------------------------------------
  614. void __fastcall TCustomCommand::DelimitReplacement(AnsiString & Replacement, char Quote)
  615. {
  616. Replacement = ShellDelimitStr(Replacement, Quote);
  617. }
  618. //---------------------------------------------------------------------------
  619. void __fastcall TCustomCommand::Validate(const AnsiString & Command)
  620. {
  621. CustomValidate(Command, NULL);
  622. }
  623. //---------------------------------------------------------------------------
  624. void __fastcall TCustomCommand::CustomValidate(const AnsiString & Command,
  625. void * Arg)
  626. {
  627. int Index = 1;
  628. while (Index <= Command.Length())
  629. {
  630. int Len;
  631. char PatternCmd;
  632. GetToken(Command, Index, Len, PatternCmd);
  633. ValidatePattern(Command, Index, Len, PatternCmd, Arg);
  634. Index += Len;
  635. }
  636. }
  637. //---------------------------------------------------------------------------
  638. bool __fastcall TCustomCommand::FindPattern(const AnsiString & Command,
  639. char PatternCmd)
  640. {
  641. bool Result = false;
  642. int Index = 1;
  643. while (!Result && (Index <= Command.Length()))
  644. {
  645. int Len;
  646. char APatternCmd;
  647. GetToken(Command, Index, Len, APatternCmd);
  648. if (((PatternCmd != '!') && (PatternCmd == APatternCmd)) ||
  649. ((PatternCmd == '!') && (Len == 1) && (APatternCmd != TEXT_TOKEN)))
  650. {
  651. Result = true;
  652. }
  653. Index += Len;
  654. }
  655. return Result;
  656. }
  657. //---------------------------------------------------------------------------
  658. void __fastcall TCustomCommand::ValidatePattern(const AnsiString & /*Command*/,
  659. int /*Index*/, int /*Len*/, char /*PatternCmd*/, void * /*Arg*/)
  660. {
  661. }
  662. //---------------------------------------------------------------------------
  663. //---------------------------------------------------------------------------
  664. TInteractiveCustomCommand::TInteractiveCustomCommand(
  665. TCustomCommand * ChildCustomCommand)
  666. {
  667. FChildCustomCommand = ChildCustomCommand;
  668. }
  669. //---------------------------------------------------------------------------
  670. void __fastcall TInteractiveCustomCommand::Prompt(int /*Index*/,
  671. const AnsiString & /*Prompt*/, AnsiString & Value)
  672. {
  673. Value = "";
  674. }
  675. //---------------------------------------------------------------------------
  676. int __fastcall TInteractiveCustomCommand::PatternLen(int Index, char PatternCmd)
  677. {
  678. int Len;
  679. switch (PatternCmd)
  680. {
  681. case '?':
  682. Len = 0;
  683. break;
  684. default:
  685. Len = FChildCustomCommand->PatternLen(Index, PatternCmd);
  686. break;
  687. }
  688. return Len;
  689. }
  690. //---------------------------------------------------------------------------
  691. bool __fastcall TInteractiveCustomCommand::PatternReplacement(int Index, const AnsiString & Pattern,
  692. AnsiString & Replacement, bool & Delimit)
  693. {
  694. bool Result;
  695. if ((Pattern.Length() >= 3) && (Pattern[2] == '?'))
  696. {
  697. AnsiString PromptStr;
  698. int Pos = Pattern.SubString(3, Pattern.Length() - 2).Pos("?");
  699. if (Pos > 0)
  700. {
  701. Replacement = Pattern.SubString(3 + Pos, Pattern.Length() - 3 - Pos);
  702. if ((Pos > 1) && (Pattern[3 + Pos - 2] == '\\'))
  703. {
  704. Delimit = false;
  705. Pos--;
  706. }
  707. PromptStr = Pattern.SubString(3, Pos - 1);
  708. }
  709. else
  710. {
  711. PromptStr = Pattern.SubString(3, Pattern.Length() - 3);
  712. }
  713. Prompt(Index, PromptStr, Replacement);
  714. Result = true;
  715. }
  716. else
  717. {
  718. Result = false;
  719. }
  720. return Result;
  721. }
  722. //---------------------------------------------------------------------------
  723. //---------------------------------------------------------------------------
  724. __fastcall TCustomCommandData::TCustomCommandData()
  725. {
  726. }
  727. //---------------------------------------------------------------------------
  728. __fastcall TCustomCommandData::TCustomCommandData(TTerminal * Terminal)
  729. {
  730. HostName = Terminal->SessionData->HostName;
  731. UserName = Terminal->SessionData->UserName;
  732. Password = Terminal->Password;
  733. }
  734. //---------------------------------------------------------------------------
  735. //---------------------------------------------------------------------------
  736. TFileCustomCommand::TFileCustomCommand()
  737. {
  738. }
  739. //---------------------------------------------------------------------------
  740. TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
  741. const AnsiString & Path)
  742. {
  743. FData = Data;
  744. FPath = Path;
  745. }
  746. //---------------------------------------------------------------------------
  747. TFileCustomCommand::TFileCustomCommand(const TCustomCommandData & Data,
  748. const AnsiString & Path, const AnsiString & FileName,
  749. const AnsiString & FileList) :
  750. TCustomCommand()
  751. {
  752. FData = Data;
  753. FPath = Path;
  754. FFileName = FileName;
  755. FFileList = FileList;
  756. }
  757. //---------------------------------------------------------------------------
  758. int __fastcall TFileCustomCommand::PatternLen(int /*Index*/, char PatternCmd)
  759. {
  760. int Len;
  761. switch (toupper(PatternCmd))
  762. {
  763. case '@':
  764. case 'U':
  765. case 'P':
  766. case '/':
  767. case '&':
  768. Len = 2;
  769. break;
  770. default:
  771. Len = 1;
  772. break;
  773. }
  774. return Len;
  775. }
  776. //---------------------------------------------------------------------------
  777. bool __fastcall TFileCustomCommand::PatternReplacement(int /*Index*/,
  778. const AnsiString & Pattern, AnsiString & Replacement, bool & Delimit)
  779. {
  780. // keep consistent with TSessionLog::OpenLogFile
  781. if (Pattern == "!@")
  782. {
  783. Replacement = FData.HostName;
  784. }
  785. else if (AnsiSameText(Pattern, "!u"))
  786. {
  787. Replacement = FData.UserName;
  788. }
  789. else if (AnsiSameText(Pattern, "!p"))
  790. {
  791. Replacement = FData.Password;
  792. }
  793. else if (Pattern == "!/")
  794. {
  795. Replacement = UnixIncludeTrailingBackslash(FPath);
  796. }
  797. else if (Pattern == "!&")
  798. {
  799. Replacement = FFileList;
  800. // already delimited
  801. Delimit = false;
  802. }
  803. else
  804. {
  805. assert(Pattern.Length() == 1);
  806. Replacement = FFileName;
  807. }
  808. return true;
  809. }
  810. //---------------------------------------------------------------------------
  811. void __fastcall TFileCustomCommand::Validate(const AnsiString & Command)
  812. {
  813. int Found[2] = { 0, 0 };
  814. CustomValidate(Command, &Found);
  815. if ((Found[0] > 0) && (Found[1] > 0))
  816. {
  817. throw Exception(FMTLOAD(CUSTOM_COMMAND_FILELIST_ERROR,
  818. (Found[1], Found[0])));
  819. }
  820. }
  821. //---------------------------------------------------------------------------
  822. void __fastcall TFileCustomCommand::ValidatePattern(const AnsiString & /*Command*/,
  823. int Index, int /*Len*/, char PatternCmd, void * Arg)
  824. {
  825. int * Found = static_cast<int *>(Arg);
  826. assert(Index > 0);
  827. if (PatternCmd == '&')
  828. {
  829. Found[0] = Index;
  830. }
  831. else if ((PatternCmd != TEXT_TOKEN) && (PatternLen(Index, PatternCmd) == 1))
  832. {
  833. Found[1] = Index;
  834. }
  835. }
  836. //---------------------------------------------------------------------------
  837. bool __fastcall TFileCustomCommand::IsFileListCommand(const AnsiString & Command)
  838. {
  839. return FindPattern(Command, '&');
  840. }
  841. //---------------------------------------------------------------------------
  842. bool __fastcall TFileCustomCommand::IsFileCommand(const AnsiString & Command)
  843. {
  844. return FindPattern(Command, '!') || FindPattern(Command, '&');
  845. }
  846. //---------------------------------------------------------------------------