system.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. unit system;
  2. interface
  3. {$define FPC_IS_SYSTEM}
  4. {$DEFINE FPC_NO_DEFAULT_HEAP}
  5. {$DEFINE FPC_NO_DEFAULT_MEMORYMANAGER}
  6. {$DEFINE HAS_MEMORYMANAGER}
  7. {$DEFINE FPC_INCLUDE_SOFTWARE_MUL}
  8. {$DEFINE FPC_INCLUDE_SOFTWARE_MOD_DIV}
  9. {$DEFINE FPC_USE_SMALL_DEFAULTSTACKSIZE}
  10. { To avoid warnings in thread.inc code,
  11. but value must be really given after
  12. systemh.inc is included otherwise the
  13. $mode switch is not effective }
  14. {$DEFINE HAS_CMDLINE}
  15. {$DEFINE DISABLE_NO_DYNLIBS_MANAGER}
  16. {$DEFINE FPC_SYSTEM_HAS_SYSDLH}
  17. {$I systemh.inc}
  18. {$IFDEF FPC_X86_DATA_NEAR}
  19. {$I locheaph.inc}
  20. {$ELSE FPC_X86_DATA_NEAR}
  21. {$I glbheaph.inc}
  22. {$ENDIF FPC_X86_DATA_NEAR}
  23. const
  24. LineEnding = #13#10;
  25. { LFNSupport is a variable here, defined below!!! }
  26. DirectorySeparator = '\';
  27. DriveSeparator = ':';
  28. ExtensionSeparator = '.';
  29. PathSeparator = ';';
  30. AllowDirectorySeparators : set of AnsiChar = ['\','/'];
  31. AllowDriveSeparators : set of AnsiChar = [':'];
  32. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  33. maxExitCode = 255;
  34. MaxPathLen = 256;
  35. const
  36. { Default filehandles }
  37. UnusedHandle = $ffff;{ instead of -1, as it is a word value}
  38. StdInputHandle = 0;
  39. StdOutputHandle = 1;
  40. StdErrorHandle = 2;
  41. FileNameCaseSensitive : boolean = false;
  42. FileNameCasePreserving: 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: Word = $0040;
  48. segA000: Word = $A000;
  49. segB000: Word = $B000;
  50. segB800: Word = $B800;}
  51. type
  52. LPSTR = ^AnsiChar;far;
  53. PFarChar = ^AnsiChar;far;
  54. PHugeChar = ^AnsiChar;huge;
  55. var
  56. { Mem[] support }
  57. mem : array[0..$7fff-1] of byte absolute $0:$0;
  58. memw : array[0..($7fff div sizeof(word))-1] of word absolute $0:$0;
  59. meml : array[0..($7fff div sizeof(longint))-1] of longint absolute $0:$0;
  60. { C-compatible arguments and environment }
  61. argc:smallint; //!! public name 'operatingsystem_parameter_argc';
  62. argv:PPAnsiChar; //!! public name 'operatingsystem_parameter_argv';
  63. { The DOS Program Segment Prefix segment (TP7 compatibility) }
  64. PrefixSeg:Word;public name '__fpc_PrefixSeg';
  65. { BP7 compatible windows variables }
  66. { In C, these are the parameters to WinMain }
  67. CmdLine: LPSTR;public name '__fpc_CmdLine';
  68. CmdShow: SmallInt;public name '__fpc_CmdShow';
  69. HInstance: Word{HINST};public name '__fpc_HInstance';
  70. HPrevInst: Word{HINST};public name '__fpc_HPrevInst';
  71. { The value that needs to be added to the segment to move the pointer by
  72. 64K bytes (BP7 compatibility) }
  73. SelectorInc: Word;public name '__fpc_SelectorInc';
  74. { SaveInt00: FarPointer;public name '__SaveInt00';}
  75. { Required for i8086.inc Stack check code }
  76. __stkbottom : pointer;public name '__stkbottom';
  77. AllFilesMask: string [3];
  78. {$ifndef RTLLITE}
  79. { System info }
  80. LFNSupport : boolean;
  81. {$ELSE RTLLITE}
  82. const
  83. LFNSupport = false;
  84. {$endif RTLLITE}
  85. implementation
  86. const
  87. fCarry = 1;
  88. { used for an offset fixup for accessing the proc parameters in asm routines
  89. that use nostackframe. We can't use the parameter name directly, because
  90. i8086 doesn't support sp relative addressing. }
  91. {$ifdef FPC_X86_CODE_FAR}
  92. extra_param_offset = 2;
  93. {$else FPC_X86_CODE_FAR}
  94. extra_param_offset = 0;
  95. {$endif FPC_X86_CODE_FAR}
  96. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  97. extra_data_offset = 2;
  98. {$else}
  99. extra_data_offset = 0;
  100. {$endif}
  101. type
  102. PFarByte = ^Byte;far;
  103. PFarWord = ^Word;far;
  104. PPFarChar = ^PFarChar;
  105. { structure, located at DS:0, initialized by InitTask }
  106. PAutoDataSegHeader = ^TAutoDataSegHeader;
  107. TAutoDataSegHeader = record
  108. null: Word;
  109. oOldSP: Word;
  110. hOldSS: Word;
  111. pLocalHeap: Word;
  112. pAtomTable: Word;
  113. pStackTop: Word;
  114. pStackMin: Word;
  115. pStackBot: Word;
  116. end;
  117. var
  118. dos_env_count:smallint;public name '__dos_env_count';
  119. {$I registers.inc}
  120. procedure MsDos(var Regs: Registers); external name 'FPC_MSDOS';
  121. { invokes int 21h with the carry flag set on entry; used for the LFN functions
  122. to ensure that the carry flag is set on exit on older DOS versions which don't
  123. support them }
  124. procedure MsDos_Carry(var Regs: Registers); external name 'FPC_MSDOS_CARRY';
  125. {$define SYSTEMUNIT}
  126. {$I wintypes.inc}
  127. {$I winprocsh.inc}
  128. {$I winprocs.inc}
  129. { in protected mode, loading invalid values into segment registers causes an
  130. exception, so we use this function to initialize our Registers structure }
  131. procedure ZeroSegRegs(var regs: Registers); inline;
  132. begin
  133. regs.DS:=0;
  134. regs.ES:=0;
  135. end;
  136. {$I system.inc}
  137. {$IFDEF FPC_X86_DATA_NEAR}
  138. {$I locheap.inc}
  139. {$ELSE FPC_X86_DATA_NEAR}
  140. {$I glbheap.inc}
  141. {$ENDIF FPC_X86_DATA_NEAR}
  142. {*****************************************************************************
  143. FinalizeHeap
  144. Dummy FinalizeHeap procedure added to fix compilation
  145. *****************************************************************************}
  146. procedure FinalizeHeap;
  147. begin
  148. end;
  149. {*****************************************************************************
  150. ParamStr/Randomize
  151. *****************************************************************************}
  152. var
  153. internal_envp : PPFarChar = nil;
  154. procedure setup_environment;
  155. var
  156. env_count : smallint;
  157. cp, dos_env: PFarChar;
  158. begin
  159. env_count:=0;
  160. dos_env:=GetDOSEnvironment;
  161. cp:=dos_env;
  162. while cp^<>#0 do
  163. begin
  164. inc(env_count);
  165. while (cp^ <> #0) do
  166. inc(cp); { skip to NUL }
  167. inc(cp); { skip to next character }
  168. end;
  169. internal_envp := getmem((env_count+1) * sizeof(PFarChar));
  170. cp:=dos_env;
  171. env_count:=0;
  172. while cp^<>#0 do
  173. begin
  174. internal_envp[env_count] := cp;
  175. inc(env_count);
  176. while (cp^ <> #0) do
  177. inc(cp); { skip to NUL }
  178. inc(cp); { skip to next character }
  179. end;
  180. internal_envp[env_count]:=nil;
  181. dos_env_count := env_count;
  182. end;
  183. function envp:PPFarChar;public name '__fpc_envp';
  184. begin
  185. if not assigned(internal_envp) then
  186. setup_environment;
  187. envp:=internal_envp;
  188. end;
  189. procedure setup_arguments;
  190. var
  191. I: SmallInt;
  192. pc: PAnsiChar;
  193. pfc: PFarChar;
  194. quote: AnsiChar;
  195. count: SmallInt;
  196. arglen, argv0len: SmallInt;
  197. argblock: PAnsiChar;
  198. arg: PAnsiChar;
  199. argv0_arr: array [0..255] of AnsiChar;
  200. {$IfDef SYSTEM_DEBUG_STARTUP}
  201. debug_output: Text;
  202. {$EndIf}
  203. begin
  204. {$IfDef SYSTEM_DEBUG_STARTUP}
  205. Assign(debug_output,'debug.txt');
  206. Rewrite(debug_output);
  207. Writeln(debug_output,'Dos command line is #',CmdLine,'#');
  208. {$EndIf}
  209. { find argv0len }
  210. argv0len:=GetModuleFileName(hInstance,FarAddr(argv0_arr),SizeOf(argv0_arr));
  211. {$IfDef SYSTEM_DEBUG_STARTUP}
  212. Writeln(debug_output,'arv0 is #',argv0_arr,'# len=', argv0len);
  213. {$EndIf}
  214. { parse dos commandline }
  215. pfc:=CmdLine;
  216. count:=1;
  217. { calc total arguments length and count }
  218. arglen:=argv0len+1;
  219. while pfc^<>#0 do
  220. begin
  221. { skip leading spaces }
  222. while pfc^ in [#1..#32] do
  223. inc(pfc);
  224. if pfc^=#0 then
  225. break;
  226. { calc argument length }
  227. quote:=' ';
  228. while (pfc^<>#0) do
  229. begin
  230. case pfc^ 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 pfarchar(pfc+1)^<>'"' then
  243. begin
  244. if quote='"' then
  245. quote:=' '
  246. else
  247. quote:='"';
  248. end
  249. else
  250. inc(pfc);
  251. end
  252. else
  253. inc(arglen);
  254. end;
  255. '''' :
  256. begin
  257. if quote<>'"' then
  258. begin
  259. if pfarchar(pfc+1)^<>'''' then
  260. begin
  261. if quote='''' then
  262. quote:=' '
  263. else
  264. quote:='''';
  265. end
  266. else
  267. inc(pfc);
  268. end
  269. else
  270. inc(arglen);
  271. end;
  272. else
  273. inc(arglen);
  274. end;
  275. inc(pfc);
  276. end;
  277. inc(arglen); { for the null terminator }
  278. inc(count);
  279. end;
  280. { set argc and allocate argv }
  281. argc:=count;
  282. argv:=AllocMem((count+1)*SizeOf(PAnsiChar));
  283. { allocate a single memory block for all arguments }
  284. argblock:=GetMem(arglen);
  285. { create argv[0] }
  286. argv[0]:=argblock;
  287. arg:=argblock;
  288. if argv0len>0 then
  289. begin
  290. pc:=@argv0_arr;
  291. while pc^<>#0 do
  292. begin
  293. arg^:=pc^;
  294. Inc(arg);
  295. Inc(pc);
  296. end;
  297. end;
  298. arg^:=#0;
  299. Inc(arg);
  300. pfc:=CmdLine;
  301. count:=1;
  302. while pfc^<>#0 do
  303. begin
  304. { skip leading spaces }
  305. while pfc^ in [#1..#32] do
  306. inc(pfc);
  307. if pfc^=#0 then
  308. break;
  309. { copy argument }
  310. argv[count]:=arg;
  311. quote:=' ';
  312. while (pfc^<>#0) do
  313. begin
  314. case pfc^ of
  315. #1..#32 :
  316. begin
  317. if quote<>' ' then
  318. begin
  319. arg^:=pfc^;
  320. inc(arg);
  321. end
  322. else
  323. break;
  324. end;
  325. '"' :
  326. begin
  327. if quote<>'''' then
  328. begin
  329. if pfarchar(pfc+1)^<>'"' then
  330. begin
  331. if quote='"' then
  332. quote:=' '
  333. else
  334. quote:='"';
  335. end
  336. else
  337. inc(pfc);
  338. end
  339. else
  340. begin
  341. arg^:=pfc^;
  342. inc(arg);
  343. end;
  344. end;
  345. '''' :
  346. begin
  347. if quote<>'"' then
  348. begin
  349. if pfarchar(pfc+1)^<>'''' then
  350. begin
  351. if quote='''' then
  352. quote:=' '
  353. else
  354. quote:='''';
  355. end
  356. else
  357. inc(pfc);
  358. end
  359. else
  360. begin
  361. arg^:=pfc^;
  362. inc(arg);
  363. end;
  364. end;
  365. else
  366. begin
  367. arg^:=pfc^;
  368. inc(arg);
  369. end;
  370. end;
  371. inc(pfc);
  372. end;
  373. arg^:=#0;
  374. Inc(arg);
  375. {$IfDef SYSTEM_DEBUG_STARTUP}
  376. Writeln(debug_output,'dos arg ',count,' #',strlen(argv[count]),'#',argv[count],'#');
  377. {$EndIf SYSTEM_DEBUG_STARTUP}
  378. inc(count);
  379. end;
  380. {$IfDef SYSTEM_DEBUG_STARTUP}
  381. Close(debug_output);
  382. {$EndIf SYSTEM_DEBUG_STARTUP}
  383. end;
  384. function paramcount : longint;
  385. begin
  386. if argv=nil then
  387. setup_arguments;
  388. paramcount := argc - 1;
  389. end;
  390. function paramstr(l : longint) : string;
  391. begin
  392. if argv=nil then
  393. setup_arguments;
  394. if (l>=0) and (l+1<=argc) then
  395. paramstr:=strpas(argv[l])
  396. else
  397. paramstr:='';
  398. end;
  399. procedure randomize;
  400. begin
  401. randseed:=GetTickCount;
  402. end;
  403. {****************************************************************************
  404. Error Message writing using messageboxes
  405. ****************************************************************************}
  406. const
  407. ErrorBufferLength = 1024;
  408. ErrorMessageBoxFlags = MB_OK or MB_ICONHAND or MB_TASKMODAL;
  409. var
  410. ErrorBuf : array[0..ErrorBufferLength] of AnsiChar;
  411. ErrorLen : SizeInt;
  412. procedure ErrorWrite(Var F: TextRec);
  413. {
  414. An error message should always end with #13#10#13#10
  415. }
  416. var
  417. i : SizeInt;
  418. Begin
  419. while F.BufPos>0 do
  420. begin
  421. begin
  422. if F.BufPos+ErrorLen>ErrorBufferLength then
  423. i:=ErrorBufferLength-ErrorLen
  424. else
  425. i:=F.BufPos;
  426. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  427. inc(ErrorLen,i);
  428. ErrorBuf[ErrorLen]:=#0;
  429. end;
  430. if ErrorLen=ErrorBufferLength then
  431. begin
  432. if not NoErrMsg then
  433. {$IFDEF FPC_X86_DATA_NEAR}
  434. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  435. {$ELSE FPC_X86_DATA_NEAR}
  436. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  437. {$ENDIF FPC_X86_DATA_NEAR}
  438. ErrorLen:=0;
  439. end;
  440. Dec(F.BufPos,i);
  441. end;
  442. End;
  443. procedure ShowErrMsg;
  444. begin
  445. if ErrorLen>0 then
  446. begin
  447. {$IFDEF FPC_X86_DATA_NEAR}
  448. MessageBox(0,Ptr(Seg(ErrorBuf),Ofs(ErrorBuf)),nil,ErrorMessageBoxFlags);
  449. {$ELSE FPC_X86_DATA_NEAR}
  450. MessageBox(0,@ErrorBuf,nil,ErrorMessageBoxFlags);
  451. {$ENDIF FPC_X86_DATA_NEAR}
  452. ErrorLen:=0;
  453. end;
  454. end;
  455. procedure ErrorClose(Var F: TextRec);
  456. begin
  457. ShowErrMsg;
  458. end;
  459. procedure ErrorOpen(Var F: TextRec);
  460. Begin
  461. TextRec(F).Handle:=StdErrorHandle;
  462. TextRec(F).Mode:=fmOutput;
  463. TextRec(F).InOutFunc:=@ErrorWrite;
  464. TextRec(F).FlushFunc:=@ErrorWrite;
  465. TextRec(F).CloseFunc:=@ErrorClose;
  466. ErrorLen:=0;
  467. End;
  468. procedure AssignError(Var T: Text);
  469. begin
  470. Assign(T,'');
  471. TextRec(T).OpenFunc:=@ErrorOpen;
  472. Rewrite(T);
  473. end;
  474. {*****************************************************************************
  475. System Dependent Exit code
  476. *****************************************************************************}
  477. procedure system_exit;
  478. {var
  479. h : byte;}
  480. begin
  481. (* RestoreInterruptHandlers;
  482. for h:=0 to max_files-1 do
  483. if openfiles[h] then
  484. begin
  485. {$ifdef SYSTEMDEBUG}
  486. writeln(stderr,'file ',opennames[h],' not closed at exit');
  487. {$endif SYSTEMDEBUG}
  488. if h>=5 then
  489. do_close(h);
  490. end;
  491. {$ifndef FPC_MM_TINY}
  492. if not CheckNullArea then
  493. writeln(stderr, 'Nil pointer assignment');
  494. {$endif FPC_MM_TINY}*)
  495. Close(stderr);
  496. Close(stdout);
  497. Close(erroutput);
  498. Close(Input);
  499. Close(Output);
  500. ShowErrMsg;
  501. asm
  502. mov al, byte [exitcode]
  503. mov ah, 4Ch
  504. int 21h
  505. end;
  506. end;
  507. {*****************************************************************************
  508. SystemUnit Initialization
  509. *****************************************************************************}
  510. procedure InitWin16Heap;
  511. begin
  512. {$ifdef FPC_X86_DATA_NEAR}
  513. SetMemoryManager(LocalHeapMemoryManager);
  514. {$else FPC_X86_DATA_NEAR}
  515. SetMemoryManager(GlobalHeapMemoryManager);
  516. {$endif FPC_X86_DATA_NEAR}
  517. end;
  518. function CheckLFN:boolean;
  519. var
  520. regs : Registers;
  521. RootName : PAnsiChar;
  522. buf : array [0..31] of AnsiChar;
  523. begin
  524. { Check LFN API on drive c:\ }
  525. RootName:='C:\';
  526. { Call 'Get Volume Information' ($71A0) }
  527. { no need to ZeroSegRegs(regs), because we initialize both DS and ES }
  528. regs.AX:=$71a0;
  529. regs.ES:=Seg(buf);
  530. regs.DI:=Ofs(buf);
  531. regs.CX:=32;
  532. regs.DS:=Seg(RootName^);
  533. regs.DX:=Ofs(RootName^);
  534. MsDos_Carry(regs);
  535. { If carryflag=0 and LFN API bit in ebx is set then use Long file names }
  536. CheckLFN:=(regs.Flags and fCarry=0) and (regs.BX and $4000=$4000);
  537. end;
  538. procedure SysInitStdIO;
  539. begin
  540. AssignError(stderr);
  541. AssignError(StdOut);
  542. Assign(Output,'');
  543. Assign(Input,'');
  544. Assign(ErrOutput,'');
  545. end;
  546. function GetProcessID: SizeUInt;
  547. begin
  548. GetProcessID := PrefixSeg;
  549. end;
  550. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  551. begin
  552. result := stklen;
  553. end;
  554. begin
  555. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  556. with PAutoDataSegHeader(Ptr(DSeg,0))^ do
  557. begin
  558. StackBottom := Ptr(SSeg,pStackTop);
  559. StackLength := pStackBot-pStackTop;
  560. end;
  561. {$else}
  562. with PAutoDataSegHeader(0)^ do
  563. begin
  564. StackBottom := NearPointer(pStackTop);
  565. StackLength := pStackBot-pStackTop;
  566. end;
  567. {$endif}
  568. __stkbottom := StackBottom;
  569. { To be set if this is a GUI or console application }
  570. IsConsole := FALSE;
  571. { To be set if this is a library and not a program }
  572. IsLibrary := FALSE;
  573. { Setup heap }
  574. InitWin16Heap;
  575. SysInitExceptions;
  576. initunicodestringmanager;
  577. { Setup stdin, stdout and stderr }
  578. SysInitStdIO;
  579. { Use LFNSupport LFN }
  580. LFNSupport:=CheckLFN;
  581. if LFNSupport then
  582. begin
  583. FileNameCasePreserving:=true;
  584. AllFilesMask := '*';
  585. end
  586. else
  587. AllFilesMask := '*.*';
  588. InitSystemDynLibs;
  589. { Reset IO Error }
  590. InOutRes:=0;
  591. {$ifdef FPC_HAS_FEATURE_THREADING}
  592. InitSystemThreads;
  593. {$endif}
  594. end.