sysutils.pp 21 KB

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