sysutils.pp 22 KB

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