sysutils.pp 22 KB

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