sysutils.pp 23 KB

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