sysutils.pp 23 KB

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