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. {$IFDEF UNICODERTL}
  18. {$MODESWITCH UNICODESTRINGS}
  19. {$ELSE}
  20. {$H+}
  21. {$ENDIF}
  22. {$modeswitch typehelpers}
  23. {$modeswitch advancedrecords}
  24. uses
  25. wintypes;
  26. {$DEFINE HAS_SLEEP}
  27. { used OS file system APIs use ansistring }
  28. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  29. { OS has an ansistring/single byte environment variable API }
  30. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  31. { Include platform independent interface part }
  32. {$i sysutilh.inc}
  33. implementation
  34. uses
  35. sysconst,dos,winprocs;
  36. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  37. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  38. {$DEFINE executeprocuni} (* Only 1 byte version of ExecuteProcess is provided by the OS *)
  39. {$DEFINE HASEXTRACTSHORTPATHNAME}
  40. function ExtractShortPathName(Const FileName : RawByteString) : RawByteString;
  41. var
  42. Regs: registers;
  43. c: array [0..255] of AnsiChar;
  44. begin
  45. if LFNSupport then
  46. begin
  47. Regs.ax:=$7160;
  48. Regs.cx:=1;
  49. Regs.ds:=Seg(PAnsiChar(FileName)^);
  50. Regs.si:=Ofs(PAnsiChar(FileName)^);
  51. Regs.es:=Seg(c);
  52. Regs.di:=Ofs(c);
  53. MsDos(Regs);
  54. if (Regs.Flags and fCarry) <> 0 then
  55. Result:=''
  56. else
  57. Result:=StrPas(@c[0]);
  58. end
  59. else
  60. Result:=FileName;
  61. end;
  62. function ExtractShortPathName(Const FileName : UnicodeString) : UnicodeString;
  63. begin
  64. Result:=ExtractShortPathName(ToSingleByteFileSystemEncodedFileName(FileName));
  65. end;
  66. { Include platform independent implementation part }
  67. {$i sysutils.inc}
  68. type
  69. PFarChar=^AnsiChar;far;
  70. PPFarChar=^PFarChar;
  71. var
  72. dos_env_count:smallint;external name '__dos_env_count';
  73. { This is implemented inside system unit }
  74. function envp:PPFarChar;external name '__fpc_envp';
  75. { in protected mode, loading invalid values into segment registers causes an
  76. exception, so we use this function to initialize our Registers structure }
  77. procedure ZeroSegRegs(var regs: Registers); inline;
  78. begin
  79. regs.DS:=0;
  80. regs.ES:=0;
  81. end;
  82. {****************************************************************************
  83. File Functions
  84. ****************************************************************************}
  85. { some internal constants }
  86. const
  87. ofRead = $0000; { Open for reading }
  88. ofWrite = $0001; { Open for writing }
  89. ofReadWrite = $0002; { Open for reading/writing }
  90. faFail = $0000; { Fail if file does not exist }
  91. faCreate = $0010; { Create if file does not exist }
  92. faOpen = $0001; { Open if file exists }
  93. faOpenReplace = $0002; { Clear if file exists }
  94. Type
  95. PSearchrec = ^Searchrec;
  96. { Native OpenFile function.
  97. if return value <> 0 call failed. }
  98. function OpenFile(const FileName: RawByteString; var Handle: THandle; Mode, Action: word): longint;
  99. var
  100. Regs: registers;
  101. begin
  102. result := 0;
  103. Handle := UnusedHandle;
  104. if LFNSupport then
  105. begin
  106. Regs.ax := $716c; { Use LFN Open/Create API }
  107. Regs.dx := Action; { Action if file does/doesn't exist }
  108. Regs.si := Ofs(PAnsiChar(FileName)^);
  109. Regs.bx := $2000 + (Mode and $ff); { File open mode }
  110. end
  111. else
  112. begin
  113. if (Action and $00f0) <> 0 then
  114. Regs.ax := $3c00 { Map to Create/Replace API }
  115. else
  116. Regs.ax := $3d00 + (Mode and $ff); { Map to Open_Existing API }
  117. Regs.dx := Ofs(PAnsiChar(FileName)^);
  118. end;
  119. Regs.Ds := Seg(PAnsiChar(FileName)^);
  120. Regs.cx := $20; { Attributes }
  121. Regs.Es := 0; { because protected mode }
  122. MsDos(Regs);
  123. if (Regs.Flags and fCarry) <> 0 then
  124. result := Regs.Ax
  125. else
  126. Handle := Regs.Ax;
  127. end;
  128. Function FileOpen (Const FileName : RawByteString; Mode : Integer) : THandle;
  129. var
  130. e: integer;
  131. Begin
  132. e := OpenFile(FileName, result, Mode, faOpen);
  133. if e <> 0 then
  134. result := -1;
  135. end;
  136. Function FileCreate (Const FileName : RawByteString) : THandle;
  137. var
  138. e: integer;
  139. begin
  140. e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
  141. if e <> 0 then
  142. result := -1;
  143. end;
  144. Function FileCreate (Const FileName : RawByteString; ShareMode:integer; Rights : integer) : THandle;
  145. begin
  146. FileCreate:=FileCreate(FileName);
  147. end;
  148. Function FileCreate (Const FileName : RawByteString; Rights:integer) : THandle;
  149. begin
  150. FileCreate:=FileCreate(FileName);
  151. end;
  152. Function FileRead (Handle : THandle; Out Buffer; Count : longint) : Longint;
  153. var
  154. regs : registers;
  155. size,
  156. readsize : longint;
  157. begin
  158. readsize:=0;
  159. while Count > 0 do
  160. begin
  161. if Count>65535 then
  162. size:=65535
  163. else
  164. size:=Count;
  165. regs.cx:=size;
  166. regs.dx:=Ofs(Buffer);
  167. regs.ds:=Seg(Buffer);
  168. regs.bx:=Handle;
  169. regs.ax:=$3f00;
  170. regs.es:=0; { because protected mode }
  171. MsDos(regs);
  172. if (regs.flags and fCarry) <> 0 then
  173. begin
  174. Result:=-1;
  175. exit;
  176. end;
  177. inc(readsize,regs.ax);
  178. dec(Count,regs.ax);
  179. { stop when not the specified size is read }
  180. if regs.ax<size then
  181. break;
  182. end;
  183. Result:=readsize;
  184. end;
  185. Function FileWrite (Handle : THandle; const Buffer; Count : Longint) : Longint;
  186. var
  187. regs : registers;
  188. size,
  189. writesize : longint;
  190. begin
  191. writesize:=0;
  192. while Count > 0 do
  193. begin
  194. if Count>65535 then
  195. size:=65535
  196. else
  197. size:=Count;
  198. regs.cx:=size;
  199. regs.dx:=Ofs(Buffer);
  200. regs.ds:=Seg(Buffer);
  201. regs.bx:=Handle;
  202. regs.ax:=$4000;
  203. regs.es:=0; { because protected mode }
  204. MsDos(regs);
  205. if (regs.flags and fCarry) <> 0 then
  206. begin
  207. Result:=-1;
  208. exit;
  209. end;
  210. inc(writesize,regs.ax);
  211. dec(Count,regs.ax);
  212. { stop when not the specified size is written }
  213. if regs.ax<size then
  214. break;
  215. end;
  216. Result:=WriteSize;
  217. end;
  218. Function FileSeek (Handle : THandle; FOffset, Origin : Longint) : Longint;
  219. var
  220. Regs: registers;
  221. begin
  222. Regs.ah := $42;
  223. Regs.Al := Origin;
  224. Regs.dx := Lo(FOffset);
  225. Regs.cx := Hi(FOffset);
  226. Regs.bx := Handle;
  227. ZeroSegRegs(Regs);
  228. MsDos(Regs);
  229. if Regs.Flags and fCarry <> 0 then
  230. result := -1
  231. else begin
  232. LongRec(result).Lo := Regs.Ax;
  233. LongRec(result).Hi := Regs.Dx;
  234. end ;
  235. end;
  236. Function FileSeek (Handle : THandle; FOffset: Int64; Origin: {Integer}Longint) : Int64;
  237. begin
  238. {$warning need to add 64bit call }
  239. FileSeek:=FileSeek(Handle,Longint(FOffset),Longint(Origin));
  240. end;
  241. Procedure FileClose (Handle : THandle);
  242. var
  243. Regs: registers;
  244. begin
  245. if Handle<=4 then
  246. exit;
  247. Regs.ax := $3e00;
  248. Regs.bx := Handle;
  249. ZeroSegRegs(Regs);
  250. MsDos(Regs);
  251. end;
  252. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  253. var
  254. regs : registers;
  255. begin
  256. if Size > high (longint) then
  257. FileTruncate := false
  258. else
  259. begin
  260. FileSeek(Handle,Size,0);
  261. Regs.cx := 0;
  262. Regs.dx := 0{tb_offset};
  263. Regs.ds := 0{tb_segment};
  264. Regs.bx := Handle;
  265. Regs.ax:=$4000;
  266. Regs.es := 0; { because protected mode }
  267. MsDos(Regs);
  268. FileTruncate:=(regs.flags and fCarry)=0;
  269. end;
  270. end;
  271. Function FileAge (Const FileName : RawByteString): Int64;
  272. var Handle: longint;
  273. begin
  274. Handle := FileOpen(FileName, 0);
  275. if Handle <> -1 then
  276. begin
  277. result := FileGetDate(Handle);
  278. FileClose(Handle);
  279. end
  280. else
  281. result := -1;
  282. end;
  283. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  284. begin
  285. Result := False;
  286. end;
  287. function FileExists (const FileName: RawByteString; FollowLink : Boolean): boolean;
  288. var
  289. L: longint;
  290. begin
  291. if FileName = '' then
  292. Result := false
  293. else
  294. begin
  295. L := FileGetAttr (FileName);
  296. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  297. (* Neither VolumeIDs nor directories are files. *)
  298. end;
  299. end;
  300. Function DirectoryExists (Const Directory : RawByteString; FollowLink : Boolean) : Boolean;
  301. Var
  302. Dir : RawByteString;
  303. drive : byte;
  304. FADir, StoredIORes : longint;
  305. begin
  306. Dir:=Directory;
  307. if (length(dir)=2) and (dir[2]=':') and
  308. ((dir[1] in ['A'..'Z']) or (dir[1] in ['a'..'z'])) then
  309. begin
  310. { We want to test GetCurDir }
  311. if dir[1] in ['A'..'Z'] then
  312. drive:=ord(dir[1])-ord('A')+1
  313. else
  314. drive:=ord(dir[1])-ord('a')+1;
  315. {$push}
  316. {$I-}
  317. StoredIORes:=InOutRes;
  318. InOutRes:=0;
  319. GetDir(drive,dir);
  320. if InOutRes <> 0 then
  321. begin
  322. InOutRes:=StoredIORes;
  323. result:=false;
  324. exit;
  325. end;
  326. end;
  327. {$pop}
  328. if (Length (Dir) > 1) and
  329. (Dir [Length (Dir)] in AllowDirectorySeparators) and
  330. (* Do not remove '\' after ':' (root directory of a drive)
  331. or in '\\' (invalid path, possibly broken UNC path). *)
  332. not (Dir [Length (Dir) - 1] in (AllowDriveSeparators + AllowDirectorySeparators)) then
  333. dir:=copy(dir,1,length(dir)-1);
  334. (* FileGetAttr returns -1 on error *)
  335. FADir := FileGetAttr (Dir);
  336. Result := (FADir <> -1) and
  337. ((FADir and faDirectory) = faDirectory);
  338. end;
  339. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  340. Var Sr : PSearchrec;
  341. begin
  342. //!! Sr := New(PSearchRec);
  343. getmem(sr,sizeof(searchrec));
  344. Rslt.FindHandle := Sr;
  345. DOS.FindFirst(Path, Attr, Sr^);
  346. result := -DosError;
  347. if result = 0 then
  348. begin
  349. Rslt.Time := Sr^.Time;
  350. Rslt.Size := Sr^.Size;
  351. Rslt.Attr := Sr^.Attr;
  352. Rslt.ExcludeAttr := 0;
  353. Name := Sr^.Name;
  354. end ;
  355. end;
  356. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  357. var
  358. Sr: PSearchRec;
  359. begin
  360. Sr := PSearchRec(Rslt.FindHandle);
  361. if Sr <> nil then
  362. begin
  363. DOS.FindNext(Sr^);
  364. result := -DosError;
  365. if result = 0 then
  366. begin
  367. Rslt.Time := Sr^.Time;
  368. Rslt.Size := Sr^.Size;
  369. Rslt.Attr := Sr^.Attr;
  370. Rslt.ExcludeAttr := 0;
  371. Name := Sr^.Name;
  372. end;
  373. end;
  374. end;
  375. Procedure InternalFindClose(var Handle: Pointer);
  376. var
  377. Sr: PSearchRec;
  378. begin
  379. Sr := PSearchRec(Handle);
  380. if Sr <> nil then
  381. begin
  382. //!! Dispose(Sr);
  383. // This call is non dummy if LFNSupport is true PM
  384. DOS.FindClose(SR^);
  385. freemem(sr,sizeof(searchrec));
  386. end;
  387. Handle := nil;
  388. end;
  389. Function FileGetDate (Handle : THandle) : Int64;
  390. var
  391. Regs: registers;
  392. begin
  393. //!! for win95 an alternative function is available.
  394. Regs.bx := Handle;
  395. Regs.ax := $5700;
  396. ZeroSegRegs(Regs);
  397. MsDos(Regs);
  398. if Regs.Flags and fCarry <> 0 then
  399. result := -1
  400. else
  401. Result:=(Regs.dx shl 16) or Regs.cx;
  402. end;
  403. Function FileSetDate (Handle : THandle; Age : Int64) : Longint;
  404. var
  405. Regs: registers;
  406. begin
  407. Regs.bx := Handle;
  408. Regs.ax := $5701;
  409. Regs.cx := Lo(dword(Age));
  410. Regs.dx := Hi(dword(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(PAnsiChar(FileName)^);
  423. Regs.Ds := Seg(PAnsiChar(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(PAnsiChar(FileName)^);
  443. Regs.Ds := Seg(PAnsiChar(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(PAnsiChar(FileName)^);
  464. Regs.Ds := Seg(PAnsiChar(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(PAnsiChar(OldName)^);
  480. Regs.Ds := Seg(PAnsiChar(OldName)^);
  481. Regs.di := Ofs(PAnsiChar(NewName)^);
  482. Regs.Es := Seg(PAnsiChar(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 = ^AnsiChar; 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. FreeTerminateProcs;
  825. DoneExceptions;
  826. end.