dos.pp 26 KB

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