system.pp 37 KB

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