dos.pp 28 KB

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