dos.pp 34 KB

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