sysutils.pp 22 KB

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