sysutils.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  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 FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  281. begin
  282. Result := False;
  283. end;
  284. function FileExists (const FileName: RawByteString; FollowLink : Boolean): boolean;
  285. var
  286. L: longint;
  287. begin
  288. if FileName = '' then
  289. Result := false
  290. else
  291. begin
  292. L := FileGetAttr (FileName);
  293. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  294. (* Neither VolumeIDs nor directories are files. *)
  295. end;
  296. end;
  297. Function DirectoryExists (Const Directory : RawByteString; FollowLink : Boolean) : Boolean;
  298. Var
  299. Dir : RawByteString;
  300. drive : byte;
  301. FADir, StoredIORes : longint;
  302. begin
  303. Dir:=Directory;
  304. if (length(dir)=2) and (dir[2]=':') and
  305. ((dir[1] in ['A'..'Z']) or (dir[1] in ['a'..'z'])) then
  306. begin
  307. { We want to test GetCurDir }
  308. if dir[1] in ['A'..'Z'] then
  309. drive:=ord(dir[1])-ord('A')+1
  310. else
  311. drive:=ord(dir[1])-ord('a')+1;
  312. {$push}
  313. {$I-}
  314. StoredIORes:=InOutRes;
  315. InOutRes:=0;
  316. GetDir(drive,dir);
  317. if InOutRes <> 0 then
  318. begin
  319. InOutRes:=StoredIORes;
  320. result:=false;
  321. exit;
  322. end;
  323. end;
  324. {$pop}
  325. if (Length (Dir) > 1) and
  326. (Dir [Length (Dir)] in AllowDirectorySeparators) and
  327. (* Do not remove '\' after ':' (root directory of a drive)
  328. or in '\\' (invalid path, possibly broken UNC path). *)
  329. not (Dir [Length (Dir) - 1] in (AllowDriveSeparators + AllowDirectorySeparators)) then
  330. dir:=copy(dir,1,length(dir)-1);
  331. (* FileGetAttr returns -1 on error *)
  332. FADir := FileGetAttr (Dir);
  333. Result := (FADir <> -1) and
  334. ((FADir and faDirectory) = faDirectory);
  335. end;
  336. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  337. Var Sr : PSearchrec;
  338. begin
  339. //!! Sr := New(PSearchRec);
  340. getmem(sr,sizeof(searchrec));
  341. Rslt.FindHandle := Sr;
  342. DOS.FindFirst(Path, Attr, Sr^);
  343. result := -DosError;
  344. if result = 0 then
  345. begin
  346. Rslt.Time := Sr^.Time;
  347. Rslt.Size := Sr^.Size;
  348. Rslt.Attr := Sr^.Attr;
  349. Rslt.ExcludeAttr := 0;
  350. Name := Sr^.Name;
  351. end ;
  352. end;
  353. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  354. var
  355. Sr: PSearchRec;
  356. begin
  357. Sr := PSearchRec(Rslt.FindHandle);
  358. if Sr <> nil then
  359. begin
  360. DOS.FindNext(Sr^);
  361. result := -DosError;
  362. if result = 0 then
  363. begin
  364. Rslt.Time := Sr^.Time;
  365. Rslt.Size := Sr^.Size;
  366. Rslt.Attr := Sr^.Attr;
  367. Rslt.ExcludeAttr := 0;
  368. Name := Sr^.Name;
  369. end;
  370. end;
  371. end;
  372. Procedure InternalFindClose(var Handle: Pointer);
  373. var
  374. Sr: PSearchRec;
  375. begin
  376. Sr := PSearchRec(Handle);
  377. if Sr <> nil then
  378. begin
  379. //!! Dispose(Sr);
  380. // This call is non dummy if LFNSupport is true PM
  381. DOS.FindClose(SR^);
  382. freemem(sr,sizeof(searchrec));
  383. end;
  384. Handle := nil;
  385. end;
  386. Function FileGetDate (Handle : THandle) : Longint;
  387. var
  388. Regs: registers;
  389. begin
  390. //!! for win95 an alternative function is available.
  391. Regs.bx := Handle;
  392. Regs.ax := $5700;
  393. ZeroSegRegs(Regs);
  394. MsDos(Regs);
  395. if Regs.Flags and fCarry <> 0 then
  396. result := -1
  397. else
  398. begin
  399. LongRec(result).Lo := Regs.cx;
  400. LongRec(result).Hi := Regs.dx;
  401. end ;
  402. end;
  403. Function FileSetDate (Handle : THandle; Age : Longint) : Longint;
  404. var
  405. Regs: registers;
  406. begin
  407. Regs.bx := Handle;
  408. Regs.ax := $5701;
  409. Regs.cx := Lo(Age);
  410. Regs.dx := Hi(Age);
  411. ZeroSegRegs(Regs);
  412. MsDos(Regs);
  413. if Regs.Flags and fCarry <> 0 then
  414. result := -Regs.Ax
  415. else
  416. result := 0;
  417. end;
  418. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  419. var
  420. Regs: registers;
  421. begin
  422. Regs.dx := Ofs(PChar(FileName)^);
  423. Regs.Ds := Seg(PChar(FileName)^);
  424. Regs.Es := 0; { because protected mode }
  425. if LFNSupport then
  426. begin
  427. Regs.Ax := $7143;
  428. Regs.Bx := 0;
  429. end
  430. else
  431. Regs.Ax := $4300;
  432. MsDos(Regs);
  433. if Regs.Flags and fCarry <> 0 then
  434. result := -1
  435. else
  436. result := Regs.Cx;
  437. end;
  438. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  439. var
  440. Regs: registers;
  441. begin
  442. Regs.dx := Ofs(PChar(FileName)^);
  443. Regs.Ds := Seg(PChar(FileName)^);
  444. Regs.Es := 0; { because protected mode }
  445. if LFNSupport then
  446. begin
  447. Regs.Ax := $7143;
  448. Regs.Bx := 1;
  449. end
  450. else
  451. Regs.Ax := $4301;
  452. Regs.Cx := Attr;
  453. MsDos(Regs);
  454. if Regs.Flags and fCarry <> 0 then
  455. result := -Regs.Ax
  456. else
  457. result := 0;
  458. end;
  459. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  460. var
  461. Regs: registers;
  462. begin
  463. Regs.dx := Ofs(PChar(FileName)^);
  464. Regs.Ds := Seg(PChar(FileName)^);
  465. Regs.Es := 0; { because protected mode }
  466. if LFNSupport then
  467. Regs.ax := $7141
  468. else
  469. Regs.ax := $4100;
  470. Regs.si := 0;
  471. Regs.cx := 0;
  472. MsDos(Regs);
  473. result := (Regs.Flags and fCarry = 0);
  474. end;
  475. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  476. var
  477. Regs: registers;
  478. begin
  479. Regs.dx := Ofs(PChar(OldName)^);
  480. Regs.Ds := Seg(PChar(OldName)^);
  481. Regs.di := Ofs(PChar(NewName)^);
  482. Regs.Es := Seg(PChar(NewName)^);
  483. if LFNSupport then
  484. Regs.ax := $7156
  485. else
  486. Regs.ax := $5600;
  487. Regs.cx := $ff;
  488. MsDos(Regs);
  489. result := (Regs.Flags and fCarry = 0);
  490. end;
  491. {****************************************************************************
  492. Disk Functions
  493. ****************************************************************************}
  494. TYPE ExtendedFat32FreeSpaceRec=packed Record
  495. RetSize : WORD; { (ret) size of returned structure}
  496. Strucversion : WORD; {(call) structure version (0000h)
  497. (ret) actual structure version (0000h)}
  498. SecPerClus, {number of sectors per cluster}
  499. BytePerSec, {number of bytes per sector}
  500. AvailClusters, {number of available clusters}
  501. TotalClusters, {total number of clusters on the drive}
  502. AvailPhysSect, {physical sectors available on the drive}
  503. TotalPhysSect, {total physical sectors on the drive}
  504. AvailAllocUnits, {Available allocation units}
  505. TotalAllocUnits : DWORD; {Total allocation units}
  506. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  507. END;
  508. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  509. VAR S : String;
  510. Rec : ExtendedFat32FreeSpaceRec;
  511. regs : registers;
  512. procedure OldDosDiskData;
  513. begin
  514. regs.dl:=drive;
  515. regs.ah:=$36;
  516. ZeroSegRegs(regs);
  517. msdos(regs);
  518. if regs.ax<>$FFFF then
  519. begin
  520. if Free then
  521. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  522. else
  523. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  524. end
  525. else
  526. do_diskdata:=-1;
  527. end;
  528. BEGIN
  529. if LFNSupport then
  530. begin
  531. S:='C:\'#0;
  532. if Drive=0 then
  533. begin
  534. GetDir(Drive,S);
  535. Setlength(S,4);
  536. S[4]:=#0;
  537. end
  538. else
  539. S[1]:=chr(Drive+64);
  540. Rec.Strucversion:=0;
  541. Rec.RetSize := 0;
  542. regs.dx:=Ofs(S[1]);
  543. regs.ds:=Seg(S[1]);
  544. regs.di:=Ofs(Rec);
  545. regs.es:=Seg(Rec);
  546. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  547. regs.ax:=$7303;
  548. msdos(regs);
  549. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  550. begin
  551. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  552. OldDosDiskData
  553. else
  554. if Free then
  555. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  556. else
  557. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  558. end
  559. else
  560. OldDosDiskData;
  561. end
  562. else
  563. OldDosDiskData;
  564. end;
  565. function diskfree(drive : byte) : int64;
  566. begin
  567. diskfree:=Do_DiskData(drive,TRUE);
  568. end;
  569. function disksize(drive : byte) : int64;
  570. begin
  571. disksize:=Do_DiskData(drive,false);
  572. end;
  573. {****************************************************************************
  574. Time Functions
  575. ****************************************************************************}
  576. Procedure GetLocalTime(var SystemTime: TSystemTime);
  577. var
  578. Regs: Registers;
  579. begin
  580. Regs.ah := $2C;
  581. ZeroSegRegs(Regs);
  582. MsDos(Regs);
  583. SystemTime.Hour := Regs.Ch;
  584. SystemTime.Minute := Regs.Cl;
  585. SystemTime.Second := Regs.Dh;
  586. SystemTime.MilliSecond := Regs.Dl*10;
  587. Regs.ah := $2A;
  588. MsDos(Regs);
  589. SystemTime.Year := Regs.Cx;
  590. SystemTime.Month := Regs.Dh;
  591. SystemTime.Day := Regs.Dl;
  592. end ;
  593. {****************************************************************************
  594. Misc Functions
  595. ****************************************************************************}
  596. procedure sysBeep;
  597. begin
  598. end;
  599. {****************************************************************************
  600. Locale Functions
  601. ****************************************************************************}
  602. { Codepage constants }
  603. const
  604. CP_US = 437;
  605. CP_MultiLingual = 850;
  606. CP_SlavicLatin2 = 852;
  607. CP_Turkish = 857;
  608. CP_Portugal = 860;
  609. CP_IceLand = 861;
  610. CP_Canada = 863;
  611. CP_NorwayDenmark = 865;
  612. { CountryInfo }
  613. type
  614. TCountryInfo = packed record
  615. InfoId: byte;
  616. case integer of
  617. 1: ( Size: word;
  618. CountryId: word;
  619. CodePage: word;
  620. CountryInfo: array[0..33] of byte );
  621. 2: ( UpperCaseTable: longint );
  622. 4: ( FilenameUpperCaseTable: longint );
  623. 5: ( FilecharacterTable: longint );
  624. 6: ( CollatingTable: longint );
  625. 7: ( DBCSLeadByteTable: longint );
  626. end ;
  627. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  628. Var Regs: Registers;
  629. begin
  630. Regs.AH := $65;
  631. Regs.AL := InfoId;
  632. Regs.BX := CodePage;
  633. Regs.DX := CountryId;
  634. Regs.ES := {transfer_buffer div 16}Seg(CountryInfo);
  635. Regs.DI := {transfer_buffer and 15}Ofs(CountryInfo);
  636. Regs.CX := SizeOf(TCountryInfo);
  637. Regs.DS := 0; { because protected mode }
  638. MsDos(Regs);
  639. end;
  640. procedure InitAnsi;
  641. type
  642. PFarChar = ^char; far;
  643. var
  644. CountryInfo: TCountryInfo; i: integer;
  645. begin
  646. { Fill table entries 0 to 127 }
  647. for i := 0 to 96 do
  648. UpperCaseTable[i] := chr(i);
  649. for i := 97 to 122 do
  650. UpperCaseTable[i] := chr(i - 32);
  651. for i := 123 to 127 do
  652. UpperCaseTable[i] := chr(i);
  653. for i := 0 to 64 do
  654. LowerCaseTable[i] := chr(i);
  655. for i := 65 to 90 do
  656. LowerCaseTable[i] := chr(i + 32);
  657. for i := 91 to 255 do
  658. LowerCaseTable[i] := chr(i);
  659. { Get country and codepage info }
  660. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  661. if CountryInfo.CodePage = 850 then
  662. begin
  663. { Special, known case }
  664. Move(CP850UCT, UpperCaseTable[128], 128);
  665. Move(CP850LCT, LowerCaseTable[128], 128);
  666. end
  667. else
  668. begin
  669. { this needs to be checked !!
  670. this is correct only if UpperCaseTable is
  671. and Offset:Segment word record (PM) }
  672. { get the uppercase table from dosmemory }
  673. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  674. for i := 128 to 255 do
  675. begin
  676. { TODO: do this properly }
  677. UpperCaseTable[i] := Chr(i){PFarChar(CountryInfo.UpperCaseTable)[i+(2-128)]};
  678. if UpperCaseTable[i] <> chr(i) then
  679. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  680. end;
  681. end;
  682. end;
  683. Procedure InitInternational;
  684. begin
  685. InitInternationalGeneric;
  686. InitAnsi;
  687. end;
  688. function SysErrorMessage(ErrorCode: Integer): String;
  689. begin
  690. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  691. end;
  692. {****************************************************************************
  693. Os utils
  694. ****************************************************************************}
  695. {$if defined(FPC_MM_TINY) or defined(FPC_MM_SMALL) or defined(FPC_MM_MEDIUM)}
  696. { environment handling for near data memory models }
  697. function far_strpas(p: pfarchar): string;
  698. begin
  699. Result:='';
  700. if p<>nil then
  701. while p^<>#0 do
  702. begin
  703. Result:=Result+p^;
  704. Inc(p);
  705. end;
  706. end;
  707. Function small_FPCGetEnvVarFromP(EP : PPFarChar; EnvVar : String) : String;
  708. var
  709. hp : ppfarchar;
  710. lenvvar,hs : string;
  711. eqpos : smallint;
  712. begin
  713. lenvvar:=upcase(envvar);
  714. hp:=EP;
  715. Result:='';
  716. If (hp<>Nil) then
  717. while assigned(hp^) do
  718. begin
  719. hs:=far_strpas(hp^);
  720. eqpos:=pos('=',hs);
  721. if upcase(copy(hs,1,eqpos-1))=lenvvar then
  722. begin
  723. Result:=copy(hs,eqpos+1,length(hs)-eqpos);
  724. exit;
  725. end;
  726. inc(hp);
  727. end;
  728. end;
  729. Function small_FPCGetEnvStrFromP(EP : PPFarChar; Index : SmallInt) : String;
  730. begin
  731. Result:='';
  732. while assigned(EP^) and (Index>1) do
  733. begin
  734. dec(Index);
  735. inc(EP);
  736. end;
  737. if Assigned(EP^) then
  738. Result:=far_strpas(EP^);
  739. end;
  740. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  741. begin
  742. Result:=small_FPCGetEnvVarFromP(envp,EnvVar);
  743. end;
  744. Function GetEnvironmentVariableCount : Integer;
  745. begin
  746. Result:=dos_env_count;
  747. end;
  748. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  749. begin
  750. Result:=small_FPCGetEnvStrFromP(Envp,Index);
  751. end;
  752. {$else}
  753. { environment handling for far data memory models }
  754. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  755. begin
  756. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  757. end;
  758. Function GetEnvironmentVariableCount : Integer;
  759. begin
  760. Result:=dos_env_count;
  761. end;
  762. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  763. begin
  764. Result:=FPCGetEnvStrFromP(Envp,Index);
  765. end;
  766. {$endif}
  767. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  768. var
  769. e : EOSError;
  770. CommandLine: RawByteString;
  771. begin
  772. dos.exec_ansistring(path,comline);
  773. if (Dos.DosError <> 0) then
  774. begin
  775. if ComLine <> '' then
  776. CommandLine := Path + ' ' + ComLine
  777. else
  778. CommandLine := Path;
  779. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  780. e.ErrorCode:=Dos.DosError;
  781. raise e;
  782. end;
  783. Result := DosExitCode;
  784. end;
  785. function ExecuteProcess (const Path: RawByteString;
  786. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  787. var
  788. CommandLine: RawByteString;
  789. I: integer;
  790. begin
  791. Commandline := '';
  792. for I := 0 to High (ComLine) do
  793. if Pos (' ', ComLine [I]) <> 0 then
  794. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  795. else
  796. CommandLine := CommandLine + ' ' + Comline [I];
  797. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  798. end;
  799. {*************************************************************************
  800. Sleep
  801. *************************************************************************}
  802. procedure Sleep (MilliSeconds: Cardinal);
  803. var
  804. ticks: LongInt;
  805. m: MSG;
  806. begin
  807. ticks:=GetTickCount;
  808. repeat
  809. if PeekMessage(FarAddr(m),0,0,0,1) then
  810. begin
  811. TranslateMessage(FarAddr(m));
  812. DispatchMessage(FarAddr(m));
  813. end;
  814. until (GetTickCount-ticks)>=MilliSeconds;
  815. end;
  816. {****************************************************************************
  817. Initialization code
  818. ****************************************************************************}
  819. Initialization
  820. InitExceptions; { Initialize exceptions. OS independent }
  821. InitInternational; { Initialize internationalization settings }
  822. OnBeep:=@SysBeep;
  823. Finalization
  824. DoneExceptions;
  825. FreeTerminateProcs;
  826. end.