system.pp 16 KB

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