sysutils.pp 23 KB

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