sysutils.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for Go32v2
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. { force ansistrings }
  16. {$H+}
  17. uses
  18. go32,dos;
  19. {$DEFINE HAS_SLEEP}
  20. { Include platform independent interface part }
  21. {$i sysutilh.inc}
  22. implementation
  23. uses
  24. sysconst;
  25. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  26. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  27. { Include platform independent implementation part }
  28. {$i sysutils.inc}
  29. {****************************************************************************
  30. File Functions
  31. ****************************************************************************}
  32. { some internal constants }
  33. const
  34. ofRead = $0000; { Open for reading }
  35. ofWrite = $0001; { Open for writing }
  36. ofReadWrite = $0002; { Open for reading/writing }
  37. faFail = $0000; { Fail if file does not exist }
  38. faCreate = $0010; { Create if file does not exist }
  39. faOpen = $0001; { Open if file exists }
  40. faOpenReplace = $0002; { Clear if file exists }
  41. Type
  42. PSearchrec = ^Searchrec;
  43. { converts S to a pchar and copies it to the transfer-buffer. }
  44. procedure StringToTB(const S: string);
  45. var
  46. P: pchar;
  47. Len: integer;
  48. begin
  49. Len := Length(S) + 1;
  50. P := StrPCopy(StrAlloc(Len), S);
  51. SysCopyToDos(longint(P), Len);
  52. StrDispose(P);
  53. end ;
  54. { Native OpenFile function.
  55. if return value <> 0 call failed. }
  56. function OpenFile(const FileName: string; var Handle: longint; Mode, Action: word): longint;
  57. var
  58. Regs: registers;
  59. begin
  60. result := 0;
  61. Handle := UnusedHandle;
  62. StringToTB(FileName);
  63. if LFNSupport then
  64. begin
  65. Regs.Eax := $716c; { Use LFN Open/Create API }
  66. Regs.Edx := Action; { Action if file does/doesn't exist }
  67. Regs.Esi := tb_offset;
  68. Regs.Ebx := $2000 + (Mode and $ff); { File open mode }
  69. end
  70. else
  71. begin
  72. if (Action and $00f0) <> 0 then
  73. Regs.Eax := $3c00 { Map to Create/Replace API }
  74. else
  75. Regs.Eax := $3d00 + (Mode and $ff); { Map to Open_Existing API }
  76. Regs.Edx := tb_offset;
  77. end;
  78. Regs.Ds := tb_segment;
  79. Regs.Ecx := $20; { Attributes }
  80. RealIntr($21, Regs);
  81. if (Regs.Flags and CarryFlag) <> 0 then
  82. result := Regs.Ax
  83. else
  84. Handle := Regs.Ax;
  85. end;
  86. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  87. var
  88. e: integer;
  89. Begin
  90. e := OpenFile(FileName, result, Mode, faOpen);
  91. if e <> 0 then
  92. result := -1;
  93. end;
  94. Function FileCreate (Const FileName : String) : Longint;
  95. var
  96. e: integer;
  97. begin
  98. e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
  99. if e <> 0 then
  100. result := -1;
  101. end;
  102. Function FileCreate (Const FileName : String; Mode:longint) : Longint;
  103. begin
  104. FileCreate:=FileCreate(FileName);
  105. end;
  106. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  107. var
  108. regs : registers;
  109. size,
  110. readsize : longint;
  111. begin
  112. readsize:=0;
  113. while Count > 0 do
  114. begin
  115. if Count>tb_size then
  116. size:=tb_size
  117. else
  118. size:=Count;
  119. regs.realecx:=size;
  120. regs.realedx:=tb_offset;
  121. regs.realds:=tb_segment;
  122. regs.realebx:=Handle;
  123. regs.realeax:=$3f00;
  124. RealIntr($21,regs);
  125. if (regs.realflags and carryflag) <> 0 then
  126. begin
  127. Result:=-1;
  128. exit;
  129. end;
  130. syscopyfromdos(Longint(@Buffer)+readsize,lo(regs.realeax));
  131. inc(readsize,lo(regs.realeax));
  132. dec(Count,lo(regs.realeax));
  133. { stop when not the specified size is read }
  134. if lo(regs.realeax)<size then
  135. break;
  136. end;
  137. Result:=readsize;
  138. end;
  139. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  140. var
  141. regs : registers;
  142. size,
  143. writesize : longint;
  144. begin
  145. writesize:=0;
  146. while Count > 0 do
  147. begin
  148. if Count>tb_size then
  149. size:=tb_size
  150. else
  151. size:=Count;
  152. syscopytodos(Longint(@Buffer)+writesize,size);
  153. regs.realecx:=size;
  154. regs.realedx:=tb_offset;
  155. regs.realds:=tb_segment;
  156. regs.realebx:=Handle;
  157. regs.realeax:=$4000;
  158. RealIntr($21,regs);
  159. if (regs.realflags and carryflag) <> 0 then
  160. begin
  161. Result:=-1;
  162. exit;
  163. end;
  164. inc(writesize,lo(regs.realeax));
  165. dec(Count,lo(regs.realeax));
  166. { stop when not the specified size is written }
  167. if lo(regs.realeax)<size then
  168. break;
  169. end;
  170. Result:=WriteSize;
  171. end;
  172. Function FileSeek (Handle, FOffset, Origin : Longint) : Longint;
  173. var
  174. Regs: registers;
  175. begin
  176. Regs.Eax := $4200;
  177. Regs.Al := Origin;
  178. Regs.Edx := Lo(FOffset);
  179. Regs.Ecx := Hi(FOffset);
  180. Regs.Ebx := Handle;
  181. RealIntr($21, Regs);
  182. if Regs.Flags and CarryFlag <> 0 then
  183. result := -1
  184. else begin
  185. LongRec(result).Lo := Regs.Ax;
  186. LongRec(result).Hi := Regs.Dx;
  187. end ;
  188. end;
  189. Function FileSeek (Handle : Longint; FOffset: Int64; Origin: Integer) : Int64;
  190. begin
  191. {$warning need to add 64bit call }
  192. FileSeek:=FileSeek(Handle,Longint(FOffset),Longint(Origin));
  193. end;
  194. Procedure FileClose (Handle : Longint);
  195. var
  196. Regs: registers;
  197. begin
  198. if Handle<=4 then
  199. exit;
  200. Regs.Eax := $3e00;
  201. Regs.Ebx := Handle;
  202. RealIntr($21, Regs);
  203. end;
  204. Function FileTruncate (Handle,Size: Longint) : boolean;
  205. var
  206. regs : trealregs;
  207. begin
  208. FileSeek(Handle,Size,0);
  209. Regs.realecx := 0;
  210. Regs.realedx := tb_offset;
  211. Regs.ds := tb_segment;
  212. Regs.ebx := Handle;
  213. Regs.eax:=$4000;
  214. RealIntr($21, Regs);
  215. FileTruncate:=(regs.realflags and carryflag)=0;
  216. end;
  217. Function FileAge (Const FileName : String): Longint;
  218. var Handle: longint;
  219. begin
  220. Handle := FileOpen(FileName, 0);
  221. if Handle <> -1 then
  222. begin
  223. result := FileGetDate(Handle);
  224. FileClose(Handle);
  225. end
  226. else
  227. result := -1;
  228. end;
  229. Function FileExists (Const FileName : String) : Boolean;
  230. Var
  231. Sr : Searchrec;
  232. begin
  233. DOS.FindFirst(FileName,$3f,sr);
  234. if DosError = 0 then
  235. begin
  236. { No volumeid,directory }
  237. Result:=(sr.attr and $18)=0;
  238. Dos.FindClose(sr);
  239. end
  240. else
  241. Result:=false;
  242. end;
  243. Function DirectoryExists (Const Directory : String) : Boolean;
  244. Var
  245. Sr : Searchrec;
  246. begin
  247. DOS.FindFirst(Directory,$3f,sr);
  248. if DosError = 0 then
  249. begin
  250. Result:=(sr.attr and $10)=$10;
  251. Dos.FindClose(sr);
  252. end
  253. else
  254. Result:=false;
  255. end;
  256. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  257. Var Sr : PSearchrec;
  258. begin
  259. //!! Sr := New(PSearchRec);
  260. getmem(sr,sizeof(searchrec));
  261. Rslt.FindHandle := longint(Sr);
  262. DOS.FindFirst(Path, Attr, Sr^);
  263. result := -DosError;
  264. if result = 0 then
  265. begin
  266. Rslt.Time := Sr^.Time;
  267. Rslt.Size := Sr^.Size;
  268. Rslt.Attr := Sr^.Attr;
  269. Rslt.ExcludeAttr := 0;
  270. Rslt.Name := Sr^.Name;
  271. end ;
  272. end;
  273. Function FindNext (Var Rslt : TSearchRec) : Longint;
  274. var
  275. Sr: PSearchRec;
  276. begin
  277. Sr := PSearchRec(Rslt.FindHandle);
  278. if Sr <> nil then
  279. begin
  280. DOS.FindNext(Sr^);
  281. result := -DosError;
  282. if result = 0 then
  283. begin
  284. Rslt.Time := Sr^.Time;
  285. Rslt.Size := Sr^.Size;
  286. Rslt.Attr := Sr^.Attr;
  287. Rslt.ExcludeAttr := 0;
  288. Rslt.Name := Sr^.Name;
  289. end;
  290. end;
  291. end;
  292. Procedure FindClose (Var F : TSearchrec);
  293. var
  294. Sr: PSearchRec;
  295. begin
  296. Sr := PSearchRec(F.FindHandle);
  297. if Sr <> nil then
  298. begin
  299. //!! Dispose(Sr);
  300. // This call is non dummy if LFNSupport is true PM
  301. DOS.FindClose(SR^);
  302. freemem(sr,sizeof(searchrec));
  303. end;
  304. F.FindHandle := 0;
  305. end;
  306. Function FileGetDate (Handle : Longint) : Longint;
  307. var
  308. Regs: registers;
  309. begin
  310. //!! for win95 an alternative function is available.
  311. Regs.Ebx := Handle;
  312. Regs.Eax := $5700;
  313. RealIntr($21, Regs);
  314. if Regs.Flags and CarryFlag <> 0 then
  315. result := -1
  316. else
  317. begin
  318. LongRec(result).Lo := Regs.cx;
  319. LongRec(result).Hi := Regs.dx;
  320. end ;
  321. end;
  322. Function FileSetDate (Handle, Age : Longint) : Longint;
  323. var
  324. Regs: registers;
  325. begin
  326. Regs.Ebx := Handle;
  327. Regs.Eax := $5701;
  328. Regs.Ecx := Lo(Age);
  329. Regs.Edx := Hi(Age);
  330. RealIntr($21, Regs);
  331. if Regs.Flags and CarryFlag <> 0 then
  332. result := -Regs.Ax
  333. else
  334. result := 0;
  335. end;
  336. Function FileGetAttr (Const FileName : String) : Longint;
  337. var
  338. Regs: registers;
  339. begin
  340. StringToTB(FileName);
  341. Regs.Edx := tb_offset;
  342. Regs.Ds := tb_segment;
  343. if LFNSupport then
  344. begin
  345. Regs.Ax := $7143;
  346. Regs.Bx := 0;
  347. end
  348. else
  349. Regs.Ax := $4300;
  350. RealIntr($21, Regs);
  351. if Regs.Flags and CarryFlag <> 0 then
  352. result := -1
  353. else
  354. result := Regs.Cx;
  355. end;
  356. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  357. var
  358. Regs: registers;
  359. begin
  360. StringToTB(FileName);
  361. Regs.Edx := tb_offset;
  362. Regs.Ds := tb_segment;
  363. if LFNSupport then
  364. begin
  365. Regs.Ax := $7143;
  366. Regs.Bx := 1;
  367. end
  368. else
  369. Regs.Ax := $4301;
  370. Regs.Cx := Attr;
  371. RealIntr($21, Regs);
  372. if Regs.Flags and CarryFlag <> 0 then
  373. result := -Regs.Ax
  374. else
  375. result := 0;
  376. end;
  377. Function DeleteFile (Const FileName : String) : Boolean;
  378. var
  379. Regs: registers;
  380. begin
  381. StringToTB(FileName);
  382. Regs.Edx := tb_offset;
  383. Regs.Ds := tb_segment;
  384. if LFNSupport then
  385. Regs.Eax := $7141
  386. else
  387. Regs.Eax := $4100;
  388. Regs.Esi := 0;
  389. Regs.Ecx := 0;
  390. RealIntr($21, Regs);
  391. result := (Regs.Flags and CarryFlag = 0);
  392. end;
  393. Function RenameFile (Const OldName, NewName : String) : Boolean;
  394. var
  395. Regs: registers;
  396. begin
  397. StringToTB(OldName + #0 + NewName);
  398. Regs.Edx := tb_offset;
  399. Regs.Ds := tb_segment;
  400. Regs.Edi := tb_offset + Length(OldName) + 1;
  401. Regs.Es := tb_segment;
  402. if LFNSupport then
  403. Regs.Eax := $7156
  404. else
  405. Regs.Eax := $5600;
  406. Regs.Ecx := $ff;
  407. RealIntr($21, Regs);
  408. result := (Regs.Flags and CarryFlag = 0);
  409. end;
  410. {****************************************************************************
  411. Disk Functions
  412. ****************************************************************************}
  413. TYPE ExtendedFat32FreeSpaceRec=packed Record
  414. RetSize : WORD; { (ret) size of returned structure}
  415. Strucversion : WORD; {(call) structure version (0000h)
  416. (ret) actual structure version (0000h)}
  417. SecPerClus, {number of sectors per cluster}
  418. BytePerSec, {number of bytes per sector}
  419. AvailClusters, {number of available clusters}
  420. TotalClusters, {total number of clusters on the drive}
  421. AvailPhysSect, {physical sectors available on the drive}
  422. TotalPhysSect, {total physical sectors on the drive}
  423. AvailAllocUnits, {Available allocation units}
  424. TotalAllocUnits : DWORD; {Total allocation units}
  425. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  426. END;
  427. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  428. VAR S : String;
  429. Rec : ExtendedFat32FreeSpaceRec;
  430. regs : registers;
  431. BEGIN
  432. if (swap(dosversion)>=$070A) AND LFNSupport then
  433. begin
  434. DosError:=0;
  435. S:='C:\'#0;
  436. if Drive=0 then
  437. begin
  438. GetDir(Drive,S);
  439. Setlength(S,4);
  440. S[4]:=#0;
  441. end
  442. else
  443. S[1]:=chr(Drive+64);
  444. Rec.Strucversion:=0;
  445. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  446. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  447. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  448. regs.ds:=tb_segment;
  449. regs.di:=tb_offset;
  450. regs.es:=tb_segment;
  451. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  452. regs.ax:=$7303;
  453. msdos(regs);
  454. if regs.ax<>$ffff then
  455. begin
  456. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  457. if Free then
  458. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  459. else
  460. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  461. end
  462. else
  463. Do_DiskData:=-1;
  464. end
  465. else
  466. begin
  467. DosError:=0;
  468. regs.dl:=drive;
  469. regs.ah:=$36;
  470. msdos(regs);
  471. if regs.ax<>$FFFF then
  472. begin
  473. if Free then
  474. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  475. else
  476. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  477. end
  478. else
  479. do_diskdata:=-1;
  480. end;
  481. end;
  482. function diskfree(drive : byte) : int64;
  483. begin
  484. diskfree:=Do_DiskData(drive,TRUE);
  485. end;
  486. function disksize(drive : byte) : int64;
  487. begin
  488. disksize:=Do_DiskData(drive,false);
  489. end;
  490. Function GetCurrentDir : String;
  491. begin
  492. GetDir(0, result);
  493. end;
  494. Function SetCurrentDir (Const NewDir : String) : Boolean;
  495. begin
  496. {$I-}
  497. ChDir(NewDir);
  498. {$I+}
  499. result := (IOResult = 0);
  500. end;
  501. Function CreateDir (Const NewDir : String) : Boolean;
  502. begin
  503. {$I-}
  504. MkDir(NewDir);
  505. {$I+}
  506. result := (IOResult = 0);
  507. end;
  508. Function RemoveDir (Const Dir : String) : Boolean;
  509. begin
  510. {$I-}
  511. RmDir(Dir);
  512. {$I+}
  513. result := (IOResult = 0);
  514. end;
  515. {****************************************************************************
  516. Time Functions
  517. ****************************************************************************}
  518. Procedure GetLocalTime(var SystemTime: TSystemTime);
  519. var
  520. Regs: Registers;
  521. begin
  522. Regs.ah := $2C;
  523. RealIntr($21, Regs);
  524. SystemTime.Hour := Regs.Ch;
  525. SystemTime.Minute := Regs.Cl;
  526. SystemTime.Second := Regs.Dh;
  527. SystemTime.MilliSecond := Regs.Dl*10;
  528. Regs.ah := $2A;
  529. RealIntr($21, Regs);
  530. SystemTime.Year := Regs.Cx;
  531. SystemTime.Month := Regs.Dh;
  532. SystemTime.Day := Regs.Dl;
  533. end ;
  534. {****************************************************************************
  535. Misc Functions
  536. ****************************************************************************}
  537. procedure Beep;
  538. begin
  539. end;
  540. {****************************************************************************
  541. Locale Functions
  542. ****************************************************************************}
  543. { Codepage constants }
  544. const
  545. CP_US = 437;
  546. CP_MultiLingual = 850;
  547. CP_SlavicLatin2 = 852;
  548. CP_Turkish = 857;
  549. CP_Portugal = 860;
  550. CP_IceLand = 861;
  551. CP_Canada = 863;
  552. CP_NorwayDenmark = 865;
  553. { CountryInfo }
  554. type
  555. TCountryInfo = packed record
  556. InfoId: byte;
  557. case integer of
  558. 1: ( Size: word;
  559. CountryId: word;
  560. CodePage: word;
  561. CountryInfo: array[0..33] of byte );
  562. 2: ( UpperCaseTable: longint );
  563. 4: ( FilenameUpperCaseTable: longint );
  564. 5: ( FilecharacterTable: longint );
  565. 6: ( CollatingTable: longint );
  566. 7: ( DBCSLeadByteTable: longint );
  567. end ;
  568. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  569. Var Regs: Registers;
  570. begin
  571. Regs.AH := $65;
  572. Regs.AL := InfoId;
  573. Regs.BX := CodePage;
  574. Regs.DX := CountryId;
  575. Regs.ES := transfer_buffer div 16;
  576. Regs.DI := transfer_buffer and 15;
  577. Regs.CX := SizeOf(TCountryInfo);
  578. RealIntr($21, Regs);
  579. DosMemGet(transfer_buffer div 16,
  580. transfer_buffer and 15,
  581. CountryInfo, Regs.CX );
  582. end;
  583. procedure InitAnsi;
  584. var
  585. CountryInfo: TCountryInfo; i: integer;
  586. begin
  587. { Fill table entries 0 to 127 }
  588. for i := 0 to 96 do
  589. UpperCaseTable[i] := chr(i);
  590. for i := 97 to 122 do
  591. UpperCaseTable[i] := chr(i - 32);
  592. for i := 123 to 127 do
  593. UpperCaseTable[i] := chr(i);
  594. for i := 0 to 64 do
  595. LowerCaseTable[i] := chr(i);
  596. for i := 65 to 90 do
  597. LowerCaseTable[i] := chr(i + 32);
  598. for i := 91 to 255 do
  599. LowerCaseTable[i] := chr(i);
  600. { Get country and codepage info }
  601. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  602. if CountryInfo.CodePage = 850 then
  603. begin
  604. { Special, known case }
  605. Move(CP850UCT, UpperCaseTable[128], 128);
  606. Move(CP850LCT, LowerCaseTable[128], 128);
  607. end
  608. else
  609. begin
  610. { this needs to be checked !!
  611. this is correct only if UpperCaseTable is
  612. and Offset:Segment word record (PM) }
  613. { get the uppercase table from dosmemory }
  614. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  615. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  616. for i := 128 to 255 do
  617. begin
  618. if UpperCaseTable[i] <> chr(i) then
  619. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  620. end;
  621. end;
  622. end;
  623. Procedure InitInternational;
  624. begin
  625. InitInternationalGeneric;
  626. InitAnsi;
  627. end;
  628. function SysErrorMessage(ErrorCode: Integer): String;
  629. begin
  630. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  631. end;
  632. {****************************************************************************
  633. Os utils
  634. ****************************************************************************}
  635. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  636. begin
  637. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  638. end;
  639. Function GetEnvironmentVariableCount : Integer;
  640. begin
  641. Result:=FPCCountEnvVar(EnvP);
  642. end;
  643. Function GetEnvironmentString(Index : Integer) : String;
  644. begin
  645. Result:=FPCGetEnvStrFromP(Envp,Index);
  646. end;
  647. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
  648. var
  649. e : EOSError;
  650. CommandLine: AnsiString;
  651. begin
  652. dos.exec(path,comline);
  653. if (Dos.DosError <> 0) then
  654. begin
  655. if ComLine <> '' then
  656. CommandLine := Path + ' ' + ComLine
  657. else
  658. CommandLine := Path;
  659. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  660. e.ErrorCode:=Dos.DosError;
  661. raise e;
  662. end;
  663. Result := DosExitCode;
  664. end;
  665. function ExecuteProcess (const Path: AnsiString;
  666. const ComLine: array of AnsiString): integer;
  667. var
  668. CommandLine: AnsiString;
  669. I: integer;
  670. begin
  671. Commandline := '';
  672. for I := 0 to High (ComLine) do
  673. if Pos (' ', ComLine [I]) <> 0 then
  674. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  675. else
  676. CommandLine := CommandLine + ' ' + Comline [I];
  677. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  678. end;
  679. {*************************************************************************
  680. Sleep
  681. *************************************************************************}
  682. procedure Sleep (MilliSeconds: Cardinal);
  683. var
  684. R: Registers;
  685. T0, T1, T2: int64;
  686. DayOver: boolean;
  687. begin
  688. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  689. because it should be supported in all DOS versions. Not precise at all,
  690. though - the smallest step is 10 ms even in the best case. *)
  691. R.AH := $2C;
  692. RealIntr($21, R);
  693. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  694. T2 := T0 + MilliSeconds;
  695. DayOver := T2 > (24 * 3600000);
  696. repeat
  697. Intr ($28, R);
  698. (* R.AH := $2C; - should be preserved. *)
  699. RealIntr($21, R);
  700. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  701. if DayOver and (T1 < T0) then
  702. Inc (T1, 24 * 3600000);
  703. until T1 >= T2;
  704. end;
  705. {****************************************************************************
  706. Initialization code
  707. ****************************************************************************}
  708. Initialization
  709. InitExceptions; { Initialize exceptions. OS independent }
  710. InitInternational; { Initialize internationalization settings }
  711. Finalization
  712. DoneExceptions;
  713. end.