sysutils.pp 23 KB

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