sysutils.pp 21 KB

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