sysutils.pp 24 KB

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