system.pp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250
  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. The new process was
  206. a pure procedure (shared text) file which was
  207. open for writing by another process, or file
  208. which was open for writing by another process,
  209. or while the pure procedure file was being
  210. executed an open(2) call requested write access
  211. requested write access.
  212. (Probably not applicable on macos)}
  213. Sys_EFBIG = 27; { File too large }
  214. Sys_ENOSPC = 28; { No space left on device }
  215. Sys_ESPIPE = 29; { Illegal seek }
  216. Sys_EROFS = 30; { Read-only file system }
  217. Sys_EMLINK = 31; { Too many links }
  218. Sys_EPIPE = 32; { Broken pipe }
  219. Sys_EDOM = 33; { Math argument out of domain of func }
  220. Sys_ERANGE = 34; { Math result not representable }
  221. { Note * is slightly different, compared to rtl/sunos/errno.inc}
  222. {$endif}
  223. {******************************************************}
  224. var
  225. {working directory}
  226. curDirectorySpec: FSSpec;
  227. function GetAppFileLocation (var spec: FSSpec): Boolean;
  228. {Requires >= System 7}
  229. var
  230. PSN: ProcessSerialNumber;
  231. info: ProcessInfoRec;
  232. appFileRefNum: Integer;
  233. appName: Str255;
  234. dummy: Mac_Handle;
  235. begin
  236. begin
  237. PSN.highLongOfPSN := 0;
  238. PSN.lowLongOfPSN := kCurrentProcess;
  239. info.processInfoLength := SizeOf(info);
  240. info.processName := nil;
  241. info.processAppSpec := @spec;
  242. if GetProcessInformation(PSN, info) = noErr then
  243. begin
  244. spec.name := '';
  245. GetAppFileLocation := true;
  246. end
  247. else
  248. GetAppFileLocation := false;
  249. end
  250. end;
  251. {Gives the path for a given file or directory. If parent is true,
  252. a path to the directory, where the file or directory is located,
  253. is returned. Functioning even with System 6}
  254. function FSpGetFullPath (spec: FSSpec; var fullPathHandle: Mac_Handle;
  255. parent: Boolean): OSErr;
  256. var
  257. res: OSErr;
  258. pb: CInfoPBRec;
  259. begin
  260. fullPathHandle:= NewHandle(0); { Allocate a zero-length handle }
  261. if fullPathHandle = nil then
  262. begin
  263. FSpGetFullPath:= MemError;
  264. Exit;
  265. end;
  266. if spec.parID = fsRtParID then { The object is a volume }
  267. begin
  268. if not parent then
  269. begin
  270. { Add a colon to make it a full pathname }
  271. spec.name := Concat(spec.name, ':');
  272. { We're done }
  273. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  274. res := MemError;
  275. end
  276. else
  277. res := noErr;
  278. end
  279. else
  280. begin
  281. { The object isn't a volume }
  282. { Add the object name }
  283. if not parent then
  284. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  285. { Get the ancestor directory names }
  286. pb.ioNamePtr := @spec.name;
  287. pb.ioVRefNum := spec.vRefNum;
  288. pb.ioDrParID := spec.parID;
  289. repeat { loop until we have an error or find the root directory }
  290. begin
  291. pb.ioFDirIndex := -1;
  292. pb.ioDrDirID := pb.ioDrParID;
  293. res := PBGetCatInfoSync(@pb);
  294. if res = noErr then
  295. begin
  296. { Append colon to directory name }
  297. spec.name := Concat(spec.name, ':');
  298. { Add directory name to fullPathHandle }
  299. Munger(fullPathHandle, 0, nil, 0, @spec.name[1], Length(spec.name));
  300. res := MemError;
  301. end
  302. end
  303. until not ((res = noErr) and (pb.ioDrDirID <> fsRtDirID));
  304. end;
  305. if res <> noErr then
  306. begin
  307. DisposeHandle(fullPathHandle);
  308. fullPathHandle:= nil;
  309. end;
  310. FSpGetFullPath := res;
  311. end;
  312. Procedure Errno2InOutRes;
  313. {
  314. Convert ErrNo error to the correct InOutRes value.
  315. It seems that some of the errno is, in macos,
  316. used for other purposes than its original definition.
  317. }
  318. begin
  319. if errno = 0 then { Else it will go through all the cases }
  320. exit;
  321. case Errno of
  322. Sys_ENFILE,
  323. Sys_EMFILE : Inoutres:=4;
  324. Sys_ENOENT : Inoutres:=2;
  325. Sys_EBADF : Inoutres:=6;
  326. Sys_ENOMEM,
  327. Sys_EFAULT : Inoutres:=217; //TODO Exchange to something better
  328. Sys_EINVAL : Inoutres:=218; //TODO RTE 218 doesn't exist
  329. Sys_EAGAIN,
  330. Sys_ENOSPC : Inoutres:=101;
  331. Sys_ENOTDIR : Inoutres:=3;
  332. Sys_EPERM,
  333. Sys_EROFS,
  334. Sys_EEXIST,
  335. Sys_EISDIR,
  336. Sys_EINTR, //Happens when attempt to rename a file fails
  337. Sys_EBUSY, //Happens when attempt to remove a locked file
  338. Sys_EACCES,
  339. Sys_EMLINK : Inoutres:=5; //Happens when attempt to remove open file
  340. Sys_ENXIO : InOutRes:=152;
  341. Sys_ESPIPE : InOutRes:=156; //Illegal seek
  342. else
  343. InOutRes := Integer(errno);//TODO Exchange to something better
  344. end;
  345. errno:=0;
  346. end;
  347. Function MacOSErr2RTEerr(err: OSErr): Integer;
  348. { Converts MacOS specific error codes to the correct FPC error code.
  349. All non zero MacOS errors shall correspond to a nonzero FPC error.}
  350. var
  351. res: Integer;
  352. begin
  353. if err = noErr then { Else it will go through all the cases }
  354. res:= 0
  355. else case err of
  356. dirFulErr, { Directory full }
  357. dskFulErr { disk full }
  358. :res:=101;
  359. nsvErr { no such volume }
  360. :res:=3;
  361. ioErr, { I/O error (bummers) }
  362. bdNamErr { there may be no bad names in the final system! }
  363. :res:=1; //TODO Exchange to something better
  364. fnOpnErr { File not open }
  365. :res:=103;
  366. eofErr, { End of file }
  367. posErr { tried to position to before start of file (r/w) }
  368. :res:=100;
  369. mFulErr { memory full (open) or file won't fit (load) }
  370. :res:=1; //TODO Exchange to something better
  371. tmfoErr { too many files open}
  372. :res:=4;
  373. fnfErr { File not found }
  374. :res:=2;
  375. wPrErr { diskette is write protected. }
  376. :res:=150;
  377. fLckdErr { file is locked }
  378. :res:=5;
  379. vLckdErr { volume is locked }
  380. :res:=150;
  381. fBsyErr { File is busy (delete) }
  382. :res:=5;
  383. dupFNErr { duplicate filename (rename) }
  384. :res:=5;
  385. opWrErr { file already open with with write permission }
  386. :res:=5;
  387. rfNumErr, { refnum error }
  388. gfpErr { get file position error }
  389. :res:=1; //TODO Exchange to something better
  390. volOffLinErr { volume not on line error (was Ejected) }
  391. :res:=152;
  392. permErr { permissions error (on file open) }
  393. :res:=5;
  394. volOnLinErr{ drive volume already on-line at MountVol }
  395. :res:=1; //TODO Exchange to something other
  396. nsDrvErr { no such drive (tried to mount a bad drive num) }
  397. :res:=1; //TODO Perhaps exchange to something better
  398. noMacDskErr, { not a mac diskette (sig bytes are wrong) }
  399. extFSErr { volume in question belongs to an external fs }
  400. :res:=157; //TODO Perhaps exchange to something better
  401. fsRnErr, { file system internal error:during rename the old
  402. entry was deleted but could not be restored. }
  403. badMDBErr { bad master directory block }
  404. :res:=1; //TODO Exchange to something better
  405. wrPermErr { write permissions error }
  406. :res:=5;
  407. dirNFErr { Directory not found }
  408. :res:=3;
  409. tmwdoErr { No free WDCB available }
  410. :res:=1; //TODO Exchange to something better
  411. badMovErr { Move into offspring error }
  412. :res:=5;
  413. wrgVolTypErr { Wrong volume type error [operation not
  414. supported for MFS] }
  415. :res:=1; //TODO Exchange to something better
  416. volGoneErr { Server volume has been disconnected. }
  417. :res:=152;
  418. diffVolErr { files on different volumes }
  419. :res:=17;
  420. catChangedErr { the catalog has been modified }
  421. { OR comment: when searching with PBCatSearch }
  422. :res:=1; //TODO Exchange to something other
  423. afpAccessDenied, { Insufficient access privileges for operation }
  424. afpDenyConflict { Specified open/deny modes conflict with current open modes }
  425. :res:=5;
  426. afpNoMoreLocks { Maximum lock limit reached }
  427. :res:=5;
  428. afpRangeNotLocked, { Tried to unlock range that was not locked by user }
  429. afpRangeOverlap { Some or all of range already locked by same user }
  430. :res:=1; //TODO Exchange to something better
  431. afpObjectTypeErr { File/Directory specified where Directory/File expected }
  432. :res:=3;
  433. afpCatalogChanged { OR comment: when searching with PBCatSearch }
  434. :res:=1; //TODO Exchange to something other
  435. afpSameObjectErr
  436. :res:=5; //TODO Exchange to something better
  437. memFullErr { Not enough room in heap zone }
  438. :res:=203;
  439. else
  440. res := 1; //TODO Exchange to something better
  441. end;
  442. MacOSErr2RTEerr:= res;
  443. end;
  444. Procedure OSErr2InOutRes(err: OSErr);
  445. begin
  446. InOutRes:= MacOSErr2RTEerr(err);
  447. end;
  448. function PathArgToFSSpec(s: string; var spec: FSSpec): Integer;
  449. var
  450. err: OSErr;
  451. begin
  452. err:= FSMakeFSSpec(curDirectorySpec.vRefNum,
  453. curDirectorySpec.parID, s, spec);
  454. if err in [ noErr, fnfErr] then
  455. PathArgToFSSpec:= 0
  456. else
  457. PathArgToFSSpec:= MacOSErr2RTEerr(err);
  458. end;
  459. function PathArgToFullPath(s: string; var fullpath: AnsiString): Boolean;
  460. var
  461. err: OSErr;
  462. res: Integer;
  463. spec: FSSpec;
  464. pathHandle: Mac_Handle;
  465. begin
  466. PathArgToFullPath:= false;
  467. res:= PathArgToFSSpec(s, spec);
  468. if res = 0 then
  469. begin
  470. err:= FSpGetFullPath(spec, pathHandle, false);
  471. if err = noErr then
  472. begin
  473. SetString(fullpath, pathHandle^, GetHandleSize(pathHandle));
  474. DisposeHandle(pathHandle);
  475. PathArgToFullPath:= true;
  476. end
  477. else
  478. OSErr2InOutRes(err);
  479. end
  480. else
  481. InOutRes:=res;
  482. end;
  483. function FSpLocationFromFullPath(fullPathLength: Integer;
  484. fullPath: Mac_Ptr; var spec: FSSpec ):OSErr;
  485. var
  486. alias: AliasHandle;
  487. res: OSErr;
  488. wasChanged: Boolean;
  489. nullString: Str32;
  490. begin
  491. nullString:= '';
  492. res:= NewAliasMinimalFromFullPath(fullPathLength,
  493. fullPath, nullString, nullString, alias);
  494. if res = noErr then
  495. begin
  496. res:= ResolveAlias(nil, alias, spec, wasChanged);
  497. DisposeHandle(Mac_Handle(alias));
  498. end;
  499. FSpLocationFromFullPath:= res;
  500. end;
  501. {*****************************************************************************
  502. ParamStr/Randomize
  503. *****************************************************************************}
  504. { number of args }
  505. function paramcount : longint;
  506. begin
  507. paramcount := argc - 1;
  508. //paramcount:=0;
  509. end;
  510. { argument number l }
  511. function paramstr(l : longint) : string;
  512. begin
  513. if (l>=0) and (l+1<=argc) then
  514. paramstr:=strpas(argv[l])
  515. else
  516. paramstr:='';
  517. end;
  518. { set randseed to a new pseudo random value }
  519. procedure randomize;
  520. begin
  521. randseed:= Cardinal(TickCount);
  522. end;
  523. {*****************************************************************************
  524. Heap Management
  525. *****************************************************************************}
  526. var
  527. { Pointer to a block allocated with the MacOS Memory Manager, which
  528. is used as the initial FPC heap. }
  529. theHeap: Mac_Ptr;
  530. intern_heapsize : longint;external name 'HEAPSIZE';
  531. { first address of heap }
  532. function getheapstart:pointer;
  533. begin
  534. getheapstart:= theHeap;
  535. end;
  536. { current length of heap }
  537. function getheapsize:longint;
  538. begin
  539. getheapsize:= intern_heapsize ;
  540. end;
  541. { function to allocate size bytes more for the program }
  542. { must return the first address of new data space or nil if failed }
  543. function Sbrk(logicalSize: Longint): Mac_Ptr ;
  544. external 'InterfaceLib' name 'NewPtr'; {Directly mapped to NewPtr}
  545. {*****************************************************************************
  546. OS Memory allocation / deallocation
  547. ****************************************************************************}
  548. function SysOSAlloc(size: ptrint): pointer;
  549. begin
  550. result := sbrk(size);
  551. end;
  552. {$define HAS_SYSOSFREE}
  553. procedure SysOSFree(p: pointer; size: ptrint);
  554. begin
  555. fpmunmap(p, size);
  556. end;
  557. { include standard heap management }
  558. {$I heap.inc}
  559. {*****************************************************************************
  560. Low Level File Routines
  561. ****************************************************************************}
  562. function do_isdevice(handle:longint):boolean;
  563. begin
  564. do_isdevice:=false;
  565. end;
  566. { close a file from the handle value }
  567. procedure do_close(h : longint);
  568. var
  569. err: OSErr;
  570. {No error handling, according to the other targets, which seems reasonable,
  571. because close might be used to clean up after an error.}
  572. begin
  573. {$ifdef MACOS_USE_STDCLIB}
  574. c_close(h);
  575. // Errno2InOutRes;
  576. {$else}
  577. err:= FSClose(h);
  578. // OSErr2InOutRes(err);
  579. {$endif}
  580. end;
  581. procedure do_erase(p : pchar);
  582. {this implementation cannot distinguish between directories and files}
  583. var
  584. s: AnsiString;
  585. begin
  586. {$ifdef MACOS_USE_STDCLIB}
  587. if not PathArgToFullPath(p, s) then
  588. exit;
  589. remove(PChar(s));
  590. Errno2InoutRes;
  591. {$else}
  592. InOutRes:=1;
  593. {$endif}
  594. end;
  595. procedure do_rename(p1,p2 : pchar);
  596. var
  597. s1,s2: AnsiString;
  598. begin
  599. {$ifdef MACOS_USE_STDCLIB}
  600. if not PathArgToFullPath(p1, s1) then
  601. exit;
  602. if not PathArgToFullPath(p2, s2) then
  603. exit;
  604. c_rename(PChar(s1),PChar(s2));
  605. Errno2InoutRes;
  606. {$else}
  607. InOutRes:=1;
  608. {$endif}
  609. end;
  610. function do_write(h:longint;addr:pointer;len : longint) : longint;
  611. begin
  612. {$ifdef MACOS_USE_STDCLIB}
  613. do_write:= c_write(h, addr, len);
  614. Errno2InoutRes;
  615. {$else}
  616. InOutRes:=1;
  617. if FSWrite(h, len, Mac_Ptr(addr)) = noErr then
  618. InOutRes:=0;
  619. do_write:= len;
  620. {$endif}
  621. end;
  622. function do_read(h:longint;addr:pointer;len : longint) : longint;
  623. var
  624. i: Longint;
  625. begin
  626. {$ifdef MACOS_USE_STDCLIB}
  627. len:= c_read(h, addr, len);
  628. Errno2InoutRes;
  629. // TEMP BUGFIX Exchange CR to LF.
  630. for i:= 0 to len-1 do
  631. if SignedBytePtr(addr + i)^ = 13 then
  632. SignedBytePtr(addr + i)^ := 10;
  633. do_read:= len;
  634. {$else}
  635. InOutRes:=1;
  636. if FSread(h, len, Mac_Ptr(addr)) = noErr then
  637. InOutRes:=0;
  638. do_read:= len;
  639. {$endif}
  640. end;
  641. function do_filepos(handle : longint) : longint;
  642. var
  643. pos: Longint;
  644. begin
  645. {$ifdef MACOS_USE_STDCLIB}
  646. {This returns the filepos without moving it.}
  647. do_filepos := lseek(handle, 0, SEEK_CUR);
  648. Errno2InoutRes;
  649. {$else}
  650. InOutRes:=1;
  651. if GetFPos(handle, pos) = noErr then
  652. InOutRes:=0;
  653. do_filepos:= pos;
  654. {$endif}
  655. end;
  656. procedure do_seek(handle,pos : longint);
  657. begin
  658. {$ifdef MACOS_USE_STDCLIB}
  659. lseek(handle, pos, SEEK_SET);
  660. Errno2InoutRes;
  661. {$else}
  662. InOutRes:=1;
  663. if SetFPos(handle, fsFromStart, pos) = noErr then
  664. InOutRes:=0;
  665. {$endif}
  666. end;
  667. function do_seekend(handle:longint):longint;
  668. begin
  669. {$ifdef MACOS_USE_STDCLIB}
  670. lseek(handle, 0, SEEK_END);
  671. Errno2InoutRes;
  672. {$else}
  673. InOutRes:=1;
  674. if SetFPos(handle, fsFromLEOF, 0) = noErr then
  675. InOutRes:=0;
  676. {$endif}
  677. end;
  678. function do_filesize(handle : longint) : longint;
  679. var
  680. aktfilepos: Longint;
  681. begin
  682. {$ifdef MACOS_USE_STDCLIB}
  683. aktfilepos:= lseek(handle, 0, SEEK_CUR);
  684. if errno = 0 then
  685. begin
  686. do_filesize := lseek(handle, 0, SEEK_END);
  687. Errno2InOutRes; {Report the error from this operation.}
  688. lseek(handle, aktfilepos, SEEK_SET); {Always try to move back,
  689. even in presence of error.}
  690. end
  691. else
  692. Errno2InOutRes;
  693. {$else}
  694. InOutRes:=1;
  695. if GetEOF(handle, pos) = noErr then
  696. InOutRes:=0;
  697. do_filesize:= pos;
  698. {$endif}
  699. end;
  700. { truncate at a given position }
  701. procedure do_truncate (handle,pos:longint);
  702. begin
  703. {$ifdef MACOS_USE_STDCLIB}
  704. ioctl(handle, FIOSETEOF, pointer(pos));
  705. Errno2InoutRes;
  706. {$else}
  707. InOutRes:=1;
  708. do_seek(handle,pos); //TODO: Is this needed (Does the user anticipate the filemarker is at the end?)
  709. if SetEOF(handle, pos) = noErr then
  710. InOutRes:=0;
  711. {$endif}
  712. end;
  713. procedure do_open(var f;p:pchar;flags:longint);
  714. {
  715. filerec and textrec have both handle and mode as the first items so
  716. they could use the same routine for opening/creating.
  717. when (flags and $100) the file will be append
  718. when (flags and $1000) the file will be truncate/rewritten
  719. when (flags and $10000) there is no check for close (needed for textfiles)
  720. }
  721. var
  722. creator, fileType: OSType;
  723. scriptTag: ScriptCode;
  724. refNum: Integer;
  725. res: OSErr;
  726. fh: Longint;
  727. oflags : longint;
  728. s: AnsiString;
  729. begin
  730. // AllowSlash(p);
  731. { close first if opened }
  732. if ((flags and $10000)=0) then
  733. begin
  734. case filerec(f).mode of
  735. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  736. fmclosed : ;
  737. else
  738. begin
  739. {not assigned}
  740. inoutres:=102;
  741. exit;
  742. end;
  743. end;
  744. end;
  745. { reset file handle }
  746. filerec(f).handle:=UnusedHandle;
  747. {$ifdef MACOS_USE_STDCLIB}
  748. { We do the conversion of filemodes here, concentrated on 1 place }
  749. case (flags and 3) of
  750. 0 : begin
  751. oflags :=O_RDONLY;
  752. filerec(f).mode:=fminput;
  753. end;
  754. 1 : begin
  755. oflags :=O_WRONLY;
  756. filerec(f).mode:=fmoutput;
  757. end;
  758. 2 : begin
  759. oflags :=O_RDWR;
  760. filerec(f).mode:=fminout;
  761. end;
  762. end;
  763. if (flags and $1000)=$1000 then
  764. oflags:=oflags or (O_CREAT or O_TRUNC)
  765. else if (flags and $100)=$100 then
  766. oflags:=oflags or (O_APPEND);
  767. { empty name is special }
  768. if p[0]=#0 then
  769. begin
  770. case FileRec(f).mode of
  771. fminput :
  772. FileRec(f).Handle:=StdInputHandle;
  773. fminout, { this is set by rewrite }
  774. fmoutput :
  775. FileRec(f).Handle:=StdOutputHandle;
  776. fmappend :
  777. begin
  778. FileRec(f).Handle:=StdOutputHandle;
  779. FileRec(f).mode:=fmoutput; {fool fmappend}
  780. end;
  781. end;
  782. exit;
  783. end
  784. else
  785. begin
  786. if not PathArgToFullPath(p, s) then
  787. exit;
  788. p:= PChar(s);
  789. end;
  790. //TODO Perhaps handle readonly filesystems, as in sysunix.inc
  791. fh:= c_open(p, oflags);
  792. Errno2InOutRes;
  793. if fh <> -1 then
  794. filerec(f).handle:= fh
  795. else
  796. filerec(f).handle:= UnusedHandle;
  797. {$else}
  798. InOutRes:=1;
  799. //creator:= $522A6368; {'MPS ' -- MPW}
  800. //creator:= $74747874; {'ttxt'}
  801. creator:= $522A6368; {'R*ch' -- BBEdit}
  802. fileType:= $54455854; {'TEXT'}
  803. { reset file handle }
  804. filerec(f).handle:=UnusedHandle;
  805. res:= FSpLocationFromFullPath(StrLen(p), p, spec);
  806. if (res = noErr) or (res = fnfErr) then
  807. begin
  808. if FSpCreate(spec, creator, fileType, smSystemScript) = noErr then
  809. ;
  810. if FSpOpenDF(spec, fsCurPerm, refNum) = noErr then
  811. begin
  812. filerec(f).handle:= refNum;
  813. InOutRes:=0;
  814. end;
  815. end;
  816. if (filerec(f).handle=UnusedHandle) then
  817. begin
  818. //errno:=GetLastError;
  819. //Errno2InoutRes;
  820. end;
  821. {$endif}
  822. end;
  823. {*****************************************************************************
  824. UnTyped File Handling
  825. *****************************************************************************}
  826. {$i file.inc}
  827. {*****************************************************************************
  828. Typed File Handling
  829. *****************************************************************************}
  830. {$i typefile.inc}
  831. {*****************************************************************************
  832. Text File Handling
  833. *****************************************************************************}
  834. { #26 is not end of a file in MacOS ! }
  835. {$i text.inc}
  836. {*****************************************************************************
  837. Directory Handling
  838. *****************************************************************************}
  839. procedure mkdir(const s:string);[IOCheck];
  840. var
  841. spec: FSSpec;
  842. createdDirID: Longint;
  843. err: OSErr;
  844. res: Integer;
  845. begin
  846. If (s='') or (InOutRes <> 0) then
  847. exit;
  848. res:= PathArgToFSSpec(s, spec);
  849. if res = 0 then
  850. begin
  851. err:= FSpDirCreate(spec, smSystemScript, createdDirID);
  852. OSErr2InOutRes(err);
  853. end
  854. else
  855. InOutRes:=res;
  856. end;
  857. procedure rmdir(const s:string);[IOCheck];
  858. {this implementation cannot distinguish between directories and files}
  859. var
  860. spec: FSSpec;
  861. err: OSErr;
  862. res: Integer;
  863. begin
  864. If (s='') or (InOutRes <> 0) then
  865. exit;
  866. res:= PathArgToFSSpec(s, spec);
  867. if res = 0 then
  868. begin
  869. err:= FSpDelete(spec);
  870. OSErr2InOutRes(err);
  871. end
  872. else
  873. InOutRes:=res;
  874. end;
  875. procedure chdir(const s:string);[IOCheck];
  876. var
  877. spec, newDirSpec: FSSpec;
  878. err: OSErr;
  879. res: Integer;
  880. begin
  881. if (s='') or (InOutRes <> 0) then
  882. exit;
  883. res:= PathArgToFSSpec(s, spec);
  884. if res = 0 then
  885. begin
  886. { The fictive file x is appended to the directory name to make
  887. FSMakeFSSpec return a FSSpec to a file in the directory.
  888. Then by clearing the name, the FSSpec then
  889. points to the directory. It doesn't matter whether x exists or not.}
  890. err:= FSMakeFSSpec (spec.vRefNum, spec.parID, ':'+spec.name+':x', newDirSpec);
  891. if err in [ noErr, fnfErr] then
  892. begin
  893. curDirectorySpec:= newDirSpec;
  894. curDirectorySpec.name:='';
  895. InOutRes:= 0;
  896. end
  897. else
  898. begin
  899. {E g if the directory doesn't exist.}
  900. OSErr2InOutRes(err);
  901. end;
  902. end
  903. else
  904. InOutRes:=res;
  905. end;
  906. procedure getDir (DriveNr: byte; var Dir: ShortString);
  907. var
  908. pathHandle: Mac_Handle;
  909. pathHandleSize: Longint;
  910. begin
  911. if FSpGetFullPath(curDirectorySpec, pathHandle, false) <> noErr then
  912. Halt(3); {exit code 3 according to MPW}
  913. pathHandleSize:= GetHandleSize(pathHandle);
  914. SetString(dir, pathHandle^, pathHandleSize);
  915. DisposeHandle(pathHandle);
  916. if pathHandleSize <= 255 then {because dir is ShortString}
  917. InOutRes := 0
  918. else
  919. InOutRes := 1; //TODO Exchange to something better
  920. end;
  921. {*****************************************************************************
  922. SystemUnit Initialization
  923. *****************************************************************************}
  924. procedure pascalmain; external name 'PASCALMAIN';
  925. {Main entry point in C style, needed to capture program parameters.
  926. For this to work, the system unit must be before the main program
  927. in the linking order.}
  928. procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
  929. begin
  930. argc:= argcparam;
  931. argv:= argvparam;
  932. envp:= envpparam;
  933. pascalmain; {run the pascal main program}
  934. end;
  935. procedure setup_arguments;
  936. begin
  937. {Nothing needs to be done here.}
  938. end;
  939. procedure setup_environment;
  940. begin
  941. end;
  942. {*****************************************************************************
  943. System Dependent Exit code
  944. *****************************************************************************}
  945. Procedure system_exit;
  946. begin
  947. {$ifndef MACOS_USE_STDCLIB}
  948. if StandAlone <> 0 then
  949. ExitToShell;
  950. {$else}
  951. c_exit(exitcode); {exitcode is only utilized by an MPW tool}
  952. {$endif}
  953. end;
  954. procedure SysInitStdIO;
  955. begin
  956. { Setup stdin, stdout and stderr }
  957. {$ifdef MACOS_USE_STDCLIB}
  958. OpenStdIO(Input,fmInput,StdInputHandle);
  959. OpenStdIO(Output,fmOutput,StdOutputHandle);
  960. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  961. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  962. {$endif }
  963. end;
  964. var
  965. pathHandle: Mac_Handle;
  966. begin
  967. if false then //To save it from the dead code stripper
  968. begin
  969. //Included only to make them available for debugging in asm.
  970. Debugger;
  971. DebugStr('');
  972. end;
  973. { To be set if this is a GUI or console application }
  974. IsConsole := TRUE;
  975. { To be set if this is a library and not a program }
  976. IsLibrary := FALSE;
  977. StackLength := InitialStkLen;
  978. StackBottom := SPtr - StackLength;
  979. { Setup working directory }
  980. if not GetAppFileLocation(curDirectorySpec) then
  981. Halt(3); //exit code 3 according to MPW
  982. { Setup heap }
  983. MaxApplZone;
  984. if Mac_FreeMem - intern_heapsize < 30000 then
  985. Halt(3); //exit code 3 according to MPW
  986. theHeap:= Sbrk(intern_heapsize);
  987. if theHeap = nil then
  988. Halt(3); //exit code 3 according to MPW
  989. InitHeap;
  990. SysInitStdIO;
  991. { Setup environment and arguments }
  992. Setup_Environment;
  993. setup_arguments;
  994. { Reset IO Error }
  995. InOutRes:=0;
  996. errno:=0;
  997. (* This should be changed to a real value during *)
  998. (* thread driver initialization if appropriate. *)
  999. ThreadID := 1;
  1000. {$ifdef HASVARIANT}
  1001. initvariantmanager;
  1002. {$endif HASVARIANT}
  1003. end.
  1004. {
  1005. $Log$
  1006. Revision 1.16 2004-06-17 16:16:13 peter
  1007. * New heapmanager that releases memory back to the OS, donated
  1008. by Micha Nelissen
  1009. Revision 1.15 2004/05/11 18:05:41 olle
  1010. + added call to MaxApplZone to have the whole MacOS heap available
  1011. Revision 1.14 2004/04/29 11:27:36 olle
  1012. * do_read/do_write addr arg changed to pointer
  1013. * misc internal changes
  1014. Revision 1.13 2004/02/04 15:17:16 olle
  1015. * internal changes
  1016. Revision 1.12 2004/01/20 23:11:20 hajny
  1017. * ExecuteProcess fixes, ProcessID and ThreadID added
  1018. Revision 1.11 2004/01/04 21:06:43 jonas
  1019. * make the C-main public
  1020. Revision 1.10 2003/10/29 22:34:52 olle
  1021. + handles program parameters for MPW
  1022. + program start stub
  1023. * improved working directory handling
  1024. * minor changes
  1025. + some documentation
  1026. Revision 1.9 2003/10/17 23:44:30 olle
  1027. + working direcory emulated
  1028. + implemented directory handling procs
  1029. + all proc which take a path param, now resolve it relative wd
  1030. Revision 1.8 2003/10/16 15:43:13 peter
  1031. * THandle is platform dependent
  1032. Revision 1.7 2003/09/27 11:52:35 peter
  1033. * sbrk returns pointer
  1034. Revision 1.6 2003/09/12 12:45:15 olle
  1035. + filehandling complete
  1036. + heaphandling complete
  1037. + support for random
  1038. * filehandling now uses filedecriptors in StdCLib
  1039. * other minor changes
  1040. - removed DEFINE MAC_SYS_RUNNABLE
  1041. Revision 1.5 2003/01/13 17:18:55 olle
  1042. + added support for rudimentary file handling
  1043. Revision 1.4 2002/11/28 10:58:02 olle
  1044. + added support for rudimentary heap
  1045. Revision 1.3 2002/10/23 15:29:09 olle
  1046. + added switch MAC_SYS_RUNABLE
  1047. + added include of system.h etc
  1048. + added standard globals
  1049. + added dummy hook procedures
  1050. Revision 1.2 2002/10/10 19:44:05 florian
  1051. * changes from Olle to compile/link a simple program
  1052. Revision 1.1 2002/10/02 21:34:31 florian
  1053. * first dummy implementation
  1054. }