system.pp 33 KB

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