system.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2004-2006 by Karoly Balogh
  4. AROS conversion
  5. Copyright (c) 2011 by Marcus Sackrow
  6. System unit for AROS
  7. Uses parts of the Free Pascal 1.0.x for Commodore Amiga/68k port
  8. by Carl Eric Codere and Nils Sjoholm
  9. See the file COPYING.FPC, included in this distribution,
  10. for details about the copyright.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. **********************************************************************}
  15. unit System;
  16. interface
  17. {$define FPC_IS_SYSTEM}
  18. {$I systemh.inc}
  19. {$I osdebugh.inc}
  20. const
  21. LineEnding = #10;
  22. LFNSupport = True;
  23. DirectorySeparator = '/';
  24. DriveSeparator = ':';
  25. ExtensionSeparator = '.';
  26. PathSeparator = ';';
  27. AllowDirectorySeparators : set of char = ['\','/'];
  28. AllowDriveSeparators : set of char = [':'];
  29. maxExitCode = 255;
  30. MaxPathLen = 256;
  31. AllFilesMask = '#?';
  32. const
  33. UnusedHandle : THandle = 0;
  34. StdInputHandle : THandle = 0;
  35. StdOutputHandle : THandle = 0;
  36. StdErrorHandle : THandle = 0;
  37. FileNameCaseSensitive : Boolean = False;
  38. FileNameCasePreserving: boolean = True;
  39. CtrlZMarksEOF: Boolean = false; (* #26 not considered as end of file *)
  40. sLineBreak = LineEnding;
  41. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
  42. BreakOn : Boolean = True;
  43. var
  44. AOS_ExecBase : Pointer; external name '_ExecBase';
  45. AOS_DOSBase : Pointer;
  46. AOS_UtilityBase: Pointer;
  47. AROS_ThreadLib : Pointer; public name 'AROS_THREADLIB';
  48. ASYS_heapPool : Pointer; { pointer for the OS pool for growing the heap }
  49. ASYS_fileSemaphore: Pointer; { mutex semaphore for filelist access arbitration }
  50. ASYS_origDir : LongInt; { original directory on startup }
  51. AOS_wbMsg : Pointer;
  52. AOS_ConName : PChar ='CON:10/30/620/100/FPC Console Output/AUTO/CLOSE/WAIT';
  53. AOS_ConHandle: THandle;
  54. SysDebugBase: Pointer = nil;
  55. argc: LongInt;
  56. argv: PPChar;
  57. envp: PPChar;
  58. killed : Boolean = False;
  59. function GetLibAdress(Base: Pointer; Offset: LongInt): Pointer;
  60. procedure Debug(s: string);
  61. procedure Debugln(s: string);
  62. procedure EnableBackTraceStr;
  63. implementation
  64. {$I system.inc}
  65. {$I osdebug.inc}
  66. type
  67. PWBArg = ^TWBArg;
  68. TWBArg = record
  69. wa_Lock : LongInt; { a lock descriptor }
  70. wa_Name : PChar; { a string relative to that lock }
  71. end;
  72. WBArgList = array[1..100] of TWBArg; { Only 1..smNumArgs are valid }
  73. PWBArgList = ^WBArgList;
  74. PWBStartup = ^TWBStartup;
  75. TWBStartup = record
  76. sm_Message : TMessage; { a standard message structure }
  77. sm_Process : Pointer; { the process descriptor for you }
  78. sm_Segment : Pointer; { a descriptor for your code }
  79. sm_NumArgs : Longint; { the number of elements in ArgList }
  80. sm_ToolWindow : Pointer; { description of window }
  81. sm_ArgList : PWBArgList; { the arguments themselves }
  82. end;
  83. {*****************************************************************************
  84. Misc. System Dependent Functions
  85. *****************************************************************************}
  86. procedure haltproc(e:longint); cdecl; external name '_haltproc';
  87. procedure System_exit;
  88. var
  89. oldDirLock: LongInt;
  90. begin
  91. if Killed then
  92. Exit;
  93. Killed := True;
  94. { Dispose the thread init/exit chains }
  95. CleanupThreadProcChain(threadInitProcList);
  96. CleanupThreadProcChain(threadExitProcList);
  97. { Closing opened files }
  98. CloseList(ASYS_fileList);
  99. { Changing back to original directory if changed }
  100. if ASYS_OrigDir <> 0 then begin
  101. oldDirLock:=CurrentDir(ASYS_origDir);
  102. { unlock our lock if its safe, so we won't leak the lock }
  103. if (oldDirLock<>0) and (oldDirLock<>ASYS_origDir) then
  104. Unlock(oldDirLock);
  105. end;
  106. // debug lib
  107. if SysDebugBase <> nil then
  108. CloseLibrary(SysDebugBase);
  109. SysDebugBase := nil;
  110. // utility
  111. if AOS_UtilityBase <> nil then
  112. CloseLibrary(AOS_UtilityBase);
  113. // Heap
  114. if ASYS_heapPool <> nil then
  115. DeletePool(ASYS_heapPool);
  116. AOS_UtilityBase := nil;
  117. ASYS_HeapPool := nil;
  118. // dos
  119. if AOS_DOSBase<>nil then
  120. CloseLibrary(AOS_DOSBase);
  121. AOS_DOSBase := nil;
  122. //
  123. if AOS_wbMsg <> nil then
  124. begin
  125. // forbid -> Amiga RKM Libraries Manual
  126. Forbid();
  127. // Reply WBStartupMessage
  128. ReplyMsg(AOS_wbMsg);
  129. end;
  130. //
  131. HaltProc(ExitCode);
  132. end;
  133. function GetWBArgsNum: Integer;
  134. var
  135. startup: PWBStartup;
  136. begin
  137. GetWBArgsNum := 0;
  138. Startup := nil;
  139. Startup := PWBStartup(AOS_wbMsg);
  140. if Startup <> nil then
  141. begin
  142. Result := Startup^.sm_NumArgs - 1;
  143. end;
  144. end;
  145. function GetWBArg(Idx: Integer): string;
  146. var
  147. startup: PWBStartup;
  148. wbarg: PWBArgList;
  149. Path: array[0..254] of Char;
  150. strPath: string;
  151. Len: Integer;
  152. begin
  153. GetWBArg := '';
  154. FillChar(Path[0],255,#0);
  155. Startup := PWBStartup(AOS_wbMsg);
  156. if Startup <> nil then
  157. begin
  158. //if (Idx >= 0) and (Idx < Startup^.sm_NumArgs) then
  159. begin
  160. wbarg := Startup^.sm_ArgList;
  161. if NameFromLock(wbarg^[Idx + 1].wa_Lock,@Path[0],255) then
  162. begin
  163. Len := 0;
  164. while (Path[Len] <> #0) and (Len < 254) do
  165. Inc(Len);
  166. if Len > 0 then
  167. if (Path[Len - 1] <> ':') and (Path[Len - 1] <> '/') then
  168. Path[Len] := '/';
  169. strPath := Path;
  170. end;
  171. Result := strPath + wbarg^[Idx + 1].wa_Name;
  172. end;
  173. end;
  174. end;
  175. { Generates correct argument array on startup }
  176. procedure GenerateArgs;
  177. var
  178. ArgVLen: LongInt;
  179. procedure AllocArg(Idx, Len: LongInt);
  180. var
  181. i, OldArgVLen : LongInt;
  182. begin
  183. if Idx >= ArgVLen then
  184. begin
  185. OldArgVLen := ArgVLen;
  186. ArgVLen := (Idx + 8) and (not 7);
  187. SysReAllocMem(Argv, Argvlen * SizeOf(Pointer));
  188. for i := OldArgVLen to ArgVLen - 1 do
  189. ArgV[i]:=nil;
  190. end;
  191. ArgV[Idx] := SysAllocMem(Succ(Len));
  192. end;
  193. var
  194. Count: Word;
  195. Start: Word;
  196. Ende: Word;
  197. LocalIndex: Word;
  198. i: Integer;
  199. P : PChar;
  200. {$H+}
  201. Temp : string;
  202. InQuotes: boolean;
  203. begin
  204. P := GetArgStr;
  205. ArgVLen := 0;
  206. { Set argv[0] }
  207. Temp := ParamStr(0);
  208. AllocArg(0, Length(Temp));
  209. Move(Temp[1], Argv[0]^, Length(Temp));
  210. Argv[0][Length(Temp)] := #0;
  211. { check if we're started from Workbench }
  212. if AOS_wbMsg <> nil then
  213. begin
  214. ArgC := GetWBArgsNum + 1;
  215. for i := 1 to ArgC - 1 do
  216. begin
  217. Temp := GetWBArg(i);
  218. AllocArg(i, Length(Temp));
  219. Move(Temp[1], Argv[i]^, Length(Temp));
  220. Argv[i][Length(Temp)] := #0;
  221. end;
  222. Exit;
  223. end;
  224. InQuotes := False;
  225. { Handle the other args }
  226. Count := 0;
  227. { first index is one }
  228. LocalIndex := 1;
  229. while (P[Count] <> #0) do
  230. begin
  231. while (p[count]=' ') or (p[count]=#9) or (p[count]=LineEnding) do
  232. Inc(count);
  233. if p[count] = '"' then
  234. begin
  235. inQuotes := True;
  236. Inc(Count);
  237. end;
  238. start := count;
  239. if inQuotes then
  240. begin
  241. while (p[count]<>#0) and (p[count]<>'"') and (p[count]<>LineEnding) do
  242. begin
  243. Inc(Count)
  244. end;
  245. end else
  246. begin
  247. while (p[count]<>#0) and (p[count]<>' ') and (p[count]<>#9) and (p[count]<>LineEnding) do
  248. inc(count);
  249. end;
  250. ende := count;
  251. if not inQuotes then
  252. begin
  253. while (p[start]=' ') and (Start < Ende) do
  254. Inc(Start)
  255. end;
  256. if (ende-start>0) then
  257. begin
  258. allocarg(localindex,ende-start);
  259. move(p[start],argv[localindex]^,ende-start);
  260. argv[localindex][ende-start]:=#0;
  261. if inQuotes and (argv[localindex][(ende-start) - 1] = '"') then
  262. argv[localindex][(ende-start)-1] := #0;
  263. inc(localindex);
  264. end;
  265. if inQuotes and (p[count] = '"') then
  266. Inc(Count);
  267. inQuotes := False;
  268. end;
  269. argc:=localindex;
  270. end;
  271. function GetProgDir: String;
  272. var
  273. s1 : String;
  274. alock : LongInt;
  275. counter: Byte;
  276. begin
  277. GetProgDir:='';
  278. SetLength(s1, 256);
  279. FillChar(s1,255,#0);
  280. { GetLock of program directory }
  281. alock:=GetProgramDir;
  282. if alock<>0 then begin
  283. if NameFromLock(alock,@s1[1],255) then begin
  284. counter:=1;
  285. while (s1[counter]<>#0) and (counter<>0) do Inc(counter);
  286. SetLength(s1, counter-1);
  287. GetProgDir:=s1;
  288. end;
  289. end;
  290. end;
  291. function GetProgramName: String;
  292. { Returns ONLY the program name }
  293. var
  294. s1 : String;
  295. counter: Byte;
  296. begin
  297. GetProgramName:='';
  298. SetLength(s1, 256);
  299. FillChar(s1,255,#0);
  300. if GetProgramName(@s1[1],255) then begin
  301. { now check out and assign the length of the string }
  302. counter := 1;
  303. while (s1[counter]<>#0) and (counter<>0) do Inc(counter);
  304. SetLength(s1, counter-1);
  305. { now remove any component path which should not be there }
  306. for counter:=length(s1) downto 1 do
  307. if (s1[counter] = '/') or (s1[counter] = ':') then break;
  308. { readjust counterv to point to character }
  309. if counter<>1 then Inc(counter);
  310. GetProgramName:=copy(s1,counter,length(s1));
  311. end;
  312. end;
  313. {*****************************************************************************
  314. ParamStr/Randomize
  315. *****************************************************************************}
  316. { number of args }
  317. function paramcount : longint;
  318. begin
  319. if AOS_wbMsg<>nil then
  320. paramcount:=GetWBArgsNum
  321. else
  322. paramcount:=argc-1;
  323. end;
  324. { argument number l }
  325. function paramstr(l : longint) : string;
  326. var
  327. s1: String;
  328. begin
  329. paramstr:='';
  330. if AOS_wbMsg<>nil then
  331. begin
  332. paramstr := GetWBArg(l);
  333. end else
  334. begin
  335. if l=0 then begin
  336. s1:=GetProgDir;
  337. if s1[length(s1)]=':' then paramstr:=s1+GetProgramName
  338. else paramstr:=s1+'/'+GetProgramName;
  339. end else begin
  340. if (l>0) and (l+1<=argc) then paramstr:=strpas(argv[l]);
  341. end;
  342. end;
  343. end;
  344. { set randseed to a new pseudo random value }
  345. procedure Randomize;
  346. var
  347. tmpTime: TDateStamp;
  348. begin
  349. DateStamp(@tmpTime);
  350. randseed := tmpTime.ds_tick;
  351. end;
  352. { AmigaOS specific startup }
  353. procedure SysInitAmigaOS;
  354. var
  355. self: PProcess;
  356. begin
  357. self := PProcess(FindTask(nil));
  358. if self^.pr_CLI = 0 then begin
  359. { if we're running from Ambient/Workbench, we catch its message }
  360. WaitPort(@self^.pr_MsgPort);
  361. AOS_wbMsg:=GetMsg(@self^.pr_MsgPort);
  362. end;
  363. AOS_DOSBase := OpenLibrary('dos.library', 0);
  364. if AOS_DOSBase = nil then
  365. Halt(1);
  366. AOS_UtilityBase := OpenLibrary('utility.library', 0);
  367. if AOS_UtilityBase = nil then
  368. Halt(1);
  369. { Creating the memory pool for growing heap }
  370. ASYS_heapPool := CreatePool(MEMF_ANY or MEMF_SEM_PROTECTED, growheapsize2, growheapsize1);
  371. if ASYS_heapPool = nil then
  372. Halt(1);
  373. { Initialize semaphore for filelist access arbitration }
  374. ASYS_fileSemaphore:=AllocPooled(ASYS_heapPool,sizeof(TSignalSemaphore));
  375. if ASYS_fileSemaphore = nil then
  376. Halt(1);
  377. InitSemaphore(ASYS_fileSemaphore);
  378. if AOS_wbMsg = nil then begin
  379. StdInputHandle := THandle(dosInput);
  380. StdOutputHandle := THandle(dosOutput);
  381. {$ifdef CPU64}
  382. StdErrorHandle := THandle(DosOutput);
  383. {$else}
  384. StdErrorHandle := THandle(DosError1);
  385. {$endif}
  386. end else begin
  387. AOS_ConHandle := Open(AOS_ConName, MODE_OLDFILE);
  388. if AOS_ConHandle <> 0 then begin
  389. StdInputHandle := AOS_ConHandle;
  390. StdOutputHandle := AOS_ConHandle;
  391. StdErrorHandle := AOS_ConHandle;
  392. end else
  393. Halt(1);
  394. end;
  395. end;
  396. function AROSBackTraceStr(Addr: CodePointer): ShortString;
  397. const
  398. DL_Dummy = TAG_USER + $03e00000;
  399. DL_ModuleName = DL_Dummy + 1;
  400. DL_SymbolName = DL_Dummy + 7;
  401. var
  402. SymName, ModName: PChar;
  403. Tags: array[0..5] of PtrUInt;
  404. s: AnsiString;
  405. Res: AnsiString;
  406. begin
  407. if Assigned(SysDebugBase) then
  408. begin
  409. ModName := nil;
  410. SymName := nil;
  411. Tags[0] := DL_Modulename;
  412. Tags[1] := PtrUInt(@ModName);
  413. Tags[2] := DL_SymbolName;
  414. Tags[3] := PtrUInt(@SymName);
  415. Tags[4] := 0;
  416. Tags[5] := 0;
  417. DecodeLocation(Addr, @Tags[0]);
  418. s := '-';
  419. if not Assigned(ModName) then
  420. ModName := @S[1];
  421. if not Assigned(SymName) then
  422. SymName := @S[1];
  423. Res := ' $' + HexStr(Addr) + ' ' + ModName + ' ' + SymName;
  424. AROSBackTraceStr := Copy(Res, 1, 254);
  425. end
  426. else
  427. begin
  428. AROSBackTraceStr := ' $' + HexStr(Addr) + ' - ';
  429. end;
  430. end;
  431. procedure EnableBackTraceStr;
  432. begin
  433. if not Assigned(SysDebugBase) then
  434. begin
  435. SysDebugBase := OpenLibrary('debug.library', 0);
  436. if Assigned(SysDebugBase) then
  437. BackTraceStrFunc := @AROSBackTraceStr;
  438. end;
  439. end;
  440. procedure SysInitStdIO;
  441. begin
  442. OpenStdIO(Input,fmInput,StdInputHandle);
  443. OpenStdIO(Output,fmOutput,StdOutputHandle);
  444. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  445. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  446. end;
  447. function GetProcessID: SizeUInt;
  448. begin
  449. GetProcessID := SizeUInt(FindTask(NIL));
  450. end;
  451. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  452. begin
  453. result := stklen;
  454. end;
  455. begin
  456. IsConsole := TRUE;
  457. SysResetFPU;
  458. if not (IsLibrary) then
  459. SysInitFPU;
  460. StackLength := CheckInitialStkLen(InitialStkLen);
  461. StackBottom := Sptr - StackLength;
  462. { OS specific startup }
  463. AOS_wbMsg := nil;
  464. ASYS_origDir := 0;
  465. ASYS_fileList := nil;
  466. envp := nil;
  467. SysInitAmigaOS;
  468. { Set up signals handlers }
  469. //InstallSignals;
  470. { Setup heap }
  471. InitHeap;
  472. SysInitExceptions;
  473. initunicodestringmanager;
  474. { Setup stdin, stdout and stderr }
  475. SysInitStdIO;
  476. { Reset IO Error }
  477. InOutRes:=0;
  478. { Arguments }
  479. GenerateArgs;
  480. InitSystemThreads;
  481. InitSystemDynLibs;
  482. end.