sysutils.pp 22 KB

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