sysutils.pp 22 KB

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