system.pp 17 KB

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