dos.pp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2014 by the Free Pascal development team
  4. DOS unit for AmigaOS & clones
  5. Heavily based on the 1.x Amiga version by Nils Sjoholm and
  6. Carl Eric Codere
  7. AmigaOS and MorphOS support by Karoly Balogh
  8. AROS support by Marcus Sackrow
  9. See the file COPYING.FPC, included in this distribution,
  10. for details about the copyright.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. **********************************************************************}
  15. {$INLINE ON}
  16. unit Dos;
  17. {--------------------------------------------------------------------}
  18. { LEFT TO DO: }
  19. {--------------------------------------------------------------------}
  20. { o DiskFree / Disksize don't work as expected }
  21. { o Implement EnvCount,EnvStr }
  22. { o FindFirst should only work with correct attributes }
  23. {--------------------------------------------------------------------}
  24. interface
  25. type
  26. SearchRec = Packed Record
  27. { watch out this is correctly aligned for all processors }
  28. { don't modify. }
  29. { Replacement for Fill }
  30. {0} AnchorPtr : Pointer; { Pointer to the Anchorpath structure }
  31. {4} Fill: Array[1..15] of Byte; {future use}
  32. {End of replacement for fill}
  33. Attr : BYTE; {attribute of found file}
  34. Time : LongInt; {last modify date of found file}
  35. Size : LongInt; {file size of found file}
  36. Name : String[255]; {name of found file}
  37. End;
  38. {$I dosh.inc}
  39. implementation
  40. {$DEFINE HAS_GETMSCOUNT}
  41. {$DEFINE HAS_GETCBREAK}
  42. {$DEFINE HAS_SETCBREAK}
  43. {$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
  44. {$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
  45. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  46. {$I dos.inc}
  47. { * include MorphOS specific functions & definitions * }
  48. {$include execd.inc}
  49. {$include execf.inc}
  50. {$include timerd.inc}
  51. {$include doslibd.inc}
  52. {$include doslibf.inc}
  53. {$include utilf.inc}
  54. const
  55. DaysPerMonth : Array[1..12] of ShortInt =
  56. (031,028,031,030,031,030,031,031,030,031,030,031);
  57. DaysPerYear : Array[1..12] of Integer =
  58. (031,059,090,120,151,181,212,243,273,304,334,365);
  59. DaysPerLeapYear : Array[1..12] of Integer =
  60. (031,060,091,121,152,182,213,244,274,305,335,366);
  61. SecsPerYear : LongInt = 31536000;
  62. SecsPerLeapYear : LongInt = 31622400;
  63. SecsPerDay : LongInt = 86400;
  64. SecsPerHour : Integer = 3600;
  65. SecsPerMinute : ShortInt = 60;
  66. TICKSPERSECOND = 50;
  67. {******************************************************************************
  68. --- Internal routines ---
  69. ******************************************************************************}
  70. { * PathConv is implemented in the system unit! * }
  71. function PathConv(path: string): string; external name 'PATHCONV';
  72. function dosLock(const name: String;
  73. accessmode: Longint) : LongInt;
  74. var
  75. buffer: array[0..255] of Char;
  76. begin
  77. move(name[1],buffer,length(name));
  78. buffer[length(name)]:=#0;
  79. dosLock:=Lock(buffer,accessmode);
  80. end;
  81. function BADDR(bval: LongInt): Pointer; Inline;
  82. begin
  83. BADDR:=Pointer(bval Shl 2);
  84. end;
  85. function BSTR2STRING(s : Pointer): PChar; Inline;
  86. begin
  87. BSTR2STRING:=PChar(BADDR(PtrInt(s)))+1;
  88. end;
  89. function BSTR2STRING(s : LongInt): PChar; Inline;
  90. begin
  91. BSTR2STRING:=PChar(BADDR(s))+1;
  92. end;
  93. function IsLeapYear(Source : Word) : Boolean;
  94. begin
  95. if (source Mod 400 = 0) or ((source Mod 4 = 0) and (source Mod 100 <> 0)) then
  96. IsLeapYear:=True
  97. else
  98. IsLeapYear:=False;
  99. end;
  100. procedure Amiga2DateStamp(Date : LongInt; var TotalDays,Minutes,Ticks: longint);
  101. { Converts a value in seconds past 1978 to a value in AMIGA DateStamp format }
  102. { Taken from SWAG and modified to work with the Amiga format - CEC }
  103. var
  104. LocalDate : LongInt;
  105. Done : Boolean;
  106. TotDays : Integer;
  107. Y: Word;
  108. H: Word;
  109. Min: Word;
  110. S : Word;
  111. begin
  112. Y := 1978; H := 0; Min := 0; S := 0;
  113. TotalDays := 0;
  114. Minutes := 0;
  115. Ticks := 0;
  116. LocalDate := Date;
  117. Done := false;
  118. while not Done do
  119. begin
  120. if LocalDate >= SecsPerYear then
  121. begin
  122. Inc(Y,1);
  123. Dec(LocalDate,SecsPerYear);
  124. Inc(TotalDays,DaysPerYear[12]);
  125. end else
  126. Done := true;
  127. if (IsLeapYear(Y+1)) and (LocalDate >= SecsPerLeapYear) and
  128. (Not Done) then
  129. begin
  130. Inc(Y,1);
  131. Dec(LocalDate,SecsPerLeapYear);
  132. Inc(TotalDays,DaysPerLeapYear[12]);
  133. end;
  134. end; { END WHILE }
  135. TotDays := LocalDate Div SecsPerDay;
  136. { Total number of days }
  137. TotalDays := TotalDays + TotDays;
  138. Dec(LocalDate,TotDays*SecsPerDay);
  139. { Absolute hours since start of day }
  140. H := LocalDate Div SecsPerHour;
  141. { Convert to minutes }
  142. Minutes := H*60;
  143. Dec(LocalDate,(H * SecsPerHour));
  144. { Find the remaining minutes to add }
  145. Min := LocalDate Div SecsPerMinute;
  146. Dec(LocalDate,(Min * SecsPerMinute));
  147. Minutes:=Minutes+Min;
  148. { Find the number of seconds and convert to ticks }
  149. S := LocalDate;
  150. Ticks:=TICKSPERSECOND*S;
  151. end;
  152. function dosSetProtection(const name: string; mask:longint): Boolean;
  153. var
  154. buffer : array[0..255] of Char;
  155. begin
  156. move(name[1],buffer,length(name));
  157. buffer[length(name)]:=#0;
  158. dosSetProtection:=SetProtection(buffer,mask) <> 0;
  159. end;
  160. function dosSetFileDate(name: string; p : PDateStamp): Boolean;
  161. var
  162. buffer : array[0..255] of Char;
  163. begin
  164. move(name[1],buffer,length(name));
  165. buffer[length(name)]:=#0;
  166. dosSetFileDate:=SetFileDate(buffer,p);
  167. end;
  168. {******************************************************************************
  169. --- Info / Date / Time ---
  170. ******************************************************************************}
  171. function DosVersion: Word;
  172. var p: PLibrary;
  173. begin
  174. p:=PLibrary(AOS_DOSBase);
  175. DosVersion:= p^.lib_Version or (p^.lib_Revision shl 8);
  176. end;
  177. { Here are a lot of stuff just for setdate and settime }
  178. var
  179. TimerBase : Pointer;
  180. procedure NewList (list: pList);
  181. begin
  182. with list^ do begin
  183. lh_Head := pNode(@lh_Tail);
  184. lh_Tail := NIL;
  185. lh_TailPred := pNode(@lh_Head)
  186. end;
  187. end;
  188. function CreateExtIO (port: pMsgPort; size: Longint): pIORequest;
  189. var
  190. IOReq: pIORequest;
  191. begin
  192. IOReq := NIL;
  193. if port <> NIL then
  194. begin
  195. IOReq := execAllocMem(size, MEMF_CLEAR);
  196. if IOReq <> NIL then
  197. begin
  198. IOReq^.io_Message.mn_Node.ln_Type := 7;
  199. IOReq^.io_Message.mn_Length := size;
  200. IOReq^.io_Message.mn_ReplyPort := port;
  201. end;
  202. end;
  203. CreateExtIO := IOReq;
  204. end;
  205. procedure DeleteExtIO (ioReq: pIORequest);
  206. begin
  207. if ioReq <> NIL then
  208. begin
  209. ioReq^.io_Message.mn_Node.ln_Type := $FF;
  210. ioReq^.io_Message.mn_ReplyPort := pMsgPort(-1);
  211. ioReq^.io_Device := pDevice(-1);
  212. execFreeMem(ioReq, ioReq^.io_Message.mn_Length);
  213. end
  214. end;
  215. function Createport(name : PChar; pri : longint): pMsgPort;
  216. var
  217. sigbit : ShortInt;
  218. port : pMsgPort;
  219. begin
  220. sigbit := AllocSignal(-1);
  221. if sigbit = -1 then CreatePort := nil;
  222. port := execAllocMem(sizeof(tMsgPort),MEMF_CLEAR);
  223. if port = nil then begin
  224. FreeSignal(sigbit);
  225. CreatePort := nil;
  226. end;
  227. with port^ do begin
  228. if assigned(name) then
  229. mp_Node.ln_Name := name
  230. else mp_Node.ln_Name := nil;
  231. mp_Node.ln_Pri := pri;
  232. mp_Node.ln_Type := 4;
  233. mp_Flags := 0;
  234. mp_SigBit := sigbit;
  235. mp_SigTask := FindTask(nil);
  236. end;
  237. if assigned(name) then AddPort(port)
  238. else NewList(addr(port^.mp_MsgList));
  239. CreatePort := port;
  240. end;
  241. procedure DeletePort (port: pMsgPort);
  242. begin
  243. if port <> NIL then
  244. begin
  245. if port^.mp_Node.ln_Name <> NIL then
  246. RemPort(port);
  247. port^.mp_Node.ln_Type := $FF;
  248. port^.mp_MsgList.lh_Head := pNode(-1);
  249. FreeSignal(port^.mp_SigBit);
  250. execFreeMem(port, sizeof(tMsgPort));
  251. end;
  252. end;
  253. function Create_Timer(theUnit : longint) : pTimeRequest;
  254. var
  255. Error : longint;
  256. TimerPort : pMsgPort;
  257. TimeReq : pTimeRequest;
  258. begin
  259. TimerPort := CreatePort(Nil, 0);
  260. if TimerPort = Nil then
  261. Create_Timer := Nil;
  262. TimeReq := pTimeRequest(CreateExtIO(TimerPort,sizeof(tTimeRequest)));
  263. if TimeReq = Nil then begin
  264. DeletePort(TimerPort);
  265. Create_Timer := Nil;
  266. end;
  267. Error := OpenDevice(TIMERNAME, theUnit, pIORequest(TimeReq), 0);
  268. if Error <> 0 then begin
  269. DeleteExtIO(pIORequest(TimeReq));
  270. DeletePort(TimerPort);
  271. Create_Timer := Nil;
  272. end;
  273. TimerBase := pointer(TimeReq^.tr_Node.io_Device);
  274. Create_Timer := pTimeRequest(TimeReq);
  275. end;
  276. Procedure Delete_Timer(WhichTimer : pTimeRequest);
  277. var
  278. WhichPort : pMsgPort;
  279. begin
  280. WhichPort := WhichTimer^.tr_Node.io_Message.mn_ReplyPort;
  281. if assigned(WhichTimer) then begin
  282. CloseDevice(pIORequest(WhichTimer));
  283. DeleteExtIO(pIORequest(WhichTimer));
  284. end;
  285. if assigned(WhichPort) then
  286. DeletePort(WhichPort);
  287. end;
  288. function set_new_time(secs, micro : longint): longint;
  289. var
  290. tr : ptimerequest;
  291. begin
  292. tr := create_timer(UNIT_MICROHZ);
  293. { non zero return says error }
  294. if tr = nil then set_new_time := -1;
  295. tr^.tr_time.tv_secs := secs;
  296. tr^.tr_time.tv_micro := micro;
  297. tr^.tr_node.io_Command := TR_SETSYSTIME;
  298. DoIO(pIORequest(tr));
  299. delete_timer(tr);
  300. set_new_time := 0;
  301. end;
  302. function get_sys_time(tv : ptimeval): longint;
  303. var
  304. tr : ptimerequest;
  305. begin
  306. tr := create_timer( UNIT_MICROHZ );
  307. { non zero return says error }
  308. if tr = nil then get_sys_time := -1;
  309. tr^.tr_node.io_Command := TR_GETSYSTIME;
  310. DoIO(pIORequest(tr));
  311. { structure assignment }
  312. tv^ := tr^.tr_time;
  313. delete_timer(tr);
  314. get_sys_time := 0;
  315. end;
  316. procedure GetDate(Var Year, Month, MDay, WDay: Word);
  317. var
  318. cd : pClockData;
  319. oldtime : ttimeval;
  320. begin
  321. new(cd);
  322. get_sys_time(@oldtime);
  323. Amiga2Date(oldtime.tv_secs,cd);
  324. Year := cd^.year;
  325. Month := cd^.month;
  326. MDay := cd^.mday;
  327. WDay := cd^.wday;
  328. dispose(cd);
  329. end;
  330. procedure SetDate(Year, Month, Day: Word);
  331. var
  332. cd : pClockData;
  333. oldtime : ttimeval;
  334. begin
  335. new(cd);
  336. get_sys_time(@oldtime);
  337. Amiga2Date(oldtime.tv_secs,cd);
  338. cd^.year := Year;
  339. cd^.month := Month;
  340. cd^.mday := Day;
  341. set_new_time(Date2Amiga(cd),0);
  342. dispose(cd);
  343. end;
  344. procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  345. var
  346. cd : pClockData;
  347. oldtime : ttimeval;
  348. begin
  349. new(cd);
  350. get_sys_time(@oldtime);
  351. Amiga2Date(oldtime.tv_secs,cd);
  352. Hour := cd^.hour;
  353. Minute := cd^.min;
  354. Second := cd^.sec;
  355. Sec100 := oldtime.tv_micro div 10000;
  356. dispose(cd);
  357. end;
  358. Procedure SetTime(Hour, Minute, Second, Sec100: Word);
  359. var
  360. cd : pClockData;
  361. oldtime : ttimeval;
  362. begin
  363. new(cd);
  364. get_sys_time(@oldtime);
  365. Amiga2Date(oldtime.tv_secs,cd);
  366. cd^.hour := Hour;
  367. cd^.min := Minute;
  368. cd^.sec := Second;
  369. set_new_time(Date2Amiga(cd), Sec100 * 10000);
  370. dispose(cd);
  371. end;
  372. function GetMsCount: int64;
  373. var
  374. TV: TTimeVal;
  375. begin
  376. Get_Sys_Time (@TV);
  377. GetMsCount := int64 (TV.TV_Secs) * 1000 + TV.TV_Micro div 1000;
  378. end;
  379. {******************************************************************************
  380. --- Exec ---
  381. ******************************************************************************}
  382. procedure Exec(const Path: PathStr; const ComLine: ComStr);
  383. var
  384. tmpPath: array[0..515] of char;
  385. result : longint;
  386. tmpLock: longint;
  387. begin
  388. DosError:= 0;
  389. LastDosExitCode:=0;
  390. tmpPath:=PathConv(Path)+#0+ComLine+#0; // hacky... :)
  391. { Here we must first check if the command we wish to execute }
  392. { actually exists, because this is NOT handled by the }
  393. { _SystemTagList call (program will abort!!) }
  394. { Try to open with shared lock }
  395. tmpLock:=Lock(tmpPath,SHARED_LOCK);
  396. if tmpLock<>0 then
  397. begin
  398. { File exists - therefore unlock it }
  399. Unlock(tmpLock);
  400. tmpPath[length(Path)]:=' '; // hacky... replaces first #0 from above, to get the whole string. :)
  401. result:=SystemTagList(tmpPath,nil);
  402. { on return of -1 the shell could not be executed }
  403. { probably because there was not enough memory }
  404. if result = -1 then
  405. DosError:=8
  406. else
  407. LastDosExitCode:=word(result);
  408. end
  409. else
  410. DosError:=3;
  411. end;
  412. procedure GetCBreak(Var BreakValue: Boolean);
  413. begin
  414. breakvalue := system.BreakOn;
  415. end;
  416. procedure SetCBreak(BreakValue: Boolean);
  417. begin
  418. system.Breakon := BreakValue;
  419. end;
  420. {******************************************************************************
  421. --- Disk ---
  422. ******************************************************************************}
  423. { How to solve the problem with this: }
  424. { We could walk through the device list }
  425. { at startup to determine possible devices }
  426. const
  427. not_to_use_devs : array[0..12] of string =(
  428. 'DF0:',
  429. 'DF1:',
  430. 'DF2:',
  431. 'DF3:',
  432. 'PED:',
  433. 'PRJ:',
  434. 'PIPE:',
  435. 'RAM:',
  436. 'CON:',
  437. 'RAW:',
  438. 'SER:',
  439. 'PAR:',
  440. 'PRT:');
  441. var
  442. deviceids : array[1..20] of byte;
  443. devicenames : array[1..20] of string[20];
  444. numberofdevices : Byte;
  445. Function DiskFree(Drive: Byte): int64;
  446. Var
  447. MyLock : LongInt;
  448. Inf : pInfoData;
  449. Free : Longint;
  450. myproc : pProcess;
  451. OldWinPtr : Pointer;
  452. Begin
  453. Free := -1;
  454. { Here we stop systemrequesters to appear }
  455. myproc := pProcess(FindTask(nil));
  456. OldWinPtr := myproc^.pr_WindowPtr;
  457. myproc^.pr_WindowPtr := Pointer(-1);
  458. { End of systemrequesterstop }
  459. New(Inf);
  460. MyLock := dosLock(devicenames[deviceids[Drive]],SHARED_LOCK);
  461. If MyLock <> 0 then begin
  462. if Info(MyLock,Inf) <> 0 then begin
  463. Free := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock) -
  464. (Inf^.id_NumBlocksUsed * Inf^.id_BytesPerBlock);
  465. end;
  466. Unlock(MyLock);
  467. end;
  468. Dispose(Inf);
  469. { Restore systemrequesters }
  470. myproc^.pr_WindowPtr := OldWinPtr;
  471. diskfree := Free;
  472. end;
  473. Function DiskSize(Drive: Byte): int64;
  474. Var
  475. MyLock : LongInt;
  476. Inf : pInfoData;
  477. Size : Longint;
  478. myproc : pProcess;
  479. OldWinPtr : Pointer;
  480. Begin
  481. Size := -1;
  482. { Here we stop systemrequesters to appear }
  483. myproc := pProcess(FindTask(nil));
  484. OldWinPtr := myproc^.pr_WindowPtr;
  485. myproc^.pr_WindowPtr := Pointer(-1);
  486. { End of systemrequesterstop }
  487. New(Inf);
  488. MyLock := dosLock(devicenames[deviceids[Drive]],SHARED_LOCK);
  489. If MyLock <> 0 then begin
  490. if Info(MyLock,Inf) <> 0 then begin
  491. Size := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock);
  492. end;
  493. Unlock(MyLock);
  494. end;
  495. Dispose(Inf);
  496. { Restore systemrequesters }
  497. myproc^.pr_WindowPtr := OldWinPtr;
  498. disksize := Size;
  499. end;
  500. procedure FindFirst(const Path: PathStr; Attr: Word; Var f: SearchRec);
  501. var
  502. tmpStr: array[0..255] of Char;
  503. Anchor: PAnchorPath;
  504. Result: LongInt;
  505. begin
  506. tmpStr:=PathConv(path)+#0;
  507. DosError:=0;
  508. new(Anchor);
  509. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  510. Result:=MatchFirst(@tmpStr,Anchor);
  511. f.AnchorPtr:=Anchor;
  512. if Result = ERROR_NO_MORE_ENTRIES then
  513. DosError:=18
  514. else
  515. if Result<>0 then DosError:=3;
  516. if DosError=0 then begin
  517. {-------------------------------------------------------------------}
  518. { Here we fill up the SearchRec attribute, but we also do check }
  519. { something else, if the it does not match the mask we are looking }
  520. { for we should go to the next file or directory. }
  521. {-------------------------------------------------------------------}
  522. with Anchor^.ap_Info do begin
  523. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  524. fib_Date.ds_Minute * 60 +
  525. fib_Date.ds_Tick div 50;
  526. f.attr := 0;
  527. {*------------------------------------*}
  528. {* Determine if is a file or a folder *}
  529. {*------------------------------------*}
  530. if fib_DirEntryType>0 then f.attr:=f.attr OR DIRECTORY;
  531. {*------------------------------------*}
  532. {* Determine if Read only *}
  533. {* Readonly if R flag on and W flag *}
  534. {* off. *}
  535. {* Should we check also that EXEC *}
  536. {* is zero? for read only? *}
  537. {*------------------------------------*}
  538. if ((fib_Protection and FIBF_READ) <> 0) and
  539. ((fib_Protection and FIBF_WRITE) = 0) then f.attr:=f.attr or READONLY;
  540. f.Name := strpas(fib_FileName);
  541. f.Size := fib_Size;
  542. end; { end with }
  543. end;
  544. end;
  545. procedure FindNext(Var f: SearchRec);
  546. var
  547. Result: longint;
  548. Anchor: PAnchorPath;
  549. begin
  550. DosError:=0;
  551. Result:=MatchNext(f.AnchorPtr);
  552. if Result = ERROR_NO_MORE_ENTRIES then
  553. DosError:=18
  554. else
  555. if Result <> 0 then DosError:=3;
  556. if DosError=0 then begin
  557. { Fill up the Searchrec information }
  558. { and also check if the files are with }
  559. { the correct attributes }
  560. Anchor:=pAnchorPath(f.AnchorPtr);
  561. with Anchor^.ap_Info do begin
  562. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  563. fib_Date.ds_Minute * 60 +
  564. fib_Date.ds_Tick div 50;
  565. f.attr := 0;
  566. {*------------------------------------*}
  567. {* Determine if is a file or a folder *}
  568. {*------------------------------------*}
  569. if fib_DirEntryType > 0 then f.attr:=f.attr OR DIRECTORY;
  570. {*------------------------------------*}
  571. {* Determine if Read only *}
  572. {* Readonly if R flag on and W flag *}
  573. {* off. *}
  574. {* Should we check also that EXEC *}
  575. {* is zero? for read only? *}
  576. {*------------------------------------*}
  577. if ((fib_Protection and FIBF_READ) <> 0) and
  578. ((fib_Protection and FIBF_WRITE) = 0) then f.attr:=f.attr or READONLY;
  579. f.Name := strpas(fib_FileName);
  580. f.Size := fib_Size;
  581. end; { end with }
  582. end;
  583. end;
  584. procedure FindClose(Var f: SearchRec);
  585. begin
  586. MatchEnd(f.AnchorPtr);
  587. if assigned(f.AnchorPtr) then
  588. Dispose(PAnchorPath(f.AnchorPtr));
  589. end;
  590. {******************************************************************************
  591. --- File ---
  592. ******************************************************************************}
  593. function FSearch(path: PathStr; dirlist: String) : PathStr;
  594. var
  595. p1 : LongInt;
  596. tmpSR : SearchRec;
  597. newdir : PathStr;
  598. begin
  599. { No wildcards allowed in these things }
  600. if (pos('?',path)<>0) or (pos('*',path)<>0) or (path='') then
  601. FSearch:=''
  602. else begin
  603. repeat
  604. p1:=pos(';',dirlist);
  605. if p1<>0 then begin
  606. newdir:=Copy(dirlist,1,p1-1);
  607. Delete(dirlist,1,p1);
  608. end else begin
  609. newdir:=dirlist;
  610. dirlist:='';
  611. end;
  612. if (newdir<>'') and (not (newdir[length(newdir)] in ['/',':'])) then
  613. newdir:=newdir+'/';
  614. FindFirst(newdir+path,anyfile,tmpSR);
  615. if doserror=0 then
  616. newdir:=newdir+path
  617. else
  618. newdir:='';
  619. until (dirlist='') or (newdir<>'');
  620. FSearch:=newdir;
  621. end;
  622. end;
  623. Procedure getftime (var f; var time : longint);
  624. {
  625. This function returns a file's date and time as the number of
  626. seconds after January 1, 1978 that the file was created.
  627. }
  628. var
  629. FInfo : pFileInfoBlock;
  630. FTime : Longint;
  631. FLock : Longint;
  632. Str : String;
  633. i : integer;
  634. begin
  635. DosError:=0;
  636. FTime := 0;
  637. {$ifdef FPC_ANSI_TEXTFILEREC}
  638. Str := strpas(filerec(f).Name);
  639. {$else}
  640. Str := ToSingleByteFileSystemEncodedFileName(filerec(f).Name);
  641. {$endif}
  642. DoDirSeparators(Str);
  643. FLock := dosLock(Str, SHARED_LOCK);
  644. IF FLock <> 0 then begin
  645. New(FInfo);
  646. if Examine(FLock, FInfo) <> 0 then begin
  647. with FInfo^.fib_Date do
  648. FTime := ds_Days * (24 * 60 * 60) +
  649. ds_Minute * 60 +
  650. ds_Tick div 50;
  651. end else begin
  652. FTime := 0;
  653. end;
  654. Unlock(FLock);
  655. Dispose(FInfo);
  656. end
  657. else
  658. DosError:=6;
  659. time := FTime;
  660. end;
  661. Procedure setftime(var f; time : longint);
  662. var
  663. DateStamp: pDateStamp;
  664. Str: String;
  665. i: Integer;
  666. Days, Minutes,Ticks: longint;
  667. FLock: longint;
  668. Begin
  669. new(DateStamp);
  670. {$ifdef FPC_ANSI_TEXTFILEREC}
  671. Str := strpas(filerec(f).Name);
  672. {$else}
  673. Str := ToSingleByteFileSystemEncodedFileName(filerec(f).Name);
  674. {$endif}
  675. DoDirSeparators(str);
  676. { Check first of all, if file exists }
  677. FLock := dosLock(Str, SHARED_LOCK);
  678. IF FLock <> 0 then
  679. begin
  680. Unlock(FLock);
  681. Amiga2DateStamp(time,Days,Minutes,ticks);
  682. DateStamp^.ds_Days:=Days;
  683. DateStamp^.ds_Minute:=Minutes;
  684. DateStamp^.ds_Tick:=Ticks;
  685. if dosSetFileDate(Str,DateStamp) then
  686. DosError:=0
  687. else
  688. DosError:=6;
  689. end
  690. else
  691. DosError:=2;
  692. if assigned(DateStamp) then Dispose(DateStamp);
  693. End;
  694. procedure getfattr(var f; var attr : word);
  695. var
  696. info : pFileInfoBlock;
  697. MyLock : Longint;
  698. flags: word;
  699. Str: String;
  700. i: integer;
  701. begin
  702. DosError:=0;
  703. flags:=0;
  704. New(info);
  705. {$ifdef FPC_ANSI_TEXTFILEREC}
  706. Str := strpas(filerec(f).Name);
  707. {$else}
  708. Str := ToSingleByteFileSystemEncodedFileName(filerec(f).Name);
  709. {$endif}
  710. DoDirSeparators(str);
  711. { open with shared lock to check if file exists }
  712. MyLock:=dosLock(Str,SHARED_LOCK);
  713. if MyLock <> 0 then
  714. Begin
  715. Examine(MyLock,info);
  716. {*------------------------------------*}
  717. {* Determine if is a file or a folder *}
  718. {*------------------------------------*}
  719. if info^.fib_DirEntryType > 0 then
  720. flags:=flags OR DIRECTORY;
  721. {*------------------------------------*}
  722. {* Determine if Read only *}
  723. {* Readonly if R flag on and W flag *}
  724. {* off. *}
  725. {* Should we check also that EXEC *}
  726. {* is zero? for read only? *}
  727. {*------------------------------------*}
  728. if ((info^.fib_Protection and FIBF_READ) <> 0)
  729. AND ((info^.fib_Protection and FIBF_WRITE) = 0)
  730. then
  731. flags:=flags OR ReadOnly;
  732. Unlock(mylock);
  733. end
  734. else
  735. DosError:=3;
  736. attr:=flags;
  737. Dispose(info);
  738. End;
  739. procedure setfattr(var f; attr : word);
  740. var
  741. flags: longint;
  742. tmpLock : longint;
  743. {$ifndef FPC_ANSI_TEXTFILEREC}
  744. r : rawbytestring;
  745. {$endif not FPC_ANSI_TEXTFILEREC}
  746. p : pchar;
  747. begin
  748. {$ifdef FPC_ANSI_TEXTFILEREC}
  749. p := @filerec(f).Name;
  750. {$else}
  751. r := ToSingleByteFileSystemEncodedFileName(filerec(f).Name);
  752. p := pchar(r);
  753. {$endif}
  754. DosError:=0;
  755. flags:=FIBF_WRITE;
  756. { By default files are read-write }
  757. if attr and ReadOnly <> 0 then flags:=FIBF_READ; { Clear the Fibf_write flags }
  758. { no need for path conversion here, because file opening already }
  759. { converts the path (KB) }
  760. { create a shared lock on the file }
  761. tmpLock:=Lock(p,SHARED_LOCK);
  762. if tmpLock <> 0 then begin
  763. Unlock(tmpLock);
  764. if SetProtection(p,flags) = 0 then DosError:=5;
  765. end else
  766. DosError:=3;
  767. end;
  768. {******************************************************************************
  769. --- Environment ---
  770. ******************************************************************************}
  771. var
  772. strofpaths : string;
  773. function SystemTags(const command: PChar; const tags: array of DWord): LongInt;
  774. begin
  775. SystemTags:=SystemTagList(command,@tags);
  776. end;
  777. function getpathstring: string;
  778. var
  779. f : text;
  780. s : string;
  781. found : boolean;
  782. temp : string[255];
  783. begin
  784. found := true;
  785. temp := '';
  786. { Alternatively, this could use PIPE: handler on systems which
  787. have this by default (not the case on classic Amiga), but then
  788. the child process should be started async, which for a simple
  789. Path command probably isn't worth the trouble. (KB) }
  790. assign(f,'T:'+HexStr(FindTask(nil))+'_path.tmp');
  791. rewrite(f);
  792. { This is a pretty ugly stunt, combining Pascal and Amiga system
  793. functions, but works... }
  794. SystemTags('C:Path',[SYS_Input, 0, SYS_Output, TextRec(f).Handle, TAG_END]);
  795. close(f);
  796. reset(f);
  797. { skip the first line, garbage }
  798. if not eof(f) then readln(f,s);
  799. while not eof(f) do begin
  800. readln(f,s);
  801. if found then begin
  802. temp := s;
  803. found := false;
  804. end else begin
  805. if (length(s) + length(temp)) < 255 then
  806. temp := temp + ';' + s;
  807. end;
  808. end;
  809. close(f);
  810. erase(f);
  811. getpathstring := temp;
  812. end;
  813. var
  814. EnvList: array of record
  815. Name: string;
  816. Local: Boolean;
  817. Value: string;
  818. end;
  819. procedure InitEnvironmentStrings;
  820. Const
  821. BUFFER_SIZE = 254;
  822. Var
  823. ThisProcess: PProcess;
  824. LocalVars_List: PMinList; // Local Var structure in struct process (pr_LocalVarsis is actually a minlist
  825. LocalVar_Node: PLocalVar;
  826. Buffer: array[0..BUFFER_SIZE] of Char; // Buffer to hold a value for GetVar()
  827. TempLen: LongInt; // hold returnlength of GetVar()
  828. // for env: searching
  829. Anchor: TAnchorPath;
  830. Res: Integer;
  831. begin
  832. SetLength(EnvList, 0);
  833. ThisProcess := PProcess(FindTask(nil)); //Get the pointer to our process
  834. LocalVars_List := @(ThisProcess^.pr_LocalVars); //get the list of pr_LocalVars as pointer
  835. LocalVar_Node := pLocalVar(LocalVars_List^.mlh_head); //get the headnode of the LocalVars list
  836. // loop through the localvar list
  837. while ( Pointer(LocalVar_Node^.lv_node.ln_Succ) <> Pointer(LocalVars_List^.mlh_Tail)) do
  838. begin
  839. // make sure the active node is valid instead of empty
  840. If not(LocalVar_Node <> nil) then
  841. break;
  842. { - process the current node - }
  843. If (LocalVar_Node^.lv_node.ln_Type = LV_Var) then
  844. begin
  845. FillChar(Buffer[0], Length(Buffer), #0); // clear Buffer
  846. // get active node's name environment variable value ino buffer and make sure it's local
  847. TempLen := GetVar(LocalVar_Node^.lv_Node.ln_Name, @Buffer[0], BUFFER_SIZE, GVF_LOCAL_ONLY);
  848. If TempLen <> -1 then
  849. begin
  850. SetLength(EnvList, Length(EnvList) + 1);
  851. EnvList[High(EnvList)].Name := LocalVar_Node^.lv_Node.ln_Name;
  852. EnvList[High(EnvList)].Value := string(PChar(@Buffer[0]));
  853. EnvList[High(EnvList)].Local := True;
  854. end;
  855. end;
  856. LocalVar_Node := pLocalVar(LocalVar_Node^.lv_node.ln_Succ); //we need to get the next node
  857. end;
  858. // search in env for all Variables
  859. FillChar(Anchor,sizeof(TAnchorPath),#0);
  860. Res := MatchFirst('ENV:#?', @Anchor);
  861. while Res = 0 do
  862. begin
  863. if Anchor.ap_Info.fib_DirEntryType <= 0 then
  864. begin
  865. SetLength(EnvList, Length(EnvList) + 1);
  866. EnvList[High(EnvList)].Name := Anchor.ap_Info.fib_FileName;
  867. EnvList[High(EnvList)].Value := '';
  868. EnvList[High(EnvList)].Local := False;
  869. end;
  870. Res := MatchNext(@Anchor);
  871. end;
  872. MatchEnd(@Anchor);
  873. // add PATH as Fake Variable:
  874. SetLength(EnvList, Length(EnvList) + 1);
  875. EnvList[High(EnvList)].Name := 'PATH';
  876. EnvList[High(EnvList)].Value := '';
  877. EnvList[High(EnvList)].Local := False;
  878. end;
  879. function EnvCount: Longint;
  880. begin
  881. InitEnvironmentStrings;
  882. EnvCount := Length(EnvList);
  883. end;
  884. function GetEnvFromEnv(envvar : String): String;
  885. var
  886. bufarr : array[0..255] of char;
  887. strbuffer : array[0..255] of char;
  888. temp : Longint;
  889. begin
  890. GetEnvFromEnv := '';
  891. if UpCase(envvar) = 'PATH' then begin
  892. if StrOfpaths = '' then StrOfPaths := GetPathString;
  893. GetEnvFromEnv := StrOfPaths;
  894. end else begin
  895. if (Pos(DriveSeparator,envvar) <> 0) or
  896. (Pos(DirectorySeparator,envvar) <> 0) then exit;
  897. move(envvar[1],strbuffer,length(envvar));
  898. strbuffer[length(envvar)] := #0;
  899. temp := GetVar(strbuffer,bufarr,255,$100);
  900. if temp <> -1 then
  901. GetEnvFromEnv := StrPas(bufarr);
  902. end;
  903. end;
  904. function EnvStr(Index: LongInt): String;
  905. begin
  906. EnvStr := '';
  907. if Length(EnvList) = 0 then
  908. InitEnvironmentStrings;
  909. if (Index >= 0) and (Index <= High(EnvList)) then
  910. begin
  911. if EnvList[Index].Local then
  912. EnvStr := EnvList[Index].Name + '=' + EnvList[Index].Value
  913. else
  914. EnvStr := EnvList[Index].Name + '=' + GetEnvFromEnv(EnvList[Index].Name);
  915. end;
  916. end;
  917. function GetEnv(envvar : String): String;
  918. var
  919. EnvVarName: String;
  920. i: Integer;
  921. begin
  922. GetEnv := '';
  923. EnvVarName := UpCase(EnvVar);
  924. if EnvVarName = 'PATH' then
  925. begin
  926. if StrOfpaths = '' then
  927. StrOfPaths := GetPathString;
  928. GetEnv := StrOfPaths;
  929. end else
  930. begin
  931. InitEnvironmentStrings;
  932. for i := 0 to High(EnvList) do
  933. begin
  934. if EnvVarName = UpCase(EnvList[i].Name) then
  935. begin
  936. if EnvList[i].Local then
  937. GetEnv := EnvList[i].Value
  938. else
  939. GetEnv := GetEnvFromEnv(EnvList[i].Name);
  940. Break;
  941. end;
  942. end;
  943. end;
  944. end;
  945. procedure AddDevice(str : String);
  946. begin
  947. inc(numberofdevices);
  948. deviceids[numberofdevices] := numberofdevices;
  949. devicenames[numberofdevices] := str;
  950. end;
  951. function MakeDeviceName(str : pchar): string;
  952. var
  953. temp : string[20];
  954. begin
  955. temp := strpas(str);
  956. temp := temp + ':';
  957. MakeDeviceName := temp;
  958. end;
  959. function IsInDeviceList(str : string): boolean;
  960. var
  961. i : byte;
  962. theresult : boolean;
  963. begin
  964. theresult := false;
  965. for i := low(not_to_use_devs) to high(not_to_use_devs) do
  966. begin
  967. if str = not_to_use_devs[i] then begin
  968. theresult := true;
  969. break;
  970. end;
  971. end;
  972. IsInDeviceList := theresult;
  973. end;
  974. procedure ReadInDevices;
  975. var
  976. dl : pDosList;
  977. temp : pchar;
  978. str : string[20];
  979. begin
  980. dl := LockDosList(LDF_DEVICES or LDF_READ );
  981. repeat
  982. dl := NextDosEntry(dl,LDF_DEVICES );
  983. if dl <> nil then begin
  984. temp := BSTR2STRING(dl^.dol_Name);
  985. str := MakeDeviceName(temp);
  986. if not IsInDeviceList(str) then
  987. AddDevice(str);
  988. end;
  989. until dl = nil;
  990. UnLockDosList(LDF_DEVICES or LDF_READ );
  991. end;
  992. begin
  993. DosError:=0;
  994. numberofdevices := 0;
  995. StrOfPaths := '';
  996. ReadInDevices;
  997. end.