2
0

system.pp 17 KB

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