sysutils.pp 23 KB

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