system.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  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. { include standard heap management }
  546. {$I heap.inc}
  547. {*****************************************************************************
  548. Low Level File Routines
  549. ****************************************************************************}
  550. function do_isdevice(handle:longint):boolean;
  551. begin
  552. do_isdevice:=false;
  553. end;
  554. { close a file from the handle value }
  555. procedure do_close(h : longint);
  556. var
  557. err: OSErr;
  558. {No error handling, according to the other targets, which seems reasonable,
  559. because close might be used to clean up after an error.}
  560. begin
  561. {$ifdef MACOS_USE_STDCLIB}
  562. c_close(h);
  563. // Errno2InOutRes;
  564. {$else}
  565. err:= FSClose(h);
  566. // OSErr2InOutRes(err);
  567. {$endif}
  568. end;
  569. procedure do_erase(p : pchar);
  570. {this implementation cannot distinguish between directories and files}
  571. var
  572. s: AnsiString;
  573. begin
  574. {$ifdef MACOS_USE_STDCLIB}
  575. if not PathArgToFullPath(p, s) then
  576. exit;
  577. remove(PChar(s));
  578. Errno2InoutRes;
  579. {$else}
  580. InOutRes:=1;
  581. {$endif}
  582. end;
  583. procedure do_rename(p1,p2 : pchar);
  584. var
  585. s1,s2: AnsiString;
  586. begin
  587. {$ifdef MACOS_USE_STDCLIB}
  588. if not PathArgToFullPath(p1, s1) then
  589. exit;
  590. if not PathArgToFullPath(p2, s2) then
  591. exit;
  592. c_rename(PChar(s1),PChar(s2));
  593. Errno2InoutRes;
  594. {$else}
  595. InOutRes:=1;
  596. {$endif}
  597. end;
  598. function do_write(h:longint;addr:pointer;len : longint) : longint;
  599. begin
  600. {$ifdef MACOS_USE_STDCLIB}
  601. do_write:= c_write(h, addr, len);
  602. Errno2InoutRes;
  603. {$else}
  604. InOutRes:=1;
  605. if FSWrite(h, len, Mac_Ptr(addr)) = noErr then
  606. InOutRes:=0;
  607. do_write:= len;
  608. {$endif}
  609. end;
  610. function do_read(h:longint;addr:pointer;len : longint) : longint;
  611. var
  612. i: Longint;
  613. begin
  614. {$ifdef MACOS_USE_STDCLIB}
  615. len:= c_read(h, addr, len);
  616. Errno2InoutRes;
  617. // TEMP BUGFIX Exchange CR to LF.
  618. for i:= 0 to len-1 do
  619. if SignedBytePtr(addr + i)^ = 13 then
  620. SignedBytePtr(addr + i)^ := 10;
  621. do_read:= len;
  622. {$else}
  623. InOutRes:=1;
  624. if FSread(h, len, Mac_Ptr(addr)) = noErr then
  625. InOutRes:=0;
  626. do_read:= len;
  627. {$endif}
  628. end;
  629. function do_filepos(handle : longint) : longint;
  630. var
  631. pos: Longint;
  632. begin
  633. {$ifdef MACOS_USE_STDCLIB}
  634. {This returns the filepos without moving it.}
  635. do_filepos := lseek(handle, 0, SEEK_CUR);
  636. Errno2InoutRes;
  637. {$else}
  638. InOutRes:=1;
  639. if GetFPos(handle, pos) = noErr then
  640. InOutRes:=0;
  641. do_filepos:= pos;
  642. {$endif}
  643. end;
  644. procedure do_seek(handle,pos : longint);
  645. begin
  646. {$ifdef MACOS_USE_STDCLIB}
  647. lseek(handle, pos, SEEK_SET);
  648. Errno2InoutRes;
  649. {$else}
  650. InOutRes:=1;
  651. if SetFPos(handle, fsFromStart, pos) = noErr then
  652. InOutRes:=0;
  653. {$endif}
  654. end;
  655. function do_seekend(handle:longint):longint;
  656. begin
  657. {$ifdef MACOS_USE_STDCLIB}
  658. lseek(handle, 0, SEEK_END);
  659. Errno2InoutRes;
  660. {$else}
  661. InOutRes:=1;
  662. if SetFPos(handle, fsFromLEOF, 0) = noErr then
  663. InOutRes:=0;
  664. {$endif}
  665. end;
  666. function do_filesize(handle : longint) : longint;
  667. var
  668. aktfilepos: Longint;
  669. begin
  670. {$ifdef MACOS_USE_STDCLIB}
  671. aktfilepos:= lseek(handle, 0, SEEK_CUR);
  672. if errno = 0 then
  673. begin
  674. do_filesize := lseek(handle, 0, SEEK_END);
  675. Errno2InOutRes; {Report the error from this operation.}
  676. lseek(handle, aktfilepos, SEEK_SET); {Always try to move back,
  677. even in presence of error.}
  678. end
  679. else
  680. Errno2InOutRes;
  681. {$else}
  682. InOutRes:=1;
  683. if GetEOF(handle, pos) = noErr then
  684. InOutRes:=0;
  685. do_filesize:= pos;
  686. {$endif}
  687. end;
  688. { truncate at a given position }
  689. procedure do_truncate (handle,pos:longint);
  690. begin
  691. {$ifdef MACOS_USE_STDCLIB}
  692. ioctl(handle, FIOSETEOF, pointer(pos));
  693. Errno2InoutRes;
  694. {$else}
  695. InOutRes:=1;
  696. do_seek(handle,pos); //TODO: Is this needed (Does the user anticipate the filemarker is at the end?)
  697. if SetEOF(handle, pos) = noErr then
  698. InOutRes:=0;
  699. {$endif}
  700. end;
  701. procedure do_open(var f;p:pchar;flags:longint);
  702. {
  703. filerec and textrec have both handle and mode as the first items so
  704. they could use the same routine for opening/creating.
  705. when (flags and $100) the file will be append
  706. when (flags and $1000) the file will be truncate/rewritten
  707. when (flags and $10000) there is no check for close (needed for textfiles)
  708. }
  709. var
  710. creator, fileType: OSType;
  711. scriptTag: ScriptCode;
  712. refNum: Integer;
  713. res: OSErr;
  714. fh: Longint;
  715. oflags : longint;
  716. s: AnsiString;
  717. begin
  718. // AllowSlash(p);
  719. { close first if opened }
  720. if ((flags and $10000)=0) then
  721. begin
  722. case filerec(f).mode of
  723. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  724. fmclosed : ;
  725. else
  726. begin
  727. {not assigned}
  728. inoutres:=102;
  729. exit;
  730. end;
  731. end;
  732. end;
  733. { reset file handle }
  734. filerec(f).handle:=UnusedHandle;
  735. {$ifdef MACOS_USE_STDCLIB}
  736. { We do the conversion of filemodes here, concentrated on 1 place }
  737. case (flags and 3) of
  738. 0 : begin
  739. oflags :=O_RDONLY;
  740. filerec(f).mode:=fminput;
  741. end;
  742. 1 : begin
  743. oflags :=O_WRONLY;
  744. filerec(f).mode:=fmoutput;
  745. end;
  746. 2 : begin
  747. oflags :=O_RDWR;
  748. filerec(f).mode:=fminout;
  749. end;
  750. end;
  751. if (flags and $1000)=$1000 then
  752. oflags:=oflags or (O_CREAT or O_TRUNC)
  753. else if (flags and $100)=$100 then
  754. oflags:=oflags or (O_APPEND);
  755. { empty name is special }
  756. if p[0]=#0 then
  757. begin
  758. case FileRec(f).mode of
  759. fminput :
  760. FileRec(f).Handle:=StdInputHandle;
  761. fminout, { this is set by rewrite }
  762. fmoutput :
  763. FileRec(f).Handle:=StdOutputHandle;
  764. fmappend :
  765. begin
  766. FileRec(f).Handle:=StdOutputHandle;
  767. FileRec(f).mode:=fmoutput; {fool fmappend}
  768. end;
  769. end;
  770. exit;
  771. end
  772. else
  773. begin
  774. if not PathArgToFullPath(p, s) then
  775. exit;
  776. p:= PChar(s);
  777. end;
  778. //TODO Perhaps handle readonly filesystems, as in sysunix.inc
  779. fh:= c_open(p, oflags);
  780. Errno2InOutRes;
  781. if fh <> -1 then
  782. filerec(f).handle:= fh
  783. else
  784. filerec(f).handle:= UnusedHandle;
  785. {$else}
  786. InOutRes:=1;
  787. //creator:= $522A6368; {'MPS ' -- MPW}
  788. //creator:= $74747874; {'ttxt'}
  789. creator:= $522A6368; {'R*ch' -- BBEdit}
  790. fileType:= $54455854; {'TEXT'}
  791. { reset file handle }
  792. filerec(f).handle:=UnusedHandle;
  793. res:= FSpLocationFromFullPath(StrLen(p), p, spec);
  794. if (res = noErr) or (res = fnfErr) then
  795. begin
  796. if FSpCreate(spec, creator, fileType, smSystemScript) = noErr then
  797. ;
  798. if FSpOpenDF(spec, fsCurPerm, refNum) = noErr then
  799. begin
  800. filerec(f).handle:= refNum;
  801. InOutRes:=0;
  802. end;
  803. end;
  804. if (filerec(f).handle=UnusedHandle) then
  805. begin
  806. //errno:=GetLastError;
  807. //Errno2InoutRes;
  808. end;
  809. {$endif}
  810. end;
  811. {*****************************************************************************
  812. UnTyped File Handling
  813. *****************************************************************************}
  814. {$i file.inc}
  815. {*****************************************************************************
  816. Typed File Handling
  817. *****************************************************************************}
  818. {$i typefile.inc}
  819. {*****************************************************************************
  820. Text File Handling
  821. *****************************************************************************}
  822. { #26 is not end of a file in MacOS ! }
  823. {$i text.inc}
  824. {*****************************************************************************
  825. Directory Handling
  826. *****************************************************************************}
  827. procedure mkdir(const s:string);[IOCheck];
  828. var
  829. spec: FSSpec;
  830. createdDirID: Longint;
  831. err: OSErr;
  832. res: Integer;
  833. begin
  834. If (s='') or (InOutRes <> 0) then
  835. exit;
  836. res:= PathArgToFSSpec(s, spec);
  837. if res = 0 then
  838. begin
  839. err:= FSpDirCreate(spec, smSystemScript, createdDirID);
  840. OSErr2InOutRes(err);
  841. end
  842. else
  843. InOutRes:=res;
  844. end;
  845. procedure rmdir(const s:string);[IOCheck];
  846. {this implementation cannot distinguish between directories and files}
  847. var
  848. spec: FSSpec;
  849. err: OSErr;
  850. res: Integer;
  851. begin
  852. If (s='') or (InOutRes <> 0) then
  853. exit;
  854. res:= PathArgToFSSpec(s, spec);
  855. if res = 0 then
  856. begin
  857. err:= FSpDelete(spec);
  858. OSErr2InOutRes(err);
  859. end
  860. else
  861. InOutRes:=res;
  862. end;
  863. procedure chdir(const s:string);[IOCheck];
  864. var
  865. spec, newDirSpec: FSSpec;
  866. err: OSErr;
  867. res: Integer;
  868. begin
  869. if (s='') or (InOutRes <> 0) then
  870. exit;
  871. res:= PathArgToFSSpec(s, spec);
  872. if res = 0 then
  873. begin
  874. { The fictive file x is appended to the directory name to make
  875. FSMakeFSSpec return a FSSpec to a file in the directory.
  876. Then by clearing the name, the FSSpec then
  877. points to the directory. It doesn't matter whether x exists or not.}
  878. err:= FSMakeFSSpec (spec.vRefNum, spec.parID, ':'+spec.name+':x', newDirSpec);
  879. if err in [ noErr, fnfErr] then
  880. begin
  881. curDirectorySpec:= newDirSpec;
  882. curDirectorySpec.name:='';
  883. InOutRes:= 0;
  884. end
  885. else
  886. begin
  887. {E g if the directory doesn't exist.}
  888. OSErr2InOutRes(err);
  889. end;
  890. end
  891. else
  892. InOutRes:=res;
  893. end;
  894. procedure getDir (DriveNr: byte; var Dir: ShortString);
  895. var
  896. pathHandle: Mac_Handle;
  897. pathHandleSize: Longint;
  898. begin
  899. if FSpGetFullPath(curDirectorySpec, pathHandle, false) <> noErr then
  900. Halt(3); {exit code 3 according to MPW}
  901. pathHandleSize:= GetHandleSize(pathHandle);
  902. SetString(dir, pathHandle^, pathHandleSize);
  903. DisposeHandle(pathHandle);
  904. if pathHandleSize <= 255 then {because dir is ShortString}
  905. InOutRes := 0
  906. else
  907. InOutRes := 1; //TODO Exchange to something better
  908. end;
  909. {*****************************************************************************
  910. SystemUnit Initialization
  911. *****************************************************************************}
  912. procedure pascalmain; external name 'PASCALMAIN';
  913. {Main entry point in C style, needed to capture program parameters.
  914. For this to work, the system unit must be before the main program
  915. in the linking order.}
  916. procedure main(argcparam: Longint; argvparam: ppchar; envpparam: ppchar); cdecl; [public];
  917. begin
  918. argc:= argcparam;
  919. argv:= argvparam;
  920. envp:= envpparam;
  921. pascalmain; {run the pascal main program}
  922. end;
  923. procedure setup_arguments;
  924. begin
  925. {Nothing needs to be done here.}
  926. end;
  927. procedure setup_environment;
  928. begin
  929. end;
  930. {*****************************************************************************
  931. System Dependent Exit code
  932. *****************************************************************************}
  933. Procedure system_exit;
  934. begin
  935. {$ifndef MACOS_USE_STDCLIB}
  936. if StandAlone <> 0 then
  937. ExitToShell;
  938. {$else}
  939. c_exit(exitcode); {exitcode is only utilized by an MPW tool}
  940. {$endif}
  941. end;
  942. procedure SysInitStdIO;
  943. begin
  944. { Setup stdin, stdout and stderr }
  945. {$ifdef MACOS_USE_STDCLIB}
  946. OpenStdIO(Input,fmInput,StdInputHandle);
  947. OpenStdIO(Output,fmOutput,StdOutputHandle);
  948. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  949. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  950. {$endif }
  951. end;
  952. var
  953. pathHandle: Mac_Handle;
  954. begin
  955. if false then //To save it from the dead code stripper
  956. begin
  957. //Included only to make them available for debugging in asm.
  958. Debugger;
  959. DebugStr('');
  960. end;
  961. { To be set if this is a GUI or console application }
  962. IsConsole := TRUE;
  963. { To be set if this is a library and not a program }
  964. IsLibrary := FALSE;
  965. StackLength := InitialStkLen;
  966. StackBottom := SPtr - StackLength;
  967. { Setup working directory }
  968. if not GetAppFileLocation(curDirectorySpec) then
  969. Halt(3); //exit code 3 according to MPW
  970. { Setup heap }
  971. MaxApplZone;
  972. if Mac_FreeMem - intern_heapsize < 30000 then
  973. Halt(3); //exit code 3 according to MPW
  974. theHeap:= Sbrk(intern_heapsize);
  975. if theHeap = nil then
  976. Halt(3); //exit code 3 according to MPW
  977. InitHeap;
  978. SysInitStdIO;
  979. { Setup environment and arguments }
  980. Setup_Environment;
  981. setup_arguments;
  982. { Reset IO Error }
  983. InOutRes:=0;
  984. errno:=0;
  985. (* This should be changed to a real value during *)
  986. (* thread driver initialization if appropriate. *)
  987. ThreadID := 1;
  988. {$ifdef HASVARIANT}
  989. initvariantmanager;
  990. {$endif HASVARIANT}
  991. end.
  992. {
  993. $Log$
  994. Revision 1.15 2004-05-11 18:05:41 olle
  995. + added call to MaxApplZone to have the whole MacOS heap available
  996. Revision 1.14 2004/04/29 11:27:36 olle
  997. * do_read/do_write addr arg changed to pointer
  998. * misc internal changes
  999. Revision 1.13 2004/02/04 15:17:16 olle
  1000. * internal changes
  1001. Revision 1.12 2004/01/20 23:11:20 hajny
  1002. * ExecuteProcess fixes, ProcessID and ThreadID added
  1003. Revision 1.11 2004/01/04 21:06:43 jonas
  1004. * make the C-main public
  1005. Revision 1.10 2003/10/29 22:34:52 olle
  1006. + handles program parameters for MPW
  1007. + program start stub
  1008. * improved working directory handling
  1009. * minor changes
  1010. + some documentation
  1011. Revision 1.9 2003/10/17 23:44:30 olle
  1012. + working direcory emulated
  1013. + implemented directory handling procs
  1014. + all proc which take a path param, now resolve it relative wd
  1015. Revision 1.8 2003/10/16 15:43:13 peter
  1016. * THandle is platform dependent
  1017. Revision 1.7 2003/09/27 11:52:35 peter
  1018. * sbrk returns pointer
  1019. Revision 1.6 2003/09/12 12:45:15 olle
  1020. + filehandling complete
  1021. + heaphandling complete
  1022. + support for random
  1023. * filehandling now uses filedecriptors in StdCLib
  1024. * other minor changes
  1025. - removed DEFINE MAC_SYS_RUNNABLE
  1026. Revision 1.5 2003/01/13 17:18:55 olle
  1027. + added support for rudimentary file handling
  1028. Revision 1.4 2002/11/28 10:58:02 olle
  1029. + added support for rudimentary heap
  1030. Revision 1.3 2002/10/23 15:29:09 olle
  1031. + added switch MAC_SYS_RUNABLE
  1032. + added include of system.h etc
  1033. + added standard globals
  1034. + added dummy hook procedures
  1035. Revision 1.2 2002/10/10 19:44:05 florian
  1036. * changes from Olle to compile/link a simple program
  1037. Revision 1.1 2002/10/02 21:34:31 florian
  1038. * first dummy implementation
  1039. }