dos.pp 31 KB

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