sysutils.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  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 Watcom
  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. watcom,dos;
  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. {$DEFINE executeprocuni} (* Only 1 byte version of ExecuteProcess is provided by the OS *)
  29. { Include platform independent interface part }
  30. {$i sysutilh.inc}
  31. implementation
  32. uses
  33. sysconst;
  34. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  35. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  36. {$DEFINE HAS_LOCALTIMEZONEOFFSET}
  37. { Include platform independent implementation part }
  38. {$i sysutils.inc}
  39. {****************************************************************************
  40. File Functions
  41. ****************************************************************************}
  42. { some internal constants }
  43. const
  44. ofRead = $0000; { Open for reading }
  45. ofWrite = $0001; { Open for writing }
  46. ofReadWrite = $0002; { Open for reading/writing }
  47. faFail = $0000; { Fail if file does not exist }
  48. faCreate = $0010; { Create if file does not exist }
  49. faOpen = $0001; { Open if file exists }
  50. faOpenReplace = $0002; { Clear if file exists }
  51. Type
  52. PSearchrec = ^Searchrec;
  53. { converts S to a pchar and copies it to the transfer-buffer. }
  54. procedure StringToTB(const S: RawByteString);
  55. begin
  56. { include terminating null char }
  57. SysCopyToDos(longint(pointer(s)), Length(S) + 1);
  58. end ;
  59. { Native OpenFile function.
  60. if return value <> 0 call failed. }
  61. function OpenFile(const FileName: RawByteString; var Handle: longint; Mode, Action: word): longint;
  62. var
  63. Regs: registers;
  64. SystemFileName: RawByteString;
  65. begin
  66. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  67. result := 0;
  68. Handle := 0;
  69. StringToTB(SystemFileName);
  70. if LFNSupport then
  71. Regs.Eax := $716c { Use LFN Open/Create API }
  72. else { Check if Extended Open/Create API is safe to use }
  73. if lo(dosversion) < 7 then
  74. Regs.Eax := $3d00 + (Mode and $ff) { For now, map to Open API }
  75. else
  76. Regs.Eax := $6c00; { Use Extended Open/Create API }
  77. if Regs.Ah = $3d then
  78. begin
  79. if (Action and $00f0) <> 0 then
  80. Regs.Eax := $3c00; { Map to Create/Replace API }
  81. Regs.Ds := tb_segment;
  82. Regs.Edx := tb_offset;
  83. end
  84. else { LFN or Extended Open/Create API }
  85. begin
  86. Regs.Edx := Action; { Action if file exists/not exists }
  87. Regs.Ds := tb_segment;
  88. Regs.Esi := tb_offset;
  89. Regs.Ebx := $2000 + (Mode and $ff); { file open mode }
  90. end;
  91. Regs.Ecx := $20; { Attributes }
  92. RealIntr($21, Regs);
  93. if (Regs.Flags and CarryFlag) <> 0 then
  94. result := Regs.Ax
  95. else
  96. Handle := Regs.Ax;
  97. end;
  98. Function FileOpen (Const FileName : rawbytestring; Mode : Integer) : Longint;
  99. Var
  100. e: integer;
  101. Begin
  102. e := OpenFile(FileName, result, Mode, faOpen);
  103. if e <> 0 then
  104. result := -1;
  105. end;
  106. Function FileCreate (Const FileName : RawByteString) : Longint;
  107. var
  108. e: integer;
  109. begin
  110. e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
  111. if e <> 0 then
  112. result := -1;
  113. end;
  114. Function FileCreate (Const FileName : RawByteString; Rights:longint) : Longint;
  115. begin
  116. FileCreate:=FileCreate(FileName);
  117. end;
  118. Function FileCreate (Const FileName : RawByteString; ShareMode:longint; Rights: Longint) : Longint;
  119. begin
  120. FileCreate:=FileCreate(FileName);
  121. end;
  122. Function FileRead (Handle : Longint; Out Buffer; Count : longint) : Longint;
  123. var
  124. regs : registers;
  125. size,
  126. readsize : longint;
  127. begin
  128. readsize:=0;
  129. while Count > 0 do
  130. begin
  131. if Count>tb_size then
  132. size:=tb_size
  133. else
  134. size:=Count;
  135. regs.realecx:=size;
  136. regs.realedx:=tb_offset;
  137. regs.realds:=tb_segment;
  138. regs.realebx:=Handle;
  139. regs.realeax:=$3f00;
  140. RealIntr($21,regs);
  141. if (regs.realflags and carryflag) <> 0 then
  142. begin
  143. Result:=-1;
  144. exit;
  145. end;
  146. syscopyfromdos(Longint(@Buffer)+readsize,lo(regs.realeax));
  147. inc(readsize,lo(regs.realeax));
  148. dec(Count,lo(regs.realeax));
  149. { stop when not the specified size is read }
  150. if lo(regs.realeax)<size then
  151. break;
  152. end;
  153. Result:=readsize;
  154. end;
  155. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  156. var
  157. regs : registers;
  158. size,
  159. writesize : longint;
  160. begin
  161. writesize:=0;
  162. while Count > 0 do
  163. begin
  164. if Count>tb_size then
  165. size:=tb_size
  166. else
  167. size:=Count;
  168. syscopytodos(Longint(@Buffer)+writesize,size);
  169. regs.realecx:=size;
  170. regs.realedx:=tb_offset;
  171. regs.realds:=tb_segment;
  172. regs.realebx:=Handle;
  173. regs.realeax:=$4000;
  174. RealIntr($21,regs);
  175. if (regs.realflags and carryflag) <> 0 then
  176. begin
  177. Result:=-1;
  178. exit;
  179. end;
  180. inc(writesize,lo(regs.realeax));
  181. dec(Count,lo(regs.realeax));
  182. { stop when not the specified size is written }
  183. if lo(regs.realeax)<size then
  184. break;
  185. end;
  186. Result:=WriteSize;
  187. end;
  188. Function FileSeek (Handle, FOffset, Origin : Longint) : Longint;
  189. var
  190. Regs: registers;
  191. res: dword;
  192. begin
  193. Regs.Eax := $4200;
  194. Regs.Al := Origin;
  195. Regs.Edx := Lo(FOffset);
  196. Regs.Ecx := Hi(FOffset);
  197. Regs.Ebx := Handle;
  198. RealIntr($21, Regs);
  199. if Regs.Flags and CarryFlag <> 0 then
  200. result := -1
  201. else begin
  202. LongRec(res).Lo := Regs.Ax;
  203. LongRec(res).Hi := Regs.Dx;
  204. result:=res;
  205. end ;
  206. end;
  207. Function FileSeek (Handle : Longint; FOffset: Int64; Origin: Longint) : Int64;
  208. begin
  209. {$warning need to add 64bit call }
  210. FileSeek:=FileSeek(Handle,Longint(FOffset),Longint(Origin));
  211. end;
  212. Procedure FileClose (Handle : Longint);
  213. var
  214. Regs: registers;
  215. begin
  216. if Handle<=4 then
  217. exit;
  218. Regs.Eax := $3e00;
  219. Regs.Ebx := Handle;
  220. RealIntr($21, Regs);
  221. end;
  222. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  223. var
  224. regs : trealregs;
  225. begin
  226. if Size > high (longint) then
  227. FileTruncate := false
  228. else
  229. begin
  230. FileSeek(Handle,Size,0);
  231. Regs.realecx := 0;
  232. Regs.realedx := tb_offset;
  233. Regs.ds := tb_segment;
  234. Regs.ebx := Handle;
  235. Regs.eax:=$4000;
  236. RealIntr($21, Regs);
  237. FileTruncate:=(regs.realflags and carryflag)=0;
  238. end;
  239. end;
  240. Function FileAge (Const FileName : RawByteString): Int64;
  241. var Handle: longint;
  242. begin
  243. Handle := FileOpen(FileName, 0);
  244. if Handle <> -1 then
  245. begin
  246. result := FileGetDate(Handle);
  247. FileClose(Handle);
  248. end
  249. else
  250. result := -1;
  251. end;
  252. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  253. begin
  254. Result := False;
  255. end;
  256. function FileExists (const FileName: RawByteString; FollowLink : Boolean): boolean;
  257. var
  258. L: longint;
  259. begin
  260. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  261. if FileName = '' then
  262. Result := false
  263. else
  264. begin
  265. L := FileGetAttr (FileName);
  266. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  267. (* Neither VolumeIDs nor directories are files. *)
  268. end;
  269. end;
  270. function DirectoryExists (const Directory: RawByteString; FollowLink : Boolean): boolean;
  271. var
  272. L: longint;
  273. begin
  274. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  275. if Directory = '' then
  276. Result := false
  277. else
  278. begin
  279. if ((Length (Directory) = 2) or
  280. (Length (Directory) = 3) and
  281. (Directory [3] in AllowDirectorySeparators)) and
  282. (Directory [2] in AllowDriveSeparators) and
  283. (UpCase (Directory [1]) in ['A'..'Z']) then
  284. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  285. L := FileGetAttr (Directory + '.')
  286. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  287. (Length (Directory) > 1) and
  288. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  289. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  290. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  291. else
  292. L := FileGetAttr (Directory);
  293. Result := (L > 0) and (L and faDirectory = faDirectory);
  294. end;
  295. end;
  296. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  297. Var Sr : PSearchrec;
  298. begin
  299. //!! Sr := New(PSearchRec);
  300. getmem(sr,sizeof(searchrec));
  301. Rslt.FindHandle := longint(Sr);
  302. { FIXME: Dos version has shortstring interface -> discards encoding }
  303. DOS.FindFirst(Path, Attr, Sr^);
  304. result := -DosError;
  305. if result = 0 then
  306. begin
  307. Rslt.Time := Sr^.Time;
  308. Rslt.Size := Sr^.Size;
  309. Rslt.Attr := Sr^.Attr;
  310. Rslt.ExcludeAttr := 0;
  311. Name := Sr^.Name;
  312. SetCodePage(Name,DefaultFileSystemCodePage,False);
  313. end ;
  314. end;
  315. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  316. var
  317. Sr: PSearchRec;
  318. begin
  319. Sr := PSearchRec(Rslt.FindHandle);
  320. if Sr <> nil then
  321. begin
  322. DOS.FindNext(Sr^);
  323. result := -DosError;
  324. if result = 0 then
  325. begin
  326. Rslt.Time := Sr^.Time;
  327. Rslt.Size := Sr^.Size;
  328. Rslt.Attr := Sr^.Attr;
  329. Rslt.ExcludeAttr := 0;
  330. Name := Sr^.Name;
  331. SetCodePage(Name,DefaultFileSystemCodePage,False);
  332. end;
  333. end;
  334. end;
  335. Procedure InternalFindClose(var Handle: longint);
  336. var
  337. Sr: PSearchRec;
  338. begin
  339. Sr := PSearchRec(PtrUint(Handle));
  340. if Sr <> nil then
  341. begin
  342. //!! Dispose(Sr);
  343. // This call is non dummy if LFNSupport is true PM
  344. DOS.FindClose(SR^);
  345. freemem(sr,sizeof(searchrec));
  346. end;
  347. Handle := 0;
  348. end;
  349. Function FileGetDate (Handle : Longint) : Int64;
  350. var
  351. Regs: registers;
  352. res: dword;
  353. begin
  354. //!! for win95 an alternative function is available.
  355. Regs.Ebx := Handle;
  356. Regs.Eax := $5700;
  357. RealIntr($21, Regs);
  358. if Regs.Flags and CarryFlag <> 0 then
  359. result := -1
  360. else
  361. begin
  362. LongRec(res).Lo := Regs.cx;
  363. LongRec(res).Hi := Regs.dx;
  364. result := res;
  365. end ;
  366. end;
  367. Function FileSetDate (Handle: longint; Age: Int64) : Longint;
  368. var
  369. Regs: registers;
  370. begin
  371. Regs.Ebx := Handle;
  372. Regs.Eax := $5701;
  373. Regs.Ecx := Lo(dword(Age));
  374. Regs.Edx := Hi(dword(Age));
  375. RealIntr($21, Regs);
  376. if Regs.Flags and CarryFlag <> 0 then
  377. result := -Regs.Ax
  378. else
  379. result := 0;
  380. end;
  381. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  382. var
  383. Regs: registers;
  384. SystemFileName: RawByteString;
  385. begin
  386. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  387. StringToTB(SystemFileName);
  388. Regs.Edx := tb_offset;
  389. Regs.Ds := tb_segment;
  390. if LFNSupport then
  391. begin
  392. Regs.Ax := $7143;
  393. Regs.Bx := 0;
  394. end
  395. else
  396. Regs.Ax := $4300;
  397. RealIntr($21, Regs);
  398. if Regs.Flags and CarryFlag <> 0 then
  399. result := -1
  400. else
  401. result := Regs.Cx;
  402. end;
  403. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  404. var
  405. Regs: registers;
  406. SystemFileName: RawByteString;
  407. begin
  408. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  409. StringToTB(SystemFileName);
  410. Regs.Edx := tb_offset;
  411. Regs.Ds := tb_segment;
  412. if LFNSupport then
  413. begin
  414. Regs.Ax := $7143;
  415. Regs.Bx := 1;
  416. end
  417. else
  418. Regs.Ax := $4301;
  419. Regs.Cx := Attr;
  420. RealIntr($21, Regs);
  421. if Regs.Flags and CarryFlag <> 0 then
  422. result := -Regs.Ax
  423. else
  424. result := 0;
  425. end;
  426. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  427. var
  428. Regs: registers;
  429. SystemFileName: RawByteString;
  430. begin
  431. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  432. StringToTB(SystemFileName);
  433. Regs.Edx := tb_offset;
  434. Regs.Ds := tb_segment;
  435. if LFNSupport then
  436. Regs.Eax := $7141
  437. else
  438. Regs.Eax := $4100;
  439. Regs.Esi := 0;
  440. Regs.Ecx := 0;
  441. RealIntr($21, Regs);
  442. result := (Regs.Flags and CarryFlag = 0);
  443. end;
  444. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  445. var
  446. Regs: registers;
  447. OldSystemFileName, NewSystemFileName: RawByteString;
  448. begin
  449. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  450. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  451. StringToTB(OldSystemFileName + #0 + NewSystemFileName);
  452. Regs.Edx := tb_offset;
  453. Regs.Ds := tb_segment;
  454. Regs.Edi := tb_offset + Length(OldSystemFileName) + 1;
  455. Regs.Es := tb_segment;
  456. if LFNSupport then
  457. Regs.Eax := $7156
  458. else
  459. Regs.Eax := $5600;
  460. Regs.Ecx := $ff;
  461. RealIntr($21, Regs);
  462. result := (Regs.Flags and CarryFlag = 0);
  463. end;
  464. {****************************************************************************
  465. Disk Functions
  466. ****************************************************************************}
  467. TYPE ExtendedFat32FreeSpaceRec=packed Record
  468. RetSize : WORD; { (ret) size of returned structure}
  469. Strucversion : WORD; {(call) structure version (0000h)
  470. (ret) actual structure version (0000h)}
  471. SecPerClus, {number of sectors per cluster}
  472. BytePerSec, {number of bytes per sector}
  473. AvailClusters, {number of available clusters}
  474. TotalClusters, {total number of clusters on the drive}
  475. AvailPhysSect, {physical sectors available on the drive}
  476. TotalPhysSect, {total physical sectors on the drive}
  477. AvailAllocUnits, {Available allocation units}
  478. TotalAllocUnits : DWORD; {Total allocation units}
  479. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  480. END;
  481. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  482. VAR S : String;
  483. Rec : ExtendedFat32FreeSpaceRec;
  484. regs : registers;
  485. procedure OldDosDiskData;
  486. begin
  487. regs.dl:=drive;
  488. regs.ah:=$36;
  489. msdos(regs);
  490. if regs.ax<>$FFFF then
  491. begin
  492. if Free then
  493. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  494. else
  495. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  496. end
  497. else
  498. do_diskdata:=-1;
  499. end;
  500. BEGIN
  501. if LFNSupport then
  502. begin
  503. S:='C:\'#0;
  504. if Drive=0 then
  505. begin
  506. GetDir(Drive,S);
  507. Setlength(S,4);
  508. S[4]:=#0;
  509. end
  510. else
  511. S[1]:=chr(Drive+64);
  512. Rec.Strucversion:=0;
  513. Rec.RetSize := 0;
  514. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  515. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  516. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  517. regs.ds:=tb_segment;
  518. regs.di:=tb_offset;
  519. regs.es:=tb_segment;
  520. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  521. regs.ax:=$7303;
  522. msdos(regs);
  523. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  524. begin
  525. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  526. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  527. OldDosDiskData
  528. else
  529. if Free then
  530. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  531. else
  532. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  533. end
  534. else
  535. Do_DiskData:=-1;
  536. end
  537. else
  538. OldDosDiskData;
  539. end;
  540. function diskfree(drive : byte) : int64;
  541. begin
  542. diskfree:=Do_DiskData(drive,TRUE);
  543. end;
  544. function disksize(drive : byte) : int64;
  545. begin
  546. disksize:=Do_DiskData(drive,false);
  547. end;
  548. {****************************************************************************
  549. Time Functions
  550. ****************************************************************************}
  551. {$I tzenv.inc}
  552. Procedure GetLocalTime(var SystemTime: TSystemTime);
  553. var
  554. Regs: Registers;
  555. begin
  556. Regs.ah := $2C;
  557. RealIntr($21, Regs);
  558. SystemTime.Hour := Regs.Ch;
  559. SystemTime.Minute := Regs.Cl;
  560. SystemTime.Second := Regs.Dh;
  561. SystemTime.MilliSecond := Regs.Dl*10;
  562. Regs.ah := $2A;
  563. RealIntr($21, Regs);
  564. SystemTime.Year := Regs.Cx;
  565. SystemTime.Month := Regs.Dh;
  566. SystemTime.Day := Regs.Dl;
  567. SystemTime.DayOfWeek := Regs.Al;
  568. end ;
  569. {****************************************************************************
  570. Misc Functions
  571. ****************************************************************************}
  572. const
  573. BeepChars: array [1..2] of char = #7'$';
  574. procedure sysBeep;
  575. var
  576. Regs: Registers;
  577. begin
  578. Regs.dx := Ofs (BeepChars);
  579. Regs.ah := 9;
  580. MsDos (Regs);
  581. end;
  582. {****************************************************************************
  583. Locale Functions
  584. ****************************************************************************}
  585. { Codepage constants }
  586. const
  587. CP_US = 437;
  588. CP_MultiLingual = 850;
  589. CP_SlavicLatin2 = 852;
  590. CP_Turkish = 857;
  591. CP_Portugal = 860;
  592. CP_IceLand = 861;
  593. CP_Canada = 863;
  594. CP_NorwayDenmark = 865;
  595. { CountryInfo }
  596. type
  597. TCountryInfo = packed record
  598. InfoId: byte;
  599. case integer of
  600. 1: ( Size: word;
  601. CountryId: word;
  602. CodePage: word;
  603. CountryInfo: array[0..33] of byte );
  604. 2: ( UpperCaseTable: longint );
  605. 4: ( FilenameUpperCaseTable: longint );
  606. 5: ( FilecharacterTable: longint );
  607. 6: ( CollatingTable: longint );
  608. 7: ( DBCSLeadByteTable: longint );
  609. end ;
  610. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  611. Var Regs: Registers;
  612. begin
  613. Regs.AH := $65;
  614. Regs.AL := InfoId;
  615. Regs.BX := CodePage;
  616. Regs.DX := CountryId;
  617. Regs.ES := tb div 16;
  618. Regs.DI := tb and 15;
  619. Regs.CX := SizeOf(TCountryInfo);
  620. RealIntr($21, Regs);
  621. DosMemGet(tb div 16,
  622. tb and 15,
  623. CountryInfo, Regs.CX );
  624. end;
  625. procedure InitAnsi;
  626. var
  627. CountryInfo: TCountryInfo; i: integer;
  628. begin
  629. { Fill table entries 0 to 127 }
  630. for i := 0 to 96 do
  631. UpperCaseTable[i] := chr(i);
  632. for i := 97 to 122 do
  633. UpperCaseTable[i] := chr(i - 32);
  634. for i := 123 to 127 do
  635. UpperCaseTable[i] := chr(i);
  636. for i := 0 to 64 do
  637. LowerCaseTable[i] := chr(i);
  638. for i := 65 to 90 do
  639. LowerCaseTable[i] := chr(i + 32);
  640. for i := 91 to 255 do
  641. LowerCaseTable[i] := chr(i);
  642. { Get country and codepage info }
  643. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  644. if CountryInfo.CodePage = 850 then
  645. begin
  646. { Special, known case }
  647. Move(CP850UCT, UpperCaseTable[128], 128);
  648. Move(CP850LCT, LowerCaseTable[128], 128);
  649. end
  650. else
  651. begin
  652. { this needs to be checked !!
  653. this is correct only if UpperCaseTable is
  654. and Offset:Segment word record (PM) }
  655. { get the uppercase table from dosmemory }
  656. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  657. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  658. for i := 128 to 255 do
  659. begin
  660. if UpperCaseTable[i] <> chr(i) then
  661. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  662. end;
  663. end;
  664. end;
  665. Procedure InitInternational;
  666. begin
  667. InitInternationalGeneric;
  668. InitAnsi;
  669. end;
  670. function SysErrorMessage(ErrorCode: Integer): String;
  671. begin
  672. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  673. end;
  674. {****************************************************************************
  675. Os utils
  676. ****************************************************************************}
  677. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  678. begin
  679. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  680. end;
  681. Function GetEnvironmentVariableCount : Integer;
  682. begin
  683. Result:=FPCCountEnvVar(EnvP);
  684. end;
  685. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  686. begin
  687. Result:=FPCGetEnvStrFromP(Envp,Index);
  688. end;
  689. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  690. var
  691. e : EOSError;
  692. CommandLine: RawByteString;
  693. begin
  694. dos.exec(path,comline);
  695. if (Dos.DosError <> 0) then
  696. begin
  697. if ComLine <> '' then
  698. CommandLine := Path + ' ' + ComLine
  699. else
  700. CommandLine := Path;
  701. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  702. e.ErrorCode:=Dos.DosError;
  703. raise e;
  704. end;
  705. Result := DosExitCode;
  706. end;
  707. function ExecuteProcess (const Path: RawByteString;
  708. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  709. var
  710. CommandLine: RawByteString;
  711. I: integer;
  712. begin
  713. Commandline := '';
  714. for I := 0 to High (ComLine) do
  715. if Pos (' ', ComLine [I]) <> 0 then
  716. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  717. else
  718. CommandLine := CommandLine + ' ' + Comline [I];
  719. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  720. end;
  721. {*************************************************************************
  722. Sleep (copied from crt.Delay)
  723. *************************************************************************}
  724. var
  725. DelayCnt : Longint;
  726. procedure Delayloop;assembler;
  727. asm
  728. .LDelayLoop1:
  729. subl $1,%eax
  730. jc .LDelayLoop2
  731. cmpl %fs:(%edi),%ebx
  732. je .LDelayLoop1
  733. .LDelayLoop2:
  734. end;
  735. procedure initdelay;assembler;
  736. asm
  737. pushl %ebx
  738. pushl %edi
  739. { for some reason, using int $31/ax=$901 doesn't work here }
  740. { and interrupts are always disabled at this point when }
  741. { running a program inside gdb(pas). Web bug 1345 (JM) }
  742. sti
  743. movl $0x46c,%edi
  744. movl $-28,%edx
  745. movl %fs:(%edi),%ebx
  746. .LInitDel1:
  747. cmpl %fs:(%edi),%ebx
  748. je .LInitDel1
  749. movl %fs:(%edi),%ebx
  750. movl %edx,%eax
  751. call DelayLoop
  752. notl %eax
  753. xorl %edx,%edx
  754. movl $55,%ecx
  755. divl %ecx
  756. movl %eax,DelayCnt
  757. popl %edi
  758. popl %ebx
  759. end;
  760. procedure Sleep(MilliSeconds: Cardinal);assembler;
  761. asm
  762. pushl %ebx
  763. pushl %edi
  764. movl MilliSeconds,%ecx
  765. jecxz .LDelay2
  766. movl $0x400,%edi
  767. movl DelayCnt,%edx
  768. movl %fs:(%edi),%ebx
  769. .LDelay1:
  770. movl %edx,%eax
  771. call DelayLoop
  772. loop .LDelay1
  773. .LDelay2:
  774. popl %edi
  775. popl %ebx
  776. end;
  777. {****************************************************************************
  778. Initialization code
  779. ****************************************************************************}
  780. Initialization
  781. InitExceptions; { Initialize exceptions. OS independent }
  782. InitInternational; { Initialize internationalization settings }
  783. InitDelay;
  784. OnBeep:=@SysBeep;
  785. InitTZ;
  786. Finalization
  787. FreeTerminateProcs;
  788. DoneExceptions;
  789. end.