sysutils.pp 23 KB

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