dos.pp 34 KB

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