system.pp 17 KB

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