sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  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): Longint;
  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 FileExists (const FileName: RawByteString): boolean;
  255. var
  256. L: longint;
  257. begin
  258. if FileName = '' then
  259. Result := false
  260. else
  261. begin
  262. L := FileGetAttr (FileName);
  263. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  264. (* Neither VolumeIDs nor directories are files. *)
  265. end;
  266. end;
  267. Function DirectoryExists (Const Directory : RawByteString) : Boolean;
  268. Var
  269. Dir : RawByteString;
  270. drive : byte;
  271. FADir, StoredIORes : longint;
  272. begin
  273. Dir:=Directory;
  274. if (length(dir)=2) and (dir[2]=':') and
  275. ((dir[1] in ['A'..'Z']) or (dir[1] in ['a'..'z'])) then
  276. begin
  277. { We want to test GetCurDir }
  278. if dir[1] in ['A'..'Z'] then
  279. drive:=ord(dir[1])-ord('A')+1
  280. else
  281. drive:=ord(dir[1])-ord('a')+1;
  282. {$push}
  283. {$I-}
  284. StoredIORes:=InOutRes;
  285. InOutRes:=0;
  286. GetDir(drive,dir);
  287. if InOutRes <> 0 then
  288. begin
  289. InOutRes:=StoredIORes;
  290. result:=false;
  291. exit;
  292. end;
  293. end;
  294. {$pop}
  295. if (Length (Dir) > 1) and
  296. (Dir [Length (Dir)] in AllowDirectorySeparators) and
  297. (* Do not remove '\' after ':' (root directory of a drive)
  298. or in '\\' (invalid path, possibly broken UNC path). *)
  299. not (Dir [Length (Dir) - 1] in (AllowDriveSeparators + AllowDirectorySeparators)) then
  300. dir:=copy(dir,1,length(dir)-1);
  301. (* FileGetAttr returns -1 on error *)
  302. FADir := FileGetAttr (Dir);
  303. Result := (FADir <> -1) and
  304. ((FADir and faDirectory) = faDirectory);
  305. end;
  306. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  307. Var Sr : PSearchrec;
  308. begin
  309. //!! Sr := New(PSearchRec);
  310. getmem(sr,sizeof(searchrec));
  311. Rslt.FindHandle := Sr;
  312. DOS.FindFirst(Path, Attr, Sr^);
  313. result := -DosError;
  314. if result = 0 then
  315. begin
  316. Rslt.Time := Sr^.Time;
  317. Rslt.Size := Sr^.Size;
  318. Rslt.Attr := Sr^.Attr;
  319. Rslt.ExcludeAttr := 0;
  320. Name := Sr^.Name;
  321. end ;
  322. end;
  323. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  324. var
  325. Sr: PSearchRec;
  326. begin
  327. Sr := PSearchRec(Rslt.FindHandle);
  328. if Sr <> nil then
  329. begin
  330. DOS.FindNext(Sr^);
  331. result := -DosError;
  332. if result = 0 then
  333. begin
  334. Rslt.Time := Sr^.Time;
  335. Rslt.Size := Sr^.Size;
  336. Rslt.Attr := Sr^.Attr;
  337. Rslt.ExcludeAttr := 0;
  338. Name := Sr^.Name;
  339. end;
  340. end;
  341. end;
  342. Procedure InternalFindClose(var Handle: Pointer);
  343. var
  344. Sr: PSearchRec;
  345. begin
  346. Sr := PSearchRec(Handle);
  347. if Sr <> nil then
  348. begin
  349. //!! Dispose(Sr);
  350. // This call is non dummy if LFNSupport is true PM
  351. DOS.FindClose(SR^);
  352. freemem(sr,sizeof(searchrec));
  353. end;
  354. Handle := nil;
  355. end;
  356. Function FileGetDate (Handle : THandle) : Longint;
  357. var
  358. Regs: registers;
  359. begin
  360. //!! for win95 an alternative function is available.
  361. Regs.bx := Handle;
  362. Regs.ax := $5700;
  363. MsDos(Regs);
  364. if Regs.Flags and fCarry <> 0 then
  365. result := -1
  366. else
  367. begin
  368. LongRec(result).Lo := Regs.cx;
  369. LongRec(result).Hi := Regs.dx;
  370. end ;
  371. end;
  372. Function FileSetDate (Handle : THandle; Age : Longint) : Longint;
  373. var
  374. Regs: registers;
  375. begin
  376. Regs.bx := Handle;
  377. Regs.ax := $5701;
  378. Regs.cx := Lo(Age);
  379. Regs.dx := Hi(Age);
  380. MsDos(Regs);
  381. if Regs.Flags and fCarry <> 0 then
  382. result := -Regs.Ax
  383. else
  384. result := 0;
  385. end;
  386. Function FileGetAttr (Const FileName : RawByteString) : Longint;
  387. var
  388. Regs: registers;
  389. begin
  390. Regs.dx := Ofs(PChar(FileName)^);
  391. Regs.Ds := Seg(PChar(FileName)^);
  392. if LFNSupport then
  393. begin
  394. Regs.Ax := $7143;
  395. Regs.Bx := 0;
  396. end
  397. else
  398. Regs.Ax := $4300;
  399. MsDos(Regs);
  400. if Regs.Flags and fCarry <> 0 then
  401. result := -1
  402. else
  403. result := Regs.Cx;
  404. end;
  405. Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
  406. var
  407. Regs: registers;
  408. begin
  409. Regs.dx := Ofs(PChar(FileName)^);
  410. Regs.Ds := Seg(PChar(FileName)^);
  411. if LFNSupport then
  412. begin
  413. Regs.Ax := $7143;
  414. Regs.Bx := 1;
  415. end
  416. else
  417. Regs.Ax := $4301;
  418. Regs.Cx := Attr;
  419. MsDos(Regs);
  420. if Regs.Flags and fCarry <> 0 then
  421. result := -Regs.Ax
  422. else
  423. result := 0;
  424. end;
  425. Function DeleteFile (Const FileName : RawByteString) : Boolean;
  426. var
  427. Regs: registers;
  428. begin
  429. Regs.dx := Ofs(PChar(FileName)^);
  430. Regs.Ds := Seg(PChar(FileName)^);
  431. if LFNSupport then
  432. Regs.ax := $7141
  433. else
  434. Regs.ax := $4100;
  435. Regs.si := 0;
  436. Regs.cx := 0;
  437. MsDos(Regs);
  438. result := (Regs.Flags and fCarry = 0);
  439. end;
  440. Function RenameFile (Const OldName, NewName : RawByteString) : Boolean;
  441. var
  442. Regs: registers;
  443. begin
  444. // StringToTB(OldName + #0 + NewName);
  445. Regs.dx := Ofs(PChar(OldName)^);
  446. Regs.Ds := Seg(PChar(OldName)^);
  447. Regs.di := Ofs(PChar(NewName)^);
  448. Regs.Es := Seg(PChar(NewName)^);
  449. if LFNSupport then
  450. Regs.ax := $7156
  451. else
  452. Regs.ax := $5600;
  453. Regs.cx := $ff;
  454. MsDos(Regs);
  455. result := (Regs.Flags and fCarry = 0);
  456. end;
  457. {****************************************************************************
  458. Disk Functions
  459. ****************************************************************************}
  460. TYPE ExtendedFat32FreeSpaceRec=packed Record
  461. RetSize : WORD; { (ret) size of returned structure}
  462. Strucversion : WORD; {(call) structure version (0000h)
  463. (ret) actual structure version (0000h)}
  464. SecPerClus, {number of sectors per cluster}
  465. BytePerSec, {number of bytes per sector}
  466. AvailClusters, {number of available clusters}
  467. TotalClusters, {total number of clusters on the drive}
  468. AvailPhysSect, {physical sectors available on the drive}
  469. TotalPhysSect, {total physical sectors on the drive}
  470. AvailAllocUnits, {Available allocation units}
  471. TotalAllocUnits : DWORD; {Total allocation units}
  472. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  473. END;
  474. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  475. VAR S : String;
  476. Rec : ExtendedFat32FreeSpaceRec;
  477. regs : registers;
  478. procedure OldDosDiskData;
  479. begin
  480. regs.dl:=drive;
  481. regs.ah:=$36;
  482. msdos(regs);
  483. if regs.ax<>$FFFF then
  484. begin
  485. if Free then
  486. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  487. else
  488. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  489. end
  490. else
  491. do_diskdata:=-1;
  492. end;
  493. BEGIN
  494. if LFNSupport then
  495. begin
  496. S:='C:\'#0;
  497. if Drive=0 then
  498. begin
  499. GetDir(Drive,S);
  500. Setlength(S,4);
  501. S[4]:=#0;
  502. end
  503. else
  504. S[1]:=chr(Drive+64);
  505. Rec.Strucversion:=0;
  506. Rec.RetSize := 0;
  507. regs.dx:=Ofs(S[1]);
  508. regs.ds:=Seg(S[1]);
  509. regs.di:=Ofs(Rec);
  510. regs.es:=Seg(Rec);
  511. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  512. regs.ax:=$7303;
  513. msdos(regs);
  514. if (regs.flags and fcarry) = 0 then {No error clausule in int except cf}
  515. begin
  516. if Rec.RetSize = 0 then (* Error - "FAT32" function not supported! *)
  517. OldDosDiskData
  518. else
  519. if Free then
  520. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  521. else
  522. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  523. end
  524. else
  525. OldDosDiskData;
  526. end
  527. else
  528. OldDosDiskData;
  529. end;
  530. function diskfree(drive : byte) : int64;
  531. begin
  532. diskfree:=Do_DiskData(drive,TRUE);
  533. end;
  534. function disksize(drive : byte) : int64;
  535. begin
  536. disksize:=Do_DiskData(drive,false);
  537. end;
  538. {****************************************************************************
  539. Time Functions
  540. ****************************************************************************}
  541. Procedure GetLocalTime(var SystemTime: TSystemTime);
  542. var
  543. Regs: Registers;
  544. begin
  545. Regs.ah := $2C;
  546. MsDos(Regs);
  547. SystemTime.Hour := Regs.Ch;
  548. SystemTime.Minute := Regs.Cl;
  549. SystemTime.Second := Regs.Dh;
  550. SystemTime.MilliSecond := Regs.Dl*10;
  551. Regs.ah := $2A;
  552. MsDos(Regs);
  553. SystemTime.Year := Regs.Cx;
  554. SystemTime.Month := Regs.Dh;
  555. SystemTime.Day := Regs.Dl;
  556. end ;
  557. {****************************************************************************
  558. Misc Functions
  559. ****************************************************************************}
  560. procedure sysBeep;
  561. begin
  562. end;
  563. {****************************************************************************
  564. Locale Functions
  565. ****************************************************************************}
  566. { Codepage constants }
  567. const
  568. CP_US = 437;
  569. CP_MultiLingual = 850;
  570. CP_SlavicLatin2 = 852;
  571. CP_Turkish = 857;
  572. CP_Portugal = 860;
  573. CP_IceLand = 861;
  574. CP_Canada = 863;
  575. CP_NorwayDenmark = 865;
  576. { CountryInfo }
  577. type
  578. TCountryInfo = packed record
  579. InfoId: byte;
  580. case integer of
  581. 1: ( Size: word;
  582. CountryId: word;
  583. CodePage: word;
  584. CountryInfo: array[0..33] of byte );
  585. 2: ( UpperCaseTable: longint );
  586. 4: ( FilenameUpperCaseTable: longint );
  587. 5: ( FilecharacterTable: longint );
  588. 6: ( CollatingTable: longint );
  589. 7: ( DBCSLeadByteTable: longint );
  590. end ;
  591. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  592. Var Regs: Registers;
  593. begin
  594. Regs.AH := $65;
  595. Regs.AL := InfoId;
  596. Regs.BX := CodePage;
  597. Regs.DX := CountryId;
  598. Regs.ES := {transfer_buffer div 16}Seg(CountryInfo);
  599. Regs.DI := {transfer_buffer and 15}Ofs(CountryInfo);
  600. Regs.CX := SizeOf(TCountryInfo);
  601. MsDos(Regs);
  602. { DosMemGet(transfer_buffer div 16,
  603. transfer_buffer and 15,
  604. CountryInfo, Regs.CX );}
  605. end;
  606. procedure InitAnsi;
  607. type
  608. PFarChar = ^char; far;
  609. var
  610. CountryInfo: TCountryInfo; i: integer;
  611. begin
  612. { Fill table entries 0 to 127 }
  613. for i := 0 to 96 do
  614. UpperCaseTable[i] := chr(i);
  615. for i := 97 to 122 do
  616. UpperCaseTable[i] := chr(i - 32);
  617. for i := 123 to 127 do
  618. UpperCaseTable[i] := chr(i);
  619. for i := 0 to 64 do
  620. LowerCaseTable[i] := chr(i);
  621. for i := 65 to 90 do
  622. LowerCaseTable[i] := chr(i + 32);
  623. for i := 91 to 255 do
  624. LowerCaseTable[i] := chr(i);
  625. { Get country and codepage info }
  626. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  627. if CountryInfo.CodePage = 850 then
  628. begin
  629. { Special, known case }
  630. Move(CP850UCT, UpperCaseTable[128], 128);
  631. Move(CP850LCT, LowerCaseTable[128], 128);
  632. end
  633. else
  634. begin
  635. { this needs to be checked !!
  636. this is correct only if UpperCaseTable is
  637. and Offset:Segment word record (PM) }
  638. { get the uppercase table from dosmemory }
  639. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  640. for i := 128 to 255 do
  641. begin
  642. UpperCaseTable[i] := PFarChar(CountryInfo.UpperCaseTable)[i+(2-128)];
  643. if UpperCaseTable[i] <> chr(i) then
  644. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  645. end;
  646. end;
  647. end;
  648. Procedure InitInternational;
  649. begin
  650. InitInternationalGeneric;
  651. InitAnsi;
  652. end;
  653. function SysErrorMessage(ErrorCode: Integer): String;
  654. begin
  655. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  656. end;
  657. {****************************************************************************
  658. Os utils
  659. ****************************************************************************}
  660. {$if defined(FPC_MM_TINY) or defined(FPC_MM_SMALL) or defined(FPC_MM_MEDIUM)}
  661. { environment handling for near data memory models }
  662. function far_strpas(p: pfarchar): string;
  663. begin
  664. Result:='';
  665. if p<>nil then
  666. while p^<>#0 do
  667. begin
  668. Result:=Result+p^;
  669. Inc(p);
  670. end;
  671. end;
  672. Function small_FPCGetEnvVarFromP(EP : PPFarChar; EnvVar : String) : String;
  673. var
  674. hp : ppfarchar;
  675. lenvvar,hs : string;
  676. eqpos : smallint;
  677. begin
  678. lenvvar:=upcase(envvar);
  679. hp:=EP;
  680. Result:='';
  681. If (hp<>Nil) then
  682. while assigned(hp^) do
  683. begin
  684. hs:=far_strpas(hp^);
  685. eqpos:=pos('=',hs);
  686. if upcase(copy(hs,1,eqpos-1))=lenvvar then
  687. begin
  688. Result:=copy(hs,eqpos+1,length(hs)-eqpos);
  689. exit;
  690. end;
  691. inc(hp);
  692. end;
  693. end;
  694. Function small_FPCGetEnvStrFromP(EP : PPFarChar; Index : SmallInt) : String;
  695. begin
  696. Result:='';
  697. while assigned(EP^) and (Index>1) do
  698. begin
  699. dec(Index);
  700. inc(EP);
  701. end;
  702. if Assigned(EP^) then
  703. Result:=far_strpas(EP^);
  704. end;
  705. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  706. begin
  707. Result:=small_FPCGetEnvVarFromP(envp,EnvVar);
  708. end;
  709. Function GetEnvironmentVariableCount : Integer;
  710. begin
  711. Result:=dos_env_count;
  712. end;
  713. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  714. begin
  715. Result:=small_FPCGetEnvStrFromP(Envp,Index);
  716. end;
  717. {$else}
  718. { environment handling for far data memory models }
  719. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  720. begin
  721. Result:=FPCGetEnvVarFromP(envp,EnvVar);
  722. end;
  723. Function GetEnvironmentVariableCount : Integer;
  724. begin
  725. Result:=dos_env_count;
  726. end;
  727. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  728. begin
  729. Result:=FPCGetEnvStrFromP(Envp,Index);
  730. end;
  731. {$endif}
  732. function ExecuteProcess(Const Path: RawByteString; Const ComLine: RawByteString;Flags:TExecuteFlags=[]):integer;
  733. var
  734. e : EOSError;
  735. CommandLine: RawByteString;
  736. begin
  737. dos.exec_ansistring(path,comline);
  738. if (Dos.DosError <> 0) then
  739. begin
  740. if ComLine <> '' then
  741. CommandLine := Path + ' ' + ComLine
  742. else
  743. CommandLine := Path;
  744. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,Dos.DosError]);
  745. e.ErrorCode:=Dos.DosError;
  746. raise e;
  747. end;
  748. Result := DosExitCode;
  749. end;
  750. function ExecuteProcess (const Path: RawByteString;
  751. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  752. var
  753. CommandLine: RawByteString;
  754. I: integer;
  755. begin
  756. Commandline := '';
  757. for I := 0 to High (ComLine) do
  758. if Pos (' ', ComLine [I]) <> 0 then
  759. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  760. else
  761. CommandLine := CommandLine + ' ' + Comline [I];
  762. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  763. end;
  764. {*************************************************************************
  765. Sleep
  766. *************************************************************************}
  767. procedure Sleep (MilliSeconds: Cardinal);
  768. var
  769. R: Registers;
  770. T0, T1, T2: int64;
  771. DayOver: boolean;
  772. begin
  773. (* Sleep is supposed to give up time slice - DOS Idle Interrupt chosen
  774. because it should be supported in all DOS versions. Not precise at all,
  775. though - the smallest step is 10 ms even in the best case. *)
  776. R.AH := $2C;
  777. MsDos(R);
  778. T0 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  779. T2 := T0 + MilliSeconds;
  780. DayOver := T2 > (24 * 3600000);
  781. repeat
  782. Intr ($28, R);
  783. (* R.AH := $2C; - should be preserved. *)
  784. MsDos(R);
  785. T1 := R.CH * 3600000 + R.CL * 60000 + R.DH * 1000 + R.DL * 10;
  786. if DayOver and (T1 < T0) then
  787. Inc (T1, 24 * 3600000);
  788. until T1 >= T2;
  789. end;
  790. {****************************************************************************
  791. Initialization code
  792. ****************************************************************************}
  793. Initialization
  794. InitExceptions; { Initialize exceptions. OS independent }
  795. InitInternational; { Initialize internationalization settings }
  796. OnBeep:=@SysBeep;
  797. Finalization
  798. DoneExceptions;
  799. end.