2
0

sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  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(SystemFileName, 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: RawByteString): boolean;
  249. var
  250. L: longint;
  251. begin
  252. if FileName = '' then
  253. Result := false
  254. else
  255. begin
  256. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  257. L := FileGetAttr (FileName);
  258. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  259. (* Neither VolumeIDs nor directories are files. *)
  260. end;
  261. end;
  262. Function DirectoryExists (Const Directory : RawByteString) : Boolean;
  263. Var
  264. Dir : RawByteString;
  265. drive : byte;
  266. FADir, StoredIORes : longint;
  267. begin
  268. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  269. Dir:=Directory;
  270. if (length(dir)=2) and (dir[2]=':') and
  271. ((dir[1] in ['A'..'Z']) or (dir[1] in ['a'..'z'])) then
  272. begin
  273. { We want to test GetCurDir }
  274. if dir[1] in ['A'..'Z'] then
  275. drive:=ord(dir[1])-ord('A')+1
  276. else
  277. drive:=ord(dir[1])-ord('a')+1;
  278. {$push}
  279. {$I-}
  280. StoredIORes:=InOutRes;
  281. InOutRes:=0;
  282. GetDir(drive,dir);
  283. if InOutRes <> 0 then
  284. begin
  285. InOutRes:=StoredIORes;
  286. result:=false;
  287. exit;
  288. end;
  289. end;
  290. {$pop}
  291. if (Length (Dir) > 1) and
  292. (Dir [Length (Dir)] in AllowDirectorySeparators) and
  293. (* Do not remove '\' after ':' (root directory of a drive)
  294. or in '\\' (invalid path, possibly broken UNC path). *)
  295. not (Dir [Length (Dir) - 1] in (AllowDriveSeparators + AllowDirectorySeparators)) then
  296. dir:=copy(dir,1,length(dir)-1);
  297. (* FileGetAttr returns -1 on error *)
  298. FADir := FileGetAttr (Dir);
  299. Result := (FADir <> -1) and
  300. ((FADir and faDirectory) = faDirectory);
  301. end;
  302. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  303. Var Sr : PSearchrec;
  304. begin
  305. //!! Sr := New(PSearchRec);
  306. getmem(sr,sizeof(searchrec));
  307. Rslt.FindHandle := longint(Sr);
  308. DOS.FindFirst(Path, Attr, Sr^);
  309. result := -DosError;
  310. if result = 0 then
  311. begin
  312. Rslt.Time := Sr^.Time;
  313. Rslt.Size := Sr^.Size;
  314. Rslt.Attr := Sr^.Attr;
  315. Rslt.ExcludeAttr := 0;
  316. Rslt.Name := Sr^.Name;
  317. end ;
  318. end;
  319. Function FindNext (Var Rslt : TSearchRec) : Longint;
  320. var
  321. Sr: PSearchRec;
  322. begin
  323. Sr := PSearchRec(Rslt.FindHandle);
  324. if Sr <> nil then
  325. begin
  326. DOS.FindNext(Sr^);
  327. result := -DosError;
  328. if result = 0 then
  329. begin
  330. Rslt.Time := Sr^.Time;
  331. Rslt.Size := Sr^.Size;
  332. Rslt.Attr := Sr^.Attr;
  333. Rslt.ExcludeAttr := 0;
  334. Rslt.Name := Sr^.Name;
  335. end;
  336. end;
  337. end;
  338. Procedure FindClose (Var F : TSearchrec);
  339. var
  340. Sr: PSearchRec;
  341. begin
  342. Sr := PSearchRec(F.FindHandle);
  343. if Sr <> nil then
  344. begin
  345. //!! Dispose(Sr);
  346. // This call is non dummy if LFNSupport is true PM
  347. DOS.FindClose(SR^);
  348. freemem(sr,sizeof(searchrec));
  349. end;
  350. F.FindHandle := 0;
  351. end;
  352. Function FileGetDate (Handle : Longint) : Longint;
  353. var
  354. Regs: registers;
  355. begin
  356. //!! for win95 an alternative function is available.
  357. Regs.Ebx := Handle;
  358. Regs.Eax := $5700;
  359. RealIntr($21, Regs);
  360. if Regs.Flags and CarryFlag <> 0 then
  361. result := -1
  362. else
  363. begin
  364. LongRec(result).Lo := Regs.cx;
  365. LongRec(result).Hi := Regs.dx;
  366. end ;
  367. end;
  368. Function FileSetDate (Handle, Age : Longint) : Longint;
  369. var
  370. Regs: registers;
  371. begin
  372. Regs.Ebx := Handle;
  373. Regs.Eax := $5701;
  374. Regs.Ecx := Lo(Age);
  375. Regs.Edx := Hi(Age);
  376. RealIntr($21, Regs);
  377. if Regs.Flags and CarryFlag <> 0 then
  378. result := -Regs.Ax
  379. else
  380. result := 0;
  381. end;
  382. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  383. var
  384. Regs: registers;
  385. SystemFileName: RawByteString;
  386. begin
  387. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  388. StringToTB(SystemFileName);
  389. Regs.Edx := tb_offset;
  390. Regs.Ds := tb_segment;
  391. if LFNSupport then
  392. begin
  393. Regs.Ax := $7143;
  394. Regs.Bx := 0;
  395. end
  396. else
  397. Regs.Ax := $4300;
  398. RealIntr($21, Regs);
  399. if Regs.Flags and CarryFlag <> 0 then
  400. result := -1
  401. else
  402. result := Regs.Cx;
  403. end;
  404. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  405. var
  406. Regs: registers;
  407. SystemFileName: RawByteString;
  408. begin
  409. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  410. StringToTB(SystemFileName);
  411. Regs.Edx := tb_offset;
  412. Regs.Ds := tb_segment;
  413. if LFNSupport then
  414. begin
  415. Regs.Ax := $7143;
  416. Regs.Bx := 1;
  417. end
  418. else
  419. Regs.Ax := $4301;
  420. Regs.Cx := Attr;
  421. RealIntr($21, Regs);
  422. if Regs.Flags and CarryFlag <> 0 then
  423. result := -Regs.Ax
  424. else
  425. result := 0;
  426. end;
  427. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  428. var
  429. Regs: registers;
  430. SystemFileName: RawByteString;
  431. begin
  432. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  433. StringToTB(SystemFileName);
  434. Regs.Edx := tb_offset;
  435. Regs.Ds := tb_segment;
  436. if LFNSupport then
  437. Regs.Eax := $7141
  438. else
  439. Regs.Eax := $4100;
  440. Regs.Esi := 0;
  441. Regs.Ecx := 0;
  442. RealIntr($21, Regs);
  443. result := (Regs.Flags and CarryFlag = 0);
  444. end;
  445. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  446. var
  447. Regs: registers;
  448. OldSystemFileName, NewSystemFileName: RawByteString;
  449. Begin
  450. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  451. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  452. StringToTB(OldSystemFileName + #0 + NewSystemFileName);
  453. Regs.Edx := tb_offset;
  454. Regs.Ds := tb_segment;
  455. Regs.Edi := tb_offset + Length(OldSystemFileName) + 1;
  456. Regs.Es := tb_segment;
  457. if LFNSupport then
  458. Regs.Eax := $7156
  459. else
  460. Regs.Eax := $5600;
  461. Regs.Ecx := $ff;
  462. RealIntr($21, Regs);
  463. result := (Regs.Flags and CarryFlag = 0);
  464. end;
  465. {****************************************************************************
  466. Disk Functions
  467. ****************************************************************************}
  468. TYPE ExtendedFat32FreeSpaceRec=packed Record
  469. RetSize : WORD; { (ret) size of returned structure}
  470. Strucversion : WORD; {(call) structure version (0000h)
  471. (ret) actual structure version (0000h)}
  472. SecPerClus, {number of sectors per cluster}
  473. BytePerSec, {number of bytes per sector}
  474. AvailClusters, {number of available clusters}
  475. TotalClusters, {total number of clusters on the drive}
  476. AvailPhysSect, {physical sectors available on the drive}
  477. TotalPhysSect, {total physical sectors on the drive}
  478. AvailAllocUnits, {Available allocation units}
  479. TotalAllocUnits : DWORD; {Total allocation units}
  480. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  481. END;
  482. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  483. VAR S : String;
  484. Rec : ExtendedFat32FreeSpaceRec;
  485. regs : registers;
  486. procedure OldDosDiskData;
  487. begin
  488. regs.dl:=drive;
  489. regs.ah:=$36;
  490. msdos(regs);
  491. if regs.ax<>$FFFF then
  492. begin
  493. if Free then
  494. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  495. else
  496. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  497. end
  498. else
  499. do_diskdata:=-1;
  500. end;
  501. BEGIN
  502. if LFNSupport then
  503. begin
  504. S:='C:\'#0;
  505. if Drive=0 then
  506. begin
  507. GetDir(Drive,S);
  508. Setlength(S,4);
  509. S[4]:=#0;
  510. end
  511. else
  512. S[1]:=chr(Drive+64);
  513. Rec.Strucversion:=0;
  514. Rec.RetSize := 0;
  515. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  516. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  517. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  518. regs.ds:=tb_segment;
  519. regs.di:=tb_offset;
  520. regs.es:=tb_segment;
  521. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  522. regs.ax:=$7303;
  523. msdos(regs);
  524. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  525. begin
  526. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  527. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  528. OldDosDiskData
  529. else
  530. if Free then
  531. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  532. else
  533. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  534. end
  535. else
  536. OldDosDiskData;
  537. end
  538. else
  539. OldDosDiskData;
  540. end;
  541. function diskfree(drive : byte) : int64;
  542. begin
  543. diskfree:=Do_DiskData(drive,TRUE);
  544. end;
  545. function disksize(drive : byte) : int64;
  546. begin
  547. disksize:=Do_DiskData(drive,false);
  548. end;
  549. Function GetCurrentDir : String;
  550. begin
  551. GetDir(0, result);
  552. end;
  553. Function SetCurrentDir (Const NewDir : String) : Boolean;
  554. begin
  555. {$I-}
  556. ChDir(NewDir);
  557. {$I+}
  558. result := (IOResult = 0);
  559. end;
  560. Function CreateDir (Const NewDir : String) : Boolean;
  561. begin
  562. {$I-}
  563. MkDir(NewDir);
  564. {$I+}
  565. result := (IOResult = 0);
  566. end;
  567. Function RemoveDir (Const Dir : String) : Boolean;
  568. begin
  569. {$I-}
  570. RmDir(Dir);
  571. {$I+}
  572. result := (IOResult = 0);
  573. end;
  574. {****************************************************************************
  575. Time Functions
  576. ****************************************************************************}
  577. Procedure GetLocalTime(var SystemTime: TSystemTime);
  578. var
  579. Regs: Registers;
  580. begin
  581. Regs.ah := $2C;
  582. RealIntr($21, Regs);
  583. SystemTime.Hour := Regs.Ch;
  584. SystemTime.Minute := Regs.Cl;
  585. SystemTime.Second := Regs.Dh;
  586. SystemTime.MilliSecond := Regs.Dl*10;
  587. Regs.ah := $2A;
  588. RealIntr($21, Regs);
  589. SystemTime.Year := Regs.Cx;
  590. SystemTime.Month := Regs.Dh;
  591. SystemTime.Day := Regs.Dl;
  592. end ;
  593. {****************************************************************************
  594. Misc Functions
  595. ****************************************************************************}
  596. procedure sysBeep;
  597. begin
  598. end;
  599. {****************************************************************************
  600. Locale Functions
  601. ****************************************************************************}
  602. { Codepage constants }
  603. const
  604. CP_US = 437;
  605. CP_MultiLingual = 850;
  606. CP_SlavicLatin2 = 852;
  607. CP_Turkish = 857;
  608. CP_Portugal = 860;
  609. CP_IceLand = 861;
  610. CP_Canada = 863;
  611. CP_NorwayDenmark = 865;
  612. { CountryInfo }
  613. type
  614. TCountryInfo = packed record
  615. InfoId: byte;
  616. case integer of
  617. 1: ( Size: word;
  618. CountryId: word;
  619. CodePage: word;
  620. CountryInfo: array[0..33] of byte );
  621. 2: ( UpperCaseTable: longint );
  622. 4: ( FilenameUpperCaseTable: longint );
  623. 5: ( FilecharacterTable: longint );
  624. 6: ( CollatingTable: longint );
  625. 7: ( DBCSLeadByteTable: longint );
  626. end ;
  627. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  628. Var Regs: Registers;
  629. begin
  630. Regs.AH := $65;
  631. Regs.AL := InfoId;
  632. Regs.BX := CodePage;
  633. Regs.DX := CountryId;
  634. Regs.ES := transfer_buffer div 16;
  635. Regs.DI := transfer_buffer and 15;
  636. Regs.CX := SizeOf(TCountryInfo);
  637. RealIntr($21, Regs);
  638. DosMemGet(transfer_buffer div 16,
  639. transfer_buffer and 15,
  640. CountryInfo, Regs.CX );
  641. end;
  642. procedure InitAnsi;
  643. var
  644. CountryInfo: TCountryInfo; i: integer;
  645. begin
  646. { Fill table entries 0 to 127 }
  647. for i := 0 to 96 do
  648. UpperCaseTable[i] := chr(i);
  649. for i := 97 to 122 do
  650. UpperCaseTable[i] := chr(i - 32);
  651. for i := 123 to 127 do
  652. UpperCaseTable[i] := chr(i);
  653. for i := 0 to 64 do
  654. LowerCaseTable[i] := chr(i);
  655. for i := 65 to 90 do
  656. LowerCaseTable[i] := chr(i + 32);
  657. for i := 91 to 255 do
  658. LowerCaseTable[i] := chr(i);
  659. { Get country and codepage info }
  660. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  661. if CountryInfo.CodePage = 850 then
  662. begin
  663. { Special, known case }
  664. Move(CP850UCT, UpperCaseTable[128], 128);
  665. Move(CP850LCT, LowerCaseTable[128], 128);
  666. end
  667. else
  668. begin
  669. { this needs to be checked !!
  670. this is correct only if UpperCaseTable is
  671. and Offset:Segment word record (PM) }
  672. { get the uppercase table from dosmemory }
  673. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  674. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  675. for i := 128 to 255 do
  676. begin
  677. if UpperCaseTable[i] <> chr(i) then
  678. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  679. end;
  680. end;
  681. end;
  682. Procedure InitInternational;
  683. begin
  684. InitInternationalGeneric;
  685. InitAnsi;
  686. end;
  687. function SysErrorMessage(ErrorCode: Integer): String;
  688. begin
  689. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  690. end;
  691. {****************************************************************************
  692. Os utils
  693. ****************************************************************************}
  694. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  695. begin
  696. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  697. end;
  698. Function GetEnvironmentVariableCount : Integer;
  699. begin
  700. Result:=FPCCountEnvVar(EnvP);
  701. end;
  702. Function GetEnvironmentString(Index : Integer) : String;
  703. begin
  704. Result:=FPCGetEnvStrFromP(Envp,Index);
  705. end;
  706. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  707. var
  708. e : EOSError;
  709. CommandLine: AnsiString;
  710. begin
  711. dos.exec_ansistring(path,comline);
  712. if (Dos.DosError <> 0) then
  713. begin
  714. if ComLine <> '' then
  715. CommandLine := Path + ' ' + ComLine
  716. else
  717. CommandLine := Path;
  718. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  719. e.ErrorCode:=Dos.DosError;
  720. raise e;
  721. end;
  722. Result := DosExitCode;
  723. end;
  724. function ExecuteProcess (const Path: AnsiString;
  725. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  726. var
  727. CommandLine: AnsiString;
  728. I: integer;
  729. begin
  730. Commandline := '';
  731. for I := 0 to High (ComLine) do
  732. if Pos (' ', ComLine [I]) <> 0 then
  733. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  734. else
  735. CommandLine := CommandLine + ' ' + Comline [I];
  736. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  737. end;
  738. {*************************************************************************
  739. Sleep
  740. *************************************************************************}
  741. procedure Sleep (MilliSeconds: Cardinal);
  742. var
  743. R: Registers;
  744. T0, T1, T2: int64;
  745. DayOver: boolean;
  746. begin
  747. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  748. because it should be supported in all DOS versions. Not precise at all,
  749. though - the smallest step is 10 ms even in the best case. *)
  750. R.AH := $2C;
  751. RealIntr($21, R);
  752. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  753. T2 := T0 + MilliSeconds;
  754. DayOver := T2 > (24 * 3600000);
  755. repeat
  756. Intr ($28, R);
  757. (* R.AH := $2C; - should be preserved. *)
  758. RealIntr($21, R);
  759. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  760. if DayOver and (T1 < T0) then
  761. Inc (T1, 24 * 3600000);
  762. until T1 >= T2;
  763. end;
  764. {****************************************************************************
  765. Initialization code
  766. ****************************************************************************}
  767. Initialization
  768. InitExceptions; { Initialize exceptions. OS independent }
  769. InitInternational; { Initialize internationalization settings }
  770. OnBeep:=@SysBeep;
  771. Finalization
  772. DoneExceptions;
  773. end.