dos.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2004 by Olle Raab and
  5. members of the Free Pascal development team
  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 Dos;
  13. Interface
  14. Uses
  15. macostp;
  16. Type
  17. SearchRec = packed record
  18. Attr: Byte; {attribute of found file}
  19. Time: LongInt; {last modify date of found file}
  20. Size: LongInt; {file size of found file}
  21. Reserved: Word; {future use}
  22. Name: string[FileNameLen]; {name of foundfile}
  23. SearchSpec: string[FileNameLen]; {search pattern}
  24. NamePos: Word; {end of path,start of name position}
  25. {MacOS specific params, private, do not use:}
  26. paramBlock: CInfoPBRec;
  27. searchFSSpec: FSSpec;
  28. searchAttr: Byte; {attribute we are searching for}
  29. exactMatch: Boolean;
  30. end;
  31. {$i dosh.inc}
  32. Implementation
  33. {TODO Obtain disk size and disk free values for volumes > 2 GB.
  34. For this, PBXGetVolInfoSync can be used. However, this function
  35. is not available on older versions of Mac OS, so the function has
  36. to be weak linked. An alternative is to directly look into the VCB
  37. (Volume Control Block), but since this is on low leveel it is a
  38. compatibility risque.}
  39. {TODO Perhaps make SearchRec.paramBlock opaque, so that uses macostp;
  40. is not needed in the interface part.}
  41. {TODO Perhaps add some kind of "Procedure AddDisk" for accessing other
  42. volumes. At lest accessing the possible disk drives with
  43. driver number 1 and 2 should be easy.}
  44. {TODO Perhaps use LongDateTime for time functions. But the function
  45. calls must then be weak linked.}
  46. Uses
  47. macutils,
  48. unixutil {for FNMatch};
  49. {$UNDEF USE_FEXPAND_INC}
  50. {$IFNDEF USE_FEXPAND_INC}
  51. {$DEFINE HAS_FEXPAND}
  52. {$ENDIF USE_FEXPAND_INC}
  53. {$DEFINE FPC_FEXPAND_VOLUMES}
  54. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  55. {$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
  56. {$I dos.inc}
  57. function MacTimeToDosPackedTime(macfiletime: UInt32): Longint;
  58. var
  59. mdt: DateTimeRec; {Mac OS datastructure}
  60. ddt: Datetime; {Dos OS datastructure}
  61. dospackedtime: Longint;
  62. begin
  63. SecondsToDate(macfiletime, mdt);
  64. with ddt do
  65. begin
  66. year := mdt.year;
  67. month := mdt.month;
  68. day := mdt.day;
  69. hour := mdt.hour;
  70. min := mdt.minute;
  71. sec := mdt.second;
  72. end;
  73. Packtime(ddt, dospackedtime);
  74. MacTimeToDosPackedTime:= dospackedtime;
  75. end;
  76. {******************************************************************************
  77. --- Info / Date / Time ---
  78. ******************************************************************************}
  79. function DosVersion:Word;
  80. begin
  81. DosVersion:=
  82. (macosSystemVersion and $FF00) or
  83. ((macosSystemVersion and $00F0) shr 4);
  84. end;
  85. procedure GetDate (var year, month, mday, wday: word);
  86. var
  87. d: DateTimeRec;
  88. begin
  89. Macostp.GetTime(d);
  90. year := d.year;
  91. month := d.month;
  92. mday := d.day;
  93. wday := d.dayOfWeek - 1; {1-based on mac}
  94. end;
  95. procedure GetTime (var hour, minute, second, sec100: word);
  96. var
  97. d: DateTimeRec;
  98. begin
  99. Macostp.GetTime(d);
  100. hour := d.hour;
  101. minute := d.minute;
  102. second := d.second;
  103. sec100 := 0;
  104. end;
  105. Procedure SetDate(Year, Month, Day: Word);
  106. var
  107. d: DateTimeRec;
  108. Begin
  109. Macostp.GetTime(d);
  110. d.year := year;
  111. d.month := month;
  112. d.day := day;
  113. Macostp.SetTime(d)
  114. End;
  115. Procedure SetTime(Hour, Minute, Second, Sec100: Word);
  116. var
  117. d: DateTimeRec;
  118. Begin
  119. Macostp.GetTime(d);
  120. d.hour := hour;
  121. d.minute := minute;
  122. d.second := second;
  123. Macostp.SetTime(d)
  124. End;
  125. {******************************************************************************
  126. --- Exec ---
  127. ******************************************************************************}
  128. { Create a DoScript AppleEvent that targets the given application with text as the direct object. }
  129. function CreateDoScriptEvent (applCreator: OSType; scriptText: PChar; var theEvent: AppleEvent): OSErr;
  130. var
  131. err: OSErr;
  132. targetAddress: AEDesc;
  133. s: signedByte;
  134. begin
  135. err := AECreateDesc(FourCharCodeToLongword(typeApplSignature), @applCreator, sizeof(applCreator), targetAddress);
  136. if err = noErr then
  137. begin
  138. err := AECreateAppleEvent(FourCharCodeToLongword('misc'), FourCharCodeToLongword('dosc'),
  139. targetAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
  140. if err = noErr then
  141. { Add script text as the direct object parameter. }
  142. err := AEPutParamPtr(theEvent, FourCharCodeToLongword('----'),
  143. FourCharCodeToLongword('TEXT'), scriptText, Length(scriptText));
  144. if err <> noErr then
  145. AEDisposeDesc(theEvent);
  146. AEDisposeDesc(targetAddress);
  147. end;
  148. CreateDoScriptEvent := err;
  149. end;
  150. Procedure Fpc_WriteBuffer(var f:Text;const b;len:longint);[external name 'FPC_WRITEBUFFER'];
  151. {declared in text.inc}
  152. procedure WriteAEDescTypeCharToFile(desc: AEDesc; var f: Text);
  153. begin
  154. if desc.descriptorType = FourCharCodeToLongword(typeChar) then
  155. begin
  156. HLock(desc.dataHandle);
  157. Fpc_WriteBuffer(f, PChar(desc.dataHandle^)^, GetHandleSize(desc.dataHandle));
  158. Flush(f);
  159. HUnLock(desc.dataHandle);
  160. end;
  161. end;
  162. function ExecuteToolserverScript(scriptText: PChar; var statusCode: Longint): OSErr;
  163. var
  164. err: OSErr;
  165. err2: OSErr; {Non serious error}
  166. theEvent: AppleEvent;
  167. reply: AppleEvent;
  168. result: AEDesc;
  169. applFileSpec: FSSpec;
  170. p: SignedByte;
  171. const
  172. applCreator = 'MPSX'; {Toolserver}
  173. begin
  174. statusCode:= 3; //3 according to MPW.
  175. err:= CreateDoScriptEvent (FourCharCodeToLongword(applCreator), scriptText, theEvent);
  176. if err = noErr then
  177. begin
  178. err := AESend(theEvent, reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeOut, nil, nil);
  179. if err = connectionInvalid then { Toolserver not available }
  180. begin
  181. err := FindApplication(FourCharCodeToLongword(applCreator), applFileSpec);
  182. if err = noErr then
  183. err := LaunchFSSpec(false, applFileSpec);
  184. if err = noErr then
  185. err := AESend(theEvent, reply, kAEWaitReply, kAENormalPriority, kAEDefaultTimeOut, nil, nil);
  186. end;
  187. if err = noErr then
  188. begin
  189. err:= AEGetParamDesc(reply, FourCharCodeToLongword('stat'),
  190. FourCharCodeToLongword(typeLongInteger), result);
  191. if err = noErr then
  192. if result.descriptorType = FourCharCodeToLongword(typeLongInteger) then
  193. statusCode:= LongintPtr(result.dataHandle^)^;
  194. {If there is no output below, we get a non zero error code}
  195. err2:= AEGetParamDesc(reply, FourCharCodeToLongword('----'),
  196. FourCharCodeToLongword(typeChar), result);
  197. if err2 = noErr then
  198. WriteAEDescTypeCharToFile(result, stdout);
  199. err2:= AEGetParamDesc(reply, FourCharCodeToLongword('diag'),
  200. FourCharCodeToLongword(typeChar), result);
  201. if err2 = noErr then
  202. WriteAEDescTypeCharToFile(result, stderr);
  203. AEDisposeDesc(reply);
  204. {$IFDEF TARGET_API_MAC_CARBON }
  205. {$ERROR FIXME AEDesc data is not allowed to be directly accessed}
  206. {$ENDIF}
  207. end;
  208. AEDisposeDesc(theEvent);
  209. end;
  210. ExecuteToolserverScript:= err;
  211. end;
  212. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  213. var
  214. s: AnsiString;
  215. err: OSErr;
  216. wdpath: AnsiString;
  217. Begin
  218. {Make ToolServers working directory in sync with our working directory}
  219. PathArgToFullPath(':', wdpath);
  220. wdpath:= 'Directory ' + wdpath;
  221. err:= ExecuteToolserverScript(PChar(wdpath), LastDosExitCode);
  222. {TODO Only change path when actually needed. But this requires some
  223. change counter to be incremented each time wd is changed. }
  224. s:= path + ' ' + comline;
  225. err:= ExecuteToolserverScript(PChar(s), LastDosExitCode);
  226. if err = afpItemNotFound then
  227. DosError := 900
  228. else
  229. DosError := MacOSErr2RTEerr(err);
  230. //TODO Better dos error codes
  231. End;
  232. {******************************************************************************
  233. --- Disk ---
  234. ******************************************************************************}
  235. {If drive is 0 the free space on the volume of the working directory is returned.
  236. If drive is 1 or 2, the free space on the first or second floppy disk is returned.
  237. If drive is 3 the free space on the boot volume is returned.
  238. If the free space is > 2 GB, then 2 GB is reported.}
  239. Function DiskFree(drive: Byte): Int64;
  240. var
  241. myHPB: HParamBlockRec;
  242. myErr: OSErr;
  243. begin
  244. myHPB.ioNamePtr := NIL;
  245. myHPB.ioVolIndex := 0;
  246. case drive of
  247. 0: myHPB.ioVRefNum := GetWorkingDirectoryVRefNum;
  248. 1: myHPB.ioVRefNum := 1;
  249. 2: myHPB.ioVRefNum := 2;
  250. 3: myHPB.ioVRefNum := macosBootVolumeVRefNum;
  251. else
  252. begin
  253. Diskfree:= -1;
  254. Exit;
  255. end;
  256. end;
  257. myErr := PBHGetVInfoSync(@myHPB);
  258. if myErr = noErr then
  259. Diskfree := myHPB.ioVAlBlkSiz * myHPB.ioVFrBlk
  260. else
  261. Diskfree:= -1;
  262. End;
  263. {If drive is 0 the size of the volume of the working directory is returned.
  264. If drive is 1 or 2, the size of the first or second floppy disk is returned.
  265. If drive is 3 the size of the boot volume is returned.
  266. If the actual size is > 2 GB, then 2 GB is reported.}
  267. Function DiskSize(drive: Byte): Int64;
  268. var
  269. myHPB: HParamBlockRec;
  270. myErr: OSErr;
  271. Begin
  272. myHPB.ioNamePtr := NIL;
  273. myHPB.ioVolIndex := 0;
  274. case drive of
  275. 0: myHPB.ioVRefNum := GetWorkingDirectoryVRefNum;
  276. 1: myHPB.ioVRefNum := 1;
  277. 2: myHPB.ioVRefNum := 2;
  278. 3: myHPB.ioVRefNum := macosBootVolumeVRefNum;
  279. else
  280. begin
  281. DiskSize:= -1;
  282. Exit;
  283. end;
  284. end;
  285. myErr := PBHGetVInfoSync(@myHPB);
  286. if myErr = noErr then
  287. DiskSize := myHPB.ioVAlBlkSiz * myHPB.ioVNmAlBlks
  288. else
  289. DiskSize:=-1;
  290. End;
  291. {******************************************************************************
  292. --- Findfirst FindNext ---
  293. ******************************************************************************}
  294. (*
  295. {The one defined in Unixutils.pp is used instead}
  296. function FNMatch (const Pattern, Name: string): Boolean;
  297. var
  298. LenPat, LenName: longint;
  299. function DoFNMatch (i, j: longint): Boolean;
  300. var
  301. Found: boolean;
  302. begin
  303. Found := true;
  304. while Found and (i <= LenPat) do
  305. begin
  306. case Pattern[i] of
  307. '?':
  308. Found := (j <= LenName);
  309. '*':
  310. begin
  311. {find the next character in pattern, different of ? and *}
  312. while Found and (i < LenPat) do
  313. begin
  314. i := i + 1;
  315. case Pattern[i] of
  316. '*':
  317. ;
  318. '?':
  319. begin
  320. j := j + 1;
  321. Found := (j <= LenName);
  322. end;
  323. otherwise
  324. Found := false;
  325. end;
  326. end;
  327. {Now, find in name the character which i points to, if the * or ?}
  328. {wasn 't the last character in the pattern, else, use up all the}
  329. {chars in name }
  330. Found := true;
  331. if (i <= LenPat) then
  332. begin
  333. repeat
  334. {find a letter (not only first !) which maches pattern[i]}
  335. while (j <= LenName) and (name[j] <> pattern[i]) do
  336. j := j + 1;
  337. if (j < LenName) then
  338. begin
  339. if DoFnMatch(i + 1, j + 1) then
  340. begin
  341. i := LenPat;
  342. j := LenName;{we can stop}
  343. Found := true;
  344. end
  345. else
  346. j := j + 1;{We didn't find one, need to look further}
  347. end;
  348. until (j >= LenName);
  349. end
  350. else
  351. j := LenName;{we can stop}
  352. end;
  353. otherwise {not a wildcard character in pattern}
  354. Found := (j <= LenName) and (pattern[i] = name[j]);
  355. end;
  356. i := i + 1;
  357. j := j + 1;
  358. end;
  359. DoFnMatch := Found and (j > LenName);
  360. end;
  361. begin {start FNMatch}
  362. LenPat := Length(Pattern);
  363. LenName := Length(Name);
  364. FNMatch := DoFNMatch(1, 1);
  365. end;
  366. *)
  367. function GetFileAttrFromPB (var paramBlock: CInfoPBRec): Word;
  368. var
  369. isLocked, isInvisible, isDirectory, isNameLocked: Boolean;
  370. attr: Word;
  371. {NOTE "nameLocked" was in pre-System 7 called "isSystem".
  372. It is used for files whose name and icon cannot be changed by the user,
  373. that is essentially system files. However in System 9 the folder
  374. "Applications (Mac OS 9)" also has this attribute, and since this is
  375. not a system file in traditional meaning, we will not use this attribute
  376. as the "sysfile" attribute.}
  377. begin
  378. with paramBlock do
  379. begin
  380. attr := 0;
  381. isDirectory := (ioFlAttrib and $10) <> 0;
  382. if isDirectory then
  383. attr := (attr or directory);
  384. isLocked := (ioFlAttrib and $01) <> 0;
  385. if isLocked then
  386. attr := (attr or readonly);
  387. if not isDirectory then
  388. begin
  389. isInvisible := (ioFlFndrInfo.fdFlags and 16384) <> 0;
  390. (* isNameLocked := (ioFlFndrInfo.fdFlags and 4096) <> 0; *)
  391. end
  392. else
  393. begin
  394. isInvisible := (ioDrUsrWds.frFlags and 16384) <> 0;
  395. (* isNameLocked := (ioDrUsrWds.frFlags and 4096) <> 0; *)
  396. end;
  397. if isInvisible then
  398. attr := (attr or hidden);
  399. (*
  400. if isNameLocked then
  401. attr := (attr or sysfile);
  402. *)
  403. GetFileAttrFromPB := attr;
  404. end;
  405. end;
  406. procedure SetPBFromFileAttr (var paramBlock: CInfoPBRec; attr: Word);
  407. begin
  408. with paramBlock do
  409. begin
  410. (*
  411. {Doesn't seem to work, despite the documentation.}
  412. {Can instead be set by FSpSetFLock/FSpRstFLock}
  413. if (attr and readonly) <> 0 then
  414. ioFlAttrib := (ioFlAttrib or $01)
  415. else
  416. ioFlAttrib := (ioFlAttrib and not($01));
  417. *)
  418. if (attr and hidden) <> 0 then
  419. ioFlFndrInfo.fdFlags := (ioFlFndrInfo.fdFlags or 16384)
  420. else
  421. ioFlFndrInfo.fdFlags := (ioFlFndrInfo.fdFlags and not(16384))
  422. end;
  423. end;
  424. function GetFileSizeFromPB (var paramBlock: CInfoPBRec): Longint;
  425. begin
  426. with paramBlock do
  427. if ((ioFlAttrib and $10) <> 0) then {if directory}
  428. GetFileSizeFromPB := 0
  429. else
  430. GetFileSizeFromPB := ioFlLgLen + ioFlRLgLen; {Add length of both forks}
  431. end;
  432. function DoFindOne (var spec: FSSpec; var paramBlock: CInfoPBRec): Integer;
  433. var
  434. err: OSErr;
  435. begin
  436. with paramBlock do
  437. begin
  438. ioVRefNum := spec.vRefNum;
  439. ioDirID := spec.parID;
  440. ioNamePtr := @spec.name;
  441. ioFDirIndex := 0;
  442. err := PBGetCatInfoSync(@paramBlock);
  443. DoFindOne := MacOSErr2RTEerr(err);
  444. end;
  445. end;
  446. {To be used after a call to DoFindOne, with the same spec and paramBlock.}
  447. {Change those parameters in paramBlock, which is to be changed.}
  448. function DoSetOne (var spec: FSSpec; var paramBlock: CInfoPBRec): Integer;
  449. var
  450. err: OSErr;
  451. begin
  452. with paramBlock do
  453. begin
  454. ioVRefNum := spec.vRefNum;
  455. ioDirID := spec.parID;
  456. ioNamePtr := @spec.name;
  457. err := PBSetCatInfoSync(@paramBlock);
  458. DoSetOne := MacOSErr2RTEerr(err);
  459. end;
  460. end;
  461. procedure DoFind (var F: SearchRec; firstTime: Boolean);
  462. var
  463. err: OSErr;
  464. s: Str255;
  465. begin
  466. with F, paramBlock do
  467. begin
  468. ioVRefNum := searchFSSpec.vRefNum;
  469. if firstTime then
  470. ioFDirIndex := 0;
  471. while true do
  472. begin
  473. s := '';
  474. ioDirID := searchFSSpec.parID;
  475. ioFDirIndex := ioFDirIndex + 1;
  476. ioNamePtr := @s;
  477. err := PBGetCatInfoSync(@paramBlock);
  478. if err <> noErr then
  479. begin
  480. if err = fnfErr then
  481. DosError := 18
  482. else
  483. DosError := MacOSErr2RTEerr(err);
  484. break;
  485. end;
  486. attr := GetFileAttrFromPB(f.paramBlock);
  487. if ((Attr and not(searchAttr)) = 0) then
  488. begin
  489. name := s;
  490. UpperString(s, true);
  491. if FNMatch(F.searchFSSpec.name, s) then
  492. begin
  493. size := GetFileSizeFromPB(paramBlock);
  494. time := MacTimeToDosPackedTime(ioFlMdDat);
  495. DosError := 0;
  496. break;
  497. end;
  498. end;
  499. end;
  500. end;
  501. end;
  502. procedure FindFirst (const path: pathstr; Attr: Word; var F: SearchRec);
  503. var
  504. s: Str255;
  505. begin
  506. fillchar(f, sizeof(f), 0);
  507. if path = '' then
  508. begin
  509. DosError := 3;
  510. Exit;
  511. end;
  512. {We always also search for readonly and archive, regardless of Attr.}
  513. F.searchAttr := (Attr or (archive or readonly));
  514. DosError := PathArgToFSSpec(path, F.searchFSSpec);
  515. with F do
  516. if (DosError = 0) or (DosError = 2) then
  517. begin
  518. SearchSpec := path;
  519. NamePos := Length(path) - Length(searchFSSpec.name);
  520. if (Pos('?', searchFSSpec.name) = 0) and (Pos('*', searchFSSpec.name) = 0) then {No wildcards}
  521. begin {If exact match, we don't have to scan the directory}
  522. exactMatch := true;
  523. DosError := DoFindOne(searchFSSpec, paramBlock);
  524. if DosError = 0 then
  525. begin
  526. Attr := GetFileAttrFromPB(paramBlock);
  527. if ((Attr and not(searchAttr)) = 0) then
  528. begin
  529. name := searchFSSpec.name;
  530. size := GetFileSizeFromPB(paramBlock);
  531. time := MacTimeToDosPackedTime(paramBlock.ioFlMdDat);
  532. end
  533. else
  534. DosError := 18;
  535. end
  536. else if DosError = 2 then
  537. DosError := 18;
  538. end
  539. else
  540. begin
  541. exactMatch := false;
  542. s := searchFSSpec.name;
  543. UpperString(s, true);
  544. F.searchFSSpec.name := s;
  545. DoFind(F, true);
  546. end;
  547. end;
  548. end;
  549. procedure FindNext (var f: searchRec);
  550. begin
  551. if F.exactMatch then
  552. DosError := 18
  553. else
  554. DoFind(F, false);
  555. end;
  556. procedure FindClose (var f: searchRec);
  557. {Note: Even if this routine is empty, this doesn't mean it will}
  558. {be empty in the future. Please use it.}
  559. begin
  560. end;
  561. {******************************************************************************
  562. --- File ---
  563. ******************************************************************************}
  564. function FSearch (path: pathstr; dirlist: string): pathstr;
  565. {Searches for a file 'path' in the working directory and then in the list of }
  566. {directories in 'dirlist' . Returns a valid (possibly relative) path or an }
  567. {empty string if not found . Wildcards are NOT allowed }
  568. {The dirlist can be separated with ; or , but not :}
  569. var
  570. NewDir: string[255];
  571. p1: Longint;
  572. spec: FSSpec;
  573. fpcerr: Integer;
  574. begin
  575. FSearch := '';
  576. if (Length(path) = 0) then
  577. Exit;
  578. {Check for Wild Cards}
  579. if (Pos('?', Path) <> 0) or (Pos('*', Path) <> 0) then
  580. Exit;
  581. path := TranslatePathToMac(path, false);
  582. {Search in working directory, or as full path}
  583. fpcerr := PathArgToFSSpec(path, spec);
  584. if (fpcerr = 0) and not IsDirectory(spec) then
  585. begin
  586. FSearch := path;
  587. Exit;
  588. end
  589. else if not IsMacFullPath(path) then {If full path, we do not need to continue.}
  590. begin
  591. {Replace ';' with native mac PathSeparator (',').}
  592. {Note: we cannot support unix style ':', because it is used as dir separator in MacOS}
  593. for p1 := 1 to length(dirlist) do
  594. if dirlist[p1] = ';' then
  595. dirlist[p1] := PathSeparator;
  596. repeat
  597. p1 := Pos(PathSeparator, DirList);
  598. if p1 = 0 then
  599. p1 := 255;
  600. NewDir := TranslatePathToMac(Copy(DirList, 1, P1 - 1), false);
  601. NewDir := ConcatMacPath(NewDir, Path);
  602. Delete(DirList, 1, p1);
  603. fpcerr := PathArgToFSSpec(NewDir, spec);
  604. if fpcerr = 0 then
  605. begin
  606. if IsDirectory(spec) then
  607. NewDir := '';
  608. end
  609. else
  610. NewDir := '';
  611. until (DirList = '') or (Length(NewDir) > 0);
  612. FSearch := NewDir;
  613. end;
  614. end;
  615. {$IFNDEF USE_FEXPAND_INC}
  616. { TODO nonexisting dirs in path's doesnt work (nonexisting files do work)
  617. example: Writeln('FExpand on :nisse:kalle : ', FExpand(':nisse:kalle')); }
  618. function FExpand (const path: pathstr): pathstr;
  619. var
  620. fullpath: AnsiString;
  621. begin
  622. DosError:= PathArgToFullPath(path, fullpath);
  623. FExpand:= fullpath;
  624. end;
  625. {$ENDIF USE_FEXPAND_INC}
  626. procedure GetFTime (var f ; var time: longint);
  627. var
  628. spec: FSSpec;
  629. paramBlock: CInfoPBRec;
  630. begin
  631. DosError := PathArgToFSSpec(filerec(f).name, spec);
  632. if (DosError = 0) or (DosError = 2) then
  633. begin
  634. DosError := DoFindOne(spec, paramBlock);
  635. if DosError = 0 then
  636. time := MacTimeToDosPackedTime(paramBlock.ioFlMdDat);
  637. end;
  638. end;
  639. procedure SetFTime (var f ; time: longint);
  640. var
  641. spec: FSSpec;
  642. paramBlock: CInfoPBRec;
  643. d: DateTimeRec; {Mac OS datastructure}
  644. t: datetime;
  645. macfiletime: UInt32;
  646. begin
  647. DosError := PathArgToFSSpec(filerec(f).name, spec);
  648. if (DosError = 0) or (DosError = 2) then
  649. begin
  650. DosError := DoFindOne(spec, paramBlock);
  651. if DosError = 0 then
  652. begin
  653. Unpacktime(time, t);
  654. with t do
  655. begin
  656. d.year := year;
  657. d.month := month;
  658. d.day := day;
  659. d.hour := hour;
  660. d.minute := min;
  661. d.second := sec;
  662. end;
  663. DateToSeconds(d, macfiletime);
  664. paramBlock.ioFlMdDat := macfiletime;
  665. DosError := DoSetOne(spec, paramBlock);
  666. end;
  667. end;
  668. end;
  669. procedure GetFAttr (var f ; var attr: word);
  670. var
  671. spec: FSSpec;
  672. paramBlock: CInfoPBRec;
  673. begin
  674. DosError := PathArgToFSSpec(filerec(f).name, spec);
  675. if (DosError = 0) or (DosError = 2) then
  676. begin
  677. DosError := DoFindOne(spec, paramBlock);
  678. if DosError = 0 then
  679. attr := GetFileAttrFromPB(paramBlock);
  680. end;
  681. end;
  682. procedure SetFAttr (var f ; attr: word);
  683. var
  684. spec: FSSpec;
  685. paramBlock: CInfoPBRec;
  686. begin
  687. if (attr and VolumeID) <> 0 then
  688. begin
  689. Doserror := 5;
  690. end;
  691. DosError := PathArgToFSSpec(filerec(f).name, spec);
  692. if (DosError = 0) or (DosError = 2) then
  693. begin
  694. DosError := DoFindOne(spec, paramBlock);
  695. if DosError = 0 then
  696. begin
  697. SetPBFromFileAttr(paramBlock, attr);
  698. DosError := DoSetOne(spec, paramBlock);
  699. if (paramBlock.ioFlAttrib and $10) = 0 then {check not directory}
  700. if DosError = 0 then
  701. if (attr and readonly) <> 0 then
  702. DosError := MacOSErr2RTEerr(FSpSetFLock(spec))
  703. else
  704. DosError := MacOSErr2RTEerr(FSpRstFLock(spec));
  705. end;
  706. end;
  707. end;
  708. {******************************************************************************
  709. --- Environment ---
  710. ******************************************************************************}
  711. Function EnvCount: Longint;
  712. var
  713. envcnt : longint;
  714. p : ppchar;
  715. Begin
  716. envcnt:=0;
  717. p:=envp; {defined in system}
  718. while (p^<>nil) do
  719. begin
  720. inc(envcnt);
  721. inc(p);
  722. end;
  723. EnvCount := envcnt
  724. End;
  725. Function EnvStr (Index: longint): String;
  726. Var
  727. i : longint;
  728. p : ppchar;
  729. Begin
  730. if Index <= 0 then
  731. envstr:=''
  732. else
  733. begin
  734. p:=envp; {defined in system}
  735. i:=1;
  736. while (i<Index) and (p^<>nil) do
  737. begin
  738. inc(i);
  739. inc(p);
  740. end;
  741. if p=nil then
  742. envstr:=''
  743. else
  744. envstr:=strpas(p^) + '=' + strpas(p^+strlen(p^)+1);
  745. end;
  746. end;
  747. function c_getenv(varname: PChar): PChar; {TODO perhaps move to a separate inc file.}
  748. external 'StdCLib' name 'getenv';
  749. Function GetEnv(EnvVar: String): String;
  750. var
  751. p: PChar;
  752. name: String;
  753. Begin
  754. name:= EnvVar+#0;
  755. p:= c_getenv(@name[1]);
  756. if p=nil then
  757. GetEnv:=''
  758. else
  759. GetEnv:=StrPas(p);
  760. End;
  761. {
  762. Procedure GetCBreak(Var BreakValue: Boolean);
  763. Begin
  764. -- Might be implemented in future on MacOS to handle Cmd-. (period) key press
  765. End;
  766. Procedure SetCBreak(BreakValue: Boolean);
  767. Begin
  768. -- Might be implemented in future on MacOS to handle Cmd-. (period) key press
  769. End;
  770. Procedure GetVerify(Var Verify: Boolean);
  771. Begin
  772. -- Might be implemented in future on MacOS
  773. End;
  774. Procedure SetVerify(Verify: Boolean);
  775. Begin
  776. -- Might be implemented in future on MacOS
  777. End;
  778. }
  779. {******************************************************************************
  780. --- Initialization ---
  781. ******************************************************************************}
  782. End.