dos.pp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2004 by Karoly Balogh for Genesi Sarl
  5. Heavily based on the Amiga/m68k RTL by Nils Sjoholm and
  6. Carl Eric Codere
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit Dos;
  14. {--------------------------------------------------------------------}
  15. { LEFT TO DO: }
  16. {--------------------------------------------------------------------}
  17. { o DiskFree / Disksize don't work as expected }
  18. { o Implement EnvCount,EnvStr }
  19. { o FindFirst should only work with correct attributes }
  20. {--------------------------------------------------------------------}
  21. Interface
  22. Const
  23. {Bitmasks for CPU Flags}
  24. fcarry = $0001;
  25. fparity = $0004;
  26. fauxiliary = $0010;
  27. fzero = $0040;
  28. fsign = $0080;
  29. foverflow = $0800;
  30. {Bitmasks for file attribute}
  31. readonly = $01;
  32. hidden = $02;
  33. sysfile = $04;
  34. volumeid = $08;
  35. directory = $10;
  36. archive = $20;
  37. anyfile = $3F;
  38. {File Status}
  39. fmclosed = $D7B0;
  40. fminput = $D7B1;
  41. fmoutput = $D7B2;
  42. fminout = $D7B3;
  43. Type
  44. ComStr = String[255]; { size increased to be more compatible with Unix}
  45. PathStr = String[255]; { size increased to be more compatible with Unix}
  46. DirStr = String[255]; { size increased to be more compatible with Unix}
  47. NameStr = String[255]; { size increased to be more compatible with Unix}
  48. ExtStr = String[255]; { size increased to be more compatible with Unix}
  49. {
  50. filerec.inc contains the definition of the filerec.
  51. textrec.inc contains the definition of the textrec.
  52. It is in a separate file to make it available in other units without
  53. having to use the DOS unit for it.
  54. }
  55. {$i filerec.inc}
  56. {$i textrec.inc}
  57. Type
  58. SearchRec = Packed Record
  59. { watch out this is correctly aligned for all processors }
  60. { don't modify. }
  61. { Replacement for Fill }
  62. {0} AnchorPtr : Pointer; { Pointer to the Anchorpath structure }
  63. {4} Fill: Array[1..15] of Byte; {future use}
  64. {End of replacement for fill}
  65. Attr : BYTE; {attribute of found file}
  66. Time : LongInt; {last modify date of found file}
  67. Size : LongInt; {file size of found file}
  68. Name : String[255]; {name of found file}
  69. End;
  70. DateTime = packed record
  71. Year: Word;
  72. Month: Word;
  73. Day: Word;
  74. Hour: Word;
  75. Min: Word;
  76. Sec: word;
  77. End;
  78. { Some ugly x86 registers... }
  79. registers = packed record
  80. case i : integer of
  81. 0 : (ax,f1,bx,f2,cx,f3,dx,f4,bp,f5,si,f51,di,f6,ds,f7,es,f8,flags,fs,gs : word);
  82. 1 : (al,ah,f9,f10,bl,bh,f11,f12,cl,ch,f13,f14,dl,dh : byte);
  83. 2 : (eax, ebx, ecx, edx, ebp, esi, edi : longint);
  84. end;
  85. Var
  86. DosError : integer;
  87. {Interrupt}
  88. Procedure Intr(intno: byte; var regs: registers);
  89. Procedure MSDos(var regs: registers);
  90. {Info/Date/Time}
  91. Function DosVersion: Word;
  92. Procedure GetDate(var year, month, mday, wday: word);
  93. Procedure GetTime(var hour, minute, second, sec100: word);
  94. procedure SetDate(year,month,day: word);
  95. Procedure SetTime(hour,minute,second,sec100: word);
  96. Procedure UnpackTime(p: longint; var t: datetime);
  97. Procedure PackTime(var t: datetime; var p: longint);
  98. {Exec}
  99. Procedure Exec(const path: pathstr; const comline: comstr);
  100. Function DosExitCode: word;
  101. {Disk}
  102. Function DiskFree(drive: byte) : longint;
  103. Function DiskSize(drive: byte) : longint;
  104. Procedure FindFirst(path: pathstr; attr: word; var f: searchRec);
  105. Procedure FindNext(var f: searchRec);
  106. Procedure FindClose(Var f: SearchRec);
  107. {File}
  108. Procedure GetFAttr(var f; var attr: word);
  109. Procedure GetFTime(var f; var time: longint);
  110. Function FSearch(path: pathstr; dirlist: string): pathstr;
  111. Function FExpand(const path: pathstr): pathstr;
  112. Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
  113. {Environment}
  114. Function EnvCount: longint;
  115. Function EnvStr(index: integer): string;
  116. Function GetEnv(envvar: string): string;
  117. {Misc}
  118. Procedure SetFAttr(var f; attr: word);
  119. Procedure SetFTime(var f; time: longint);
  120. Procedure GetCBreak(var breakvalue: boolean);
  121. Procedure SetCBreak(breakvalue: boolean);
  122. Procedure GetVerify(var verify: boolean);
  123. Procedure SetVerify(verify: boolean);
  124. {Do Nothing Functions}
  125. Procedure SwapVectors;
  126. Procedure GetIntVec(intno: byte; var vector: pointer);
  127. Procedure SetIntVec(intno: byte; vector: pointer);
  128. Procedure Keep(exitcode: word);
  129. implementation
  130. const
  131. DaysPerMonth : Array[1..12] of ShortInt =
  132. (031,028,031,030,031,030,031,031,030,031,030,031);
  133. DaysPerYear : Array[1..12] of Integer =
  134. (031,059,090,120,151,181,212,243,273,304,334,365);
  135. DaysPerLeapYear : Array[1..12] of Integer =
  136. (031,060,091,121,152,182,213,244,274,305,335,366);
  137. SecsPerYear : LongInt = 31536000;
  138. SecsPerLeapYear : LongInt = 31622400;
  139. SecsPerDay : LongInt = 86400;
  140. SecsPerHour : Integer = 3600;
  141. SecsPerMinute : ShortInt = 60;
  142. TICKSPERSECOND = 50;
  143. type
  144. BPTR = Longint;
  145. BSTR = Longint;
  146. const
  147. LDF_READ = 1;
  148. LDF_DEVICES = 4;
  149. ERROR_NO_MORE_ENTRIES = 232;
  150. FIBF_SCRIPT = 64; { program is a script }
  151. FIBF_PURE = 32; { program is reentrant }
  152. FIBF_ARCHIVE = 16; { cleared whenever file is changed }
  153. FIBF_READ = 8; { ignoed by old filesystem }
  154. FIBF_WRITE = 4; { ignored by old filesystem }
  155. FIBF_EXECUTE = 2; { ignored by system, used by shell }
  156. FIBF_DELETE = 1; { prevent file from being deleted }
  157. SHARED_LOCK = -2;
  158. {******************************************************************************
  159. --- Internal routines ---
  160. ******************************************************************************}
  161. function Lock(const name : string;
  162. accessmode : Longint) : BPTR;
  163. var
  164. buffer: Array[0..255] of char;
  165. Begin
  166. move(name[1],buffer,length(name));
  167. buffer[length(name)]:=#0;
  168. lock:=dos_Lock(buffer,accessmode);
  169. end;
  170. FUNCTION BADDR(bval : BPTR): POINTER;
  171. BEGIN
  172. BADDR := POINTER( bval shl 2);
  173. END;
  174. Procedure AmigaToDt(SecsPast: LongInt; Var Dt: DateTime);
  175. var
  176. cd : pClockData;
  177. Begin
  178. New(cd);
  179. util_Amiga2Date(SecsPast,cd);
  180. Dt.sec := cd^.sec;
  181. Dt.min := cd^.min;
  182. Dt.hour := cd^.hour;
  183. Dt.day := cd^.mday;
  184. Dt.month := cd^.month;
  185. Dt.year := cd^.year;
  186. Dispose(cd);
  187. End;
  188. Function DtToAmiga(DT: DateTime): LongInt;
  189. var
  190. cd : pClockData;
  191. temp : Longint;
  192. Begin
  193. New(cd);
  194. cd^.sec := Dt.sec;
  195. cd^.min := Dt.min;
  196. cd^.hour := Dt.hour;
  197. cd^.mday := Dt.day;
  198. cd^.month := Dt.month;
  199. cd^.year := Dt.year;
  200. temp := util_Date2Amiga(cd);
  201. Dispose(cd);
  202. DtToAmiga := temp;
  203. end;
  204. function IsLeapYear(Source : Word) : Boolean;
  205. Begin
  206. {$WARNING FIX ME!!! Leap year calculation is "somewhat" buggy.}
  207. If (Source Mod 4 = 0) Then
  208. IsLeapYear := True
  209. Else
  210. IsLeapYear := False;
  211. End;
  212. Procedure Amiga2DateStamp(Date : LongInt; Var TotalDays,Minutes,Ticks: longint);
  213. { Converts a value in seconds past 1978 to a value in AMIGA DateStamp format }
  214. { Taken from SWAG and modified to work with the Amiga format - CEC }
  215. Var
  216. LocalDate : LongInt; Done : Boolean; TotDays : Integer;
  217. Y: Word;
  218. H: Word;
  219. Min: Word;
  220. S : Word;
  221. Begin
  222. Y := 1978; H := 0; Min := 0; S := 0;
  223. TotalDays := 0;
  224. Minutes := 0;
  225. Ticks := 0;
  226. LocalDate := Date;
  227. Done := False;
  228. While Not Done Do
  229. Begin
  230. If LocalDate >= SecsPerYear Then
  231. Begin
  232. Inc(Y,1);
  233. Dec(LocalDate,SecsPerYear);
  234. Inc(TotalDays,DaysPerYear[12]);
  235. End
  236. Else
  237. Done := True;
  238. If (IsLeapYear(Y+1)) And (LocalDate >= SecsPerLeapYear) And
  239. (Not Done) Then
  240. Begin
  241. Inc(Y,1);
  242. Dec(LocalDate,SecsPerLeapYear);
  243. Inc(TotalDays,DaysPerLeapYear[12]);
  244. End;
  245. End; { END WHILE }
  246. Done := False;
  247. TotDays := LocalDate Div SecsPerDay;
  248. { Total number of days }
  249. TotalDays := TotalDays + TotDays;
  250. Dec(LocalDate,TotDays*SecsPerDay);
  251. { Absolute hours since start of day }
  252. H := LocalDate Div SecsPerHour;
  253. { Convert to minutes }
  254. Minutes := H*60;
  255. Dec(LocalDate,(H * SecsPerHour));
  256. { Find the remaining minutes to add }
  257. Min := LocalDate Div SecsPerMinute;
  258. Dec(LocalDate,(Min * SecsPerMinute));
  259. Minutes:=Minutes+Min;
  260. { Find the number of seconds and convert to ticks }
  261. S := LocalDate;
  262. Ticks:=TICKSPERSECOND*S;
  263. End;
  264. function SetProtection(const name: string; mask:longint): Boolean;
  265. var
  266. buffer : array[0..255] of Char;
  267. begin
  268. move(name[1],buffer,length(name));
  269. buffer[length(name)]:=#0;
  270. SetProtection:=dos_SetProtection(buffer,mask);
  271. end;
  272. function SetFileDate(name: string; p : PDateStamp): Boolean;
  273. var buffer : array[0..255] of Char;
  274. begin
  275. move(name[1],buffer,length(name));
  276. buffer[length(name)]:=#0;
  277. SetFileDate:=dos_SetFileDate(buffer,p);
  278. end;
  279. {******************************************************************************
  280. --- Dos Interrupt ---
  281. ******************************************************************************}
  282. Procedure Intr (intno: byte; var regs: registers);
  283. Begin
  284. { Does not apply to MorphOS - not implemented }
  285. End;
  286. Procedure SwapVectors;
  287. Begin
  288. { Does not apply to MorphOS - Do Nothing }
  289. End;
  290. Procedure msdos(var regs : registers);
  291. Begin
  292. { ! Not implemented in MorphOS ! }
  293. End;
  294. Procedure getintvec(intno : byte;var vector : pointer);
  295. Begin
  296. { ! Not implemented in MorphOS ! }
  297. End;
  298. Procedure setintvec(intno : byte;vector : pointer);
  299. Begin
  300. { ! Not implemented in MorphOS ! }
  301. End;
  302. {******************************************************************************
  303. --- Info / Date / Time ---
  304. ******************************************************************************}
  305. function DosVersion: Word;
  306. var p: PLibrary;
  307. begin
  308. p:=PLibrary(MOS_DOSBase);
  309. DosVersion:= p^.lib_Version or (p^.lib_Revision shl 8);
  310. end;
  311. { Here are a lot of stuff just for setdate and settime }
  312. Const
  313. { unit defintions }
  314. UNIT_MICROHZ = 0;
  315. UNIT_VBLANK = 1;
  316. TIMERNAME : PChar = 'timer.device';
  317. Type
  318. ptimeval = ^ttimeval;
  319. ttimeval = record
  320. tv_secs : longint;
  321. tv_micro : longint;
  322. end;
  323. ptimerequest = ^ttimerequest;
  324. ttimerequest = record
  325. tr_node : tIORequest;
  326. tr_time : ttimeval;
  327. end;
  328. Const
  329. { IO_COMMAND to use for adding a timer }
  330. CMD_NONSTD = 9;
  331. TR_ADDREQUEST = CMD_NONSTD;
  332. TR_GETSYSTIME = CMD_NONSTD + 1;
  333. TR_SETSYSTIME = CMD_NONSTD + 2;
  334. MEMF_PUBLIC = %000000000000000000000001;
  335. MEMF_CLEAR = %000000010000000000000000;
  336. { To use any of the routines below, TimerBase must be set to point
  337. to the timer.device, either by calling CreateTimer or by pulling
  338. the device pointer from a valid TimeRequest, i.e.
  339. TimerBase := TimeRequest.io_Device;
  340. _after_ you have called OpenDevice on the timer.
  341. }
  342. var
  343. TimerBase : Pointer;
  344. procedure NewList (list: pList);
  345. begin
  346. with list^ do
  347. begin
  348. lh_Head := pNode(@lh_Tail);
  349. lh_Tail := NIL;
  350. lh_TailPred := pNode(@lh_Head)
  351. end
  352. end;
  353. function CreateExtIO (port: pMsgPort; size: Longint): pIORequest;
  354. var
  355. IOReq: pIORequest;
  356. begin
  357. IOReq := NIL;
  358. if port <> NIL then
  359. begin
  360. IOReq := exec_AllocMem(size, MEMF_CLEAR or MEMF_PUBLIC);
  361. if IOReq <> NIL then
  362. begin
  363. IOReq^.io_Message.mn_Node.ln_Type := 7;
  364. IOReq^.io_Message.mn_Length := size;
  365. IOReq^.io_Message.mn_ReplyPort := port;
  366. end;
  367. end;
  368. CreateExtIO := IOReq;
  369. end;
  370. procedure DeleteExtIO (ioReq: pIORequest);
  371. begin
  372. if ioReq <> NIL then
  373. begin
  374. ioReq^.io_Message.mn_Node.ln_Type := $FF;
  375. ioReq^.io_Message.mn_ReplyPort := pMsgPort(-1);
  376. ioReq^.io_Device := pDevice(-1);
  377. exec_FreeMem(ioReq, ioReq^.io_Message.mn_Length);
  378. end
  379. end;
  380. function Createport(name : PChar; pri : longint): pMsgPort;
  381. var
  382. sigbit : ShortInt;
  383. port : pMsgPort;
  384. begin
  385. sigbit := exec_AllocSignal(-1);
  386. if sigbit = -1 then CreatePort := nil;
  387. port := exec_Allocmem(sizeof(tMsgPort),MEMF_CLEAR or MEMF_PUBLIC);
  388. if port = nil then begin
  389. exec_FreeSignal(sigbit);
  390. CreatePort := nil;
  391. end;
  392. with port^ do begin
  393. if assigned(name) then
  394. mp_Node.ln_Name := name
  395. else mp_Node.ln_Name := nil;
  396. mp_Node.ln_Pri := pri;
  397. mp_Node.ln_Type := 4;
  398. mp_Flags := 0;
  399. mp_SigBit := sigbit;
  400. mp_SigTask := exec_FindTask(nil);
  401. end;
  402. if assigned(name) then exec_AddPort(port)
  403. else NewList(addr(port^.mp_MsgList));
  404. CreatePort := port;
  405. end;
  406. procedure DeletePort (port: pMsgPort);
  407. begin
  408. if port <> NIL then
  409. begin
  410. if port^.mp_Node.ln_Name <> NIL then
  411. exec_RemPort(port);
  412. port^.mp_Node.ln_Type := $FF;
  413. port^.mp_MsgList.lh_Head := pNode(-1);
  414. exec_FreeSignal(port^.mp_SigBit);
  415. exec_FreeMem(port, sizeof(tMsgPort));
  416. end;
  417. end;
  418. Function Create_Timer(theUnit : longint) : pTimeRequest;
  419. var
  420. Error : longint;
  421. TimerPort : pMsgPort;
  422. TimeReq : pTimeRequest;
  423. begin
  424. TimerPort := CreatePort(Nil, 0);
  425. if TimerPort = Nil then
  426. Create_Timer := Nil;
  427. TimeReq := pTimeRequest(CreateExtIO(TimerPort,sizeof(tTimeRequest)));
  428. if TimeReq = Nil then begin
  429. DeletePort(TimerPort);
  430. Create_Timer := Nil;
  431. end;
  432. Error := exec_OpenDevice(TIMERNAME, theUnit, pIORequest(TimeReq), 0);
  433. if Error <> 0 then begin
  434. DeleteExtIO(pIORequest(TimeReq));
  435. DeletePort(TimerPort);
  436. Create_Timer := Nil;
  437. end;
  438. TimerBase := pointer(TimeReq^.tr_Node.io_Device);
  439. Create_Timer := pTimeRequest(TimeReq);
  440. end;
  441. Procedure Delete_Timer(WhichTimer : pTimeRequest);
  442. var
  443. WhichPort : pMsgPort;
  444. begin
  445. WhichPort := WhichTimer^.tr_Node.io_Message.mn_ReplyPort;
  446. if assigned(WhichTimer) then begin
  447. exec_CloseDevice(pIORequest(WhichTimer));
  448. DeleteExtIO(pIORequest(WhichTimer));
  449. end;
  450. if assigned(WhichPort) then
  451. DeletePort(WhichPort);
  452. end;
  453. function set_new_time(secs, micro : longint): longint;
  454. var
  455. tr : ptimerequest;
  456. begin
  457. tr := create_timer(UNIT_MICROHZ);
  458. { non zero return says error }
  459. if tr = nil then set_new_time := -1;
  460. tr^.tr_time.tv_secs := secs;
  461. tr^.tr_time.tv_micro := micro;
  462. tr^.tr_node.io_Command := TR_SETSYSTIME;
  463. exec_DoIO(pIORequest(tr));
  464. delete_timer(tr);
  465. set_new_time := 0;
  466. end;
  467. function get_sys_time(tv : ptimeval): longint;
  468. var
  469. tr : ptimerequest;
  470. begin
  471. tr := create_timer( UNIT_MICROHZ );
  472. { non zero return says error }
  473. if tr = nil then get_sys_time := -1;
  474. tr^.tr_node.io_Command := TR_GETSYSTIME;
  475. exec_DoIO(pIORequest(tr));
  476. { structure assignment }
  477. tv^ := tr^.tr_time;
  478. delete_timer(tr);
  479. get_sys_time := 0;
  480. end;
  481. Procedure GetDate(Var Year, Month, MDay, WDay: Word);
  482. Var
  483. cd : pClockData;
  484. oldtime : ttimeval;
  485. begin
  486. New(cd);
  487. get_sys_time(@oldtime);
  488. util_Amiga2Date(oldtime.tv_secs,cd);
  489. Year := cd^.year;
  490. Month := cd^.month;
  491. MDay := cd^.mday;
  492. WDay := cd^.wday;
  493. Dispose(cd);
  494. end;
  495. Procedure SetDate(Year, Month, Day: Word);
  496. var
  497. cd : pClockData;
  498. oldtime : ttimeval;
  499. Begin
  500. new(cd);
  501. get_sys_time(@oldtime);
  502. util_Amiga2Date(oldtime.tv_secs,cd);
  503. cd^.year := Year;
  504. cd^.month := Month;
  505. cd^.mday := Day;
  506. set_new_time(util_Date2Amiga(cd),0);
  507. dispose(cd);
  508. End;
  509. Procedure GetTime(Var Hour, Minute, Second, Sec100: Word);
  510. Var
  511. cd : pClockData;
  512. oldtime : ttimeval;
  513. begin
  514. New(cd);
  515. get_sys_time(@oldtime);
  516. util_Amiga2Date(oldtime.tv_secs,cd);
  517. Hour := cd^.hour;
  518. Minute := cd^.min;
  519. Second := cd^.sec;
  520. Sec100 := oldtime.tv_micro div 10000;
  521. Dispose(cd);
  522. END;
  523. Procedure SetTime(Hour, Minute, Second, Sec100: Word);
  524. var
  525. cd : pClockData;
  526. oldtime : ttimeval;
  527. Begin
  528. new(cd);
  529. get_sys_time(@oldtime);
  530. util_Amiga2Date(oldtime.tv_secs,cd);
  531. cd^.hour := Hour;
  532. cd^.min := Minute;
  533. cd^.sec := Second;
  534. set_new_time(util_Date2Amiga(cd), Sec100 * 10000);
  535. dispose(cd);
  536. End;
  537. Procedure unpacktime(p : longint;var t : datetime);
  538. Begin
  539. AmigaToDt(p,t);
  540. End;
  541. Procedure packtime(var t : datetime;var p : longint);
  542. Begin
  543. p := DtToAmiga(t);
  544. end;
  545. {******************************************************************************
  546. --- Exec ---
  547. ******************************************************************************}
  548. Var
  549. LastDosExitCode: word;
  550. Ver : Boolean;
  551. Procedure Exec (Const Path: PathStr; Const ComLine: ComStr);
  552. var
  553. p : string;
  554. buf: array[0..255] of char;
  555. result : longint;
  556. MyLock : longint;
  557. i : Integer;
  558. Begin
  559. DosError := 0;
  560. LastdosExitCode := 0;
  561. p:=Path+' '+ComLine;
  562. { allow backslash as slash }
  563. for i:=1 to length(p) do
  564. if p[i]='\' then p[i]:='/';
  565. Move(p[1],buf,length(p));
  566. buf[Length(p)]:=#0;
  567. { Here we must first check if the command we wish to execute }
  568. { actually exists, because this is NOT handled by the }
  569. { _SystemTagList call (program will abort!!) }
  570. { Try to open with shared lock }
  571. MyLock:=Lock(Path,SHARED_LOCK);
  572. if MyLock <> 0 then
  573. Begin
  574. { File exists - therefore unlock it }
  575. dos_Unlock(MyLock);
  576. result:=dos_SystemTagList(buf,nil);
  577. { on return of -1 the shell could not be executed }
  578. { probably because there was not enough memory }
  579. if result = -1 then
  580. DosError:=8
  581. else
  582. LastDosExitCode:=word(result);
  583. end
  584. else
  585. DosError:=3;
  586. End;
  587. Function DosExitCode: Word;
  588. Begin
  589. DosExitCode:=LastdosExitCode;
  590. End;
  591. Procedure GetCBreak(Var BreakValue: Boolean);
  592. Begin
  593. breakvalue := system.BreakOn;
  594. End;
  595. Procedure SetCBreak(BreakValue: Boolean);
  596. Begin
  597. system.Breakon := BreakValue;
  598. End;
  599. Procedure GetVerify(Var Verify: Boolean);
  600. Begin
  601. verify:=ver;
  602. End;
  603. Procedure SetVerify(Verify: Boolean);
  604. Begin
  605. ver:=Verify;
  606. End;
  607. {******************************************************************************
  608. --- Disk ---
  609. ******************************************************************************}
  610. { How to solve the problem with this: }
  611. { We could walk through the device list }
  612. { at startup to determine possible devices }
  613. const
  614. not_to_use_devs : array[0..12] of string =(
  615. 'DF0:',
  616. 'DF1:',
  617. 'DF2:',
  618. 'DF3:',
  619. 'PED:',
  620. 'PRJ:',
  621. 'PIPE:',
  622. 'RAM:',
  623. 'CON:',
  624. 'RAW:',
  625. 'SER:',
  626. 'PAR:',
  627. 'PRT:');
  628. var
  629. deviceids : array[1..20] of byte;
  630. devicenames : array[1..20] of string[20];
  631. numberofdevices : Byte;
  632. Function DiskFree(Drive: Byte): Longint;
  633. Var
  634. MyLock : BPTR;
  635. Inf : pInfoData;
  636. Free : Longint;
  637. myproc : pProcess;
  638. OldWinPtr : Pointer;
  639. Begin
  640. Free := -1;
  641. { Here we stop systemrequesters to appear }
  642. myproc := pProcess(exec_FindTask(nil));
  643. OldWinPtr := myproc^.pr_WindowPtr;
  644. myproc^.pr_WindowPtr := Pointer(-1);
  645. { End of systemrequesterstop }
  646. New(Inf);
  647. MyLock := Lock(devicenames[deviceids[Drive]],SHARED_LOCK);
  648. If MyLock <> 0 then begin
  649. if dos_Info(MyLock,Inf) then begin
  650. Free := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock) -
  651. (Inf^.id_NumBlocksUsed * Inf^.id_BytesPerBlock);
  652. end;
  653. dos_Unlock(MyLock);
  654. end;
  655. Dispose(Inf);
  656. { Restore systemrequesters }
  657. myproc^.pr_WindowPtr := OldWinPtr;
  658. diskfree := Free;
  659. end;
  660. Function DiskSize(Drive: Byte): Longint;
  661. Var
  662. MyLock : BPTR;
  663. Inf : pInfoData;
  664. Size : Longint;
  665. myproc : pProcess;
  666. OldWinPtr : Pointer;
  667. Begin
  668. Size := -1;
  669. { Here we stop systemrequesters to appear }
  670. myproc := pProcess(exec_FindTask(nil));
  671. OldWinPtr := myproc^.pr_WindowPtr;
  672. myproc^.pr_WindowPtr := Pointer(-1);
  673. { End of systemrequesterstop }
  674. New(Inf);
  675. MyLock := Lock(devicenames[deviceids[Drive]],SHARED_LOCK);
  676. If MyLock <> 0 then begin
  677. if dos_Info(MyLock,Inf) then begin
  678. Size := (Inf^.id_NumBlocks * Inf^.id_BytesPerBlock);
  679. end;
  680. dos_Unlock(MyLock);
  681. end;
  682. Dispose(Inf);
  683. { Restore systemrequesters }
  684. myproc^.pr_WindowPtr := OldWinPtr;
  685. disksize := Size;
  686. end;
  687. Procedure FindFirst(Path: PathStr; Attr: Word; Var f: SearchRec);
  688. var
  689. buf: Array[0..255] of char;
  690. Anchor : pAnchorPath;
  691. Result : Longint;
  692. index : Integer;
  693. s : string;
  694. j : integer;
  695. Begin
  696. DosError:=0;
  697. New(Anchor);
  698. {----- allow backslash as slash -----}
  699. for index:=1 to length(path) do
  700. if path[index]='\' then path[index]:='/';
  701. { remove any dot characters and replace by their current }
  702. { directory equivalent. }
  703. if pos('../',path) = 1 then
  704. begin
  705. getdir(0,s);
  706. while pos('../',path) = 1 do
  707. { look for parent directory }
  708. Begin
  709. delete(path,1,3);
  710. j:=length(s);
  711. while (s[j] <> '/') AND (s[j] <> ':') AND (j > 0 ) do
  712. dec(j);
  713. if j > 0 then
  714. s:=copy(s,1,j-1);
  715. end;
  716. if (length(s) <> 0) and (s[length(s)] <> ':') then
  717. s:=s + '/';
  718. path:=s+path;
  719. end
  720. else
  721. if pos('./',path) = 1 then
  722. { look for current directory }
  723. Begin
  724. delete(path,1,2);
  725. getdir(0,s);
  726. if (s[length(s)] <> '/') and (s[length(s)] <> ':') then
  727. s:=s+'/';
  728. path:=s+path;
  729. end;
  730. {----- replace * by #? AmigaOs strings -----}
  731. repeat
  732. index:= pos('*',Path);
  733. if index <> 0 then
  734. Begin
  735. delete(Path,index,1);
  736. insert('#?',Path,index);
  737. end;
  738. until index =0;
  739. {--------------------------------------------}
  740. FillChar(Anchor^,sizeof(TAnchorPath),#0);
  741. move(path[1],buf,length(path));
  742. buf[length(path)]:=#0;
  743. Result:=dos_MatchFirst(@buf,Anchor);
  744. f.AnchorPtr:=Anchor;
  745. if Result = ERROR_NO_MORE_ENTRIES then
  746. DosError:=18
  747. else
  748. if Result <> 0 then
  749. DosError:=3;
  750. { If there is an error, deallocate }
  751. { the anchorpath structure }
  752. if DosError <> 0 then
  753. Begin
  754. dos_MatchEnd(Anchor);
  755. if assigned(Anchor) then
  756. Dispose(Anchor);
  757. end
  758. else
  759. {-------------------------------------------------------------------}
  760. { Here we fill up the SearchRec attribute, but we also do check }
  761. { something else, if the it does not match the mask we are looking }
  762. { for we should go to the next file or directory. }
  763. {-------------------------------------------------------------------}
  764. Begin
  765. with Anchor^.ap_Info do
  766. Begin
  767. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  768. fib_Date.ds_Minute * 60 +
  769. fib_Date.ds_Tick div 50;
  770. {*------------------------------------*}
  771. {* Determine if is a file or a folder *}
  772. {*------------------------------------*}
  773. if fib_DirEntryType > 0 then
  774. f.attr:=f.attr OR DIRECTORY;
  775. {*------------------------------------*}
  776. {* Determine if Read only *}
  777. {* Readonly if R flag on and W flag *}
  778. {* off. *}
  779. {* Should we check also that EXEC *}
  780. {* is zero? for read only? *}
  781. {*------------------------------------*}
  782. if ((fib_Protection and FIBF_READ) <> 0)
  783. AND ((fib_Protection and FIBF_WRITE) = 0)
  784. then
  785. f.attr:=f.attr or READONLY;
  786. f.Name := strpas(fib_FileName);
  787. f.Size := fib_Size;
  788. end; { end with }
  789. end;
  790. End;
  791. Procedure FindNext(Var f: SearchRec);
  792. var
  793. Result: longint;
  794. Anchor : pAnchorPath;
  795. Begin
  796. DosError:=0;
  797. Result:=dos_MatchNext(f.AnchorPtr);
  798. if Result = ERROR_NO_MORE_ENTRIES then
  799. DosError:=18
  800. else
  801. if Result <> 0 then
  802. DosError:=3;
  803. { If there is an error, deallocate }
  804. { the anchorpath structure }
  805. if DosError <> 0 then
  806. Begin
  807. dos_MatchEnd(f.AnchorPtr);
  808. if assigned(f.AnchorPtr) then
  809. {Dispose}FreeMem(f.AnchorPtr);
  810. end
  811. else
  812. { Fill up the Searchrec information }
  813. { and also check if the files are with }
  814. { the correct attributes }
  815. Begin
  816. Anchor:=pAnchorPath(f.AnchorPtr);
  817. with Anchor^.ap_Info do
  818. Begin
  819. f.Time := fib_Date.ds_Days * (24 * 60 * 60) +
  820. fib_Date.ds_Minute * 60 +
  821. fib_Date.ds_Tick div 50;
  822. {*------------------------------------*}
  823. {* Determine if is a file or a folder *}
  824. {*------------------------------------*}
  825. if fib_DirEntryType > 0 then
  826. f.attr:=f.attr OR DIRECTORY;
  827. {*------------------------------------*}
  828. {* Determine if Read only *}
  829. {* Readonly if R flag on and W flag *}
  830. {* off. *}
  831. {* Should we check also that EXEC *}
  832. {* is zero? for read only? *}
  833. {*------------------------------------*}
  834. if ((fib_Protection and FIBF_READ) <> 0)
  835. AND ((fib_Protection and FIBF_WRITE) = 0)
  836. then
  837. f.attr:=f.attr or READONLY;
  838. f.Name := strpas(fib_FileName);
  839. f.Size := fib_Size;
  840. end; { end with }
  841. end;
  842. End;
  843. Procedure FindClose(Var f: SearchRec);
  844. begin
  845. end;
  846. {******************************************************************************
  847. --- File ---
  848. ******************************************************************************}
  849. Procedure FSplit(path: pathstr; var dir: dirstr; var name: namestr; var ext: extstr);
  850. var
  851. I: Word;
  852. begin
  853. { allow backslash as slash }
  854. for i:=1 to length(path) do
  855. if path[i]='\' then path[i]:='/';
  856. I := Length(Path);
  857. while (I > 0) and not ((Path[I] = '/') or (Path[I] = ':'))
  858. do Dec(I);
  859. if Path[I] = '/' then
  860. dir := Copy(Path, 0, I)
  861. else dir := Copy(Path,0,I);
  862. if Length(Path) > Length(dir) then
  863. name := Copy(Path, I + 1, Length(Path)-I)
  864. else
  865. name := '';
  866. { Remove extension }
  867. if pos('.',name) <> 0 then
  868. begin
  869. ext:=copy(name,pos('.',name),length(name));
  870. delete(name,pos('.',name),length(name));
  871. end
  872. else
  873. ext := '';
  874. end;
  875. {$DEFINE FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
  876. {$DEFINE FPC_FEXPAND_DRIVESEP_IS_ROOT}
  877. {$DEFINE FPC_FEXPAND_NO_DEFAULT_PATHS}
  878. {$I fexpand.inc}
  879. {$UNDEF FPC_FEXPAND_VOLUMES} (* Full paths begin with drive specification *)
  880. {$UNDEF FPC_FEXPAND_DRIVESEP_IS_ROOT}
  881. {$UNDEF FPC_FEXPAND_NO_DEFAULT_PATHS}
  882. Function fsearch(path : pathstr;dirlist : string) : pathstr;
  883. var
  884. i,p1 : longint;
  885. s : searchrec;
  886. newdir : pathstr;
  887. begin
  888. { No wildcards allowed in these things }
  889. if (pos('?',path)<>0) or (pos('*',path)<>0) then
  890. fsearch:=''
  891. else
  892. begin
  893. { allow slash as backslash }
  894. for i:=1 to length(dirlist) do
  895. if dirlist[i]='\' then dirlist[i]:='/';
  896. repeat
  897. p1:=pos(';',dirlist);
  898. if p1<>0 then
  899. begin
  900. newdir:=copy(dirlist,1,p1-1);
  901. delete(dirlist,1,p1);
  902. end
  903. else
  904. begin
  905. newdir:=dirlist;
  906. dirlist:='';
  907. end;
  908. if (newdir<>'') and (not (newdir[length(newdir)] in ['/',':'])) then
  909. newdir:=newdir+'/';
  910. findfirst(newdir+path,anyfile,s);
  911. if doserror=0 then
  912. newdir:=newdir+path
  913. else
  914. newdir:='';
  915. until (dirlist='') or (newdir<>'');
  916. fsearch:=newdir;
  917. end;
  918. end;
  919. Procedure getftime (var f; var time : longint);
  920. {
  921. This function returns a file's date and time as the number of
  922. seconds after January 1, 1978 that the file was created.
  923. }
  924. var
  925. FInfo : pFileInfoBlock;
  926. FTime : Longint;
  927. FLock : Longint;
  928. Str : String;
  929. i : integer;
  930. begin
  931. DosError:=0;
  932. FTime := 0;
  933. Str := StrPas(filerec(f).name);
  934. for i:=1 to length(Str) do
  935. if str[i]='\' then str[i]:='/';
  936. FLock := Lock(Str, SHARED_LOCK);
  937. IF FLock <> 0 then begin
  938. New(FInfo);
  939. if dos_Examine(FLock, FInfo) then begin
  940. with FInfo^.fib_Date do
  941. FTime := ds_Days * (24 * 60 * 60) +
  942. ds_Minute * 60 +
  943. ds_Tick div 50;
  944. end else begin
  945. FTime := 0;
  946. end;
  947. dos_Unlock(FLock);
  948. Dispose(FInfo);
  949. end
  950. else
  951. DosError:=6;
  952. time := FTime;
  953. end;
  954. Procedure setftime(var f; time : longint);
  955. var
  956. DateStamp: pDateStamp;
  957. Str: String;
  958. i: Integer;
  959. Days, Minutes,Ticks: longint;
  960. FLock: longint;
  961. Begin
  962. new(DateStamp);
  963. Str := StrPas(filerec(f).name);
  964. for i:=1 to length(Str) do
  965. if str[i]='\' then str[i]:='/';
  966. { Check first of all, if file exists }
  967. FLock := Lock(Str, SHARED_LOCK);
  968. IF FLock <> 0 then
  969. begin
  970. dos_Unlock(FLock);
  971. Amiga2DateStamp(time,Days,Minutes,ticks);
  972. DateStamp^.ds_Days:=Days;
  973. DateStamp^.ds_Minute:=Minutes;
  974. DateStamp^.ds_Tick:=Ticks;
  975. if SetFileDate(Str,DateStamp) then
  976. DosError:=0
  977. else
  978. DosError:=6;
  979. end
  980. else
  981. DosError:=2;
  982. if assigned(DateStamp) then Dispose(DateStamp);
  983. End;
  984. Procedure getfattr(var f; var attr : word);
  985. var
  986. info : pFileInfoBlock;
  987. MyLock : Longint;
  988. flags: word;
  989. Str: String;
  990. i: integer;
  991. Begin
  992. DosError:=0;
  993. flags:=0;
  994. New(info);
  995. Str := StrPas(filerec(f).name);
  996. for i:=1 to length(Str) do
  997. if str[i]='\' then str[i]:='/';
  998. { open with shared lock to check if file exists }
  999. MyLock:=Lock(Str,SHARED_LOCK);
  1000. if MyLock <> 0 then
  1001. Begin
  1002. dos_Examine(MyLock,info);
  1003. {*------------------------------------*}
  1004. {* Determine if is a file or a folder *}
  1005. {*------------------------------------*}
  1006. if info^.fib_DirEntryType > 0 then
  1007. flags:=flags OR DIRECTORY;
  1008. {*------------------------------------*}
  1009. {* Determine if Read only *}
  1010. {* Readonly if R flag on and W flag *}
  1011. {* off. *}
  1012. {* Should we check also that EXEC *}
  1013. {* is zero? for read only? *}
  1014. {*------------------------------------*}
  1015. if ((info^.fib_Protection and FIBF_READ) <> 0)
  1016. AND ((info^.fib_Protection and FIBF_WRITE) = 0)
  1017. then
  1018. flags:=flags OR ReadOnly;
  1019. dos_Unlock(mylock);
  1020. end
  1021. else
  1022. DosError:=3;
  1023. attr:=flags;
  1024. Dispose(info);
  1025. End;
  1026. Procedure setfattr (var f;attr : word);
  1027. var
  1028. flags: longint;
  1029. MyLock : longint;
  1030. str: string;
  1031. i: integer;
  1032. Begin
  1033. DosError:=0;
  1034. flags:=FIBF_WRITE;
  1035. { open with shared lock }
  1036. Str := StrPas(filerec(f).name);
  1037. for i:=1 to length(Str) do
  1038. if str[i]='\' then str[i]:='/';
  1039. MyLock:=Lock(Str,SHARED_LOCK);
  1040. { By default files are read-write }
  1041. if attr AND ReadOnly <> 0 then
  1042. { Clear the Fibf_write flags }
  1043. flags:=FIBF_READ;
  1044. if MyLock <> 0 then
  1045. Begin
  1046. dos_Unlock(MyLock);
  1047. if Not SetProtection(Str,flags) then
  1048. DosError:=5;
  1049. end
  1050. else
  1051. DosError:=3;
  1052. End;
  1053. {******************************************************************************
  1054. --- Environment ---
  1055. ******************************************************************************}
  1056. var
  1057. StrofPaths : string[255];
  1058. function getpathstring: string;
  1059. var
  1060. f : text;
  1061. s : string;
  1062. found : boolean;
  1063. temp : string[255];
  1064. begin
  1065. found := true;
  1066. temp := '';
  1067. assign(f,'ram:makepathstr');
  1068. rewrite(f);
  1069. writeln(f,'path >ram:temp.lst');
  1070. close(f);
  1071. exec('c:protect','ram:makepathstr sarwed');
  1072. exec('C:execute','ram:makepathstr');
  1073. exec('c:delete','ram:makepathstr quiet');
  1074. assign(f,'ram:temp.lst');
  1075. reset(f);
  1076. { skip the first line, garbage }
  1077. if not eof(f) then readln(f,s);
  1078. while not eof(f) do begin
  1079. readln(f,s);
  1080. if found then begin
  1081. temp := s;
  1082. found := false;
  1083. end else begin;
  1084. if (length(s) + length(temp)) < 255 then
  1085. temp := temp + ';' + s;
  1086. end;
  1087. end;
  1088. close(f);
  1089. exec('C:delete','ram:temp.lst quiet');
  1090. getpathstring := temp;
  1091. end;
  1092. Function EnvCount: Longint;
  1093. { HOW TO GET THIS VALUE: }
  1094. { Each time this function is called, we look at the }
  1095. { local variables in the Process structure (2.0+) }
  1096. { And we also read all files in the ENV: directory }
  1097. Begin
  1098. EnvCount := 0;
  1099. End;
  1100. Function EnvStr(Index: Integer): String;
  1101. Begin
  1102. EnvStr:='';
  1103. End;
  1104. function GetEnv(envvar : String): String;
  1105. var
  1106. bufarr : array[0..255] of char;
  1107. strbuffer : array[0..255] of char;
  1108. temp : Longint;
  1109. begin
  1110. if UpCase(envvar) = 'PATH' then begin
  1111. if StrOfpaths = '' then StrOfPaths := GetPathString;
  1112. GetEnv := StrofPaths;
  1113. end else begin
  1114. move(envvar,strbuffer,length(envvar));
  1115. strbuffer[length(envvar)] := #0;
  1116. temp := dos_GetVar(strbuffer,bufarr,255,$100);
  1117. if temp = -1 then
  1118. GetEnv := ''
  1119. else GetEnv := StrPas(bufarr);
  1120. end;
  1121. end;
  1122. {******************************************************************************
  1123. --- Not Supported ---
  1124. ******************************************************************************}
  1125. Procedure keep(exitcode : word);
  1126. Begin
  1127. { ! Not implemented in Linux ! }
  1128. End;
  1129. procedure AddDevice(str : String);
  1130. begin
  1131. inc(numberofdevices);
  1132. deviceids[numberofdevices] := numberofdevices;
  1133. devicenames[numberofdevices] := str;
  1134. end;
  1135. function MakeDeviceName(str : pchar): string;
  1136. var
  1137. temp : string[20];
  1138. begin
  1139. temp := strpas(str);
  1140. temp := temp + ':';
  1141. MakeDeviceName := temp;
  1142. end;
  1143. function IsInDeviceList(str : string): boolean;
  1144. var
  1145. i : byte;
  1146. theresult : boolean;
  1147. begin
  1148. theresult := false;
  1149. for i := low(not_to_use_devs) to high(not_to_use_devs) do
  1150. begin
  1151. if str = not_to_use_devs[i] then begin
  1152. theresult := true;
  1153. break;
  1154. end;
  1155. end;
  1156. IsInDeviceList := theresult;
  1157. end;
  1158. function BSTR2STRING(s : BSTR): pchar;
  1159. begin
  1160. BSTR2STRING := Pointer(Longint(BADDR(s))+1);
  1161. end;
  1162. procedure ReadInDevices;
  1163. var
  1164. dl : pDosList;
  1165. temp : pchar;
  1166. str : string[20];
  1167. begin
  1168. dl := dos_LockDosList(LDF_DEVICES or LDF_READ );
  1169. repeat
  1170. dl := dos_NextDosEntry(dl,LDF_DEVICES );
  1171. if dl <> nil then begin
  1172. temp := BSTR2STRING(dl^.dol_Name);
  1173. str := MakeDeviceName(temp);
  1174. if not IsInDeviceList(str) then
  1175. AddDevice(str);
  1176. end;
  1177. until dl = nil;
  1178. dos_UnLockDosList(LDF_DEVICES or LDF_READ );
  1179. end;
  1180. Begin
  1181. DosError:=0;
  1182. ver := TRUE;
  1183. numberofdevices := 0;
  1184. StrOfPaths := '';
  1185. AddDevice('DF0:');
  1186. AddDevice('DF1:');
  1187. AddDevice('DF2:');
  1188. AddDevice('DF3:');
  1189. ReadInDevices;
  1190. End.
  1191. {
  1192. $Log$
  1193. Revision 1.1 2004-05-12 20:27:29 karoly
  1194. * first implementation of MorphOS DOS unit, based on Amiga version
  1195. }