system.pp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2002-2004 by Olle Raab
  4. FreePascal system unit for MacOS.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit System;
  12. interface
  13. {$define FPC_IS_SYSTEM}
  14. {$DEFINE FPC_ANSI_TEXTFILEREC}
  15. { include system-independent routine headers }
  16. {$I systemh.inc}
  17. {$if defined(cpum68k) and defined(fpusoft)}
  18. {$define fpc_softfpu_interface}
  19. {$i softfpu.pp}
  20. {$undef fpc_softfpu_interface}
  21. {$endif defined(cpum68k) and defined(fpusoft)}
  22. const
  23. LineEnding = #13;
  24. LFNSupport = true;
  25. DirectorySeparator = ':';
  26. DriveSeparator = ':';
  27. ExtensionSeparator = '.';
  28. PathSeparator = ','; {Is used in MPW and OzTeX}
  29. AllowDirectorySeparators : set of char = [':'];
  30. AllowDriveSeparators : set of char = [':'];
  31. FileNameCaseSensitive = false;
  32. FileNameCasePreserving = true;
  33. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  34. maxExitCode = 65535;
  35. MaxPathLen = 256;
  36. AllFilesMask = '*';
  37. const
  38. { Default filehandles }
  39. UnusedHandle : Longint = -1;
  40. StdInputHandle : Longint = 0;
  41. StdOutputHandle : Longint = 1;
  42. StdErrorHandle : Longint = 2;
  43. sLineBreak = LineEnding;
  44. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCR;
  45. var
  46. argc : longint;
  47. argv : ppchar;
  48. envp : ppchar;
  49. {*********************************}
  50. {** MacOS specific functions **}
  51. {*********************************}
  52. {To be called at regular intervals, for lenghty tasks.
  53. Yield might give time for other tasks to run under the cooperative
  54. multitasked macos. For an MPW Tool, it also spinns the cursor.}
  55. procedure Yield;
  56. {To set mac file type and creator codes, to be used for files created
  57. by the FPC runtime library. They must be exactly 4 chars long.}
  58. procedure SetDefaultMacOSFiletype(ftype: ShortString);
  59. procedure SetDefaultMacOSCreator(creator: ShortString);
  60. var
  61. {Whether unix and dos style paths should be translated. Default false}
  62. pathTranslation: Boolean;
  63. {*********************************}
  64. {** Available features on macos **}
  65. {*********************************}
  66. var
  67. macosHasGestalt: Boolean;
  68. macosHasWaitNextEvent: Boolean;
  69. macosHasColorQD: Boolean;
  70. macosHasFPU: Boolean;
  71. macosSystemVersion: Integer;
  72. macosHasSysDebugger: Boolean = false;
  73. macosHasCFM: Boolean;
  74. macosHasAppleEvents: Boolean;
  75. macosHasAliasMgr: Boolean;
  76. macosHasFSSpec: Boolean;
  77. macosHasFindFolder: Boolean;
  78. macosHasScriptMgr: Boolean;
  79. macosNrOfScriptsInstalled: Integer;
  80. macosHasAppearance: Boolean;
  81. macosHasAppearance101: Boolean;
  82. macosHasAppearance11: Boolean;
  83. macosBootVolumeVRefNum: Integer;
  84. macosBootVolumeName: String[31];
  85. {
  86. MacOS paths
  87. ===========
  88. MacOS directory separator is a colon ":" which is the only character not
  89. allowed in filenames.
  90. A path containing no colon or which begins with a colon is a partial path.
  91. E g ":kalle:petter" ":kalle" "kalle"
  92. All other paths are full (absolute) paths. E g "HD:kalle:" "HD:"
  93. When generating paths, one is safe is one ensures that all partial paths
  94. begins with a colon, and all full paths ends with a colon.
  95. In full paths the first name (e g HD above) is the name of a mounted volume.
  96. These names are not unique, because, for instance, two diskettes with the
  97. same names could be inserted. This means that paths on MacOS is not
  98. waterproof. In case of equal names the first volume found will do.
  99. Two colons "::" are the relative path to the parent. Three is to the
  100. grandparent etc.
  101. }
  102. implementation
  103. {
  104. About the implementation
  105. ========================
  106. A MacOS application is assembled and linked by MPW (Macintosh
  107. Programmers Workshop), which nowadays is free to use. For info
  108. and download of MPW and MacOS api, see www.apple.com
  109. It can be linked to either a graphical user interface application,
  110. a standalone text only application (using SIOW) or
  111. to an MPW tool, this is entirely controlled by the linking step.
  112. It requires system 7 and CFM, which is always the case for PowerPC.
  113. If a m68k version would be implemented, it would save a lot
  114. of efforts if it also uses CFM. This System.pp should, with
  115. minor modifications, probably work with m68k.
  116. Initial working directory is the directory of the application,
  117. or for an MPWTool, the working directory as set by the
  118. Directory command in MPW.
  119. Note about working directory. There is a facility in MacOS which
  120. manages a working directory for an application, initially set to
  121. the applications directory, or for an MPWTool, the tool's directory.
  122. However, this requires the application to have a unique application
  123. signature (creator code), to distinguish its working directory
  124. from working directories of other applications. Due to the fact
  125. that casual applications are anonymous in this sense (without an
  126. application signature), this facility will not work. Also, this
  127. working directory facility is not present in Carbon. Hence we
  128. will manage a working directory by our self.
  129. Deviations
  130. ==========
  131. In current implementation, working directory is stored as
  132. directory id. This means there is a possibility the user moves the
  133. working directory or a parent to it, while the application uses it.
  134. Then the path to the wd suddenly changes. This is AFAIK not in
  135. accordance with other OS's. Although this is a minor caveat,
  136. it is mentioned here. To overcome this the wd could be stored
  137. as a path instead, but this imposes translations from fullpath
  138. to directory ID each time the filesystem is accessed.
  139. The initial working directory for an MPWTool, as considered by
  140. FPC, is different from the MacOS working directory facility,
  141. see above.
  142. Possible improvements:
  143. =====================
  144. Perhaps handle readonly filesystems, as in sysunix.inc
  145. }
  146. {$if defined(cpum68k) and defined(fpusoft)}
  147. {$define fpc_softfpu_implementation}
  148. {$define softfpu_compiler_mul32to64}
  149. {$define softfpu_inline}
  150. {$i softfpu.pp}
  151. {$undef fpc_softfpu_implementation}
  152. { we get these functions and types from the softfpu code }
  153. {$define FPC_SYSTEM_HAS_float64}
  154. {$define FPC_SYSTEM_HAS_float32}
  155. {$define FPC_SYSTEM_HAS_flag}
  156. {$define FPC_SYSTEM_HAS_extractFloat64Frac0}
  157. {$define FPC_SYSTEM_HAS_extractFloat64Frac1}
  158. {$define FPC_SYSTEM_HAS_extractFloat64Exp}
  159. {$define FPC_SYSTEM_HAS_extractFloat64Sign}
  160. {$define FPC_SYSTEM_HAS_ExtractFloat32Frac}
  161. {$define FPC_SYSTEM_HAS_extractFloat32Exp}
  162. {$define FPC_SYSTEM_HAS_extractFloat32Sign}
  163. {$endif defined(cpum68k) and defined(fpusoft)}
  164. {******** include system independent routines **********}
  165. {$I system.inc}
  166. {*****************************************************************************
  167. ParamStr/Randomize
  168. *****************************************************************************}
  169. { number of args }
  170. function paramcount : longint;
  171. begin
  172. paramcount := argc - 1;
  173. //paramcount:=0;
  174. end;
  175. { argument number l }
  176. function paramstr(l : longint) : string;
  177. begin
  178. if (l>=0) and (l+1<=argc) then
  179. paramstr:=strpas(argv[l])
  180. else
  181. paramstr:='';
  182. end;
  183. { set randseed to a new pseudo random value }
  184. procedure randomize;
  185. begin
  186. randseed:= Cardinal(TickCount);
  187. end;
  188. {*****************************************************************************
  189. SystemUnit Initialization
  190. *****************************************************************************}
  191. {$ifndef FPC_DARWIN_PASCALMAIN}
  192. procedure pascalmain; external name 'PASCALMAIN';
  193. {Main entry point in C style, needed to capture program parameters.
  194. For this to work, the system unit must be before the main program
  195. in the linking order.}
  196. procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
  197. {$else FPC_DARWIN_PASCALMAIN}
  198. procedure FPC_SYSTEMMAIN(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
  199. {$endif FPC_DARWIN_PASCALMAIN}
  200. begin
  201. argc:= argcparam;
  202. argv:= argvparam;
  203. envp:= envpparam;
  204. {$ifndef FPC_DARWIN_PASCALMAIN}
  205. pascalmain; {run the pascal main program}
  206. {$endif FPC_DARWIN_PASCALMAIN}
  207. end;
  208. procedure setup_arguments;
  209. begin
  210. {Nothing needs to be done here.}
  211. end;
  212. procedure setup_environment;
  213. begin
  214. end;
  215. { FindSysFolder returns the (real) vRefNum, and the DirID of the current
  216. system folder. It uses the Folder Manager if present, otherwise it falls
  217. back to SysEnvirons. It returns zero on success, otherwise a standard
  218. system error. }
  219. function FindSysFolder(var foundVRefNum: Integer; var foundDirID: Longint): OSErr;
  220. var
  221. gesResponse: Longint;
  222. envRec: SysEnvRec;
  223. myWDPB: WDPBRec;
  224. volName: String[34];
  225. err: OSErr;
  226. begin
  227. foundVRefNum := 0;
  228. foundDirID := 0;
  229. if macosHasGestalt
  230. and (Gestalt (FourCharCodeToLongword(gestaltFindFolderAttr), gesResponse) = noErr)
  231. and BitIsSet (gesResponse, gestaltFindFolderPresent) then
  232. begin { Does Folder Manager exist? }
  233. err := FindFolder (kOnSystemDisk, FourCharCodeToLongword(kSystemFolderType),
  234. kDontCreateFolder, foundVRefNum, foundDirID);
  235. end
  236. else
  237. begin
  238. { Gestalt can't give us the answer, so we resort to SysEnvirons }
  239. err := SysEnvirons (curSysEnvVers, envRec);
  240. if (err = noErr) then
  241. begin
  242. myWDPB.ioVRefNum := envRec.sysVRefNum;
  243. volName := '';
  244. myWDPB.ioNamePtr := @volName;
  245. myWDPB.ioWDIndex := 0;
  246. myWDPB.ioWDProcID := 0;
  247. err := PBGetWDInfoSync (@myWDPB);
  248. if (err = noErr) then
  249. begin
  250. foundVRefNum := myWDPB.ioWDVRefNum;
  251. foundDirID := myWDPB.ioWDDirID;
  252. end;
  253. end;
  254. end;
  255. FindSysFolder:= err;
  256. end;
  257. {$ifdef CPUM68K}
  258. {$WARNING FIXME: Dummy TrapAvailable!}
  259. function TrapAvailable(_trap: Word): Boolean;
  260. begin
  261. TrapAvailable:=false;
  262. end;
  263. {$endif CPUM68K}
  264. procedure InvestigateSystem;
  265. {$IFDEF CPUM68K}
  266. const
  267. _GestaltDispatch = $A0AD;
  268. _WaitNextEvent = $A860;
  269. _ScriptUtil = $A8B5;
  270. qdOffscreenTrap = $AB1D;
  271. {$ENDIF}
  272. var
  273. err: Integer;
  274. response: Longint;
  275. {$IFDEF CPUM68K}
  276. environs: SysEnvRec;
  277. {$ENDIF}
  278. {Vi rŠknar med att man kšr pŒ minst system 6.0.5. DŒ finns bŒde Gestalt och GDevice med.}
  279. {Enligt Change Histrory Šr MacOS 6.0.5 mera konsistent mellan maskinmodellerna Šn fšregŒende system}
  280. begin
  281. {$IFDEF CPUM68K}
  282. macosHasGestalt := TrapAvailable(_GestaltDispatch);
  283. {$ELSE}
  284. macosHasGestalt := true; {There is always Gestalt on PowerPC}
  285. {$ENDIF}
  286. if not macosHasGestalt then (* If we don't have Gestalt, then we can't have any System 7 features *)
  287. begin
  288. {$IFDEF CPUM68K}
  289. { Detta kan endast gŠlla pŒ en 68K maskin.}
  290. macosHasScriptMgr := TrapAvailable(_ScriptUtil);
  291. macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
  292. err := SysEnvirons(1, environs);
  293. if err = noErr then
  294. begin
  295. if environs.machineType < 0 then { gammalt ROM}
  296. macosHasWaitNextEvent := FALSE
  297. else
  298. macosHasWaitNextEvent := TrapAvailable(_WaitNextEvent);
  299. macosHasColorQD := environs.hasColorQD;
  300. macosHasFPU := environs.hasFPU;
  301. macosSystemVersion := environs.systemVersion;
  302. end
  303. else
  304. begin
  305. macosHasWaitNextEvent := FALSE;
  306. macosHasColorQD := FALSE;
  307. macosHasFPU := FALSE;
  308. macosSystemVersion := 0;
  309. end;
  310. {$WARNING FIXME: MacJmp}
  311. //macosHasSysDebugger := (LongintPtr(MacJmp)^ <> 0);
  312. macosHasSysDebugger := false;
  313. macosHasCFM := false;
  314. macosHasAppleEvents := false;
  315. macosHasAliasMgr := false;
  316. macosHasFSSpec := false;
  317. macosHasFindFolder := false;
  318. macosHasAppearance := false;
  319. macosHasAppearance101 := false;
  320. macosHasAppearance11 := false;
  321. {$IFDEF THINK_PASCAL}
  322. if (macosHasScriptMgr) then
  323. macosNrOfScriptsInstalled := GetEnvirons(smEnabled);
  324. {$ELSE}
  325. {$WARNING FIXME: GetScriptManagerVariable and smEnabled}
  326. //if (macosHasScriptMgr) then
  327. // macosNrOfScriptsInstalled := GetScriptManagerVariable(smEnabled); {Gamla rutinnamnet var GetEnvirons.}
  328. {$ENDIF}
  329. {$ENDIF CPUM68K}
  330. end
  331. else
  332. begin
  333. macosHasScriptMgr := Gestalt(FourCharCodeToLongword(gestaltScriptMgrVersion), response) = noErr; {Fšr att ta reda pŒ om script mgr finns.}
  334. macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
  335. macosHasWaitNextEvent := true;
  336. if Gestalt(FourCharCodeToLongword(gestaltSystemVersion), response) = noErr then
  337. macosSystemVersion := response
  338. else
  339. macosSystemVersion := 0; {Borde inte kunna hŠnda.}
  340. if Gestalt(FourCharCodeToLongword(gestaltOSAttr), response) = noErr then
  341. macosHasSysDebugger := BitIsSet(response, gestaltSysDebuggerSupport)
  342. else
  343. macosHasSysDebugger := false;
  344. if Gestalt(FourCharCodeToLongword(gestaltQuickdrawVersion), response) = noErr then
  345. macosHasColorQD := (response >= $0100)
  346. else
  347. macosHasColorQD := false;
  348. if Gestalt(FourCharCodeToLongword(gestaltFPUType), response) = noErr then
  349. macosHasFPU := (response <> gestaltNoFPU)
  350. else
  351. macosHasFPU := false;
  352. if Gestalt(FourCharCodeToLongword(gestaltCFMAttr), response) = noErr then
  353. macosHasCFM := BitIsSet(response, gestaltCFMPresent)
  354. else
  355. macosHasCFM := false;
  356. macosHasAppleEvents := Gestalt(FourCharCodeToLongword(gestaltAppleEventsAttr), response) = noErr;
  357. macosHasAliasMgr := Gestalt(FourCharCodeToLongword(gestaltAliasMgrAttr), response) = noErr;
  358. if Gestalt(FourCharCodeToLongword(gestaltFSAttr), response) = noErr then
  359. macosHasFSSpec := BitIsSet(response, gestaltHasFSSpecCalls)
  360. else
  361. macosHasFSSpec := false;
  362. macosHasFindFolder := Gestalt(FourCharCodeToLongword(gestaltFindFolderAttr), response) = noErr;
  363. if macosHasScriptMgr then
  364. begin
  365. err := Gestalt(FourCharCodeToLongword(gestaltScriptCount), response);
  366. if (err = noErr) then
  367. macosNrOfScriptsInstalled := Integer(response);
  368. end;
  369. if (Gestalt(FourCharCodeToLongword(gestaltAppearanceAttr), response) = noErr) then
  370. begin
  371. macosHasAppearance := BitIsSet(response, gestaltAppearanceExists);
  372. if Gestalt(FourCharCodeToLongword(gestaltAppearanceVersion), response) = noErr then
  373. begin
  374. macosHasAppearance101 := (response >= $101);
  375. macosHasAppearance11 := (response >= $110);
  376. end
  377. end
  378. else
  379. begin
  380. macosHasAppearance := false;
  381. macosHasAppearance101 := false;
  382. macosHasAppearance11 := false;
  383. end;
  384. end;
  385. end;
  386. {*****************************************************************************
  387. System Dependent Exit code
  388. *****************************************************************************}
  389. Procedure system_exit;
  390. var
  391. s: ShortString;
  392. begin
  393. if StandAlone <> 0 then
  394. if exitcode <> 0 then
  395. begin
  396. Str(exitcode,s);
  397. if IsConsole then
  398. Writeln( '### Program exited with exit code ' + s)
  399. else if macosHasSysDebugger then
  400. DebugStr('A possible error occurred, exit code: ' + s + '. Type "g" and return to continue.')
  401. else
  402. {Be quiet}
  403. end;
  404. {$ifndef MACOS_USE_STDCLIB}
  405. if StandAlone <> 0 then
  406. ExitToShell;
  407. {$else}
  408. c_exit(exitcode); {exitcode is only utilized by an MPW tool}
  409. {$endif}
  410. end;
  411. procedure SysInitStdIO;
  412. begin
  413. { Setup stdin, stdout and stderr }
  414. {$ifdef MACOS_USE_STDCLIB}
  415. OpenStdIO(Input,fmInput,StdInputHandle);
  416. OpenStdIO(Output,fmOutput,StdOutputHandle);
  417. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  418. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  419. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  420. {$endif }
  421. end;
  422. function GetProcessID: SizeUInt;
  423. begin
  424. GetProcessID := 1;
  425. {$WARNING To be implemented - using GetProcessInformation???}
  426. end;
  427. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  428. begin
  429. result := stklen;
  430. end;
  431. var
  432. resHdl: Mac_Handle;
  433. isFolder, hadAlias, leafIsAlias: Boolean;
  434. dirStr: string[2];
  435. err: OSErr;
  436. dummySysFolderDirID: Longint;
  437. begin
  438. InvestigateSystem; {Must be first}
  439. {Check requred features for system.pp to work.}
  440. if not macosHasFSSpec then
  441. Halt(3); //exit code 3 according to MPW
  442. if FindSysFolder(macosBootVolumeVRefNum, dummySysFolderDirID) <> noErr then
  443. Halt(3); //exit code 3 according to MPW
  444. if GetVolumeName(macosBootVolumeVRefNum, macosBootVolumeName) <> noErr then
  445. Halt(3); //exit code 3 according to MPW
  446. { To be set if this is a GUI or console application }
  447. if StandAlone = 0 then
  448. IsConsole := true {Its an MPW tool}
  449. else
  450. begin
  451. resHdl:= Get1Resource(FourCharCodeToLongword('siow'),0);
  452. IsConsole := (resHdl <> nil); {A SIOW app is also a console}
  453. ReleaseResource(resHdl);
  454. end;
  455. { To be set if this is a library and not a program }
  456. IsLibrary := FALSE;
  457. StackLength := CheckInitialStkLen(InitialStkLen);
  458. StackBottom := SPtr - StackLength;
  459. pathTranslation:= false;
  460. { Setup working directory }
  461. if StandAlone <> 0 then
  462. begin
  463. if not GetAppFileLocation(workingDirectorySpec) then
  464. Halt(3); //exit code 3 according to MPW
  465. end
  466. else
  467. begin
  468. { The fictive file x is used to make
  469. FSMakeFSSpec return a FSSpec to a file in the directory.
  470. Then by clearing the name, the FSSpec then
  471. points to the directory. It doesn't matter whether x exists or not.}
  472. dirStr:= ':x';
  473. err:= ResolveFolderAliases(0, 0, @dirStr, true,
  474. workingDirectorySpec, isFolder, hadAlias, leafIsAlias);
  475. workingDirectorySpec.name:='';
  476. if (err <> noErr) and (err <> fnfErr) then
  477. Halt(3); //exit code 3 according to MPW
  478. end;
  479. { Setup heap }
  480. if StandAlone <> 0 then
  481. MaxApplZone;
  482. InitHeap;
  483. SysInitExceptions;
  484. initunicodestringmanager;
  485. SysInitStdIO;
  486. { Setup environment and arguments }
  487. Setup_Environment;
  488. setup_arguments;
  489. { Reset IO Error }
  490. InOutRes:=0;
  491. errno:=0;
  492. InitSystemThreads;
  493. if StandAlone = 0 then
  494. begin
  495. InitGraf(@qd.thePort);
  496. SetFScaleDisable(true);
  497. InitCursorCtl(nil);
  498. end;
  499. end.