sysutils.pp 21 KB

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