dos.pp 26 KB

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