system.pp 37 KB

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