sysutils.pp 23 KB

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