sysutils.pp 23 KB

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