sysutils.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  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. begin
  242. if FileName = '' then
  243. Result := false
  244. else
  245. Result := FileGetAttr (ExpandFileName (FileName)) and
  246. (faDirectory or faVolumeID) = 0;
  247. (* Neither VolumeIDs nor directories are files. *)
  248. end;
  249. Function DirectoryExists (Const Directory : String) : Boolean;
  250. Var
  251. Dir : String;
  252. drive : byte;
  253. FADir, StoredIORes : longint;
  254. begin
  255. Dir:=Directory;
  256. if (length(dir)=2) and (dir[2]=':') and
  257. ((dir[1] in ['A'..'Z']) or (dir[1] in ['a'..'z'])) then
  258. begin
  259. { We want to test GetCurDir }
  260. if dir[1] in ['A'..'Z'] then
  261. drive:=ord(dir[1])-ord('A')+1
  262. else
  263. drive:=ord(dir[1])-ord('a')+1;
  264. {$undef OPT_I}
  265. {$ifopt I+}
  266. {$define OPT_I}
  267. {$endif}
  268. {$I-}
  269. StoredIORes:=InOutRes;
  270. InOutRes:=0;
  271. GetDir(drive,dir);
  272. if InOutRes <> 0 then
  273. begin
  274. InOutRes:=StoredIORes;
  275. result:=false;
  276. exit;
  277. end;
  278. end;
  279. {$ifdef OPT_I}
  280. {$I+}
  281. {$endif}
  282. if (Length (Dir) > 1) and
  283. (Dir [Length (Dir)] in AllowDirectorySeparators) and
  284. (* Do not remove '\' after ':' (root directory of a drive)
  285. or in '\\' (invalid path, possibly broken UNC path). *)
  286. not (Dir [Length (Dir) - 1] in (AllowDriveSeparators + AllowDirectorySeparators)) then
  287. dir:=copy(dir,1,length(dir)-1);
  288. (* FileGetAttr returns -1 on error *)
  289. FADir := FileGetAttr (Dir);
  290. Result := (FADir <> -1) and
  291. ((FADir and faDirectory) = faDirectory);
  292. end;
  293. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  294. Var Sr : PSearchrec;
  295. begin
  296. //!! Sr := New(PSearchRec);
  297. getmem(sr,sizeof(searchrec));
  298. Rslt.FindHandle := longint(Sr);
  299. DOS.FindFirst(Path, Attr, Sr^);
  300. result := -DosError;
  301. if result = 0 then
  302. begin
  303. Rslt.Time := Sr^.Time;
  304. Rslt.Size := Sr^.Size;
  305. Rslt.Attr := Sr^.Attr;
  306. Rslt.ExcludeAttr := 0;
  307. Rslt.Name := Sr^.Name;
  308. end ;
  309. end;
  310. Function FindNext (Var Rslt : TSearchRec) : Longint;
  311. var
  312. Sr: PSearchRec;
  313. begin
  314. Sr := PSearchRec(Rslt.FindHandle);
  315. if Sr <> nil then
  316. begin
  317. DOS.FindNext(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. Rslt.Name := Sr^.Name;
  326. end;
  327. end;
  328. end;
  329. Procedure FindClose (Var F : TSearchrec);
  330. var
  331. Sr: PSearchRec;
  332. begin
  333. Sr := PSearchRec(F.FindHandle);
  334. if Sr <> nil then
  335. begin
  336. //!! Dispose(Sr);
  337. // This call is non dummy if LFNSupport is true PM
  338. DOS.FindClose(SR^);
  339. freemem(sr,sizeof(searchrec));
  340. end;
  341. F.FindHandle := 0;
  342. end;
  343. Function FileGetDate (Handle : Longint) : Longint;
  344. var
  345. Regs: registers;
  346. begin
  347. //!! for win95 an alternative function is available.
  348. Regs.Ebx := Handle;
  349. Regs.Eax := $5700;
  350. RealIntr($21, Regs);
  351. if Regs.Flags and CarryFlag <> 0 then
  352. result := -1
  353. else
  354. begin
  355. LongRec(result).Lo := Regs.cx;
  356. LongRec(result).Hi := Regs.dx;
  357. end ;
  358. end;
  359. Function FileSetDate (Handle, Age : Longint) : Longint;
  360. var
  361. Regs: registers;
  362. begin
  363. Regs.Ebx := Handle;
  364. Regs.Eax := $5701;
  365. Regs.Ecx := Lo(Age);
  366. Regs.Edx := Hi(Age);
  367. RealIntr($21, Regs);
  368. if Regs.Flags and CarryFlag <> 0 then
  369. result := -Regs.Ax
  370. else
  371. result := 0;
  372. end;
  373. Function FileGetAttr (Const FileName : String) : Longint;
  374. var
  375. Regs: registers;
  376. begin
  377. StringToTB(FileName);
  378. Regs.Edx := tb_offset;
  379. Regs.Ds := tb_segment;
  380. if LFNSupport then
  381. begin
  382. Regs.Ax := $7143;
  383. Regs.Bx := 0;
  384. end
  385. else
  386. Regs.Ax := $4300;
  387. RealIntr($21, Regs);
  388. if Regs.Flags and CarryFlag <> 0 then
  389. result := -1
  390. else
  391. result := Regs.Cx;
  392. end;
  393. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  394. var
  395. Regs: registers;
  396. begin
  397. StringToTB(FileName);
  398. Regs.Edx := tb_offset;
  399. Regs.Ds := tb_segment;
  400. if LFNSupport then
  401. begin
  402. Regs.Ax := $7143;
  403. Regs.Bx := 1;
  404. end
  405. else
  406. Regs.Ax := $4301;
  407. Regs.Cx := Attr;
  408. RealIntr($21, Regs);
  409. if Regs.Flags and CarryFlag <> 0 then
  410. result := -Regs.Ax
  411. else
  412. result := 0;
  413. end;
  414. Function DeleteFile (Const FileName : String) : Boolean;
  415. var
  416. Regs: registers;
  417. begin
  418. StringToTB(FileName);
  419. Regs.Edx := tb_offset;
  420. Regs.Ds := tb_segment;
  421. if LFNSupport then
  422. Regs.Eax := $7141
  423. else
  424. Regs.Eax := $4100;
  425. Regs.Esi := 0;
  426. Regs.Ecx := 0;
  427. RealIntr($21, Regs);
  428. result := (Regs.Flags and CarryFlag = 0);
  429. end;
  430. Function RenameFile (Const OldName, NewName : String) : Boolean;
  431. var
  432. Regs: registers;
  433. begin
  434. StringToTB(OldName + #0 + NewName);
  435. Regs.Edx := tb_offset;
  436. Regs.Ds := tb_segment;
  437. Regs.Edi := tb_offset + Length(OldName) + 1;
  438. Regs.Es := tb_segment;
  439. if LFNSupport then
  440. Regs.Eax := $7156
  441. else
  442. Regs.Eax := $5600;
  443. Regs.Ecx := $ff;
  444. RealIntr($21, Regs);
  445. result := (Regs.Flags and CarryFlag = 0);
  446. end;
  447. {****************************************************************************
  448. Disk Functions
  449. ****************************************************************************}
  450. TYPE ExtendedFat32FreeSpaceRec=packed Record
  451. RetSize : WORD; { (ret) size of returned structure}
  452. Strucversion : WORD; {(call) structure version (0000h)
  453. (ret) actual structure version (0000h)}
  454. SecPerClus, {number of sectors per cluster}
  455. BytePerSec, {number of bytes per sector}
  456. AvailClusters, {number of available clusters}
  457. TotalClusters, {total number of clusters on the drive}
  458. AvailPhysSect, {physical sectors available on the drive}
  459. TotalPhysSect, {total physical sectors on the drive}
  460. AvailAllocUnits, {Available allocation units}
  461. TotalAllocUnits : DWORD; {Total allocation units}
  462. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  463. END;
  464. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  465. VAR S : String;
  466. Rec : ExtendedFat32FreeSpaceRec;
  467. regs : registers;
  468. procedure OldDosDiskData;
  469. begin
  470. regs.dl:=drive;
  471. regs.ah:=$36;
  472. msdos(regs);
  473. if regs.ax<>$FFFF then
  474. begin
  475. if Free then
  476. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  477. else
  478. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  479. end
  480. else
  481. do_diskdata:=-1;
  482. end;
  483. BEGIN
  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. RealIntr($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. RealIntr($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;
  617. Regs.DI := transfer_buffer and 15;
  618. Regs.CX := SizeOf(TCountryInfo);
  619. RealIntr($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. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  657. for i := 128 to 255 do
  658. begin
  659. if UpperCaseTable[i] <> chr(i) then
  660. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  661. end;
  662. end;
  663. end;
  664. Procedure InitInternational;
  665. begin
  666. InitInternationalGeneric;
  667. InitAnsi;
  668. end;
  669. function SysErrorMessage(ErrorCode: Integer): String;
  670. begin
  671. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  672. end;
  673. {****************************************************************************
  674. Os utils
  675. ****************************************************************************}
  676. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  677. begin
  678. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  679. end;
  680. Function GetEnvironmentVariableCount : Integer;
  681. begin
  682. Result:=FPCCountEnvVar(EnvP);
  683. end;
  684. Function GetEnvironmentString(Index : Integer) : String;
  685. begin
  686. Result:=FPCGetEnvStrFromP(Envp,Index);
  687. end;
  688. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  689. var
  690. e : EOSError;
  691. CommandLine: AnsiString;
  692. begin
  693. dos.exec_ansistring(path,comline);
  694. if (Dos.DosError <> 0) then
  695. begin
  696. if ComLine <> '' then
  697. CommandLine := Path + ' ' + ComLine
  698. else
  699. CommandLine := Path;
  700. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  701. e.ErrorCode:=Dos.DosError;
  702. raise e;
  703. end;
  704. Result := DosExitCode;
  705. end;
  706. function ExecuteProcess (const Path: AnsiString;
  707. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  708. var
  709. CommandLine: AnsiString;
  710. I: integer;
  711. begin
  712. Commandline := '';
  713. for I := 0 to High (ComLine) do
  714. if Pos (' ', ComLine [I]) <> 0 then
  715. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  716. else
  717. CommandLine := CommandLine + ' ' + Comline [I];
  718. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  719. end;
  720. {*************************************************************************
  721. Sleep
  722. *************************************************************************}
  723. procedure Sleep (MilliSeconds: Cardinal);
  724. var
  725. R: Registers;
  726. T0, T1, T2: int64;
  727. DayOver: boolean;
  728. begin
  729. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  730. because it should be supported in all DOS versions. Not precise at all,
  731. though - the smallest step is 10 ms even in the best case. *)
  732. R.AH := $2C;
  733. RealIntr($21, R);
  734. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  735. T2 := T0 + MilliSeconds;
  736. DayOver := T2 > (24 * 3600000);
  737. repeat
  738. Intr ($28, R);
  739. (* R.AH := $2C; - should be preserved. *)
  740. RealIntr($21, R);
  741. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  742. if DayOver and (T1 < T0) then
  743. Inc (T1, 24 * 3600000);
  744. until T1 >= T2;
  745. end;
  746. {****************************************************************************
  747. Initialization code
  748. ****************************************************************************}
  749. Initialization
  750. InitExceptions; { Initialize exceptions. OS independent }
  751. InitInternational; { Initialize internationalization settings }
  752. OnBeep:=@SysBeep;
  753. Finalization
  754. DoneExceptions;
  755. end.