sysutils.pp 22 KB

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