sysutils.pp 16 KB

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