sysutils.pp 23 KB

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