strutils.pp 99 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722
  1. {
  2. Delphi/Kylix compatibility unit: String handling routines.
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. {$inline on}
  14. {$IFNDEF FPC_DOTTEDUNITS}
  15. unit StrUtils;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. interface
  18. {$IFDEF FPC_DOTTEDUNITS}
  19. uses
  20. System.SysUtils, System.Types;
  21. {$ELSE FPC_DOTTEDUNITS}
  22. uses
  23. SysUtils, Types;
  24. {$ENDIF FPC_DOTTEDUNITS}
  25. { ---------------------------------------------------------------------
  26. Case insensitive search/replace
  27. ---------------------------------------------------------------------}
  28. Function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
  29. Function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
  30. Function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
  31. Function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
  32. function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
  33. Function AnsiReplaceText(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
  34. Function AnsiMatchText(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
  35. Function AnsiIndexText(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  36. Function StartsText(const ASubText, AText: string): Boolean; inline;
  37. Function EndsText(const ASubText, AText: string): Boolean; inline;
  38. function ResemblesText(const AText, AOther: string): Boolean; inline;
  39. function ContainsText(const AText, ASubText: string): Boolean; inline;
  40. function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
  41. function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
  42. { ---------------------------------------------------------------------
  43. Case sensitive search/replace
  44. ---------------------------------------------------------------------}
  45. Function AnsiContainsStr(const AText, ASubText: AnsiString): Boolean;inline;
  46. function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean; inline;
  47. Function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
  48. Function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
  49. Function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
  50. Function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
  51. Function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;inline;
  52. Function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;inline;
  53. Function AnsiIndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer;
  54. Function StartsStr(const ASubText, AText: string): Boolean;
  55. Function EndsStr(const ASubText, AText: string): Boolean;
  56. Function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  57. Function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  58. Function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  59. Function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  60. Operator in (const AText: Ansistring; const AValues: array of Ansistring):Boolean;inline;
  61. Operator in (const AText: UnicodeString; const AValues: array of UnicodeString):Boolean;inline;
  62. function ContainsStr(const AText, ASubText: string): Boolean; inline;
  63. function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean; inline;
  64. function IndexStr(const AText: Ansistring; const AValues: array of Ansistring): Integer; inline;
  65. { ---------------------------------------------------------------------
  66. Miscellaneous
  67. ---------------------------------------------------------------------}
  68. Function DupeString(const AText: string; ACount: Integer): string;
  69. Function ReverseString(const AText: string): string;
  70. Function AnsiReverseString(const AText: AnsiString): AnsiString;inline;
  71. Function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  72. Function RandomFrom(const AValues: array of string): string; overload;
  73. Function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string = ''): string; overload;
  74. Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
  75. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  76. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
  77. function SplitString(const S, Delimiters: string): TRTLStringDynArray;
  78. { ---------------------------------------------------------------------
  79. VB emulations.
  80. ---------------------------------------------------------------------}
  81. Function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  82. Function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  83. Function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
  84. Function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
  85. Function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;inline;
  86. Function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  87. Function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;inline;
  88. Function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;inline;
  89. Function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;inline;
  90. Function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;inline;
  91. Function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
  92. Function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;inline;
  93. { ---------------------------------------------------------------------
  94. Extended search and replace
  95. ---------------------------------------------------------------------}
  96. const
  97. { Default word delimiters are any character except the core alphanumerics. }
  98. WordDelimiters: set of AnsiChar = [#0..#255] - ['a'..'z','A'..'Z','1'..'9','0'];
  99. resourcestring
  100. SErrAmountStrings = 'Amount of search and replace strings don''t match';
  101. type
  102. TStringSearchOption = (soDown, soMatchCase, soWholeWord);
  103. TStringSearchOptions = set of TStringSearchOption;
  104. TStringSeachOption = TStringSearchOption;
  105. Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions): PAnsiChar;
  106. Function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar;inline; // ; Options: TStringSearchOptions = [soDown]
  107. Function PosEx(const SubStr, S: Ansistring; Offset: SizeInt): SizeInt;inline;
  108. Function PosEx(const SubStr, S: Ansistring): SizeInt;inline;
  109. Function PosEx(c:AnsiChar; const S: AnsiString; Offset: SizeInt): SizeInt;inline;
  110. Function PosEx(const SubStr, S: UnicodeString; Offset: SizeInt): SizeInt;inline;
  111. Function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeInt): SizeInt;inline;
  112. Function PosEx(const SubStr, S: UnicodeString): Sizeint;inline;
  113. function StringsReplace(const S: Ansistring; OldPattern, NewPattern: array of Ansistring; Flags: TReplaceFlags): string;
  114. { ---------------------------------------------------------------------
  115. Delphi compat
  116. ---------------------------------------------------------------------}
  117. Function ReplaceStr(const AText, AFromText, AToText: string): string;inline;
  118. Function ReplaceText(const AText, AFromText, AToText: string): string;inline;
  119. { ---------------------------------------------------------------------
  120. Soundex Functions.
  121. ---------------------------------------------------------------------}
  122. type
  123. TSoundexLength = 1..MaxInt;
  124. Function Soundex(const AText: string; ALength: TSoundexLength): string;
  125. Function Soundex(const AText: string): string;inline; // ; ALength: TSoundexLength = 4
  126. type
  127. TSoundexIntLength = 1..8;
  128. Function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  129. Function SoundexInt(const AText: string): Integer;inline; //; ALength: TSoundexIntLength = 4
  130. Function DecodeSoundexInt(AValue: Integer): string;
  131. Function SoundexWord(const AText: string): Word;
  132. Function DecodeSoundexWord(AValue: Word): string;
  133. Function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;inline;
  134. Function SoundexSimilar(const AText, AOther: string): Boolean;inline; //; ALength: TSoundexLength = 4
  135. Function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;inline;
  136. Function SoundexCompare(const AText, AOther: string): Integer;inline; //; ALength: TSoundexLength = 4
  137. Function SoundexProc(const AText, AOther: string): Boolean;
  138. type
  139. TCompareTextProc = Function(const AText, AOther: string): Boolean;
  140. Const
  141. AnsiResemblesProc: TCompareTextProc = @SoundexProc;
  142. ResemblesProc: TCompareTextProc = @SoundexProc;
  143. { ---------------------------------------------------------------------
  144. Other functions, based on RxStrUtils.
  145. ---------------------------------------------------------------------}
  146. type
  147. TRomanConversionStrictness = (rcsStrict, rcsRelaxed, rcsDontCare);
  148. resourcestring
  149. SInvalidRomanNumeral = '%s is not a valid Roman numeral';
  150. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  151. function DelSpace(const S: string): string;
  152. function DelChars(const S: string; Chr: AnsiChar): string;
  153. function DelChars(const S: string; Chars: TSysCharSet): string;
  154. function DelSpace1(const S: string): string;
  155. function Tab2Space(const S: string; Numb: Byte): string;
  156. function NPos(const C: string; S: string; N: Integer): SizeInt;
  157. Function RPosEx(C:AnsiChar;const S : AnsiString;offs:SizeInt):SizeInt; overload;
  158. Function RPosEx(C:Unicodechar;const S : UnicodeString;offs:SizeInt):SizeInt; overload;
  159. Function RPosEx(Const Substr : AnsiString; Const Source : AnsiString;offs:SizeInt) : SizeInt; overload;
  160. Function RPosEx(Const Substr : UnicodeString; Const Source : UnicodeString;offs:SizeInt) : SizeInt; overload;
  161. Function RPos(c:AnsiChar;const S : AnsiString):SizeInt; overload; inline;
  162. Function RPos(c:Unicodechar;const S : UnicodeString):SizeInt; overload; inline;
  163. Function RPos(Const Substr : AnsiString; Const Source : AnsiString) : SizeInt; overload; inline;
  164. Function RPos(Const Substr : UnicodeString; Const Source : UnicodeString) : SizeInt; overload; inline;
  165. function AddChar(C: AnsiChar; const S: string; N: Integer): string;
  166. function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
  167. function PadLeft(const S: string; N: Integer): string;inline;
  168. function PadRight(const S: string; N: Integer): string;inline;
  169. function PadCenter(const S: string; Len: SizeInt): string;
  170. function Copy2Symb(const S: string; Symb: AnsiChar): string;
  171. function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
  172. function Copy2Space(const S: string): string;inline;
  173. function Copy2SpaceDel(var S: string): string;inline;
  174. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  175. function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
  176. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
  177. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  178. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  179. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: SizeInt): string;
  180. {$ENDIF}
  181. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
  182. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  183. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  184. function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
  185. {$ENDIF}
  186. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  187. function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  188. function FindPart(const HelpWilds, InputStr: string): SizeInt;
  189. function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
  190. function XorString(const Key, Src: ShortString): ShortString;
  191. function XorEncode(const Key, Source: Ansistring): Ansistring;
  192. function XorDecode(const Key, Source: Ansistring): Ansistring;
  193. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  194. function Numb2USA(const S: string): string;
  195. function Hex2Dec(const S: string): Longint;
  196. function Hex2Dec64(const S: string): int64;
  197. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  198. function Numb2Dec(S: string; Base: Byte): Longint;
  199. function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
  200. function IntToBin(Value: Longint; Digits: Integer): string;
  201. function IntToBin(Value: int64; Digits:integer): string;
  202. function IntToRoman(Value: Longint): string;
  203. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  204. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  205. function RomanToIntDef(Const S : String; const ADefault: Longint = 0; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  206. procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer); overload;
  207. procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer); overload;
  208. procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer); overload;
  209. procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  210. procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer); overload;
  211. procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  212. procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer); overload;
  213. function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
  214. function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
  215. function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer; overload;
  216. function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
  217. function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
  218. function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer; overload;
  219. function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer; overload;
  220. function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer; overload;
  221. const
  222. DigitChars = ['0'..'9'];
  223. Brackets = ['(',')','[',']','{','}'];
  224. StdWordDelims = [#0..' ',',','.',';','/','\',':','''','"','`'] + Brackets;
  225. StdSwitchChars = ['-','/'];
  226. function PosSet (const c:TSysCharSet;const s : ansistring ):SizeInt;
  227. function PosSet (const c:string;const s : ansistring ):SizeInt;
  228. function PosSetEx (const c:TSysCharSet;const s : ansistring;count:Integer ):SizeInt;
  229. function PosSetEx (const c:string;const s : ansistring;count:Integer ):SizeInt;
  230. Procedure RemoveLeadingChars(VAR S : AnsiString; Const CSet:TSysCharset);
  231. Procedure RemoveTrailingChars(VAR S : AnsiString;Const CSet:TSysCharset);
  232. Procedure RemoveLeadingChars(VAR S : UnicodeString; Const CSet:TSysCharset);
  233. Procedure RemoveTrailingChars(VAR S : UnicodeString;Const CSet:TSysCharset);
  234. Procedure RemovePadChars(VAR S : AnsiString;Const CSet:TSysCharset);
  235. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  236. Function TrimRightSet(const S: String;const CSet:TSysCharSet): String;
  237. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  238. type
  239. SizeIntArray = array of SizeInt;
  240. Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  241. Function FindMatchesBoyerMooreCaseSensitive(const S,OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  242. Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  243. Function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean) : Boolean;
  244. Type
  245. TStringReplaceAlgorithm = (sraDefault, // Default algoritm as used in StringUtils.
  246. sraManySmall, // Algorithm optimized for many small replacements.
  247. sraBoyerMoore // Algorithm optimized for long replacements.
  248. );
  249. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  250. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  251. { We need these for backwards compatibility:
  252. The compiler will stop searching and convert to ansistring if the widestring version of stringreplace is used.
  253. They currently simply refer to sysutils, till the new mechanisms are proven to work with unicode.}
  254. {$IF SIZEOF(CHAR)=1}
  255. Function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring; overload;
  256. Function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring; overload;
  257. {$ENDIF}
  258. Type
  259. TRawByteStringArray = Array of RawByteString;
  260. TUnicodeStringArray = Array of UnicodeString;
  261. Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
  262. Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
  263. implementation
  264. {$IFDEF FPC_DOTTEDUNITS}
  265. uses System.SysConst; // HexDigits
  266. {$ELSE FPC_DOTTEDUNITS}
  267. uses sysconst; // HexDigits
  268. {$ENDIF FPC_DOTTEDUNITS}
  269. (*
  270. FindMatchesBoyerMooreCaseSensitive
  271. Finds one or many ocurrences of an ansistring in another ansistring.
  272. It is case sensitive.
  273. * Parameters:
  274. S: The PAnsiChar to be searched in. (Read only).
  275. OldPattern: The PAnsiChar to be searched. (Read only).
  276. SSize: The size of S in Chars. (Read only).
  277. OldPatternSize: The size of OldPatter in chars. (Read only).
  278. aMatches: SizeInt array where match indexes are returned (zero based) (write only).
  279. aMatchAll: Finds all matches, not just the first one. (Read only).
  280. * Returns:
  281. Nothing, information returned in aMatches parameter.
  282. The function is based in the Boyer-Moore algorithm.
  283. *)
  284. function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: PAnsiChar;
  285. const SSize, OldPatternSize: SizeInt; out aMatches: SizeIntArray;
  286. const aMatchAll: Boolean) : Boolean;
  287. const
  288. ALPHABET_LENGHT=256;
  289. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  290. var
  291. //Stores the amount of replaces that will take place
  292. MatchesCount: SizeInt;
  293. //Currently allocated space for matches.
  294. MatchesAllocatedLimit: SizeInt;
  295. type
  296. AlphabetArray=array [0..ALPHABET_LENGHT-1] of SizeInt;
  297. function Max(const a1,a2: SizeInt): SizeInt;
  298. begin
  299. if a1>a2 then Result:=a1 else Result:=a2;
  300. end;
  301. procedure MakeDeltaJumpTable1(out DeltaJumpTable1: AlphabetArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  302. var
  303. i: SizeInt;
  304. begin
  305. for i := 0 to ALPHABET_LENGHT-1 do begin
  306. DeltaJumpTable1[i]:=aPatternSize;
  307. end;
  308. //Last AnsiChar do not enter in the equation
  309. for i := 0 to aPatternSize - 1 - 1 do begin
  310. DeltaJumpTable1[Ord(aPattern[i])]:=aPatternSize -1 - i;
  311. end;
  312. end;
  313. function IsPrefix(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): Boolean;
  314. var
  315. i: SizeInt;
  316. SuffixLength: SizeInt;
  317. begin
  318. SuffixLength:=aPatternSize-aPos;
  319. for i := 0 to SuffixLength-1 do begin
  320. if (aPattern[i] <> aPattern[aPos+i]) then begin
  321. exit(false);
  322. end;
  323. end;
  324. Result:=true;
  325. end;
  326. function SuffixLength(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): SizeInt;
  327. var
  328. i: SizeInt;
  329. begin
  330. i:=0;
  331. while (i<aPos) and (aPattern[aPos-i] = aPattern[aPatternSize-1-i]) do begin
  332. inc(i);
  333. end;
  334. Result:=i;
  335. end;
  336. procedure MakeDeltaJumpTable2(var DeltaJumpTable2: SizeIntArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  337. var
  338. Position: SizeInt;
  339. LastPrefixIndex: SizeInt;
  340. SuffixLengthValue: SizeInt;
  341. begin
  342. LastPrefixIndex:=aPatternSize-1;
  343. Position:=aPatternSize-1;
  344. while Position>=0 do begin
  345. if IsPrefix(aPattern,aPatternSize,Position+1) then begin
  346. LastPrefixIndex := Position+1;
  347. end;
  348. DeltaJumpTable2[Position] := LastPrefixIndex + (aPatternSize-1 - Position);
  349. Dec(Position);
  350. end;
  351. Position:=0;
  352. while Position<aPatternSize-1 do begin
  353. SuffixLengthValue:=SuffixLength(aPattern,aPatternSize,Position);
  354. if aPattern[Position-SuffixLengthValue] <> aPattern[aPatternSize-1 - SuffixLengthValue] then begin
  355. DeltaJumpTable2[aPatternSize - 1 - SuffixLengthValue] := aPatternSize - 1 - Position + SuffixLengthValue;
  356. end;
  357. Inc(Position);
  358. end;
  359. end;
  360. //Resizes the allocated space for replacement index
  361. procedure ResizeAllocatedMatches;
  362. begin
  363. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  364. SetLength(aMatches,MatchesAllocatedLimit);
  365. end;
  366. //Add a match to be replaced
  367. procedure AddMatch(const aPosition: SizeInt); inline;
  368. begin
  369. if MatchesCount = MatchesAllocatedLimit then begin
  370. ResizeAllocatedMatches;
  371. end;
  372. aMatches[MatchesCount]:=aPosition;
  373. inc(MatchesCount);
  374. end;
  375. var
  376. i,j: SizeInt;
  377. DeltaJumpTable1: array [0..ALPHABET_LENGHT-1] of SizeInt;
  378. DeltaJumpTable2: SizeIntArray;
  379. begin
  380. MatchesCount:=0;
  381. MatchesAllocatedLimit:=0;
  382. SetLength(aMatches,MatchesCount);
  383. if OldPatternSize=0 then begin
  384. Exit;
  385. end;
  386. SetLength(DeltaJumpTable2,OldPatternSize);
  387. MakeDeltaJumpTable1(DeltaJumpTable1,OldPattern,OldPatternSize);
  388. MakeDeltaJumpTable2(DeltaJumpTable2,OldPattern,OldPatternSize);
  389. i:=OldPatternSize-1;
  390. while i < SSize do begin
  391. j:=OldPatternSize-1;
  392. while (j>=0) and (S[i] = OldPattern[j]) do begin
  393. dec(i);
  394. dec(j);
  395. end;
  396. if (j<0) then begin
  397. AddMatch(i+1);
  398. //Only first match ?
  399. if not aMatchAll then break;
  400. inc(i,DeltaJumpTable2[0]+1);
  401. end else begin
  402. i:=i + Max(DeltaJumpTable1[ord(s[i])],DeltaJumpTable2[j]);
  403. end;
  404. end;
  405. SetLength(aMatches,MatchesCount);
  406. Result:=MatchesCount>0;
  407. end;
  408. function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: PAnsiChar; const SSize, OldPatternSize: SizeInt; out
  409. aMatches: SizeIntArray; const aMatchAll: Boolean): Boolean;
  410. const
  411. ALPHABET_LENGHT=256;
  412. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  413. var
  414. //Lowercased OldPattern
  415. lPattern: string;
  416. //Array of lowercased alphabet
  417. lCaseArray: array [0..ALPHABET_LENGHT-1] of AnsiChar;
  418. //Stores the amount of replaces that will take place
  419. MatchesCount: SizeInt;
  420. //Currently allocated space for matches.
  421. MatchesAllocatedLimit: SizeInt;
  422. type
  423. AlphabetArray=array [0..ALPHABET_LENGHT-1] of SizeInt;
  424. function Max(const a1,a2: SizeInt): SizeInt;
  425. begin
  426. if a1>a2 then Result:=a1 else Result:=a2;
  427. end;
  428. procedure MakeDeltaJumpTable1(out DeltaJumpTable1: AlphabetArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  429. var
  430. i: SizeInt;
  431. begin
  432. for i := 0 to ALPHABET_LENGHT-1 do begin
  433. DeltaJumpTable1[i]:=aPatternSize;
  434. end;
  435. //Last AnsiChar do not enter in the equation
  436. for i := 0 to aPatternSize - 1 - 1 do begin
  437. DeltaJumpTable1[Ord(aPattern[i])]:=aPatternSize - 1 - i;
  438. end;
  439. end;
  440. function IsPrefix(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): Boolean; inline;
  441. var
  442. i: SizeInt;
  443. SuffixLength: SizeInt;
  444. begin
  445. SuffixLength:=aPatternSize-aPos;
  446. for i := 0 to SuffixLength-1 do begin
  447. if (aPattern[i+1] <> aPattern[aPos+i]) then begin
  448. exit(false);
  449. end;
  450. end;
  451. Result:=true;
  452. end;
  453. function SuffixLength(const aPattern: PAnsiChar; const aPatternSize, aPos: SizeInt): SizeInt; inline;
  454. var
  455. i: SizeInt;
  456. begin
  457. i:=0;
  458. while (i<aPos) and (aPattern[aPos-i] = aPattern[aPatternSize-1-i]) do begin
  459. inc(i);
  460. end;
  461. Result:=i;
  462. end;
  463. procedure MakeDeltaJumpTable2(var DeltaJumpTable2: SizeIntArray; const aPattern: PAnsiChar; const aPatternSize: SizeInt);
  464. var
  465. Position: SizeInt;
  466. LastPrefixIndex: SizeInt;
  467. SuffixLengthValue: SizeInt;
  468. begin
  469. LastPrefixIndex:=aPatternSize-1;
  470. Position:=aPatternSize-1;
  471. while Position>=0 do begin
  472. if IsPrefix(aPattern,aPatternSize,Position+1) then begin
  473. LastPrefixIndex := Position+1;
  474. end;
  475. DeltaJumpTable2[Position] := LastPrefixIndex + (aPatternSize-1 - Position);
  476. Dec(Position);
  477. end;
  478. Position:=0;
  479. while Position<aPatternSize-1 do begin
  480. SuffixLengthValue:=SuffixLength(aPattern,aPatternSize,Position);
  481. if aPattern[Position-SuffixLengthValue] <> aPattern[aPatternSize-1 - SuffixLengthValue] then begin
  482. DeltaJumpTable2[aPatternSize - 1 - SuffixLengthValue] := aPatternSize - 1 - Position + SuffixLengthValue;
  483. end;
  484. Inc(Position);
  485. end;
  486. end;
  487. //Resizes the allocated space for replacement index
  488. procedure ResizeAllocatedMatches;
  489. begin
  490. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  491. SetLength(aMatches,MatchesAllocatedLimit);
  492. end;
  493. //Add a match to be replaced
  494. procedure AddMatch(const aPosition: SizeInt); inline;
  495. begin
  496. if MatchesCount = MatchesAllocatedLimit then begin
  497. ResizeAllocatedMatches;
  498. end;
  499. aMatches[MatchesCount]:=aPosition;
  500. inc(MatchesCount);
  501. end;
  502. var
  503. i,j: SizeInt;
  504. DeltaJumpTable1: array [0..ALPHABET_LENGHT-1] of SizeInt;
  505. DeltaJumpTable2: SizeIntArray;
  506. //Pointer to lowered OldPattern
  507. plPattern: PAnsiChar;
  508. begin
  509. MatchesCount:=0;
  510. MatchesAllocatedLimit:=0;
  511. SetLength(aMatches,MatchesCount);
  512. if OldPatternSize=0 then begin
  513. Exit;
  514. end;
  515. //Build an internal array of lowercase version of every possible AnsiChar.
  516. for j := 0 to Pred(ALPHABET_LENGHT) do begin
  517. lCaseArray[j]:=AnsiLowerCase(AnsiChar(j))[1];
  518. end;
  519. //Create the new lowercased pattern
  520. SetLength(lPattern,OldPatternSize);
  521. for j := 0 to Pred(OldPatternSize) do begin
  522. lPattern[j+1]:=lCaseArray[ord(OldPattern[j])];
  523. end;
  524. SetLength(DeltaJumpTable2,OldPatternSize);
  525. MakeDeltaJumpTable1(DeltaJumpTable1,@lPattern[1],OldPatternSize);
  526. MakeDeltaJumpTable2(DeltaJumpTable2,@lPattern[1],OldPatternSize);
  527. plPattern:=@lPattern[1];
  528. i:=OldPatternSize-1;
  529. while i < SSize do begin
  530. j:=OldPatternSize-1;
  531. while (j>=0) and (lCaseArray[Ord(S[i])] = plPattern[j]) do begin
  532. dec(i);
  533. dec(j);
  534. end;
  535. if (j<0) then begin
  536. AddMatch(i+1);
  537. //Only first match ?
  538. if not aMatchAll then break;
  539. inc(i,DeltaJumpTable2[0]+1);
  540. end else begin
  541. i:=i + Max(DeltaJumpTable1[Ord(lCaseArray[Ord(s[i])])],DeltaJumpTable2[j]);
  542. end;
  543. end;
  544. SetLength(aMatches,MatchesCount);
  545. Result:=MatchesCount>0;
  546. end;
  547. function StringReplaceFast(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer): string;
  548. const
  549. MATCHESCOUNTRESIZER=100; //Arbitrary value. Memory used = MATCHESCOUNTRESIZER * sizeof(SizeInt)
  550. var
  551. //Stores where a replace will take place
  552. Matches: array of SizeInt;
  553. //Stores the amount of replaces that will take place
  554. MatchesCount: SizeInt;
  555. //Currently allocated space for matches.
  556. MatchesAllocatedLimit: SizeInt;
  557. //Uppercase version of pattern
  558. PatternUppercase: string;
  559. //Lowercase version of pattern
  560. PatternLowerCase: string;
  561. //Index
  562. MatchIndex: SizeInt;
  563. MatchLimit: SizeInt;
  564. MatchInternal: SizeInt;
  565. MatchTarget: SizeInt;
  566. AdvanceIndex: SizeInt;
  567. //Miscelanous variables
  568. OldPatternSize: SizeInt;
  569. NewPatternSize: SizeInt;
  570. //Resizes the allocated space for replacement index
  571. procedure ResizeAllocatedMatches;
  572. begin
  573. MatchesAllocatedLimit:=MatchesCount+MATCHESCOUNTRESIZER;
  574. SetLength(Matches,MatchesAllocatedLimit);
  575. end;
  576. //Add a match to be replaced
  577. procedure AddMatch(const aPosition: SizeInt); inline;
  578. begin
  579. if MatchesCount = MatchesAllocatedLimit then begin
  580. ResizeAllocatedMatches;
  581. end;
  582. Matches[MatchesCount]:=aPosition;
  583. inc(MatchesCount);
  584. end;
  585. begin
  586. aCount:=0;
  587. if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
  588. //This cases will never match nothing.
  589. Result:=S;
  590. exit;
  591. end;
  592. Result:='';
  593. OldPatternSize:=Length(OldPattern);
  594. MatchesCount:=0;
  595. MatchesAllocatedLimit:=0;
  596. if rfIgnoreCase in Flags then begin
  597. //Different algorithm for case sensitive and insensitive
  598. //This is insensitive, so 2 new ansistrings are created for search pattern, one upper and one lower case.
  599. //It is easy, usually, to create 2 versions of the match pattern than uppercased and lowered case each
  600. //character in the "to be matched" string.
  601. PatternUppercase:=AnsiUpperCase(OldPattern);
  602. PatternLowerCase:=AnsiLowerCase(OldPattern);
  603. MatchIndex:=Length(OldPattern);
  604. MatchLimit:=Length(S);
  605. NewPatternSize:=Length(NewPattern);
  606. while MatchIndex <= MatchLimit do begin
  607. if (S[MatchIndex]=PatternLowerCase[OldPatternSize]) or (S[MatchIndex]=PatternUppercase[OldPatternSize]) then begin
  608. //Match backwards...
  609. MatchInternal:=OldPatternSize-1;
  610. MatchTarget:=MatchIndex-1;
  611. while MatchInternal>=1 do begin
  612. if (S[MatchTarget]=PatternLowerCase[MatchInternal]) or (S[MatchTarget]=PatternUppercase[MatchInternal]) then begin
  613. dec(MatchInternal);
  614. dec(MatchTarget);
  615. end else begin
  616. break;
  617. end;
  618. end;
  619. if MatchInternal=0 then begin
  620. //Match found, all AnsiChar meet the sequence
  621. //MatchTarget points to AnsiChar before, so matching is +1
  622. AddMatch(MatchTarget+1);
  623. inc(MatchIndex,OldPatternSize);
  624. if not (rfReplaceAll in Flags) then begin
  625. break;
  626. end;
  627. end else begin
  628. //Match not found
  629. inc(MatchIndex);
  630. end;
  631. end else begin
  632. inc(MatchIndex);
  633. end;
  634. end;
  635. end else begin
  636. //Different algorithm for case sensitive and insensitive
  637. //This is sensitive, so just 1 binary comprare
  638. MatchIndex:=Length(OldPattern);
  639. MatchLimit:=Length(S);
  640. NewPatternSize:=Length(NewPattern);
  641. while MatchIndex <= MatchLimit do begin
  642. if (S[MatchIndex]=OldPattern[OldPatternSize]) then begin
  643. //Match backwards...
  644. MatchInternal:=OldPatternSize-1;
  645. MatchTarget:=MatchIndex-1;
  646. while MatchInternal>=1 do begin
  647. if (S[MatchTarget]=OldPattern[MatchInternal]) then begin
  648. dec(MatchInternal);
  649. dec(MatchTarget);
  650. end else begin
  651. break;
  652. end;
  653. end;
  654. if MatchInternal=0 then begin
  655. //Match found, all AnsiChar meet the sequence
  656. //MatchTarget points to AnsiChar before, so matching is +1
  657. AddMatch(MatchTarget+1);
  658. inc(MatchIndex,OldPatternSize);
  659. if not (rfReplaceAll in Flags) then begin
  660. break;
  661. end;
  662. end else begin
  663. //Match not found
  664. inc(MatchIndex);
  665. end;
  666. end else begin
  667. inc(MatchIndex);
  668. end;
  669. end;
  670. end;
  671. //Create room enough for the result string
  672. aCount:=MatchesCount;
  673. SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
  674. MatchIndex:=1;
  675. MatchTarget:=1;
  676. //Matches[x] are 1 based offsets
  677. for MatchInternal := 0 to Pred(MatchesCount) do begin
  678. //Copy information up to next match
  679. AdvanceIndex:=Matches[MatchInternal]-MatchIndex;
  680. if AdvanceIndex>0 then begin
  681. move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
  682. inc(MatchTarget,AdvanceIndex);
  683. inc(MatchIndex,AdvanceIndex);
  684. end;
  685. //Copy the new replace information string
  686. if NewPatternSize>0 then begin
  687. move(NewPattern[1],Result[MatchTarget],NewPatternSize);
  688. inc(MatchTarget,NewPatternSize);
  689. end;
  690. inc(MatchIndex,OldPatternSize);
  691. end;
  692. if MatchTarget<=Length(Result) then begin
  693. //Add remain data at the end of source.
  694. move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
  695. end;
  696. end;
  697. (*
  698. StringReplaceBoyerMoore
  699. Replaces one or many ocurrences of an ansistring in another ansistring by a new one.
  700. It can perform the compare ignoring case (ansi).
  701. * Parameters (Read only):
  702. S: The string to be searched in.
  703. OldPattern: The string to be searched.
  704. NewPattern: The string to replace OldPattern matches.
  705. Flags:
  706. rfReplaceAll: Replace all occurrences.
  707. rfIgnoreCase: Ignore case in OldPattern matching.
  708. * Returns:
  709. The modified string (if needed).
  710. It is memory conservative, just sizeof(SizeInt) per match in blocks off 100 matches
  711. plus Length(OldPattern)*2 in the case of ignoring case.
  712. Memory copies are the minimun necessary.
  713. Algorithm based in the Boyer-Moore string search algorithm.
  714. It is faster when the "S" string is very long and the OldPattern is also
  715. very big. As much big the OldPattern is, faster the search is too.
  716. It uses 2 different helper versions of Boyer-Moore algorithm, one for case
  717. sensitive and one for case INsensitive for speed reasons.
  718. *)
  719. function StringReplaceBoyerMoore(const S, OldPattern, NewPattern: string;Flags: TReplaceFlags; out aCount : Integer): string;
  720. var
  721. Matches: SizeIntArray;
  722. OldPatternSize: SizeInt;
  723. NewPatternSize: SizeInt;
  724. MatchesCount: SizeInt;
  725. MatchIndex: SizeInt;
  726. MatchTarget: SizeInt;
  727. MatchInternal: SizeInt;
  728. AdvanceIndex: SizeInt;
  729. begin
  730. aCount:=0;
  731. OldPatternSize:=Length(OldPattern);
  732. NewPatternSize:=Length(NewPattern);
  733. if (OldPattern='') or (Length(OldPattern)>Length(S)) then begin
  734. Result:=S;
  735. exit;
  736. end;
  737. if rfIgnoreCase in Flags then begin
  738. FindMatchesBoyerMooreCaseINSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
  739. end else begin
  740. FindMatchesBoyerMooreCaseSensitive(@s[1],@OldPattern[1],Length(S),Length(OldPattern),Matches, rfReplaceAll in Flags);
  741. end;
  742. MatchesCount:=Length(Matches);
  743. aCount:=MatchesCount;
  744. //Create room enougth for the result string
  745. SetLength(Result,Length(S)-OldPatternSize*MatchesCount+NewPatternSize*MatchesCount);
  746. MatchIndex:=1;
  747. MatchTarget:=1;
  748. //Matches[x] are 0 based offsets
  749. for MatchInternal := 0 to Pred(MatchesCount) do begin
  750. //Copy information up to next match
  751. AdvanceIndex:=Matches[MatchInternal]+1-MatchIndex;
  752. if AdvanceIndex>0 then begin
  753. move(S[MatchIndex],Result[MatchTarget],AdvanceIndex);
  754. inc(MatchTarget,AdvanceIndex);
  755. inc(MatchIndex,AdvanceIndex);
  756. end;
  757. //Copy the new replace information string
  758. if NewPatternSize>0 then begin
  759. move(NewPattern[1],Result[MatchTarget],NewPatternSize);
  760. inc(MatchTarget,NewPatternSize);
  761. end;
  762. inc(MatchIndex,OldPatternSize);
  763. end;
  764. if MatchTarget<=Length(Result) then begin
  765. //Add remain data at the end of source.
  766. move(S[MatchIndex],Result[MatchTarget],Length(Result)-MatchTarget+1);
  767. end;
  768. end;
  769. function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; Algorithm: TStringReplaceAlgorithm): string;
  770. Var
  771. C : Integer;
  772. begin
  773. Result:=StringReplace(S, OldPattern, NewPattern, Flags,C,Algorithm);
  774. end;
  775. Function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags; out aCount : Integer; Algorithm : TStringReplaceAlgorithm = sraDefault): string; overload;
  776. begin
  777. Case Algorithm of
  778. sraDefault : Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags,aCount);
  779. sraManySmall : Result:=StringReplaceFast(S,OldPattern,NewPattern,Flags,aCount);
  780. sraBoyerMoore : Result:=StringReplaceBoyerMoore(S,OldPattern,NewPattern,Flags,aCount);
  781. end;
  782. end;
  783. {$IF SIZEOF(CHAR)=1}
  784. function StringReplace(const S, OldPattern, NewPattern: unicodestring; Flags: TReplaceFlags): unicodestring;
  785. begin
  786. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags);
  787. end;
  788. function StringReplace(const S, OldPattern, NewPattern: widestring; Flags: TReplaceFlags): widestring;
  789. begin
  790. Result:={$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SysUtils.StringReplace(S,OldPattern,NewPattern,Flags);
  791. end;
  792. {$ENDIF}
  793. function FindMatchesBoyerMooreCaseSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
  794. ): Boolean;
  795. Var
  796. I : SizeInt;
  797. begin
  798. Result:=FindMatchesBoyerMooreCaseSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
  799. For I:=0 to pred(Length(AMatches)) do
  800. Inc(AMatches[i]);
  801. end;
  802. function FindMatchesBoyerMooreCaseInSensitive(const S, OldPattern: String; out aMatches: SizeIntArray; const aMatchAll: Boolean
  803. ): Boolean;
  804. Var
  805. I : SizeInt;
  806. begin
  807. Result:=FindMatchesBoyerMooreCaseInSensitive(PAnsiChar(S),PAnsiChar(OldPattern),Length(S),Length(OldPattern),aMatches,aMatchAll);
  808. For I:=0 to pred(Length(AMatches)) do
  809. Inc(AMatches[i]);
  810. end;
  811. { ---------------------------------------------------------------------
  812. Possibly Exception raising functions
  813. ---------------------------------------------------------------------}
  814. function Hex2Dec(const S: string): Longint;
  815. var
  816. HexStr: string;
  817. begin
  818. if Pos('$',S)=0 then
  819. HexStr:='$'+ S
  820. else
  821. HexStr:=S;
  822. Result:=StrToInt(HexStr);
  823. end;
  824. function Hex2Dec64(const S: string): int64;
  825. var
  826. HexStr: string;
  827. begin
  828. if Pos('$',S)=0 then
  829. HexStr:='$'+ S
  830. else
  831. HexStr:=S;
  832. Result:=StrToInt64(HexStr);
  833. end;
  834. {
  835. We turn off implicit exceptions, since these routines are tested, and it
  836. saves 20% codesize (and some speed) and don't throw exceptions, except maybe
  837. heap related. If they don't, that is consider a bug.
  838. In the future, be wary with routines that use strtoint, floating point
  839. and/or format() derivatives. And check every divisor for 0.
  840. }
  841. {$IMPLICITEXCEPTIONS OFF}
  842. { ---------------------------------------------------------------------
  843. Case insensitive search/replace
  844. ---------------------------------------------------------------------}
  845. function AnsiResemblesText(const AText, AOther: AnsiString): Boolean;
  846. begin
  847. if Assigned(AnsiResemblesProc) then
  848. Result:=AnsiResemblesProc(AText,AOther)
  849. else
  850. Result:=False;
  851. end;
  852. function AnsiContainsText(const AText, ASubText: AnsiString): Boolean;
  853. begin
  854. AnsiContainsText:=AnsiPos(AnsiUppercase(ASubText),AnsiUppercase(AText))>0;
  855. end;
  856. function AnsiStartsText(const ASubText, AText: AnsiString): Boolean;
  857. begin
  858. Result := (ASubText = '') or AnsiSameText(LeftStr(AText, Length(ASubText)), ASubText);
  859. end;
  860. function AnsiEndsText(const ASubText, AText: AnsiString): Boolean;
  861. begin
  862. Result := (ASubText = '') or AnsiSameText(RightStr(AText, Length(ASubText)), ASubText);
  863. end;
  864. function AnsiEndsText(const ASubText, AText: UnicodeString): Boolean;
  865. begin
  866. Result := (ASubText = '') or SameText(RightStr(AText, Length(ASubText)), ASubText);
  867. end;
  868. function StartsText(const ASubText, AText: String): Boolean; inline;
  869. begin
  870. Result := AnsiStartsText(ASubText, AText);
  871. end;
  872. function EndsText(const ASubText, AText: string): Boolean;
  873. begin
  874. Result := AnsiEndsText(ASubText, AText);
  875. end;
  876. function ResemblesText(const AText, AOther: string): Boolean;
  877. begin
  878. if Assigned(ResemblesProc) then
  879. Result := ResemblesProc(AText, AOther)
  880. else
  881. Result := False;
  882. end;
  883. function ContainsText(const AText, ASubText: string): Boolean;
  884. begin
  885. Result := AnsiContainsText(AText, ASubText);
  886. end;
  887. function MatchText(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
  888. begin
  889. Result := AnsiMatchText(AText, AValues);
  890. end;
  891. function IndexText(const AText: Ansistring; const AValues: array of Ansistring): Integer;
  892. begin
  893. Result := AnsiIndexText(AText, AValues);
  894. end;
  895. function ContainsStr(const AText, ASubText: String): Boolean;
  896. begin
  897. Result := AnsiContainsStr(AText, ASubText);
  898. end;
  899. function MatchStr(const AText: Ansistring; const AValues: array of Ansistring): Boolean;
  900. begin
  901. Result := AnsiMatchStr(AText, AValues);
  902. end;
  903. function IndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  904. begin
  905. Result := AnsiIndexStr(AText, AValues);
  906. end;
  907. function AnsiReplaceText(const AText, AFromText, AToText: Ansistring): Ansistring;
  908. begin
  909. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll,rfIgnoreCase]);
  910. end;
  911. function AnsiMatchText(const AText: Ansistring; const AValues: array of AnsiString): Boolean;
  912. begin
  913. Result:=(AnsiIndexText(AText,AValues)<>-1)
  914. end;
  915. function AnsiIndexText(const AText: AnsiString; const AValues: array of Ansistring): Integer;
  916. begin
  917. for Result := Low(AValues) to High(AValues) do
  918. if AnsiSameText(AValues[Result], AText) then
  919. Exit;
  920. Result := -1;
  921. end;
  922. { ---------------------------------------------------------------------
  923. Case sensitive search/replace
  924. ---------------------------------------------------------------------}
  925. function AnsiContainsStr(const AText, ASubText: Ansistring): Boolean;
  926. begin
  927. Result := AnsiPos(ASubText,AText)>0;
  928. end;
  929. function AnsiContainsStr(const AText, ASubText: Unicodestring): Boolean;
  930. begin
  931. Result := AnsiPos(ASubText,AText)>0;
  932. end;
  933. function AnsiStartsStr(const ASubText, AText: AnsiString): Boolean;
  934. begin
  935. Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
  936. end;
  937. function AnsiStartsStr(const ASubText, AText: UnicodeString): Boolean;
  938. begin
  939. Result := (ASubText = '') or (LeftStr(AText, Length(ASubText)) = ASubText);
  940. end;
  941. function AnsiEndsStr(const ASubText, AText: AnsiString): Boolean;
  942. begin
  943. Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
  944. end;
  945. function AnsiEndsStr(const ASubText, AText: UnicodeString): Boolean;
  946. begin
  947. Result := (ASubText = '') or (RightStr(AText, Length(ASubText)) = ASubText);
  948. end;
  949. function StartsStr(const ASubText, AText: string): Boolean;
  950. begin
  951. if (Length(AText) >= Length(ASubText)) and (ASubText <> '') then
  952. Result := StrLComp(PChar(ASubText), PChar(AText), Length(ASubText)) = 0
  953. else
  954. Result := (AsubText='');
  955. end;
  956. function EndsStr(const ASubText, AText: string): Boolean;
  957. begin
  958. if Length(AText) >= Length(ASubText) then
  959. Result := StrLComp(PChar(ASubText),
  960. PChar(AText) + Length(AText) - Length(ASubText), Length(ASubText)) = 0
  961. else
  962. Result := False;
  963. end;
  964. function AnsiReplaceStr(const AText, AFromText, AToText: AnsiString): AnsiString;
  965. begin
  966. Result := StringReplace(AText,AFromText,AToText,[rfReplaceAll]);
  967. end;
  968. function AnsiMatchStr(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
  969. begin
  970. Result:=AnsiIndexStr(AText,Avalues)<>-1;
  971. end;
  972. function AnsiIndexStr(const AText: AnsiString; const AValues: array of AnsiString): Integer;
  973. var
  974. i : longint;
  975. begin
  976. result:=-1;
  977. if (high(AValues)=-1) or (High(AValues)>MaxInt) Then
  978. Exit;
  979. for i:=low(AValues) to High(Avalues) do
  980. if (avalues[i]=AText) Then
  981. exit(i); // make sure it is the first val.
  982. end;
  983. function MatchStr(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  984. begin
  985. Result := IndexStr(AText,AValues) <> -1;
  986. end;
  987. function MatchText(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  988. begin
  989. Result := IndexText(AText,AValues) <> -1;
  990. end;
  991. function IndexStr(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  992. var
  993. i: longint;
  994. begin
  995. Result := -1;
  996. if (high(AValues) = -1) or (High(AValues) > MaxInt) Then
  997. Exit;
  998. for i := low(AValues) to High(Avalues) do
  999. if (avalues[i] = AText) Then
  1000. exit(i); // make sure it is the first val.
  1001. end;
  1002. function IndexText(const AText: UnicodeString; const AValues: array of UnicodeString): Integer;
  1003. var
  1004. i : Integer;
  1005. begin
  1006. Result:=-1;
  1007. if (high(AValues)=-1) or (High(AValues)>MaxInt) Then
  1008. Exit;
  1009. for i:=low(AValues) to High(Avalues) do
  1010. if UnicodeCompareText(avalues[i],atext)=0 Then
  1011. exit(i); // make sure it is the first val.
  1012. end;
  1013. operator in(const AText: AnsiString; const AValues: array of AnsiString): Boolean;
  1014. begin
  1015. Result := AnsiIndexStr(AText,AValues) <>-1;
  1016. end;
  1017. operator in(const AText: UnicodeString; const AValues: array of UnicodeString): Boolean;
  1018. begin
  1019. Result := IndexStr(AText,AValues) <> -1;
  1020. end;
  1021. { ---------------------------------------------------------------------
  1022. Playthingies
  1023. ---------------------------------------------------------------------}
  1024. function DupeString(const AText: string; ACount: Integer): string;
  1025. var
  1026. Len, BitIndex, Rp: SizeInt;
  1027. begin
  1028. Len := Length(AText);
  1029. if (Len = 0) or (ACount <= 0) then
  1030. Exit('');
  1031. if ACount = 1 then
  1032. Exit(AText);
  1033. SetLength(Result, ACount * Len);
  1034. Rp := 0;
  1035. // Build up ACount repeats by duplicating the string built so far and adding another AText if corresponding ACount binary digit is 1.
  1036. // For example, ACount = 5 = %101 will, starting from the empty string:
  1037. // (1) duplicate (count = 0), add AText (count = 1)
  1038. // (0) duplicate (count = 2)
  1039. // (1) duplicate (count = 4), add AText (count = 5)
  1040. for BitIndex := BsrDWord(ACount) downto 0 do
  1041. begin
  1042. Move(Pointer(Result)^, PAnsiChar(Pointer(Result))[Rp], Rp * SizeOf(AnsiChar));
  1043. Inc(Rp, Rp);
  1044. if ACount shr BitIndex and 1 <> 0 then
  1045. begin
  1046. Move(Pointer(AText)^, PAnsiChar(Pointer(Result))[Rp], Len * SizeOf(AnsiChar));
  1047. Inc(Rp, Len);
  1048. end;
  1049. end;
  1050. end;
  1051. function ReverseString(const AText: string): string;
  1052. var
  1053. i,j : SizeInt;
  1054. begin
  1055. setlength(result,length(atext));
  1056. i:=1; j:=length(atext);
  1057. while (i<=j) do
  1058. begin
  1059. result[i]:=atext[j-i+1];
  1060. inc(i);
  1061. end;
  1062. end;
  1063. function AnsiReverseString(const AText: AnsiString): AnsiString;
  1064. begin
  1065. Result:=ReverseString(AText);
  1066. end;
  1067. function StuffString(const AText: string; AStart, ALength: Cardinal; const ASubText: string): string;
  1068. var i,j,k : SizeUInt;
  1069. begin
  1070. j:=length(ASubText);
  1071. i:=length(AText);
  1072. if AStart>i then
  1073. aStart:=i+1;
  1074. k:=i+1-AStart;
  1075. if ALength> k then
  1076. ALength:=k;
  1077. SetLength(Result,i+j-ALength);
  1078. move (AText[1],result[1],AStart-1);
  1079. move (ASubText[1],result[AStart],j);
  1080. move (AText[AStart+ALength], Result[AStart+j],i+1-AStart-ALength);
  1081. end;
  1082. function RandomFrom(const AValues: array of string): string;
  1083. begin
  1084. if high(AValues)=-1 then exit('');
  1085. result:=Avalues[random(High(AValues)+1)];
  1086. end;
  1087. function IfThen(AValue: Boolean; const ATrue: string; const AFalse: string): string;
  1088. begin
  1089. if avalue then
  1090. result:=atrue
  1091. else
  1092. result:=afalse;
  1093. end;
  1094. Function IfThen(AValue: Boolean; const ATrue: TStringDynArray; const AFalse: TStringDynArray = nil): TStringDynArray; overload;
  1095. begin
  1096. if avalue then
  1097. result:=atrue
  1098. else
  1099. result:=afalse;
  1100. end;
  1101. function NaturalCompareText(const Str1, Str2: string; const ADecSeparator, AThousandSeparator: AnsiChar): Integer;
  1102. {
  1103. NaturalCompareBase compares strings in a collated order and
  1104. so numbers are sorted too. It sorts like this:
  1105. 01
  1106. 001
  1107. 0001
  1108. and
  1109. 0
  1110. 00
  1111. 000
  1112. 000_A
  1113. 000_B
  1114. in a intuitive order.
  1115. }
  1116. var
  1117. Num1, Num2: double;
  1118. pStr1, pStr2: PAnsiChar;
  1119. Len1, Len2: SizeInt;
  1120. TextLen1, TextLen2: SizeInt;
  1121. TextStr1: string = '';
  1122. TextStr2: string = '';
  1123. i: SizeInt;
  1124. j: SizeInt;
  1125. function Sign(const AValue: sizeint): integer;inline;
  1126. begin
  1127. If Avalue<0 then
  1128. Result:=-1
  1129. else If Avalue>0 then
  1130. Result:=1
  1131. else
  1132. Result:=0;
  1133. end;
  1134. function IsNumber(ch: AnsiChar): boolean;
  1135. begin
  1136. Result := ch in ['0'..'9'];
  1137. end;
  1138. function GetInteger(var pch: PAnsiChar; var Len: sizeint): double;
  1139. begin
  1140. Result := 0;
  1141. while (pch^ <> #0) and IsNumber(pch^) do
  1142. begin
  1143. Result := Result * 10 + Ord(pch^) - Ord('0');
  1144. Inc(Len);
  1145. Inc(pch);
  1146. end;
  1147. end;
  1148. procedure GetChars;
  1149. begin
  1150. TextLen1 := 0;
  1151. while not ((pStr1 + TextLen1)^ in ['0'..'9']) and ((pStr1 + TextLen1)^ <> #0) do
  1152. Inc(TextLen1);
  1153. SetLength(TextStr1, TextLen1);
  1154. i := 1;
  1155. j := 0;
  1156. while i <= TextLen1 do
  1157. begin
  1158. TextStr1[i] := (pStr1 + j)^;
  1159. Inc(i);
  1160. Inc(j);
  1161. end;
  1162. TextLen2 := 0;
  1163. while not ((pStr2 + TextLen2)^ in ['0'..'9']) and ((pStr2 + TextLen2)^ <> #0) do
  1164. Inc(TextLen2);
  1165. SetLength(TextStr2, TextLen2);
  1166. i := 1;
  1167. j := 0;
  1168. while i <= TextLen2 do
  1169. begin
  1170. TextStr2[i] := (pStr2 + j)^;
  1171. Inc(i);
  1172. Inc(j);
  1173. end;
  1174. end;
  1175. begin
  1176. if (Str1 <> '') and (Str2 <> '') then
  1177. begin
  1178. pStr1 := PAnsiChar(Str1);
  1179. pStr2 := PAnsiChar(Str2);
  1180. Result := 0;
  1181. while not ((pStr1^ = #0) or (pStr2^ = #0)) do
  1182. begin
  1183. TextLen1 := 1;
  1184. TextLen2 := 1;
  1185. Len1 := 0;
  1186. Len2 := 0;
  1187. while (pStr1^ = ' ') do
  1188. begin
  1189. Inc(pStr1);
  1190. Inc(Len1);
  1191. end;
  1192. while (pStr2^ = ' ') do
  1193. begin
  1194. Inc(pStr2);
  1195. Inc(Len2);
  1196. end;
  1197. if IsNumber(pStr1^) and IsNumber(pStr2^) then
  1198. begin
  1199. Num1 := GetInteger(pStr1, Len1);
  1200. Num2 := GetInteger(pStr2, Len2);
  1201. if Num1 < Num2 then
  1202. Result := -1
  1203. else if Num1 > Num2 then
  1204. Result := 1
  1205. else
  1206. begin
  1207. Result := Sign(Len1 - Len2);
  1208. end;
  1209. Dec(pStr1);
  1210. Dec(pStr2);
  1211. end
  1212. else
  1213. begin
  1214. GetChars;
  1215. if TextStr1 <> TextStr2 then
  1216. Result := WideCompareText(UTF8Decode(TextStr1), UTF8Decode(TextStr2))
  1217. else
  1218. Result := 0;
  1219. end;
  1220. if Result <> 0 then
  1221. Break;
  1222. Inc(pStr1, TextLen1);
  1223. Inc(pStr2, TextLen2);
  1224. end;
  1225. end;
  1226. Num1 := Length(Str1);
  1227. Num2 := Length(Str2);
  1228. if (Result = 0) and (Num1 <> Num2) then
  1229. begin
  1230. if Num1 < Num2 then
  1231. Result := -1
  1232. else
  1233. Result := 1;
  1234. end;
  1235. end;
  1236. function SplitString(const S, Delimiters: string): TRTLStringDynArray;
  1237. Var
  1238. a : Array of Char;
  1239. I : Integer;
  1240. begin
  1241. SetLength(A,Length(Delimiters));
  1242. For I:=1 to Length(Delimiters) do
  1243. A[I-1]:=Delimiters[i];
  1244. Result := S.Split(A);
  1245. end;
  1246. function NaturalCompareText (const S1 , S2 : string ): Integer ;
  1247. begin
  1248. Result := NaturalCompareText(S1, S2,
  1249. DefaultFormatSettings.DecimalSeparator,
  1250. DefaultFormatSettings.ThousandSeparator);
  1251. end;
  1252. { ---------------------------------------------------------------------
  1253. VB emulations.
  1254. ---------------------------------------------------------------------}
  1255. function LeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1256. begin
  1257. Result:=Copy(AText,1,ACount);
  1258. end;
  1259. function RightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1260. var j,l:SizeInt;
  1261. begin
  1262. l:=length(atext);
  1263. j:=ACount;
  1264. if j>l then j:=l;
  1265. Result:=Copy(AText,l-j+1,j);
  1266. end;
  1267. function MidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
  1268. begin
  1269. if (ACount=0) or (AStart>length(atext)) then
  1270. exit('');
  1271. Result:=Copy(AText,AStart,ACount);
  1272. end;
  1273. function LeftBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
  1274. begin
  1275. Result:=LeftStr(AText,AByteCount);
  1276. end;
  1277. function RightBStr(const AText: AnsiString; const AByteCount: SizeInt): AnsiString;
  1278. begin
  1279. Result:=RightStr(Atext,AByteCount);
  1280. end;
  1281. function MidBStr(const AText: AnsiString; const AByteStart, AByteCount: SizeInt): AnsiString;
  1282. begin
  1283. Result:=MidStr(AText,AByteStart,AByteCount);
  1284. end;
  1285. function AnsiLeftStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1286. begin
  1287. Result := copy(AText,1,ACount);
  1288. end;
  1289. function AnsiRightStr(const AText: AnsiString; const ACount: SizeInt): AnsiString;
  1290. begin
  1291. Result := copy(AText,length(AText)-ACount+1,ACount);
  1292. end;
  1293. function AnsiMidStr(const AText: AnsiString; const AStart, ACount: SizeInt): AnsiString;
  1294. begin
  1295. Result:=Copy(AText,AStart,ACount);
  1296. end;
  1297. function LeftStr(const AText: WideString; const ACount: SizeInt): WideString;
  1298. begin
  1299. Result:=Copy(AText,1,ACount);
  1300. end;
  1301. function RightStr(const AText: WideString; const ACount: SizeInt): WideString;
  1302. var
  1303. j,l:SizeInt;
  1304. begin
  1305. l:=length(atext);
  1306. j:=ACount;
  1307. if j>l then j:=l;
  1308. Result:=Copy(AText,l-j+1,j);
  1309. end;
  1310. function MidStr(const AText: WideString; const AStart, ACount: SizeInt): WideString;
  1311. begin
  1312. Result:=Copy(AText,AStart,ACount);
  1313. end;
  1314. { ---------------------------------------------------------------------
  1315. Extended search and replace
  1316. ---------------------------------------------------------------------}
  1317. type
  1318. TEqualFunction = function (const a,b : AnsiChar) : boolean;
  1319. function EqualWithCase (const a,b : AnsiChar) : boolean;
  1320. begin
  1321. result := (a = b);
  1322. end;
  1323. function EqualWithoutCase (const a,b : AnsiChar) : boolean;
  1324. begin
  1325. result := (lowerCase(a) = lowerCase(b));
  1326. end;
  1327. function IsWholeWord (bufstart, bufend, wordstart, wordend : PAnsiChar) : boolean;
  1328. begin
  1329. // Check start
  1330. result := ((wordstart = bufstart) or ((wordstart-1)^ in worddelimiters)) and
  1331. // Check end
  1332. ((wordend = bufend) or ((wordend+1)^ in worddelimiters));
  1333. end;
  1334. function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string;
  1335. Equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1336. var Found : boolean;
  1337. s, c : PAnsiChar;
  1338. begin
  1339. result := aStart;
  1340. Found := false;
  1341. while not Found and (result <= endchar) do
  1342. begin
  1343. // Search first letter
  1344. while (result <= endchar) and not Equals(result^,SearchString[1]) do
  1345. inc (result);
  1346. // Check if following is searchstring
  1347. c := result;
  1348. s := @(Searchstring[1]);
  1349. Found := true;
  1350. while (c <= endchar) and (s^ <> #0) and Found do
  1351. begin
  1352. Found := Equals(c^, s^);
  1353. inc (c);
  1354. inc (s);
  1355. end;
  1356. if s^ <> #0 then
  1357. Found := false;
  1358. // Check if it is a word
  1359. if Found and WholeWords then
  1360. Found := IsWholeWord(buf,endchar,result,c-1);
  1361. if not found then
  1362. inc (result);
  1363. end;
  1364. if not Found then
  1365. result := nil;
  1366. end;
  1367. function SearchUp(buf,aStart,endchar:PAnsiChar; SearchString:string;
  1368. equals : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1369. var Found : boolean;
  1370. s, c, l : PAnsiChar;
  1371. begin
  1372. result := aStart;
  1373. Found := false;
  1374. l := @(SearchString[length(SearchString)]);
  1375. while not Found and (result >= buf) do
  1376. begin
  1377. // Search last letter
  1378. while (result >= buf) and not Equals(result^,l^) do
  1379. dec (result);
  1380. // Check if before is searchstring
  1381. c := result;
  1382. s := l;
  1383. Found := true;
  1384. while (c >= buf) and (s >= @SearchString[1]) and Found do
  1385. begin
  1386. Found := Equals(c^, s^);
  1387. dec (c);
  1388. dec (s);
  1389. end;
  1390. if (s >= @(SearchString[1])) then
  1391. Found := false;
  1392. // Check if it is a word
  1393. if Found and WholeWords then
  1394. Found := IsWholeWord(buf,endchar,c+1,result);
  1395. if found then
  1396. result := c+1
  1397. else
  1398. dec (result);
  1399. end;
  1400. if not Found then
  1401. result := nil;
  1402. end;
  1403. //function SearchDown(buf,aStart,endchar:PAnsiChar; SearchString:string; equal : TEqualFunction; WholeWords:boolean) : PAnsiChar;
  1404. function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String; Options: TStringSearchOptions
  1405. ): PAnsiChar;
  1406. var
  1407. equal : TEqualFunction;
  1408. begin
  1409. SelStart := SelStart + SelLength;
  1410. if (SearchString = '') or (SelStart > BufLen) or (SelStart < 0) then
  1411. result := nil
  1412. else
  1413. begin
  1414. if soMatchCase in Options then
  1415. Equal := @EqualWithCase
  1416. else
  1417. Equal := @EqualWithoutCase;
  1418. if soDown in Options then
  1419. result := SearchDown(buf,buf+SelStart,Buf+(BufLen-1), SearchString, Equal, (soWholeWord in Options))
  1420. else
  1421. result := SearchUp(buf,buf+SelStart,Buf+(Buflen-1), SearchString, Equal, (soWholeWord in Options));
  1422. end;
  1423. end;
  1424. function SearchBuf(Buf: PAnsiChar; BufLen: SizeInt; SelStart, SelLength: SizeInt; SearchString: String): PAnsiChar; // ; Options: TStringSearchOptions = [soDown]
  1425. begin
  1426. Result:=SearchBuf(Buf,BufLen,SelStart,SelLength,SearchString,[soDown]);
  1427. end;
  1428. function PosEx(const SubStr, S: AnsiString; Offset: SizeInt): SizeInt;
  1429. begin
  1430. Result := Pos(SubStr, S, Offset);
  1431. end;
  1432. function PosEx(c: AnsiChar; const S: Ansistring; Offset: SizeInt): SizeInt;
  1433. begin
  1434. Result := Pos(c, S, Offset);
  1435. end;
  1436. function PosEx(const SubStr, S: Ansistring): SizeInt;
  1437. begin
  1438. Result := Pos(SubStr, S);
  1439. end;
  1440. function PosEx(const SubStr, S: UnicodeString; Offset: SizeInt): SizeInt;
  1441. begin
  1442. Result := Pos(SubStr, S, Offset);
  1443. end;
  1444. function PosEx(c: WideChar; const S: UnicodeString; Offset: SizeInt): SizeInt;
  1445. begin
  1446. Result := Pos(c, S, Offset);
  1447. end;
  1448. function PosEx(const SubStr, S: UnicodeString): Sizeint;
  1449. begin
  1450. Result := Pos(SubStr, S);
  1451. end;
  1452. function StringsReplace(const S: AnsiString; OldPattern, NewPattern: array of AnsiString; Flags: TReplaceFlags): string;
  1453. var pc,pcc,lastpc : PAnsiChar;
  1454. strcount : integer;
  1455. ResStr,
  1456. CompStr : string;
  1457. Found : Boolean;
  1458. sc : sizeint;
  1459. begin
  1460. sc := length(OldPattern);
  1461. if sc <> length(NewPattern) then
  1462. raise exception.Create(SErrAmountStrings);
  1463. dec(sc);
  1464. if rfIgnoreCase in Flags then
  1465. begin
  1466. CompStr:=AnsiUpperCase(S);
  1467. for strcount := 0 to sc do
  1468. OldPattern[strcount] := AnsiUpperCase(OldPattern[strcount]);
  1469. end
  1470. else
  1471. CompStr := s;
  1472. ResStr := '';
  1473. pc := @CompStr[1];
  1474. pcc := @s[1];
  1475. lastpc := pc+Length(S);
  1476. while pc < lastpc do
  1477. begin
  1478. Found := False;
  1479. for strcount := 0 to sc do
  1480. begin
  1481. if (length(OldPattern[strcount])>0) and
  1482. (OldPattern[strcount][1]=pc^) and
  1483. (Length(OldPattern[strcount]) <= (lastpc-pc)) and
  1484. (CompareByte(OldPattern[strcount][1],pc^,Length(OldPattern[strcount]))=0) then
  1485. begin
  1486. ResStr := ResStr + NewPattern[strcount];
  1487. pc := pc+Length(OldPattern[strcount]);
  1488. pcc := pcc+Length(OldPattern[strcount]);
  1489. Found := true;
  1490. end
  1491. end;
  1492. if not found then
  1493. begin
  1494. ResStr := ResStr + pcc^;
  1495. inc(pc);
  1496. inc(pcc);
  1497. end
  1498. else if not (rfReplaceAll in Flags) then
  1499. begin
  1500. ResStr := ResStr + StrPas(pcc);
  1501. break;
  1502. end;
  1503. end;
  1504. Result := ResStr;
  1505. end;
  1506. { ---------------------------------------------------------------------
  1507. Delphi compat
  1508. ---------------------------------------------------------------------}
  1509. function ReplaceStr(const AText, AFromText, AToText: string): string;
  1510. begin
  1511. result:=AnsiReplaceStr(AText, AFromText, AToText);
  1512. end;
  1513. function ReplaceText(const AText, AFromText, AToText: string): string;
  1514. begin
  1515. result:=AnsiReplaceText(AText, AFromText, AToText);
  1516. end;
  1517. { ---------------------------------------------------------------------
  1518. Soundex Functions.
  1519. ---------------------------------------------------------------------}
  1520. Const
  1521. SScore : array[1..255] of AnsiChar =
  1522. ('0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 1..32
  1523. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 33..64
  1524. '0','1','2','3','0','1','2','i','0','2','2','4','5','5','0','1','2','6','2','3','0','1','i','2','i','2', // 65..90
  1525. '0','0','0','0','0','0', // 91..96
  1526. '0','1','2','3','0','1','2','i','0','2','2','4','5','5','0','1','2','6','2','3','0','1','i','2','i','2', // 97..122
  1527. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 123..154
  1528. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 155..186
  1529. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 187..218
  1530. '0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0', // 219..250
  1531. '0','0','0','0','0'); // 251..255
  1532. function Soundex(const AText: string; ALength: TSoundexLength): string;
  1533. Var
  1534. S,PS : AnsiChar;
  1535. I,L : SizeInt;
  1536. begin
  1537. Result:='';
  1538. PS:=#0;
  1539. If Length(AText)>0 then
  1540. begin
  1541. Result:=Upcase(AText[1]);
  1542. I:=2;
  1543. L:=Length(AText);
  1544. While (I<=L) and (Length(Result)<ALength) do
  1545. begin
  1546. S:=SScore[Ord(AText[i])];
  1547. If Not (S in ['0','i',PS]) then
  1548. Result:=Result+S;
  1549. If (S<>'i') then
  1550. PS:=S;
  1551. Inc(I);
  1552. end;
  1553. end;
  1554. L:=Length(Result);
  1555. If (L<ALength) then
  1556. Result:=Result+StringOfChar('0',Alength-L);
  1557. end;
  1558. function Soundex(const AText: string): string; // ; ALength: TSoundexLength = 4
  1559. begin
  1560. Result:=Soundex(AText,4);
  1561. end;
  1562. Const
  1563. Ord0 = Ord('0');
  1564. OrdA = Ord('A');
  1565. function SoundexInt(const AText: string; ALength: TSoundexIntLength): Integer;
  1566. var
  1567. SE: string;
  1568. I: SizeInt;
  1569. begin
  1570. Result:=-1;
  1571. SE:=Soundex(AText,ALength);
  1572. If Length(SE)>0 then
  1573. begin
  1574. Result:=Ord(SE[1])-OrdA;
  1575. if ALength > 1 then
  1576. begin
  1577. Result:=Result*26+(Ord(SE[2])-Ord0);
  1578. for I:=3 to ALength do
  1579. Result:=(Ord(SE[I])-Ord0)+Result*7;
  1580. end;
  1581. Result:=ALength+Result*9;
  1582. end;
  1583. end;
  1584. function SoundexInt(const AText: string): Integer; //; ALength: TSoundexIntLength = 4
  1585. begin
  1586. Result:=SoundexInt(AText,4);
  1587. end;
  1588. function DecodeSoundexInt(AValue: Integer): string;
  1589. var
  1590. I, Len: Integer;
  1591. begin
  1592. Result := '';
  1593. Len := AValue mod 9;
  1594. AValue := AValue div 9;
  1595. for I:=Len downto 3 do
  1596. begin
  1597. Result:=Chr(Ord0+(AValue mod 7))+Result;
  1598. AValue:=AValue div 7;
  1599. end;
  1600. if Len>1 then
  1601. begin
  1602. Result:=Chr(Ord0+(AValue mod 26))+Result;
  1603. AValue:=AValue div 26;
  1604. end;
  1605. Result:=Chr(OrdA+AValue)+Result;
  1606. end;
  1607. function SoundexWord(const AText: string): Word;
  1608. Var
  1609. S : String;
  1610. begin
  1611. S:=SoundEx(Atext,4);
  1612. Result:=Ord(S[1])-OrdA;
  1613. Result:=Result*26+ord(S[2])-48;
  1614. Result:=Result*7+ord(S[3])-48;
  1615. Result:=Result*7+ord(S[4])-48;
  1616. end;
  1617. function DecodeSoundexWord(AValue: Word): string;
  1618. begin
  1619. Result := Chr(Ord0+ (AValue mod 7));
  1620. AValue := AValue div 7;
  1621. Result := Chr(Ord0+ (AValue mod 7)) + Result;
  1622. AValue := AValue div 7;
  1623. Result := IntToStr(AValue mod 26) + Result;
  1624. AValue := AValue div 26;
  1625. Result := Chr(OrdA+AValue) + Result;
  1626. end;
  1627. function SoundexSimilar(const AText, AOther: string; ALength: TSoundexLength): Boolean;
  1628. begin
  1629. Result:=Soundex(AText,ALength)=Soundex(AOther,ALength);
  1630. end;
  1631. function SoundexSimilar(const AText, AOther: string): Boolean; //; ALength: TSoundexLength = 4
  1632. begin
  1633. Result:=SoundexSimilar(AText,AOther,4);
  1634. end;
  1635. function SoundexCompare(const AText, AOther: string; ALength: TSoundexLength): Integer;
  1636. begin
  1637. Result:=AnsiCompareStr(Soundex(AText,ALength),Soundex(AOther,ALength));
  1638. end;
  1639. function SoundexCompare(const AText, AOther: string): Integer; //; ALength: TSoundexLength = 4
  1640. begin
  1641. Result:=SoundexCompare(AText,AOther,4);
  1642. end;
  1643. function SoundexProc(const AText, AOther: string): Boolean;
  1644. begin
  1645. Result:=SoundexSimilar(AText,AOther);
  1646. end;
  1647. { ---------------------------------------------------------------------
  1648. RxStrUtils-like functions.
  1649. ---------------------------------------------------------------------}
  1650. function IsEmptyStr(const S: string; const EmptyChars: TSysCharSet): Boolean;
  1651. var
  1652. i,l: SizeInt;
  1653. begin
  1654. l:=Length(S);
  1655. i:=1;
  1656. Result:=True;
  1657. while Result and (i<=l) do
  1658. begin
  1659. Result:=(S[i] in EmptyChars);
  1660. Inc(i);
  1661. end;
  1662. end;
  1663. function DelSpace(const S: string): string;
  1664. begin
  1665. Result:=DelChars(S,' ');
  1666. end;
  1667. function DelChars(const S: string; Chr: AnsiChar): string;
  1668. var
  1669. I,J: SizeInt;
  1670. begin
  1671. Result:=S;
  1672. I:=Length(Result);
  1673. While I>0 do
  1674. begin
  1675. if Result[I]=Chr then
  1676. begin
  1677. J:=I-1;
  1678. While (J>0) and (Result[J]=Chr) do
  1679. Dec(j);
  1680. Delete(Result,J+1,I-J);
  1681. I:=J+1;
  1682. end;
  1683. dec(I);
  1684. end;
  1685. end;
  1686. function DelChars(const S: string; Chars: TSysCharSet): string;
  1687. var
  1688. I,J: SizeInt;
  1689. begin
  1690. Result:=S;
  1691. if Chars=[] then exit;
  1692. I:=Length(Result);
  1693. While I>0 do
  1694. begin
  1695. if Result[I]in Chars then
  1696. begin
  1697. J:=I-1;
  1698. While (J>0) and (Result[J]in Chars) do
  1699. Dec(j);
  1700. Delete(Result,J+1,I-J);
  1701. I:=J+1;
  1702. end;
  1703. dec(I);
  1704. end;
  1705. end;
  1706. function DelSpace1(const S: string): string;
  1707. var
  1708. I,J: SizeInt;
  1709. begin
  1710. Result:=S;
  1711. I:=Length(Result);
  1712. While I>0 do
  1713. begin
  1714. if Result[I]=#32 then
  1715. begin
  1716. J:=I-1;
  1717. While (J>0) and (Result[J]=#32) do
  1718. Dec(j);
  1719. Inc(J);
  1720. if I<>J then
  1721. begin
  1722. Delete(Result,J+1,I-J);
  1723. I:=J+1;
  1724. end;
  1725. end;
  1726. dec(I);
  1727. end;
  1728. end;
  1729. function Tab2Space(const S: string; Numb: Byte): string;
  1730. var
  1731. I: SizeInt;
  1732. begin
  1733. I:=1;
  1734. Result:=S;
  1735. while I <= Length(Result) do
  1736. if Result[I]<>Chr(9) then
  1737. inc(I)
  1738. else
  1739. begin
  1740. Result[I]:=' ';
  1741. If (Numb>1) then
  1742. Insert(StringOfChar(' ',Numb-1),Result,I);
  1743. Inc(I,Numb);
  1744. end;
  1745. end;
  1746. function NPos(const C: string; S: string; N: Integer): SizeInt;
  1747. var
  1748. i,p,k: SizeInt;
  1749. begin
  1750. Result:=0;
  1751. if N<1 then
  1752. Exit;
  1753. k:=0;
  1754. i:=1;
  1755. Repeat
  1756. p:=pos(C,S);
  1757. Inc(k,p);
  1758. if p>0 then
  1759. delete(S,1,p);
  1760. Inc(i);
  1761. Until (i>n) or (p=0);
  1762. If (P>0) then
  1763. Result:=K;
  1764. end;
  1765. function AddChar(C: AnsiChar; const S: string; N: Integer): string;
  1766. Var
  1767. l : SizeInt;
  1768. begin
  1769. Result:=S;
  1770. l:=Length(Result);
  1771. if l<N then
  1772. Result:=StringOfChar(C,N-l)+Result;
  1773. end;
  1774. function AddCharR(C: AnsiChar; const S: string; N: Integer): string;
  1775. Var
  1776. l : SizeInt;
  1777. begin
  1778. Result:=S;
  1779. l:=Length(Result);
  1780. if l<N then
  1781. Result:=Result+StringOfChar(C,N-l);
  1782. end;
  1783. function PadRight(const S: string; N: Integer): string;inline;
  1784. begin
  1785. Result:=AddCharR(' ',S,N);
  1786. end;
  1787. function PadLeft(const S: string; N: Integer): string;inline;
  1788. begin
  1789. Result:=AddChar(' ',S,N);
  1790. end;
  1791. function Copy2Symb(const S: string; Symb: AnsiChar): string;
  1792. var
  1793. p: SizeInt;
  1794. begin
  1795. p:=Pos(Symb,S);
  1796. if p=0 then
  1797. p:=Length(S)+1;
  1798. Result:=Copy(S,1,p-1);
  1799. end;
  1800. function Copy2SymbDel(var S: string; Symb: AnsiChar): string;
  1801. var
  1802. p: SizeInt;
  1803. begin
  1804. p:=Pos(Symb,S);
  1805. if p=0 then
  1806. begin
  1807. result:=s;
  1808. s:='';
  1809. end
  1810. else
  1811. begin
  1812. Result:=Copy(S,1,p-1);
  1813. delete(s,1,p);
  1814. end;
  1815. end;
  1816. function Copy2Space(const S: string): string;inline;
  1817. begin
  1818. Result:=Copy2Symb(S,' ');
  1819. end;
  1820. function Copy2SpaceDel(var S: string): string;inline;
  1821. begin
  1822. Result:=Copy2SymbDel(S,' ');
  1823. end;
  1824. function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string;
  1825. var
  1826. P,PE : PAnsiChar;
  1827. begin
  1828. Result:=AnsiLowerCase(S);
  1829. P:=PAnsiChar(pointer(Result));
  1830. PE:=P+Length(Result);
  1831. while (P<PE) do
  1832. begin
  1833. while (P<PE) and (P^ in WordDelims) do
  1834. inc(P);
  1835. if (P<PE) then
  1836. P^:=UpCase(P^);
  1837. while (P<PE) and not (P^ in WordDelims) do
  1838. inc(P);
  1839. end;
  1840. end;
  1841. function WordCount(const S: string; const WordDelims: TSysCharSet): SizeInt;
  1842. var
  1843. P,PE : PAnsiChar;
  1844. begin
  1845. Result:=0;
  1846. P:=PAnsiChar(pointer(S));
  1847. PE:=P+Length(S);
  1848. while (P<PE) do
  1849. begin
  1850. while (P<PE) and (P^ in WordDelims) do
  1851. Inc(P);
  1852. if (P<PE) then
  1853. inc(Result);
  1854. while (P<PE) and not (P^ in WordDelims) do
  1855. inc(P);
  1856. end;
  1857. end;
  1858. function WordPosition(const N: Integer; const S: string; const WordDelims: TSysCharSet): SizeInt;
  1859. var
  1860. PS,P,PE : PAnsiChar;
  1861. Count: Integer;
  1862. begin
  1863. Result:=0;
  1864. Count:=0;
  1865. PS:=PAnsiChar(pointer(S));
  1866. PE:=PS+Length(S);
  1867. P:=PS;
  1868. while (P<PE) and (Count<>N) do
  1869. begin
  1870. while (P<PE) and (P^ in WordDelims) do
  1871. inc(P);
  1872. if (P<PE) then
  1873. inc(Count);
  1874. if (Count<>N) then
  1875. while (P<PE) and not (P^ in WordDelims) do
  1876. inc(P)
  1877. else
  1878. Result:=(P-PS)+1;
  1879. end;
  1880. end;
  1881. function ExtractWord(N: Integer; const S: string; const WordDelims: TSysCharSet): string;inline;
  1882. var
  1883. i: SizeInt;
  1884. begin
  1885. Result:=ExtractWordPos(N,S,WordDelims,i);
  1886. end;
  1887. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; out Pos: Integer): string;
  1888. var
  1889. i,j,l: SizeInt;
  1890. begin
  1891. j:=0;
  1892. i:=WordPosition(N, S, WordDelims);
  1893. if (I>High(Integer)) then
  1894. begin
  1895. Result:='';
  1896. Pos:=-1;
  1897. Exit;
  1898. end;
  1899. Pos:=i;
  1900. if (i<>0) then
  1901. begin
  1902. j:=i;
  1903. l:=Length(S);
  1904. while (j<=L) and not (S[j] in WordDelims) do
  1905. inc(j);
  1906. end;
  1907. SetLength(Result,j-i);
  1908. If ((j-i)>0) then
  1909. Move(S[i],Result[1],j-i);
  1910. end;
  1911. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  1912. function ExtractWordPos(N: Integer; const S: string; const WordDelims: TSysCharSet; Out Pos: SizeInt): string;
  1913. var
  1914. i,j,l: SizeInt;
  1915. begin
  1916. j:=0;
  1917. i:=WordPosition(N, S, WordDelims);
  1918. Pos:=i;
  1919. if (i<>0) then
  1920. begin
  1921. j:=i;
  1922. l:=Length(S);
  1923. while (j<=L) and not (S[j] in WordDelims) do
  1924. inc(j);
  1925. end;
  1926. SetLength(Result,j-i);
  1927. If ((j-i)>0) then
  1928. Move(S[i],Result[1],j-i);
  1929. end;
  1930. {$ENDIF}
  1931. function ExtractDelimited(N: Integer; const S: string; const Delims: TSysCharSet): string;
  1932. var
  1933. w,i,l,len: SizeInt;
  1934. begin
  1935. w:=0;
  1936. i:=1;
  1937. l:=0;
  1938. len:=Length(S);
  1939. SetLength(Result, 0);
  1940. while (i<=len) and (w<>N) do
  1941. begin
  1942. if s[i] in Delims then
  1943. inc(w)
  1944. else
  1945. begin
  1946. if (N-1)=w then
  1947. begin
  1948. inc(l);
  1949. SetLength(Result,l);
  1950. Result[L]:=S[i];
  1951. end;
  1952. end;
  1953. inc(i);
  1954. end;
  1955. end;
  1956. {$IF SIZEOF(SIZEINT)<>SIZEOF(INTEGER)}
  1957. function ExtractSubstr(const S: string; var Pos: SizeInt; const Delims: TSysCharSet): string;
  1958. var
  1959. i,l: SizeInt;
  1960. begin
  1961. i:=Pos;
  1962. l:=Length(S);
  1963. while (i<=l) and not (S[i] in Delims) do
  1964. inc(i);
  1965. Result:=Copy(S,Pos,i-Pos);
  1966. while (i<=l) and (S[i] in Delims) do
  1967. inc(i);
  1968. Pos:=i;
  1969. end;
  1970. {$ENDIF}
  1971. function ExtractSubstr(const S: string; var Pos: Integer; const Delims: TSysCharSet): string;
  1972. var
  1973. i,l: SizeInt;
  1974. begin
  1975. i:=Pos;
  1976. l:=Length(S);
  1977. while (i<=l) and not (S[i] in Delims) do
  1978. inc(i);
  1979. Result:=Copy(S,Pos,i-Pos);
  1980. while (i<=l) and (S[i] in Delims) do
  1981. inc(i);
  1982. if I>MaxInt then
  1983. Pos:=MaxInt
  1984. else
  1985. Pos:=i;
  1986. end;
  1987. function IsWordPresent(const W, S: string; const WordDelims: TSysCharSet): Boolean;
  1988. var
  1989. i,Count : SizeInt;
  1990. begin
  1991. Result:=False;
  1992. Count:=WordCount(S, WordDelims);
  1993. I:=1;
  1994. While (Not Result) and (I<=Count) do
  1995. begin
  1996. Result:=ExtractWord(i,S,WordDelims)=W;
  1997. Inc(i);
  1998. end;
  1999. end;
  2000. function Numb2USA(const S: string): string;
  2001. var
  2002. i, NA: Integer;
  2003. begin
  2004. i:=Length(S);
  2005. Result:=S;
  2006. NA:=0;
  2007. while (i > 0) do begin
  2008. if ((Length(Result) - i + 1 - NA) mod 3 = 0) and (i <> 1) then
  2009. begin
  2010. insert(',', Result, i);
  2011. inc(NA);
  2012. end;
  2013. Dec(i);
  2014. end;
  2015. end;
  2016. function PadCenter(const S: string; Len: SizeInt): string;
  2017. begin
  2018. if Length(S)<Len then
  2019. begin
  2020. Result:=StringOfChar(' ',(Len div 2) -(Length(S) div 2))+S;
  2021. Result:=Result+StringOfChar(' ',Len-Length(Result));
  2022. end
  2023. else
  2024. Result:=S;
  2025. end;
  2026. function Dec2Numb(N: Longint; Len, Base: Byte): string;
  2027. var
  2028. C: Integer;
  2029. Number: Longint;
  2030. begin
  2031. if N=0 then
  2032. Result:='0'
  2033. else
  2034. begin
  2035. Number:=N;
  2036. Result:='';
  2037. while Number>0 do
  2038. begin
  2039. C:=Number mod Base;
  2040. if C>9 then
  2041. C:=C+55
  2042. else
  2043. C:=C+48;
  2044. Result:=Chr(C)+Result;
  2045. Number:=Number div Base;
  2046. end;
  2047. end;
  2048. if (Result<>'') then
  2049. Result:=AddChar('0',Result,Len);
  2050. end;
  2051. function Numb2Dec(S: string; Base: Byte): Longint;
  2052. var
  2053. i, P: sizeint;
  2054. begin
  2055. i:=Length(S);
  2056. Result:=0;
  2057. S:=UpperCase(S);
  2058. P:=1;
  2059. while (i>=1) do
  2060. begin
  2061. if (S[i]>'@') then
  2062. Result:=Result+(Ord(S[i])-55)*P
  2063. else
  2064. Result:=Result+(Ord(S[i])-48)*P;
  2065. Dec(i);
  2066. P:=P*Base;
  2067. end;
  2068. end;
  2069. function RomanToIntDontCare(const S: String): Longint;
  2070. {This was the original implementation of RomanToInt,
  2071. it is internally used in TryRomanToInt when Strictness = rcsDontCare}
  2072. const
  2073. RomanChars = ['C','D','I','L','M','V','X'];
  2074. RomanValues : array['C'..'X'] of Word
  2075. = (100,500,0,0,0,0,1,0,0,50,1000,0,0,0,0,0,0,0,0,5,0,10);
  2076. var
  2077. index, Next: AnsiChar;
  2078. i,l: SizeInt;
  2079. Negative: Boolean;
  2080. begin
  2081. Result:=0;
  2082. i:=0;
  2083. Negative:=(Length(S)>0) and (S[1]='-');
  2084. if Negative then
  2085. inc(i);
  2086. l:=Length(S);
  2087. while (i<l) do
  2088. begin
  2089. inc(i);
  2090. index:=UpCase(S[i]);
  2091. if index in RomanChars then
  2092. begin
  2093. if Succ(i)<=l then
  2094. Next:=UpCase(S[i+1])
  2095. else
  2096. Next:=#0;
  2097. if (Next in RomanChars) and (RomanValues[index]<RomanValues[Next]) then
  2098. begin
  2099. inc(Result, RomanValues[Next]);
  2100. Dec(Result, RomanValues[index]);
  2101. inc(i);
  2102. end
  2103. else
  2104. inc(Result, RomanValues[index]);
  2105. end
  2106. else
  2107. begin
  2108. Result:=0;
  2109. Exit;
  2110. end;
  2111. end;
  2112. if Negative then
  2113. Result:=-Result;
  2114. end;
  2115. { TryRomanToInt: try to convert a roman numeral to an integer
  2116. Parameters:
  2117. S: Roman numeral (like: 'MCMXXII')
  2118. N: Integer value of S (only meaningfull if the function succeeds)
  2119. Stricness: controls how strict the parsing of S is
  2120. - rcsStrict:
  2121. * Follow common subtraction rules
  2122. - only 1 preceding subtraction character allowed: IX = 9, but IIX <> 8
  2123. - from M you can only subtract C
  2124. - from D you can only subtract C
  2125. - from C you can only subtract X
  2126. - from L you can only subtract X
  2127. - from X you can only subtract I
  2128. - from V you can only subtract I
  2129. * The numeral is parsed in "groups" (first M's, then D's etc.), the next group to be parsed
  2130. must always be of a lower denomination than the previous one.
  2131. Example: 'MMDCCXX' is allowed but 'MMCCXXDD' is not
  2132. * There can only ever be 3 consecutive M's, C's, X's or I's
  2133. * There can only ever be 1 D, 1 L and 1 V
  2134. * After IX or IV there can be no more characters
  2135. * Negative numbers are not supported
  2136. // As a consequence the maximum allowed Roman numeral is MMMCMXCIX = 3999, also N can never become 0 (zero)
  2137. - rcsRelaxed: Like rcsStrict but with the following exceptions:
  2138. * An infinite number of (leading) M's is allowed
  2139. * Up to 4 consecutive M's, C's, X's and I's are allowed
  2140. // So this is allowed: 'MMMMMMCXIIII' = 6124
  2141. - rcsDontCare:
  2142. * no checking on the order of "groups" is done
  2143. * there are no restrictions on the number of consecutive chars
  2144. * negative numbers are supported
  2145. * an empty string as input will return True and N will be 0
  2146. * invalid input will return false
  2147. // for backwards comatibility: it supports rather ludicrous input like '-IIIMIII' -> -(2+(1000-1)+3)=-1004
  2148. }
  2149. function TryRomanToInt(S: String; out N: LongInt; Strictness: TRomanConversionStrictness = rcsRelaxed): Boolean;
  2150. var
  2151. i, Len: SizeInt;
  2152. Terminated: Boolean;
  2153. begin
  2154. Result := (False);
  2155. S := UpperCase(S); //don't use AnsiUpperCase please
  2156. Len := Length(S);
  2157. if (Strictness = rcsDontCare) then
  2158. begin
  2159. N := RomanToIntDontCare(S);
  2160. if (N = 0) then
  2161. begin
  2162. Result := (Len = 0);
  2163. end
  2164. else
  2165. Result := True;
  2166. Exit;
  2167. end;
  2168. if (Len = 0) then
  2169. begin
  2170. Result:=true;
  2171. N:=0;
  2172. Exit;
  2173. end;
  2174. i := 1;
  2175. N := 0;
  2176. Terminated := False;
  2177. //leading M's
  2178. while (i <= Len) and ((Strictness <> rcsStrict) or (i < 4)) and (S[i] = 'M') do
  2179. begin
  2180. //writeln('TryRomanToInt: Found 1000');
  2181. Inc(i);
  2182. N := N + 1000;
  2183. end;
  2184. //then CM or or CD or D or (C, CC, CCC, CCCC)
  2185. if (i <= Len) and (S[i] = 'D') then
  2186. begin
  2187. //writeln('TryRomanToInt: Found 500');
  2188. Inc(i);
  2189. N := N + 500;
  2190. end
  2191. else if (i + 1 <= Len) and (S[i] = 'C') then
  2192. begin
  2193. if (S[i+1] = 'M') then
  2194. begin
  2195. //writeln('TryRomanToInt: Found 900');
  2196. Inc(i,2);
  2197. N := N + 900;
  2198. end
  2199. else if (S[i+1] = 'D') then
  2200. begin
  2201. //writeln('TryRomanToInt: Found 400');
  2202. Inc(i,2);
  2203. N := N + 400;
  2204. end;
  2205. end ;
  2206. //next max 4 or 3 C's, depending on Strictness
  2207. if (i <= Len) and (S[i] = 'C') then
  2208. begin
  2209. //find max 4 C's
  2210. //writeln('TryRomanToInt: Found 100');
  2211. Inc(i);
  2212. N := N + 100;
  2213. if (i <= Len) and (S[i] = 'C') then
  2214. begin
  2215. //writeln('TryRomanToInt: Found 100');
  2216. Inc(i);
  2217. N := N + 100;
  2218. end;
  2219. if (i <= Len) and (S[i] = 'C') then
  2220. begin
  2221. //writeln('TryRomanToInt: Found 100');
  2222. Inc(i);
  2223. N := N + 100;
  2224. end;
  2225. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'C') then
  2226. begin
  2227. //writeln('TryRomanToInt: Found 100');
  2228. Inc(i);
  2229. N := N + 100;
  2230. end;
  2231. end;
  2232. //then XC or XL
  2233. if (i + 1 <= Len) and (S[i] = 'X') then
  2234. begin
  2235. if (S[i+1] = 'C') then
  2236. begin
  2237. //writeln('TryRomanToInt: Found 90');
  2238. Inc(i,2);
  2239. N := N + 90;
  2240. end
  2241. else if (S[i+1] = 'L') then
  2242. begin
  2243. //writeln('TryRomanToInt: Found 40');
  2244. Inc(i,2);
  2245. N := N + 40;
  2246. end;
  2247. end;
  2248. //then L
  2249. if (i <= Len) and (S[i] = 'L') then
  2250. begin
  2251. //writeln('TryRomanToInt: Found 50');
  2252. Inc(i);
  2253. N := N + 50;
  2254. end;
  2255. //then (X, xx, xxx, xxxx)
  2256. if (i <= Len) and (S[i] = 'X') then
  2257. begin
  2258. //find max 3 or 4 X's, depending on Strictness
  2259. //writeln('TryRomanToInt: Found 10');
  2260. Inc(i);
  2261. N := N + 10;
  2262. if (i <= Len) and (S[i] = 'X') then
  2263. begin
  2264. //writeln('TryRomanToInt: Found 10');
  2265. Inc(i);
  2266. N := N + 10;
  2267. end;
  2268. if (i <= Len) and (S[i] = 'X') then
  2269. begin
  2270. //writeln('TryRomanToInt: Found 10');
  2271. Inc(i);
  2272. N := N + 10;
  2273. end;
  2274. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'X') then
  2275. begin
  2276. //writeln('TryRomanToInt: Found 10');
  2277. Inc(i);
  2278. N := N + 10;
  2279. end;
  2280. end;
  2281. //then IX or IV
  2282. if (i + 1 <= Len) and (S[i] = 'I') then
  2283. begin
  2284. if (S[i+1] = 'X') then
  2285. begin
  2286. Terminated := (True);
  2287. //writeln('TryRomanToInt: Found 9');
  2288. Inc(i,2);
  2289. N := N + 9;
  2290. end
  2291. else if (S[i+1] = 'V') then
  2292. begin
  2293. Terminated := (True);
  2294. //writeln('TryRomanToInt: Found 4');
  2295. Inc(i,2);
  2296. N := N + 4;
  2297. end;
  2298. end;
  2299. //then V
  2300. if (not Terminated) and (i <= Len) and (S[i] = 'V') then
  2301. begin
  2302. //writeln('TryRomanToInt: Found 5');
  2303. Inc(i);
  2304. N := N + 5;
  2305. end;
  2306. //then I
  2307. if (not Terminated) and (i <= Len) and (S[i] = 'I') then
  2308. begin
  2309. Terminated := (True);
  2310. //writeln('TryRomanToInt: Found 1');
  2311. Inc(i);
  2312. N := N + 1;
  2313. //Find max 2 or 3 closing I's, depending on strictness
  2314. if (i <= Len) and (S[i] = 'I') then
  2315. begin
  2316. //writeln('TryRomanToInt: Found 1');
  2317. Inc(i);
  2318. N := N + 1;
  2319. end;
  2320. if (i <= Len) and (S[i] = 'I') then
  2321. begin
  2322. //writeln('TryRomanToInt: Found 1');
  2323. Inc(i);
  2324. N := N + 1;
  2325. end;
  2326. if (Strictness <> rcsStrict) and (i <= Len) and (S[i] = 'I') then
  2327. begin
  2328. //writeln('TryRomanToInt: Found 1');
  2329. Inc(i);
  2330. N := N + 1;
  2331. end;
  2332. end;
  2333. //writeln('TryRomanToInt: Len = ',Len,' i = ',i);
  2334. Result := (i > Len);
  2335. //if Result then writeln('TryRomanToInt: N = ',N);
  2336. end;
  2337. function RomanToInt(const S: string; Strictness: TRomanConversionStrictness = rcsRelaxed): Longint;
  2338. begin
  2339. if not TryRomanToInt(S, Result, Strictness) then
  2340. raise EConvertError.CreateFmt(SInvalidRomanNumeral,[S]);
  2341. end;
  2342. function RomanToIntDef(const S: String; const ADefault: Longint;
  2343. Strictness: TRomanConversionStrictness): Longint;
  2344. begin
  2345. if not TryRomanToInt(S, Result, Strictness) then
  2346. Result := ADefault;
  2347. end;
  2348. function IntToRoman(Value: Longint): string;
  2349. const
  2350. Arabics : Array[1..13] of Integer
  2351. = (1,4,5,9,10,40,50,90,100,400,500,900,1000);
  2352. Romans : Array[1..13] of String
  2353. = ('I','IV','V','IX','X','XL','L','XC','C','CD','D','CM','M');
  2354. var
  2355. i: Integer;
  2356. begin
  2357. Result:='';
  2358. for i:=13 downto 1 do
  2359. while (Value >= Arabics[i]) do
  2360. begin
  2361. Value:=Value-Arabics[i];
  2362. Result:=Result+Romans[i];
  2363. end;
  2364. end;
  2365. function IntToBin(Value: Longint; Digits, Spaces: Integer): string;
  2366. var endpos : integer;
  2367. p,p2:PChar;
  2368. k: integer;
  2369. begin
  2370. Result:='';
  2371. if (Digits>32) then
  2372. Digits:=32;
  2373. if (spaces=0) then
  2374. begin
  2375. result:=inttobin(value,digits);
  2376. exit;
  2377. end;
  2378. endpos:=digits+ (digits-1) div spaces;
  2379. setlength(result,endpos);
  2380. p:=@result[endpos];
  2381. p2:=@result[1];
  2382. k:=spaces;
  2383. while (p>=p2) do
  2384. begin
  2385. if k=0 then
  2386. begin
  2387. p^:=' ';
  2388. dec(p);
  2389. k:=spaces;
  2390. end;
  2391. p^:=chr(48+(cardinal(value) and 1));
  2392. value:=cardinal(value) shr 1;
  2393. dec(p);
  2394. dec(k);
  2395. end;
  2396. end;
  2397. function IntToBin(Value: Longint; Digits: Integer): string;
  2398. var p,p2 : PChar;
  2399. begin
  2400. result:='';
  2401. if digits<=0 then exit;
  2402. setlength(result,digits);
  2403. p:=PChar(pointer(@result[digits]));
  2404. p2:=PChar(pointer(@result[1]));
  2405. // typecasts because we want to keep intto* delphi compat and take an integer
  2406. while (p>=p2) and (cardinal(value)>0) do
  2407. begin
  2408. p^:=chr(48+(cardinal(value) and 1));
  2409. value:=cardinal(value) shr 1;
  2410. dec(p);
  2411. end;
  2412. digits:=p-p2+1;
  2413. if digits>0 then
  2414. fillchar(result[1],digits,#48);
  2415. end;
  2416. function intToBin(Value: int64; Digits:integer): string;
  2417. var p,p2 : PChar;
  2418. begin
  2419. result:='';
  2420. if digits<=0 then exit;
  2421. setlength(result,digits);
  2422. p:=PChar(pointer(@result[digits]));
  2423. p2:=PChar(pointer(@result[1]));
  2424. // typecasts because we want to keep intto* delphi compat and take a signed val
  2425. // and avoid warnings
  2426. while (p>=p2) and (qword(value)>0) do
  2427. begin
  2428. p^:=chr(48+(cardinal(value) and 1));
  2429. value:=qword(value) shr 1;
  2430. dec(p);
  2431. end;
  2432. digits:=p-p2+1;
  2433. if digits>0 then
  2434. fillchar(result[1],digits,#48);
  2435. end;
  2436. function FindPart(const HelpWilds, InputStr: string): SizeInt;
  2437. var
  2438. Diff, i, J: SizeInt;
  2439. begin
  2440. Result:=0;
  2441. i:=Pos('?',HelpWilds);
  2442. if (i=0) then
  2443. Result:=Pos(HelpWilds, inputStr)
  2444. else
  2445. begin
  2446. Diff:=Length(inputStr) - Length(HelpWilds);
  2447. for i:=0 to Diff do
  2448. begin
  2449. for J:=1 to Length(HelpWilds) do
  2450. if (inputStr[i + J] = HelpWilds[J]) or (HelpWilds[J] = '?') then
  2451. begin
  2452. if (J=Length(HelpWilds)) then
  2453. begin
  2454. Result:=i+1;
  2455. Exit;
  2456. end;
  2457. end
  2458. else
  2459. Break;
  2460. end;
  2461. end;
  2462. end;
  2463. Function isMatch(level : integer;inputstr,wilds : string; CWild, CinputWord: SizeInt;MaxInputword,maxwilds : SizeInt; Out EOS : Boolean) : Boolean;
  2464. function WildisQuestionmark : boolean;
  2465. begin
  2466. Result:=CWild <= MaxWilds;
  2467. if Result then
  2468. Result:= Wilds[CWild]='?';
  2469. end;
  2470. function WildisStar : boolean;
  2471. begin
  2472. Result:=CWild <= MaxWilds;
  2473. if Result then
  2474. Result:= Wilds[CWild]='*';
  2475. end;
  2476. begin
  2477. EOS:=False;
  2478. Result:=True;
  2479. repeat
  2480. if WildisStar then { handling of '*' }
  2481. begin
  2482. inc(CWild);
  2483. if CWild>MaxWilds then
  2484. begin
  2485. EOS:=true;
  2486. exit;
  2487. end;
  2488. while WildisQuestionmark do { equal to '?' }
  2489. begin
  2490. { goto next letter }
  2491. inc(CWild);
  2492. inc(CinputWord);
  2493. end;
  2494. { increase until a match }
  2495. Repeat
  2496. while (CinputWord <= MaxinputWord) and (CWild <= MaxWilds) and (inputStr[CinputWord]<>Wilds[CWild]) do
  2497. inc(CinputWord);
  2498. Result:=isMatch(Level+1,inputstr,wilds,CWild, CinputWord,MaxInputword,maxwilds,EOS);
  2499. if not Result then
  2500. Inc(cInputWord);
  2501. Until Result or (CinputWord>=MaxinputWord);
  2502. if Result and EOS then
  2503. Exit;
  2504. Continue;
  2505. end;
  2506. if WildisQuestionmark then { equal to '?' }
  2507. begin
  2508. { goto next letter }
  2509. inc(CWild);
  2510. inc(CinputWord);
  2511. Continue;
  2512. end;
  2513. if (CinputWord>MaxinputWord) or (CWild > MaxWilds) or (inputStr[CinputWord] = Wilds[CWild]) then { equal letters }
  2514. begin
  2515. { goto next letter }
  2516. inc(CWild);
  2517. inc(CinputWord);
  2518. Continue;
  2519. end;
  2520. Result:=false;
  2521. Exit;
  2522. until (CinputWord > MaxinputWord) or (CWild > MaxWilds);
  2523. { no completed evaluation, we need to check what happened }
  2524. if (CinputWord <= MaxinputWord) or (CWild < MaxWilds) then
  2525. Result:=false
  2526. else if (CWild>Maxwilds) then
  2527. EOS:=False
  2528. else
  2529. begin
  2530. EOS:=Wilds[CWild]='*';
  2531. if not EOS then
  2532. Result:=False;
  2533. end
  2534. end;
  2535. function IsWild(InputStr, Wilds: string; IgnoreCase: Boolean): Boolean;
  2536. var
  2537. i: SizeInt;
  2538. MaxinputWord, MaxWilds: SizeInt; { Length of inputStr and Wilds }
  2539. eos : Boolean;
  2540. begin
  2541. Result:=true;
  2542. if Wilds = inputStr then
  2543. Exit;
  2544. { delete '**', because '**' = '*' }
  2545. i:=Pos('**', Wilds);
  2546. while i > 0 do
  2547. begin
  2548. Delete(Wilds, i, 1);
  2549. i:=Pos('**', Wilds);
  2550. end;
  2551. if Wilds = '*' then { for fast end, if Wilds only '*' }
  2552. Exit;
  2553. MaxinputWord:=Length(inputStr);
  2554. MaxWilds:=Length(Wilds);
  2555. if (MaxWilds = 0) or (MaxinputWord = 0) then
  2556. begin
  2557. Result:=false;
  2558. Exit;
  2559. end;
  2560. if ignoreCase then { upcase all letters }
  2561. begin
  2562. inputStr:=AnsiUpperCase(inputStr);
  2563. Wilds:=AnsiUpperCase(Wilds);
  2564. end;
  2565. Result:=isMatch(1,inputStr,wilds,1,1,MaxinputWord, MaxWilds,EOS);
  2566. end;
  2567. function XorString(const Key, Src: ShortString): ShortString;
  2568. var
  2569. i: SizeInt;
  2570. begin
  2571. Result:=Src;
  2572. if Length(Key) > 0 then
  2573. for i:=1 to Length(Src) do
  2574. Result[i]:=Chr(Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Ord(Src[i]));
  2575. end;
  2576. function XorEncode(const Key, Source: Ansistring): Ansistring;
  2577. var
  2578. i: Integer;
  2579. C: Byte;
  2580. begin
  2581. Result:='';
  2582. for i:=1 to Length(Source) do
  2583. begin
  2584. if Length(Key) > 0 then
  2585. C:=Byte(Key[1 + ((i - 1) mod Length(Key))]) xor Byte(Source[i])
  2586. else
  2587. C:=Byte(Source[i]);
  2588. Result:=Result+AnsiLowerCase(intToHex(C, 2));
  2589. end;
  2590. end;
  2591. function XorDecode(const Key, Source: Ansistring): Ansistring;
  2592. var
  2593. i: Integer;
  2594. C: AnsiChar;
  2595. begin
  2596. Result:='';
  2597. for i:=0 to Length(Source) div 2 - 1 do
  2598. begin
  2599. C:=Chr(StrTointDef('$' + Copy(Source, (i * 2) + 1, 2), Ord(' ')));
  2600. if Length(Key) > 0 then
  2601. C:=Chr(Byte(Key[1 + (i mod Length(Key))]) xor Byte(C));
  2602. Result:=Result + C;
  2603. end;
  2604. end;
  2605. function GetCmdLineArg(const Switch: string; SwitchChars: TSysCharSet): string;
  2606. var
  2607. i: Integer;
  2608. S: string;
  2609. begin
  2610. i:=1;
  2611. Result:='';
  2612. while (Result='') and (i<=ParamCount) do
  2613. begin
  2614. S:=ParamStr(i);
  2615. if (SwitchChars=[]) or ((S[1] in SwitchChars) and (Length(S) > 1)) and
  2616. (AnsiCompareText(Copy(S,2,Length(S)-1),Switch)=0) then
  2617. begin
  2618. inc(i);
  2619. if i<=ParamCount then
  2620. Result:=ParamStr(i);
  2621. end;
  2622. inc(i);
  2623. end;
  2624. end;
  2625. function RPosEx(C: AnsiChar; const S: AnsiString; offs: SizeInt): SizeInt;
  2626. var p,p2: PAnsiChar;
  2627. Begin
  2628. If (offs>0) and (offs<=Length(S)) Then
  2629. begin
  2630. p:=@s[offs];
  2631. p2:=@s[1];
  2632. while (p2<=p) and (p^<>c) do dec(p);
  2633. RPosEx:=(p-p2)+1;
  2634. end
  2635. else
  2636. RPosEX:=0;
  2637. End;
  2638. function RPos(c: AnsiChar; const S: AnsiString): SizeInt;
  2639. Begin
  2640. Result:=RPosEx(c,S,Length(S)); { Length(S) must be used because character version returns 0 on offs > length. }
  2641. End;
  2642. function RPos(const Substr: AnsiString; const Source: AnsiString): SizeInt;
  2643. begin
  2644. Result:=RPosEx(Substr,Source,High(Result)); { High(Result) is possible because string version clamps offs > length to offs = length. }
  2645. end;
  2646. function RPosEx(const Substr: AnsiString; const Source: AnsiString; offs: SizeInt): SizeInt;
  2647. var
  2648. MaxLen,llen : SizeInt;
  2649. c : AnsiChar;
  2650. pc,pc2 : PAnsiChar;
  2651. begin
  2652. llen:=Length(SubStr);
  2653. maxlen:=length(source);
  2654. if offs<maxlen then maxlen:=offs;
  2655. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2656. begin
  2657. pc:=@source[maxlen-llen+1];
  2658. pc2:=@source[1];
  2659. c:=substr[1];
  2660. repeat
  2661. if (c=pc^) and
  2662. (CompareChar(Substr[1],pc^,llen)=0) then
  2663. begin
  2664. rPosex:=pc-pc2+1;
  2665. exit;
  2666. end;
  2667. dec(pc);
  2668. until pc<pc2;
  2669. end;
  2670. rPosex:=0;
  2671. end;
  2672. function RPosEx(C: unicodechar; const S: UnicodeString; offs: SizeInt): SizeInt;
  2673. var p,p2: PUnicodeChar;
  2674. Begin
  2675. If (offs>0) and (offs<=Length(S)) Then
  2676. begin
  2677. p:=@s[offs];
  2678. p2:=@s[1];
  2679. while (p2<=p) and (p^<>c) do dec(p);
  2680. RPosEx:=SizeUint(pointer(p)-pointer(p2)) div sizeof(unicodechar)+1; { p-p2+1 but avoids signed division... }
  2681. end
  2682. else
  2683. RPosEX:=0;
  2684. End;
  2685. function RPos(c: Unicodechar; const S: UnicodeString): SizeInt;
  2686. Begin
  2687. Result:=RPosEx(c,S,Length(S)); { Length(S) must be used because character version returns 0 on offs > length. }
  2688. End;
  2689. function RPos(const Substr: UnicodeString; const Source: UnicodeString): SizeInt;
  2690. begin
  2691. Result:=RPosEx(Substr,Source,High(Result)); { High(Result) is possible because string version clamps offs > length to offs = length. }
  2692. end;
  2693. function RPosEx(const Substr: UnicodeString; const Source: UnicodeString; offs: SizeInt): SizeInt;
  2694. var
  2695. MaxLen,llen : SizeInt;
  2696. c : unicodechar;
  2697. pc,pc2 : punicodechar;
  2698. begin
  2699. llen:=Length(SubStr);
  2700. maxlen:=length(source);
  2701. if offs<maxlen then maxlen:=offs;
  2702. if (llen>0) and (maxlen>0) and ( llen<=maxlen) then
  2703. begin
  2704. pc:=@source[maxlen-llen+1];
  2705. pc2:=@source[1];
  2706. c:=substr[1];
  2707. repeat
  2708. if (c=pc^) and
  2709. (Compareword(Substr[1],pc^,llen)=0) then
  2710. begin
  2711. rPosex:=SizeUint(pointer(pc)-pointer(pc2)) div sizeof(unicodechar)+1; { pc-pc2+1 but avoids signed division... }
  2712. exit;
  2713. end;
  2714. dec(pc);
  2715. until pc<pc2;
  2716. end;
  2717. rPosex:=0;
  2718. end;
  2719. procedure BinToHex(BinValue: PAnsiChar; HexValue: PAnsiChar; BinBufSize: Integer);
  2720. var
  2721. i : longint;
  2722. begin
  2723. for i:=0 to BinBufSize-1 do
  2724. begin
  2725. HexValue[0]:=HexDigits[((Ord(BinValue[i]) shr 4))];
  2726. HexValue[1]:=HexDigits[((Ord(BinValue[i]) and 15))];
  2727. Inc(HexValue,2);
  2728. end;
  2729. end;
  2730. procedure BinToHex(BinValue: PAnsiChar; HexValue: PWideChar; BinBufSize: Integer);
  2731. var
  2732. i : longint;
  2733. begin
  2734. for i:=0 to BinBufSize-1 do
  2735. begin
  2736. HexValue[0]:=HexDigitsW[((Ord(BinValue[i]) shr 4))];
  2737. HexValue[1]:=HexDigitsW[((Ord(BinValue[i]) and 15))];
  2738. Inc(HexValue,2);
  2739. end;
  2740. end;
  2741. procedure BinToHex(const BinBuffer: TBytes; BinBufOffset: Integer; var HexBuffer: TBytes; HexBufOffset: Integer; Count: Integer);
  2742. var
  2743. i : longint;
  2744. begin
  2745. for i:=0 to Count-1 do
  2746. begin
  2747. HexBuffer[HexBufOffset+2*i+0]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] shr 4)]);
  2748. HexBuffer[HexBufOffset+2*i+1]:=Byte(HexDigits[(BinBuffer[BinBufOffset + i] and 15)]);
  2749. end;
  2750. end;
  2751. procedure BinToHex(BinValue: Pointer; HexValue: PAnsiChar; BinBufSize: Integer);
  2752. begin
  2753. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2754. end;
  2755. procedure BinToHex(BinValue: Pointer; HexValue: PWideChar; BinBufSize: Integer);
  2756. begin
  2757. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2758. end;
  2759. procedure BinToHex(const BinValue; HexValue: PAnsiChar; BinBufSize: Integer);
  2760. begin
  2761. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2762. end;
  2763. procedure BinToHex(const BinValue; HexValue: PWideChar; BinBufSize: Integer);
  2764. begin
  2765. BinToHex(PAnsiChar(BinValue), HexValue, BinBufSize);
  2766. end;
  2767. function HexToBin(const HexText: PWideChar; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
  2768. var
  2769. i : Integer;
  2770. PText : PWideChar;
  2771. PBinBuf : PAnsiChar;
  2772. begin
  2773. PText:=HexText+HexTextOffset;
  2774. PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
  2775. i:=Count;
  2776. Result:=HexToBin(PText, PBinBuf, i);
  2777. end;
  2778. function HexToBin(const HexText: TBytes; HexTextOffset: Integer; var BinBuffer: TBytes; BinBufOffset: Integer; Count: Integer): Integer;
  2779. var
  2780. i : Integer;
  2781. PText : PAnsiChar;
  2782. PBinBuf : PAnsiChar;
  2783. begin
  2784. PText:=PAnsiChar(HexText)+HexTextOffset;
  2785. PBinBuf:=PAnsiChar(BinBuffer)+BinBufOffset;
  2786. i:=Count;
  2787. Result:=HexToBin(PText, PBinBuf, i);
  2788. end;
  2789. function HexToBin(HexText: PWideChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
  2790. begin
  2791. Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
  2792. end;
  2793. function HexToBin(const HexText: PWideChar; var BinBuffer; BinBufSize: Integer): Integer;
  2794. begin
  2795. Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
  2796. end;
  2797. function HexToBin(HexText: PAnsiChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
  2798. const
  2799. LookUpTable1 : array ['0' .. '9'] of UInt8 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  2800. LookUpTable2 : array ['a' .. 'f'] of UInt8 = (10, 11, 12, 13, 14, 15);
  2801. LookUpTable3 : array ['A' .. 'F'] of UInt8 = (10, 11, 12, 13, 14, 15);
  2802. var
  2803. i : integer;
  2804. num1,num2 : UInt8;
  2805. res : UInt8;
  2806. begin
  2807. i:=BinBufSize;
  2808. while (i>0) do
  2809. begin
  2810. // get value of first character (1-byte)
  2811. case HexText^ of
  2812. '0'..'9':
  2813. num1:=LookUpTable1[HexText^];
  2814. 'a'..'f':
  2815. num1:=LookUpTable2[HexText^];
  2816. 'A'..'F':
  2817. num1:=LookUpTable3[HexText^];
  2818. else
  2819. break;
  2820. end;
  2821. inc(HexText);
  2822. // get value of second character (1-byte)
  2823. case HexText^ of
  2824. '0'..'9':
  2825. num2:=LookUpTable1[HexText^];
  2826. 'a'..'f':
  2827. num2:=LookUpTable2[HexText^];
  2828. 'A'..'F':
  2829. num2:=LookUpTable3[HexText^];
  2830. else
  2831. break;
  2832. end;
  2833. // map two byte values into one byte
  2834. res:=num2+(num1 shl 4);
  2835. BinBuffer^:=AnsiChar(res);
  2836. inc(BinBuffer);
  2837. inc(HexText);
  2838. dec(i);
  2839. end;
  2840. Result:=BinBufSize-i;
  2841. end;
  2842. function HexToBin(HexText: PWideChar; BinBuffer: PAnsiChar; BinBufSize: Integer): Integer;
  2843. const
  2844. LookUpTable1 : array ['0' .. '9'] of UInt8 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
  2845. LookUpTable2 : array ['a' .. 'f'] of UInt8 = (10, 11, 12, 13, 14, 15);
  2846. LookUpTable3 : array ['A' .. 'F'] of UInt8 = (10, 11, 12, 13, 14, 15);
  2847. var
  2848. i : integer;
  2849. num1,num2 : UInt8;
  2850. res : UInt8;
  2851. begin
  2852. i:=BinBufSize;
  2853. while (i>0) do
  2854. begin
  2855. // 2-byte chars could use lower bits for another character
  2856. if (HexText^ > #255) then break;
  2857. // get value of first character (2-byte)
  2858. case HexText^ of
  2859. '0'..'9':
  2860. num1:=LookUpTable1[HexText^];
  2861. 'a'..'f':
  2862. num1:=LookUpTable2[HexText^];
  2863. 'A'..'F':
  2864. num1:=LookUpTable3[HexText^];
  2865. else
  2866. break;
  2867. end;
  2868. inc(HexText);
  2869. // 2-byte chars could use lower bits for another character
  2870. if (HexText^ > #255) then break;
  2871. // get value of second character (2-byte)
  2872. case HexText^ of
  2873. '0'..'9':
  2874. num2:=LookUpTable1[HexText^];
  2875. 'a'..'f':
  2876. num2:=LookUpTable2[HexText^];
  2877. 'A'..'F':
  2878. num2:=LookUpTable3[HexText^];
  2879. else
  2880. break;
  2881. end;
  2882. // map four byte values into one byte
  2883. res:=num2+(num1 shl 4);
  2884. BinBuffer^:=AnsiChar(res);
  2885. inc(BinBuffer);
  2886. inc(HexText);
  2887. dec(i);
  2888. end;
  2889. Result:=BinBufSize-i;
  2890. end;
  2891. function HexToBin(HexText: PAnsiChar; var BinBuffer; BinBufSize: Integer): Integer;
  2892. begin
  2893. Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
  2894. end;
  2895. function HexToBin(const HexText: PAnsiChar; BinBuffer: Pointer; BinBufSize: Integer): Integer;
  2896. begin
  2897. Result:=HexToBin(HexText, PAnsiChar(BinBuffer), BinBufSize);
  2898. end;
  2899. function PosSetEx(const c: TSysCharSet; const s: ansistring; count: Integer): SizeInt;
  2900. var i,j:SizeInt;
  2901. begin
  2902. if PAnsiChar(pointer(s))=nil then
  2903. j:=0
  2904. else
  2905. begin
  2906. i:=length(s);
  2907. j:=count;
  2908. if j>i then
  2909. begin
  2910. result:=0;
  2911. exit;
  2912. end;
  2913. while (j<=i) and (not (s[j] in c)) do inc(j);
  2914. if (j>i) then
  2915. j:=0; // not found.
  2916. end;
  2917. result:=j;
  2918. end;
  2919. function PosSet(const c: TSysCharSet; const s: ansistring): SizeInt;
  2920. begin
  2921. result:=possetex(c,s,1);
  2922. end;
  2923. function PosSetEx(const c: string; const s: ansistring; count: Integer): SizeInt;
  2924. var cset : TSysCharSet;
  2925. i : SizeInt;
  2926. begin
  2927. cset:=[];
  2928. if length(c)>0 then
  2929. for i:=1 to length(c) do
  2930. include(cset,c[i]);
  2931. result:=possetex(cset,s,count);
  2932. end;
  2933. function PosSet(const c: string; const s: ansistring): SizeInt;
  2934. var cset : TSysCharSet;
  2935. i : SizeInt;
  2936. begin
  2937. cset:=[];
  2938. if length(c)>0 then
  2939. for i:=1 to length(c) do
  2940. include(cset,c[i]);
  2941. result:=possetex(cset,s,1);
  2942. end;
  2943. procedure Removeleadingchars(VAR S: AnsiString; const CSet: TSysCharset);
  2944. VAR I,J : Longint;
  2945. Begin
  2946. I:=Length(S);
  2947. IF (I>0) Then
  2948. Begin
  2949. J:=1;
  2950. While (J<=I) And (S[J] IN CSet) DO
  2951. INC(J);
  2952. IF J>1 Then
  2953. Delete(S,1,J-1);
  2954. End;
  2955. End;
  2956. procedure Removeleadingchars(VAR S: UnicodeString; const CSet: TSysCharset);
  2957. VAR I,J : Longint;
  2958. Begin
  2959. I:=Length(S);
  2960. IF (I>0) Then
  2961. Begin
  2962. J:=1;
  2963. While (J<=I) And (S[J] IN CSet) DO
  2964. INC(J);
  2965. IF J>1 Then
  2966. Delete(S,1,J-1);
  2967. End;
  2968. End;
  2969. function TrimLeftSet(const S: String;const CSet:TSysCharSet): String;
  2970. begin
  2971. result:=s;
  2972. removeleadingchars(result,cset);
  2973. end;
  2974. procedure RemoveTrailingChars(VAR S: AnsiString; const CSet: TSysCharset);
  2975. VAR I,J: LONGINT;
  2976. Begin
  2977. I:=Length(S);
  2978. IF (I>0) Then
  2979. Begin
  2980. J:=I;
  2981. While (j>0) and (S[J] IN CSet) DO DEC(J);
  2982. IF J<>I Then
  2983. SetLength(S,J);
  2984. End;
  2985. End;
  2986. procedure RemoveTrailingChars(VAR S: UnicodeString; const CSet: TSysCharset);
  2987. VAR I,J: LONGINT;
  2988. Begin
  2989. I:=Length(S);
  2990. IF (I>0) Then
  2991. Begin
  2992. J:=I;
  2993. While (j>0) and (S[J] IN CSet) DO DEC(J);
  2994. IF J<>I Then
  2995. SetLength(S,J);
  2996. End;
  2997. End;
  2998. function TrimRightSet(const S: String; const CSet: TSysCharSet): String;
  2999. begin
  3000. result:=s;
  3001. RemoveTrailingchars(result,cset);
  3002. end;
  3003. procedure RemovePadChars(VAR S: AnsiString; const CSet: TSysCharset);
  3004. VAR I,J,K: LONGINT;
  3005. Begin
  3006. I:=Length(S);
  3007. IF (I>0) Then
  3008. Begin
  3009. J:=I;
  3010. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3011. if j=0 Then
  3012. begin
  3013. s:='';
  3014. exit;
  3015. end;
  3016. k:=1;
  3017. While (k<=I) And (S[k] IN CSet) DO
  3018. INC(k);
  3019. IF k>1 Then
  3020. begin
  3021. move(s[k],s[1],j-k+1);
  3022. setlength(s,j-k+1);
  3023. end
  3024. else
  3025. setlength(s,j);
  3026. End;
  3027. End;
  3028. procedure RemovePadChars(VAR S: UnicodeString; const CSet: TSysCharset);
  3029. VAR I,J,K: LONGINT;
  3030. Begin
  3031. I:=Length(S);
  3032. IF (I>0) Then
  3033. Begin
  3034. J:=I;
  3035. While (j>0) and (S[J] IN CSet) DO DEC(J);
  3036. if j=0 Then
  3037. begin
  3038. s:='';
  3039. exit;
  3040. end;
  3041. k:=1;
  3042. While (k<=I) And (S[k] IN CSet) DO
  3043. INC(k);
  3044. IF k>1 Then
  3045. begin
  3046. move(s[k],s[1],j-k+1);
  3047. setlength(s,j-k+1);
  3048. end
  3049. else
  3050. setlength(s,j);
  3051. End;
  3052. End;
  3053. function TrimSet(const S: String;const CSet:TSysCharSet): String;
  3054. begin
  3055. result:=s;
  3056. RemovePadChars(result,cset);
  3057. end;
  3058. Function SplitCommandLine(S : RawByteString) : TRawByteStringArray;
  3059. Function GetNextWord : RawByteString;
  3060. Const
  3061. WhiteSpace = [' ',#9,#10,#13];
  3062. Literals = ['"',''''];
  3063. Var
  3064. Wstart,wend : Integer;
  3065. InLiteral : Boolean;
  3066. LastLiteral : AnsiChar;
  3067. Procedure AppendToResult;
  3068. begin
  3069. Result:=Result+Copy(S,WStart,WEnd-WStart);
  3070. WStart:=Wend+1;
  3071. end;
  3072. begin
  3073. Result:='';
  3074. WStart:=1;
  3075. While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
  3076. Inc(WStart);
  3077. WEnd:=WStart;
  3078. InLiteral:=False;
  3079. LastLiteral:=#0;
  3080. While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
  3081. begin
  3082. if charinset(S[Wend],Literals) then
  3083. If InLiteral then
  3084. begin
  3085. InLiteral:=Not (S[Wend]=LastLiteral);
  3086. if not InLiteral then
  3087. AppendToResult;
  3088. end
  3089. else
  3090. begin
  3091. InLiteral:=True;
  3092. LastLiteral:=S[Wend];
  3093. AppendToResult;
  3094. end;
  3095. inc(wend);
  3096. end;
  3097. AppendToResult;
  3098. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  3099. inc(Wend);
  3100. Delete(S,1,WEnd-1);
  3101. end;
  3102. Var
  3103. W : RawByteString;
  3104. len : Integer;
  3105. begin
  3106. Len:=0;
  3107. Result:=Default(TRawByteStringArray);
  3108. SetLength(Result,(Length(S) div 2)+1);
  3109. While Length(S)>0 do
  3110. begin
  3111. W:=GetNextWord;
  3112. If (W<>'') then
  3113. begin
  3114. Result[Len]:=W;
  3115. Inc(Len);
  3116. end;
  3117. end;
  3118. SetLength(Result,Len);
  3119. end;
  3120. Function SplitCommandLine(S : UnicodeString) : TUnicodeStringArray;
  3121. Function GetNextWord : UnicodeString;
  3122. Const
  3123. WhiteSpace = [' ',#9,#10,#13];
  3124. Literals = ['"',''''];
  3125. Var
  3126. Wstart,wend : Integer;
  3127. InLiteral : Boolean;
  3128. LastLiteral : AnsiChar;
  3129. Procedure AppendToResult;
  3130. begin
  3131. Result:=Result+Copy(S,WStart,WEnd-WStart);
  3132. WStart:=Wend+1;
  3133. end;
  3134. begin
  3135. Result:='';
  3136. WStart:=1;
  3137. While (WStart<=Length(S)) and charinset(S[WStart],WhiteSpace) do
  3138. Inc(WStart);
  3139. WEnd:=WStart;
  3140. InLiteral:=False;
  3141. LastLiteral:=#0;
  3142. While (Wend<=Length(S)) and (Not charinset(S[Wend],WhiteSpace) or InLiteral) do
  3143. begin
  3144. if charinset(S[Wend],Literals) then
  3145. If InLiteral then
  3146. begin
  3147. InLiteral:=Not (S[Wend]=LastLiteral);
  3148. if not InLiteral then
  3149. AppendToResult;
  3150. end
  3151. else
  3152. begin
  3153. InLiteral:=True;
  3154. LastLiteral:=S[Wend];
  3155. AppendToResult;
  3156. end;
  3157. inc(wend);
  3158. end;
  3159. AppendToResult;
  3160. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  3161. inc(Wend);
  3162. Delete(S,1,WEnd-1);
  3163. end;
  3164. Var
  3165. W : UnicodeString;
  3166. len : Integer;
  3167. begin
  3168. Len:=0;
  3169. Result:=Default(TUnicodeStringArray);
  3170. SetLength(Result,(Length(S) div 2)+1);
  3171. While Length(S)>0 do
  3172. begin
  3173. W:=GetNextWord;
  3174. If (W<>'') then
  3175. begin
  3176. Result[Len]:=W;
  3177. Inc(Len);
  3178. end;
  3179. end;
  3180. SetLength(Result,Len);
  3181. end;
  3182. end.