sysutils.pp 22 KB

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