sysutils.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  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. SystemTime.DayOfWeek := Regs.Al;
  580. end ;
  581. {****************************************************************************
  582. Misc Functions
  583. ****************************************************************************}
  584. const
  585. BeepChars: array [1..2] of char = #7'$';
  586. procedure sysBeep;
  587. var
  588. Regs: Registers;
  589. begin
  590. Regs.dx := Ofs (BeepChars);
  591. Regs.ah := 9;
  592. MsDos (Regs);
  593. end;
  594. {****************************************************************************
  595. Locale Functions
  596. ****************************************************************************}
  597. { Codepage constants }
  598. const
  599. CP_US = 437;
  600. CP_MultiLingual = 850;
  601. CP_SlavicLatin2 = 852;
  602. CP_Turkish = 857;
  603. CP_Portugal = 860;
  604. CP_IceLand = 861;
  605. CP_Canada = 863;
  606. CP_NorwayDenmark = 865;
  607. { CountryInfo }
  608. type
  609. TCountryInfo = packed record
  610. InfoId: byte;
  611. case integer of
  612. 1: ( Size: word;
  613. CountryId: word;
  614. CodePage: word;
  615. CountryInfo: array[0..33] of byte );
  616. 2: ( UpperCaseTable: longint );
  617. 4: ( FilenameUpperCaseTable: longint );
  618. 5: ( FilecharacterTable: longint );
  619. 6: ( CollatingTable: longint );
  620. 7: ( DBCSLeadByteTable: longint );
  621. end ;
  622. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  623. Var Regs: Registers;
  624. begin
  625. Regs.AH := $65;
  626. Regs.AL := InfoId;
  627. Regs.BX := CodePage;
  628. Regs.DX := CountryId;
  629. Regs.ES := transfer_buffer div 16;
  630. Regs.DI := transfer_buffer and 15;
  631. Regs.CX := SizeOf(TCountryInfo);
  632. RealIntr($21, Regs);
  633. DosMemGet(transfer_buffer div 16,
  634. transfer_buffer and 15,
  635. CountryInfo, Regs.CX );
  636. end;
  637. procedure InitAnsi;
  638. var
  639. CountryInfo: TCountryInfo; i: integer;
  640. begin
  641. { Fill table entries 0 to 127 }
  642. for i := 0 to 96 do
  643. UpperCaseTable[i] := chr(i);
  644. for i := 97 to 122 do
  645. UpperCaseTable[i] := chr(i - 32);
  646. for i := 123 to 127 do
  647. UpperCaseTable[i] := chr(i);
  648. for i := 0 to 64 do
  649. LowerCaseTable[i] := chr(i);
  650. for i := 65 to 90 do
  651. LowerCaseTable[i] := chr(i + 32);
  652. for i := 91 to 255 do
  653. LowerCaseTable[i] := chr(i);
  654. { Get country and codepage info }
  655. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  656. if CountryInfo.CodePage = 850 then
  657. begin
  658. { Special, known case }
  659. Move(CP850UCT, UpperCaseTable[128], 128);
  660. Move(CP850LCT, LowerCaseTable[128], 128);
  661. end
  662. else
  663. begin
  664. { this needs to be checked !!
  665. this is correct only if UpperCaseTable is
  666. and Offset:Segment word record (PM) }
  667. { get the uppercase table from dosmemory }
  668. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  669. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  670. for i := 128 to 255 do
  671. begin
  672. { Never modify the lowercase of any char if ord(char) < 127 }
  673. if (UpperCaseTable[i] <> chr(i)) and (ord(UpperCaseTable[i])>=128) then
  674. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  675. end;
  676. end;
  677. end;
  678. Procedure InitInternational;
  679. begin
  680. InitInternationalGeneric;
  681. InitAnsi;
  682. end;
  683. function SysErrorMessage(ErrorCode: Integer): String;
  684. begin
  685. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  686. end;
  687. {****************************************************************************
  688. Os utils
  689. ****************************************************************************}
  690. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  691. begin
  692. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  693. end;
  694. Function GetEnvironmentVariableCount : Integer;
  695. begin
  696. Result:=FPCCountEnvVar(EnvP);
  697. end;
  698. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  699. begin
  700. Result:=FPCGetEnvStrFromP(Envp,Index);
  701. end;
  702. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  703. var
  704. e : EOSError;
  705. CommandLine: AnsiString;
  706. begin
  707. dos.exec_ansistring(path,comline);
  708. if (Dos.DosError <> 0) then
  709. begin
  710. if ComLine <> '' then
  711. CommandLine := Path + ' ' + ComLine
  712. else
  713. CommandLine := Path;
  714. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  715. e.ErrorCode:=Dos.DosError;
  716. raise e;
  717. end;
  718. Result := DosExitCode;
  719. end;
  720. function ExecuteProcess (const Path: RawByteString;
  721. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  722. var
  723. CommandLine: RawByteString;
  724. I: integer;
  725. begin
  726. Commandline := '';
  727. for I := 0 to High (ComLine) do
  728. if Pos (' ', ComLine [I]) <> 0 then
  729. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  730. else
  731. CommandLine := CommandLine + ' ' + Comline [I];
  732. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  733. end;
  734. function ExecuteProcess(Const Path: unicodeString; Const ComLine: unicodeString;Flags:TExecuteFlags=[]):integer;
  735. var
  736. e : EOSError;
  737. CommandLine: UnicodeString;
  738. begin
  739. dos.exec_ansistring(path,comline);
  740. if (Dos.DosError <> 0) then
  741. begin
  742. if ComLine <> '' then
  743. CommandLine := Path + ' ' + ComLine
  744. else
  745. CommandLine := Path;
  746. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  747. e.ErrorCode:=Dos.DosError;
  748. raise e;
  749. end;
  750. Result := DosExitCode;
  751. end;
  752. function ExecuteProcess (const Path: unicodeString;
  753. const ComLine: array of unicodeString;Flags:TExecuteFlags=[]): integer;
  754. var
  755. CommandLine: UnicodeString;
  756. I: integer;
  757. begin
  758. Commandline := '';
  759. for I := 0 to High (ComLine) do
  760. if Pos (' ', ComLine [I]) <> 0 then
  761. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  762. else
  763. CommandLine := CommandLine + ' ' + Comline [I];
  764. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  765. end;
  766. {*************************************************************************
  767. Sleep
  768. *************************************************************************}
  769. procedure Sleep (MilliSeconds: Cardinal);
  770. var
  771. R: Registers;
  772. T0, T1, T2: int64;
  773. DayOver: boolean;
  774. begin
  775. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  776. because it should be supported in all DOS versions. Not precise at all,
  777. though - the smallest step is 10 ms even in the best case. *)
  778. R.AH := $2C;
  779. RealIntr($21, R);
  780. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  781. T2 := T0 + MilliSeconds;
  782. DayOver := T2 > (24 * 3600000);
  783. repeat
  784. Intr ($28, R);
  785. (* R.AH := $2C; - should be preserved. *)
  786. RealIntr($21, R);
  787. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  788. if DayOver and (T1 < T0) then
  789. Inc (T1, 24 * 3600000);
  790. until T1 >= T2;
  791. end;
  792. {****************************************************************************
  793. Initialization code
  794. ****************************************************************************}
  795. Initialization
  796. InitExceptions; { Initialize exceptions. OS independent }
  797. InitInternational; { Initialize internationalization settings }
  798. OnBeep:=@SysBeep;
  799. Finalization
  800. FreeTerminateProcs;
  801. DoneExceptions;
  802. end.