system.pp 17 KB

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