dos.pp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2004 by Karoly Balogh for Genesi S.a.r.l.
  5. Heavily based on the Commodore Amiga/m68k RTL by Nils Sjoholm and
  6. Carl Eric Codere
  7. MorphOS port was done on a free Pegasos II/G4 machine
  8. provided by Genesi S.a.r.l. <www.genesi.lu>
  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 : LongInt): PChar; Inline;
  86. begin
  87. BSTR2STRING:=Pointer(Longint(BADDR(s))+1);
  88. end;
  89. function IsLeapYear(Source : Word) : Boolean;
  90. begin
  91. if (source Mod 400 = 0) or ((source Mod 4 = 0) and (source Mod 100 <> 0)) then
  92. IsLeapYear:=True
  93. else
  94. IsLeapYear:=False;
  95. end;
  96. Procedure Amiga2DateStamp(Date : LongInt; Var TotalDays,Minutes,Ticks: longint);
  97. { Converts a value in seconds past 1978 to a value in AMIGA DateStamp format }
  98. { Taken from SWAG and modified to work with the Amiga format - CEC }
  99. Var
  100. LocalDate : LongInt; Done : Boolean; TotDays : Integer;
  101. Y: Word;
  102. H: Word;
  103. Min: Word;
  104. S : Word;
  105. Begin
  106. Y := 1978; H := 0; Min := 0; S := 0;
  107. TotalDays := 0;
  108. Minutes := 0;
  109. Ticks := 0;
  110. LocalDate := Date;
  111. Done := False;
  112. While Not Done Do
  113. Begin
  114. If LocalDate >= SecsPerYear Then
  115. Begin
  116. Inc(Y,1);
  117. Dec(LocalDate,SecsPerYear);
  118. Inc(TotalDays,DaysPerYear[12]);
  119. End
  120. Else
  121. Done := True;
  122. If (IsLeapYear(Y+1)) And (LocalDate >= SecsPerLeapYear) And
  123. (Not Done) Then
  124. Begin
  125. Inc(Y,1);
  126. Dec(LocalDate,SecsPerLeapYear);
  127. Inc(TotalDays,DaysPerLeapYear[12]);
  128. End;
  129. End; { END WHILE }
  130. Done := False;
  131. TotDays := LocalDate Div SecsPerDay;
  132. { Total number of days }
  133. TotalDays := TotalDays + TotDays;
  134. Dec(LocalDate,TotDays*SecsPerDay);
  135. { Absolute hours since start of day }
  136. H := LocalDate Div SecsPerHour;
  137. { Convert to minutes }
  138. Minutes := H*60;
  139. Dec(LocalDate,(H * SecsPerHour));
  140. { Find the remaining minutes to add }
  141. Min := LocalDate Div SecsPerMinute;
  142. Dec(LocalDate,(Min * SecsPerMinute));
  143. Minutes:=Minutes+Min;
  144. { Find the number of seconds and convert to ticks }
  145. S := LocalDate;
  146. Ticks:=TICKSPERSECOND*S;
  147. End;
  148. function dosSetProtection(const name: string; mask:longint): Boolean;
  149. var
  150. buffer : array[0..255] of Char;
  151. begin
  152. move(name[1],buffer,length(name));
  153. buffer[length(name)]:=#0;
  154. dosSetProtection:=SetProtection(buffer,mask);
  155. end;
  156. function dosSetFileDate(name: string; p : PDateStamp): Boolean;
  157. var buffer : array[0..255] of Char;
  158. begin
  159. move(name[1],buffer,length(name));
  160. buffer[length(name)]:=#0;
  161. dosSetFileDate:=SetFileDate(buffer,p);
  162. end;
  163. {******************************************************************************
  164. --- Info / Date / Time ---
  165. ******************************************************************************}
  166. function DosVersion: Word;
  167. var p: PLibrary;
  168. begin
  169. p:=PLibrary(MOS_DOSBase);
  170. DosVersion:= p^.lib_Version or (p^.lib_Revision shl 8);
  171. end;
  172. { Here are a lot of stuff just for setdate and settime }
  173. var
  174. TimerBase : Pointer;
  175. procedure NewList (list: pList);
  176. begin
  177. with list^ do
  178. begin
  179. lh_Head := pNode(@lh_Tail);
  180. lh_Tail := NIL;
  181. lh_TailPred := pNode(@lh_Head)
  182. end
  183. end;
  184. function CreateExtIO (port: pMsgPort; size: Longint): pIORequest;
  185. var
  186. IOReq: pIORequest;
  187. begin
  188. IOReq := NIL;
  189. if port <> NIL then
  190. begin
  191. IOReq := execAllocMem(size, MEMF_CLEAR or MEMF_PUBLIC);
  192. if IOReq <> NIL then
  193. begin
  194. IOReq^.io_Message.mn_Node.ln_Type := 7;
  195. IOReq^.io_Message.mn_Length := size;
  196. IOReq^.io_Message.mn_ReplyPort := port;
  197. end;
  198. end;
  199. CreateExtIO := IOReq;
  200. end;
  201. procedure DeleteExtIO (ioReq: pIORequest);
  202. begin
  203. if ioReq <> NIL then
  204. begin
  205. ioReq^.io_Message.mn_Node.ln_Type := $FF;
  206. ioReq^.io_Message.mn_ReplyPort := pMsgPort(-1);
  207. ioReq^.io_Device := pDevice(-1);
  208. execFreeMem(ioReq, ioReq^.io_Message.mn_Length);
  209. end
  210. end;
  211. function Createport(name : PChar; pri : longint): pMsgPort;
  212. var
  213. sigbit : ShortInt;
  214. port : pMsgPort;
  215. begin
  216. sigbit := AllocSignal(-1);
  217. if sigbit = -1 then CreatePort := nil;
  218. port := execAllocMem(sizeof(tMsgPort),MEMF_CLEAR or MEMF_PUBLIC);
  219. if port = nil then begin
  220. FreeSignal(sigbit);
  221. CreatePort := nil;
  222. end;
  223. with port^ do begin
  224. if assigned(name) then
  225. mp_Node.ln_Name := name
  226. else mp_Node.ln_Name := nil;
  227. mp_Node.ln_Pri := pri;
  228. mp_Node.ln_Type := 4;
  229. mp_Flags := 0;
  230. mp_SigBit := sigbit;
  231. mp_SigTask := FindTask(nil);
  232. end;
  233. if assigned(name) then AddPort(port)
  234. else NewList(addr(port^.mp_MsgList));
  235. CreatePort := port;
  236. end;
  237. procedure DeletePort (port: pMsgPort);
  238. begin
  239. if port <> NIL then
  240. begin
  241. if port^.mp_Node.ln_Name <> NIL then
  242. RemPort(port);
  243. port^.mp_Node.ln_Type := $FF;
  244. port^.mp_MsgList.lh_Head := pNode(-1);
  245. FreeSignal(port^.mp_SigBit);
  246. execFreeMem(port, sizeof(tMsgPort));
  247. end;
  248. end;
  249. Function Create_Timer(theUnit : longint) : pTimeRequest;
  250. var
  251. Error : longint;
  252. TimerPort : pMsgPort;
  253. TimeReq : pTimeRequest;
  254. begin
  255. TimerPort := CreatePort(Nil, 0);
  256. if TimerPort = Nil then
  257. Create_Timer := Nil;
  258. TimeReq := pTimeRequest(CreateExtIO(TimerPort,sizeof(tTimeRequest)));
  259. if TimeReq = Nil then begin
  260. DeletePort(TimerPort);
  261. Create_Timer := Nil;
  262. end;
  263. Error := OpenDevice(TIMERNAME, theUnit, pIORequest(TimeReq), 0);
  264. if Error <> 0 then begin
  265. DeleteExtIO(pIORequest(TimeReq));
  266. DeletePort(TimerPort);
  267. Create_Timer := Nil;
  268. end;
  269. TimerBase := pointer(TimeReq^.tr_Node.io_Device);
  270. Create_Timer := pTimeRequest(TimeReq);
  271. end;
  272. Procedure Delete_Timer(WhichTimer : pTimeRequest);
  273. var
  274. WhichPort : pMsgPort;
  275. begin
  276. WhichPort := WhichTimer^.tr_Node.io_Message.mn_ReplyPort;
  277. if assigned(WhichTimer) then begin
  278. CloseDevice(pIORequest(WhichTimer));
  279. DeleteExtIO(pIORequest(WhichTimer));
  280. end;
  281. if assigned(WhichPort) then
  282. DeletePort(WhichPort);
  283. end;
  284. function set_new_time(secs, micro : longint): longint;
  285. var
  286. tr : ptimerequest;
  287. begin
  288. tr := create_timer(UNIT_MICROHZ);
  289. { non zero return says error }
  290. if tr = nil then set_new_time := -1;
  291. tr^.tr_time.tv_secs := secs;
  292. tr^.tr_time.tv_micro := micro;
  293. tr^.tr_node.io_Command := TR_SETSYSTIME;
  294. DoIO(pIORequest(tr));
  295. delete_timer(tr);
  296. set_new_time := 0;
  297. end;
  298. function get_sys_time(tv : ptimeval): longint;
  299. var
  300. tr : ptimerequest;
  301. begin
  302. tr := create_timer( UNIT_MICROHZ );
  303. { non zero return says error }
  304. if tr = nil then get_sys_time := -1;
  305. tr^.tr_node.io_Command := TR_GETSYSTIME;
  306. DoIO(pIORequest(tr));
  307. { structure assignment }
  308. tv^ := tr^.tr_time;
  309. delete_timer(tr);
  310. get_sys_time := 0;
  311. end;
  312. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  313. Var
  314. cd : pClockData;
  315. oldtime : ttimeval;
  316. begin
  317. New(cd);
  318. get_sys_time(@oldtime);
  319. Amiga2Date(oldtime.tv_secs,cd);
  320. Year := cd^.year;
  321. Month := cd^.month;
  322. MDay := cd^.mday;
  323. WDay := cd^.wday;
  324. Dispose(cd);
  325. end;
  326. Procedure SetDate(Year, Month, Day: Word);
  327. var
  328. cd : pClockData;
  329. oldtime : ttimeval;
  330. Begin
  331. new(cd);
  332. get_sys_time(@oldtime);
  333. Amiga2Date(oldtime.tv_secs,cd);
  334. cd^.year := Year;
  335. cd^.month := Month;
  336. cd^.mday := Day;
  337. set_new_time(Date2Amiga(cd),0);
  338. dispose(cd);
  339. End;
  340. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  341. Var
  342. cd : pClockData;
  343. oldtime : ttimeval;
  344. begin
  345. New(cd);
  346. get_sys_time(@oldtime);
  347. Amiga2Date(oldtime.tv_secs,cd);
  348. Hour := cd^.hour;
  349. Minute := cd^.min;
  350. Second := cd^.sec;
  351. Sec100 := oldtime.tv_micro div 10000;
  352. Dispose(cd);
  353. END;
  354. Procedure SetTime(Hour, Minute, Second, Sec100: Word);
  355. var
  356. cd : pClockData;
  357. oldtime : ttimeval;
  358. Begin
  359. new(cd);
  360. get_sys_time(@oldtime);
  361. Amiga2Date(oldtime.tv_secs,cd);
  362. cd^.hour := Hour;
  363. cd^.min := Minute;
  364. cd^.sec := Second;
  365. set_new_time(Date2Amiga(cd), Sec100 * 10000);
  366. dispose(cd);
  367. End;
  368. function GetMsCount: int64;
  369. var
  370. TV: TTimeVal;
  371. begin
  372. Get_Sys_Time (@TV);
  373. GetMsCount := TV.TV_Secs * 1000 + TV.TV_Micro div 1000;
  374. end;
  375. {******************************************************************************
  376. --- Exec ---
  377. ******************************************************************************}
  378. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  379. var
  380. p : string;
  381. buf: array[0..255] of char;
  382. result : longint;
  383. MyLock : longint;
  384. i : Integer;
  385. Begin
  386. DosError := 0;
  387. LastdosExitCode := 0;
  388. p:=Path+' '+ComLine;
  389. { allow backslash as slash }
  390. for i:=1 to length(p) do
  391. if p[i]='\' then p[i]:='/';
  392. Move(p[1],buf,length(p));
  393. buf[Length(p)]:=#0;
  394. { Here we must first check if the command we wish to execute }
  395. { actually exists, because this is NOT handled by the }
  396. { _SystemTagList call (program will abort!!) }
  397. { Try to open with shared lock }
  398. MyLock:=dosLock(Path,SHARED_LOCK);
  399. if MyLock <> 0 then
  400. Begin
  401. { File exists - therefore unlock it }
  402. Unlock(MyLock);
  403. result:=SystemTagList(buf,nil);
  404. { on return of -1 the shell could not be executed }
  405. { probably because there was not enough memory }
  406. if result = -1 then
  407. DosError:=8
  408. else
  409. LastDosExitCode:=word(result);
  410. end
  411. else
  412. DosError:=3;
  413. End;
  414. Procedure GetCBreak(Var BreakValue: Boolean);
  415. Begin
  416. breakvalue := system.BreakOn;
  417. End;
  418. Procedure SetCBreak(BreakValue: Boolean);
  419. Begin
  420. system.Breakon := BreakValue;
  421. End;
  422. {******************************************************************************
  423. --- Disk ---
  424. ******************************************************************************}
  425. { How to solve the problem with this: }
  426. { We could walk through the device list }
  427. { at startup to determine possible devices }
  428. const
  429. not_to_use_devs : array[0..12] of string =(
  430. 'DF0:',
  431. 'DF1:',
  432. 'DF2:',
  433. 'DF3:',
  434. 'PED:',
  435. 'PRJ:',
  436. 'PIPE:',
  437. 'RAM:',
  438. 'CON:',
  439. 'RAW:',
  440. 'SER:',
  441. 'PAR:',
  442. 'PRT:');
  443. var
  444. deviceids : array[1..20] of byte;
  445. devicenames : array[1..20] of string[20];
  446. numberofdevices : Byte;
  447. Function DiskFree(Drive: Byte): int64;
  448. Var
  449. MyLock : LongInt;
  450. Inf : pInfoData;
  451. Free : Longint;
  452. myproc : pProcess;
  453. OldWinPtr : Pointer;
  454. Begin
  455. Free := -1;
  456. { Here we stop systemrequesters to appear }
  457. myproc := pProcess(FindTask(nil));
  458. OldWinPtr := myproc^.pr_WindowPtr;
  459. myproc^.pr_WindowPtr := Pointer(-1);
  460. { End of systemrequesterstop }
  461. New(Inf);
  462. MyLock := dosLock(devicenames[deviceids[Drive]],SHARED_LOCK);
  463. If MyLock <> 0 then begin
  464. if Info(MyLock,Inf) then begin
  465. Free := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock) -
  466. (Inf^.id_NumBlocksUsed * Inf^.id_BytesPerBlock);
  467. end;
  468. Unlock(MyLock);
  469. end;
  470. Dispose(Inf);
  471. { Restore systemrequesters }
  472. myproc^.pr_WindowPtr := OldWinPtr;
  473. diskfree := Free;
  474. end;
  475. Function DiskSize(Drive: Byte): int64;
  476. Var
  477. MyLock : LongInt;
  478. Inf : pInfoData;
  479. Size : Longint;
  480. myproc : pProcess;
  481. OldWinPtr : Pointer;
  482. Begin
  483. Size := -1;
  484. { Here we stop systemrequesters to appear }
  485. myproc := pProcess(FindTask(nil));
  486. OldWinPtr := myproc^.pr_WindowPtr;
  487. myproc^.pr_WindowPtr := Pointer(-1);
  488. { End of systemrequesterstop }
  489. New(Inf);
  490. MyLock := dosLock(devicenames[deviceids[Drive]],SHARED_LOCK);
  491. If MyLock <> 0 then begin
  492. if Info(MyLock,Inf) then begin
  493. Size := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock);
  494. end;
  495. Unlock(MyLock);
  496. end;
  497. Dispose(Inf);
  498. { Restore systemrequesters }
  499. myproc^.pr_WindowPtr := OldWinPtr;
  500. disksize := Size;
  501. end;
  502. procedure FindFirst(const Path: PathStr; Attr: Word; Var f: SearchRec);
  503. var
  504. tmpStr: array[0..255] of Char;
  505. Anchor: PAnchorPath;
  506. Result: LongInt;
  507. begin
  508. tmpStr:=PathConv(path)+#0;
  509. DosError:=0;
  510. new(Anchor);
  511. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  512. Result:=MatchFirst(@tmpStr,Anchor);
  513. f.AnchorPtr:=Anchor;
  514. if Result = ERROR_NO_MORE_ENTRIES then
  515. DosError:=18
  516. else
  517. if Result<>0 then DosError:=3;
  518. if DosError=0 then begin
  519. {-------------------------------------------------------------------}
  520. { Here we fill up the SearchRec attribute, but we also do check }
  521. { something else, if the it does not match the mask we are looking }
  522. { for we should go to the next file or directory. }
  523. {-------------------------------------------------------------------}
  524. with Anchor^.ap_Info do begin
  525. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  526. fib_Date.ds_Minute * 60 +
  527. fib_Date.ds_Tick div 50;
  528. {*------------------------------------*}
  529. {* Determine if is a file or a folder *}
  530. {*------------------------------------*}
  531. if fib_DirEntryType>0 then f.attr:=f.attr OR DIRECTORY;
  532. {*------------------------------------*}
  533. {* Determine if Read only *}
  534. {* Readonly if R flag on and W flag *}
  535. {* off. *}
  536. {* Should we check also that EXEC *}
  537. {* is zero? for read only? *}
  538. {*------------------------------------*}
  539. if ((fib_Protection and FIBF_READ) <> 0) and
  540. ((fib_Protection and FIBF_WRITE) = 0) then f.attr:=f.attr or READONLY;
  541. f.Name := strpas(fib_FileName);
  542. f.Size := fib_Size;
  543. end; { end with }
  544. end;
  545. end;
  546. procedure FindNext(Var f: SearchRec);
  547. var
  548. Result: longint;
  549. Anchor: PAnchorPath;
  550. begin
  551. DosError:=0;
  552. Result:=MatchNext(f.AnchorPtr);
  553. if Result = ERROR_NO_MORE_ENTRIES then
  554. DosError:=18
  555. else
  556. if Result <> 0 then DosError:=3;
  557. if DosError=0 then begin
  558. { Fill up the Searchrec information }
  559. { and also check if the files are with }
  560. { the correct attributes }
  561. Anchor:=pAnchorPath(f.AnchorPtr);
  562. with Anchor^.ap_Info do begin
  563. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  564. fib_Date.ds_Minute * 60 +
  565. fib_Date.ds_Tick div 50;
  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. counter: LongInt;
  596. p1 : LongInt;
  597. tmpSR : SearchRec;
  598. newdir : PathStr;
  599. begin
  600. { No wildcards allowed in these things }
  601. if (pos('?',path)<>0) or (pos('*',path)<>0) or (path='') then
  602. FSearch:=''
  603. else begin
  604. repeat
  605. p1:=pos(';',dirlist);
  606. if p1<>0 then begin
  607. newdir:=Copy(dirlist,1,p1-1);
  608. Delete(dirlist,1,p1);
  609. end else begin
  610. newdir:=dirlist;
  611. dirlist:='';
  612. end;
  613. if (newdir<>'') and (not (newdir[length(newdir)] in ['/',':'])) then
  614. newdir:=newdir+'/';
  615. FindFirst(newdir+path,anyfile,tmpSR);
  616. if doserror=0 then
  617. newdir:=newdir+path
  618. else
  619. newdir:='';
  620. until (dirlist='') or (newdir<>'');
  621. FSearch:=newdir;
  622. end;
  623. end;
  624. Procedure getftime (var f; var time : longint);
  625. {
  626. This function returns a file's date and time as the number of
  627. seconds after January 1, 1978 that the file was created.
  628. }
  629. var
  630. FInfo : pFileInfoBlock;
  631. FTime : Longint;
  632. FLock : Longint;
  633. Str : String;
  634. i : integer;
  635. begin
  636. DosError:=0;
  637. FTime := 0;
  638. Str := StrPas(filerec(f).name);
  639. for i:=1 to length(Str) do
  640. if str[i]='\' then str[i]:='/';
  641. FLock := dosLock(Str, SHARED_LOCK);
  642. IF FLock <> 0 then begin
  643. New(FInfo);
  644. if Examine(FLock, FInfo) then begin
  645. with FInfo^.fib_Date do
  646. FTime := ds_Days * (24 * 60 * 60) +
  647. ds_Minute * 60 +
  648. ds_Tick div 50;
  649. end else begin
  650. FTime := 0;
  651. end;
  652. Unlock(FLock);
  653. Dispose(FInfo);
  654. end
  655. else
  656. DosError:=6;
  657. time := FTime;
  658. end;
  659. Procedure setftime(var f; time : longint);
  660. var
  661. DateStamp: pDateStamp;
  662. Str: String;
  663. i: Integer;
  664. Days, Minutes,Ticks: longint;
  665. FLock: longint;
  666. Begin
  667. new(DateStamp);
  668. Str := StrPas(filerec(f).name);
  669. for i:=1 to length(Str) do
  670. if str[i]='\' then str[i]:='/';
  671. { Check first of all, if file exists }
  672. FLock := dosLock(Str, SHARED_LOCK);
  673. IF FLock <> 0 then
  674. begin
  675. Unlock(FLock);
  676. Amiga2DateStamp(time,Days,Minutes,ticks);
  677. DateStamp^.ds_Days:=Days;
  678. DateStamp^.ds_Minute:=Minutes;
  679. DateStamp^.ds_Tick:=Ticks;
  680. if dosSetFileDate(Str,DateStamp) then
  681. DosError:=0
  682. else
  683. DosError:=6;
  684. end
  685. else
  686. DosError:=2;
  687. if assigned(DateStamp) then Dispose(DateStamp);
  688. End;
  689. Procedure getfattr(var f; var attr : word);
  690. var
  691. info : pFileInfoBlock;
  692. MyLock : Longint;
  693. flags: word;
  694. Str: String;
  695. i: integer;
  696. Begin
  697. DosError:=0;
  698. flags:=0;
  699. New(info);
  700. Str := StrPas(filerec(f).name);
  701. for i:=1 to length(Str) do
  702. if str[i]='\' then str[i]:='/';
  703. { open with shared lock to check if file exists }
  704. MyLock:=dosLock(Str,SHARED_LOCK);
  705. if MyLock <> 0 then
  706. Begin
  707. Examine(MyLock,info);
  708. {*------------------------------------*}
  709. {* Determine if is a file or a folder *}
  710. {*------------------------------------*}
  711. if info^.fib_DirEntryType > 0 then
  712. flags:=flags OR DIRECTORY;
  713. {*------------------------------------*}
  714. {* Determine if Read only *}
  715. {* Readonly if R flag on and W flag *}
  716. {* off. *}
  717. {* Should we check also that EXEC *}
  718. {* is zero? for read only? *}
  719. {*------------------------------------*}
  720. if ((info^.fib_Protection and FIBF_READ) <> 0)
  721. AND ((info^.fib_Protection and FIBF_WRITE) = 0)
  722. then
  723. flags:=flags OR ReadOnly;
  724. Unlock(mylock);
  725. end
  726. else
  727. DosError:=3;
  728. attr:=flags;
  729. Dispose(info);
  730. End;
  731. Procedure setfattr (var f;attr : word);
  732. var
  733. flags: longint;
  734. MyLock : longint;
  735. str: string;
  736. i: integer;
  737. Begin
  738. DosError:=0;
  739. flags:=FIBF_WRITE;
  740. { open with shared lock }
  741. Str := StrPas(filerec(f).name);
  742. for i:=1 to length(Str) do
  743. if str[i]='\' then str[i]:='/';
  744. MyLock:=dosLock(Str,SHARED_LOCK);
  745. { By default files are read-write }
  746. if attr AND ReadOnly <> 0 then
  747. { Clear the Fibf_write flags }
  748. flags:=FIBF_READ;
  749. if MyLock <> 0 then
  750. Begin
  751. Unlock(MyLock);
  752. if Not dosSetProtection(Str,flags) then
  753. DosError:=5;
  754. end
  755. else
  756. DosError:=3;
  757. End;
  758. {******************************************************************************
  759. --- Environment ---
  760. ******************************************************************************}
  761. var
  762. StrofPaths : string[255];
  763. function getpathstring: string;
  764. var
  765. f : text;
  766. s : string;
  767. found : boolean;
  768. temp : string[255];
  769. begin
  770. found := true;
  771. temp := '';
  772. assign(f,'ram:makepathstr');
  773. rewrite(f);
  774. writeln(f,'path >ram:temp.lst');
  775. close(f);
  776. exec('c:protect','ram:makepathstr sarwed quiet');
  777. exec('C:execute','ram:makepathstr');
  778. exec('c:delete','ram:makepathstr quiet');
  779. assign(f,'ram:temp.lst');
  780. reset(f);
  781. { skip the first line, garbage }
  782. if not eof(f) then readln(f,s);
  783. while not eof(f) do begin
  784. readln(f,s);
  785. if found then begin
  786. temp := s;
  787. found := false;
  788. end else begin;
  789. if (length(s) + length(temp)) < 255 then
  790. temp := temp + ';' + s;
  791. end;
  792. end;
  793. close(f);
  794. exec('C:delete','ram:temp.lst quiet');
  795. getpathstring := temp;
  796. end;
  797. Function EnvCount: Longint;
  798. { HOW TO GET THIS VALUE: }
  799. { Each time this function is called, we look at the }
  800. { local variables in the Process structure (2.0+) }
  801. { And we also read all files in the ENV: directory }
  802. Begin
  803. EnvCount := 0;
  804. End;
  805. Function EnvStr(Index: LongInt): String;
  806. Begin
  807. EnvStr:='';
  808. End;
  809. function GetEnv(envvar : String): String;
  810. var
  811. bufarr : array[0..255] of char;
  812. strbuffer : array[0..255] of char;
  813. temp : Longint;
  814. begin
  815. if UpCase(envvar) = 'PATH' then begin
  816. if StrOfpaths = '' then StrOfPaths := GetPathString;
  817. GetEnv := StrofPaths;
  818. end else begin
  819. move(envvar[1],strbuffer,length(envvar));
  820. strbuffer[length(envvar)] := #0;
  821. temp := GetVar(strbuffer,bufarr,255,$100);
  822. if temp = -1 then
  823. GetEnv := ''
  824. else GetEnv := StrPas(bufarr);
  825. end;
  826. end;
  827. procedure AddDevice(str : String);
  828. begin
  829. inc(numberofdevices);
  830. deviceids[numberofdevices] := numberofdevices;
  831. devicenames[numberofdevices] := str;
  832. end;
  833. function MakeDeviceName(str : pchar): string;
  834. var
  835. temp : string[20];
  836. begin
  837. temp := strpas(str);
  838. temp := temp + ':';
  839. MakeDeviceName := temp;
  840. end;
  841. function IsInDeviceList(str : string): boolean;
  842. var
  843. i : byte;
  844. theresult : boolean;
  845. begin
  846. theresult := false;
  847. for i := low(not_to_use_devs) to high(not_to_use_devs) do
  848. begin
  849. if str = not_to_use_devs[i] then begin
  850. theresult := true;
  851. break;
  852. end;
  853. end;
  854. IsInDeviceList := theresult;
  855. end;
  856. procedure ReadInDevices;
  857. var
  858. dl : pDosList;
  859. temp : pchar;
  860. str : string[20];
  861. begin
  862. dl := LockDosList(LDF_DEVICES or LDF_READ );
  863. repeat
  864. dl := NextDosEntry(dl,LDF_DEVICES );
  865. if dl <> nil then begin
  866. temp := BSTR2STRING(dl^.dol_Name);
  867. str := MakeDeviceName(temp);
  868. if not IsInDeviceList(str) then
  869. AddDevice(str);
  870. end;
  871. until dl = nil;
  872. UnLockDosList(LDF_DEVICES or LDF_READ );
  873. end;
  874. Begin
  875. DosError:=0;
  876. numberofdevices := 0;
  877. StrOfPaths := '';
  878. ReadInDevices;
  879. End.
  880. {
  881. $Log$
  882. Revision 1.13 2004-12-07 13:35:53 karoly
  883. * more cleanup in FindFirst/FindNext
  884. * implemented FindClose, no more leaking of file locks
  885. Revision 1.12 2004/12/06 20:01:20 karoly
  886. * made it compile again after changes by Tomas
  887. * cleaned up FindFirst mess (still more things to do, as usual)
  888. Revision 1.11 2004/12/05 16:44:43 hajny
  889. * GetMsCount added, platform independent routines moved to single include file
  890. Revision 1.10 2004/11/23 02:57:58 karoly
  891. * Fixed missing $INLINE
  892. Revision 1.9 2004/11/18 22:30:33 karoly
  893. * Some cleanup, leap year calculation fixed
  894. Revision 1.8 2004/10/27 01:31:40 karoly
  895. * GetEnv fixed
  896. Revision 1.7 2004/08/03 15:59:41 karoly
  897. * more cleanup & more includes
  898. Revision 1.6 2004/06/26 20:48:24 karoly
  899. * more cleanup + changes to use new includes
  900. Revision 1.5 2004/06/13 22:51:08 karoly
  901. * cleanup and changes to use new includes
  902. Revision 1.4 2004/05/16 00:24:19 karoly
  903. * some cleanup
  904. Revision 1.3 2004/05/13 00:48:52 karoly
  905. * fixed a typo
  906. Revision 1.2 2004/05/13 00:42:29 karoly
  907. * getpathstring displayed dos messages, fixed
  908. Revision 1.1 2004/05/12 20:27:29 karoly
  909. * first implementation of MorphOS DOS unit, based on Amiga version
  910. }