12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562 |
- {**************************************************************************************************}
- { }
- { Project JEDI Code Library (JCL) }
- { }
- { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
- { you may not use this file except in compliance with the License. You may obtain a copy of the }
- { License at http://www.mozilla.org/MPL/ }
- { }
- { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
- { ANY KIND, either express or implied. See the License for the specific language governing rights }
- { and limitations under the License. }
- { }
- { The Original Code is JclSysUtils.pas. }
- { }
- { The Initial Developer of the Original Code is Marcel van Brakel. }
- { Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved. }
- { }
- { Contributors: }
- { Alexander Radchenko, }
- { Andreas Hausladen (ahuser) }
- { Anthony Steele }
- { Bernhard Berger }
- { Heri Bender }
- { Jean-Fabien Connault (cycocrew) }
- { Jens Fudickar }
- { Jeroen Speldekamp }
- { Marcel van Brakel }
- { Peter Friese }
- { Petr Vones (pvones) }
- { Python }
- { Robert Marquardt (marquardt) }
- { Robert R. Marsh }
- { Robert Rossmair (rrossmair) }
- { Rudy Velthuis }
- { Uwe Schuster (uschuster) }
- { Wayne Sherman }
- { }
- {**************************************************************************************************}
- { }
- { Description: Various pointer and class related routines. }
- { }
- {**************************************************************************************************}
- { }
- { Last modified: $Date:: $ }
- { Revision: $Rev:: $ }
- { Author: $Author:: $ }
- { }
- {**************************************************************************************************}
- unit JclSysUtils;
- {$I jcl.inc}
- interface
- uses
- {$IFDEF UNITVERSIONING}
- JclUnitVersioning,
- {$ENDIF UNITVERSIONING}
- {$IFDEF HAS_UNITSCOPE}
- {$IFDEF MSWINDOWS}
- Winapi.Windows,
- {$ENDIF MSWINDOWS}
- System.SysUtils, System.Classes, System.TypInfo, System.SyncObjs,
- {$ELSE ~HAS_UNITSCOPE}
- {$IFDEF MSWINDOWS}
- Windows,
- {$ENDIF MSWINDOWS}
- SysUtils, Classes, TypInfo, SyncObjs,
- {$ENDIF ~HAS_UNITSCOPE}
- JclBase, JclSynch;
- // memory initialization
- // first parameter is "out" to make FPC happy with uninitialized values
- procedure ResetMemory(out P; Size: Longint);
- // Pointer manipulation
- procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
- procedure FreeMemAndNil(var P: Pointer);
- function PCharOrNil(const S: string): PChar;
- function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
- {$IFDEF SUPPORTS_WIDESTRING}
- function PWideCharOrNil(const W: WideString): PWideChar;
- {$ENDIF SUPPORTS_WIDESTRING}
- function SizeOfMem(const APointer: Pointer): Integer;
- function WriteProtectedMemory(BaseAddress, Buffer: Pointer; Size: Cardinal;
- out WrittenBytes: Cardinal): Boolean;
- // Guards
- type
- ISafeGuard = interface
- function ReleaseItem: Pointer;
- function GetItem: Pointer;
- procedure FreeItem;
- property Item: Pointer read GetItem;
- end;
- IMultiSafeGuard = interface (IInterface)
- function AddItem(Item: Pointer): Pointer;
- procedure FreeItem(Index: Integer);
- function GetCount: Integer;
- function GetItem(Index: Integer): Pointer;
- function ReleaseItem(Index: Integer): Pointer;
- property Count: Integer read GetCount;
- property Items[Index: Integer]: Pointer read GetItem;
- end;
- TJclSafeGuard = class(TInterfacedObject, ISafeGuard)
- private
- FItem: Pointer;
- public
- constructor Create(Mem: Pointer);
- destructor Destroy; override;
- { ISafeGuard }
- function ReleaseItem: Pointer;
- function GetItem: Pointer;
- procedure FreeItem; virtual;
- property Item: Pointer read GetItem;
- end;
- TJclObjSafeGuard = class(TJclSafeGuard, ISafeGuard)
- public
- constructor Create(Obj: TObject);
- { ISafeGuard }
- procedure FreeItem; override;
- end;
- TJclMultiSafeGuard = class(TInterfacedObject, IMultiSafeGuard)
- private
- FItems: TList;
- public
- constructor Create;
- destructor Destroy; override;
- { IMultiSafeGuard }
- function AddItem(Item: Pointer): Pointer;
- procedure FreeItem(Index: Integer); virtual;
- function GetCount: Integer;
- function GetItem(Index: Integer): Pointer;
- function ReleaseItem(Index: Integer): Pointer;
- property Count: Integer read GetCount;
- property Items[Index: Integer]: Pointer read GetItem;
- end;
- TJclObjMultiSafeGuard = class(TJclMultiSafeGuard, IMultiSafeGuard)
- public
- { IMultiSafeGuard }
- procedure FreeItem(Index: Integer); override;
- end;
- function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
- function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
- function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
- function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
- function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
- function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
- (*
- {$IFDEF SUPPORTS_GENERICS}
- type
- ISafeGuard<T: class> = interface
- function ReleaseItem: T;
- function GetItem: T;
- procedure FreeItem;
- property Item: T read GetItem;
- end;
- TSafeGuard<T: class> = class(TObject, ISafeGuard<T>)
- private
- FItem: T;
- function ReleaseItem: T;
- function GetItem: T;
- procedure FreeItem;
- constructor Create(Instance: T);
- destructor Destroy; override;
- public
- class function New(Instance: T): ISafeGuard<T>; static;
- end;
- {$ENDIF SUPPORTS_GENERICS}
- *)
- { Shared memory between processes functions }
- // Functions for the shared memory owner
- type
- ESharedMemError = class(EJclError);
- {$IFDEF MSWINDOWS}
- { SharedGetMem return ERROR_ALREADY_EXISTS if the shared memory is already
- allocated, otherwise it returns 0.
- Throws ESharedMemError if the Name is invalid. }
- function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
- { SharedAllocMem calls SharedGetMem and then fills the memory with zero if
- it was not already allocated.
- Throws ESharedMemError if the Name is invalid. }
- function SharedAllocMem(const Name: string; Size: Cardinal;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
- { SharedFreeMem releases the shared memory if it was the last reference. }
- function SharedFreeMem(var P{: Pointer}): Boolean;
- // Functions for the shared memory user
- { SharedOpenMem returns True if the shared memory was already allocated by
- SharedGetMem or SharedAllocMem. Otherwise it returns False.
- Throws ESharedMemError if the Name is invalid. }
- function SharedOpenMem(var P{: Pointer}; const Name: string;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean; overload;
- { SharedOpenMem return nil if the shared memory was not already allocated
- by SharedGetMem or SharedAllocMem.
- Throws ESharedMemError if the Name is invalid. }
- function SharedOpenMem(const Name: string;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer; overload;
- { SharedCloseMem releases the shared memory if it was the last reference. }
- function SharedCloseMem(var P{: Pointer}): Boolean;
- {$ENDIF MSWINDOWS}
- // Binary search
- function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer;
- Nearest: Boolean = False): Integer;
- type
- TUntypedSearchCompare = function(Param: Pointer; ItemIndex: Integer; const Value): Integer;
- function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;
- const Value; Nearest: Boolean = False): Integer;
- // Dynamic array sort and search routines
- type
- TDynArraySortCompare = function (Item1, Item2: Pointer): Integer;
- procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);
- // Usage: SortDynArray(Array, SizeOf(Array[0]), SortFunction);
- function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;
- ValuePtr: Pointer; Nearest: Boolean = False): SizeInt;
- // Usage: SearchDynArray(Array, SizeOf(Array[0]), SortFunction, @SearchedValue);
- { Various compare functions for basic types }
- function DynArrayCompareByte(Item1, Item2: Pointer): Integer;
- function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;
- function DynArrayCompareWord(Item1, Item2: Pointer): Integer;
- function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;
- function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;
- function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;
- function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;
- function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;
- function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;
- function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;
- function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;
- function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;
- function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;
- function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;
- function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;
- function DynArrayCompareString(Item1, Item2: Pointer): Integer;
- function DynArrayCompareText(Item1, Item2: Pointer): Integer;
- // Object lists
- procedure ClearObjectList(List: TList);
- procedure FreeObjectList(var List: TList);
- // Reference memory stream
- type
- TJclReferenceMemoryStream = class(TCustomMemoryStream)
- public
- constructor Create(const Ptr: Pointer; Size: Longint);
- function Write(const Buffer; Count: Longint): Longint; override;
- end;
- // AutoPtr
- type
- IAutoPtr = interface
- { Returns the object as pointer, so it is easier to assign it to a variable }
- function AsPointer: Pointer;
- { Returns the AutoPtr handled object }
- function AsObject: TObject;
- { Releases the object from the AutoPtr. The AutoPtr looses the control over
- the object. }
- function ReleaseObject: TObject;
- end;
- TJclAutoPtr = class(TInterfacedObject, IAutoPtr)
- private
- FValue: TObject;
- public
- constructor Create(AValue: TObject);
- destructor Destroy; override;
- { IAutoPtr }
- function AsPointer: Pointer;
- function AsObject: TObject;
- function ReleaseObject: TObject;
- end;
- function CreateAutoPtr(Value: TObject): IAutoPtr;
- // Replacement for the C ternary conditional operator ? :
- function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer; overload;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload;
- {$IFDEF SUPPORTS_VARIANT}
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;
- {$ENDIF SUPPORTS_VARIANT}
- // Classes information and manipulation
- type
- EJclVMTError = class(EJclError);
- // Virtual Methods
- {$IFNDEF FPC}
- function GetVirtualMethodCount(AClass: TClass): Integer;
- {$ENDIF ~FPC}
- function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
- procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);
- // Dynamic Methods
- type
- TDynamicIndexList = array [0..MaxInt div 16] of Word;
- PDynamicIndexList = ^TDynamicIndexList;
- TDynamicAddressList = array [0..MaxInt div 16] of Pointer;
- PDynamicAddressList = ^TDynamicAddressList;
- function GetDynamicMethodCount(AClass: TClass): Integer;
- function GetDynamicIndexList(AClass: TClass): PDynamicIndexList;
- function GetDynamicAddressList(AClass: TClass): PDynamicAddressList;
- function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean;
- {$IFNDEF FPC}
- function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer;
- {$ENDIF ~FPC}
- { init table methods }
- function GetInitTable(AClass: TClass): PTypeInfo;
- { field table methods }
- type
- PFieldEntry = ^TFieldEntry;
- TFieldEntry = packed record
- OffSet: Integer;
- IDX: Word;
- Name: ShortString;
- end;
- PFieldClassTable = ^TFieldClassTable;
- TFieldClassTable = packed record
- Count: Smallint;
- Classes: array [0..8191] of ^TPersistentClass;
- end;
- PFieldTable = ^TFieldTable;
- TFieldTable = packed record
- EntryCount: Word;
- FieldClassTable: PFieldClassTable;
- FirstEntry: TFieldEntry;
- {Entries: array [1..65534] of TFieldEntry;}
- end;
- function GetFieldTable(AClass: TClass): PFieldTable;
- { method table }
- type
- PMethodEntry = ^TMethodEntry;
- TMethodEntry = packed record
- EntrySize: Word;
- Address: Pointer;
- Name: ShortString;
- end;
- PMethodTable = ^TMethodTable;
- TMethodTable = packed record
- Count: Word;
- FirstEntry: TMethodEntry;
- {Entries: array [1..65534] of TMethodEntry;}
- end;
- function GetMethodTable(AClass: TClass): PMethodTable;
- function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;
- // Function to compare if two methods/event handlers are equal
- function MethodEquals(aMethod1, aMethod2: TMethod): boolean;
- function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;
- // Class Parent
- procedure SetClassParent(AClass: TClass; NewClassParent: TClass);
- function GetClassParent(AClass: TClass): TClass;
- {$IFNDEF FPC}
- function IsClass(Address: Pointer): Boolean;
- function IsObject(Address: Pointer): Boolean;
- {$ENDIF ~FPC}
- function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;
- // Interface information
- function GetImplementorOfInterface(const I: IInterface): TObject;
- // interfaced persistent
- type
- TJclInterfacedPersistent = class(TInterfacedPersistent, IInterface)
- protected
- FOwnerInterface: IInterface;
- FRefCount: Integer;
- public
- procedure AfterConstruction; override;
- { IInterface }
- // function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall;
- function _AddRef: Integer; stdcall;
- function _Release: Integer; stdcall;
- end;
- // Numeric formatting routines
- type
- TDigitCount = 0..255;
- TDigitValue = -1..35; // invalid, '0'..'9', 'A'..'Z'
- TNumericSystemBase = 2..Succ(High(TDigitValue));
- {$IFNDEF WINSCP}
- TJclNumericFormat = class(TObject)
- private
- FWantedPrecision: TDigitCount;
- FPrecision: TDigitCount;
- FNumberOfFractionalDigits: TDigitCount;
- FExpDivision: Integer;
- FDigitBlockSize: TDigitCount;
- FWidth: TDigitCount;
- FSignChars: array [Boolean] of Char;
- FBase: TNumericSystemBase;
- FFractionalPartSeparator: Char;
- FDigitBlockSeparator: Char;
- FShowPositiveSign: Boolean;
- FPaddingChar: Char;
- FMultiplier: string;
- function GetDigitValue(Digit: Char): Integer;
- function GetNegativeSign: Char;
- function GetPositiveSign: Char;
- procedure InvalidDigit(Digit: Char);
- procedure SetPrecision(const Value: TDigitCount);
- procedure SetBase(const Value: TNumericSystemBase);
- procedure SetNegativeSign(const Value: Char);
- procedure SetPositiveSign(const Value: Char);
- procedure SetExpDivision(const Value: Integer);
- protected
- function IntToStr(const Value: Int64; out FirstDigitPos: Integer): string; overload;
- function ShowSign(const Value: Float): Boolean; overload;
- function ShowSign(const Value: Int64): Boolean; overload;
- function SignChar(const Value: Float): Char; overload;
- function SignChar(const Value: Int64): Char; overload;
- property WantedPrecision: TDigitCount read FWantedPrecision;
- public
- constructor Create;
- function Digit(DigitValue: TDigitValue): Char;
- function DigitValue(Digit: Char): TDigitValue;
- function IsDigit(Value: Char): Boolean;
- function Sign(Value: Char): Integer;
- procedure GetMantissaExp(const Value: Float; out Mantissa: string; out Exponent: Integer);
- function FloatToHTML(const Value: Float): string;
- function IntToStr(const Value: Int64): string; overload;
- function FloatToStr(const Value: Float): string; overload;
- function StrToInt(const Value: string): Int64;
- property Base: TNumericSystemBase read FBase write SetBase;
- property Precision: TDigitCount read FPrecision write SetPrecision;
- property NumberOfFractionalDigits: TDigitCount read FNumberOfFractionalDigits write FNumberOfFractionalDigits;
- property ExponentDivision: Integer read FExpDivision write SetExpDivision;
- property DigitBlockSize: TDigitCount read FDigitBlockSize write FDigitBlockSize;
- property DigitBlockSeparator: Char read FDigitBlockSeparator write FDigitBlockSeparator;
- property FractionalPartSeparator: Char read FFractionalPartSeparator write FFractionalPartSeparator;
- property Multiplier: string read FMultiplier write FMultiplier;
- property PaddingChar: Char read FPaddingChar write FPaddingChar;
- property ShowPositiveSign: Boolean read FShowPositiveSign write FShowPositiveSign;
- property Width: TDigitCount read FWidth write FWidth;
- property NegativeSign: Char read GetNegativeSign write SetNegativeSign;
- property PositiveSign: Char read GetPositiveSign write SetPositiveSign;
- end;
- function IntToStrZeroPad(Value, Count: Integer): string;
- // Child processes
- type
- // e.g. TStrings.Append
- TTextHandler = procedure(const Text: string) of object;
- TJclProcessPriority = (ppIdle, ppNormal, ppHigh, ppRealTime, ppBelowNormal, ppAboveNormal);
- const
- ABORT_EXIT_CODE = {$IFDEF MSWINDOWS} ERROR_CANCELLED {$ELSE} 1223 {$ENDIF};
- function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean = False;
- AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
- AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent;
- OutputLineCallback: TTextHandler; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
- AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean = False;
- AbortPtr: PBoolean = nil; ProcessPriority: TJclProcessPriority = ppNormal;
- AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent;
- var Output: string; RawOutput: Boolean = False; ProcessPriority: TJclProcessPriority = ppNormal;
- AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;
- RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
- ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent;
- OutputLineCallback, ErrorLineCallback: TTextHandler; RawOutput: Boolean = False; RawError: Boolean = False;
- ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; var Output, Error: string;
- RawOutput: Boolean = False; RawError: Boolean = False; AbortPtr: PBoolean = nil;
- ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent;
- var Output, Error: string; RawOutput: Boolean = False; RawError: Boolean = False;
- ProcessPriority: TJclProcessPriority = ppNormal; AutoConvertOem: Boolean = False): Cardinal; overload;
- type
- {$IFDEF MSWINDOWS}
- TJclExecuteCmdProcessOptionBeforeResumeEvent = procedure(const ProcessInfo: TProcessInformation) of object;
- TStartupVisibility = (svHide, svShow, svNotSet);
- {$ENDIF MSWINDOWS}
- TJclExecuteCmdProcessOptions = {record} class(TObject)
- private
- FCommandLine: string;
- FAbortPtr: PBoolean;
- FAbortEvent: TJclEvent;
- FOutputLineCallback: TTextHandler;
- FRawOutput: Boolean;
- FMergeError: Boolean;
- FErrorLineCallback: TTextHandler;
- FRawError: Boolean;
- FProcessPriority: TJclProcessPriority;
- FAutoConvertOem: Boolean;
- {$IFDEF MSWINDOWS}
- FCreateProcessFlags: DWORD;
- FStartupVisibility: TStartupVisibility;
- FBeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent;
- {$ENDIF MSWINDOWS}
- FExitCode: Cardinal;
- FOutput: string;
- FError: string;
- public
- // in:
- property CommandLine: string read FCommandLine write FCommandLine;
- property AbortPtr: PBoolean read FAbortPtr write FAbortPtr;
- property AbortEvent: TJclEvent read FAbortEvent write FAbortEvent;
- property OutputLineCallback: TTextHandler read FOutputLineCallback write FOutputLineCallback;
- property RawOutput: Boolean read FRawOutput write FRawOutput default False;
- property MergeError: Boolean read FMergeError write FMergeError default False;
- property ErrorLineCallback: TTextHandler read FErrorLineCallback write FErrorLineCallback;
- property RawError: Boolean read FRawError write FRawError default False;
- property ProcessPriority: TJclProcessPriority read FProcessPriority write FProcessPriority default ppNormal;
- // AutoConvertOem assumes the process outputs OEM encoded strings and converts them to the
- // default string encoding.
- property AutoConvertOem: Boolean read FAutoConvertOem write FAutoConvertOem default True;
- {$IFDEF MSWINDOWS}
- property CreateProcessFlags: DWORD read FCreateProcessFlags write FCreateProcessFlags;
- property StartupVisibility: TStartupVisibility read FStartupVisibility write FStartupVisibility;
- property BeforeResume: TJclExecuteCmdProcessOptionBeforeResumeEvent read FBeforeResume write FBeforeResume;
- {$ENDIF MSWINDOWS}
- // out:
- property ExitCode: Cardinal read FExitCode;
- property Output: string read FOutput;
- property Error: string read FError;
- public
- constructor Create(const ACommandLine: string);
- end;
- function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;
- type
- {$HPPEMIT 'namespace Jclsysutils'}
- {$HPPEMIT '{'}
- {$HPPEMIT ' // For some reason, the generator puts this interface after its first'}
- {$HPPEMIT ' // usage, resulting in an unusable header file. We fix this by forward'}
- {$HPPEMIT ' // declaring the interface.'}
- {$HPPEMIT ' __interface IJclCommandLineTool;'}
- (*$HPPEMIT '}'*)
- IJclCommandLineTool = interface
- ['{A0034B09-A074-D811-847D-0030849E4592}']
- function GetExeName: string;
- function GetOptions: TStrings;
- function GetOutput: string;
- function GetOutputCallback: TTextHandler;
- procedure AddPathOption(const Option, Path: string);
- function Execute(const CommandLine: string): Boolean;
- procedure SetOutputCallback(const CallbackMethod: TTextHandler);
- property ExeName: string read GetExeName;
- property Options: TStrings read GetOptions;
- property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
- property Output: string read GetOutput;
- end;
- EJclCommandLineToolError = class(EJclError);
- TJclCommandLineTool = class(TInterfacedObject, IJclCommandLineTool)
- private
- FExeName: string;
- FOptions: TStringList;
- FOutput: string;
- FOutputCallback: TTextHandler;
- public
- constructor Create(const AExeName: string);
- destructor Destroy; override;
- { IJclCommandLineTool }
- function GetExeName: string;
- function GetOptions: TStrings;
- function GetOutput: string;
- function GetOutputCallback: TTextHandler;
- procedure AddPathOption(const Option, Path: string);
- function Execute(const CommandLine: string): Boolean;
- procedure SetOutputCallback(const CallbackMethod: TTextHandler);
- property ExeName: string read GetExeName;
- property Options: TStrings read GetOptions;
- property OutputCallback: TTextHandler read GetOutputCallback write SetOutputCallback;
- property Output: string read GetOutput;
- end;
- // Console Utilities
- function ReadKey: Char;
- {$ENDIF ~WINSCP}
- // Loading of modules (DLLs)
- type
- {$IFDEF MSWINDOWS}
- TModuleHandle = HINST;
- {$ENDIF MSWINDOWS}
- {$IFDEF LINUX}
- TModuleHandle = Pointer;
- {$ENDIF LINUX}
- const
- INVALID_MODULEHANDLE_VALUE = TModuleHandle(0);
- function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;
- function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;
- procedure UnloadModule(var Module: TModuleHandle);
- function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;
- function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;
- function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
- function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
- // Conversion Utilities
- type
- EJclConversionError = class(EJclError);
- function StrToBoolean(const S: string): Boolean;
- function BooleanToStr(B: Boolean): string;
- function IntToBool(I: Integer): Boolean;
- function BoolToInt(B: Boolean): Integer;
- function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;
- function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;
- function StrToUInt(const Value: string): Cardinal;
- {$IFNDEF WINSCP}
- const
- {$IFDEF MSWINDOWS}
- ListSeparator = ';';
- {$ENDIF MSWINDOWS}
- {$IFDEF LINUX}
- ListSeparator = ':';
- {$ENDIF LINUX}
- {$ENDIF}
- // functions to handle items in a separated list of items
- // add items at the end
- procedure ListAddItems(var List: string; const Separator, Items: string);
- // add items at the end if they are not present
- procedure ListIncludeItems(var List: string; const Separator, Items: string);
- // delete multiple items
- procedure ListRemoveItems(var List: string; const Separator, Items: string);
- // delete one item
- procedure ListDelItem(var List: string; const Separator: string;
- const Index: Integer);
- // return the number of item
- function ListItemCount(const List, Separator: string): Integer;
- // return the Nth item
- function ListGetItem(const List, Separator: string;
- const Index: Integer): string;
- // set the Nth item
- procedure ListSetItem(var List: string; const Separator: string;
- const Index: Integer; const Value: string);
- // return the index of an item
- function ListItemIndex(const List, Separator, Item: string): Integer;
- // RTL package information
- function SystemTObjectInstance: TJclAddr;
- function IsCompiledWithPackages: Boolean;
- // GUID
- function JclGUIDToString(const GUID: TGUID): string;
- function JclStringToGUID(const S: string): TGUID;
- function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;
- // thread safe support
- type
- TJclIntfCriticalSection = class(TInterfacedObject, IInterface)
- private
- FCriticalSection: TCriticalSection;
- public
- constructor Create;
- destructor Destroy; override;
- { IInterface }
- // function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
- function _AddRef: Integer; stdcall;
- function _Release: Integer; stdcall;
- end;
- type
- {$IFDEF BORLAND}
- {$IFDEF COMPILER16_UP}
- TFileHandle = THandle;
- {$ELSE ~COMPILER16_UP}
- TFileHandle = Integer;
- {$ENDIF ~COMPILER16_UP}
- {$ELSE ~BORLAND}
- TFileHandle = THandle;
- {$ENDIF ~BORLAND}
- {$IFNDEF WINSCP}
- TJclSimpleLog = class (TObject)
- private
- FDateTimeFormatStr: String;
- FLogFileHandle: TFileHandle;
- FLogFileName: string;
- FLoggingActive: Boolean;
- FLogWasEmpty: Boolean;
- function GetLogOpen: Boolean;
- protected
- function CreateDefaultFileName: string;
- public
- constructor Create(const ALogFileName: string = '');
- destructor Destroy; override;
- procedure ClearLog;
- procedure CloseLog;
- procedure OpenLog;
- procedure Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
- procedure Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
- //Writes a line to the log file. The current timestamp is written before the line.
- procedure TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
- procedure TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true); overload;
- procedure WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);
- // DateTimeFormatStr property assumes the values described in "FormatDateTime Function" in Delphi Help
- property DateTimeFormatStr: String read FDateTimeFormatStr write FDateTimeFormatStr;
- property LogFileName: string read FLogFileName;
- //1 Property to activate / deactivate the logging
- property LoggingActive: Boolean read FLoggingActive write FLoggingActive default True;
- property LogOpen: Boolean read GetLogOpen;
- end;
- {$ENDIF ~WINSCP}
- type
- TJclFormatSettings = class
- private
- function GetCurrencyDecimals: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetCurrencyFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetCurrencyString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetDateSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetDayNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetDayNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetDecimalSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetListSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetLongDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetLongDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetLongMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetLongTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetMonthNamesHighIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetMonthNamesLowIndex: Integer; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetNegCurrFormat: Byte; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetShortDateFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetShortDayNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetShortMonthNames(AIndex: Integer): string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetShortTimeFormat: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetThousandSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetTimeAMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetTimePMString: string; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetTimeSeparator: Char; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- function GetTwoDigitYearCenturyWindow: Word; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetCurrencyDecimals(AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetCurrencyFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetCurrencyString(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetDateSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetDecimalSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetListSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetLongDateFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetLongTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetNegCurrFormat(const AValue: Byte); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetShortDateFormat(AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetShortTimeFormat(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetThousandSeparator(AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetTimeAMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetTimePMString(const AValue: string); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetTimeSeparator(const AValue: Char); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- procedure SetTwoDigitYearCenturyWindow(const AValue: Word); {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
- public
- property CurrencyDecimals: Byte read GetCurrencyDecimals write SetCurrencyDecimals;
- property CurrencyFormat: Byte read GetCurrencyFormat write SetCurrencyFormat;
- property CurrencyString: string read GetCurrencyString write SetCurrencyString;
- property DateSeparator: Char read GetDateSeparator write SetDateSeparator;
- property DayNamesHighIndex: Integer read GetDayNamesHighIndex;
- property DayNamesLowIndex: Integer read GetDayNamesLowIndex;
- property DecimalSeparator: Char read GetDecimalSeparator write SetDecimalSeparator;
- property ListSeparator: Char read GetListSeparator write SetListSeparator;
- property LongDateFormat: string read GetLongDateFormat write SetLongDateFormat;
- property LongDayNames[AIndex: Integer]: string read GetLongDayNames;
- property LongMonthNames[AIndex: Integer]: string read GetLongMonthNames;
- property LongTimeFormat: string read GetLongTimeFormat write SetLongTimeFormat;
- property MonthNamesHighIndex: Integer read GetMonthNamesHighIndex;
- property MonthNamesLowIndex: Integer read GetMonthNamesLowIndex;
- property NegCurrFormat: Byte read GetNegCurrFormat write SetNegCurrFormat;
- property ShortDateFormat: string read GetShortDateFormat write SetShortDateFormat;
- property ShortDayNames[AIndex: Integer]: string read GetShortDayNames;
- property ShortMonthNames[AIndex: Integer]: string read GetShortMonthNames;
- property ShortTimeFormat: string read GetShortTimeFormat write SetShortTimeFormat;
- property ThousandSeparator: Char read GetThousandSeparator write SetThousandSeparator;
- property TimeAMString: string read GetTimeAMString write SetTimeAMString;
- property TimePMString: string read GetTimePMString write SetTimePMString;
- property TimeSeparator: Char read GetTimeSeparator write SetTimeSeparator;
- property TwoDigitYearCenturyWindow: Word read GetTwoDigitYearCenturyWindow write SetTwoDigitYearCenturyWindow;
- end;
- var
- JclFormatSettings: TJclFormatSettings;
- {$IFNDEF WINSCP}
- // Procedure to initialize the SimpleLog Variable
- procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);
- // Global Variable to make it easier for an application wide log handling.
- // Must be initialized with InitSimpleLog before using
- var
- SimpleLog : TJclSimpleLog;
- {$ENDIF ~WINSCP}
- // Validates if then variant value is null or is empty
- function VarIsNullEmpty(const V: Variant): Boolean;
- // Validates if then variant value is null or is empty or VarToStr is a blank string
- function VarIsNullEmptyBlank(const V: Variant): Boolean;
- {$IFDEF UNITVERSIONING}
- const
- UnitVersioning: TUnitVersionInfo = (
- RCSfile: '$URL$';
- Revision: '$Revision$';
- Date: '$Date$';
- LogPath: 'JCL\source\common';
- Extra: '';
- Data: nil
- );
- {$ENDIF UNITVERSIONING}
- implementation
- uses
- {$IFDEF HAS_UNIT_LIBC}
- Libc,
- {$ENDIF HAS_UNIT_LIBC}
- {$IFDEF MSWINDOWS}
- {$IFNDEF WINSCP}
- JclConsole,
- {$ENDIF ~WINSCP}
- {$ENDIF MSWINDOWS}
- {$IFDEF HAS_UNITSCOPE}
- System.Variants, System.Types, System.Contnrs,
- {$IFDEF HAS_UNIT_ANSISTRINGS}
- System.AnsiStrings,
- {$ENDIF HAS_UNIT_ANSISTRINGS}
- {$ELSE ~HAS_UNITSCOPE}
- Variants, Types, Contnrs,
- {$IFDEF HAS_UNIT_ANSISTRINGS}
- AnsiStrings,
- {$ENDIF HAS_UNIT_ANSISTRINGS}
- {$ENDIF ~HAS_UNITSCOPE}
- JclFileUtils, {$IFNDEF WINSCP}JclMath,{$ENDIF ~WINSCP} JclResources, JclStrings,
- {$IFNDEF WINSCP}JclStringConversions,{$ENDIF ~WINSCP} JclSysInfo, JclWin32;
- // memory initialization
- procedure ResetMemory(out P; Size: Longint);
- begin
- if Size > 0 then
- begin
- Byte(P) := 0;
- FillChar(P, Size, 0);
- end;
- end;
- // Pointer manipulation
- procedure GetAndFillMem(var P: Pointer; const Size: Integer; const Value: Byte);
- begin
- GetMem(P, Size);
- FillChar(P^, Size, Value);
- end;
- procedure FreeMemAndNil(var P: Pointer);
- var
- Q: Pointer;
- begin
- Q := P;
- P := nil;
- FreeMem(Q);
- end;
- function PCharOrNil(const S: string): PChar;
- begin
- Result := Pointer(S);
- end;
- function PAnsiCharOrNil(const S: AnsiString): PAnsiChar;
- begin
- Result := Pointer(S);
- end;
- {$IFDEF SUPPORTS_WIDESTRING}
- function PWideCharOrNil(const W: WideString): PWideChar;
- begin
- Result := Pointer(W);
- end;
- {$ENDIF SUPPORTS_WIDESTRING}
- {$IFDEF MSWINDOWS}
- type
- PUsed = ^TUsed;
- TUsed = record
- SizeFlags: Integer;
- end;
- const
- cThisUsedFlag = 2;
- cPrevFreeFlag = 1;
- cFillerFlag = Integer($80000000);
- cFlags = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
- function SizeOfMem(const APointer: Pointer): Integer;
- var
- U: PUsed;
- begin
- if IsMemoryManagerSet then
- Result:= -1
- else
- begin
- Result := 0;
- if APointer <> nil then
- begin
- U := APointer;
- U := PUsed(TJclAddr(U) - SizeOf(TUsed));
- if (U.SizeFlags and cThisUsedFlag) <> 0 then
- Result := (U.SizeFlags) and (not cFlags - SizeOf(TUsed));
- end;
- end;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF LINUX}
- function SizeOfMem(const APointer: Pointer): Integer;
- begin
- if IsMemoryManagerSet then
- Result:= -1
- else
- begin
- if APointer <> nil then
- Result := malloc_usable_size(APointer)
- else
- Result := 0;
- end;
- end;
- {$ENDIF LINUX}
- function WriteProtectedMemory(BaseAddress, Buffer: Pointer;
- Size: Cardinal; out WrittenBytes: Cardinal): Boolean;
- {$IFDEF MSWINDOWS}
- var
- OldProtect, Dummy: Cardinal;
- begin
- WrittenBytes := 0;
- if Size > 0 then
- begin
- // (outchy) VirtualProtect for DEP issues
- OldProtect := 0;
- Result := VirtualProtect(BaseAddress, Size, PAGE_EXECUTE_READWRITE, OldProtect);
- if Result then
- try
- Move(Buffer^, BaseAddress^, Size);
- WrittenBytes := Size;
- if OldProtect in [PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY] then
- FlushInstructionCache(GetCurrentProcess, BaseAddress, Size);
- finally
- Dummy := 0;
- VirtualProtect(BaseAddress, Size, OldProtect, Dummy);
- end;
- end;
- Result := WrittenBytes = Size;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF LINUX}
- { TODO -cHelp : Author: Andreas Hausladen }
- { TODO : Works so far, but causes app to hang on termination }
- var
- AlignedAddress: Cardinal;
- PageSize, ProtectSize: Cardinal;
- begin
- Result := False;
- WrittenBytes := 0;
- PageSize := Cardinal(getpagesize);
- AlignedAddress := Cardinal(BaseAddress) and not (PageSize - 1); // start memory page
- // get the number of needed memory pages
- ProtectSize := PageSize;
- while Cardinal(BaseAddress) + Size > AlignedAddress + ProtectSize do
- Inc(ProtectSize, PageSize);
- if mprotect(Pointer(AlignedAddress), ProtectSize,
- PROT_READ or PROT_WRITE or PROT_EXEC) = 0 then // obtain write access
- begin
- try
- Move(Buffer^, BaseAddress^, Size); // replace code
- Result := True;
- WrittenBytes := Size;
- finally
- // Is there any function that returns the current page protection?
- // mprotect(p, ProtectSize, PROT_READ or PROT_EXEC); // lock memory page
- end;
- end;
- end;
- procedure FlushInstructionCache;
- { TODO -cHelp : Author: Andreas Hausladen }
- begin
- // do nothing
- end;
- {$ENDIF LINUX}
- // Guards
- //=== { TJclSafeGuard } ======================================================
- constructor TJclSafeGuard.Create(Mem: Pointer);
- begin
- inherited Create;
- FItem := Mem;
- end;
- destructor TJclSafeGuard.Destroy;
- begin
- FreeItem;
- inherited Destroy;
- end;
- function TJclSafeGuard.ReleaseItem: Pointer;
- begin
- Result := FItem;
- FItem := nil;
- end;
- function TJclSafeGuard.GetItem: Pointer;
- begin
- Result := FItem;
- end;
- procedure TJclSafeGuard.FreeItem;
- begin
- if FItem <> nil then
- FreeMem(FItem);
- FItem := nil;
- end;
- //=== { TJclObjSafeGuard } ===================================================
- constructor TJclObjSafeGuard.Create(Obj: TObject);
- begin
- inherited Create(Pointer(Obj));
- end;
- procedure TJclObjSafeGuard.FreeItem;
- begin
- if FItem <> nil then
- begin
- TObject(FItem).Free;
- FItem := nil;
- end;
- end;
- //=== { TJclMultiSafeGuard } =================================================
- constructor TJclMultiSafeGuard.Create;
- begin
- inherited Create;
- FItems := TList.Create;
- end;
- destructor TJclMultiSafeGuard.Destroy;
- var
- I: Integer;
- begin
- for I := FItems.Count - 1 downto 0 do
- FreeItem(I);
- FItems.Free;
- inherited Destroy;
- end;
- function TJclMultiSafeGuard.AddItem(Item: Pointer): Pointer;
- begin
- Result := Item;
- FItems.Add(Item);
- end;
- procedure TJclMultiSafeGuard.FreeItem(Index: Integer);
- begin
- FreeMem(FItems[Index]);
- FItems.Delete(Index);
- end;
- function TJclMultiSafeGuard.GetCount: Integer;
- begin
- Result := FItems.Count;
- end;
- function TJclMultiSafeGuard.GetItem(Index: Integer): Pointer;
- begin
- Result := FItems[Index];
- end;
- function TJclMultiSafeGuard.ReleaseItem(Index: Integer): Pointer;
- begin
- Result := FItems[Index];
- FItems.Delete(Index);
- end;
- function Guard(Mem: Pointer; var SafeGuard: IMultiSafeGuard): Pointer; overload;
- begin
- if SafeGuard = nil then
- SafeGuard := TJclMultiSafeGuard.Create;
- Result := SafeGuard.AddItem(Mem);
- end;
- //=== { TJclObjMultiSafeGuard } ==============================================
- procedure TJclObjMultiSafeGuard.FreeItem(Index: Integer);
- begin
- TObject(FItems[Index]).Free;
- FItems.Delete(Index);
- end;
- function Guard(Obj: TObject; var SafeGuard: IMultiSafeGuard): TObject; overload;
- begin
- if SafeGuard = nil then
- SafeGuard := TJclObjMultiSafeGuard.Create;
- Result := SafeGuard.AddItem(Obj);
- end;
- function Guard(Mem: Pointer; out SafeGuard: ISafeGuard): Pointer; overload;
- begin
- Result := Mem;
- SafeGuard := TJclSafeGuard.Create(Mem);
- end;
- function Guard(Obj: TObject; out SafeGuard: ISafeGuard): TObject; overload;
- begin
- Result := Obj;
- SafeGuard := TJclObjSafeGuard.Create(Obj);
- end;
- function GuardGetMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
- begin
- GetMem(Result, Size);
- Guard(Result, SafeGuard);
- end;
- function GuardAllocMem(Size: Cardinal; out SafeGuard: ISafeGuard): Pointer;
- begin
- Result := AllocMem(Size);
- Guard(Result, SafeGuard);
- end;
- {$IFDEF SUPPORTS_GENERICS_}
- //=== { TSafeGuard<T> } ======================================================
- constructor TSafeGuard<T>.Create(Instance: T);
- begin
- inherited Create;
- FItem := Instance;
- end;
- destructor TSafeGuard<T>.Destroy;
- begin
- FreeItem;
- inherited Destroy;
- end;
- function TSafeGuard<T>.ReleaseItem: T;
- begin
- Result := FItem;
- FItem := nil;
- end;
- function TSafeGuard<T>.GetItem: T;
- begin
- Result := FItem;
- end;
- procedure TSafeGuard<T>.FreeItem;
- begin
- if FItem <> nil then
- FItem.Free;
- FItem := nil;
- end;
- {$ENDIF SUPPORTS_GENERICS_}
- //=== Shared memory functions ================================================
- type
- PMMFHandleListItem = ^TMMFHandleListItem;
- TMMFHandleListItem = record
- Next: PMMFHandleListItem;
- Memory: Pointer;
- Handle: THandle;
- Name: string;
- References: Integer;
- end;
- PMMFHandleList = PMMFHandleListItem;
- var
- MMFHandleList: PMMFHandleList = nil;
- {$IFDEF THREADSAFE}
- MMFFinalized: Boolean = False;
- GlobalMMFHandleListCS: TJclIntfCriticalSection = nil;
- {$ENDIF THREADSAFE}
- {$IFDEF THREADSAFE}
- function GetAccessToHandleList: IInterface;
- var
- OldValue: Pointer;
- CS: TJclIntfCriticalSection;
- begin
- if not Assigned(GlobalMMFHandleListCS) and not MMFFinalized then
- begin
- CS := TJclIntfCriticalSection.Create;
- {$IFDEF RTL200_UP} // Delphi 2009+
- OldValue := InterlockedCompareExchangePointer(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
- {$ELSE}
- {$IFDEF RTL160_UP} // Delphi 7-2007
- OldValue := Pointer(InterlockedCompareExchange(Longint(GlobalMMFHandleListCS), Longint(CS), 0));
- {$ELSE} // Delphi 5, 6
- OldValue := InterlockedCompareExchange(Pointer(GlobalMMFHandleListCS), Pointer(CS), nil);
- {$ENDIF RTL180_UP}
- {$ENDIF RTL185_UP}
- if OldValue <> nil then
- CS.Free;
- end;
- Result := GlobalMMFHandleListCS;
- end;
- {$ENDIF THREADSAFE}
- {$IFDEF MSWINDOWS}
- function SharedGetMem(var P{: Pointer}; const Name: string; Size: Cardinal;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Integer;
- var
- FileMappingHandle: THandle;
- Iterate, NewListItem: PMMFHandleListItem;
- Protect: Cardinal;
- {$IFDEF THREADSAFE}
- HandleListAccess: IInterface;
- {$ENDIF THREADSAFE}
- begin
- Result := 0;
- Pointer(P) := nil;
- if not JclCheckWinVersion(5, 0) and ((Name = '') or (Pos('\', Name) > 0)) then
- raise ESharedMemError.CreateResFmt(@RsInvalidMMFName, [Name]);
- {$IFDEF THREADSAFE}
- HandleListAccess := GetAccessToHandleList;
- {$ENDIF THREADSAFE}
- // search for same name
- Iterate := MMFHandleList;
- while Iterate <> nil do
- begin
- if CompareText(Iterate^.Name, Name) = 0 then
- begin
- Inc(Iterate^.References);
- Pointer(P) := Iterate^.Memory;
- Result := ERROR_ALREADY_EXISTS;
- Exit;
- end;
- Iterate := Iterate^.Next;
- end;
- // open file mapping
- FileMappingHandle := OpenFileMapping(DesiredAccess, False, PChar(Name));
- if FileMappingHandle = 0 then
- begin
- if Size = 0 then
- raise ESharedMemError.CreateResFmt(@RsInvalidMMFEmpty, [Name]);
- Protect := PAGE_READWRITE;
- if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and (DesiredAccess = FILE_MAP_COPY) then
- Protect := PAGE_WRITECOPY;
- FileMappingHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, Protect,
- 0, Size, PChar(Name));
- end
- else
- Result := ERROR_ALREADY_EXISTS;
- if GetLastError = ERROR_ALREADY_EXISTS then
- Result := ERROR_ALREADY_EXISTS
- else
- begin
- if FileMappingHandle = 0 then
- RaiseLastOSError;
- end;
- // map view
- Pointer(P) := MapViewOfFile(FileMappingHandle, DesiredAccess, 0, 0, Size);
- if Pointer(P) = nil then
- begin
- try
- RaiseLastOSError;
- except
- CloseHandle(FileMappingHandle);
- raise;
- end;
- end;
- // add list item to MMFHandleList
- New(NewListItem);
- NewListItem^.Name := Name;
- NewListItem^.Handle := FileMappingHandle;
- NewListItem^.Memory := Pointer(P);
- NewListItem^.References := 1;
- NewListItem^.Next := MMFHandleList;
- MMFHandleList := NewListItem;
- end;
- function SharedAllocMem(const Name: string; Size: Cardinal;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
- begin
- Result := nil;
- if (SharedGetMem(Result, Name, Size, DesiredAccess) <> ERROR_ALREADY_EXISTS) and
- ((DesiredAccess and (FILE_MAP_WRITE or FILE_MAP_COPY)) <> 0) and
- (Size > 0) and (Result <> nil) then
- ResetMemory(Pointer(Result)^, Size);
- end;
- function SharedFreeMem(var P{: Pointer}): Boolean;
- var
- N, Iterate: PMMFHandleListItem;
- {$IFDEF THREADSAFE}
- HandleListAccess: IInterface;
- {$ENDIF THREADSAFE}
- begin
- if Pointer(P) <> nil then
- begin
- Result := False;
- {$IFDEF THREADSAFE}
- HandleListAccess := GetAccessToHandleList;
- {$ENDIF THREADSAFE}
- Iterate := MMFHandleList;
- N := nil;
- while Iterate <> nil do
- begin
- if Iterate^.Memory = Pointer(P) then
- begin
- if Iterate^.References > 1 then
- begin
- Dec(Iterate^.References);
- Pointer(P) := nil;
- Result := True;
- Exit;
- end;
- UnmapViewOfFile(Iterate^.Memory);
- CloseHandle(Iterate^.Handle);
- if N = nil then
- MMFHandleList := Iterate^.Next
- else
- N^.Next := Iterate^.Next;
- Dispose(Iterate);
- Pointer(P) := nil;
- Result := True;
- Break;
- end;
- N := Iterate;
- Iterate := Iterate^.Next;
- end;
- end
- else
- Result := True;
- end;
- function SharedOpenMem(var P{: Pointer}; const Name: string;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Boolean;
- begin
- Result := SharedGetMem(P, Name, 0, DesiredAccess) = ERROR_ALREADY_EXISTS;
- end;
- function SharedOpenMem(const Name: string;
- DesiredAccess: Cardinal = FILE_MAP_ALL_ACCESS): Pointer;
- begin
- Result := nil;
- SharedGetMem(Result, Name, 0, DesiredAccess);
- end;
- function SharedCloseMem(var P{: Pointer}): Boolean;
- begin
- Result := SharedFreeMem(P);
- end;
- {$ENDIF MSWINDOWS}
- //=== Binary search ==========================================================
- function SearchSortedList(List: TList; SortFunc: TListSortCompare; Item: Pointer; Nearest: Boolean): Integer;
- var
- L, H, I, C: Integer;
- B: Boolean;
- begin
- Result := -1;
- if List <> nil then
- begin
- L := 0;
- H := List.Count - 1;
- B := False;
- while L <= H do
- begin
- I := (L + H) shr 1;
- C := SortFunc(List.List{$IFNDEF RTL230_UP}^{$ENDIF !RTL230_UP}[I], Item);
- if C < 0 then
- L := I + 1
- else
- begin
- H := I - 1;
- if C = 0 then
- begin
- B := True;
- L := I;
- end;
- end;
- end;
- if B then
- Result := L
- else
- if Nearest and (H >= 0) then
- Result := H;
- end;
- end;
- function SearchSortedUntyped(Param: Pointer; ItemCount: Integer; SearchFunc: TUntypedSearchCompare;
- const Value; Nearest: Boolean): Integer;
- var
- L, H, I, C: Integer;
- B: Boolean;
- begin
- Result := -1;
- if ItemCount > 0 then
- begin
- L := 0;
- H := ItemCount - 1;
- B := False;
- while L <= H do
- begin
- I := (L + H) shr 1;
- C := SearchFunc(Param, I, Value);
- if C < 0 then
- L := I + 1
- else
- begin
- H := I - 1;
- if C = 0 then
- begin
- B := True;
- L := I;
- end;
- end;
- end;
- if B then
- Result := L
- else
- if Nearest and (H >= 0) then
- Result := H;
- end;
- end;
- //=== Dynamic array sort and search routines =================================
- procedure SortDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare);
- var
- TempBuf: TDynByteArray;
- procedure QuickSort(L, R: SizeInt);
- var
- I, J, T: SizeInt;
- P, IPtr, JPtr: Pointer;
- ElSize: Integer;
- begin
- ElSize := ElementSize;
- repeat
- I := L;
- J := R;
- P := Pointer(TJclAddr(ArrayPtr) + TJclAddr(((L + R) shr 1) * SizeInt(ElementSize)));
- repeat
- IPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize)));
- JPtr := Pointer(TJclAddr(ArrayPtr) + TJclAddr(J * SizeInt(ElementSize)));
- while SortFunc(IPtr, P) < 0 do
- begin
- Inc(I);
- Inc(PByte(IPtr), ElSize);
- end;
- while SortFunc(JPtr, P) > 0 do
- begin
- Dec(J);
- Dec(PByte(JPtr), ElSize);
- end;
- if I <= J then
- begin
- if I <> J then
- begin
- case ElementSize of
- SizeOf(Byte):
- begin
- T := PByte(IPtr)^;
- PByte(IPtr)^ := PByte(JPtr)^;
- PByte(JPtr)^ := T;
- end;
- SizeOf(Word):
- begin
- T := PWord(IPtr)^;
- PWord(IPtr)^ := PWord(JPtr)^;
- PWord(JPtr)^ := T;
- end;
- SizeOf(Integer):
- begin
- T := PInteger(IPtr)^;
- PInteger(IPtr)^ := PInteger(JPtr)^;
- PInteger(JPtr)^ := T;
- end;
- else
- Move(IPtr^, TempBuf[0], ElementSize);
- Move(JPtr^, IPtr^, ElementSize);
- Move(TempBuf[0], JPtr^, ElementSize);
- end;
- end;
- if P = IPtr then
- P := JPtr
- else
- if P = JPtr then
- P := IPtr;
- Inc(I);
- Dec(J);
- end;
- until I > J;
- if L < J then
- QuickSort(L, J);
- L := I;
- until I >= R;
- end;
- begin
- if ArrayPtr <> nil then
- begin
- SetLength(TempBuf, ElementSize);
- QuickSort(0, PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1);
- end;
- end;
- function SearchDynArray(const ArrayPtr: Pointer; ElementSize: Cardinal; SortFunc: TDynArraySortCompare;
- ValuePtr: Pointer; Nearest: Boolean): SizeInt;
- var
- L, H, I, C: SizeInt;
- B: Boolean;
- begin
- Result := -1;
- if ArrayPtr <> nil then
- begin
- L := 0;
- H := PSizeInt(TJclAddr(ArrayPtr) - SizeOf(SizeInt))^ - 1;
- B := False;
- while L <= H do
- begin
- I := (L + H) shr 1;
- C := SortFunc(Pointer(TJclAddr(ArrayPtr) + TJclAddr(I * SizeInt(ElementSize))), ValuePtr);
- if C < 0 then
- L := I + 1
- else
- begin
- H := I - 1;
- if C = 0 then
- begin
- B := True;
- L := I;
- end;
- end;
- end;
- if B then
- Result := L
- else
- if Nearest and (H >= 0) then
- Result := H;
- end;
- end;
- { Various compare functions for basic types }
- function DynArrayCompareByte(Item1, Item2: Pointer): Integer;
- begin
- Result := PByte(Item1)^ - PByte(Item2)^;
- end;
- function DynArrayCompareShortInt(Item1, Item2: Pointer): Integer;
- begin
- Result := PShortInt(Item1)^ - PShortInt(Item2)^;
- end;
- function DynArrayCompareWord(Item1, Item2: Pointer): Integer;
- begin
- Result := PWord(Item1)^ - PWord(Item2)^;
- end;
- function DynArrayCompareSmallInt(Item1, Item2: Pointer): Integer;
- begin
- Result := PSmallInt(Item1)^ - PSmallInt(Item2)^;
- end;
- function DynArrayCompareInteger(Item1, Item2: Pointer): Integer;
- begin
- if PInteger(Item1)^ < PInteger(Item2)^ then
- Result := -1
- else
- if PInteger(Item1)^ > PInteger(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareCardinal(Item1, Item2: Pointer): Integer;
- begin
- if PCardinal(Item1)^ < PCardinal(Item2)^ then
- Result := -1
- else
- if PCardinal(Item1)^ > PCardinal(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareInt64(Item1, Item2: Pointer): Integer;
- begin
- if PInt64(Item1)^ < PInt64(Item2)^ then
- Result := -1
- else
- if PInt64(Item1)^ > PInt64(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareSingle(Item1, Item2: Pointer): Integer;
- begin
- if PSingle(Item1)^ < PSingle(Item2)^ then
- Result := -1
- else
- if PSingle(Item1)^ > PSingle(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareDouble(Item1, Item2: Pointer): Integer;
- begin
- if PDouble(Item1)^ < PDouble(Item2)^ then
- Result := -1
- else
- if PDouble(Item1)^ > PDouble(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareExtended(Item1, Item2: Pointer): Integer;
- begin
- if PExtended(Item1)^ < PExtended(Item2)^ then
- Result := -1
- else
- if PExtended(Item1)^ > PExtended(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareFloat(Item1, Item2: Pointer): Integer;
- begin
- if PFloat(Item1)^ < PFloat(Item2)^ then
- Result := -1
- else
- if PFloat(Item1)^ > PFloat(Item2)^ then
- Result := 1
- else
- Result := 0;
- end;
- function DynArrayCompareAnsiString(Item1, Item2: Pointer): Integer;
- begin
- Result := AnsiCompareStr(PAnsiString(Item1)^, PAnsiString(Item2)^);
- end;
- function DynArrayCompareAnsiText(Item1, Item2: Pointer): Integer;
- begin
- Result := AnsiCompareText(PAnsiString(Item1)^, PAnsiString(Item2)^);
- end;
- function DynArrayCompareWideString(Item1, Item2: Pointer): Integer;
- begin
- Result := WideCompareStr(PWideString(Item1)^, PWideString(Item2)^);
- end;
- function DynArrayCompareWideText(Item1, Item2: Pointer): Integer;
- begin
- Result := WideCompareText(PWideString(Item1)^, PWideString(Item2)^);
- end;
- function DynArrayCompareString(Item1, Item2: Pointer): Integer;
- begin
- Result := CompareStr(PString(Item1)^, PString(Item2)^);
- end;
- function DynArrayCompareText(Item1, Item2: Pointer): Integer;
- begin
- Result := CompareText(PString(Item1)^, PString(Item2)^);
- end;
- //=== Object lists ===========================================================
- procedure ClearObjectList(List: TList);
- var
- I: Integer;
- begin
- if List <> nil then
- begin
- for I := List.Count - 1 downto 0 do
- begin
- if List[I] <> nil then
- begin
- if TObject(List[I]) is TList then
- begin
- // recursively delete TList sublists
- ClearObjectList(TList(List[I]));
- end;
- TObject(List[I]).Free;
- if (not (List is TComponentList))
- and ((not(List is TObjectList)) or not TObjectList(List).OwnsObjects) then
- List[I] := nil;
- end;
- end;
- List.Clear;
- end;
- end;
- procedure FreeObjectList(var List: TList);
- begin
- if List <> nil then
- begin
- ClearObjectList(List);
- FreeAndNil(List);
- end;
- end;
- //=== { TJclReferenceMemoryStream } ==========================================
- constructor TJclReferenceMemoryStream.Create(const Ptr: Pointer; Size: Longint);
- begin
- {$IFDEF MSWINDOWS}
- Assert(not IsBadReadPtr(Ptr, Size));
- {$ENDIF MSWINDOWS}
- inherited Create;
- SetPointer(Ptr, Size);
- end;
- function TJclReferenceMemoryStream.Write(const Buffer; Count: Longint): Longint;
- begin
- raise EJclError.CreateRes(@RsCannotWriteRefStream);
- end;
- //=== { TJclAutoPtr } ========================================================
- constructor TJclAutoPtr.Create(AValue: TObject);
- begin
- inherited Create;
- FValue := AValue;
- end;
- destructor TJclAutoPtr.Destroy;
- begin
- FValue.Free;
- inherited Destroy;
- end;
- function TJclAutoPtr.AsObject: TObject;
- begin
- Result := FValue;
- end;
- function TJclAutoPtr.AsPointer: Pointer;
- begin
- Result := FValue;
- end;
- function TJclAutoPtr.ReleaseObject: TObject;
- begin
- Result := FValue;
- FValue := nil;
- end;
- function CreateAutoPtr(Value: TObject): IAutoPtr;
- begin
- Result := TJclAutoPtr.Create(Value);
- end;
- //=== replacement for the C distfix operator ? : =============================
- function Iff(const Condition: Boolean; const TruePart, FalsePart: string): string;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Char): Char;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Byte): Byte;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Integer): Integer;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Cardinal): Cardinal;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Float): Float;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Boolean): Boolean;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Pointer): Pointer;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Int64): Int64;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- {$IFDEF SUPPORTS_VARIANT}
- function Iff(const Condition: Boolean; const TruePart, FalsePart: Variant): Variant; overload;
- begin
- if Condition then
- Result := TruePart
- else
- Result := FalsePart;
- end;
- {$ENDIF SUPPORTS_VARIANT}
- //=== Classes information and manipulation ===================================
- // Virtual Methods
- // Helper method
- procedure SetVMTPointer(AClass: TClass; Offset: Integer; Value: Pointer);
- var
- WrittenBytes: DWORD;
- PatchAddress: PPointer;
- begin
- {$OVERFLOWCHECKS OFF}
- PatchAddress := Pointer(TJclAddr(AClass) + TJclAddr(Offset));
- {$IFDEF OVERFLOWCHECKS_ON}
- {$OVERFLOWCHECKS ON}
- {$ENDIF OVERFLOWCHECKS_ON}
- if not WriteProtectedMemory(PatchAddress, @Value, SizeOf(Value), WrittenBytes) then
- raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,
- [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);
- if WrittenBytes <> SizeOf(Pointer) then
- raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);
- // make sure that everything keeps working in a dual processor setting
- // (outchy) done by WriteProtectedMemory
- // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};
- end;
- {$IFNDEF FPC}
- function GetVirtualMethodCount(AClass: TClass): Integer;
- type
- PINT_PTR = ^INT_PTR;
- var
- BeginVMT: INT_PTR;
- EndVMT: INT_PTR;
- TablePointer: INT_PTR;
- I: Integer;
- begin
- BeginVMT := INT_PTR(AClass);
- // Scan the offset entries in the class table for the various fields,
- // namely vmtIntfTable, vmtAutoTable, ..., vmtDynamicTable
- // The last entry is always the vmtClassName, so stop once we got there
- // After the last virtual method there is one of these entries.
- EndVMT := PINT_PTR(INT_PTR(AClass) + vmtClassName)^;
- // Set iterator to first item behind VMT table pointer
- I := vmtSelfPtr + SizeOf(Pointer);
- repeat
- TablePointer := PINT_PTR(INT_PTR(AClass) + I)^;
- if (TablePointer <> 0) and (TablePointer >= BeginVMT) and
- (TablePointer < EndVMT) then
- EndVMT := INT_PTR(TablePointer);
- Inc(I, SizeOf(Pointer));
- until I >= vmtClassName;
- Result := (EndVMT - BeginVMT) div SizeOf(Pointer);
- end;
- {$ENDIF ~FPC}
- function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
- begin
- {$OVERFLOWCHECKS OFF}
- Result := PPointer(TJclAddr(AClass) + TJclAddr(Index * SizeOf(Pointer)))^;
- {$IFDEF OVERFLOWCHECKS_ON}
- {$OVERFLOWCHECKS ON}
- {$ENDIF OVERFLOWCHECKS_ON}
- end;
- procedure SetVirtualMethod(AClass: TClass; const Index: Integer; const Method: Pointer);
- begin
- SetVMTPointer(AClass, Index * SizeOf(Pointer), Method);
- end;
- function GetDynamicMethodCount(AClass: TClass): Integer; assembler;
- asm
- {$IFDEF CPU32}
- // --> RAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtDynamicTable
- TEST EAX, EAX
- JE @@Exit
- MOVZX EAX, WORD PTR [EAX]
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- EAX Result
- MOV RAX, [RCX].vmtDynamicTable
- TEST RAX, RAX
- JE @@Exit
- MOVZX RAX, WORD PTR [RAX]
- {$ENDIF CPU64}
- @@Exit:
- end;
- function GetDynamicIndexList(AClass: TClass): PDynamicIndexList; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtDynamicTable
- ADD EAX, 2
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtDynamicTable
- ADD RAX, 2
- {$ENDIF CPU64}
- end;
- function GetDynamicAddressList(AClass: TClass): PDynamicAddressList; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtDynamicTable
- MOVZX EDX, Word ptr [EAX]
- ADD EAX, EDX
- ADD EAX, EDX
- ADD EAX, 2
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtDynamicTable
- MOVZX RDX, Word ptr [RAX]
- ADD RAX, RDX
- ADD RAX, RDX
- ADD RAX, 2
- {$ENDIF CPU64}
- end;
- function HasDynamicMethod(AClass: TClass; Index: Integer): Boolean; assembler;
- // Mainly copied from System.GetDynaMethod
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // EDX Index
- // <-- AL Result
- PUSH EDI
- XCHG EAX, EDX
- JMP @@HaveVMT
- @@OuterLoop:
- MOV EDX, [EDX]
- @@HaveVMT:
- MOV EDI, [EDX].vmtDynamicTable
- TEST EDI, EDI
- JE @@Parent
- MOVZX ECX, WORD PTR [EDI]
- PUSH ECX
- ADD EDI,2
- REPNE SCASW
- JE @@Found
- POP ECX
- @@Parent:
- MOV EDX,[EDX].vmtParent
- TEST EDX,EDX
- JNE @@OuterLoop
- MOV EAX, 0
- JMP @@Exit
- @@Found:
- POP EAX
- MOV EAX, 1
- @@Exit:
- POP EDI
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // EDX Index
- // <-- AL Result
- MOV EAX, EDX
- MOV RDX, RCX
- JMP @@HaveVMT
- @@OuterLoop:
- MOV RDX, [RDX]
- @@HaveVMT:
- MOV RDI, [RDX].vmtDynamicTable
- TEST RDI, RDI
- JE @@Parent
- MOVZX RCX, WORD PTR [RDI]
- PUSH RCX
- ADD RDI,2
- REPNE SCASW
- JE @@Found
- POP RCX
- @@Parent:
- MOV RDX,[RDX].vmtParent
- TEST RDX,RDX
- JNE @@OuterLoop
- MOV RAX, 0
- JMP @@Exit
- @@Found:
- POP RAX
- MOV RAX, 1
- @@Exit:
- {$ENDIF CPU64}
- end;
- {$IFNDEF FPC}
- function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer; assembler;
- asm
- CALL System.@FindDynaClass
- end;
- {$ENDIF ~FPC}
- //=== Interface Table ========================================================
- function GetInitTable(AClass: TClass): PTypeInfo; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtInitTable
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtInitTable
- {$ENDIF CPU64}
- end;
- function GetFieldTable(AClass: TClass): PFieldTable; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtFieldTable
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtFieldTable
- {$ENDIF CPU64}
- end;
- function GetMethodTable(AClass: TClass): PMethodTable; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtMethodTable
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtMethodTable
- {$ENDIF CPU64}
- end;
- function GetMethodEntry(MethodTable: PMethodTable; Index: Integer): PMethodEntry;
- begin
- Result := Pointer(TJclAddr(MethodTable) + 2);
- for Index := Index downto 1 do
- Inc(TJclAddr(Result), Result^.EntrySize);
- end;
- function MethodEquals(aMethod1, aMethod2: TMethod): boolean;
- begin
- Result := (aMethod1.Code = aMethod2.Code) and
- (aMethod1.Data = aMethod2.Data);
- end;
- function NotifyEventEquals(aMethod1, aMethod2: TNotifyEvent): boolean;
- begin
- Result := MethodEquals(TMethod(aMethod1),TMethod(aMethod2));
- end;
- //=== Class Parent methods ===================================================
- procedure SetClassParent(AClass: TClass; NewClassParent: TClass);
- var
- WrittenBytes: DWORD;
- PatchAddress: Pointer;
- begin
- {$OVERFLOWCHECKS OFF}
- PatchAddress := PPointer(TJclAddr(AClass) + TJclAddr(vmtParent))^;
- {$IFDEF OVERFLOWCHECKS_ON}
- {$OVERFLOWCHECKS ON}
- {$ENDIF OVERFLOWCHECKS_ON}
- if not WriteProtectedMemory(PatchAddress, @NewClassParent, SizeOf(Pointer), WrittenBytes) then
- raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError,
- [SysErrorMessage({$IFDEF FPC}GetLastOSError{$ELSE}GetLastError{$ENDIF})]);
- if WrittenBytes <> SizeOf(Pointer) then
- raise EJclVMTError.CreateResFmt(@RsVMTMemoryWriteError, [IntToStr(WrittenBytes)]);
- // make sure that everything keeps working in a dual processor setting
- // (outchy) done by WriteProtectedMemory
- // FlushInstructionCache{$IFDEF MSWINDOWS}(GetCurrentProcess, PatchAddress, SizeOf(Pointer)){$ENDIF};
- end;
- function GetClassParent(AClass: TClass): TClass; assembler;
- asm
- {$IFDEF CPU32}
- // --> EAX AClass
- // <-- EAX Result
- MOV EAX, [EAX].vmtParent
- TEST EAX, EAX
- JE @@Exit
- MOV EAX, [EAX]
- {$ENDIF CPU32}
- {$IFDEF CPU64}
- // --> RCX AClass
- // <-- RAX Result
- MOV RAX, [RCX].vmtParent
- TEST RAX, RAX
- JE @@Exit
- MOV RAX, [RAX]
- {$ENDIF CPU64}
- @@Exit:
- end;
- {$IFDEF BORLAND}
- function IsClass(Address: Pointer): Boolean; assembler;
- asm
- CMP Address, Address.vmtSelfPtr
- JNZ @False
- MOV Result, True
- JMP @Exit
- @False:
- MOV Result, False
- @Exit:
- end;
- {$ENDIF BORLAND}
- {$IFDEF BORLAND}
- function IsObject(Address: Pointer): Boolean; assembler;
- asm
- // or IsClass(Pointer(Address^));
- MOV EAX, [Address]
- CMP EAX, EAX.vmtSelfPtr
- JNZ @False
- MOV Result, True
- JMP @Exit
- @False:
- MOV Result, False
- @Exit:
- end;
- {$ENDIF BORLAND}
- function InheritsFromByName(AClass: TClass; const AClassName: string): Boolean;
- begin
- while (AClass <> nil) and not AClass.ClassNameIs(AClassName) do
- AClass := AClass.ClassParent;
- Result := AClass <> nil;
- end;
- //=== Interface information ==================================================
- function GetImplementorOfInterface(const I: IInterface): TObject;
- { TODO -cDOC : Original code by Hallvard Vassbotn }
- { TODO -cTesting : Check the implemetation for any further version of compiler }
- const
- AddByte = $04244483; // opcode for ADD DWORD PTR [ESP+4], Shortint
- AddLong = $04244481; // opcode for ADD DWORD PTR [ESP+4], Longint
- type
- PAdjustSelfThunk = ^TAdjustSelfThunk;
- TAdjustSelfThunk = packed record
- case AddInstruction: Longint of
- AddByte: (AdjustmentByte: ShortInt);
- AddLong: (AdjustmentLong: Longint);
- end;
- PInterfaceMT = ^TInterfaceMT;
- TInterfaceMT = packed record
- QueryInterfaceThunk: PAdjustSelfThunk;
- end;
- TInterfaceRef = ^PInterfaceMT;
- var
- QueryInterfaceThunk: PAdjustSelfThunk;
- begin
- try
- Result := Pointer(I);
- if Assigned(Result) then
- begin
- QueryInterfaceThunk := TInterfaceRef(I)^.QueryInterfaceThunk;
- case QueryInterfaceThunk.AddInstruction of
- AddByte:
- Inc(PByte(Result), QueryInterfaceThunk.AdjustmentByte);
- AddLong:
- Inc(PByte(Result), QueryInterfaceThunk.AdjustmentLong);
- else
- Result := nil;
- end;
- end;
- except
- Result := nil;
- end;
- end;
- //=== { TJclInterfacedPersistent } ===========================================
- procedure TJclInterfacedPersistent.AfterConstruction;
- begin
- inherited AfterConstruction;
- if GetOwner <> nil then
- GetOwner.GetInterface(IInterface, FOwnerInterface);
- end;
- function TJclInterfacedPersistent._AddRef: Integer;
- begin
- if FOwnerInterface <> nil then
- Result := FOwnerInterface._AddRef
- else
- Result := InterlockedIncrement(FRefCount);
- end;
- function TJclInterfacedPersistent._Release: Integer;
- begin
- if FOwnerInterface <> nil then
- Result := FOwnerInterface._Release
- else
- begin
- Result := InterlockedDecrement(FRefCount);
- if Result = 0 then
- Destroy;
- end;
- end;
- //=== Numeric formatting routines ============================================
- function IntToStrZeroPad(Value, Count: Integer): string;
- begin
- Result := IntToStr(Value);
- if Length(Result) < Count then
- Result := StrRepeatChar('0', Count - Length(Result)) + Result;
- end;
- //=== { TJclNumericFormat } ==================================================
- { TODO -cHelp : Author: Robert Rossmair }
- { Digit: converts a digit value (number) to a digit (char)
- DigitValue: converts a digit (char) into a number (digit value)
- IntToStr,
- FloatToStr,
- FloatToHTML: converts a numeric value to a base <Base> numeric representation with formating options
- StrToIn: converts a base <Base> numeric representation into an integer, if possible
- GetMantisseExponent: similar to AsString, but returns the Exponent separately as an integer
- }
- const
- {$IFDEF MATH_EXTENDED_PRECISION}
- BinaryPrecision = 64;
- {$ENDIF MATH_EXTENDED_PRECISION}
- {$IFDEF MATH_DOUBLE_PRECISION}
- BinaryPrecision = 53;
- {$ENDIF MATH_DOUBLE_PRECISION}
- {$IFDEF MATH_SINGLE_PRECISION}
- BinaryPrecision = 24;
- {$ENDIF MATH_SINGLE_PRECISION}
- {$IFNDEF WINSCP}
- constructor TJclNumericFormat.Create;
- begin
- inherited Create;
- { TODO : Initialize, when possible, from locale info }
- FBase := 10;
- FExpDivision := 1;
- SetPrecision(6);
- FNumberOfFractionalDigits := BinaryPrecision;
- FSignChars[False] := '-';
- FSignChars[True] := '+';
- FPaddingChar := ' ';
- FMultiplier := '×';
- FFractionalPartSeparator := JclFormatSettings.DecimalSeparator;
- FDigitBlockSeparator := JclFormatSettings.ThousandSeparator;
- end;
- procedure TJclNumericFormat.InvalidDigit(Digit: Char);
- begin
- raise EConvertError.CreateResFmt(@RsInvalidDigit, [Base, Digit]);
- end;
- function TJclNumericFormat.Digit(DigitValue: TDigitValue): Char;
- begin
- Assert(DigitValue < Base, Format(LoadResString(@RsInvalidDigitValue), [Base, DigitValue]));
- if DigitValue > 9 then
- Result := Chr(Ord('A') + DigitValue - 10)
- else
- Result := Chr(Ord('0') + DigitValue);
- end;
- function TJclNumericFormat.GetDigitValue(Digit: Char): Integer;
- begin
- Result := CharHex(Digit);
- if (Result = $FF) or (Result >= Base) then
- Result := -1;
- end;
- function TJclNumericFormat.DigitValue(Digit: Char): TDigitValue;
- begin
- Result := GetDigitValue(Digit);
- if Result = -1 then
- InvalidDigit(Digit);
- end;
- function TJclNumericFormat.IsDigit(Value: Char): Boolean;
- begin
- Result := GetDigitValue(Value) <> -1;
- end;
- function TJclNumericFormat.FloatToHTML(const Value: Float): string;
- var
- Mantissa: string;
- Exponent: Integer;
- begin
- GetMantissaExp(Value, Mantissa, Exponent);
- Result := Format('%s %s %d<sup>%d</sup>', [Mantissa, Multiplier, Base, Exponent]);
- end;
- procedure TJclNumericFormat.GetMantissaExp(const Value: Float;
- out Mantissa: string; out Exponent: Integer);
- const
- {$IFDEF FPC}
- InfMantissa: array [Boolean] of string[4] = ('inf', '-inf');
- {$ElSE ~FPC}
- InfMantissa: array [Boolean] of string = ('inf', '-inf');
- {$ENDIF ~FPC}
- var
- BlockDigits: TDigitCount;
- IntDigits, FracDigits: Integer;
- FirstDigitPos, Prec: Integer;
- I, J, N: Integer;
- K: Int64;
- X: Extended;
- HighDigit: Char;
- function GetDigit(X: Extended): Char;
- var
- N: Integer;
- begin
- N := Trunc(X);
- if N > 9 then
- Result := Chr(Ord('A') + N - 10)
- else
- Result := Chr(Ord('0') + N);
- end;
- begin
- X := Abs(Value);
- if X > MaxFloatingPoint then
- begin
- Mantissa := InfMantissa[Value < 0];
- Exponent := 1;
- Exit;
- end
- else
- if X < MinFloatingPoint then
- begin
- Mantissa := Format('%.*f', [Precision, 0.0]);
- Exponent := 1;
- Exit;
- end;
- IntDigits := 1;
- Prec := Precision;
- Exponent := Trunc(LogBaseN(Base, X));
- if FExpDivision > 1 then
- begin
- N := Exponent mod FExpDivision;
- Dec(Exponent, N);
- Inc(IntDigits, N);
- end;
- X := X / Power(Base, Exponent);
- if X < 1.0 then
- begin
- Dec(Exponent, FExpDivision);
- X := X * PowerInt(Base, FExpDivision);
- Inc(IntDigits, FExpDivision - 1);
- end;
- { TODO : Here's a problem if X > High(Int64).
- It *seems* to surface only if ExponentDivision > 12, but it
- has not been investigated if ExponentDivision <= 12 is safe. }
- K := Trunc(X);
- if Value < 0 then
- K := -K;
- Mantissa := IntToStr(K, FirstDigitPos);
- FracDigits := Prec - IntDigits;
- if FracDigits > NumberOfFractionalDigits then
- FracDigits := NumberOfFractionalDigits;
- if FracDigits > 0 then
- begin
- J := Length(Mantissa) + 1;
- // allocate sufficient space for point + digits + digit block separators
- SetLength(Mantissa, FracDigits * 2 + J);
- Mantissa[J] := FractionalPartSeparator;
- I := J + 1;
- BlockDigits := 0;
- while FracDigits > 0 do
- begin
- if (BlockDigits > 0) and (BlockDigits = DigitBlockSize) then
- begin
- Mantissa[I] := DigitBlockSeparator;
- Inc(I);
- BlockDigits := 0;
- end;
- X := Frac(X) * Base;
- Mantissa[I] := GetDigit(X);
- Inc(I);
- Inc(BlockDigits);
- Dec(FracDigits);
- end;
- Mantissa[I] := #0;
- StrResetLength(Mantissa);
- end;
- if Frac(X) >= 0.5 then
- // round up
- begin
- HighDigit := Digit(Base - 1);
- for I := Length(Mantissa) downto 1 do
- begin
- if Mantissa[I] = HighDigit then
- if (I = FirstDigitPos) then
- begin
- Mantissa[I] := '1';
- Inc(Exponent);
- Break;
- end
- else
- Mantissa[I] := '0'
- else
- if (Mantissa[I] = DigitBlockSeparator) or (Mantissa[I] = FractionalPartSeparator) then
- Continue
- else
- begin
- if Mantissa[I] = '9' then
- Mantissa[I] := 'A'
- else
- Mantissa[I] := Succ(Mantissa[I]);
- Break;
- end;
- end;
- end;
- end;
- function TJclNumericFormat.FloatToStr(const Value: Float): string;
- var
- Mantissa: string;
- Exponent: Integer;
- begin
- GetMantissaExp(Value, Mantissa, Exponent);
- Result := Format('%s %s %d^%d', [Mantissa, Multiplier, Base, Exponent]);
- end;
- function TJclNumericFormat.IntToStr(const Value: Int64): string;
- var
- FirstDigitPos: Integer;
- begin
- Result := IntToStr(Value, FirstDigitPos);
- end;
- function TJclNumericFormat.IntToStr(const Value: Int64; out FirstDigitPos: Integer): string;
- const
- MaxResultLen = 64 + 63 + 1; // max. digits + max. group separators + sign
- var
- Remainder: Int64;
- I, N: Integer;
- Chars, Digits: Cardinal;
- LoopFinished, HasSign, SpacePadding: Boolean;
- begin
- SpacePadding := PaddingChar = ' ';
- HasSign := ShowSign(Value);
- Chars := MaxResultLen;
- if Width > Chars then
- Chars := Width;
- Result := StrRepeatChar(' ', Chars);
- Remainder := Abs(Value);
- Digits := 0;
- Chars := 0;
- if HasSign then
- Chars := 1;
- I := MaxResultLen;
- while True do
- begin
- N := Remainder mod Base;
- Remainder := Remainder div Base;
- if N > 9 then
- Result[I] := Chr(Ord('A') + N - 10)
- else
- Result[I] := Chr(Ord('0') + N);
- Dec(I);
- Inc(Digits);
- Inc(Chars);
- if (Remainder = 0) and (SpacePadding or (Chars >= Width)) then
- Break;
- if (Digits = DigitBlockSize) then
- begin
- Inc(Chars);
- LoopFinished := (Remainder = 0) and (Chars = Width);
- if LoopFinished then
- Result[I] := ' '
- else
- Result[I] := DigitBlockSeparator;
- Dec(I);
- if LoopFinished then
- Break;
- Digits := 0;
- end;
- end;
- FirstDigitPos := I + 1;
- if HasSign then
- Result[I] := SignChar(Value)
- else
- Inc(I);
- N := MaxResultLen - Width + 1;
- if N < I then
- I := N;
- Result := Copy(Result, I, MaxResultLen);
- Dec(FirstDigitPos, I - 1);
- end;
- procedure TJclNumericFormat.SetBase(const Value: TNumericSystemBase);
- begin
- FBase := Value;
- SetPrecision(FWantedPrecision);
- end;
- procedure TJclNumericFormat.SetExpDivision(const Value: Integer);
- begin
- if Value <= 1 then
- FExpDivision := 1
- else
- // see TODO in GetMantissaExp
- if Value > 12 then
- FExpDivision := 12
- else
- FExpDivision := Value;
- end;
- procedure TJclNumericFormat.SetPrecision(const Value: TDigitCount);
- begin
- FWantedPrecision := Value;
- // Do not display more digits than Float precision justifies
- if Base = 2 then
- FPrecision := BinaryPrecision
- else
- FPrecision := Trunc(BinaryPrecision / LogBase2(Base));
- if Value < FPrecision then
- FPrecision := Value;
- end;
- function TJclNumericFormat.Sign(Value: Char): Integer;
- begin
- Result := 0;
- if Value = FSignChars[False] then
- Result := -1;
- if Value = FSignChars[True] then
- Result := +1;
- end;
- function TJclNumericFormat.StrToInt(const Value: string): Int64;
- var
- I, N: Integer;
- C: Char;
- begin
- Result := 0;
- I := 1;
- if (Length(Value) >= I)
- and ((Value[I] = '+') or (Value[I] = '-')) then
- Inc(I);
- for I := I to Length(Value) do
- begin
- C := Value[I];
- if C = DigitBlockSeparator then
- Continue
- else
- begin
- N := CharHex(C);
- if (N = $FF) or (N >= Base) then
- InvalidDigit(C);
- Result := Result * Base + N;
- end;
- end;
- if Value[1] = '-' then
- Result := -Result;
- end;
- function TJclNumericFormat.ShowSign(const Value: Float): Boolean;
- begin
- Result := FShowPositiveSign or (Value < 0);
- end;
- function TJclNumericFormat.ShowSign(const Value: Int64): Boolean;
- begin
- Result := FShowPositiveSign or (Value < 0);
- end;
- function TJclNumericFormat.SignChar(const Value: Float): Char;
- begin
- Result := FSignChars[Value >= 0];
- end;
- function TJclNumericFormat.SignChar(const Value: Int64): Char;
- begin
- Result := FSignChars[Value >= 0];
- end;
- function TJclNumericFormat.GetNegativeSign: Char;
- begin
- Result := FSignChars[False];
- end;
- function TJclNumericFormat.GetPositiveSign: Char;
- begin
- Result := FSignChars[True];
- end;
- procedure TJclNumericFormat.SetNegativeSign(const Value: Char);
- begin
- FSignChars[False] := Value;
- end;
- procedure TJclNumericFormat.SetPositiveSign(const Value: Char);
- begin
- FSignChars[True] := Value;
- end;
- //=== Child processes ========================================================
- const
- BufferSize = 255;
- type
- TBuffer = array [0..BufferSize] of AnsiChar;
- TPipeInfo = record
- PipeRead, PipeWrite: THandle;
- Buffer: TBuffer;
- Line: string;
- TextHandler: TTextHandler;
- RawOutput: Boolean;
- AutoConvertOem: Boolean;
- Event: TJclEvent;
- end;
- PPipeInfo = ^TPipeInfo;
- // MuteCRTerminatedLines was "outsourced" from Win32ExecAndRedirectOutput
- function InternalExecuteMuteCRTerminatedLines(const RawOutput: string): string;
- const
- Delta = 1024;
- var
- BufPos, OutPos, LfPos, EndPos: Integer;
- C: Char;
- begin
- SetLength(Result, Length(RawOutput));
- OutPos := 1;
- LfPos := OutPos;
- EndPos := OutPos;
- for BufPos := 1 to Length(RawOutput) do
- begin
- if OutPos >= Length(Result)-2 then
- SetLength(Result, Length(Result) + Delta);
- C := RawOutput[BufPos];
- case C of
- NativeCarriageReturn:
- OutPos := LfPos;
- NativeLineFeed:
- begin
- OutPos := EndPos;
- Result[OutPos] := NativeCarriageReturn;
- Inc(OutPos);
- Result[OutPos] := C;
- Inc(OutPos);
- EndPos := OutPos;
- LfPos := OutPos;
- end;
- else
- Result[OutPos] := C;
- Inc(OutPos);
- EndPos := OutPos;
- end;
- end;
- SetLength(Result, OutPos - 1);
- end;
- procedure InternalExecuteProcessLine(const PipeInfo: TPipeInfo; LineEnd: Integer);
- begin
- if PipeInfo.RawOutput or (PipeInfo.Line[LineEnd] <> NativeCarriageReturn) then
- begin
- while (LineEnd > 0) and CharIsReturn(PipeInfo.Line[LineEnd]) do
- Dec(LineEnd);
- PipeInfo.TextHandler(Copy(PipeInfo.Line, 1, LineEnd));
- end;
- end;
- procedure InternalExecuteProcessBuffer(var PipeInfo: TPipeInfo; PipeBytesRead: Cardinal);
- var
- CR, LF: Integer;
- {$IFDEF MSWINDOWS}
- LineLen, Len: Integer;
- {$ENDIF MSWINDOWS}
- S: AnsiString;
- begin
- {$IFDEF MSWINDOWS}
- if PipeInfo.AutoConvertOem then
- begin
- {$IFDEF UNICODE}
- Len := MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, nil, 0);
- LineLen := Length(PipeInfo.Line);
- // Convert directly into the PipeInfo.Line string
- SetLength(PipeInfo.Line, LineLen + Len);
- MultiByteToWideChar(CP_OEMCP, 0, PipeInfo.Buffer, PipeBytesRead, PChar(PipeInfo.Line) + LineLen, Len);
- {$ELSE}
- Len := PipeBytesRead;
- LineLen := Length(PipeInfo.Line);
- // Convert directly into the PipeInfo.Line string
- SetLength(PipeInfo.Line, LineLen + Len);
- OemToAnsiBuff(PipeInfo.Buffer, PAnsiChar(PipeInfo.Line) + LineLen, PipeBytesRead);
- {$ENDIF UNICODE}
- end
- else
- {$ENDIF MSWINDOWS}
- begin
- SetString(S, PipeInfo.Buffer, PipeBytesRead); // interpret as ANSI
- {$IFDEF UNICODE}
- PipeInfo.Line := PipeInfo.Line + string(S); // ANSI => UNICODE
- {$ELSE}
- PipeInfo.Line := PipeInfo.Line + S;
- {$ENDIF UNICODE}
- end;
- if Assigned(PipeInfo.TextHandler) then
- repeat
- CR := Pos(NativeCarriageReturn, PipeInfo.Line);
- if CR = Length(PipeInfo.Line) then
- CR := 0; // line feed at CR + 1 might be missing
- LF := Pos(NativeLineFeed, PipeInfo.Line);
- if (CR > 0) and ((LF > CR + 1) or (LF = 0)) then
- LF := CR; // accept CR as line end
- if LF > 0 then
- begin
- InternalExecuteProcessLine(PipeInfo, LF);
- Delete(PipeInfo.Line, 1, LF);
- end;
- until LF = 0;
- end;
- procedure InternalExecuteReadPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
- var
- NullDWORD: ^DWORD; // XE4 broke PDWORD
- Res: DWORD;
- begin
- NullDWORD := nil;
- if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], BufferSize, NullDWORD^, @Overlapped) then
- begin
- Res := GetLastError;
- case Res of
- ERROR_BROKEN_PIPE:
- begin
- CloseHandle(PipeInfo.PipeRead);
- PipeInfo.PipeRead := 0;
- end;
- ERROR_IO_PENDING:
- ;
- else
- {$IFDEF DELPHI11_UP}
- RaiseLastOSError(Res);
- {$ELSE}
- RaiseLastOSError;
- {$ENDIF DELPHI11_UP}
- end;
- end;
- end;
- procedure InternalExecuteHandlePipeEvent(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
- var
- PipeBytesRead: DWORD;
- begin
- if GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, False) then
- begin
- InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
- // automatically launch the next read
- InternalExecuteReadPipe(PipeInfo, Overlapped);
- end
- else
- if GetLastError = ERROR_BROKEN_PIPE then
- begin
- CloseHandle(PipeInfo.PipeRead);
- PipeInfo.PipeRead := 0;
- end
- else
- RaiseLastOSError;
- end;
- procedure InternalExecuteFlushPipe(var PipeInfo: TPipeInfo; var Overlapped: TOverlapped);
- var
- PipeBytesRead: DWORD;
- begin
- CancelIo(PipeInfo.PipeRead);
- GetOverlappedResult(PipeInfo.PipeRead, Overlapped, PipeBytesRead, True);
- if PipeBytesRead > 0 then
- InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
- while PeekNamedPipe(PipeInfo.PipeRead, nil, 0, nil, @PipeBytesRead, nil) and (PipeBytesRead > 0) do
- begin
- if PipeBytesRead > BufferSize then
- PipeBytesRead := BufferSize;
- if not ReadFile(PipeInfo.PipeRead, PipeInfo.Buffer[0], PipeBytesRead, PipeBytesRead, nil) then
- RaiseLastOSError;
- InternalExecuteProcessBuffer(PipeInfo, PipeBytesRead);
- end;
- end;
- var
- AsyncPipeCounter: Integer;
- // CreateAsyncPipe creates a pipe that uses overlapped reading.
- function CreateAsyncPipe(var hReadPipe, hWritePipe: THandle;
- lpPipeAttributes: PSecurityAttributes; nSize: DWORD): BOOL;
- var
- PipeName: string;
- Error: DWORD;
- PipeReadHandle, PipeWriteHandle: THandle;
- begin
- Result := False;
- if (@hReadPipe = nil) or (@hWritePipe = nil) then
- begin
- SetLastError(ERROR_INVALID_PARAMETER);
- Exit;
- end;
- if nSize = 0 then
- nSize := 4096;
- InterlockedIncrement(AsyncPipeCounter);
- // In some (not so) rare instances there is a race condition
- // where the counter is the same for two threads at the same
- // time. This makes the CreateNamedPipe call below fail
- // because of the limit set to 1 in the call.
- // So, to be sure this call succeeds, we put both the process
- // and thread id in the name of the pipe.
- // This was found to happen while simply starting 7 instances
- // of the same exe file in parallel.
- PipeName := Format('\\.\Pipe\AsyncAnonPipe.%.8x.%.8x.%.8x', [GetCurrentProcessId, GetCurrentThreadId, AsyncPipeCounter]);
- PipeReadHandle := CreateNamedPipe(PChar(PipeName), PIPE_ACCESS_INBOUND or FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE or PIPE_WAIT, 1, nSize, nSize, 120 * 1000, lpPipeAttributes);
- if PipeReadHandle = INVALID_HANDLE_VALUE then
- Exit;
- PipeWriteHandle := CreateFile(PChar(PipeName), GENERIC_WRITE, 0, lpPipeAttributes, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL {or FILE_FLAG_OVERLAPPED}, 0);
- if PipeWriteHandle = INVALID_HANDLE_VALUE then
- begin
- Error := GetLastError;
- CloseHandle(PipeReadHandle);
- SetLastError(Error);
- Exit;
- end;
- hReadPipe := PipeReadHandle;
- hWritePipe := PipeWriteHandle;
- Result := True;
- end;
- const
- BELOW_NORMAL_PRIORITY_CLASS = $00004000;
- ABOVE_NORMAL_PRIORITY_CLASS = $00008000;
- ProcessPriorities: array [TJclProcessPriority] of DWORD =
- (IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS);
- { TJclExecuteCmdProcessOptions }
- constructor TJclExecuteCmdProcessOptions.Create(const ACommandLine: string);
- begin
- inherited Create;
- FCommandLine := ACommandLine;
- FAutoConvertOem := True;
- FProcessPriority := ppNormal;
- end;
- function ExecuteCmdProcess(Options: TJclExecuteCmdProcessOptions): Boolean;
- var
- OutPipeInfo, ErrorPipeInfo: TPipeInfo;
- Index: Cardinal;
- {$IFDEF MSWINDOWS}
- const
- StartupVisibilityFlags: array[TStartupVisibility] of DWORD = (SW_HIDE, SW_SHOW, SW_SHOWDEFAULT);
- var
- StartupInfo: TStartupInfo;
- ProcessInfo: TProcessInformation;
- SecurityAttr: TSecurityAttributes;
- OutOverlapped, ErrorOverlapped: TOverlapped;
- ProcessEvent: TJclDispatcherObject;
- WaitEvents: array of TJclDispatcherObject;
- InternalAbort: Boolean;
- LastError: DWORD;
- CommandLine: string;
- AbortPtr: PBoolean;
- Flags: DWORD;
- begin
- Result := False;
- // hack to pass a null reference to the parameter lpNumberOfBytesRead of ReadFile
- Options.FExitCode := $FFFFFFFF;
- SecurityAttr.nLength := SizeOf(SecurityAttr);
- SecurityAttr.lpSecurityDescriptor := nil;
- SecurityAttr.bInheritHandle := True;
- ResetMemory(OutPipeInfo, SizeOf(OutPipeInfo));
- OutPipeInfo.TextHandler := Options.OutputLineCallback;
- OutPipeInfo.RawOutput := Options.RawOutput;
- OutPipeInfo.AutoConvertOem := Options.AutoConvertOem;
- if not CreateAsyncPipe(OutPipeInfo.PipeRead, OutPipeInfo.PipeWrite, @SecurityAttr, 0) then
- begin
- Options.FExitCode := GetLastError;
- Exit;
- end;
- OutPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});
- ResetMemory(ErrorPipeInfo, SizeOf(ErrorPipeInfo));
- if not Options.MergeError then
- begin
- ErrorPipeInfo.TextHandler := Options.ErrorLineCallback;
- ErrorPipeInfo.RawOutput := Options.RawError;
- ErrorPipeInfo.AutoConvertOem := Options.AutoConvertOem;
- if not CreateAsyncPipe(ErrorPipeInfo.PipeRead, ErrorPipeInfo.PipeWrite, @SecurityAttr, 0) then
- begin
- Options.FExitCode := GetLastError;
- CloseHandle(OutPipeInfo.PipeWrite);
- CloseHandle(OutPipeInfo.PipeRead);
- OutPipeInfo.Event.Free;
- Exit;
- end;
- ErrorPipeInfo.Event := TJclEvent.Create(@SecurityAttr, False {automatic reset}, False {not flagged}, '' {anonymous});
- end;
- ResetMemory(StartupInfo, SizeOf(TStartupInfo));
- StartupInfo.cb := SizeOf(TStartupInfo);
- StartupInfo.dwFlags := STARTF_USESTDHANDLES;
- if Options.StartupVisibility <> svNotSet then
- begin
- StartupInfo.dwFlags := StartupInfo.dwFlags or STARTF_USESHOWWINDOW;
- StartupInfo.wShowWindow := StartupVisibilityFlags[Options.StartupVisibility];
- end;
- StartupInfo.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
- StartupInfo.hStdOutput := OutPipeInfo.PipeWrite;
- if Options.MergeError then
- StartupInfo.hStdError := OutPipeInfo.PipeWrite
- else
- StartupInfo.hStdError := ErrorPipeInfo.PipeWrite;
- CommandLine := Options.CommandLine;
- UniqueString(CommandLine); // CommandLine must be in a writable memory block
- ResetMemory(ProcessInfo, SizeOf(ProcessInfo));
- ProcessEvent := nil;
- try
- Flags := Options.CreateProcessFlags and not (NORMAL_PRIORITY_CLASS or IDLE_PRIORITY_CLASS or
- HIGH_PRIORITY_CLASS or REALTIME_PRIORITY_CLASS);
- Flags := Flags or ProcessPriorities[Options.ProcessPriority];
- if Assigned(Options.BeforeResume) then
- Flags := Flags or CREATE_SUSPENDED;
- if CreateProcess(nil, PChar(CommandLine), nil, nil, True, Flags,
- nil, nil, StartupInfo, ProcessInfo) then
- begin
- Result := True;
- try
- try
- if Assigned(Options.BeforeResume) then
- Options.BeforeResume(ProcessInfo);
- finally
- if Flags and CREATE_SUSPENDED <> 0 then // CREATE_SUSPENDED may also have come from CreateProcessFlags
- ResumeThread(ProcessInfo.hThread);
- end;
- // init out and error events
- CloseHandle(OutPipeInfo.PipeWrite);
- OutPipeInfo.PipeWrite := 0;
- if not Options.MergeError then
- begin
- CloseHandle(ErrorPipeInfo.PipeWrite);
- ErrorPipeInfo.PipeWrite := 0;
- end;
- InternalAbort := False;
- AbortPtr := Options.AbortPtr;
- if AbortPtr <> nil then
- AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}False{$IFDEF FPC}){$ENDIF}
- else
- AbortPtr := @InternalAbort;
- // init the array of events to wait for
- ProcessEvent := TJclDispatcherObject.Attach(ProcessInfo.hProcess);
- SetLength(WaitEvents, 2);
- // add the process first
- WaitEvents[0] := ProcessEvent;
- // add the output event
- WaitEvents[1] := OutPipeInfo.Event;
- // add the error event
- if not Options.MergeError then
- begin
- SetLength(WaitEvents, 3);
- WaitEvents[2] := ErrorPipeInfo.Event;
- end;
- // add the abort event if any
- if Options.AbortEvent <> nil then
- begin
- Options.AbortEvent.ResetEvent;
- Index := Length(WaitEvents);
- SetLength(WaitEvents, Index + 1);
- WaitEvents[Index] := Options.AbortEvent;
- end;
- // init the asynchronous reads
- ResetMemory(OutOverlapped, SizeOf(OutOverlapped));
- OutOverlapped.hEvent := OutPipeInfo.Event.Handle;
- InternalExecuteReadPipe(OutPipeInfo, OutOverlapped);
- if not Options.MergeError then
- begin
- ResetMemory(ErrorOverlapped, SizeOf(ErrorOverlapped));
- ErrorOverlapped.hEvent := ErrorPipeInfo.Event.Handle;
- InternalExecuteReadPipe(ErrorPipeInfo, ErrorOverlapped);
- end;
- // event based loop
- while not {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} do
- begin
- Index := WaitAlertableForMultipleObjects(WaitEvents, False, INFINITE);
- if Index = WAIT_OBJECT_0 then
- // the subprocess has ended
- Break
- else
- if Index = (WAIT_OBJECT_0 + 1) then
- begin
- // event on output
- InternalExecuteHandlePipeEvent(OutPipeInfo, OutOverlapped);
- end
- else
- if (Index = (WAIT_OBJECT_0 + 2)) and not Options.MergeError then
- begin
- // event on error
- InternalExecuteHandlePipeEvent(ErrorPipeInfo, ErrorOverlapped);
- end
- else
- if ((Index = (WAIT_OBJECT_0 + 2)) and Options.MergeError) or
- ((Index = (WAIT_OBJECT_0 + 3)) and not Options.MergeError) then
- // event on abort
- AbortPtr^ := {$IFDEF FPC}Byte({$ENDIF}True{$IFDEF FPC}){$ENDIF}
- else
- {$IFDEF DELPHI11_UP}
- RaiseLastOSError(Index);
- {$ELSE}
- RaiseLastOSError;
- {$ENDIF DELPHI11_UP}
- end;
- if {$IFDEF FPC}Boolean({$ENDIF}AbortPtr^{$IFDEF FPC}){$ENDIF} then
- TerminateProcess(ProcessEvent.Handle, Cardinal(ABORT_EXIT_CODE));
- if (ProcessEvent.WaitForever = {$IFDEF RTL280_UP}TJclWaitResult.{$ENDIF RTL280_UP}wrSignaled) and not GetExitCodeProcess(ProcessEvent.Handle, Options.FExitCode) then
- Options.FExitCode := $FFFFFFFF;
- CloseHandle(ProcessInfo.hThread);
- ProcessInfo.hThread := 0;
- if OutPipeInfo.PipeRead <> 0 then
- // read data remaining in output pipe
- InternalExecuteFlushPipe(OutPipeinfo, OutOverlapped);
- if not Options.MergeError and (ErrorPipeInfo.PipeRead <> 0) then
- // read data remaining in error pipe
- InternalExecuteFlushPipe(ErrorPipeInfo, ErrorOverlapped);
- except
- // always terminate process in case of an exception.
- // This is especially useful when an exception occurred in one of
- // the texthandler but only do it if the process actually started,
- // this prevents eating up the last error value by calling those
- // three functions with an invalid handle
- // Note that we don't do it in the finally block because these
- // calls would also then eat up the last error value which we tried
- // to avoid in the first place
- if ProcessInfo.hProcess <> 0 then
- begin
- TerminateProcess(ProcessInfo.hProcess, Cardinal(ABORT_EXIT_CODE));
- WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
- GetExitCodeProcess(ProcessInfo.hProcess, Options.FExitCode);
- end;
- raise;
- end;
- end;
- finally
- LastError := GetLastError;
- try
- if OutPipeInfo.PipeRead <> 0 then
- CloseHandle(OutPipeInfo.PipeRead);
- if OutPipeInfo.PipeWrite <> 0 then
- CloseHandle(OutPipeInfo.PipeWrite);
- if ErrorPipeInfo.PipeRead <> 0 then
- CloseHandle(ErrorPipeInfo.PipeRead);
- if ErrorPipeInfo.PipeWrite <> 0 then
- CloseHandle(ErrorPipeInfo.PipeWrite);
- if ProcessInfo.hThread <> 0 then
- CloseHandle(ProcessInfo.hThread);
- if Assigned(ProcessEvent) then
- ProcessEvent.Free // this calls CloseHandle(ProcessInfo.hProcess)
- else if ProcessInfo.hProcess <> 0 then
- CloseHandle(ProcessInfo.hProcess);
- OutPipeInfo.Event.Free;
- ErrorPipeInfo.Event.Free;
- finally
- SetLastError(LastError);
- end;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- var
- PipeBytesRead: Cardinal;
- Pipe: PIOFile;
- Cmd: string;
- begin
- Cmd := Format('%s 2>&1', [Options.CommandLine]);
- Pipe := nil;
- try
- Pipe := Libc.popen(PChar(Cmd), 'r');
- { TODO : handle Abort }
- repeat
- PipeBytesRead := fread_unlocked(@OutBuffer, 1, BufferSize, Pipe);
- if PipeBytesRead > 0 then
- ProcessBuffer(OutBuffer, OutLine, PipeBytesRead);
- until PipeBytesRead = 0;
- Result := pclose(Pipe);
- Pipe := nil;
- wait(nil);
- finally
- if Pipe <> nil then
- pclose(Pipe);
- wait(nil);
- end;
- {$ENDIF UNIX}
- if OutPipeInfo.Line <> '' then
- if Assigned(OutPipeInfo.TextHandler) then
- // output wasn't terminated by a line feed...
- // (shouldn't happen, but you never know)
- InternalExecuteProcessLine(OutPipeInfo, Length(OutPipeInfo.Line))
- else
- if Options.RawOutput then
- Options.FOutput := OutPipeInfo.Line
- else
- Options.FOutput := InternalExecuteMuteCRTerminatedLines(OutPipeInfo.Line);
- if ErrorPipeInfo.Line <> '' then
- if Assigned(ErrorPipeInfo.TextHandler) then
- // error wasn't terminated by a line feed...
- // (shouldn't happen, but you never know)
- InternalExecuteProcessLine(ErrorPipeInfo, Length(ErrorPipeInfo.Line))
- else
- if Options.RawError then
- Options.FError := ErrorPipeInfo.Line
- else
- Options.FError := InternalExecuteMuteCRTerminatedLines(ErrorPipeInfo.Line);
- end;
- function InternalExecute(CommandLine: string; AbortPtr: PBoolean; AbortEvent: TJclEvent;
- var Output: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;
- MergeError: Boolean; var Error: string; ErrorLineCallback: TTextHandler; RawError: Boolean;
- ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Options: TJclExecuteCmdProcessOptions;
- begin
- Options := TJclExecuteCmdProcessOptions.Create(CommandLine);
- try
- Options.AutoConvertOem := AutoConvertOem;
- Options.AbortPtr := AbortPtr;
- Options.AbortEvent := AbortEvent;
- Options.OutputLineCallback := OutputLineCallback;
- Options.RawOutput := RawOutput;
- Options.MergeError := MergeError;
- Options.ErrorLineCallback := ErrorLineCallback;
- Options.RawError := RawError;
- Options.ProcessPriority := ProcessPriority;
- ExecuteCmdProcess(Options);
- Result := Options.ExitCode;
- // Append => backward compatiblity
- Output := Output + Options.Output;
- Error := Error + Options.Error;
- finally
- Options.Free;
- end;
- end;
- { TODO -cHelp :
- RawOutput: Do not process isolated carriage returns (#13).
- That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }
- function Execute(const CommandLine: string; var Output: string; RawOutput: Boolean;
- AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Error: string;
- begin
- Error := '';
- Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, True, Error,
- nil, False, ProcessPriority, AutoConvertOem);
- end;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output: string; RawOutput: Boolean;
- ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Error: string;
- begin
- Error := '';
- Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, True, Error,
- nil, False, ProcessPriority, AutoConvertOem);
- end;
- { TODO -cHelp :
- Author: Robert Rossmair
- OutputLineCallback called once per line of output. }
- function Execute(const CommandLine: string; OutputLineCallback: TTextHandler; RawOutput: Boolean;
- AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Output, Error: string;
- begin
- Output := '';
- Error := '';
- Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, True, Error,
- nil, False, ProcessPriority, AutoConvertOem);
- end;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback: TTextHandler; RawOutput: Boolean;
- ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Output, Error: string;
- begin
- Output := '';
- Error := '';
- Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, True, Error,
- nil, False, ProcessPriority, AutoConvertOem);
- end;
- { TODO -cHelp :
- RawOutput: Do not process isolated carriage returns (#13).
- That is, for RawOutput = False, lines not terminated by a line feed (#10) are deleted from Output. }
- function Execute(const CommandLine: string; var Output, Error: string; RawOutput, RawError: Boolean;
- AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- begin
- Result := InternalExecute(CommandLine, AbortPtr, nil, Output, nil, RawOutput, False, Error,
- nil, RawError, ProcessPriority, AutoConvertOem);
- end;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent; var Output, Error: string;
- RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- begin
- Result := InternalExecute(CommandLine, nil, AbortEvent, Output, nil, RawOutput, False, Error,
- nil, RawError, ProcessPriority, AutoConvertOem);
- end;
- { TODO -cHelp :
- Author: Robert Rossmair
- OutputLineCallback called once per line of output. }
- function Execute(const CommandLine: string; OutputLineCallback, ErrorLineCallback: TTextHandler;
- RawOutput, RawError: Boolean; AbortPtr: PBoolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Output, Error: string;
- begin
- Output := '';
- Error := '';
- Result := InternalExecute(CommandLine, AbortPtr, nil, Output, OutputLineCallback, RawOutput, False, Error,
- ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);
- end;
- function Execute(const CommandLine: string; AbortEvent: TJclEvent; OutputLineCallback, ErrorLineCallback: TTextHandler;
- RawOutput, RawError: Boolean; ProcessPriority: TJclProcessPriority; AutoConvertOem: Boolean): Cardinal;
- var
- Output, Error: string;
- begin
- Output := '';
- Error := '';
- Result := InternalExecute(CommandLine, nil, AbortEvent, Output, OutputLineCallback, RawOutput, False, Error,
- ErrorLineCallback, RawError, ProcessPriority, AutoConvertOem);
- end;
- //=== { TJclCommandLineTool } ================================================
- constructor TJclCommandLineTool.Create(const AExeName: string);
- begin
- inherited Create;
- FOptions := TStringList.Create;
- FExeName := AExeName;
- end;
- destructor TJclCommandLineTool.Destroy;
- begin
- FreeAndNil(FOptions);
- inherited Destroy;
- end;
- procedure TJclCommandLineTool.AddPathOption(const Option, Path: string);
- var
- S: string;
- begin
- S := PathRemoveSeparator(Path);
- {$IFDEF MSWINDOWS}
- S := AnsiLowerCase(S); // file names are case insensitive
- {$ENDIF MSWINDOWS}
- S := Format('-%s%s', [Option, S]);
- // avoid duplicate entries (note that search is case sensitive)
- if GetOptions.IndexOf(S) = -1 then
- GetOptions.Add(S);
- end;
- function TJclCommandLineTool.Execute(const CommandLine: string): Boolean;
- begin
- if Assigned(FOutputCallback) then
- Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutputCallback) = 0
- else
- Result := JclSysUtils.Execute(Format('"%s" %s', [ExeName, CommandLine]), FOutput) = 0;
- end;
- function TJclCommandLineTool.GetExeName: string;
- begin
- Result := FExeName;
- end;
- function TJclCommandLineTool.GetOptions: TStrings;
- begin
- Result := FOptions;
- end;
- function TJclCommandLineTool.GetOutput: string;
- begin
- Result := FOutput;
- end;
- function TJclCommandLineTool.GetOutputCallback: TTextHandler;
- begin
- Result := FOutputCallback;
- end;
- procedure TJclCommandLineTool.SetOutputCallback(const CallbackMethod: TTextHandler);
- begin
- FOutputCallback := CallbackMethod;
- end;
- //=== Console Utilities ======================================================
- function ReadKey: Char;
- {$IFDEF MSWINDOWS}
- { TODO -cHelp : Contributor: Robert Rossmair }
- var
- Console: TJclConsole;
- InputMode: TJclConsoleInputModes;
- begin
- Console := TJclConsole.Default;
- InputMode := Console.Input.Mode;
- Console.Input.Mode := [imProcessed];
- Console.Input.Clear;
- Result := Char(Console.Input.GetEvent.Event.KeyEvent.AsciiChar);
- Console.Input.Mode := InputMode;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- { TODO -cHelp : Donator: Wayne Sherman }
- var
- ReadFileDescriptor: TFDSet;
- TimeVal: TTimeVal;
- SaveTerminalSettings: TTermIos;
- RawTerminalSettings: TTermIos;
- begin
- Result := #0;
- //Save Original Terminal Settings
- tcgetattr(stdin, SaveTerminalSettings);
- tcgetattr(stdin, RawTerminalSettings);
- //Put Terminal in RAW mode
- cfmakeraw(RawTerminalSettings);
- tcsetattr(stdin, TCSANOW, RawTerminalSettings);
- try
- //Setup file I/O descriptor for STDIN
- FD_ZERO(ReadFileDescriptor);
- FD_SET(stdin, ReadFileDescriptor);
- TimeVal.tv_sec := High(LongInt); //wait forever
- TimeVal.tv_usec := 0;
- //clear keyboard buffer first
- TCFlush(stdin, TCIFLUSH);
- //wait for a key to be pressed
- if select(1, @ReadFileDescriptor, nil, nil, @TimeVal) > 0 then
- begin
- //Now read the character
- Result := Char(getchar);
- end
- else
- raise EJclError.CreateRes(@RsReadKeyError);
- finally
- //Restore Original Terminal Settings
- tcsetattr(stdin, TCSANOW, SaveTerminalSettings);
- end;
- end;
- {$ENDIF UNIX}
- {$ENDIF ~WINSCP}
- //=== Loading of modules (DLLs) ==============================================
- function LoadModule(var Module: TModuleHandle; FileName: string): Boolean;
- {$IFDEF MSWINDOWS}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := SafeLoadLibrary(FileName);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := dlopen(PChar(FileName), RTLD_NOW);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF UNIX}
- function LoadModuleEx(var Module: TModuleHandle; FileName: string; Flags: Cardinal): Boolean;
- {$IFDEF MSWINDOWS}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := LoadLibraryEx(PChar(FileName), 0, Flags); // SafeLoadLibrary?
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- begin
- if Module = INVALID_MODULEHANDLE_VALUE then
- Module := dlopen(PChar(FileName), Flags);
- Result := Module <> INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF UNIX}
- procedure UnloadModule(var Module: TModuleHandle);
- {$IFDEF MSWINDOWS}
- begin
- if Module <> INVALID_MODULEHANDLE_VALUE then
- FreeLibrary(Module);
- Module := INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- begin
- if Module <> INVALID_MODULEHANDLE_VALUE then
- dlclose(Pointer(Module));
- Module := INVALID_MODULEHANDLE_VALUE;
- end;
- {$ENDIF UNIX}
- function GetModuleSymbol(Module: TModuleHandle; SymbolName: string): Pointer;
- {$IFDEF MSWINDOWS}
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := GetProcAddress(Module, PChar(SymbolName));
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := dlsym(Module, PChar(SymbolName));
- end;
- {$ENDIF UNIX}
- function GetModuleSymbolEx(Module: TModuleHandle; SymbolName: string; var Accu: Boolean): Pointer;
- {$IFDEF MSWINDOWS}
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := GetProcAddress(Module, PChar(SymbolName));
- Accu := Accu and (Result <> nil);
- end;
- {$ENDIF MSWINDOWS}
- {$IFDEF UNIX}
- begin
- Result := nil;
- if Module <> INVALID_MODULEHANDLE_VALUE then
- Result := dlsym(Module, PChar(SymbolName));
- Accu := Accu and (Result <> nil);
- end;
- {$ENDIF UNIX}
- function ReadModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Sym^, Buffer, Size);
- end;
- function WriteModuleData(Module: TModuleHandle; SymbolName: string; var Buffer; Size: Cardinal): Boolean;
- var
- Sym: Pointer;
- begin
- Result := True;
- Sym := GetModuleSymbolEx(Module, SymbolName, Result);
- if Result then
- Move(Buffer, Sym^, Size);
- end;
- //=== Conversion Utilities ===================================================
- const
- DefaultTrueBoolStr = 'True'; // DO NOT LOCALIZE
- DefaultFalseBoolStr = 'False'; // DO NOT LOCALIZE
- DefaultYesBoolStr = 'Yes'; // DO NOT LOCALIZE
- DefaultNoBoolStr = 'No'; // DO NOT LOCALIZE
- function StrToBoolean(const S: string): Boolean;
- var
- LowerCasedText: string;
- begin
- { TODO : Possibility to add localized strings, like in Delphi 7 }
- { TODO : Lower case constants }
- LowerCasedText := LowerCase(S);
- Result := ((S = '1') or
- (LowerCasedText = LowerCase(DefaultTrueBoolStr)) or (LowerCasedText = LowerCase(DefaultYesBoolStr))) or
- (LowerCasedText = LowerCase(DefaultTrueBoolStr[1])) or (LowerCasedText = LowerCase(DefaultYesBoolStr[1]));
- if not Result then
- begin
- Result := not ((S = '0') or
- (LowerCasedText = LowerCase(DefaultFalseBoolStr)) or (LowerCasedText = LowerCase(DefaultNoBoolStr)) or
- (LowerCasedText = LowerCase(DefaultFalseBoolStr[1])) or (LowerCasedText = LowerCase(DefaultNoBoolStr[1])));
- if Result then
- raise EJclConversionError.CreateResFmt(@RsStringToBoolean, [S]);
- end;
- end;
- function BooleanToStr(B: Boolean): string;
- begin
- if B then
- Result := DefaultTrueBoolStr
- else
- Result := DefaultFalseBoolStr;
- end;
- function IntToBool(I: Integer): Boolean;
- begin
- Result := I <> 0;
- end;
- function BoolToInt(B: Boolean): Integer;
- begin
- Result := Ord(B);
- end;
- function TryStrToUInt(const Value: string; out Res: Cardinal): Boolean;
- var i6: Int64;
- begin
- Result := false;
- if not TryStrToInt64(Value, i6) then exit;
- if ( i6 < Low(Res)) or ( i6 > High(Res)) then exit;
- Result := true;
- Res := i6;
- end;
- function StrToUIntDef(const Value: string; const Default: Cardinal): Cardinal;
- begin
- if not TryStrToUInt(Value, Result)
- then Result := Default;
- end;
- function StrToUInt(const Value: string): Cardinal;
- begin
- if not TryStrToUInt(Value, Result)
- then raise EConvertError.Create('"'+Value+'" is not within range of Cardinal data type');
- end;
- //=== RTL package information ================================================
- function SystemTObjectInstance: TJclAddr;
- begin
- Result := ModuleFromAddr(Pointer(System.TObject));
- end;
- function IsCompiledWithPackages: Boolean;
- begin
- Result := SystemTObjectInstance <> HInstance;
- end;
- //=== GUID ===================================================================
- function JclGUIDToString(const GUID: TGUID): string;
- begin
- Result := Format('{%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}',
- [GUID.D1, GUID.D2, GUID.D3, GUID.D4[0], GUID.D4[1], GUID.D4[2],
- GUID.D4[3], GUID.D4[4], GUID.D4[5], GUID.D4[6], GUID.D4[7]]);
- end;
- function JclStringToGUID(const S: string): TGUID;
- begin
- if (Length(S) <> 38) or (S[1] <> '{') or (S[10] <> '-') or (S[15] <> '-') or
- (S[20] <> '-') or (S[25] <> '-') or (S[38] <> '}') then
- raise EJclConversionError.CreateResFmt(@RsInvalidGUIDString, [S]);
- Result.D1 := StrToInt('$' + Copy(S, 2, 8));
- Result.D2 := StrToInt('$' + Copy(S, 11, 4));
- Result.D3 := StrToInt('$' + Copy(S, 16, 4));
- Result.D4[0] := StrToInt('$' + Copy(S, 21, 2));
- Result.D4[1] := StrToInt('$' + Copy(S, 23, 2));
- Result.D4[2] := StrToInt('$' + Copy(S, 26, 2));
- Result.D4[3] := StrToInt('$' + Copy(S, 28, 2));
- Result.D4[4] := StrToInt('$' + Copy(S, 30, 2));
- Result.D4[5] := StrToInt('$' + Copy(S, 32, 2));
- Result.D4[6] := StrToInt('$' + Copy(S, 34, 2));
- Result.D4[7] := StrToInt('$' + Copy(S, 36, 2));
- end;
- function GUIDEquals(const GUID1, GUID2: TGUID): Boolean;
- begin
- Result := (GUID1.D1 = GUID2.D1) and (GUID1.D2 = GUID2.D2) and (GUID1.D3 = GUID2.D3) and
- (GUID1.D4[0] = GUID2.D4[0]) and (GUID1.D4[1] = GUID2.D4[1]) and
- (GUID1.D4[2] = GUID2.D4[2]) and (GUID1.D4[3] = GUID2.D4[3]) and
- (GUID1.D4[4] = GUID2.D4[4]) and (GUID1.D4[5] = GUID2.D4[5]) and
- (GUID1.D4[6] = GUID2.D4[6]) and (GUID1.D4[7] = GUID2.D4[7]);
- end;
- // add items at the end
- procedure ListAddItems(var List: string; const Separator, Items: string);
- var
- StrList, NewItems: TStringList;
- Index: Integer;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- NewItems := TStringList.Create;
- try
- StrToStrings(Items, Separator, NewItems);
- for Index := 0 to NewItems.Count - 1 do
- StrList.Add(NewItems.Strings[Index]);
- List := StringsToStr(StrList, Separator);
- finally
- NewItems.Free;
- end;
- finally
- StrList.Free;
- end;
- end;
- // add items at the end if they are not present
- procedure ListIncludeItems(var List: string; const Separator, Items: string);
- var
- StrList, NewItems: TStringList;
- Index: Integer;
- Item: string;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- NewItems := TStringList.Create;
- try
- StrToStrings(Items, Separator, NewItems);
- for Index := 0 to NewItems.Count - 1 do
- begin
- Item := NewItems.Strings[Index];
- if StrList.IndexOf(Item) = -1 then
- StrList.Add(Item);
- end;
- List := StringsToStr(StrList, Separator);
- finally
- NewItems.Free;
- end;
- finally
- StrList.Free;
- end;
- end;
- // delete multiple items
- procedure ListRemoveItems(var List: string; const Separator, Items: string);
- var
- StrList, RemItems: TStringList;
- Index, Position: Integer;
- Item: string;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- RemItems := TStringList.Create;
- try
- StrToStrings(Items, Separator, RemItems, False);
- for Index := 0 to RemItems.Count - 1 do
- begin
- Item := RemItems.Strings[Index];
- repeat
- Position := StrList.IndexOf(Item);
- if Position >= 0 then
- StrList.Delete(Position);
- until Position < 0;
- end;
- List := StringsToStr(StrList, Separator);
- finally
- RemItems.Free;
- end;
- finally
- StrList.Free;
- end;
- end;
- // delete one item
- procedure ListDelItem(var List: string; const Separator: string; const Index: Integer);
- var
- StrList: TStringList;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- StrList.Delete(Index);
- List := StringsToStr(StrList, Separator);
- finally
- StrList.Free;
- end;
- end;
- // return the number of item
- function ListItemCount(const List, Separator: string): Integer;
- var
- StrList: TStringList;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- Result := StrList.Count;
- finally
- StrList.Free;
- end;
- end;
- // return the Nth item
- function ListGetItem(const List, Separator: string; const Index: Integer): string;
- var
- StrList: TStringList;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- Result := StrList.Strings[Index];
- finally
- StrList.Free;
- end;
- end;
- // set the Nth item
- procedure ListSetItem(var List: string; const Separator: string;
- const Index: Integer; const Value: string);
- var
- StrList: TStringList;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- StrList.Strings[Index] := Value;
- List := StringsToStr(StrList, Separator);
- finally
- StrList.Free;
- end;
- end;
- // return the index of an item
- function ListItemIndex(const List, Separator, Item: string): Integer;
- var
- StrList: TStringList;
- begin
- StrList := TStringList.Create;
- try
- StrToStrings(List, Separator, StrList, False);
- Result := StrList.IndexOf(Item);
- finally
- StrList.Free;
- end;
- end;
- //=== { TJclIntfCriticalSection } ============================================
- constructor TJclIntfCriticalSection.Create;
- begin
- inherited Create;
- FCriticalSection := TCriticalSection.Create;
- end;
- destructor TJclIntfCriticalSection.Destroy;
- begin
- FCriticalSection.Free;
- inherited Destroy;
- end;
- function TJclIntfCriticalSection._AddRef: Integer;
- begin
- FCriticalSection.Acquire;
- Result := -1;
- end;
- function TJclIntfCriticalSection._Release: Integer;
- begin
- FCriticalSection.Release;
- Result := -1;
- end;
- {$IFNDEF WINSCP}
- //=== { TJclSimpleLog } ======================================================
- {$IFDEF LINUX}
- const
- INVALID_HANDLE_VALUE = 0;
- {$ENDIF LINUX}
- constructor TJclSimpleLog.Create(const ALogFileName: string = '');
- begin
- if ALogFileName = '' then
- FLogFileName := CreateDefaultFileName
- else
- FLogFileName := ALogFileName;
- FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);
- FLoggingActive := True;
- end;
- function TJclSimpleLog.CreateDefaultFileName: string;
- begin
- Result := PathExtractFileDirFixed(ParamStr(0)) +
- PathExtractFileNameNoExt(ParamStr(0)) + '_Err.log';
- end;
- destructor TJclSimpleLog.Destroy;
- begin
- CloseLog;
- inherited Destroy;
- end;
- procedure TJclSimpleLog.ClearLog;
- var
- WasOpen: Boolean;
- begin
- WasOpen := LogOpen;
- if WasOpen then
- CloseLog;
- if not FileExists(FlogFileName) then
- Exit;
- FLogFileHandle := FileCreate(FLogFileName);
- FLogWasEmpty := True;
- if Not WasOpen then
- CloseLog;
- end;
- procedure TJclSimpleLog.CloseLog;
- begin
- if LogOpen then
- begin
- FileClose(FLogFileHandle);
- FLogFileHandle := TFileHandle(INVALID_HANDLE_VALUE);
- FLogWasEmpty := False;
- end;
- end;
- function TJclSimpleLog.GetLogOpen: Boolean;
- begin
- Result := DWORD_PTR(FLogFileHandle) <> INVALID_HANDLE_VALUE;
- end;
- procedure TJclSimpleLog.OpenLog;
- begin
- if not LogOpen then
- begin
- FLogFileHandle := FileOpen(FLogFileName, fmOpenWrite or fmShareDenyWrite);
- if LogOpen then
- FLogWasEmpty := FileSeek(FLogFileHandle, 0, soFromEnd) = 0
- else
- begin
- FLogFileHandle := FileCreate(FLogFileName);
- FLogWasEmpty := True;
- if LogOpen then
- FileWrite(FLogFileHandle, BOM_UTF8[0], Length(BOM_UTF8));
- end;
- end
- else
- FLogWasEmpty := False;
- end;
- procedure TJclSimpleLog.Write(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);
- var
- S: string;
- UTF8S: TUTF8String;
- SL: TStringList;
- I: Integer;
- WasOpen: Boolean;
- begin
- if LoggingActive then
- begin
- WasOpen := LogOpen;
- if not WasOpen then
- OpenLog;
- if LogOpen then
- begin
- SL := TStringList.Create;
- try
- SL.Text := Text;
- for I := 0 to SL.Count - 1 do
- begin
- S := StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));
- UTF8S := StringToUTF8(S);
- FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));
- end;
- finally
- SL.Free;
- end;
- // Keep the logfile Open when it was opened before and the KeepOpen is active
- if not (WasOpen and KeepOpen) then
- CloseLog;
- end;
- end;
- end;
- procedure TJclSimpleLog.Write(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);
- begin
- if Assigned(Strings) then
- Write(Strings.Text, Indent, KeepOpen);
- end;
- procedure TJclSimpleLog.TimeWrite(const Text: string; Indent: Integer = 0; KeepOpen: Boolean = true);
- var
- S: string;
- UTF8S: TUTF8String;
- SL: TStringList;
- I: Integer;
- WasOpen: Boolean;
- begin
- if LoggingActive then
- begin
- WasOpen := LogOpen;
- if not LogOpen then
- OpenLog;
- if LogOpen then
- begin
- SL := TStringList.Create;
- try
- SL.Text := Text;
- for I := 0 to SL.Count - 1 do
- begin
- if DateTimeFormatStr = '' then
- S := DateTimeToStr(Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]))
- else
- S := FormatDateTime( DateTimeFormatStr, Now)+' : '+StringOfChar(' ', Indent) + StrEnsureSuffix(NativeLineBreak, TrimRight(SL[I]));
- UTF8S := StringToUTF8(S);
- FileWrite(FLogFileHandle, UTF8S[1], Length(UTF8S));
- end;
- finally
- SL.Free;
- end;
- if Not WasOpen and Not KeepOpen then
- CloseLog;
- end;
- end;
- end;
- procedure TJclSimpleLog.TimeWrite(Strings: TStrings; Indent: Integer = 0; KeepOpen: Boolean = true);
- begin
- if Assigned(Strings) then
- TimeWrite(Strings.Text, Indent, KeepOpen);
- end;
- procedure TJclSimpleLog.WriteStamp(SeparatorLen: Integer = 0; KeepOpen: Boolean = true);
- var
- WasOpen: Boolean;
- begin
- if SeparatorLen <= 0 then
- SeparatorLen := 40;
- if LoggingActive then
- begin
- WasOpen := LogOpen;
- if not LogOpen then
- begin
- OpenLog;
- if LogOpen and not FLogWasEmpty then
- Write(NativeLineBreak);
- end;
- if LogOpen then
- begin
- Write(StrRepeat('=', SeparatorLen), 0, True);
- if DateTimeFormatStr = '' then
- Write(Format('= %-*s =', [SeparatorLen - 4, DateTimeToStr(Now)]), 0, True)
- else
- Write(Format('= %-*s =', [SeparatorLen - 4, FormatDateTime( DateTimeFormatStr, Now)]), 0, True);
- Write(StrRepeat('=', SeparatorLen), 0, True);
- if Not WasOpen and Not KeepOpen then
- CloseLog;
- end;
- end;
- end;
- procedure InitSimpleLog(const ALogFileName: string = ''; AOpenLog: Boolean = true);
- begin
- if Assigned(SimpleLog) then
- FreeAndNil(SimpleLog);
- SimpleLog := TJclSimpleLog.Create(ALogFileName);
- if AOpenLog then
- SimpleLog.OpenLog;
- end;
- {$ENDIF ~WINSCP}
- function TJclFormatSettings.GetCurrencyDecimals: Byte;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.CurrencyDecimals;
- {$ELSE}
- Result := SysUtils.CurrencyDecimals;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetCurrencyFormat: Byte;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.CurrencyFormat;
- {$ELSE}
- Result := SysUtils.CurrencyFormat;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetCurrencyString: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.CurrencyString;
- {$ELSE}
- Result := SysUtils.CurrencyString;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetDateSeparator: Char;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.DateSeparator;
- {$ELSE}
- Result := SysUtils.DateSeparator;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetDayNamesHighIndex: Integer;
- begin
- {$IFDEF RTL220_UP}
- Result := High(FormatSettings.LongDayNames);
- {$ELSE}
- Result := High(SysUtils.LongDayNames);
- {$ENDIF}
- end;
- function TJclFormatSettings.GetDayNamesLowIndex: Integer;
- begin
- {$IFDEF RTL220_UP}
- Result := Low(FormatSettings.LongDayNames);
- {$ELSE}
- Result := Low(SysUtils.LongDayNames);
- {$ENDIF}
- end;
- function TJclFormatSettings.GetDecimalSeparator: Char;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.DecimalSeparator;
- {$ELSE}
- Result := SysUtils.DecimalSeparator;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetListSeparator: Char;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ListSeparator;
- {$ELSE}
- Result := SysUtils.ListSeparator;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetLongDateFormat: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.LongDateFormat;
- {$ELSE}
- Result := SysUtils.LongDateFormat;
- {$ENDIF}
- end;
- { TJclFormatSettings }
- function TJclFormatSettings.GetLongDayNames(AIndex: Integer): string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.LongDayNames[AIndex];
- {$ELSE}
- Result := SysUtils.LongDayNames[AIndex];
- {$ENDIF}
- end;
- function TJclFormatSettings.GetLongMonthNames(AIndex: Integer): string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.LongMonthNames[AIndex];
- {$ELSE}
- Result := SysUtils.LongMonthNames[AIndex];
- {$ENDIF}
- end;
- function TJclFormatSettings.GetLongTimeFormat: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.LongTimeFormat;
- {$ELSE}
- Result := SysUtils.LongTimeFormat;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetMonthNamesHighIndex: Integer;
- begin
- {$IFDEF RTL220_UP}
- Result := High(FormatSettings.LongMonthNames);
- {$ELSE}
- Result := High(SysUtils.LongMonthNames);
- {$ENDIF}
- end;
- function TJclFormatSettings.GetMonthNamesLowIndex: Integer;
- begin
- {$IFDEF RTL220_UP}
- Result := Low(FormatSettings.LongMonthNames);
- {$ELSE}
- Result := Low(SysUtils.LongMonthNames);
- {$ENDIF}
- end;
- function TJclFormatSettings.GetNegCurrFormat: Byte;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.NegCurrFormat;
- {$ELSE}
- Result := SysUtils.NegCurrFormat;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetShortDateFormat: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ShortDateFormat;
- {$ELSE}
- Result := SysUtils.ShortDateFormat;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetShortDayNames(AIndex: Integer): string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ShortDayNames[AIndex];
- {$ELSE}
- Result := SysUtils.ShortDayNames[AIndex];
- {$ENDIF}
- end;
- function TJclFormatSettings.GetShortMonthNames(AIndex: Integer): string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ShortMonthNames[AIndex];
- {$ELSE}
- Result := SysUtils.ShortMonthNames[AIndex];
- {$ENDIF}
- end;
- function TJclFormatSettings.GetShortTimeFormat: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ShortTimeFormat;
- {$ELSE}
- Result := SysUtils.ShortTimeFormat;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetThousandSeparator: Char;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.ThousandSeparator;
- {$ELSE}
- Result := SysUtils.ThousandSeparator;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetTimeAMString: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.TimeAMString;
- {$ELSE}
- Result := SysUtils.TimeAMString;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetTimePMString: string;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.TimePMString;
- {$ELSE}
- Result := SysUtils.TimePMString;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetTimeSeparator: Char;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.TimeSeparator;
- {$ELSE}
- Result := SysUtils.TimeSeparator;
- {$ENDIF}
- end;
- function TJclFormatSettings.GetTwoDigitYearCenturyWindow: Word;
- begin
- {$IFDEF RTL220_UP}
- Result := FormatSettings.TwoDigitYearCenturyWindow;
- {$ELSE}
- Result := SysUtils.TwoDigitYearCenturyWindow;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetCurrencyDecimals(AValue: Byte);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.CurrencyDecimals := AValue;
- {$ELSE}
- SysUtils.CurrencyDecimals := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetCurrencyFormat(const AValue: Byte);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.CurrencyFormat := AValue;
- {$ELSE}
- SysUtils.CurrencyFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetCurrencyString(AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.CurrencyString := AValue;
- {$ELSE}
- SysUtils.CurrencyString := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetDateSeparator(const AValue: Char);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.DateSeparator := AValue;
- {$ELSE}
- SysUtils.DateSeparator := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetDecimalSeparator(AValue: Char);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.DecimalSeparator := AValue;
- {$ELSE}
- SysUtils.DecimalSeparator := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetListSeparator(const AValue: Char);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.ListSeparator := AValue;
- {$ELSE}
- SysUtils.ListSeparator := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetLongDateFormat(const AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.LongDateFormat := AValue;
- {$ELSE}
- SysUtils.LongDateFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetLongTimeFormat(const AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.LongTimeFormat := AValue;
- {$ELSE}
- SysUtils.LongTimeFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetNegCurrFormat(const AValue: Byte);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.NegCurrFormat := AValue;
- {$ELSE}
- SysUtils.NegCurrFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetShortDateFormat(AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.ShortDateFormat := AValue;
- {$ELSE}
- SysUtils.ShortDateFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetShortTimeFormat(const AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.ShortTimeFormat := AValue;
- {$ELSE}
- SysUtils.ShortTimeFormat := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetThousandSeparator(AValue: Char);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.TimeSeparator := AValue;
- {$ELSE}
- SysUtils.TimeSeparator := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetTimeAMString(const AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.TimeAMString := AValue;
- {$ELSE}
- SysUtils.TimeAMString := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetTimePMString(const AValue: string);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.TimePMString := AValue;
- {$ELSE}
- SysUtils.TimePMString := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetTimeSeparator(const AValue: Char);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.TimeSeparator := AValue;
- {$ELSE}
- SysUtils.TimeSeparator := AValue;
- {$ENDIF}
- end;
- procedure TJclFormatSettings.SetTwoDigitYearCenturyWindow(const AValue: Word);
- begin
- {$IFDEF RTL220_UP}
- FormatSettings.TwoDigitYearCenturyWindow:= AValue;
- {$ELSE}
- SysUtils.TwoDigitYearCenturyWindow:= AValue;
- {$ENDIF}
- end;
- function VarIsNullEmpty(const V: Variant): Boolean;
- begin
- Result := VarIsNull(V) or VarIsEmpty(V);
- end;
- function VarIsNullEmptyBlank(const V: Variant): Boolean;
- begin
- Result := VarIsNull(V) or VarIsEmpty(V) or (VarToStr(V) = '');
- end;
- initialization
- {$IFNDEF WINSCP}
- SimpleLog := nil;
- {$ENDIF ~WINSCP}
- {$IFDEF UNITVERSIONING}
- RegisterUnitVersion(HInstance, UnitVersioning);
- {$ENDIF UNITVERSIONING}
- finalization
- {$IFDEF UNITVERSIONING}
- UnregisterUnitVersion(HInstance);
- {$ENDIF UNITVERSIONING}
- {$IFDEF MSWINDOWS}
- {$IFDEF THREADSAFE}
- // The user must release shared memory blocks himself. We don't clean up his
- // memory leaks and make it impossible to release the shared memory in other
- // unit's finalization blocks.
- MMFFinalized := True;
- FreeAndNil(GlobalMMFHandleListCS);
- {$ENDIF THREADSAFE}
- {$ENDIF MSWINDOWS}
- {$IFNDEF WINSCP}
- if Assigned(SimpleLog) then
- FreeAndNil(SimpleLog);
- {$ENDIF ~WINSCP}
- end.
|