2
0

dos.pp 27 KB

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