dos.pp 26 KB

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