sysutils.pp 21 KB

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