sysutils.pp 22 KB

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