system.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302
  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. {Platform specific information}
  17. type
  18. {$ifdef CPU64}
  19. THandle = Int64;
  20. {$else CPU64}
  21. THandle = Longint;
  22. {$endif CPU64}
  23. const
  24. LineEnding = #13;
  25. LFNSupport = true;
  26. DirectorySeparator = ':';
  27. DriveSeparator = ':';
  28. PathSeparator = ','; {Is used in MPW and OzTeX}
  29. FileNameCaseSensitive = false;
  30. maxExitCode = 65535;
  31. { include heap support headers }
  32. {$I heaph.inc}
  33. const
  34. { Default filehandles }
  35. UnusedHandle : Longint = -1;
  36. StdInputHandle : Longint = 0;
  37. StdOutputHandle : Longint = 1;
  38. StdErrorHandle : Longint = 2;
  39. sLineBreak = LineEnding;
  40. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCR;
  41. var
  42. argc : longint;
  43. argv : ppchar;
  44. envp : ppchar;
  45. {*********************************}
  46. {** MacOS specific functions **}
  47. {*********************************}
  48. {To be called at regular intervals, for lenghty tasks.
  49. Yield might give time for other tasks to run under the cooperative
  50. multitasked macos. For an MPW Tool, it also spinns the cursor.}
  51. procedure Yield;
  52. {To set mac file type and creator codes, to be used for files created
  53. by the FPC runtime library. They must be exactly 4 chars long.}
  54. procedure SetDefaultMacOSFiletype(ftype: ShortString);
  55. procedure SetDefaultMacOSCreator(creator: ShortString);
  56. {*********************************}
  57. {** Available features on macos **}
  58. {*********************************}
  59. var
  60. macosHasGestalt: Boolean;
  61. macosHasWaitNextEvent: Boolean;
  62. macosHasColorQD: Boolean;
  63. macosHasFPU: Boolean;
  64. macosSystemVersion: Integer;
  65. macosHasSysDebugger: Boolean = false;
  66. macosHasCFM: Boolean;
  67. macosHasAppleEvents: Boolean;
  68. macosHasAliasMgr: Boolean;
  69. macosHasFSSpec: Boolean;
  70. macosHasFindFolder: Boolean;
  71. macosHasScriptMgr: Boolean;
  72. macosNrOfScriptsInstalled: Integer;
  73. macosHasAppearance: Boolean;
  74. macosHasAppearance101: Boolean;
  75. macosHasAppearance11: Boolean;
  76. macosBootVolumeVRefNum: Integer;
  77. macosBootVolumeName: String[31];
  78. {
  79. MacOS paths
  80. ===========
  81. MacOS directory separator is a colon ":" which is the only character not
  82. allowed in filenames.
  83. A path containing no colon or which begins with a colon is a partial path.
  84. E g ":kalle:petter" ":kalle" "kalle"
  85. All other paths are full (absolute) paths. E g "HD:kalle:" "HD:"
  86. When generating paths, one is safe is one ensures that all partial paths
  87. begins with a colon, and all full paths ends with a colon.
  88. In full paths the first name (e g HD above) is the name of a mounted volume.
  89. These names are not unique, because, for instance, two diskettes with the
  90. same names could be inserted. This means that paths on MacOS is not
  91. waterproof. In case of equal names the first volume found will do.
  92. Two colons "::" are the relative path to the parent. Three is to the
  93. grandparent etc.
  94. }
  95. implementation
  96. {
  97. About the implementation
  98. ========================
  99. A MacOS application is assembled and linked by MPW (Macintosh
  100. Programmers Workshop), which nowadays is free to use. For info
  101. and download of MPW and MacOS api, see www.apple.com
  102. It can be linked to either a graphical user interface application,
  103. a standalone text only application (using SIOW) or
  104. to an MPW tool, this is entirely controlled by the linking step.
  105. It requires system 7 and CFM, which is always the case for PowerPC.
  106. If a m68k version would be implemented, it would save a lot
  107. of efforts if it also uses CFM. This System.pp should, with
  108. minor modifications, probably work with m68k.
  109. Initial working directory is the directory of the application,
  110. or for an MPWTool, the working directory as set by the
  111. Directory command in MPW.
  112. Note about working directory. There is a facility in MacOS which
  113. manages a working directory for an application, initially set to
  114. the applications directory, or for an MPWTool, the tool's directory.
  115. However, this requires the application to have a unique application
  116. signature (creator code), to distinguish its working directory
  117. from working directories of other applications. Due to the fact
  118. that casual applications are anonymous in this sense (without an
  119. application signature), this facility will not work. Also, this
  120. working directory facility is not present in Carbon. Hence we
  121. will manage a working directory by our self.
  122. Deviations
  123. ==========
  124. In current implementation, working directory is stored as
  125. directory id. This means there is a possibility the user moves the
  126. working directory or a parent to it, while the application uses it.
  127. Then the path to the wd suddenly changes. This is AFAIK not in
  128. accordance with other OS's. Although this is a minor caveat,
  129. it is mentioned here. To overcome this the wd could be stored
  130. as a path instead, but this imposes translations from fullpath
  131. to directory ID each time the filesystem is accessed.
  132. The initial working directory for an MPWTool, as considered by
  133. FPC, is different from the MacOS working directory facility,
  134. see above.
  135. Possible improvements:
  136. =====================
  137. Perhaps handle readonly filesystems, as in sysunix.inc
  138. }
  139. {******** include system independent routines **********}
  140. {$I system.inc}
  141. {*********************** MacOS API *********************}
  142. {This implementation uses StdCLib: }
  143. {$define MACOS_USE_STDCLIB}
  144. {Some MacOS API routines and StdCLib included for internal use:}
  145. {$I macostp.inc}
  146. {Note, because the System unit is the most low level, it should not
  147. depend on any other units, and thus the macos api must be accessed
  148. as an include file and not a unit.}
  149. {The reason StdCLib is used is that it can easily be connected
  150. to either SIOW or, in case of MPWTOOL, to MPW }
  151. {If the Apples Universal Interfaces are used, the qd variable is required
  152. to be allocated somewhere, so we do it here for the convenience to the user.}
  153. var
  154. qd: QDGlobals; cvar;
  155. {$ifdef MACOS_USE_STDCLIB}
  156. {************** API to StdCLib in MacOS ***************}
  157. {The reason StdCLib is used is that it can easily be connected
  158. to either SIOW or, in case of MPWTOOL, to MPW }
  159. {$endif}
  160. {*********************** Macutils *********************}
  161. {And also include the same utilities as in the macutils.pp unit.}
  162. var
  163. {emulated working directory}
  164. workingDirectorySpec: FSSpec; cvar;
  165. {Also declared in macutils.pp as external. Declared here to be available
  166. to macutils.inc and below in this file.}
  167. {$I macutils.inc}
  168. {******************************************************}
  169. function GetAppFileLocation (var spec: FSSpec): Boolean;
  170. {Requires >= System 7}
  171. var
  172. PSN: ProcessSerialNumber;
  173. info: ProcessInfoRec;
  174. appFileRefNum: Integer;
  175. appName: Str255;
  176. dummy: Mac_Handle;
  177. begin
  178. begin
  179. PSN.highLongOfPSN := 0;
  180. PSN.lowLongOfPSN := kCurrentProcess;
  181. info.processInfoLength := SizeOf(info);
  182. info.processName := nil;
  183. info.processAppSpec := @spec;
  184. if GetProcessInformation(PSN, info) = noErr then
  185. begin
  186. spec.name := '';
  187. GetAppFileLocation := true;
  188. end
  189. else
  190. GetAppFileLocation := false;
  191. end
  192. end;
  193. Procedure Errno2InOutRes;
  194. {
  195. Convert ErrNo error to the correct InOutRes value.
  196. It seems that some of the errno is, in macos,
  197. used for other purposes than its original definition.
  198. }
  199. begin
  200. if errno = 0 then { Else it will go through all the cases }
  201. exit;
  202. case Errno of
  203. Sys_ENFILE,
  204. Sys_EMFILE : Inoutres:=4;
  205. Sys_ENOENT : Inoutres:=2;
  206. Sys_EBADF : Inoutres:=6;
  207. Sys_ENOMEM,
  208. Sys_EFAULT : Inoutres:=217; //TODO Exchange to something better
  209. Sys_EINVAL : Inoutres:=218; //TODO RTE 218 doesn't exist
  210. Sys_EAGAIN,
  211. Sys_ENOSPC : Inoutres:=101;
  212. Sys_ENOTDIR : Inoutres:=3;
  213. Sys_EPERM,
  214. Sys_EROFS,
  215. Sys_EEXIST,
  216. Sys_EISDIR,
  217. Sys_EINTR, //Happens when attempt to rename a file fails
  218. Sys_EBUSY, //Happens when attempt to remove a locked file
  219. Sys_EACCES,
  220. Sys_EMLINK : Inoutres:=5; //Happens when attempt to remove open file
  221. Sys_ENXIO : InOutRes:=152;
  222. Sys_ESPIPE : InOutRes:=156; //Illegal seek
  223. else
  224. InOutRes := Integer(errno);//TODO Exchange to something better
  225. end;
  226. errno:=0;
  227. end;
  228. Procedure OSErr2InOutRes(err: OSErr);
  229. begin
  230. InOutRes:= MacOSErr2RTEerr(err);
  231. end;
  232. function FSpLocationFromFullPath(fullPathLength: Integer;
  233. fullPath: Mac_Ptr; var spec: FSSpec ):OSErr;
  234. var
  235. alias: AliasHandle;
  236. res: OSErr;
  237. wasChanged: Boolean;
  238. nullString: Str32;
  239. begin
  240. nullString:= '';
  241. res:= NewAliasMinimalFromFullPath(fullPathLength,
  242. fullPath, nullString, nullString, alias);
  243. if res = noErr then
  244. begin
  245. res:= ResolveAlias(nil, alias, spec, wasChanged);
  246. DisposeHandle(Mac_Handle(alias));
  247. end;
  248. FSpLocationFromFullPath:= res;
  249. end;
  250. {*****************************************************************************
  251. MacOS specific functions
  252. *****************************************************************************}
  253. var
  254. defaultCreator: OSType = $4D505320; {'MPS ' MPW Shell}
  255. //defaultCreator: OSType = $74747874; {'ttxt' Simple Text}
  256. defaultFileType: OSType = $54455854; {'TEXT'}
  257. procedure Yield;
  258. begin
  259. if StandAlone = 0 then
  260. SpinCursor(1);
  261. end;
  262. procedure SetDefaultMacOSFiletype(ftype: ShortString);
  263. begin
  264. if Length(ftype) = 4 then
  265. defaultFileType:= PLongWord(@ftype[1])^;
  266. end;
  267. procedure SetDefaultMacOSCreator(creator: ShortString);
  268. begin
  269. if Length(creator) = 4 then
  270. defaultCreator:= PLongWord(@creator[1])^;
  271. end;
  272. {*****************************************************************************
  273. ParamStr/Randomize
  274. *****************************************************************************}
  275. { number of args }
  276. function paramcount : longint;
  277. begin
  278. paramcount := argc - 1;
  279. //paramcount:=0;
  280. end;
  281. { argument number l }
  282. function paramstr(l : longint) : string;
  283. begin
  284. if (l>=0) and (l+1<=argc) then
  285. paramstr:=strpas(argv[l])
  286. else
  287. paramstr:='';
  288. end;
  289. { set randseed to a new pseudo random value }
  290. procedure randomize;
  291. begin
  292. randseed:= Cardinal(TickCount);
  293. end;
  294. {*****************************************************************************
  295. OS Memory allocation / deallocation
  296. ****************************************************************************}
  297. { function to allocate size bytes more for the program }
  298. { must return the first address of new data space or nil if failed }
  299. function SysOSAlloc(size: ptrint): pointer;
  300. begin
  301. result := NewPtr(size);
  302. end;
  303. {$define HAS_SYSOSFREE}
  304. procedure SysOSFree(p: pointer; size: ptrint);
  305. begin
  306. DisposePtr(p);
  307. end;
  308. { include standard heap management }
  309. {$I heap.inc}
  310. {*****************************************************************************
  311. Low Level File Routines
  312. ****************************************************************************}
  313. function do_isdevice(handle:longint):boolean;
  314. begin
  315. do_isdevice:=false;
  316. end;
  317. { close a file from the handle value }
  318. procedure do_close(h : longint);
  319. var
  320. err: OSErr;
  321. {No error handling, according to the other targets, which seems reasonable,
  322. because close might be used to clean up after an error.}
  323. begin
  324. {$ifdef MACOS_USE_STDCLIB}
  325. c_close(h);
  326. // Errno2InOutRes;
  327. {$else}
  328. err:= FSClose(h);
  329. // OSErr2InOutRes(err);
  330. {$endif}
  331. end;
  332. procedure do_erase(p : pchar);
  333. var
  334. spec: FSSpec;
  335. err: OSErr;
  336. res: Integer;
  337. begin
  338. res:= PathArgToFSSpec(p, spec);
  339. if (res = 0) then
  340. begin
  341. if not IsDirectory(spec) then
  342. begin
  343. err:= FSpDelete(spec);
  344. OSErr2InOutRes(err);
  345. end
  346. else
  347. InOutRes:= 2;
  348. end
  349. else
  350. InOutRes:=res;
  351. end;
  352. procedure do_rename(p1,p2 : pchar);
  353. var
  354. s1,s2: AnsiString;
  355. begin
  356. {$ifdef MACOS_USE_STDCLIB}
  357. InOutRes:= PathArgToFullPath(p1, s1);
  358. if InOutRes <> 0 then
  359. exit;
  360. InOutRes:= PathArgToFullPath(p2, s2);
  361. if InOutRes <> 0 then
  362. exit;
  363. c_rename(PChar(s1),PChar(s2));
  364. Errno2InoutRes;
  365. {$else}
  366. InOutRes:=1;
  367. {$endif}
  368. end;
  369. function do_write(h:longint;addr:pointer;len : longint) : longint;
  370. begin
  371. {$ifdef MACOS_USE_STDCLIB}
  372. do_write:= c_write(h, addr, len);
  373. Errno2InoutRes;
  374. {$else}
  375. InOutRes:=1;
  376. if FSWrite(h, len, Mac_Ptr(addr)) = noErr then
  377. InOutRes:=0;
  378. do_write:= len;
  379. {$endif}
  380. end;
  381. function do_read(h:longint;addr:pointer;len : longint) : longint;
  382. var
  383. i: Longint;
  384. begin
  385. {$ifdef MACOS_USE_STDCLIB}
  386. len:= c_read(h, addr, len);
  387. Errno2InoutRes;
  388. do_read:= len;
  389. {$else}
  390. InOutRes:=1;
  391. if FSread(h, len, Mac_Ptr(addr)) = noErr then
  392. InOutRes:=0;
  393. do_read:= len;
  394. {$endif}
  395. end;
  396. function do_filepos(handle : longint) : longint;
  397. var
  398. pos: Longint;
  399. begin
  400. {$ifdef MACOS_USE_STDCLIB}
  401. {This returns the filepos without moving it.}
  402. do_filepos := lseek(handle, 0, SEEK_CUR);
  403. Errno2InoutRes;
  404. {$else}
  405. InOutRes:=1;
  406. if GetFPos(handle, pos) = noErr then
  407. InOutRes:=0;
  408. do_filepos:= pos;
  409. {$endif}
  410. end;
  411. procedure do_seek(handle,pos : longint);
  412. begin
  413. {$ifdef MACOS_USE_STDCLIB}
  414. lseek(handle, pos, SEEK_SET);
  415. Errno2InoutRes;
  416. {$else}
  417. InOutRes:=1;
  418. if SetFPos(handle, fsFromStart, pos) = noErr then
  419. InOutRes:=0;
  420. {$endif}
  421. end;
  422. function do_seekend(handle:longint):longint;
  423. begin
  424. {$ifdef MACOS_USE_STDCLIB}
  425. do_seekend:= lseek(handle, 0, SEEK_END);
  426. Errno2InoutRes;
  427. {$else}
  428. InOutRes:=1;
  429. if SetFPos(handle, fsFromLEOF, 0) = noErr then
  430. InOutRes:=0;
  431. {TODO Resulting file position is to be returned.}
  432. {$endif}
  433. end;
  434. function do_filesize(handle : longint) : longint;
  435. var
  436. aktfilepos: Longint;
  437. begin
  438. {$ifdef MACOS_USE_STDCLIB}
  439. aktfilepos:= lseek(handle, 0, SEEK_CUR);
  440. if errno = 0 then
  441. begin
  442. do_filesize := lseek(handle, 0, SEEK_END);
  443. Errno2InOutRes; {Report the error from this operation.}
  444. lseek(handle, aktfilepos, SEEK_SET); {Always try to move back,
  445. even in presence of error.}
  446. end
  447. else
  448. Errno2InOutRes;
  449. {$else}
  450. InOutRes:=1;
  451. if GetEOF(handle, pos) = noErr then
  452. InOutRes:=0;
  453. do_filesize:= pos;
  454. {$endif}
  455. end;
  456. { truncate at a given position }
  457. procedure do_truncate (handle,pos:longint);
  458. begin
  459. {$ifdef MACOS_USE_STDCLIB}
  460. ioctl(handle, FIOSETEOF, pointer(pos));
  461. Errno2InoutRes;
  462. {$else}
  463. InOutRes:=1;
  464. do_seek(handle,pos); //TODO: Is this needed (Does the user anticipate the filemarker is at the end?)
  465. if SetEOF(handle, pos) = noErr then
  466. InOutRes:=0;
  467. {$endif}
  468. end;
  469. procedure do_open(var f;p:pchar;flags:longint);
  470. {
  471. filerec and textrec have both handle and mode as the first items so
  472. they could use the same routine for opening/creating.
  473. when (flags and $100) the file will be append
  474. when (flags and $1000) the file will be truncate/rewritten
  475. when (flags and $10000) there is no check for close (needed for textfiles)
  476. }
  477. var
  478. scriptTag: ScriptCode;
  479. refNum: Integer;
  480. err: OSErr;
  481. res: Integer;
  482. spec: FSSpec;
  483. fh: Longint;
  484. oflags : longint;
  485. fullPath: AnsiString;
  486. finderInfo: FInfo;
  487. begin
  488. // AllowSlash(p);
  489. { close first if opened }
  490. if ((flags and $10000)=0) then
  491. begin
  492. case filerec(f).mode of
  493. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  494. fmclosed : ;
  495. else
  496. begin
  497. {not assigned}
  498. inoutres:=102;
  499. exit;
  500. end;
  501. end;
  502. end;
  503. { reset file handle }
  504. filerec(f).handle:=UnusedHandle;
  505. {$ifdef MACOS_USE_STDCLIB}
  506. { We do the conversion of filemodes here, concentrated on 1 place }
  507. case (flags and 3) of
  508. 0 : begin
  509. oflags :=O_RDONLY;
  510. filerec(f).mode:=fminput;
  511. end;
  512. 1 : begin
  513. oflags :=O_WRONLY;
  514. filerec(f).mode:=fmoutput;
  515. end;
  516. 2 : begin
  517. oflags :=O_RDWR;
  518. filerec(f).mode:=fminout;
  519. end;
  520. end;
  521. if (flags and $1000)=$1000 then
  522. oflags:=oflags or (O_CREAT or O_TRUNC)
  523. else if (flags and $100)=$100 then
  524. oflags:=oflags or (O_APPEND);
  525. { empty name is special }
  526. if p[0]=#0 then
  527. begin
  528. case FileRec(f).mode of
  529. fminput :
  530. FileRec(f).Handle:=StdInputHandle;
  531. fminout, { this is set by rewrite }
  532. fmoutput :
  533. FileRec(f).Handle:=StdOutputHandle;
  534. fmappend :
  535. begin
  536. FileRec(f).Handle:=StdOutputHandle;
  537. FileRec(f).mode:=fmoutput; {fool fmappend}
  538. end;
  539. end;
  540. exit;
  541. end
  542. else
  543. begin
  544. InOutRes:= PathArgToFSSpec(p, spec);
  545. if (InOutRes = 0) or (InOutRes = 2) then
  546. begin
  547. err:= FSpGetFullPath(spec, fullPath, false);
  548. InOutRes:= MacOSErr2RTEerr(err);
  549. end;
  550. if InOutRes <> 0 then
  551. exit;
  552. p:= PChar(fullPath);
  553. if FileRec(f).mode in [fmoutput, fminout, fmappend] then
  554. begin
  555. {Since opening of an existing file will not change filetype and creator,
  556. it is set here. Otherwise overwritten darwin files will not get filetype
  557. TEXT. This is not done when only opening file for reading.}
  558. FSpGetFInfo(spec, finderInfo);
  559. finderInfo.fdType:= defaultFileType;
  560. finderInfo.fdCreator:= defaultCreator;
  561. FSpSetFInfo(spec, finderInfo);
  562. end;
  563. end;
  564. fh:= c_open(p, oflags);
  565. if (fh = -1) and (errno = Sys_EROFS) and ((oflags and O_RDWR)<>0) then
  566. begin
  567. oflags:=oflags and not(O_RDWR);
  568. fh:= c_open(p, oflags);
  569. end;
  570. Errno2InOutRes;
  571. if fh <> -1 then
  572. filerec(f).handle:= fh
  573. else
  574. filerec(f).handle:= UnusedHandle;
  575. {$else}
  576. InOutRes:=1;
  577. { reset file handle }
  578. filerec(f).handle:=UnusedHandle;
  579. res:= FSpLocationFromFullPath(StrLen(p), p, spec);
  580. if (res = noErr) or (res = fnfErr) then
  581. begin
  582. if FSpCreate(spec, defaultCreator, defaultFileType, smSystemScript) = noErr then
  583. ;
  584. if FSpOpenDF(spec, fsCurPerm, refNum) = noErr then
  585. begin
  586. filerec(f).handle:= refNum;
  587. InOutRes:=0;
  588. end;
  589. end;
  590. if (filerec(f).handle=UnusedHandle) then
  591. begin
  592. //errno:=GetLastError;
  593. //Errno2InoutRes;
  594. end;
  595. {$endif}
  596. end;
  597. {*****************************************************************************
  598. UnTyped File Handling
  599. *****************************************************************************}
  600. {$i file.inc}
  601. {*****************************************************************************
  602. Typed File Handling
  603. *****************************************************************************}
  604. {$i typefile.inc}
  605. {*****************************************************************************
  606. Text File Handling
  607. *****************************************************************************}
  608. { #26 is not end of a file in MacOS ! }
  609. {$i text.inc}
  610. {*****************************************************************************
  611. Directory Handling
  612. *****************************************************************************}
  613. procedure mkdir(const s:string);[IOCheck];
  614. var
  615. spec: FSSpec;
  616. createdDirID: Longint;
  617. err: OSErr;
  618. res: Integer;
  619. begin
  620. If (s='') or (InOutRes <> 0) then
  621. exit;
  622. res:= PathArgToFSSpec(s, spec);
  623. if (res = 0) or (res = 2) then
  624. begin
  625. err:= FSpDirCreate(spec, smSystemScript, createdDirID);
  626. OSErr2InOutRes(err);
  627. end
  628. else
  629. InOutRes:=res;
  630. end;
  631. procedure rmdir(const s:string);[IOCheck];
  632. var
  633. spec: FSSpec;
  634. err: OSErr;
  635. res: Integer;
  636. begin
  637. If (s='') or (InOutRes <> 0) then
  638. exit;
  639. res:= PathArgToFSSpec(s, spec);
  640. if (res = 0) then
  641. begin
  642. if IsDirectory(spec) then
  643. begin
  644. err:= FSpDelete(spec);
  645. OSErr2InOutRes(err);
  646. end
  647. else
  648. InOutRes:= 20;
  649. end
  650. else
  651. InOutRes:=res;
  652. end;
  653. procedure chdir(const s:string);[IOCheck];
  654. var
  655. spec, newDirSpec: FSSpec;
  656. err: OSErr;
  657. res: Integer;
  658. begin
  659. if (s='') or (InOutRes <> 0) then
  660. exit;
  661. res:= PathArgToFSSpec(s, spec);
  662. if (res = 0) or (res = 2) then
  663. begin
  664. { The fictive file x is appended to the directory name to make
  665. FSMakeFSSpec return a FSSpec to a file in the directory.
  666. Then by clearing the name, the FSSpec then
  667. points to the directory. It doesn't matter whether x exists or not.}
  668. err:= FSMakeFSSpec (spec.vRefNum, spec.parID, ':'+spec.name+':x', newDirSpec);
  669. if (err = noErr) or (err = fnfErr) then
  670. begin
  671. workingDirectorySpec:= newDirSpec;
  672. workingDirectorySpec.name:='';
  673. InOutRes:= 0;
  674. end
  675. else
  676. begin
  677. {E g if the directory doesn't exist.}
  678. OSErr2InOutRes(err);
  679. end;
  680. end
  681. else
  682. InOutRes:=res;
  683. end;
  684. procedure getDir (DriveNr: byte; var Dir: ShortString);
  685. var
  686. fullPath: AnsiString;
  687. pathHandleSize: Longint;
  688. begin
  689. if FSpGetFullPath(workingDirectorySpec, fullPath, false) <> noErr then
  690. Halt(3); {exit code 3 according to MPW}
  691. if Length(fullPath) <= 255 then {because dir is ShortString}
  692. InOutRes := 0
  693. else
  694. InOutRes := 1; //TODO Exchange to something better
  695. dir:= fullPath;
  696. end;
  697. {*****************************************************************************
  698. SystemUnit Initialization
  699. *****************************************************************************}
  700. procedure pascalmain; external name 'PASCALMAIN';
  701. {Main entry point in C style, needed to capture program parameters.
  702. For this to work, the system unit must be before the main program
  703. in the linking order.}
  704. procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
  705. begin
  706. argc:= argcparam;
  707. argv:= argvparam;
  708. envp:= envpparam;
  709. pascalmain; {run the pascal main program}
  710. end;
  711. procedure setup_arguments;
  712. begin
  713. {Nothing needs to be done here.}
  714. end;
  715. procedure setup_environment;
  716. begin
  717. end;
  718. { FindSysFolder returns the (real) vRefNum, and the DirID of the current
  719. system folder. It uses the Folder Manager if present, otherwise it falls
  720. back to SysEnvirons. It returns zero on success, otherwise a standard
  721. system error. }
  722. function FindSysFolder(var foundVRefNum: Integer; var foundDirID: Longint): OSErr;
  723. var
  724. gesResponse: Longint;
  725. envRec: SysEnvRec;
  726. myWDPB: WDPBRec;
  727. volName: String[34];
  728. err: OSErr;
  729. begin
  730. foundVRefNum := 0;
  731. foundDirID := 0;
  732. if macosHasGestalt
  733. and (Gestalt (FourCharCodeToLongword(gestaltFindFolderAttr), gesResponse) = noErr)
  734. and BitIsSet (gesResponse, gestaltFindFolderPresent) then
  735. begin { Does Folder Manager exist? }
  736. err := FindFolder (kOnSystemDisk, FourCharCodeToLongword(kSystemFolderType),
  737. kDontCreateFolder, foundVRefNum, foundDirID);
  738. end
  739. else
  740. begin
  741. { Gestalt can't give us the answer, so we resort to SysEnvirons }
  742. err := SysEnvirons (curSysEnvVers, envRec);
  743. if (err = noErr) then
  744. begin
  745. myWDPB.ioVRefNum := envRec.sysVRefNum;
  746. volName := '';
  747. myWDPB.ioNamePtr := @volName;
  748. myWDPB.ioWDIndex := 0;
  749. myWDPB.ioWDProcID := 0;
  750. err := PBGetWDInfoSync (@myWDPB);
  751. if (err = noErr) then
  752. begin
  753. foundVRefNum := myWDPB.ioWDVRefNum;
  754. foundDirID := myWDPB.ioWDDirID;
  755. end;
  756. end;
  757. end;
  758. FindSysFolder:= err;
  759. end;
  760. procedure InvestigateSystem;
  761. {$IFDEF CPUM68K}
  762. const
  763. _GestaltDispatch = $A0AD;
  764. _WaitNextEvent = $A860;
  765. _ScriptUtil = $A8B5;
  766. qdOffscreenTrap = $AB1D;
  767. {$ENDIF}
  768. var
  769. err: Integer;
  770. response: Longint;
  771. {$IFDEF CPUM68K}
  772. environs: SysEnvRec;
  773. {$ENDIF}
  774. {Vi rŠknar med att man kšr pŒ minst system 6.0.5. DŒ finns bŒde Gestalt och GDevice med.}
  775. {Enligt Change Histrory Šr MacOS 6.0.5 mera konsistent mellan maskinmodellerna Šn fšregŒende system}
  776. begin
  777. {$IFDEF CPUM68K}
  778. macosHasGestalt := TrapAvailable(_GestaltDispatch);
  779. {$ELSE}
  780. macosHasGestalt := true; {There is always Gestalt on PowerPC}
  781. {$ENDIF}
  782. if not macosHasGestalt then (* If we don't have Gestalt, then we can't have any System 7 features *)
  783. begin
  784. {$IFDEF CPUM68K}
  785. { Detta kan endast gŠlla pŒ en 68K maskin.}
  786. macosHasScriptMgr := TrapAvailable(_ScriptUtil);
  787. macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
  788. err := SysEnvirons(1, environs);
  789. if err = noErr then
  790. begin
  791. if environs.machineType < 0 then { gammalt ROM}
  792. macosHasWaitNextEvent := FALSE
  793. else
  794. macosHasWaitNextEvent := TrapAvailable(_WaitNextEvent);
  795. macosHasColorQD := environs.hasColorQD;
  796. macosHasFPU := environs.hasFPU;
  797. macosSystemVersion := environs.systemVersion;
  798. end
  799. else
  800. begin
  801. macosHasWaitNextEvent := FALSE;
  802. macosHasColorQD := FALSE;
  803. macosHasFPU := FALSE;
  804. macosSystemVersion := 0;
  805. end;
  806. macosHasSysDebugger := (LongintPtr(MacJmp)^ <> 0);
  807. macosHasCFM := false;
  808. macosHasAppleEvents := false;
  809. macosHasAliasMgr := false;
  810. macosHasFSSpec := false;
  811. macosHasFindFolder := false;
  812. macosHasAppearance := false;
  813. macosHasAppearance101 := false;
  814. macosHasAppearance11 := false;
  815. {$IFDEF THINK_PASCAL}
  816. if (macosHasScriptMgr) then
  817. macosNrOfScriptsInstalled := GetEnvirons(smEnabled);
  818. {$ELSE}
  819. if (macosHasScriptMgr) then
  820. macosNrOfScriptsInstalled := GetScriptManagerVariable(smEnabled); {Gamla rutinnamnet var GetEnvirons.}
  821. {$ENDIF}
  822. {$ENDIF}
  823. end
  824. else
  825. begin
  826. macosHasScriptMgr := Gestalt(FourCharCodeToLongword(gestaltScriptMgrVersion), response) = noErr; {Fšr att ta reda pŒ om script mgr finns.}
  827. macosNrOfScriptsInstalled := 1; (* assume only Roman script, to start with *)
  828. macosHasWaitNextEvent := true;
  829. if Gestalt(FourCharCodeToLongword(gestaltSystemVersion), response) = noErr then
  830. macosSystemVersion := response
  831. else
  832. macosSystemVersion := 0; {Borde inte kunna hŠnda.}
  833. if Gestalt(FourCharCodeToLongword(gestaltOSAttr), response) = noErr then
  834. macosHasSysDebugger := BitIsSet(response, gestaltSysDebuggerSupport)
  835. else
  836. macosHasSysDebugger := false;
  837. if Gestalt(FourCharCodeToLongword(gestaltQuickdrawVersion), response) = noErr then
  838. macosHasColorQD := (response >= $0100)
  839. else
  840. macosHasColorQD := false;
  841. if Gestalt(FourCharCodeToLongword(gestaltFPUType), response) = noErr then
  842. macosHasFPU := (response <> gestaltNoFPU)
  843. else
  844. macosHasFPU := false;
  845. if Gestalt(FourCharCodeToLongword(gestaltCFMAttr), response) = noErr then
  846. macosHasCFM := BitIsSet(response, gestaltCFMPresent)
  847. else
  848. macosHasCFM := false;
  849. macosHasAppleEvents := Gestalt(FourCharCodeToLongword(gestaltAppleEventsAttr), response) = noErr;
  850. macosHasAliasMgr := Gestalt(FourCharCodeToLongword(gestaltAliasMgrAttr), response) = noErr;
  851. if Gestalt(FourCharCodeToLongword(gestaltFSAttr), response) = noErr then
  852. macosHasFSSpec := BitIsSet(response, gestaltHasFSSpecCalls)
  853. else
  854. macosHasFSSpec := false;
  855. macosHasFindFolder := Gestalt(FourCharCodeToLongword(gestaltFindFolderAttr), response) = noErr;
  856. if macosHasScriptMgr then
  857. begin
  858. err := Gestalt(FourCharCodeToLongword(gestaltScriptCount), response);
  859. if (err = noErr) then
  860. macosNrOfScriptsInstalled := Integer(response);
  861. end;
  862. if (Gestalt(FourCharCodeToLongword(gestaltAppearanceAttr), response) = noErr) then
  863. begin
  864. macosHasAppearance := BitIsSet(response, gestaltAppearanceExists);
  865. if Gestalt(FourCharCodeToLongword(gestaltAppearanceVersion), response) = noErr then
  866. begin
  867. macosHasAppearance101 := (response >= $101);
  868. macosHasAppearance11 := (response >= $110);
  869. end
  870. end
  871. else
  872. begin
  873. macosHasAppearance := false;
  874. macosHasAppearance101 := false;
  875. macosHasAppearance11 := false;
  876. end;
  877. end;
  878. end;
  879. {*****************************************************************************
  880. System Dependent Exit code
  881. *****************************************************************************}
  882. Procedure system_exit;
  883. var
  884. s: ShortString;
  885. begin
  886. if StandAlone <> 0 then
  887. if exitcode <> 0 then
  888. begin
  889. Str(exitcode,s);
  890. if IsConsole then
  891. Writeln( '### Program exited with exit code ' + s)
  892. else if macosHasSysDebugger then
  893. DebugStr('A possible error occured, exit code: ' + s + '. Type "g" and return to continue.')
  894. else
  895. {Be quiet}
  896. end;
  897. {$ifndef MACOS_USE_STDCLIB}
  898. if StandAlone <> 0 then
  899. ExitToShell;
  900. {$else}
  901. c_exit(exitcode); {exitcode is only utilized by an MPW tool}
  902. {$endif}
  903. end;
  904. procedure SysInitStdIO;
  905. begin
  906. { Setup stdin, stdout and stderr }
  907. {$ifdef MACOS_USE_STDCLIB}
  908. OpenStdIO(Input,fmInput,StdInputHandle);
  909. OpenStdIO(Output,fmOutput,StdOutputHandle);
  910. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  911. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  912. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  913. {$endif }
  914. end;
  915. var
  916. resHdl: Mac_Handle;
  917. isFolder, hadAlias, leafIsAlias: Boolean;
  918. dirStr: string[2];
  919. err: OSErr;
  920. dummySysFolderDirID: Longint;
  921. begin
  922. InvestigateSystem; {Must be first}
  923. {Check requred features for system.pp to work.}
  924. if not macosHasFSSpec then
  925. Halt(3); //exit code 3 according to MPW
  926. if FindSysFolder(macosBootVolumeVRefNum, dummySysFolderDirID) <> noErr then
  927. Halt(3); //exit code 3 according to MPW
  928. if GetVolumeName(macosBootVolumeVRefNum, macosBootVolumeName) <> noErr then
  929. Halt(3); //exit code 3 according to MPW
  930. { To be set if this is a GUI or console application }
  931. if StandAlone = 0 then
  932. IsConsole := true {Its an MPW tool}
  933. else
  934. begin
  935. resHdl:= Get1Resource(FourCharCodeToLongword('siow'),0);
  936. IsConsole := (resHdl <> nil); {A SIOW app is also a console}
  937. ReleaseResource(resHdl);
  938. end;
  939. { To be set if this is a library and not a program }
  940. IsLibrary := FALSE;
  941. StackLength := InitialStkLen;
  942. StackBottom := SPtr - StackLength;
  943. { Setup working directory }
  944. if StandAlone <> 0 then
  945. begin
  946. if not GetAppFileLocation(workingDirectorySpec) then
  947. Halt(3); //exit code 3 according to MPW
  948. end
  949. else
  950. begin
  951. { The fictive file x is used to make
  952. FSMakeFSSpec return a FSSpec to a file in the directory.
  953. Then by clearing the name, the FSSpec then
  954. points to the directory. It doesn't matter whether x exists or not.}
  955. dirStr:= ':x';
  956. err:= ResolveFolderAliases(0, 0, @dirStr, true,
  957. workingDirectorySpec, isFolder, hadAlias, leafIsAlias);
  958. workingDirectorySpec.name:='';
  959. if (err <> noErr) and (err <> fnfErr) then
  960. Halt(3); //exit code 3 according to MPW
  961. end;
  962. { Setup heap }
  963. if StandAlone <> 0 then
  964. MaxApplZone;
  965. InitHeap;
  966. SysInitExceptions;
  967. SysInitStdIO;
  968. { Setup environment and arguments }
  969. Setup_Environment;
  970. setup_arguments;
  971. { Reset IO Error }
  972. InOutRes:=0;
  973. errno:=0;
  974. (* This should be changed to a real value during *)
  975. (* thread driver initialization if appropriate. *)
  976. ThreadID := 1;
  977. {$ifdef HASVARIANT}
  978. initvariantmanager;
  979. {$endif HASVARIANT}
  980. if StandAlone = 0 then
  981. begin
  982. InitGraf(@qd.thePort);
  983. SetFScaleDisable(true);
  984. InitCursorCtl(nil);
  985. end;
  986. end.
  987. {
  988. $Log$
  989. Revision 1.25 2004-11-04 09:32:31 peter
  990. ErrOutput added
  991. Revision 1.24 2004/10/25 15:38:59 peter
  992. * compiler defined HEAP and HEAPSIZE removed
  993. Revision 1.23 2004/10/19 19:56:59 olle
  994. * Interface to StdLibC moved from system to macostp
  995. Revision 1.22 2004/09/30 19:58:42 olle
  996. + Added SetDefaultMacOS[Filetype|Creator]
  997. * Files written to by fpc rtl now always will get decent filetype/creator
  998. * Adapted to use FSpGetFullPath
  999. Revision 1.21 2004/09/12 19:51:02 olle
  1000. + InitGraf called for MPW tool, which make strange bug disappear.
  1001. * bugfix initial wd for MPW tool
  1002. + Added SysInitExceptions
  1003. Revision 1.20 2004/09/03 19:26:08 olle
  1004. + added maxExitCode to all System.pp
  1005. * constrained error code to be below maxExitCode in RunError et. al.
  1006. Revision 1.19 2004/08/20 10:18:15 olle
  1007. + added Yield routine
  1008. Revision 1.18 2004/07/14 23:34:07 olle
  1009. + added qd, the "QuickDraw globals"
  1010. Revision 1.17 2004/06/21 19:23:34 olle
  1011. + Variables describing misc OS features added
  1012. + Detection of GUI app
  1013. * Working directory for APPTYPE TOOL correct now
  1014. + Exit code <> 0 written to, console for console apps, to system debugger (if installed) for GUI apps.
  1015. * Misc fixes
  1016. Revision 1.16 2004/06/17 16:16:13 peter
  1017. * New heapmanager that releases memory back to the OS, donated
  1018. by Micha Nelissen
  1019. Revision 1.15 2004/05/11 18:05:41 olle
  1020. + added call to MaxApplZone to have the whole MacOS heap available
  1021. Revision 1.14 2004/04/29 11:27:36 olle
  1022. * do_read/do_write addr arg changed to pointer
  1023. * misc internal changes
  1024. Revision 1.13 2004/02/04 15:17:16 olle
  1025. * internal changes
  1026. Revision 1.12 2004/01/20 23:11:20 hajny
  1027. * ExecuteProcess fixes, ProcessID and ThreadID added
  1028. Revision 1.11 2004/01/04 21:06:43 jonas
  1029. * make the C-main public
  1030. Revision 1.10 2003/10/29 22:34:52 olle
  1031. + handles program parameters for MPW
  1032. + program start stub
  1033. * improved working directory handling
  1034. * minor changes
  1035. + some documentation
  1036. Revision 1.9 2003/10/17 23:44:30 olle
  1037. + working direcory emulated
  1038. + implemented directory handling procs
  1039. + all proc which take a path param, now resolve it relative wd
  1040. Revision 1.8 2003/10/16 15:43:13 peter
  1041. * THandle is platform dependent
  1042. Revision 1.7 2003/09/27 11:52:35 peter
  1043. * sbrk returns pointer
  1044. Revision 1.6 2003/09/12 12:45:15 olle
  1045. + filehandling complete
  1046. + heaphandling complete
  1047. + support for random
  1048. * filehandling now uses filedecriptors in StdCLib
  1049. * other minor changes
  1050. - removed DEFINE MAC_SYS_RUNNABLE
  1051. Revision 1.5 2003/01/13 17:18:55 olle
  1052. + added support for rudimentary file handling
  1053. Revision 1.4 2002/11/28 10:58:02 olle
  1054. + added support for rudimentary heap
  1055. Revision 1.3 2002/10/23 15:29:09 olle
  1056. + added switch MAC_SYS_RUNABLE
  1057. + added include of system.h etc
  1058. + added standard globals
  1059. + added dummy hook procedures
  1060. Revision 1.2 2002/10/10 19:44:05 florian
  1061. * changes from Olle to compile/link a simple program
  1062. Revision 1.1 2002/10/02 21:34:31 florian
  1063. * first dummy implementation
  1064. }