sysutils.pp 21 KB

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