2
0

sysutils.pp 23 KB

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