sysutils.pp 22 KB

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