system.pp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  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 paths
  46. ===========
  47. MacOS directory separator is a colon ":" which is the only character not
  48. allowed in filenames.
  49. A path containing no colon or which begins with a colon is a partial path.
  50. E g ":kalle:petter" ":kalle" "kalle"
  51. All other paths are full (absolute) paths. E g "HD:kalle:" "HD:"
  52. When generating paths, one is safe is one ensures that all partial paths
  53. begins with a colon, and all full paths ends with a colon.
  54. In full paths the first name (e g HD above) is the name of a mounted volume.
  55. These names are not unique, because, for instance, two diskettes with the
  56. same names could be inserted. This means that paths on MacOS is not
  57. waterproof. In case of equal names the first volume found will do.
  58. Two colons "::" are the relative path to the parent. Three is to the
  59. grandparent etc.
  60. }
  61. implementation
  62. {
  63. About the implementation
  64. ========================
  65. A MacOS application is assembled and linked by MPW (Macintosh
  66. Programmers Workshop), which nowadays is free to use. For info
  67. and download of MPW and MacOS api, see www.apple.com
  68. It can be linked to either a standalone application (using SIOW) or
  69. to an MPW tool, this is entirely controlled by the linking step.
  70. It requires system 7 and CFM, which is always the case for PowerPC.
  71. If a m68k version would be implemented, it would save a lot
  72. of efforts if it also uses CFM. This System.pp should, with
  73. minor modifications, probably work with m68k.
  74. Initial working directory is the directory of the application,
  75. or for an MPWTool, the MPW directory.
  76. Note about working directory. There is a facility in MacOS which
  77. manages a working directory for an application, initially set to
  78. the applictaions directory, or for an MPWTool, the tool's directory.
  79. However, this requires the application to have a unique application
  80. signature (creator code), to distinguish its working directory
  81. from working directories of other applications. Due to the fact
  82. that casual applications are anonymous in this sense (without an
  83. application signature), this facility will not work. Hence we
  84. will manage a working directory by our self.
  85. Deviations
  86. ==========
  87. In current implementation, working directory is stored as
  88. directory id. This means there is a possibility the user moves the
  89. working directory or a parent to it, while the application uses it.
  90. Then the path to the wd suddenly changes. This is AFAIK not in
  91. accordance with other OS's. Although this is a minor caveat,
  92. it is mentioned here. To overcome this the wd could be stored
  93. as a path instead, but this imposes translations from fullpath
  94. to directory id each time the filesystem is accessed.
  95. The initial working directory for an MPWTool, as considered by
  96. FPC, is different from the MacOS working directory facility,
  97. see above.
  98. Possible improvements:
  99. =====================
  100. TODO: Add check so that working directory cannot be removed. Alt ensure
  101. the nothing crashes if wd is removed.
  102. TODO: rmdir and erase does not differentiate between files and directories
  103. thus removing both of them.
  104. TODO: Check of the MacOS version (and prescence of CFM) to
  105. ensure it is a supported version. only needed for m68k.
  106. }
  107. {This implementation uses StdCLib, which is included in the MPW.}
  108. {$define MACOS_USE_STDCLIB}
  109. {******** include system independent routines **********}
  110. {$I system.inc}
  111. {*********************** MacOS API *********************}
  112. {Below is some MacOS API routines included for internal use.
  113. Note, because the System unit is the most low level, it should not
  114. depend on any other units, and thus the macos api must be accessed
  115. as an include file and not a unit.}
  116. {$I macostp.inc}
  117. {$ifdef MACOS_USE_STDCLIB}
  118. {************** API to StdCLib in MacOS ***************}
  119. {The reason StdCLib is used is that it can easily be connected
  120. to either SIOW or, in case of MPWTOOL, to MPW }
  121. {The prefix C_ or c_ is used where names conflicts with pascal
  122. keywords and names. Suffix Ptr is added for pointer to a type.}
  123. type
  124. size_t = Longint;
  125. off_t = Longint;
  126. C_int = Longint;
  127. C_short = Integer;
  128. C_long = Longint;
  129. C_unsigned_int = Cardinal;
  130. var
  131. errno: C_int; external name 'errno';
  132. MacOSErr: C_short; external name 'MacOSErr';
  133. const
  134. _IOFBF = $00;
  135. _IOLBF = $40;
  136. _IONBF = $04;
  137. O_RDONLY = $00; // Open for reading only.
  138. O_WRONLY = $01; // Open for writing only.
  139. O_RDWR = $02; // Open for reading & writing.
  140. O_APPEND = $08; // Write to the end of the file.
  141. O_RSRC = $10; // Open the resource fork.
  142. O_ALIAS = $20; // Open alias file.
  143. O_CREAT = $100; // Open or create a file.
  144. O_TRUNC = $200; // Open and truncate to zero length.
  145. O_EXCL = $400; // Create file only; fail if exists.
  146. O_BINARY = $800; // Open as a binary stream.
  147. O_NRESOLVE = $4000; // Don't resolve any aliases.
  148. SEEK_SET = 0;
  149. SEEK_CUR = 1;
  150. SEEK_END = 2;
  151. FIOINTERACTIVE = $00006602; // If device is interactive
  152. FIOBUFSIZE = $00006603; // Return optimal buffer size
  153. FIOFNAME = $00006604; // Return filename
  154. FIOREFNUM = $00006605; // Return fs refnum
  155. FIOSETEOF = $00006606; // Set file length
  156. TIOFLUSH = $00007408; // discard unread input. arg is ignored
  157. function c_open(path: PChar; oflag: C_int): C_int; cdecl;
  158. external 'StdCLib' name 'open';
  159. function c_close(filedes: C_int): C_int; cdecl;
  160. external 'StdCLib' name 'close';
  161. function c_write(filedes: C_int; buf: pointer; nbyte: size_t): size_t; cdecl;
  162. external 'StdCLib' name 'write';
  163. function c_read(filedes: C_int; buf: pointer; nbyte: size_t): size_t; cdecl;
  164. external 'StdCLib' name 'read';
  165. function lseek(filedes: C_int; offset: off_t; whence: C_int): off_t; cdecl;
  166. external 'StdCLib' name 'lseek';
  167. function ioctl(filedes: C_int; cmd: C_unsigned_int; arg: pointer): C_int; cdecl;
  168. external 'StdCLib' name 'ioctl';
  169. function remove(filename: PChar): C_int; cdecl;
  170. external 'StdCLib';
  171. function c_rename(old, c_new: PChar): C_int; cdecl;
  172. external 'StdCLib' name 'rename';
  173. procedure c_exit(status: C_int); cdecl;
  174. external 'StdCLib' name 'exit';
  175. {cdecl is actually only needed for m68k}
  176. var
  177. {Is set to nonzero for MPWTool, zero otherwise.}
  178. StandAlone: C_int; external name 'StandAlone';
  179. CONST
  180. Sys_EPERM = 1; { No permission match }
  181. Sys_ENOENT = 2; { No such file or directory }
  182. Sys_ENORSRC = 3; { Resource not found *}
  183. Sys_EINTR = 4; { System service interrupted *}
  184. Sys_EIO = 5; { I/O error }
  185. Sys_ENXIO = 6; { No such device or address }
  186. Sys_E2BIG = 7; { Insufficient space for return argument * }
  187. Sys_ENOEXEC = 8; { File not executable * }
  188. Sys_EBADF = 9; { Bad file number }
  189. Sys_ECHILD = 10; { No child processes }
  190. Sys_EAGAIN = 11; { Resource temporarily unavailable * }
  191. Sys_ENOMEM = 12; { Not enough space * }
  192. Sys_EACCES = 13; { Permission denied }
  193. Sys_EFAULT = 14; { Illegal filename * }
  194. Sys_ENOTBLK = 15; { Block device required }
  195. Sys_EBUSY = 16; { Device or resource busy }
  196. Sys_EEXIST = 17; { File exists }
  197. Sys_EXDEV = 18; { Cross-device link }
  198. Sys_ENODEV = 19; { No such device }
  199. Sys_ENOTDIR = 20; { Not a directory }
  200. Sys_EISDIR = 21; { Is a directory }
  201. Sys_EINVAL = 22; { Invalid parameter * }
  202. Sys_ENFILE = 23; { File table overflow }
  203. Sys_EMFILE = 24; { Too many open files }
  204. Sys_ENOTTY = 25; { Not a typewriter }
  205. Sys_ETXTBSY = 26; { Text file busy }
  206. Sys_EFBIG = 27; { File too large }
  207. Sys_ENOSPC = 28; { No space left on device }
  208. Sys_ESPIPE = 29; { Illegal seek }
  209. Sys_EROFS = 30; { Read-only file system }
  210. Sys_EMLINK = 31; { Too many links }
  211. Sys_EPIPE = 32; { Broken pipe }
  212. Sys_EDOM = 33; { Math argument out of domain of func }
  213. Sys_ERANGE = 34; { Math result not representable }
  214. { Note * is slightly different, compared to rtl/sunos/errno.inc}
  215. {$endif}
  216. {******************************************************}
  217. var
  218. {working directory}
  219. curDirectorySpec: FSSpec;
  220. function GetAppFileLocation (var spec: FSSpec): Boolean;
  221. //Requires >= System 7
  222. var
  223. PSN: ProcessSerialNumber;
  224. info: ProcessInfoRec;
  225. appFileRefNum: Integer;
  226. appName: Str255;
  227. dummy: Mac_Handle;
  228. begin
  229. begin
  230. PSN.highLongOfPSN := 0;
  231. PSN.lowLongOfPSN := kCurrentProcess;
  232. info.processInfoLength := SizeOf(info);
  233. info.processName := nil;
  234. info.processAppSpec := @spec;
  235. if GetProcessInformation(PSN, info) = noErr then
  236. begin
  237. spec.name := '';
  238. GetAppFileLocation := true;
  239. end
  240. else
  241. GetAppFileLocation := false;
  242. end
  243. end;
  244. {Gives the path for a given file or directory. If parent is true,
  245. a path to the directory, where the file or directory is located,
  246. is returned. Functioning even with System 6}
  247. function FSpGetFullPath (spec: FSSpec; var fullPathHandle: Mac_Handle;
  248. parent: Boolean): OSErr;
  249. var
  250. res: OSErr;
  251. pb: CInfoPBRec;
  252. begin
  253. fullPathHandle:= NewHandle(0); { Allocate a zero-length handle }
  254. if fullPathHandle = nil then
  255. begin
  256. FSpGetFullPath:= MemError;
  257. Exit;
  258. end;
  259. if spec.parID = fsRtParID then { The object is a volume }
  260. begin
  261. if not parent then
  262. begin
  263. { Add a colon to make it a full pathname }
  264. spec.name := Concat(spec.name, ':');
  265. { We're done }
  266. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  267. res := MemError;
  268. end
  269. else
  270. res := noErr;
  271. end
  272. else
  273. begin
  274. { The object isn't a volume }
  275. { Add the object name }
  276. if not parent then
  277. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  278. { Get the ancestor directory names }
  279. pb.ioNamePtr := @spec.name;
  280. pb.ioVRefNum := spec.vRefNum;
  281. pb.ioDrParID := spec.parID;
  282. repeat { loop until we have an error or find the root directory }
  283. begin
  284. pb.ioFDirIndex := -1;
  285. pb.ioDrDirID := pb.ioDrParID;
  286. res := PBGetCatInfoSync(@pb);
  287. if res = noErr then
  288. begin
  289. { Append colon to directory name }
  290. spec.name := Concat(spec.name, ':');
  291. { Add directory name to fullPathHandle }
  292. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  293. res := MemError;
  294. end
  295. end
  296. until not ((res = noErr) and (pb.ioDrDirID <> fsRtDirID));
  297. end;
  298. if res <> noErr then
  299. begin
  300. DisposeHandle(fullPathHandle);
  301. fullPathHandle:= nil;
  302. end;
  303. FSpGetFullPath := res;
  304. end;
  305. Procedure Errno2InOutRes;
  306. {
  307. Convert ErrNo error to the correct InOutRes value.
  308. It seems that some of the errno is, in macos,
  309. used for other purposes than its original definition.
  310. }
  311. begin
  312. if errno = 0 then { Else it will go through all the cases }
  313. exit;
  314. case Errno of
  315. Sys_ENFILE,
  316. Sys_EMFILE : Inoutres:=4;
  317. Sys_ENOENT : Inoutres:=2;
  318. Sys_EBADF : Inoutres:=6;
  319. Sys_ENOMEM,
  320. Sys_EFAULT : Inoutres:=217; //TODO Exchange to something better
  321. Sys_EINVAL : Inoutres:=218; //TODO RTE 218 doesn't exist
  322. Sys_EAGAIN,
  323. Sys_ENOSPC : Inoutres:=101;
  324. Sys_ENOTDIR : Inoutres:=3;
  325. Sys_EPERM,
  326. Sys_EROFS,
  327. Sys_EEXIST,
  328. Sys_EISDIR,
  329. Sys_EINTR, //Happens when attempt to rename a file fails
  330. Sys_EBUSY, //Happens when attempt to remove a locked file
  331. Sys_EACCES,
  332. Sys_ETXTBSY, //Happens when attempt to open an already open file
  333. Sys_EMLINK : Inoutres:=5; //Happens when attempt to remove open file
  334. Sys_ENXIO : InOutRes:=152;
  335. Sys_ESPIPE : InOutRes:=156; //Illegal seek
  336. else
  337. InOutRes := Integer(errno);//TODO Exchange to something better
  338. end;
  339. errno:=0;
  340. end;
  341. Procedure OSErr2InOutRes(err: OSErr);
  342. { Convert MacOS specific error codes to the correct InOutRes value}
  343. begin
  344. if err = noErr then { Else it will go through all the cases }
  345. exit;
  346. case err of
  347. dirFulErr, { Directory full }
  348. dskFulErr { disk full }
  349. :Inoutres:=101;
  350. nsvErr { no such volume }
  351. :Inoutres:=3;
  352. ioErr, { I/O error (bummers) }
  353. bdNamErr { there may be no bad names in the final system! }
  354. :Inoutres:=1; //TODO Exchange to something better
  355. fnOpnErr { File not open }
  356. :Inoutres:=103;
  357. eofErr, { End of file }
  358. posErr { tried to position to before start of file (r/w) }
  359. :Inoutres:=100;
  360. mFulErr { memory full (open) or file won't fit (load) }
  361. :Inoutres:=1; //TODO Exchange to something better
  362. tmfoErr { too many files open}
  363. :Inoutres:=4;
  364. fnfErr { File not found }
  365. :Inoutres:=2;
  366. wPrErr { diskette is write protected. }
  367. :Inoutres:=150;
  368. fLckdErr { file is locked }
  369. :Inoutres:=5;
  370. vLckdErr { volume is locked }
  371. :Inoutres:=150;
  372. fBsyErr { File is busy (delete) }
  373. :Inoutres:=5;
  374. dupFNErr { duplicate filename (rename) }
  375. :Inoutres:=5;
  376. opWrErr { file already open with with write permission }
  377. :Inoutres:=5;
  378. rfNumErr, { refnum error }
  379. gfpErr { get file position error }
  380. :Inoutres:=1; //TODO Exchange to something better
  381. volOffLinErr { volume not on line error (was Ejected) }
  382. :Inoutres:=152;
  383. permErr { permissions error (on file open) }
  384. :Inoutres:=5;
  385. volOnLinErr{ drive volume already on-line at MountVol }
  386. :Inoutres:=0; //TODO Exchange to something other
  387. nsDrvErr { no such drive (tried to mount a bad drive num) }
  388. :Inoutres:=1; //TODO Perhaps exchange to something better
  389. noMacDskErr, { not a mac diskette (sig bytes are wrong) }
  390. extFSErr { volume in question belongs to an external fs }
  391. :Inoutres:=157; //TODO Perhaps exchange to something better
  392. fsRnErr, { file system internal error:during rename the old
  393. entry was deleted but could not be restored. }
  394. badMDBErr { bad master directory block }
  395. :Inoutres:=1; //TODO Exchange to something better
  396. wrPermErr { write permissions error }
  397. :Inoutres:=5;
  398. dirNFErr { Directory not found }
  399. :Inoutres:=3;
  400. tmwdoErr { No free WDCB available }
  401. :Inoutres:=1; //TODO Exchange to something better
  402. badMovErr { Move into offspring error }
  403. :Inoutres:=5;
  404. wrgVolTypErr { Wrong volume type error [operation not
  405. supported for MFS] }
  406. :Inoutres:=1; //TODO Exchange to something better
  407. volGoneErr { Server volume has been disconnected. }
  408. :Inoutres:=152;
  409. diffVolErr { files on different volumes }
  410. :Inoutres:=17;
  411. catChangedErr { the catalog has been modified }
  412. { OR comment: when searching with PBCatSearch }
  413. :Inoutres:=0; //TODO Exchange to something other
  414. afpAccessDenied, { Insufficient access privileges for operation }
  415. afpDenyConflict { Specified open/deny modes conflict with current open modes }
  416. :Inoutres:=5;
  417. afpNoMoreLocks { Maximum lock limit reached }
  418. :Inoutres:=5;
  419. afpRangeNotLocked, { Tried to unlock range that was not locked by user }
  420. afpRangeOverlap { Some or all of range already locked by same user }
  421. :Inoutres:=1; //TODO Exchange to something better
  422. afpObjectTypeErr { File/Directory specified where Directory/File expected }
  423. :Inoutres:=3;
  424. afpCatalogChanged { OR comment: when searching with PBCatSearch }
  425. :Inoutres:=0; //TODO Exchange to something other
  426. afpSameObjectErr
  427. :Inoutres:=5; //TODO Exchange to something better
  428. memFullErr { Not enough room in heap zone }
  429. :Inoutres:=203;
  430. else
  431. InOutRes := 1; //TODO Exchange to something better
  432. end;
  433. end;
  434. function PathArgToFSSpec(s: string; var spec: FSSpec): Boolean;
  435. var
  436. err: OSErr;
  437. begin
  438. err:= FSMakeFSSpec(curDirectorySpec.vRefNum,
  439. curDirectorySpec.parID, s, spec);
  440. if err in [ noErr, fnfErr] then
  441. PathArgToFSSpec:= true
  442. else
  443. begin
  444. OSErr2InOutRes(err);
  445. PathArgToFSSpec:= false;
  446. end;
  447. end;
  448. function PathArgToFullPath(s: string; var fullpath: AnsiString): Boolean;
  449. var
  450. err: OSErr;
  451. spec: FSSpec;
  452. pathHandle: Mac_Handle;
  453. begin
  454. PathArgToFullPath:= false;
  455. if PathArgToFSSpec(s, spec) then
  456. begin
  457. err:= FSpGetFullPath(spec, pathHandle, false);
  458. if err = noErr then
  459. begin
  460. SetString(fullpath, pathHandle^, GetHandleSize(pathHandle));
  461. DisposeHandle(pathHandle);
  462. PathArgToFullPath:= true;
  463. end
  464. else
  465. OSErr2InOutRes(err);
  466. end;
  467. end;
  468. function FSpLocationFromFullPath(fullPathLength: Integer;
  469. fullPath: Mac_Ptr; var spec: FSSpec ):OSErr;
  470. var
  471. alias: AliasHandle;
  472. res: OSErr;
  473. wasChanged: Boolean;
  474. nullString: Str32;
  475. begin
  476. nullString:= '';
  477. res:= NewAliasMinimalFromFullPath(fullPathLength,
  478. fullPath, nullString, nullString, alias);
  479. if res = noErr then
  480. begin
  481. res:= ResolveAlias(nil, alias, spec, wasChanged);
  482. DisposeHandle(Mac_Handle(alias));
  483. end;
  484. FSpLocationFromFullPath:= res;
  485. end;
  486. {*****************************************************************************
  487. ParamStr/Randomize
  488. *****************************************************************************}
  489. { number of args }
  490. function paramcount : longint;
  491. begin
  492. paramcount := argc - 1;
  493. //paramcount:=0;
  494. end;
  495. { argument number l }
  496. function paramstr(l : longint) : string;
  497. begin
  498. if (l>=0) and (l+1<=argc) then
  499. paramstr:=strpas(argv[l])
  500. else
  501. paramstr:='';
  502. end;
  503. { set randseed to a new pseudo random value }
  504. procedure randomize;
  505. begin
  506. randseed:= Cardinal(TickCount);
  507. end;
  508. {*****************************************************************************
  509. Heap Management
  510. *****************************************************************************}
  511. var
  512. { Pointer to a block allocated with the MacOS Memory Manager, which
  513. is used as the initial FPC heap. }
  514. theHeap: Mac_Ptr;
  515. intern_heapsize : longint;external name 'HEAPSIZE';
  516. { first address of heap }
  517. function getheapstart:pointer;
  518. begin
  519. getheapstart:= theHeap;
  520. end;
  521. { current length of heap }
  522. function getheapsize:longint;
  523. begin
  524. getheapsize:= intern_heapsize ;
  525. end;
  526. { function to allocate size bytes more for the program }
  527. { must return the first address of new data space or nil if failed }
  528. function Sbrk(logicalSize: Longint): Mac_Ptr ;
  529. external 'InterfaceLib' name 'NewPtr'; //Directly mapped to NewPtr
  530. { include standard heap management }
  531. {$I heap.inc}
  532. {*****************************************************************************
  533. Low Level File Routines
  534. ****************************************************************************}
  535. function do_isdevice(handle:longint):boolean;
  536. begin
  537. do_isdevice:=false;
  538. end;
  539. { close a file from the handle value }
  540. procedure do_close(h : longint);
  541. var
  542. err: OSErr;
  543. {No error handling, according to the other targets, which seems reasonable,
  544. because close might be used to clean up after an error.}
  545. begin
  546. {$ifdef MACOS_USE_STDCLIB}
  547. c_close(h);
  548. // Errno2InOutRes;
  549. {$else}
  550. err:= FSClose(h);
  551. // OSErr2InOutRes(err);
  552. {$endif}
  553. end;
  554. procedure do_erase(p : pchar);
  555. {this implementation cannot distinguish between directories and files}
  556. var
  557. s: AnsiString;
  558. begin
  559. {$ifdef MACOS_USE_STDCLIB}
  560. if not PathArgToFullPath(p, s) then
  561. exit;
  562. remove(PChar(s));
  563. Errno2InoutRes;
  564. {$else}
  565. InOutRes:=1;
  566. {$endif}
  567. end;
  568. procedure do_rename(p1,p2 : pchar);
  569. var
  570. s1,s2: AnsiString;
  571. begin
  572. {$ifdef MACOS_USE_STDCLIB}
  573. if not PathArgToFullPath(p1, s1) then
  574. exit;
  575. if not PathArgToFullPath(p2, s2) then
  576. exit;
  577. c_rename(PChar(s1),PChar(s2));
  578. Errno2InoutRes;
  579. {$else}
  580. InOutRes:=1;
  581. {$endif}
  582. end;
  583. function do_write(h,addr,len : longint) : longint;
  584. begin
  585. {$ifdef MACOS_USE_STDCLIB}
  586. do_write:= c_write(h, pointer(addr), len);
  587. Errno2InoutRes;
  588. {$else}
  589. InOutRes:=1;
  590. if FSWrite(h, len, Mac_Ptr(addr)) = noErr then
  591. InOutRes:=0;
  592. do_write:= len;
  593. {$endif}
  594. end;
  595. function do_read(h,addr,len : longint) : longint;
  596. var
  597. i: Longint;
  598. begin
  599. {$ifdef MACOS_USE_STDCLIB}
  600. len:= c_read(h, pointer(addr), len);
  601. Errno2InoutRes;
  602. // TEMP BUGFIX Exchange CR to LF.
  603. for i:= 0 to len-1 do
  604. if SignedBytePtr(ord(addr) + i)^ = 13 then
  605. SignedBytePtr(ord(addr) + i)^ := 10;
  606. do_read:= len;
  607. {$else}
  608. InOutRes:=1;
  609. if FSread(h, len, Mac_Ptr(addr)) = noErr then
  610. InOutRes:=0;
  611. do_read:= len;
  612. {$endif}
  613. end;
  614. function do_filepos(handle : longint) : longint;
  615. var
  616. pos: Longint;
  617. begin
  618. {$ifdef MACOS_USE_STDCLIB}
  619. {This returns the filepos without moving it.}
  620. do_filepos := lseek(handle, 0, SEEK_CUR);
  621. Errno2InoutRes;
  622. {$else}
  623. InOutRes:=1;
  624. if GetFPos(handle, pos) = noErr then
  625. InOutRes:=0;
  626. do_filepos:= pos;
  627. {$endif}
  628. end;
  629. procedure do_seek(handle,pos : longint);
  630. begin
  631. {$ifdef MACOS_USE_STDCLIB}
  632. lseek(handle, pos, SEEK_SET);
  633. Errno2InoutRes;
  634. {$else}
  635. InOutRes:=1;
  636. if SetFPos(handle, fsFromStart, pos) = noErr then
  637. InOutRes:=0;
  638. {$endif}
  639. end;
  640. function do_seekend(handle:longint):longint;
  641. begin
  642. {$ifdef MACOS_USE_STDCLIB}
  643. lseek(handle, 0, SEEK_END);
  644. Errno2InoutRes;
  645. {$else}
  646. InOutRes:=1;
  647. if SetFPos(handle, fsFromLEOF, 0) = noErr then
  648. InOutRes:=0;
  649. {$endif}
  650. end;
  651. function do_filesize(handle : longint) : longint;
  652. var
  653. aktfilepos: Longint;
  654. begin
  655. {$ifdef MACOS_USE_STDCLIB}
  656. aktfilepos:= lseek(handle, 0, SEEK_CUR);
  657. if errno = 0 then
  658. begin
  659. do_filesize := lseek(handle, 0, SEEK_END);
  660. Errno2InOutRes; {Report the error from this operation.}
  661. lseek(handle, aktfilepos, SEEK_SET); {Always try to move back,
  662. even in presence of error.}
  663. end
  664. else
  665. Errno2InOutRes;
  666. {$else}
  667. InOutRes:=1;
  668. if GetEOF(handle, pos) = noErr then
  669. InOutRes:=0;
  670. do_filesize:= pos;
  671. {$endif}
  672. end;
  673. { truncate at a given position }
  674. procedure do_truncate (handle,pos:longint);
  675. begin
  676. {$ifdef MACOS_USE_STDCLIB}
  677. ioctl(handle, FIOSETEOF, pointer(pos));
  678. Errno2InoutRes;
  679. {$else}
  680. InOutRes:=1;
  681. do_seek(handle,pos); //TODO: Is this needed (Does the user anticipate the filemarker is at the end?)
  682. if SetEOF(handle, pos) = noErr then
  683. InOutRes:=0;
  684. {$endif}
  685. end;
  686. procedure do_open(var f;p:pchar;flags:longint);
  687. {
  688. filerec and textrec have both handle and mode as the first items so
  689. they could use the same routine for opening/creating.
  690. when (flags and $100) the file will be append
  691. when (flags and $1000) the file will be truncate/rewritten
  692. when (flags and $10000) there is no check for close (needed for textfiles)
  693. }
  694. var
  695. creator, fileType: OSType;
  696. scriptTag: ScriptCode;
  697. refNum: Integer;
  698. res: OSErr;
  699. fh: Longint;
  700. oflags : longint;
  701. s: AnsiString;
  702. begin
  703. // AllowSlash(p);
  704. { close first if opened }
  705. if ((flags and $10000)=0) then
  706. begin
  707. case filerec(f).mode of
  708. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  709. fmclosed : ;
  710. else
  711. begin
  712. {not assigned}
  713. inoutres:=102;
  714. exit;
  715. end;
  716. end;
  717. end;
  718. { reset file handle }
  719. filerec(f).handle:=UnusedHandle;
  720. {$ifdef MACOS_USE_STDCLIB}
  721. { We do the conversion of filemodes here, concentrated on 1 place }
  722. case (flags and 3) of
  723. 0 : begin
  724. oflags :=O_RDONLY;
  725. filerec(f).mode:=fminput;
  726. end;
  727. 1 : begin
  728. oflags :=O_WRONLY;
  729. filerec(f).mode:=fmoutput;
  730. end;
  731. 2 : begin
  732. oflags :=O_RDWR;
  733. filerec(f).mode:=fminout;
  734. end;
  735. end;
  736. if (flags and $1000)=$1000 then
  737. oflags:=oflags or (O_CREAT or O_TRUNC)
  738. else if (flags and $100)=$100 then
  739. oflags:=oflags or (O_APPEND);
  740. { empty name is special }
  741. if p[0]=#0 then
  742. begin
  743. case FileRec(f).mode of
  744. fminput :
  745. FileRec(f).Handle:=StdInputHandle;
  746. fminout, { this is set by rewrite }
  747. fmoutput :
  748. FileRec(f).Handle:=StdOutputHandle;
  749. fmappend :
  750. begin
  751. FileRec(f).Handle:=StdOutputHandle;
  752. FileRec(f).mode:=fmoutput; {fool fmappend}
  753. end;
  754. end;
  755. exit;
  756. end
  757. else
  758. begin
  759. if not PathArgToFullPath(p, s) then
  760. exit;
  761. p:= PChar(s);
  762. end;
  763. //TODO Perhaps handle readonly filesystems, as in sysunix.inc
  764. fh:= c_open(p, oflags);
  765. Errno2InOutRes;
  766. if fh <> -1 then
  767. filerec(f).handle:= fh
  768. else
  769. filerec(f).handle:= UnusedHandle;
  770. {$else}
  771. InOutRes:=1;
  772. //creator:= $522A6368; {'MPS ' -- MPW}
  773. //creator:= $74747874; {'ttxt'}
  774. creator:= $522A6368; {'R*ch' -- BBEdit}
  775. fileType:= $54455854; {'TEXT'}
  776. { reset file handle }
  777. filerec(f).handle:=UnusedHandle;
  778. res:= FSpLocationFromFullPath(StrLen(p), p, spec);
  779. if (res = noErr) or (res = fnfErr) then
  780. begin
  781. if FSpCreate(spec, creator, fileType, smSystemScript) = noErr then
  782. ;
  783. if FSpOpenDF(spec, fsCurPerm, refNum) = noErr then
  784. begin
  785. filerec(f).handle:= refNum;
  786. InOutRes:=0;
  787. end;
  788. end;
  789. if (filerec(f).handle=UnusedHandle) then
  790. begin
  791. //errno:=GetLastError;
  792. //Errno2InoutRes;
  793. end;
  794. {$endif}
  795. end;
  796. {*****************************************************************************
  797. UnTyped File Handling
  798. *****************************************************************************}
  799. {$i file.inc}
  800. {*****************************************************************************
  801. Typed File Handling
  802. *****************************************************************************}
  803. {$i typefile.inc}
  804. {*****************************************************************************
  805. Text File Handling
  806. *****************************************************************************}
  807. { #26 is not end of a file in MacOS ! }
  808. {$i text.inc}
  809. {*****************************************************************************
  810. Directory Handling
  811. *****************************************************************************}
  812. procedure mkdir(const s:string);[IOCheck];
  813. var
  814. spec: FSSpec;
  815. createdDirID: Longint;
  816. err: OSErr;
  817. begin
  818. If (s='') or (InOutRes <> 0) then
  819. exit;
  820. if PathArgToFSSpec(s, spec) then
  821. begin
  822. err:= FSpDirCreate(spec, smSystemScript, createdDirID);
  823. OSErr2InOutRes(err);
  824. end;
  825. end;
  826. procedure rmdir(const s:string);[IOCheck];
  827. {this implementation cannot distinguish between directories and files}
  828. var
  829. spec: FSSpec;
  830. err: OSErr;
  831. begin
  832. If (s='') or (InOutRes <> 0) then
  833. exit;
  834. if PathArgToFSSpec(s, spec) then
  835. begin
  836. err:= FSpDelete(spec);
  837. OSErr2InOutRes(err);
  838. end;
  839. end;
  840. procedure chdir(const s:string);[IOCheck];
  841. var
  842. spec, newDirSpec: FSSpec;
  843. err: OSErr;
  844. begin
  845. if (s='') or (InOutRes <> 0) then
  846. exit;
  847. if PathArgToFSSpec(s, spec) then
  848. begin
  849. { The fictive file x is appended to the directory name to make
  850. FSMakeFSSpec return a FSSpec to a file in the directory.
  851. Then by clearing the name, the FSSpec then
  852. points to the directory. It doesn't matter whether x exists or not.}
  853. err:= FSMakeFSSpec (spec.vRefNum, spec.parID, ':'+spec.name+':x', newDirSpec);
  854. if err in [ noErr, fnfErr] then
  855. begin
  856. curDirectorySpec:= newDirSpec;
  857. curDirectorySpec.name:='';
  858. InOutRes:= 0;
  859. end
  860. else
  861. begin
  862. //E g if the directory doesn't exist.
  863. OSErr2InOutRes(err);
  864. end;
  865. end;
  866. end;
  867. procedure getDir (DriveNr: byte; var Dir: ShortString);
  868. var
  869. pathHandle: Mac_Handle;
  870. pathHandleSize: Longint;
  871. begin
  872. if FSpGetFullPath(curDirectorySpec, pathHandle, false) <> noErr then
  873. Halt(3); //exit code 3 according to MPW
  874. pathHandleSize:= GetHandleSize(pathHandle);
  875. SetString(dir, pathHandle^, pathHandleSize);
  876. DisposeHandle(pathHandle);
  877. if pathHandleSize <= 255 then //because dir is ShortString
  878. InOutRes := 0
  879. else
  880. InOutRes := 1; //TODO Exchange to something better
  881. end;
  882. {*****************************************************************************
  883. SystemUnit Initialization
  884. *****************************************************************************}
  885. procedure pascalmain; external name 'PASCALMAIN';
  886. {Main entry point in C style, needed to capture program parameters.
  887. For this to work, the system unit must be before the main program
  888. in the linking order.}
  889. procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl;
  890. begin
  891. argc:= argcparam;
  892. argv:= argvparam;
  893. envp:= envpparam;
  894. pascalmain; {run the pascal main program}
  895. end;
  896. procedure setup_arguments;
  897. begin
  898. //Nothing needs to be done here.
  899. end;
  900. procedure setup_environment;
  901. begin
  902. end;
  903. {*****************************************************************************
  904. System Dependent Exit code
  905. *****************************************************************************}
  906. Procedure system_exit;
  907. begin
  908. {$ifndef MACOS_USE_STDCLIB}
  909. if StandAlone <> 0 then
  910. ExitToShell;
  911. {$else}
  912. c_exit(exitcode); //exitcode is only utilized by an MPW tool
  913. {$endif}
  914. end;
  915. procedure SysInitStdIO;
  916. begin
  917. { Setup stdin, stdout and stderr }
  918. {$ifdef MACOS_USE_STDCLIB}
  919. OpenStdIO(Input,fmInput,StdInputHandle);
  920. OpenStdIO(Output,fmOutput,StdOutputHandle);
  921. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  922. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  923. {$endif }
  924. end;
  925. var
  926. pathHandle: Mac_Handle;
  927. begin
  928. if false then //To save it from the dead code stripper
  929. begin
  930. //Included only to make them available for debugging in asm.
  931. Debugger;
  932. DebugStr('');
  933. end;
  934. { To be set if this is a GUI or console application }
  935. IsConsole := TRUE;
  936. { To be set if this is a library and not a program }
  937. IsLibrary := FALSE;
  938. StackLength := InitialStkLen;
  939. StackBottom := SPtr - StackLength;
  940. { Setup working directory }
  941. if not GetAppFileLocation(curDirectorySpec) then
  942. Halt(3); //exit code 3 according to MPW
  943. { Setup heap }
  944. if Mac_FreeMem - intern_heapsize < 30000 then
  945. Halt(3); //exit code 3 according to MPW
  946. theHeap:= Sbrk(intern_heapsize);
  947. if theHeap = nil then
  948. Halt(3); //exit code 3 according to MPW
  949. InitHeap;
  950. SysInitStdIO;
  951. { Setup environment and arguments }
  952. Setup_Environment;
  953. setup_arguments;
  954. { Reset IO Error }
  955. InOutRes:=0;
  956. errno:=0;
  957. {$ifdef HASVARIANT}
  958. initvariantmanager;
  959. {$endif HASVARIANT}
  960. end.
  961. {
  962. $Log$
  963. Revision 1.10 2003-10-29 22:34:52 olle
  964. + handles program parameters for MPW
  965. + program start stub
  966. * improved working directory handling
  967. * minor changes
  968. + some documentation
  969. Revision 1.9 2003/10/17 23:44:30 olle
  970. + working direcory emulated
  971. + implemented directory handling procs
  972. + all proc which take a path param, now resolve it relative wd
  973. Revision 1.8 2003/10/16 15:43:13 peter
  974. * THandle is platform dependent
  975. Revision 1.7 2003/09/27 11:52:35 peter
  976. * sbrk returns pointer
  977. Revision 1.6 2003/09/12 12:45:15 olle
  978. + filehandling complete
  979. + heaphandling complete
  980. + support for random
  981. * filehandling now uses filedecriptors in StdCLib
  982. * other minor changes
  983. - removed DEFINE MAC_SYS_RUNNABLE
  984. Revision 1.5 2003/01/13 17:18:55 olle
  985. + added support for rudimentary file handling
  986. Revision 1.4 2002/11/28 10:58:02 olle
  987. + added support for rudimentary heap
  988. Revision 1.3 2002/10/23 15:29:09 olle
  989. + added switch MAC_SYS_RUNABLE
  990. + added include of system.h etc
  991. + added standard globals
  992. + added dummy hook procedures
  993. Revision 1.2 2002/10/10 19:44:05 florian
  994. * changes from Olle to compile/link a simple program
  995. Revision 1.1 2002/10/02 21:34:31 florian
  996. * first dummy implementation
  997. }