sysutils.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Sysutils unit for Go32v2
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit sysutils;
  14. interface
  15. {$MODE objfpc}
  16. { force ansistrings }
  17. {$H+}
  18. uses
  19. go32,dos;
  20. { Include platform independent interface part }
  21. {$i sysutilh.inc}
  22. implementation
  23. { Include platform independent implementation part }
  24. {$i sysutils.inc}
  25. {****************************************************************************
  26. File Functions
  27. ****************************************************************************}
  28. { some internal constants }
  29. const
  30. ofRead = $0000; { Open for reading }
  31. ofWrite = $0001; { Open for writing }
  32. ofReadWrite = $0002; { Open for reading/writing }
  33. faFail = $0000; { Fail if file does not exist }
  34. faCreate = $0010; { Create if file does not exist }
  35. faOpen = $0001; { Open if file exists }
  36. faOpenReplace = $0002; { Clear if file exists }
  37. Type
  38. PSearchrec = ^Searchrec;
  39. { converts S to a pchar and copies it to the transfer-buffer. }
  40. procedure StringToTB(const S: string);
  41. var
  42. P: pchar;
  43. Len: integer;
  44. begin
  45. Len := Length(S) + 1;
  46. P := StrPCopy(StrAlloc(Len), S);
  47. SysCopyToDos(longint(P), Len);
  48. StrDispose(P);
  49. end ;
  50. { Native OpenFile function.
  51. if return value <> 0 call failed. }
  52. function OpenFile(const FileName: string; var Handle: longint; Mode, Action: word): longint;
  53. var
  54. Regs: registers;
  55. begin
  56. result := 0;
  57. Handle := 0;
  58. StringToTB(FileName);
  59. if LFNSupport then Regs.Eax:=$716c
  60. else Regs.Eax:=$6c00;
  61. Regs.Edx := Action; { Action if file exists/not exists }
  62. Regs.Ds := tb_segment;
  63. Regs.Esi := tb_offset;
  64. Regs.Ebx := $2000 + (Mode and $ff); { file open mode }
  65. Regs.Ecx := $20; { Attributes }
  66. RealIntr($21, Regs);
  67. if Regs.Flags and CarryFlag <> 0 then result := Regs.Ax
  68. else Handle := Regs.Ax;
  69. end ;
  70. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  71. var
  72. e: integer;
  73. Begin
  74. e := OpenFile(FileName, result, Mode, faOpen);
  75. if e <> 0 then
  76. result := -1;
  77. end;
  78. Function FileCreate (Const FileName : String) : Longint;
  79. var
  80. e: integer;
  81. begin
  82. e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
  83. if e <> 0 then
  84. result := -1;
  85. end;
  86. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  87. begin
  88. result := Do_Read(Handle, longint(@Buffer), Count);
  89. end;
  90. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  91. begin
  92. result := Do_Write(Handle, longint(@Buffer), Count);
  93. end;
  94. Function FileSeek (Handle, FOffset, Origin : Longint) : Longint;
  95. var
  96. Regs: registers;
  97. begin
  98. Regs.Eax := $4200;
  99. Regs.Al := Origin;
  100. Regs.Edx := Lo(FOffset);
  101. Regs.Ecx := Hi(FOffset);
  102. Regs.Ebx := Handle;
  103. RealIntr($21, Regs);
  104. if Regs.Flags and CarryFlag <> 0 then
  105. result := -1
  106. else begin
  107. LongRec(result).Lo := Regs.Ax;
  108. LongRec(result).Hi := Regs.Dx;
  109. end ;
  110. end;
  111. Procedure FileClose (Handle : Longint);
  112. var
  113. Regs: registers;
  114. begin
  115. if Handle<=4 then
  116. exit;
  117. Regs.Eax := $3e00;
  118. Regs.Ebx := Handle;
  119. RealIntr($21, Regs);
  120. end;
  121. Function FileTruncate (Handle,Size: Longint) : boolean;
  122. var
  123. regs : trealregs;
  124. begin
  125. FileSeek(Handle,Size,0);
  126. Regs.realecx := 0;
  127. Regs.realedx := tb_offset;
  128. Regs.ds := tb_segment;
  129. Regs.ebx := Handle;
  130. Regs.eax:=$4000;
  131. RealIntr($21, Regs);
  132. FileTruncate:=(regs.realflags and carryflag)=0;
  133. end;
  134. Function FileAge (Const FileName : String): Longint;
  135. var Handle: longint;
  136. begin
  137. Handle := FileOpen(FileName, 0);
  138. if Handle <> -1 then
  139. begin
  140. result := FileGetDate(Handle);
  141. FileClose(Handle);
  142. end
  143. else
  144. result := -1;
  145. end;
  146. Function FileExists (Const FileName : String) : Boolean;
  147. var Handle: longint;
  148. begin
  149. //!! This can be done quicker, need to find out how
  150. Result := (OpenFile(FileName, Handle, ofRead, faOpen) = 0);
  151. if Handle <> 0 then
  152. FileClose(Handle);
  153. end;
  154. Function FindFirst (Const Path : String; Attr : Longint; Var Rslt : TSearchRec) : Longint;
  155. Var Sr : PSearchrec;
  156. begin
  157. //!! Sr := New(PSearchRec);
  158. getmem(sr,sizeof(searchrec));
  159. Rslt.FindHandle := longint(Sr);
  160. DOS.FindFirst(Path, Attr, Sr^);
  161. result := -DosError;
  162. if result = 0 then
  163. begin
  164. Rslt.Time := Sr^.Time;
  165. Rslt.Size := Sr^.Size;
  166. Rslt.Attr := Sr^.Attr;
  167. Rslt.ExcludeAttr := 0;
  168. Rslt.Name := Sr^.Name;
  169. end ;
  170. end;
  171. Function FindNext (Var Rslt : TSearchRec) : Longint;
  172. var
  173. Sr: PSearchRec;
  174. begin
  175. Sr := PSearchRec(Rslt.FindHandle);
  176. if Sr <> nil then
  177. begin
  178. DOS.FindNext(Sr^);
  179. result := -DosError;
  180. if result = 0 then
  181. begin
  182. Rslt.Time := Sr^.Time;
  183. Rslt.Size := Sr^.Size;
  184. Rslt.Attr := Sr^.Attr;
  185. Rslt.ExcludeAttr := 0;
  186. Rslt.Name := Sr^.Name;
  187. end;
  188. end;
  189. end;
  190. Procedure FindClose (Var F : TSearchrec);
  191. var
  192. Sr: PSearchRec;
  193. begin
  194. Sr := PSearchRec(F.FindHandle);
  195. if Sr <> nil then
  196. begin
  197. //!! Dispose(Sr);
  198. // This call is non dummy if LFNSupport is true PM
  199. DOS.FindClose(SR^);
  200. freemem(sr,sizeof(searchrec));
  201. end;
  202. F.FindHandle := 0;
  203. end;
  204. Function FileGetDate (Handle : Longint) : Longint;
  205. var
  206. Regs: registers;
  207. begin
  208. //!! for win95 an alternative function is available.
  209. Regs.Ebx := Handle;
  210. Regs.Eax := $5700;
  211. RealIntr($21, Regs);
  212. if Regs.Flags and CarryFlag <> 0 then
  213. result := -1
  214. else
  215. begin
  216. LongRec(result).Lo := Regs.cx;
  217. LongRec(result).Hi := Regs.dx;
  218. end ;
  219. end;
  220. Function FileSetDate (Handle, Age : Longint) : Longint;
  221. var
  222. Regs: registers;
  223. begin
  224. Regs.Ebx := Handle;
  225. Regs.Eax := $5701;
  226. Regs.Ecx := Lo(Age);
  227. Regs.Edx := Hi(Age);
  228. RealIntr($21, Regs);
  229. if Regs.Flags and CarryFlag <> 0 then
  230. result := -Regs.Ax
  231. else
  232. result := 0;
  233. end;
  234. Function FileGetAttr (Const FileName : String) : Longint;
  235. var
  236. Regs: registers;
  237. begin
  238. StringToTB(FileName);
  239. Regs.Edx := tb_offset;
  240. Regs.Ds := tb_segment;
  241. if LFNSupport then
  242. begin
  243. Regs.Ax := $7143;
  244. Regs.Bx := 0;
  245. end
  246. else
  247. Regs.Ax := $4300;
  248. RealIntr($21, Regs);
  249. if Regs.Flags and CarryFlag <> 0 then
  250. result := -1
  251. else
  252. result := Regs.Cx;
  253. end;
  254. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  255. var
  256. Regs: registers;
  257. begin
  258. StringToTB(FileName);
  259. Regs.Edx := tb_offset;
  260. Regs.Ds := tb_segment;
  261. if LFNSupport then
  262. begin
  263. Regs.Ax := $7143;
  264. Regs.Bx := 1;
  265. end
  266. else
  267. Regs.Ax := $4301;
  268. Regs.Cx := Attr;
  269. RealIntr($21, Regs);
  270. if Regs.Flags and CarryFlag <> 0 then
  271. result := -Regs.Ax
  272. else
  273. result := 0;
  274. end;
  275. Function DeleteFile (Const FileName : String) : Boolean;
  276. var
  277. Regs: registers;
  278. begin
  279. StringToTB(FileName);
  280. Regs.Edx := tb_offset;
  281. Regs.Ds := tb_segment;
  282. if LFNSupport then
  283. Regs.Eax := $7141
  284. else
  285. Regs.Eax := $4100;
  286. Regs.Esi := 0;
  287. Regs.Ecx := 0;
  288. RealIntr($21, Regs);
  289. result := (Regs.Flags and CarryFlag = 0);
  290. end;
  291. Function RenameFile (Const OldName, NewName : String) : Boolean;
  292. var
  293. Regs: registers;
  294. begin
  295. StringToTB(OldName + #0 + NewName);
  296. Regs.Edx := tb_offset;
  297. Regs.Ds := tb_segment;
  298. Regs.Edi := tb_offset + Length(OldName) + 1;
  299. Regs.Es := tb_segment;
  300. if LFNSupport then
  301. Regs.Eax := $7156
  302. else
  303. Regs.Eax := $5600;
  304. Regs.Ecx := $ff;
  305. RealIntr($21, Regs);
  306. result := (Regs.Flags and CarryFlag = 0);
  307. end;
  308. Function FileSearch (Const Name, DirList : String) : String;
  309. begin
  310. result := DOS.FSearch(Name, DirList);
  311. end;
  312. {****************************************************************************
  313. Disk Functions
  314. ****************************************************************************}
  315. TYPE ExtendedFat32FreeSpaceRec=packed Record
  316. RetSize : WORD; { (ret) size of returned structure}
  317. Strucversion : WORD; {(call) structure version (0000h)
  318. (ret) actual structure version (0000h)}
  319. SecPerClus, {number of sectors per cluster}
  320. BytePerSec, {number of bytes per sector}
  321. AvailClusters, {number of available clusters}
  322. TotalClusters, {total number of clusters on the drive}
  323. AvailPhysSect, {physical sectors available on the drive}
  324. TotalPhysSect, {total physical sectors on the drive}
  325. AvailAllocUnits, {Available allocation units}
  326. TotalAllocUnits : DWORD; {Total allocation units}
  327. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  328. END;
  329. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  330. VAR S : String;
  331. Rec : ExtendedFat32FreeSpaceRec;
  332. regs : registers;
  333. BEGIN
  334. if (swap(dosversion)>=$070A) AND LFNSupport then
  335. begin
  336. DosError:=0;
  337. S:='C:\'#0;
  338. if Drive=0 then
  339. begin
  340. GetDir(Drive,S);
  341. Setlength(S,4);
  342. S[4]:=#0;
  343. end
  344. else
  345. S[1]:=chr(Drive+64);
  346. Rec.Strucversion:=0;
  347. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  348. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  349. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  350. regs.ds:=tb_segment;
  351. regs.di:=tb_offset;
  352. regs.es:=tb_segment;
  353. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  354. regs.ax:=$7303;
  355. msdos(regs);
  356. if regs.ax<>$ffff then
  357. begin
  358. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  359. if Free then
  360. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  361. else
  362. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  363. end
  364. else
  365. Do_DiskData:=-1;
  366. end
  367. else
  368. begin
  369. DosError:=0;
  370. regs.dl:=drive;
  371. regs.ah:=$36;
  372. msdos(regs);
  373. if regs.ax<>$FFFF then
  374. begin
  375. if Free then
  376. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  377. else
  378. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  379. end
  380. else
  381. do_diskdata:=-1;
  382. end;
  383. end;
  384. function diskfree(drive : byte) : int64;
  385. begin
  386. diskfree:=Do_DiskData(drive,TRUE);
  387. end;
  388. function disksize(drive : byte) : int64;
  389. begin
  390. disksize:=Do_DiskData(drive,false);
  391. end;
  392. Function GetCurrentDir : String;
  393. begin
  394. GetDir(0, result);
  395. end;
  396. Function SetCurrentDir (Const NewDir : String) : Boolean;
  397. begin
  398. {$I-}
  399. ChDir(NewDir);
  400. {$I+}
  401. result := (IOResult = 0);
  402. end;
  403. Function CreateDir (Const NewDir : String) : Boolean;
  404. begin
  405. {$I-}
  406. MkDir(NewDir);
  407. {$I+}
  408. result := (IOResult = 0);
  409. end;
  410. Function RemoveDir (Const Dir : String) : Boolean;
  411. begin
  412. {$I-}
  413. RmDir(Dir);
  414. {$I+}
  415. result := (IOResult = 0);
  416. end;
  417. {****************************************************************************
  418. Time Functions
  419. ****************************************************************************}
  420. Procedure GetLocalTime(var SystemTime: TSystemTime);
  421. var
  422. Regs: Registers;
  423. begin
  424. Regs.ah := $2C;
  425. RealIntr($21, Regs);
  426. SystemTime.Hour := Regs.Ch;
  427. SystemTime.Minute := Regs.Cl;
  428. SystemTime.Second := Regs.Dh;
  429. SystemTime.MilliSecond := Regs.Dl;
  430. Regs.ah := $2A;
  431. RealIntr($21, Regs);
  432. SystemTime.Year := Regs.Cx;
  433. SystemTime.Month := Regs.Dh;
  434. SystemTime.Day := Regs.Dl;
  435. end ;
  436. {****************************************************************************
  437. Misc Functions
  438. ****************************************************************************}
  439. procedure Beep;
  440. begin
  441. end;
  442. {****************************************************************************
  443. Locale Functions
  444. ****************************************************************************}
  445. { Codepage constants }
  446. const
  447. CP_US = 437;
  448. CP_MultiLingual = 850;
  449. CP_SlavicLatin2 = 852;
  450. CP_Turkish = 857;
  451. CP_Portugal = 860;
  452. CP_IceLand = 861;
  453. CP_Canada = 863;
  454. CP_NorwayDenmark = 865;
  455. { CountryInfo }
  456. type
  457. TCountryInfo = packed record
  458. InfoId: byte;
  459. case integer of
  460. 1: ( Size: word;
  461. CountryId: word;
  462. CodePage: word;
  463. CountryInfo: array[0..33] of byte );
  464. 2: ( UpperCaseTable: longint );
  465. 4: ( FilenameUpperCaseTable: longint );
  466. 5: ( FilecharacterTable: longint );
  467. 6: ( CollatingTable: longint );
  468. 7: ( DBCSLeadByteTable: longint );
  469. end ;
  470. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  471. Var Regs: Registers;
  472. begin
  473. Regs.AH := $65;
  474. Regs.AL := InfoId;
  475. Regs.BX := CodePage;
  476. Regs.DX := CountryId;
  477. Regs.ES := transfer_buffer div 16;
  478. Regs.DI := transfer_buffer and 15;
  479. Regs.CX := SizeOf(TCountryInfo);
  480. RealIntr($21, Regs);
  481. DosMemGet(transfer_buffer div 16,
  482. transfer_buffer and 15,
  483. CountryInfo, Regs.CX );
  484. end;
  485. procedure InitAnsi;
  486. var
  487. CountryInfo: TCountryInfo; i: integer;
  488. begin
  489. { Fill table entries 0 to 127 }
  490. for i := 0 to 96 do
  491. UpperCaseTable[i] := chr(i);
  492. for i := 97 to 122 do
  493. UpperCaseTable[i] := chr(i - 32);
  494. for i := 123 to 127 do
  495. UpperCaseTable[i] := chr(i);
  496. for i := 0 to 64 do
  497. LowerCaseTable[i] := chr(i);
  498. for i := 65 to 90 do
  499. LowerCaseTable[i] := chr(i + 32);
  500. for i := 91 to 255 do
  501. LowerCaseTable[i] := chr(i);
  502. { Get country and codepage info }
  503. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  504. if CountryInfo.CodePage = 850 then
  505. begin
  506. { Special, known case }
  507. Move(CP850UCT, UpperCaseTable[128], 128);
  508. Move(CP850LCT, LowerCaseTable[128], 128);
  509. end
  510. else
  511. begin
  512. { this needs to be checked !!
  513. this is correct only if UpperCaseTable is
  514. and Offset:Segment word record (PM) }
  515. { get the uppercase table from dosmemory }
  516. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  517. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  518. for i := 128 to 255 do
  519. begin
  520. if UpperCaseTable[i] <> chr(i) then
  521. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  522. end;
  523. end;
  524. end;
  525. Procedure InitInternational;
  526. begin
  527. InitAnsi;
  528. end;
  529. function SysErrorMessage(ErrorCode: Integer): String;
  530. begin
  531. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  532. end;
  533. {****************************************************************************
  534. Os utils
  535. ****************************************************************************}
  536. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  537. begin
  538. Result:=getenv(EnvVar);
  539. end;
  540. {****************************************************************************
  541. Initialization code
  542. ****************************************************************************}
  543. Initialization
  544. InitExceptions; { Initialize exceptions. OS independent }
  545. InitInternational; { Initialize internationalization settings }
  546. Finalization
  547. OutOfMemory.Free;
  548. InValidPointer.Free;
  549. end.
  550. {
  551. $Log$
  552. Revision 1.4 2001-02-20 22:14:19 peter
  553. * merged getenvironmentvariable
  554. Revision 1.3 2000/08/30 06:29:19 michael
  555. + Merged syserrormsg fix
  556. Revision 1.2 2000/08/20 15:46:46 peter
  557. * sysutils.pp moved to target and merged with disk.inc, filutil.inc
  558. Revision 1.1.2.2 2000/08/22 19:21:48 michael
  559. + Implemented syserrormessage. Made dummies for go32v2 and OS/2
  560. * Changed linux/errors.pp so it uses pchars for storage.
  561. Revision 1.1.2.1 2000/08/20 15:08:32 peter
  562. * forgot the add command :(
  563. }