system.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  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. interface
  12. { two debug conditionnals can be used
  13. - SYSTEMDEBUG
  14. -for STACK checks
  15. -for non closed files at exit (or at any time with GDB)
  16. - SYSTEM_DEBUG_STARTUP
  17. specifically for
  18. - proxy command line (DJGPP feature)
  19. - list of args
  20. - list of env variables (PM) }
  21. {$ifndef NO_EXCEPTIONS_IN_SYSTEM}
  22. {$define EXCEPTIONS_IN_SYSTEM}
  23. {$endif NO_EXCEPTIONS_IN_SYSTEM}
  24. {$define USE_NOTHREADMANAGER}
  25. { include system-independent routine headers }
  26. {$I systemh.inc}
  27. const
  28. LineEnding = #13#10;
  29. { LFNSupport is a variable here, defined below!!! }
  30. DirectorySeparator = '\';
  31. DriveSeparator = ':';
  32. ExtensionSeparator = '.';
  33. PathSeparator = ';';
  34. AllowDirectorySeparators : set of char = ['\','/'];
  35. AllowDriveSeparators : set of char = [':'];
  36. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  37. maxExitCode = 255;
  38. MaxPathLen = 256;
  39. const
  40. { Default filehandles }
  41. UnusedHandle = -1;
  42. StdInputHandle = 0;
  43. StdOutputHandle = 1;
  44. StdErrorHandle = 2;
  45. FileNameCaseSensitive : boolean = false;
  46. FileNameCasePreserving: boolean = false;
  47. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  48. sLineBreak = LineEnding;
  49. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  50. { Default memory segments (Tp7 compatibility) }
  51. seg0040 = $0040;
  52. segA000 = $A000;
  53. segB000 = $B000;
  54. segB800 = $B800;
  55. var
  56. { Mem[] support }
  57. mem : array[0..$7fffffff-1] of byte absolute $0:$0;
  58. memw : array[0..($7fffffff div sizeof(word))-1] of word absolute $0:$0;
  59. meml : array[0..($7fffffff div sizeof(longint))-1] of longint absolute $0:$0;
  60. { C-compatible arguments and environment }
  61. argc:longint;public name 'operatingsystem_parameter_argc';
  62. argv:PPchar;public name 'operatingsystem_parameter_argv';
  63. envp:PPchar;public name 'operatingsystem_parameter_envp';
  64. dos_argv0 : pchar; public name 'dos_argv0';
  65. AllFilesMask: string [3];
  66. {$ifndef RTLLITE}
  67. { System info }
  68. LFNSupport : boolean;
  69. {$ELSE RTLLITE}
  70. const
  71. LFNSupport = false;
  72. {$endif RTLLITE}
  73. type
  74. { Dos Extender info }
  75. p_stub_info = ^t_stub_info;
  76. t_stub_info = packed record
  77. magic : array[0..15] of char;
  78. size : longint;
  79. minstack : longint;
  80. memory_handle : longint;
  81. initial_size : longint;
  82. minkeep : word;
  83. ds_selector : word;
  84. ds_segment : word;
  85. psp_selector : word;
  86. cs_selector : word;
  87. env_size : word;
  88. basename : array[0..7] of char;
  89. argv0 : array [0..15] of char;
  90. dpmi_server : array [0..15] of char;
  91. end;
  92. p_go32_info_block = ^t_go32_info_block;
  93. t_go32_info_block = packed record
  94. size_of_this_structure_in_bytes : longint; {offset 0}
  95. linear_address_of_primary_screen : longint; {offset 4}
  96. linear_address_of_secondary_screen : longint; {offset 8}
  97. linear_address_of_transfer_buffer : longint; {offset 12}
  98. size_of_transfer_buffer : longint; {offset 16}
  99. pid : longint; {offset 20}
  100. master_interrupt_controller_base : byte; {offset 24}
  101. slave_interrupt_controller_base : byte; {offset 25}
  102. selector_for_linear_memory : word; {offset 26}
  103. linear_address_of_stub_info_structure : longint; {offset 28}
  104. linear_address_of_original_psp : longint; {offset 32}
  105. run_mode : word; {offset 36}
  106. run_mode_info : word; {offset 38}
  107. end;
  108. var
  109. stub_info : p_stub_info; public name 'operatingsystem_stub_info';
  110. go32_info_block : t_go32_info_block; public name 'operatingsystem_go32_info_block';
  111. {$ifdef SYSTEMDEBUG}
  112. const
  113. accept_sbrk : boolean = true;
  114. {$endif}
  115. {
  116. necessary for objects.pas, should be removed (at least from the interface
  117. to the implementation)
  118. }
  119. type
  120. trealregs=record
  121. realedi,realesi,realebp,realres,
  122. realebx,realedx,realecx,realeax : longint;
  123. realflags,
  124. reales,realds,realfs,realgs,
  125. realip,realcs,realsp,realss : word;
  126. end;
  127. function do_write(h:longint;addr:pointer;len : longint) : longint;
  128. function do_read(h:longint;addr:pointer;len : longint) : longint;
  129. procedure syscopyfromdos(addr : longint; len : longint);
  130. procedure syscopytodos(addr : longint; len : longint);
  131. procedure sysrealintr(intnr : word;var regs : trealregs);
  132. function tb : longint;
  133. implementation
  134. { include system independent routines }
  135. {$I system.inc}
  136. var
  137. _args : ppchar;external name '_args';
  138. __stubinfo : p_stub_info;external name '__stubinfo';
  139. ___dos_argv0 : pchar;external name '___dos_argv0';
  140. procedure setup_arguments;
  141. type
  142. arrayword = array [0..255] of word;
  143. var
  144. psp : word;
  145. proxy_s : string[50];
  146. proxy_argc,proxy_seg,proxy_ofs,lin : longint;
  147. rm_argv : ^arrayword;
  148. argv0len : longint;
  149. useproxy : boolean;
  150. hp : ppchar;
  151. doscmd : string[129]; { Dos commandline copied from PSP, max is 128 chars +1 for terminating zero }
  152. arglen,cmdlen,
  153. count : longint;
  154. argstart,
  155. pc,arg : pchar;
  156. quote : char;
  157. argvlen : longint;
  158. function atohex(s : pchar) : longint;
  159. var
  160. rv : longint;
  161. v : byte;
  162. begin
  163. rv:=0;
  164. while (s^<>#0) do
  165. begin
  166. v:=byte(s^)-byte('0');
  167. if (v > 9) then
  168. dec(v,7);
  169. v:=v and 15; { in case it's lower case }
  170. rv:=(rv shl 4) or v;
  171. inc(longint(s));
  172. end;
  173. atohex:=rv;
  174. end;
  175. procedure allocarg(idx,len:longint);
  176. var
  177. oldargvlen : longint;
  178. begin
  179. if idx>=argvlen then
  180. begin
  181. oldargvlen:=argvlen;
  182. argvlen:=(idx+8) and (not 7);
  183. sysreallocmem(argv,argvlen*sizeof(pointer));
  184. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  185. end;
  186. { use realloc to reuse already existing memory }
  187. { always allocate, even if length is zero, since }
  188. { the arg. is still present! }
  189. sysreallocmem(argv[idx],len+1);
  190. end;
  191. begin
  192. count:=0;
  193. argc:=1;
  194. argv:=nil;
  195. argvlen:=0;
  196. { load commandline from psp }
  197. psp:=stub_info^.psp_selector;
  198. sysseg_move(psp, 128, get_ds, longint(@doscmd), 128);
  199. doscmd[length(doscmd)+1]:=#0;
  200. {$IfDef SYSTEM_DEBUG_STARTUP}
  201. Writeln(stderr,'Dos command line is #',doscmd,'# size = ',length(doscmd));
  202. {$EndIf }
  203. { create argv[0] }
  204. argv0len:=strlen(dos_argv0);
  205. allocarg(count,argv0len+1);
  206. move(dos_argv0^,argv[count]^,argv0len+1);
  207. inc(count);
  208. { setup cmdline variable }
  209. cmdlen:=argv0len+length(doscmd)+2;
  210. cmdline:=Getmem(cmdlen);
  211. move(dos_argv0^,cmdline^,argv0len);
  212. cmdline[argv0len]:=' ';
  213. inc(argv0len);
  214. move(doscmd[1],cmdline[argv0len],length(doscmd));
  215. cmdline[cmdlen-1]:=#0;
  216. { parse dos commandline }
  217. pc:=@doscmd[1];
  218. while pc^<>#0 do
  219. begin
  220. { skip leading spaces }
  221. while pc^ in [#1..#32] do
  222. inc(pc);
  223. if pc^=#0 then
  224. break;
  225. { calc argument length }
  226. quote:=' ';
  227. argstart:=pc;
  228. arglen:=0;
  229. while (pc^<>#0) do
  230. begin
  231. case pc^ of
  232. #1..#32 :
  233. begin
  234. if quote<>' ' then
  235. inc(arglen)
  236. else
  237. break;
  238. end;
  239. '"' :
  240. begin
  241. if quote<>'''' then
  242. begin
  243. if pchar(pc+1)^<>'"' then
  244. begin
  245. if quote='"' then
  246. quote:=' '
  247. else
  248. quote:='"';
  249. end
  250. else
  251. inc(pc);
  252. end
  253. else
  254. inc(arglen);
  255. end;
  256. '''' :
  257. begin
  258. if quote<>'"' then
  259. begin
  260. if pchar(pc+1)^<>'''' then
  261. begin
  262. if quote='''' then
  263. quote:=' '
  264. else
  265. quote:='''';
  266. end
  267. else
  268. inc(pc);
  269. end
  270. else
  271. inc(arglen);
  272. end;
  273. else
  274. inc(arglen);
  275. end;
  276. inc(pc);
  277. end;
  278. { copy argument }
  279. allocarg(count,arglen);
  280. quote:=' ';
  281. pc:=argstart;
  282. arg:=argv[count];
  283. while (pc^<>#0) do
  284. begin
  285. case pc^ of
  286. #1..#32 :
  287. begin
  288. if quote<>' ' then
  289. begin
  290. arg^:=pc^;
  291. inc(arg);
  292. end
  293. else
  294. break;
  295. end;
  296. '"' :
  297. begin
  298. if quote<>'''' then
  299. begin
  300. if pchar(pc+1)^<>'"' then
  301. begin
  302. if quote='"' then
  303. quote:=' '
  304. else
  305. quote:='"';
  306. end
  307. else
  308. inc(pc);
  309. end
  310. else
  311. begin
  312. arg^:=pc^;
  313. inc(arg);
  314. end;
  315. end;
  316. '''' :
  317. begin
  318. if quote<>'"' then
  319. begin
  320. if pchar(pc+1)^<>'''' then
  321. begin
  322. if quote='''' then
  323. quote:=' '
  324. else
  325. quote:='''';
  326. end
  327. else
  328. inc(pc);
  329. end
  330. else
  331. begin
  332. arg^:=pc^;
  333. inc(arg);
  334. end;
  335. end;
  336. else
  337. begin
  338. arg^:=pc^;
  339. inc(arg);
  340. end;
  341. end;
  342. inc(pc);
  343. end;
  344. arg^:=#0;
  345. {$IfDef SYSTEM_DEBUG_STARTUP}
  346. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  347. {$EndIf SYSTEM_DEBUG_STARTUP}
  348. inc(count);
  349. end;
  350. argc:=count;
  351. { check for !proxy for long commandlines passed using environment }
  352. hp:=envp;
  353. useproxy:=false;
  354. while assigned(hp^) do
  355. begin
  356. if (hp^[0]=' ') then
  357. begin
  358. proxy_s:=strpas(hp^);
  359. if Copy(proxy_s,1,7)=' !proxy' then
  360. begin
  361. proxy_s[13]:=#0;
  362. proxy_s[18]:=#0;
  363. proxy_s[23]:=#0;
  364. { Do not set argv[2..4] to PROXY_S
  365. values, because PROXY_S is on stack,
  366. while ARGV[2..4] need to be on heap.
  367. PM 2011-06-08
  368. argv[2]:=@proxy_s[9];
  369. argv[3]:=@proxy_s[14];
  370. argv[4]:=@proxy_s[19];}
  371. allocarg(2,4);
  372. strcopy(argv[2], @proxy_s[9]);
  373. allocarg(3,4);
  374. strcopy(argv[3], @proxy_s[14]);
  375. allocarg(4,4);
  376. strcopy(argv[4], @proxy_s[19]);
  377. { We need to change this variable env name
  378. otherwise it will be used by other DJGPP variables
  379. if we call them. PM 2011-07-04
  380. Hide it as '_!proxy' instead of ' !proxy' }
  381. hp^[0]:='_';
  382. useproxy:=true;
  383. break;
  384. end;
  385. end;
  386. inc(hp);
  387. end;
  388. { check for !proxy for long commandlines passed using commandline }
  389. if (not useproxy) and
  390. (argc > 1) and (far_strlen(get_ds,longint(argv[1])) = 6) then
  391. begin
  392. move(argv[1]^,proxy_s[1],6);
  393. proxy_s[0] := #6;
  394. if (proxy_s = '!proxy') then
  395. useproxy:=true;
  396. end;
  397. { use proxy when found }
  398. if useproxy then
  399. begin
  400. proxy_argc:=atohex(argv[2]);
  401. proxy_seg:=atohex(argv[3]);
  402. proxy_ofs:=atohex(argv[4]);
  403. {$IfDef SYSTEM_DEBUG_STARTUP}
  404. Writeln(stderr,'proxy command line found');
  405. writeln(stderr,'argc: ',proxy_argc,' seg: ',proxy_seg,' ofs: ',proxy_ofs);
  406. {$EndIf SYSTEM_DEBUG_STARTUP}
  407. rm_argv:=SysGetmem(proxy_argc*sizeof(word));
  408. sysseg_move(dos_selector,proxy_seg*16+proxy_ofs, get_ds,longint(rm_argv),proxy_argc*sizeof(word));
  409. for count:=0 to proxy_argc - 1 do
  410. begin
  411. lin:=proxy_seg*16+rm_argv^[count];
  412. arglen:=far_strlen(dos_selector,lin);
  413. allocarg(count,arglen);
  414. sysseg_move(dos_selector,lin,get_ds,longint(argv[count]),arglen+1);
  415. {$IfDef SYSTEM_DEBUG_STARTUP}
  416. Writeln(stderr,'arg ',count,' #',rm_argv^[count],'#',arglen,'#',argv[count],'#');
  417. {$EndIf SYSTEM_DEBUG_STARTUP}
  418. end;
  419. SysFreemem(rm_argv);
  420. argc:=proxy_argc;
  421. end;
  422. { create an nil entry }
  423. allocarg(argc,0);
  424. { free unused memory }
  425. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  426. _args:=argv;
  427. end;
  428. procedure setup_environment;
  429. var env_selector : word;
  430. env_count : longint;
  431. dos_env,cp : pchar;
  432. begin
  433. stub_info:=__stubinfo;
  434. dos_env := sysgetmem(stub_info^.env_size);
  435. env_count:=0;
  436. sysseg_move(stub_info^.psp_selector,$2c, get_ds, longint(@env_selector), 2);
  437. sysseg_move(env_selector, 0, get_ds, longint(dos_env), stub_info^.env_size);
  438. cp:=dos_env;
  439. while cp ^ <> #0 do
  440. begin
  441. inc(env_count);
  442. while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
  443. inc(longint(cp)); { skip to next character }
  444. end;
  445. envp := sysgetmem((env_count+1) * sizeof(pchar));
  446. if (envp = nil) then HandleError (203);
  447. cp:=dos_env;
  448. env_count:=0;
  449. while cp^ <> #0 do
  450. begin
  451. envp[env_count] := sysgetmem(strlen(cp)+1);
  452. strcopy(envp[env_count], cp);
  453. {$IfDef SYSTEM_DEBUG_STARTUP}
  454. Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
  455. {$EndIf SYSTEM_DEBUG_STARTUP}
  456. inc(env_count);
  457. while (cp^ <> #0) do
  458. inc(longint(cp)); { skip to NUL }
  459. inc(longint(cp)); { skip to next character }
  460. end;
  461. envp[env_count]:=nil;
  462. longint(cp):=longint(cp)+3;
  463. dos_argv0 := sysgetmem(strlen(cp)+1);
  464. if (dos_argv0 = nil) then HandleError (203);
  465. strcopy(dos_argv0, cp);
  466. { update ___dos_argv0 also }
  467. ___dos_argv0:=dos_argv0
  468. end;
  469. {*****************************************************************************
  470. System Dependent Exit code
  471. *****************************************************************************}
  472. procedure __exit(exitcode:longint);cdecl;external;
  473. Procedure system_exit;
  474. var
  475. h : byte;
  476. begin
  477. for h:=0 to max_files-1 do
  478. if openfiles[h] then
  479. begin
  480. {$ifdef SYSTEMDEBUG}
  481. writeln(stderr,'file ',opennames[h],' not closed at exit');
  482. {$endif SYSTEMDEBUG}
  483. if h>=5 then
  484. do_close(h);
  485. end;
  486. { halt is not allways called !! }
  487. { not on normal exit !! PM }
  488. set_pm_interrupt($00,old_int00);
  489. {$ifndef EXCEPTIONS_IN_SYSTEM}
  490. set_pm_interrupt($75,old_int75);
  491. {$endif EXCEPTIONS_IN_SYSTEM}
  492. __exit(exitcode);
  493. end;
  494. procedure new_int00;
  495. begin
  496. HandleError(200);
  497. end;
  498. {$ifndef EXCEPTIONS_IN_SYSTEM}
  499. procedure new_int75;
  500. begin
  501. asm
  502. xorl %eax,%eax
  503. outb %al,$0x0f0
  504. movb $0x20,%al
  505. outb %al,$0x0a0
  506. outb %al,$0x020
  507. end;
  508. HandleError(200);
  509. end;
  510. {$endif EXCEPTIONS_IN_SYSTEM}
  511. var
  512. __stkbottom : pointer;external name '__stkbottom';
  513. {*****************************************************************************
  514. ParamStr/Randomize
  515. *****************************************************************************}
  516. function paramcount : longint;
  517. begin
  518. paramcount := argc - 1;
  519. end;
  520. function paramstr(l : longint) : string;
  521. begin
  522. if (l>=0) and (l+1<=argc) then
  523. paramstr:=strpas(argv[l])
  524. else
  525. paramstr:='';
  526. end;
  527. procedure randomize;
  528. var
  529. hl : longint;
  530. regs : trealregs;
  531. begin
  532. regs.realeax:=$2c00;
  533. sysrealintr($21,regs);
  534. hl:=lo(regs.realedx);
  535. randseed:=hl*$10000+ lo(regs.realecx);
  536. end;
  537. {*****************************************************************************
  538. SystemUnit Initialization
  539. *****************************************************************************}
  540. function CheckLFN:boolean;
  541. var
  542. regs : TRealRegs;
  543. RootName : pchar;
  544. begin
  545. { Check LFN API on drive c:\ }
  546. RootName:='C:\';
  547. syscopytodos(longint(RootName),strlen(RootName)+1);
  548. { Call 'Get Volume Information' ($71A0) }
  549. regs.realeax:=$71a0;
  550. regs.reales:=tb_segment;
  551. regs.realedi:=tb_offset;
  552. regs.realecx:=32;
  553. regs.realds:=tb_segment;
  554. regs.realedx:=tb_offset;
  555. regs.realflags:=carryflag;
  556. sysrealintr($21,regs);
  557. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  558. CheckLFN:=(regs.realflags and carryflag=0) and (regs.realebx and $4000=$4000);
  559. end;
  560. {$ifdef EXCEPTIONS_IN_SYSTEM}
  561. {$define IN_SYSTEM}
  562. {$i dpmiexcp.pp}
  563. {$endif EXCEPTIONS_IN_SYSTEM}
  564. procedure SysInitStdIO;
  565. begin
  566. OpenStdIO(Input,fmInput,StdInputHandle);
  567. OpenStdIO(Output,fmOutput,StdOutputHandle);
  568. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  569. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  570. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  571. end;
  572. function GetProcessID: SizeUInt;
  573. begin
  574. GetProcessID := SizeUInt (Go32_info_block.pid);
  575. end;
  576. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  577. begin
  578. result := stklen;
  579. end;
  580. var
  581. temp_int : tseginfo;
  582. Begin
  583. StackLength := CheckInitialStkLen(InitialStkLen);
  584. StackBottom := __stkbottom;
  585. { To be set if this is a GUI or console application }
  586. IsConsole := TRUE;
  587. { To be set if this is a library and not a program }
  588. IsLibrary := FALSE;
  589. { save old int 0 and 75 }
  590. get_pm_interrupt($00,old_int00);
  591. get_pm_interrupt($75,old_int75);
  592. temp_int.segment:=get_cs;
  593. temp_int.offset:=@new_int00;
  594. set_pm_interrupt($00,temp_int);
  595. {$ifndef EXCEPTIONS_IN_SYSTEM}
  596. temp_int.offset:=@new_int75;
  597. set_pm_interrupt($75,temp_int);
  598. {$endif EXCEPTIONS_IN_SYSTEM}
  599. { Setup heap }
  600. InitHeap;
  601. SysInitExceptions;
  602. initunicodestringmanager;
  603. { Setup stdin, stdout and stderr }
  604. SysInitStdIO;
  605. { Setup environment and arguments }
  606. Setup_Environment;
  607. Setup_Arguments;
  608. { Use LFNSupport LFN }
  609. LFNSupport:=CheckLFN;
  610. if LFNSupport then
  611. begin
  612. FileNameCasePreserving:=true;
  613. AllFilesMask := '*';
  614. end
  615. else
  616. AllFilesMask := '*.*';
  617. { Reset IO Error }
  618. InOutRes:=0;
  619. {$ifdef FPC_HAS_FEATURE_THREADING}
  620. InitSystemThreads;
  621. {$endif}
  622. {$ifdef EXCEPTIONS_IN_SYSTEM}
  623. InitDPMIExcp;
  624. InstallDefaultHandlers;
  625. {$endif EXCEPTIONS_IN_SYSTEM}
  626. initvariantmanager;
  627. End.