system.pp 16 KB

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