sysutils.pp 22 KB

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