dos.pp 27 KB

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