dos.pp 31 KB

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