sysutils.pp 23 KB

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