system.pp 18 KB

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