sysutils.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  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): Longint;
  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) : Longint;
  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. begin
  376. LongRec(result).Lo := Regs.cx;
  377. LongRec(result).Hi := Regs.dx;
  378. end ;
  379. end;
  380. Function FileSetDate (Handle, Age : Longint) : Longint;
  381. var
  382. Regs: registers;
  383. begin
  384. Regs.Ebx := Handle;
  385. Regs.Eax := $5701;
  386. Regs.Ecx := Lo(Age);
  387. Regs.Edx := Hi(Age);
  388. RealIntr($21, Regs);
  389. if Regs.Flags and CarryFlag <> 0 then
  390. result := -Regs.Ax
  391. else
  392. result := 0;
  393. end;
  394. Function FileGetAttr (Const FileName : RawByteString) : 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 := 0;
  407. end
  408. else
  409. Regs.Ax := $4300;
  410. RealIntr($21, Regs);
  411. if Regs.Flags and CarryFlag <> 0 then
  412. result := -1
  413. else
  414. result := Regs.Cx;
  415. end;
  416. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  417. var
  418. Regs: registers;
  419. SystemFileName: RawByteString;
  420. begin
  421. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  422. StringToTB(SystemFileName);
  423. Regs.Edx := tb_offset;
  424. Regs.Ds := tb_segment;
  425. if LFNSupport then
  426. begin
  427. Regs.Ax := $7143;
  428. Regs.Bx := 1;
  429. end
  430. else
  431. Regs.Ax := $4301;
  432. Regs.Cx := Attr;
  433. RealIntr($21, Regs);
  434. if Regs.Flags and CarryFlag <> 0 then
  435. result := -Regs.Ax
  436. else
  437. result := 0;
  438. end;
  439. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  440. var
  441. Regs: registers;
  442. SystemFileName: RawByteString;
  443. begin
  444. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  445. StringToTB(SystemFileName);
  446. Regs.Edx := tb_offset;
  447. Regs.Ds := tb_segment;
  448. if LFNSupport then
  449. Regs.Eax := $7141
  450. else
  451. Regs.Eax := $4100;
  452. Regs.Esi := 0;
  453. Regs.Ecx := 0;
  454. RealIntr($21, Regs);
  455. result := (Regs.Flags and CarryFlag = 0);
  456. end;
  457. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  458. var
  459. Regs: registers;
  460. OldSystemFileName, NewSystemFileName: RawByteString;
  461. Begin
  462. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  463. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  464. StringToTB(OldSystemFileName + #0 + NewSystemFileName);
  465. Regs.Edx := tb_offset;
  466. Regs.Ds := tb_segment;
  467. Regs.Edi := tb_offset + Length(OldSystemFileName) + 1;
  468. Regs.Es := tb_segment;
  469. if LFNSupport then
  470. Regs.Eax := $7156
  471. else
  472. Regs.Eax := $5600;
  473. Regs.Ecx := $ff;
  474. RealIntr($21, Regs);
  475. result := (Regs.Flags and CarryFlag = 0);
  476. end;
  477. {****************************************************************************
  478. Disk Functions
  479. ****************************************************************************}
  480. TYPE ExtendedFat32FreeSpaceRec=packed Record
  481. RetSize : WORD; { (ret) size of returned structure}
  482. Strucversion : WORD; {(call) structure version (0000h)
  483. (ret) actual structure version (0000h)}
  484. SecPerClus, {number of sectors per cluster}
  485. BytePerSec, {number of bytes per sector}
  486. AvailClusters, {number of available clusters}
  487. TotalClusters, {total number of clusters on the drive}
  488. AvailPhysSect, {physical sectors available on the drive}
  489. TotalPhysSect, {total physical sectors on the drive}
  490. AvailAllocUnits, {Available allocation units}
  491. TotalAllocUnits : DWORD; {Total allocation units}
  492. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  493. END;
  494. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  495. VAR S : String;
  496. Rec : ExtendedFat32FreeSpaceRec;
  497. regs : registers;
  498. procedure OldDosDiskData;
  499. begin
  500. regs.dl:=drive;
  501. regs.ah:=$36;
  502. msdos(regs);
  503. if regs.ax<>$FFFF then
  504. begin
  505. if Free then
  506. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  507. else
  508. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  509. end
  510. else
  511. do_diskdata:=-1;
  512. end;
  513. BEGIN
  514. if LFNSupport then
  515. begin
  516. S:='C:\'#0;
  517. if Drive=0 then
  518. begin
  519. GetDir(Drive,S);
  520. Setlength(S,4);
  521. S[4]:=#0;
  522. end
  523. else
  524. S[1]:=chr(Drive+64);
  525. Rec.Strucversion:=0;
  526. Rec.RetSize := 0;
  527. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  528. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  529. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  530. regs.ds:=tb_segment;
  531. regs.di:=tb_offset;
  532. regs.es:=tb_segment;
  533. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  534. regs.ax:=$7303;
  535. msdos(regs);
  536. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  537. begin
  538. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  539. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  540. OldDosDiskData
  541. else
  542. if Free then
  543. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  544. else
  545. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  546. end
  547. else
  548. OldDosDiskData;
  549. end
  550. else
  551. OldDosDiskData;
  552. end;
  553. function diskfree(drive : byte) : int64;
  554. begin
  555. diskfree:=Do_DiskData(drive,TRUE);
  556. end;
  557. function disksize(drive : byte) : int64;
  558. begin
  559. disksize:=Do_DiskData(drive,false);
  560. end;
  561. {****************************************************************************
  562. Time Functions
  563. ****************************************************************************}
  564. Procedure GetLocalTime(var SystemTime: TSystemTime);
  565. var
  566. Regs: Registers;
  567. begin
  568. Regs.ah := $2C;
  569. RealIntr($21, Regs);
  570. SystemTime.Hour := Regs.Ch;
  571. SystemTime.Minute := Regs.Cl;
  572. SystemTime.Second := Regs.Dh;
  573. SystemTime.MilliSecond := Regs.Dl*10;
  574. Regs.ah := $2A;
  575. RealIntr($21, Regs);
  576. SystemTime.Year := Regs.Cx;
  577. SystemTime.Month := Regs.Dh;
  578. SystemTime.Day := Regs.Dl;
  579. end ;
  580. {****************************************************************************
  581. Misc Functions
  582. ****************************************************************************}
  583. procedure sysBeep;
  584. begin
  585. end;
  586. {****************************************************************************
  587. Locale Functions
  588. ****************************************************************************}
  589. { Codepage constants }
  590. const
  591. CP_US = 437;
  592. CP_MultiLingual = 850;
  593. CP_SlavicLatin2 = 852;
  594. CP_Turkish = 857;
  595. CP_Portugal = 860;
  596. CP_IceLand = 861;
  597. CP_Canada = 863;
  598. CP_NorwayDenmark = 865;
  599. { CountryInfo }
  600. type
  601. TCountryInfo = packed record
  602. InfoId: byte;
  603. case integer of
  604. 1: ( Size: word;
  605. CountryId: word;
  606. CodePage: word;
  607. CountryInfo: array[0..33] of byte );
  608. 2: ( UpperCaseTable: longint );
  609. 4: ( FilenameUpperCaseTable: longint );
  610. 5: ( FilecharacterTable: longint );
  611. 6: ( CollatingTable: longint );
  612. 7: ( DBCSLeadByteTable: longint );
  613. end ;
  614. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  615. Var Regs: Registers;
  616. begin
  617. Regs.AH := $65;
  618. Regs.AL := InfoId;
  619. Regs.BX := CodePage;
  620. Regs.DX := CountryId;
  621. Regs.ES := transfer_buffer div 16;
  622. Regs.DI := transfer_buffer and 15;
  623. Regs.CX := SizeOf(TCountryInfo);
  624. RealIntr($21, Regs);
  625. DosMemGet(transfer_buffer div 16,
  626. transfer_buffer and 15,
  627. CountryInfo, Regs.CX );
  628. end;
  629. procedure InitAnsi;
  630. var
  631. CountryInfo: TCountryInfo; i: integer;
  632. begin
  633. { Fill table entries 0 to 127 }
  634. for i := 0 to 96 do
  635. UpperCaseTable[i] := chr(i);
  636. for i := 97 to 122 do
  637. UpperCaseTable[i] := chr(i - 32);
  638. for i := 123 to 127 do
  639. UpperCaseTable[i] := chr(i);
  640. for i := 0 to 64 do
  641. LowerCaseTable[i] := chr(i);
  642. for i := 65 to 90 do
  643. LowerCaseTable[i] := chr(i + 32);
  644. for i := 91 to 255 do
  645. LowerCaseTable[i] := chr(i);
  646. { Get country and codepage info }
  647. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  648. if CountryInfo.CodePage = 850 then
  649. begin
  650. { Special, known case }
  651. Move(CP850UCT, UpperCaseTable[128], 128);
  652. Move(CP850LCT, LowerCaseTable[128], 128);
  653. end
  654. else
  655. begin
  656. { this needs to be checked !!
  657. this is correct only if UpperCaseTable is
  658. and Offset:Segment word record (PM) }
  659. { get the uppercase table from dosmemory }
  660. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  661. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  662. for i := 128 to 255 do
  663. begin
  664. { Never modify the lowercase of any char if ord(char) < 127 }
  665. if (UpperCaseTable[i] <> chr(i)) and (ord(UpperCaseTable[i])>=128) then
  666. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  667. end;
  668. end;
  669. end;
  670. Procedure InitInternational;
  671. begin
  672. InitInternationalGeneric;
  673. InitAnsi;
  674. end;
  675. function SysErrorMessage(ErrorCode: Integer): String;
  676. begin
  677. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  678. end;
  679. {****************************************************************************
  680. Os utils
  681. ****************************************************************************}
  682. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  683. begin
  684. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  685. end;
  686. Function GetEnvironmentVariableCount : Integer;
  687. begin
  688. Result:=FPCCountEnvVar(EnvP);
  689. end;
  690. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  691. begin
  692. Result:=FPCGetEnvStrFromP(Envp,Index);
  693. end;
  694. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  695. var
  696. e : EOSError;
  697. CommandLine: AnsiString;
  698. begin
  699. dos.exec_ansistring(path,comline);
  700. if (Dos.DosError <> 0) then
  701. begin
  702. if ComLine <> '' then
  703. CommandLine := Path + ' ' + ComLine
  704. else
  705. CommandLine := Path;
  706. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  707. e.ErrorCode:=Dos.DosError;
  708. raise e;
  709. end;
  710. Result := DosExitCode;
  711. end;
  712. function ExecuteProcess (const Path: RawByteString;
  713. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  714. var
  715. CommandLine: RawByteString;
  716. I: integer;
  717. begin
  718. Commandline := '';
  719. for I := 0 to High (ComLine) do
  720. if Pos (' ', ComLine [I]) <> 0 then
  721. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  722. else
  723. CommandLine := CommandLine + ' ' + Comline [I];
  724. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  725. end;
  726. function ExecuteProcess(Const Path: unicodeString; Const ComLine: unicodeString;Flags:TExecuteFlags=[]):integer;
  727. var
  728. e : EOSError;
  729. CommandLine: UnicodeString;
  730. begin
  731. dos.exec_ansistring(path,comline);
  732. if (Dos.DosError <> 0) then
  733. begin
  734. if ComLine <> '' then
  735. CommandLine := Path + ' ' + ComLine
  736. else
  737. CommandLine := Path;
  738. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  739. e.ErrorCode:=Dos.DosError;
  740. raise e;
  741. end;
  742. Result := DosExitCode;
  743. end;
  744. function ExecuteProcess (const Path: unicodeString;
  745. const ComLine: array of unicodeString;Flags:TExecuteFlags=[]): integer;
  746. var
  747. CommandLine: UnicodeString;
  748. I: integer;
  749. begin
  750. Commandline := '';
  751. for I := 0 to High (ComLine) do
  752. if Pos (' ', ComLine [I]) <> 0 then
  753. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  754. else
  755. CommandLine := CommandLine + ' ' + Comline [I];
  756. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  757. end;
  758. {*************************************************************************
  759. Sleep
  760. *************************************************************************}
  761. procedure Sleep (MilliSeconds: Cardinal);
  762. var
  763. R: Registers;
  764. T0, T1, T2: int64;
  765. DayOver: boolean;
  766. begin
  767. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  768. because it should be supported in all DOS versions. Not precise at all,
  769. though - the smallest step is 10 ms even in the best case. *)
  770. R.AH := $2C;
  771. RealIntr($21, R);
  772. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  773. T2 := T0 + MilliSeconds;
  774. DayOver := T2 > (24 * 3600000);
  775. repeat
  776. Intr ($28, R);
  777. (* R.AH := $2C; - should be preserved. *)
  778. RealIntr($21, R);
  779. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  780. if DayOver and (T1 < T0) then
  781. Inc (T1, 24 * 3600000);
  782. until T1 >= T2;
  783. end;
  784. {****************************************************************************
  785. Initialization code
  786. ****************************************************************************}
  787. Initialization
  788. InitExceptions; { Initialize exceptions. OS independent }
  789. InitInternational; { Initialize internationalization settings }
  790. OnBeep:=@SysBeep;
  791. Finalization
  792. DoneExceptions;
  793. end.