sysutils.pp 22 KB

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