sysutils.pp 23 KB

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