system.pp 17 KB

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