system.pp 17 KB

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