system.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. {
  2. This file is part of the Pas2JS run time library.
  3. Copyright (c) 2017 by Mattias Gaertner
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit System;
  11. {$mode objfpc}
  12. {$modeswitch externalclass}
  13. interface
  14. const
  15. LineEnding = #10;
  16. sLineBreak = LineEnding;
  17. MaxSmallint = 32767;
  18. MinSmallint = -32768;
  19. MaxShortInt = 127;
  20. MinShortInt = -128;
  21. MaxByte = $FF;
  22. MaxWord = $FFFF;
  23. MaxLongint = $7fffffff;
  24. MaxCardinal = LongWord($ffffffff);
  25. Maxint = MaxLongint;
  26. IsMultiThread = false;
  27. {*****************************************************************************
  28. Base types
  29. *****************************************************************************}
  30. type
  31. Integer = LongInt;
  32. Cardinal = LongWord;
  33. DWord = LongWord;
  34. SizeInt = NativeInt;
  35. SizeUInt = NativeUInt;
  36. PtrInt = NativeInt;
  37. PtrUInt = NativeUInt;
  38. ValSInt = NativeInt;
  39. ValUInt = NativeUInt;
  40. ValReal = Double;
  41. Real = Double;
  42. Extended = Double;
  43. Int64 = NativeInt unimplemented; // only 53 bits at runtime
  44. UInt64 = NativeUInt unimplemented; // only 52 bits at runtime
  45. QWord = NativeUInt unimplemented; // only 52 bits at runtime
  46. Single = Double unimplemented;
  47. Comp = NativeInt unimplemented;
  48. NativeLargeInt = NativeInt;
  49. NativeLargeUInt = NativeUInt;
  50. UnicodeString = String;
  51. WideString = String;
  52. WideChar = char;
  53. TDynArrayIndex = NativeInt;
  54. TTextLineBreakStyle = (tlbsLF,tlbsCRLF,tlbsCR);
  55. {*****************************************************************************
  56. TObject, TClass
  57. *****************************************************************************}
  58. type
  59. TGuid = string;
  60. TClass = class of TObject;
  61. { TObject }
  62. TObject = class
  63. private
  64. class var FClassName: String; external name '$classname';
  65. class var FClassParent: TClass; external name '$ancestor';
  66. class var FUnitName: String; external name '$module.$name';
  67. public
  68. constructor Create;
  69. destructor Destroy; virtual;
  70. // Free is using compiler magic.
  71. // Reasons:
  72. // 1. In JS calling obj.Free when obj=nil would crash.
  73. // 2. In JS freeing memory requires to set all references to nil.
  74. // Therefore any obj.free call is replaced by the compiler with some rtl magic.
  75. procedure Free;
  76. class function ClassType: TClass; assembler;
  77. class property ClassName: String read FClassName;
  78. class function ClassNameIs(const Name: string): boolean;
  79. class property ClassParent: TClass read FClassParent;
  80. class function InheritsFrom(aClass: TClass): boolean; assembler;
  81. class property UnitName: String read FUnitName;
  82. procedure AfterConstruction; virtual;
  83. procedure BeforeDestruction; virtual;
  84. function GetInterface(const iidstr: String; out obj): boolean;
  85. function GetInterfaceByStr(const iidstr: String; out obj) : boolean;
  86. function GetInterfaceWeak(const iid: TGuid; out obj): boolean; // equal to GetInterface but the interface returned is not referenced
  87. function Equals(Obj: TObject): boolean; virtual;
  88. function ToString: String; virtual;
  89. end;
  90. const
  91. { IInterface }
  92. S_OK = 0;
  93. S_FALSE = 1;
  94. E_NOINTERFACE = -2147467262; // FPC: longint($80004002)
  95. E_UNEXPECTED = -2147418113; // FPC: longint($8000FFFF)
  96. E_NOTIMPL = -2147467263; // FPC: longint($80004001)
  97. type
  98. IUnknown = interface
  99. ['{00000000-0000-0000-C000-000000000046}']
  100. function QueryInterface(const iid: TGuid; out obj): Integer;
  101. function _AddRef: Integer;
  102. function _Release: Integer;
  103. end;
  104. IInterface = IUnknown;
  105. {$M+}
  106. IInvokable = interface(IInterface)
  107. end;
  108. {$M-}
  109. { Enumerator support }
  110. IEnumerator = interface(IInterface)
  111. function GetCurrent: TObject;
  112. function MoveNext: Boolean;
  113. procedure Reset;
  114. property Current: TObject read GetCurrent;
  115. end;
  116. IEnumerable = interface(IInterface)
  117. function GetEnumerator: IEnumerator;
  118. end;
  119. { TInterfacedObject }
  120. TInterfacedObject = class(TObject,IUnknown)
  121. protected
  122. fRefCount: Integer;
  123. { implement methods of IUnknown }
  124. function QueryInterface(const iid: TGuid; out obj): Integer; virtual;
  125. function _AddRef: Integer; virtual;
  126. function _Release: Integer; virtual;
  127. public
  128. procedure BeforeDestruction; override;
  129. property RefCount: Integer read fRefCount;
  130. end;
  131. TInterfacedClass = class of TInterfacedObject;
  132. { TAggregatedObject - sub or satellite object using same interface as controller }
  133. TAggregatedObject = class(TObject)
  134. private
  135. fController: Pointer;
  136. function GetController: IUnknown;
  137. protected
  138. { implement methods of IUnknown }
  139. function QueryInterface(const iid: TGuid; out obj): Integer; virtual;
  140. function _AddRef: Integer; virtual;
  141. function _Release: Integer; virtual;
  142. public
  143. constructor Create(const aController: IUnknown);
  144. property Controller: IUnknown read GetController;
  145. end;
  146. { TContainedObject }
  147. TContainedObject = class(TAggregatedObject,IInterface)
  148. protected
  149. function QueryInterface(const iid: TGuid; out obj): Integer; override;
  150. end;
  151. const
  152. { for safe as operator support }
  153. IObjectInstance: TGuid = '{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}';
  154. const
  155. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
  156. {*****************************************************************************
  157. Init / Exit / ExitProc
  158. *****************************************************************************}
  159. var
  160. ExitCode: Integer; external name 'rtl.exitcode';
  161. IsConsole: Boolean = {$IFDEF NodeJS}true{$ELSE}false{$ENDIF};
  162. type
  163. TOnParamCount = function: Longint;
  164. TOnParamStr = function(Index: Longint): String;
  165. var
  166. OnParamCount: TOnParamCount;
  167. OnParamStr: TOnParamStr;
  168. function ParamCount: Longint;
  169. function ParamStr(Index: Longint): String;
  170. {*****************************************************************************
  171. Math
  172. *****************************************************************************}
  173. var // ToDo: make these const
  174. PI: Double; external name 'Math.PI';
  175. MathE: Double; external name 'Math.E'; // Euler's number
  176. MathLN10: Double; external name 'Math.LN10'; // ln(10)
  177. MathLN2: Double; external name 'Math.LN2'; // ln(2)
  178. MathLog10E: Double; external name 'Math.Log10E'; // log10(e)
  179. MathLog2E: Double; external name 'Math.LOG2E'; // log2(e)
  180. MathSQRT1_2: Double; external name 'Math.SQRT1_2'; // sqrt(0.5)
  181. MathSQRT2: Double; external name 'Math.SQRT2'; // sqrt(2)
  182. function Abs(const A: integer): integer; overload; external name 'Math.abs';
  183. function Abs(const A: NativeInt): integer; overload; external name 'Math.abs';
  184. function Abs(const A: Double): Double; overload; external name 'Math.abs';
  185. function ArcTan(const A, B: Double): Double; external name 'Math.atan';
  186. function Cos(const A: Double): Double; external name 'Math.cos';
  187. function Exp(const A: Double): Double; external name 'Math.exp';
  188. function Frac(const A: Double): Double; assembler;
  189. function Ln(const A: Double): Double; external name 'Math.log';
  190. function Odd(const A: Integer): Boolean; assembler;
  191. function Random(const Range: Integer): Integer; overload; assembler;
  192. function Random: Double; overload; external name 'Math.random';
  193. function Round(const A: Double): NativeInt; external name 'Math.round';
  194. function Sin(const A: Double): Double; external name 'Math.sin';
  195. function Sqr(const A: Integer): Integer; assembler; overload;
  196. function Sqr(const A: Double): Double; assembler; overload;
  197. function sqrt(const A: Double): Double; external name 'Math.sqrt';
  198. function Trunc(const A: Double): NativeInt;
  199. {*****************************************************************************
  200. String functions
  201. *****************************************************************************}
  202. function Int(const A: Double): double;
  203. function Copy(const S: string; Index, Size: Integer): String; assembler; overload;
  204. function Copy(const S: string; Index: Integer): String; assembler; overload;
  205. procedure Delete(var S: String; Index, Size: Integer); assembler; overload;
  206. function Pos(const Search, InString: String): Integer; assembler; overload;
  207. function Pos(const Search, InString: String; StartAt : Integer): Integer; assembler; overload;
  208. procedure Insert(const Insertion: String; var Target: String; Index: Integer); overload;
  209. function upcase(c : char) : char; assembler;
  210. procedure val(const S: String; out NI : NativeInt; out Code: Integer); overload;
  211. procedure val(const S: String; out SI : ShortInt; out Code: Integer); overload;
  212. procedure val(const S: String; out B : Byte; out Code: Integer); overload;
  213. procedure val(const S: String; out SI : smallint; out Code: Integer); overload;
  214. procedure val(const S: String; out W : word; out Code : Integer); overload;
  215. procedure val(const S: String; out I : integer; out Code : Integer); overload;
  216. procedure val(const S: String; out C : Cardinal; out Code: Integer); overload;
  217. procedure val(const S: String; out d : double; out Code : Integer); overload;
  218. function StringOfChar(c: Char; l: NativeInt): String;
  219. {*****************************************************************************
  220. Other functions
  221. *****************************************************************************}
  222. procedure Write; varargs; // ToDo: should be compiler built-in function
  223. procedure Writeln; varargs; // ToDo: should be compiler built-in function
  224. Type
  225. TConsoleHandler = Procedure (S : JSValue; NewLine : Boolean);
  226. Function SetWriteCallBack(H : TConsoleHandler) : TConsoleHandler;
  227. function Assigned(const V: JSValue): boolean; assembler; overload;
  228. function StrictEqual(const A: JSValue; const B): boolean; assembler;
  229. function StrictInequal(const A: JSValue; const B): boolean; assembler;
  230. implementation
  231. // function parseInt(s: String; Radix: NativeInt): NativeInt; external name 'parseInt'; // may result NaN
  232. function isNaN(i: JSValue): boolean; external name 'isNaN'; // may result NaN
  233. // needed by ClassNameIs, the real SameText is in SysUtils
  234. function SameText(const s1, s2: String): Boolean; assembler;
  235. asm
  236. return s1.toLowerCase() == s2.toLowerCase();
  237. end;
  238. function ParamCount: Longint;
  239. begin
  240. if Assigned(OnParamCount) then
  241. Result:=OnParamCount()
  242. else
  243. Result:=0;
  244. end;
  245. function ParamStr(Index: Longint): String;
  246. begin
  247. if Assigned(OnParamStr) then
  248. Result:=OnParamStr(Index)
  249. else if Index=0 then
  250. Result:='js'
  251. else
  252. Result:='';
  253. end;
  254. function Frac(const A: Double): Double; assembler;
  255. asm
  256. return A % 1;
  257. end;
  258. function Odd(const A: Integer): Boolean; assembler;
  259. asm
  260. return A&1 != 0;
  261. end;
  262. function Random(const Range: Integer): Integer; assembler;
  263. asm
  264. return Math.floor(Math.random()*Range);
  265. end;
  266. function Sqr(const A: Integer): Integer; assembler;
  267. asm
  268. return A*A;
  269. end;
  270. function Sqr(const A: Double): Double; assembler;
  271. asm
  272. return A*A;
  273. end;
  274. function Trunc(const A: Double): NativeInt; assembler;
  275. asm
  276. if (!Math.trunc) {
  277. Math.trunc = function(v) {
  278. v = +v;
  279. if (!isFinite(v)) return v;
  280. return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0);
  281. };
  282. }
  283. $mod.Trunc = Math.trunc;
  284. return Math.trunc(A);
  285. end;
  286. function Copy(const S: string; Index, Size: Integer): String; assembler;
  287. asm
  288. if (Index<1) Index = 1;
  289. return (Size>0) ? S.substring(Index-1,Index+Size-1) : "";
  290. end;
  291. function Copy(const S: string; Index: Integer): String; assembler;
  292. asm
  293. if (Index<1) Index = 1;
  294. return S.substr(Index-1);
  295. end;
  296. procedure Delete(var S: String; Index, Size: Integer);
  297. var
  298. h: String;
  299. begin
  300. if (Index<1) or (Index>length(S)) or (Size<=0) then exit;
  301. h:=S;
  302. S:=copy(h,1,Index-1)+copy(h,Index+Size);
  303. end;
  304. function Pos(const Search, InString: String): Integer; assembler;
  305. asm
  306. return InString.indexOf(Search)+1;
  307. end;
  308. function Pos(const Search, InString: String; StartAt : Integer): Integer; assembler; overload;
  309. asm
  310. return InString.indexOf(Search,StartAt-1)+1;
  311. end;
  312. procedure Insert(const Insertion: String; var Target: String; Index: Integer);
  313. var
  314. t: String;
  315. begin
  316. if Insertion='' then exit;
  317. t:=Target;
  318. if Index<1 then
  319. Target:=Insertion+t
  320. else if Index>length(t) then
  321. Target:=t+Insertion
  322. else
  323. Target:=copy(t,1,Index-1)+Insertion+copy(t,Index,length(t));
  324. end;
  325. var
  326. WriteBuf: String;
  327. JSArguments: array of JSValue; external name 'arguments';
  328. WriteCallBack : TConsoleHandler;
  329. Function SetWriteCallBack(H : TConsoleHandler) : TConsoleHandler;
  330. begin
  331. Result:=WriteCallBack;
  332. WriteCallBack:=H;
  333. end;
  334. procedure Write;
  335. var
  336. i: Integer;
  337. begin
  338. for i:=0 to length(JSArguments)-1 do
  339. if Assigned(WriteCallBack) then
  340. WriteCallBack(JSArguments[i],False)
  341. else
  342. WriteBuf:=WriteBuf+String(JSArguments[i]);
  343. end;
  344. procedure Writeln;
  345. var
  346. i,l: Integer;
  347. s: String;
  348. begin
  349. L:=length(JSArguments)-1;
  350. if Assigned(WriteCallBack) then
  351. begin
  352. for i:=0 to L do
  353. WriteCallBack(JSArguments[i],I=L);
  354. end
  355. else
  356. begin
  357. s:=WriteBuf;
  358. for i:=0 to L do
  359. s:=s+String(JSArguments[i]);
  360. asm
  361. console.log(s);
  362. end;
  363. WriteBuf:='';
  364. end;
  365. end;
  366. function Int(const A: Double): double;
  367. function FTrunc(const A: Double): double; overload; external name 'Math.trunc';
  368. begin
  369. Result:=FTrunc(A);
  370. end;
  371. function Number(S: String): Double; external name 'Number';
  372. procedure val(const S: String; out NI : NativeInt; out Code: Integer);
  373. var
  374. x : double;
  375. begin
  376. Code:=0;
  377. x:=Number(S);
  378. if isNaN(x) or (X<>Int(X)) then
  379. Code:=1
  380. else
  381. NI:=Trunc(x);
  382. end;
  383. procedure val(const S: String; out SI : ShortInt; out Code: Integer);
  384. var
  385. X:Double;
  386. begin
  387. Code:=0;
  388. x:=Number(S);
  389. if isNaN(x) or (X<>Int(X)) then
  390. Code:=1
  391. else if (x<MinShortInt) or (x>MaxShortInt) then
  392. Code:=2
  393. else
  394. SI:=Trunc(x);
  395. end;
  396. procedure val(const S: String; out SI: smallint; out Code: Integer);
  397. var
  398. x: double;
  399. begin
  400. Code:=0;
  401. x:=Number(S);
  402. if isNaN(x) or (X<>Int(X)) then
  403. Code:=1
  404. else if (x<MinSmallint) or (x>MaxSmallint) then
  405. Code:=2
  406. else
  407. SI:=Trunc(x);
  408. end;
  409. procedure val(const S: String; out C: Cardinal; out Code: Integer);
  410. var
  411. x: double;
  412. begin
  413. Code:=0;
  414. x:=Number(S);
  415. if isNaN(x) or (X<>Int(X)) then
  416. Code:=1
  417. else if (x<0) or (x>MaxCardinal) then
  418. Code:=2
  419. else
  420. C:=trunc(x);
  421. end;
  422. procedure val(const S: String; out B: Byte; out Code: Integer);
  423. var
  424. x: double;
  425. begin
  426. Code:=0;
  427. x:=Number(S);
  428. if isNaN(x) or (X<>Int(X)) then
  429. Code:=1
  430. else if (x<0) or (x>MaxByte) then
  431. Code:=2
  432. else
  433. B:=Trunc(x);
  434. end;
  435. procedure val(const S: String; out W: word; out Code: Integer);
  436. var
  437. x: double;
  438. begin
  439. Code:=0;
  440. x:=Number(S);
  441. if isNaN(x) then
  442. Code:=1
  443. else if (x<0) or (x>MaxWord) then
  444. Code:=2
  445. else
  446. W:=Trunc(x);
  447. end;
  448. procedure val(const S : String; out I : integer; out Code : Integer);
  449. var
  450. x: double;
  451. begin
  452. Code:=0;
  453. x:=Number(S);
  454. if isNaN(x) then
  455. Code:=1
  456. else if x>MaxInt then
  457. Code:=2
  458. else
  459. I:=Trunc(x);
  460. end;
  461. procedure val(const S : String; out d : double; out Code : Integer);
  462. Var
  463. x: double;
  464. begin
  465. x:=Number(S);
  466. if isNaN(x) then
  467. Code:=1
  468. else
  469. begin
  470. Code:=0;
  471. d:=x;
  472. end;
  473. end;
  474. function upcase(c : char) : char; assembler;
  475. asm
  476. return c.toUpperCase();
  477. end;
  478. function StringOfChar(c: Char; l: NativeInt): String;
  479. var
  480. i: Integer;
  481. begin
  482. Result:='';
  483. for i:=1 to l do Result:=Result+c;
  484. end;
  485. function Assigned(const V: JSValue): boolean; assembler;
  486. asm
  487. return (V!=undefined) && (V!=null) && (!rtl.isArray(V) || (V.length > 0));
  488. end;
  489. function StrictEqual(const A: JSValue; const B): boolean; assembler;
  490. asm
  491. return A === B;
  492. end;
  493. function StrictInequal(const A: JSValue; const B): boolean; assembler;
  494. asm
  495. return A !== B;
  496. end;
  497. { TContainedObject }
  498. function TContainedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  499. begin
  500. if GetInterface(iid,obj) then
  501. Result:=S_OK
  502. else
  503. Result:=Integer(E_NOINTERFACE);
  504. end;
  505. { TAggregatedObject }
  506. function TAggregatedObject.GetController: IUnknown;
  507. begin
  508. Result := IUnknown(fController);
  509. end;
  510. function TAggregatedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  511. begin
  512. Result := IUnknown(fController).QueryInterface(iid, obj);
  513. end;
  514. function TAggregatedObject._AddRef: Integer;
  515. begin
  516. Result := IUnknown(fController)._AddRef;
  517. end;
  518. function TAggregatedObject._Release: Integer;
  519. begin
  520. Result := IUnknown(fController)._Release;
  521. end;
  522. constructor TAggregatedObject.Create(const aController: IUnknown);
  523. begin
  524. inherited Create;
  525. { do not keep a counted reference to the controller! }
  526. fController := Pointer(aController);
  527. end;
  528. { TInterfacedObject }
  529. function TInterfacedObject.QueryInterface(const iid: TGuid; out obj): Integer;
  530. begin
  531. if GetInterface(iid,obj) then
  532. Result:=S_OK
  533. else
  534. Result:=Integer(E_NOINTERFACE);
  535. end;
  536. function TInterfacedObject._AddRef: Integer;
  537. begin
  538. inc(fRefCount);
  539. Result:=fRefCount;
  540. end;
  541. function TInterfacedObject._Release: Integer;
  542. begin
  543. dec(fRefCount);
  544. Result:=fRefCount;
  545. if fRefCount=0 then
  546. Destroy;
  547. end;
  548. procedure TInterfacedObject.BeforeDestruction;
  549. begin
  550. if fRefCount<>0 then
  551. asm
  552. rtl.raiseE('EHeapMemoryError');
  553. end;
  554. end;
  555. { TObject }
  556. constructor TObject.Create;
  557. begin
  558. end;
  559. destructor TObject.Destroy;
  560. begin
  561. end;
  562. procedure TObject.Free;
  563. begin
  564. Destroy;
  565. end;
  566. class function TObject.ClassType: TClass; assembler;
  567. asm
  568. return this;
  569. end;
  570. class function TObject.ClassNameIs(const Name: string): boolean;
  571. begin
  572. Result:=SameText(Name,ClassName);
  573. end;
  574. class function TObject.InheritsFrom(aClass: TClass): boolean; assembler;
  575. asm
  576. return (aClass!=null) && ((this==aClass) || aClass.isPrototypeOf(this));
  577. end;
  578. procedure TObject.AfterConstruction;
  579. begin
  580. end;
  581. procedure TObject.BeforeDestruction;
  582. begin
  583. end;
  584. function TObject.GetInterface(const iidstr: String; out obj): boolean;
  585. begin
  586. Result := GetInterfaceByStr(iidstr,obj);
  587. end;
  588. function TObject.GetInterfaceByStr(const iidstr: String; out obj): boolean;
  589. begin
  590. if (iidstr = IObjectInstance) then
  591. begin
  592. obj:=Self;
  593. exit(true);
  594. end;
  595. asm
  596. var i = rtl.getIntfG(this,iidstr,2);
  597. obj.set(i);
  598. return i!==null;
  599. end;
  600. Result:=false;
  601. end;
  602. function TObject.GetInterfaceWeak(const iid: TGuid; out obj): boolean;
  603. begin
  604. Result:=GetInterfaceByStr(iid,obj);
  605. end;
  606. function TObject.Equals(Obj: TObject): boolean;
  607. begin
  608. Result:=Obj=Self;
  609. end;
  610. function TObject.ToString: String;
  611. begin
  612. Result:=ClassName;
  613. end;
  614. initialization
  615. ExitCode:=0; // set it here, so that WPO does not remove it
  616. end.