sysutils.pp 22 KB

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