sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  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. SystemTime.DayOfWeek := Regs.Al;
  559. end ;
  560. {****************************************************************************
  561. Misc Functions
  562. ****************************************************************************}
  563. const
  564. BeepChars: array [1..2] of char = #7'$';
  565. procedure sysBeep;
  566. var
  567. Regs: Registers;
  568. begin
  569. Regs.dx := Ofs (BeepChars);
  570. Regs.ah := 9;
  571. MsDos (Regs);
  572. end;
  573. {****************************************************************************
  574. Locale Functions
  575. ****************************************************************************}
  576. { Codepage constants }
  577. const
  578. CP_US = 437;
  579. CP_MultiLingual = 850;
  580. CP_SlavicLatin2 = 852;
  581. CP_Turkish = 857;
  582. CP_Portugal = 860;
  583. CP_IceLand = 861;
  584. CP_Canada = 863;
  585. CP_NorwayDenmark = 865;
  586. { CountryInfo }
  587. type
  588. TCountryInfo = packed record
  589. InfoId: byte;
  590. case integer of
  591. 1: ( Size: word;
  592. CountryId: word;
  593. CodePage: word;
  594. CountryInfo: array[0..33] of byte );
  595. 2: ( UpperCaseTable: longint );
  596. 4: ( FilenameUpperCaseTable: longint );
  597. 5: ( FilecharacterTable: longint );
  598. 6: ( CollatingTable: longint );
  599. 7: ( DBCSLeadByteTable: longint );
  600. end ;
  601. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  602. Var Regs: Registers;
  603. begin
  604. Regs.AH := $65;
  605. Regs.AL := InfoId;
  606. Regs.BX := CodePage;
  607. Regs.DX := CountryId;
  608. Regs.ES := {transfer_buffer div 16}Seg(CountryInfo);
  609. Regs.DI := {transfer_buffer and 15}Ofs(CountryInfo);
  610. Regs.CX := SizeOf(TCountryInfo);
  611. MsDos(Regs);
  612. { DosMemGet(transfer_buffer div 16,
  613. transfer_buffer and 15,
  614. CountryInfo, Regs.CX );}
  615. end;
  616. procedure InitAnsi;
  617. type
  618. PFarChar = ^char; far;
  619. var
  620. CountryInfo: TCountryInfo; i: integer;
  621. begin
  622. { Fill table entries 0 to 127 }
  623. for i := 0 to 96 do
  624. UpperCaseTable[i] := chr(i);
  625. for i := 97 to 122 do
  626. UpperCaseTable[i] := chr(i - 32);
  627. for i := 123 to 127 do
  628. UpperCaseTable[i] := chr(i);
  629. for i := 0 to 64 do
  630. LowerCaseTable[i] := chr(i);
  631. for i := 65 to 90 do
  632. LowerCaseTable[i] := chr(i + 32);
  633. for i := 91 to 255 do
  634. LowerCaseTable[i] := chr(i);
  635. { Get country and codepage info }
  636. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  637. if CountryInfo.CodePage = 850 then
  638. begin
  639. { Special, known case }
  640. Move(CP850UCT, UpperCaseTable[128], 128);
  641. Move(CP850LCT, LowerCaseTable[128], 128);
  642. end
  643. else
  644. begin
  645. { this needs to be checked !!
  646. this is correct only if UpperCaseTable is
  647. and Offset:Segment word record (PM) }
  648. { get the uppercase table from dosmemory }
  649. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  650. for i := 128 to 255 do
  651. begin
  652. UpperCaseTable[i] := PFarChar(CountryInfo.UpperCaseTable)[i+(2-128)];
  653. if UpperCaseTable[i] <> chr(i) then
  654. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  655. end;
  656. end;
  657. end;
  658. Procedure InitInternational;
  659. begin
  660. InitInternationalGeneric;
  661. InitAnsi;
  662. end;
  663. function SysErrorMessage(ErrorCode: Integer): String;
  664. begin
  665. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  666. end;
  667. {****************************************************************************
  668. Os utils
  669. ****************************************************************************}
  670. {$if defined(FPC_MM_TINY) or defined(FPC_MM_SMALL) or defined(FPC_MM_MEDIUM)}
  671. { environment handling for near data memory models }
  672. function far_strpas(p: pfarchar): string;
  673. begin
  674. Result:='';
  675. if p<>nil then
  676. while p^<>#0 do
  677. begin
  678. Result:=Result+p^;
  679. Inc(p);
  680. end;
  681. end;
  682. Function small_FPCGetEnvVarFromP(EP : PPFarChar; EnvVar : String) : String;
  683. var
  684. hp : ppfarchar;
  685. lenvvar,hs : string;
  686. eqpos : smallint;
  687. begin
  688. lenvvar:=upcase(envvar);
  689. hp:=EP;
  690. Result:='';
  691. If (hp<>Nil) then
  692. while assigned(hp^) do
  693. begin
  694. hs:=far_strpas(hp^);
  695. eqpos:=pos('=',hs);
  696. if upcase(copy(hs,1,eqpos-1))=lenvvar then
  697. begin
  698. Result:=copy(hs,eqpos+1,length(hs)-eqpos);
  699. exit;
  700. end;
  701. inc(hp);
  702. end;
  703. end;
  704. Function small_FPCGetEnvStrFromP(EP : PPFarChar; Index : SmallInt) : String;
  705. begin
  706. Result:='';
  707. while assigned(EP^) and (Index>1) do
  708. begin
  709. dec(Index);
  710. inc(EP);
  711. end;
  712. if Assigned(EP^) then
  713. Result:=far_strpas(EP^);
  714. end;
  715. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  716. begin
  717. Result:=small_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:=small_FPCGetEnvStrFromP(Envp,Index);
  726. end;
  727. {$else}
  728. { environment handling for far data memory models }
  729. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  730. begin
  731. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  732. end;
  733. Function GetEnvironmentVariableCount : Integer;
  734. begin
  735. Result:=dos_env_count;
  736. end;
  737. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  738. begin
  739. Result:=FPCGetEnvStrFromP(Envp,Index);
  740. end;
  741. {$endif}
  742. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  743. var
  744. e : EOSError;
  745. CommandLine: RawByteString;
  746. begin
  747. dos.exec_ansistring(path,comline);
  748. if (Dos.DosError <> 0) then
  749. begin
  750. if ComLine <> '' then
  751. CommandLine := Path + ' ' + ComLine
  752. else
  753. CommandLine := Path;
  754. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  755. e.ErrorCode:=Dos.DosError;
  756. raise e;
  757. end;
  758. Result := DosExitCode;
  759. end;
  760. function ExecuteProcess (const Path: RawByteString;
  761. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  762. var
  763. CommandLine: RawByteString;
  764. I: integer;
  765. begin
  766. Commandline := '';
  767. for I := 0 to High (ComLine) do
  768. if Pos (' ', ComLine [I]) <> 0 then
  769. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  770. else
  771. CommandLine := CommandLine + ' ' + Comline [I];
  772. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  773. end;
  774. {*************************************************************************
  775. Sleep
  776. *************************************************************************}
  777. procedure Sleep (MilliSeconds: Cardinal);
  778. var
  779. R: Registers;
  780. T0, T1, T2: int64;
  781. DayOver: boolean;
  782. begin
  783. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  784. because it should be supported in all DOS versions. Not precise at all,
  785. though - the smallest step is 10 ms even in the best case. *)
  786. R.AH := $2C;
  787. MsDos(R);
  788. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  789. T2 := T0 + MilliSeconds;
  790. DayOver := T2 > (24 * 3600000);
  791. repeat
  792. Intr ($28, R);
  793. (* R.AH := $2C; - should be preserved. *)
  794. MsDos(R);
  795. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  796. if DayOver and (T1 < T0) then
  797. Inc (T1, 24 * 3600000);
  798. until T1 >= T2;
  799. end;
  800. {****************************************************************************
  801. Initialization code
  802. ****************************************************************************}
  803. Initialization
  804. InitExceptions; { Initialize exceptions. OS independent }
  805. InitInternational; { Initialize internationalization settings }
  806. OnBeep:=@SysBeep;
  807. Finalization
  808. FreeTerminateProcs;
  809. DoneExceptions;
  810. end.