sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  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 FileExists (const FileName: RawByteString): boolean;
  250. var
  251. L: longint;
  252. begin
  253. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  254. if FileName = '' then
  255. Result := false
  256. else
  257. begin
  258. L := FileGetAttr (FileName);
  259. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  260. (* Neither VolumeIDs nor directories are files. *)
  261. end;
  262. end;
  263. function DirectoryExists (const Directory: RawByteString): boolean;
  264. var
  265. L: longint;
  266. begin
  267. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  268. if Directory = '' then
  269. Result := false
  270. else
  271. begin
  272. if ((Length (Directory) = 2) or
  273. (Length (Directory) = 3) and
  274. (Directory [3] in AllowDirectorySeparators)) and
  275. (Directory [2] in AllowDriveSeparators) and
  276. (UpCase (Directory [1]) in ['A'..'Z']) then
  277. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  278. L := FileGetAttr (Directory + '.')
  279. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  280. (Length (Directory) > 1) and
  281. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  282. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  283. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  284. else
  285. L := FileGetAttr (Directory);
  286. Result := (L > 0) and (L and faDirectory = faDirectory);
  287. end;
  288. end;
  289. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  290. Var Sr : PSearchrec;
  291. begin
  292. //!! Sr := New(PSearchRec);
  293. getmem(sr,sizeof(searchrec));
  294. Rslt.FindHandle := longint(Sr);
  295. { FIXME: Dos version has shortstring interface -> discards encoding }
  296. DOS.FindFirst(Path, Attr, Sr^);
  297. result := -DosError;
  298. if result = 0 then
  299. begin
  300. Rslt.Time := Sr^.Time;
  301. Rslt.Size := Sr^.Size;
  302. Rslt.Attr := Sr^.Attr;
  303. Rslt.ExcludeAttr := 0;
  304. Name := Sr^.Name;
  305. SetCodePage(Name,DefaultFileSystemCodePage,False);
  306. end ;
  307. end;
  308. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  309. var
  310. Sr: PSearchRec;
  311. begin
  312. Sr := PSearchRec(Rslt.FindHandle);
  313. if Sr <> nil then
  314. begin
  315. DOS.FindNext(Sr^);
  316. result := -DosError;
  317. if result = 0 then
  318. begin
  319. Rslt.Time := Sr^.Time;
  320. Rslt.Size := Sr^.Size;
  321. Rslt.Attr := Sr^.Attr;
  322. Rslt.ExcludeAttr := 0;
  323. Name := Sr^.Name;
  324. SetCodePage(Name,DefaultFileSystemCodePage,False);
  325. end;
  326. end;
  327. end;
  328. Procedure InternalFindClose(var Handle: longint);
  329. var
  330. Sr: PSearchRec;
  331. begin
  332. Sr := PSearchRec(PtrUint(Handle));
  333. if Sr <> nil then
  334. begin
  335. //!! Dispose(Sr);
  336. // This call is non dummy if LFNSupport is true PM
  337. DOS.FindClose(SR^);
  338. freemem(sr,sizeof(searchrec));
  339. end;
  340. Handle := 0;
  341. end;
  342. Function FileGetDate (Handle : Longint) : Longint;
  343. var
  344. Regs: registers;
  345. begin
  346. //!! for win95 an alternative function is available.
  347. Regs.Ebx := Handle;
  348. Regs.Eax := $5700;
  349. RealIntr($21, Regs);
  350. if Regs.Flags and CarryFlag <> 0 then
  351. result := -1
  352. else
  353. begin
  354. LongRec(result).Lo := Regs.cx;
  355. LongRec(result).Hi := Regs.dx;
  356. end ;
  357. end;
  358. Function FileSetDate (Handle, Age : Longint) : Longint;
  359. var
  360. Regs: registers;
  361. begin
  362. Regs.Ebx := Handle;
  363. Regs.Eax := $5701;
  364. Regs.Ecx := Lo(Age);
  365. Regs.Edx := Hi(Age);
  366. RealIntr($21, Regs);
  367. if Regs.Flags and CarryFlag <> 0 then
  368. result := -Regs.Ax
  369. else
  370. result := 0;
  371. end;
  372. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  373. var
  374. Regs: registers;
  375. SystemFileName: RawByteString;
  376. begin
  377. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  378. StringToTB(SystemFileName);
  379. Regs.Edx := tb_offset;
  380. Regs.Ds := tb_segment;
  381. if LFNSupport then
  382. begin
  383. Regs.Ax := $7143;
  384. Regs.Bx := 0;
  385. end
  386. else
  387. Regs.Ax := $4300;
  388. RealIntr($21, Regs);
  389. if Regs.Flags and CarryFlag <> 0 then
  390. result := -1
  391. else
  392. result := Regs.Cx;
  393. end;
  394. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  395. var
  396. Regs: registers;
  397. SystemFileName: RawByteString;
  398. begin
  399. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  400. StringToTB(SystemFileName);
  401. Regs.Edx := tb_offset;
  402. Regs.Ds := tb_segment;
  403. if LFNSupport then
  404. begin
  405. Regs.Ax := $7143;
  406. Regs.Bx := 1;
  407. end
  408. else
  409. Regs.Ax := $4301;
  410. Regs.Cx := Attr;
  411. RealIntr($21, Regs);
  412. if Regs.Flags and CarryFlag <> 0 then
  413. result := -Regs.Ax
  414. else
  415. result := 0;
  416. end;
  417. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  418. var
  419. Regs: registers;
  420. SystemFileName: RawByteString;
  421. begin
  422. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  423. StringToTB(SystemFileName);
  424. Regs.Edx := tb_offset;
  425. Regs.Ds := tb_segment;
  426. if LFNSupport then
  427. Regs.Eax := $7141
  428. else
  429. Regs.Eax := $4100;
  430. Regs.Esi := 0;
  431. Regs.Ecx := 0;
  432. RealIntr($21, Regs);
  433. result := (Regs.Flags and CarryFlag = 0);
  434. end;
  435. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  436. var
  437. Regs: registers;
  438. OldSystemFileName, NewSystemFileName: RawByteString;
  439. begin
  440. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  441. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  442. StringToTB(OldSystemFileName + #0 + NewSystemFileName);
  443. Regs.Edx := tb_offset;
  444. Regs.Ds := tb_segment;
  445. Regs.Edi := tb_offset + Length(OldSystemFileName) + 1;
  446. Regs.Es := tb_segment;
  447. if LFNSupport then
  448. Regs.Eax := $7156
  449. else
  450. Regs.Eax := $5600;
  451. Regs.Ecx := $ff;
  452. RealIntr($21, Regs);
  453. result := (Regs.Flags and CarryFlag = 0);
  454. end;
  455. {****************************************************************************
  456. Disk Functions
  457. ****************************************************************************}
  458. TYPE ExtendedFat32FreeSpaceRec=packed Record
  459. RetSize : WORD; { (ret) size of returned structure}
  460. Strucversion : WORD; {(call) structure version (0000h)
  461. (ret) actual structure version (0000h)}
  462. SecPerClus, {number of sectors per cluster}
  463. BytePerSec, {number of bytes per sector}
  464. AvailClusters, {number of available clusters}
  465. TotalClusters, {total number of clusters on the drive}
  466. AvailPhysSect, {physical sectors available on the drive}
  467. TotalPhysSect, {total physical sectors on the drive}
  468. AvailAllocUnits, {Available allocation units}
  469. TotalAllocUnits : DWORD; {Total allocation units}
  470. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  471. END;
  472. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  473. VAR S : String;
  474. Rec : ExtendedFat32FreeSpaceRec;
  475. regs : registers;
  476. procedure OldDosDiskData;
  477. begin
  478. regs.dl:=drive;
  479. regs.ah:=$36;
  480. msdos(regs);
  481. if regs.ax<>$FFFF then
  482. begin
  483. if Free then
  484. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  485. else
  486. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  487. end
  488. else
  489. do_diskdata:=-1;
  490. end;
  491. BEGIN
  492. if LFNSupport then
  493. begin
  494. S:='C:\'#0;
  495. if Drive=0 then
  496. begin
  497. GetDir(Drive,S);
  498. Setlength(S,4);
  499. S[4]:=#0;
  500. end
  501. else
  502. S[1]:=chr(Drive+64);
  503. Rec.Strucversion:=0;
  504. Rec.RetSize := 0;
  505. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  506. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  507. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  508. regs.ds:=tb_segment;
  509. regs.di:=tb_offset;
  510. regs.es:=tb_segment;
  511. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  512. regs.ax:=$7303;
  513. msdos(regs);
  514. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  515. begin
  516. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  517. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  518. OldDosDiskData
  519. else
  520. if Free then
  521. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  522. else
  523. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  524. end
  525. else
  526. Do_DiskData:=-1;
  527. end
  528. else
  529. OldDosDiskData;
  530. end;
  531. function diskfree(drive : byte) : int64;
  532. begin
  533. diskfree:=Do_DiskData(drive,TRUE);
  534. end;
  535. function disksize(drive : byte) : int64;
  536. begin
  537. disksize:=Do_DiskData(drive,false);
  538. end;
  539. {****************************************************************************
  540. Time Functions
  541. ****************************************************************************}
  542. Procedure GetLocalTime(var SystemTime: TSystemTime);
  543. var
  544. Regs: Registers;
  545. begin
  546. Regs.ah := $2C;
  547. RealIntr($21, Regs);
  548. SystemTime.Hour := Regs.Ch;
  549. SystemTime.Minute := Regs.Cl;
  550. SystemTime.Second := Regs.Dh;
  551. SystemTime.MilliSecond := Regs.Dl*10;
  552. Regs.ah := $2A;
  553. RealIntr($21, Regs);
  554. SystemTime.Year := Regs.Cx;
  555. SystemTime.Month := Regs.Dh;
  556. SystemTime.Day := Regs.Dl;
  557. end ;
  558. {****************************************************************************
  559. Misc Functions
  560. ****************************************************************************}
  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: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  669. var
  670. e : EOSError;
  671. CommandLine: RawByteString;
  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: RawByteString;
  687. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  688. var
  689. CommandLine: RawByteString;
  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.