2
0

sysutils.pp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  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 OS/2
  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. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit sysutils;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. interface
  16. {$MODE objfpc}
  17. {$MODESWITCH OUT}
  18. {$IFDEF UNICODERTL}
  19. {$MODESWITCH UNICODESTRINGS}
  20. {$ELSE}
  21. {$H+}
  22. {$ENDIF}
  23. {$modeswitch typehelpers}
  24. {$modeswitch advancedrecords}
  25. {$DEFINE HAS_SLEEP}
  26. {$DEFINE HAS_OSERROR}
  27. { used OS file system APIs use ansistring }
  28. {$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
  29. { OS has an ansistring/single byte environment variable API }
  30. {$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
  31. { OS has an ansistring/single byte API for executing other processes }
  32. {$DEFINE EXECUTEPROCUNI}
  33. { Include platform independent interface part }
  34. {$i sysutilh.inc}
  35. implementation
  36. {$IFDEF FPC_DOTTEDUNITS}
  37. uses
  38. System.SysConst, OS2Api.doscalls;
  39. {$ELSE FPC_DOTTEDUNITS}
  40. uses
  41. sysconst, DosCalls;
  42. {$ENDIF FPC_DOTTEDUNITS}
  43. type
  44. (* Necessary here due to a different definition of TDateTime in DosCalls. *)
  45. TDateTime = System.TDateTime;
  46. threadvar
  47. LastOSError: cardinal;
  48. {$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
  49. {$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
  50. {$DEFINE FPC_FEXPAND_GETENV_PCHAR}
  51. {$DEFINE HAS_GETTICKCOUNT}
  52. {$DEFINE HAS_GETTICKCOUNT64}
  53. {$DEFINE HAS_LOCALTIMEZONEOFFSET}
  54. { Include platform independent implementation part }
  55. {$i sysutils.inc}
  56. {****************************************************************************
  57. File Functions
  58. ****************************************************************************}
  59. const
  60. ofRead = $0000; {Open for reading}
  61. ofWrite = $0001; {Open for writing}
  62. ofReadWrite = $0002; {Open for reading/writing}
  63. doDenyRW = $0010; {DenyAll (no sharing)}
  64. faCreateNew = $00010000; {Create if file does not exist}
  65. faOpenReplace = $00040000; {Truncate if file exists}
  66. faCreate = $00050000; {Create if file does not exist, truncate otherwise}
  67. FindResvdMask = $00003737 {Allowed bits for DosFindFirst parameter Attribute}
  68. and $000000FF; {combined with a mask for allowed attributes only}
  69. function FileOpen (const FileName: rawbytestring; Mode: integer): THandle;
  70. Var
  71. SystemFileName: RawByteString;
  72. Handle: THandle;
  73. Rc, Action: cardinal;
  74. begin
  75. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  76. (* DenyReadWrite if sharing not specified. *)
  77. if (Mode and 112 = 0) or (Mode and 112 > 64) then
  78. Mode := Mode or doDenyRW;
  79. Rc:=Sys_DosOpenL(PAnsiChar (SystemFileName), Handle, Action, 0, 0, 1, Mode, nil);
  80. If Rc=0 then
  81. FileOpen:=Handle
  82. else
  83. begin
  84. FileOpen:=feInvalidHandle; //FileOpen:=-RC;
  85. //should return feInvalidHandle(=-1) if fail, other negative returned value are no more errors
  86. OSErrorWatch (RC);
  87. end;
  88. end;
  89. function FileCreate (const FileName: RawByteString): THandle;
  90. begin
  91. FileCreate := FileCreate (FileName, doDenyRW, 777); (* Sharing to DenyAll *)
  92. end;
  93. function FileCreate (const FileName: RawByteString; Rights: integer): THandle;
  94. begin
  95. FileCreate := FileCreate (FileName, doDenyRW, Rights);
  96. (* Sharing to DenyAll *)
  97. end;
  98. function FileCreate (const FileName: RawByteString; ShareMode: integer;
  99. Rights: integer): THandle;
  100. var
  101. SystemFileName: RawByteString;
  102. Handle: THandle;
  103. RC, Action: cardinal;
  104. begin
  105. SystemFileName:=ToSingleByteFileSystemEncodedFileName(FileName);
  106. ShareMode := ShareMode and 112;
  107. (* Sharing to DenyAll as default in case of values not allowed by OS/2. *)
  108. if (ShareMode = 0) or (ShareMode > 64) then
  109. ShareMode := doDenyRW;
  110. RC := Sys_DosOpenL (PAnsiChar (SystemFileName), Handle, Action, 0, 0, $12,
  111. faCreate or ofReadWrite or ShareMode, nil);
  112. if RC = 0 then
  113. FileCreate := Handle
  114. else
  115. begin
  116. FileCreate := feInvalidHandle;
  117. OSErrorWatch (RC);
  118. end;
  119. End;
  120. function FileRead (Handle: THandle; Out Buffer; Count: longint): longint;
  121. Var
  122. T: cardinal;
  123. RC: cardinal;
  124. begin
  125. RC := DosRead (Handle, Buffer, Count, T);
  126. if RC = 0 then
  127. FileRead := longint (T)
  128. else
  129. begin
  130. FileRead := -1;
  131. OSErrorWatch (RC);
  132. end;
  133. end;
  134. function FileWrite (Handle: THandle; const Buffer; Count: longint): longint;
  135. Var
  136. T: cardinal;
  137. RC: cardinal;
  138. begin
  139. RC := DosWrite (Handle, Buffer, Count, T);
  140. if RC = 0 then
  141. FileWrite := longint (T)
  142. else
  143. begin
  144. FileWrite := -1;
  145. OSErrorWatch (RC);
  146. end;
  147. end;
  148. function FileSeek (Handle: THandle; FOffset, Origin: longint): longint;
  149. var
  150. NPos: int64;
  151. RC: cardinal;
  152. begin
  153. RC := Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos);
  154. if (RC = 0) and (NPos < high (longint)) then
  155. FileSeek:= longint (NPos)
  156. else
  157. begin
  158. FileSeek:=-1;
  159. OSErrorWatch (RC);
  160. end;
  161. end;
  162. function FileSeek (Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
  163. var
  164. NPos: int64;
  165. RC: cardinal;
  166. begin
  167. RC := Sys_DosSetFilePtrL (Handle, FOffset, Origin, NPos);
  168. if RC = 0 then
  169. FileSeek:= NPos
  170. else
  171. begin
  172. FileSeek:=-1;
  173. OSErrorWatch (RC);
  174. end;
  175. end;
  176. procedure FileClose (Handle: THandle);
  177. var
  178. RC: cardinal;
  179. begin
  180. RC := DosClose (Handle);
  181. if RC <> 0 then
  182. OSErrorWatch (RC);
  183. end;
  184. function FileTruncate (Handle: THandle; Size: Int64): boolean;
  185. var
  186. RC: cardinal;
  187. begin
  188. RC := Sys_DosSetFileSizeL(Handle, Size);
  189. FileTruncate := RC = 0;
  190. if RC = 0 then
  191. FileSeek(Handle, 0, 2)
  192. else
  193. OSErrorWatch (RC);
  194. end;
  195. function FileAge (const FileName: RawByteString): Int64;
  196. var Handle: longint;
  197. begin
  198. Handle := FileOpen (FileName, 0);
  199. if Handle <> -1 then
  200. begin
  201. Result := FileGetDate (Handle);
  202. FileClose (Handle);
  203. end
  204. else
  205. Result := -1;
  206. end;
  207. function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
  208. begin
  209. Result := False;
  210. end;
  211. function FileExists (const FileName: RawByteString; FollowLink : Boolean): boolean;
  212. var
  213. L: longint;
  214. begin
  215. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  216. if FileName = '' then
  217. Result := false
  218. else
  219. begin
  220. L := FileGetAttr (FileName);
  221. Result := (L >= 0) and (L and (faDirectory or faVolumeID) = 0);
  222. (* Neither VolumeIDs nor directories are files. *)
  223. end;
  224. end;
  225. type PSearchRec = ^TSearchRec;
  226. Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
  227. var SR: PSearchRec;
  228. FStat: PFileFindBuf3L;
  229. Count: cardinal;
  230. Err: cardinal;
  231. I: cardinal;
  232. SystemEncodedPath: RawByteString;
  233. begin
  234. SystemEncodedPath := ToSingleByteFileSystemEncodedFileName(Path);
  235. New (FStat);
  236. Rslt.FindHandle := THandle ($FFFFFFFF);
  237. Count := 1;
  238. if FSApi64 then
  239. Err := DosFindFirst (PAnsiChar (SystemEncodedPath), Rslt.FindHandle,
  240. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandardL)
  241. else
  242. Err := DosFindFirst (PAnsiChar (SystemEncodedPath), Rslt.FindHandle,
  243. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandard);
  244. if Err <> 0 then
  245. OSErrorWatch (Err)
  246. else if Count = 0 then
  247. Err := 18;
  248. InternalFindFirst := -Err;
  249. if Err = 0 then
  250. begin
  251. Rslt.ExcludeAttr := 0;
  252. Rslt.Time := cardinal (FStat^.DateLastWrite) shl 16 + FStat^.TimeLastWrite;
  253. if FSApi64 then
  254. begin
  255. Rslt.Size := FStat^.FileSize;
  256. Name := FStat^.Name;
  257. Rslt.Attr := FStat^.AttrFile;
  258. end
  259. else
  260. begin
  261. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  262. Name := PFileFindBuf3 (FStat)^.Name;
  263. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  264. end;
  265. SetCodePage (Name, DefaultFileSystemCodePage, false);
  266. end
  267. else
  268. InternalFindClose(Rslt.FindHandle);
  269. Dispose (FStat);
  270. end;
  271. Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
  272. var
  273. SR: PSearchRec;
  274. FStat: PFileFindBuf3L;
  275. Count: cardinal;
  276. Err: cardinal;
  277. begin
  278. New (FStat);
  279. Count := 1;
  280. Err := DosFindNext (Rslt.FindHandle, FStat, SizeOf (FStat^), Count);
  281. if Err <> 0 then
  282. OSErrorWatch (Err)
  283. else if Count = 0 then
  284. Err := 18;
  285. InternalFindNext := -Err;
  286. if Err = 0 then
  287. begin
  288. Rslt.ExcludeAttr := 0;
  289. Rslt.Time := cardinal (FStat^.DateLastWrite) shl 16 + FStat^.TimeLastWrite;
  290. if FSApi64 then
  291. begin
  292. Rslt.Size := FStat^.FileSize;
  293. Name := FStat^.Name;
  294. Rslt.Attr := FStat^.AttrFile;
  295. end
  296. else
  297. begin
  298. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  299. Name := PFileFindBuf3 (FStat)^.Name;
  300. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  301. end;
  302. SetCodePage (Name, DefaultFileSystemCodePage, false);
  303. end;
  304. Dispose (FStat);
  305. end;
  306. Procedure InternalFindClose(var Handle: THandle);
  307. var
  308. SR: PSearchRec;
  309. RC: cardinal;
  310. begin
  311. RC := DosFindClose (Handle);
  312. Handle := 0;
  313. if RC <> 0 then
  314. OSErrorWatch (RC);
  315. end;
  316. function FileGetDate (Handle: THandle): Int64;
  317. var
  318. FStat: TFileStatus3;
  319. Time: Longint;
  320. RC: cardinal;
  321. begin
  322. RC := DosQueryFileInfo(Handle, ilStandard, @FStat, SizeOf(FStat));
  323. if RC = 0 then
  324. begin
  325. Time := FStat.TimeLastWrite + dword (FStat.DateLastWrite) shl 16;
  326. if Time = 0 then
  327. Time := FStat.TimeCreation + dword (FStat.DateCreation) shl 16;
  328. end else
  329. begin
  330. Time:=0;
  331. OSErrorWatch (RC);
  332. end;
  333. FileGetDate:=Time;
  334. end;
  335. function FileSetDate (Handle: THandle; Age: Int64): longint;
  336. var
  337. FStat: PFileStatus3;
  338. RC: cardinal;
  339. begin
  340. New (FStat);
  341. RC := DosQueryFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  342. if RC <> 0 then
  343. begin
  344. FileSetDate := -1;
  345. OSErrorWatch (RC);
  346. end
  347. else
  348. begin
  349. FStat^.DateLastAccess := Hi (dword (Age));
  350. FStat^.DateLastWrite := Hi (dword (Age));
  351. FStat^.TimeLastAccess := Lo (dword (Age));
  352. FStat^.TimeLastWrite := Lo (dword (Age));
  353. RC := DosSetFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  354. if RC <> 0 then
  355. begin
  356. FileSetDate := -1;
  357. OSErrorWatch (RC);
  358. end
  359. else
  360. FileSetDate := 0;
  361. end;
  362. Dispose (FStat);
  363. end;
  364. function FileGetAttr (const FileName: RawByteString): longint;
  365. var
  366. FS: PFileStatus3;
  367. SystemFileName: RawByteString;
  368. RC: cardinal;
  369. begin
  370. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  371. New(FS);
  372. RC := DosQueryPathInfo(PAnsiChar (SystemFileName), ilStandard, FS, SizeOf(FS^));
  373. if RC = 0 then
  374. Result := FS^.AttrFile
  375. else
  376. begin
  377. Result := - longint (RC);
  378. OSErrorWatch (RC);
  379. end;
  380. Dispose(FS);
  381. end;
  382. function FileSetAttr (const Filename: RawByteString; Attr: longint): longint;
  383. Var
  384. FS: PFileStatus3;
  385. SystemFileName: RawByteString;
  386. RC: cardinal;
  387. Begin
  388. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  389. New(FS);
  390. RC := DosQueryPathInfo (PAnsiChar (SystemFileName), ilStandard, FS, SizeOf (FS^));
  391. if RC = 0 then
  392. begin
  393. FS^.AttrFile:=Attr;
  394. RC := DosSetPathInfo(PAnsiChar (SystemFileName), ilStandard, FS, SizeOf(FS^), 0);
  395. if RC <> 0 then
  396. OSErrorWatch (RC);
  397. end
  398. else
  399. OSErrorWatch (RC);
  400. Result := - longint (RC);
  401. Dispose(FS);
  402. end;
  403. function DeleteFile (const FileName: RawByteString): boolean;
  404. var
  405. SystemFileName: RawByteString;
  406. RC: cardinal;
  407. Begin
  408. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  409. RC := DosDelete (PAnsiChar (SystemFileName));
  410. if RC <> 0 then
  411. begin
  412. Result := false;
  413. OSErrorWatch (RC);
  414. end
  415. else
  416. Result := true;
  417. End;
  418. function RenameFile (const OldName, NewName: RawByteString): boolean;
  419. var
  420. OldSystemFileName, NewSystemFileName: RawByteString;
  421. RC: cardinal;
  422. Begin
  423. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  424. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  425. RC := DosMove (PAnsiChar (OldSystemFileName), PAnsiChar (NewSystemFileName));
  426. if RC <> 0 then
  427. begin
  428. Result := false;
  429. OSErrorWatch (RC);
  430. end
  431. else
  432. Result := true;
  433. End;
  434. {****************************************************************************
  435. Disk Functions
  436. ****************************************************************************}
  437. function DiskFree (Drive: byte): int64;
  438. var FI: TFSinfo;
  439. RC: cardinal;
  440. begin
  441. {In OS/2, we use the filesystem information.}
  442. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  443. if RC = 0 then
  444. DiskFree := int64 (FI.Free_Clusters) *
  445. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  446. else
  447. begin
  448. DiskFree := -1;
  449. OSErrorWatch (RC);
  450. end;
  451. end;
  452. function DiskSize (Drive: byte): int64;
  453. var FI: TFSinfo;
  454. RC: cardinal;
  455. begin
  456. {In OS/2, we use the filesystem information.}
  457. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  458. if RC = 0 then
  459. DiskSize := int64 (FI.Total_Clusters) *
  460. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  461. else
  462. begin
  463. DiskSize := -1;
  464. OSErrorWatch (RC);
  465. end;
  466. end;
  467. function DirectoryExists (const Directory: RawByteString; FollowLink : Boolean): boolean;
  468. var
  469. L: longint;
  470. begin
  471. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  472. if Directory = '' then
  473. Result := false
  474. else
  475. begin
  476. if ((Length (Directory) = 2) or
  477. (Length (Directory) = 3) and
  478. (Directory [3] in AllowDirectorySeparators)) and
  479. (Directory [2] in AllowDriveSeparators) and
  480. (UpCase (Directory [1]) in ['A'..'Z']) then
  481. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  482. L := FileGetAttr (Directory + '.')
  483. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  484. (Length (Directory) > 1) and
  485. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  486. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  487. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  488. else
  489. L := FileGetAttr (Directory);
  490. Result := (L > 0) and (L and faDirectory = faDirectory);
  491. end;
  492. end;
  493. {****************************************************************************
  494. Time Functions
  495. ****************************************************************************}
  496. {$DEFINE HAS_DUAL_TZHANDLING}
  497. {$I tzenv.inc}
  498. var
  499. TZAlwaysFromEnv: boolean;
  500. procedure InitTZ2; inline;
  501. var
  502. DT: {$IFDEF FPC_DOTTEDUNITS}OS2Api.{$endif}DosCalls.TDateTime;
  503. begin
  504. DosGetDateTime (DT);
  505. TZAlwaysFromEnv := DT.TimeZone = -1;
  506. end;
  507. procedure GetLocalTime (var SystemTime: TSystemTime);
  508. var
  509. DT: {$IFDEF FPC_DOTTEDUNITS}OS2Api.{$endif}DosCalls.TDateTime;
  510. begin
  511. DosGetDateTime(DT);
  512. with SystemTime do
  513. begin
  514. Year:=DT.Year;
  515. Month:=DT.Month;
  516. Day:=DT.Day;
  517. DayOfWeek:=DT.WeekDay;
  518. Hour:=DT.Hour;
  519. Minute:=DT.Minute;
  520. Second:=DT.Second;
  521. MilliSecond:=DT.Sec100 * 10;
  522. end;
  523. end;
  524. function GetUniversalTime (var SystemTime: TSystemTime): boolean;
  525. var
  526. DT: {$IFDEF FPC_DOTTEDUNITS}OS2Api.{$endif}DosCalls.TDateTime;
  527. Offset: longint;
  528. begin
  529. if TZAlwaysFromEnv then
  530. begin
  531. GetLocalTime (SystemTime);
  532. Offset := GetLocalTimeOffset;
  533. end
  534. else
  535. begin
  536. DosGetDateTime (DT);
  537. with SystemTime do
  538. begin
  539. Year := DT.Year;
  540. Month := DT.Month;
  541. Day := DT.Day;
  542. DayOfWeek := DT.WeekDay;
  543. Hour := DT.Hour;
  544. Minute := DT.Minute;
  545. Second := DT.Second;
  546. MilliSecond := DT.Sec100 * 10;
  547. end;
  548. if DT.TimeZone = -1 then
  549. Offset := GetLocalTimeOffset
  550. else
  551. Offset := DT.TimeZone;
  552. end;
  553. UpdateTimeWithOffset (SystemTime, Offset);
  554. GetUniversalTime := true;
  555. end;
  556. function GetLocalTimeOffset: integer;
  557. var
  558. DT: {$IFDEF FPC_DOTTEDUNITS}OS2Api.{$endif}DosCalls.TDateTime;
  559. begin
  560. if TZAlwaysFromEnv then
  561. begin
  562. if InDST then
  563. GetLocalTimeOffset := DSTOffsetMin
  564. else
  565. GetLocalTimeOffset := TZOffsetMin;
  566. end
  567. else
  568. begin
  569. DosGetDateTime (DT);
  570. if DT.TimeZone <> -1 then
  571. GetLocalTimeOffset := DT.TimeZone
  572. else
  573. begin
  574. if InDST then
  575. GetLocalTimeOffset := DSTOffsetMin
  576. else
  577. GetLocalTimeOffset := TZOffsetMin;
  578. end;
  579. end;
  580. end;
  581. {****************************************************************************
  582. Misc Functions
  583. ****************************************************************************}
  584. procedure sysbeep;
  585. begin
  586. DosBeep (800, 250);
  587. end;
  588. {****************************************************************************
  589. Locale Functions
  590. ****************************************************************************}
  591. var
  592. Country: TCountryCode;
  593. CtryInfo: TCountryInfo;
  594. procedure InitAnsi;
  595. var
  596. I: byte;
  597. RC: cardinal;
  598. begin
  599. for I := 0 to 255 do
  600. UpperCaseTable [I] := Chr (I);
  601. Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
  602. FillChar (Country, SizeOf (Country), 0);
  603. DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
  604. for I := 0 to 255 do
  605. if UpperCaseTable [I] <> Chr (I) then
  606. LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
  607. end;
  608. procedure InitInternational;
  609. var
  610. Size: cardinal;
  611. RC: cardinal;
  612. begin
  613. Size := 0;
  614. FillChar (Country, SizeOf (Country), 0);
  615. FillChar (CtryInfo, SizeOf (CtryInfo), 0);
  616. RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
  617. if RC = 0 then
  618. begin
  619. DateSeparator := CtryInfo.DateSeparator;
  620. case CtryInfo.DateFormat of
  621. 1: begin
  622. ShortDateFormat := 'd/m/y';
  623. LongDateFormat := 'dd" "mmmm" "yyyy';
  624. end;
  625. 2: begin
  626. ShortDateFormat := 'y/m/d';
  627. LongDateFormat := 'yyyy" "mmmm" "dd';
  628. end;
  629. 3: begin
  630. ShortDateFormat := 'm/d/y';
  631. LongDateFormat := 'mmmm" "dd" "yyyy';
  632. end;
  633. end;
  634. TimeSeparator := CtryInfo.TimeSeparator;
  635. DecimalSeparator := CtryInfo.DecimalSeparator;
  636. ThousandSeparator := CtryInfo.ThousandSeparator;
  637. CurrencyFormat := CtryInfo.CurrencyFormat;
  638. CurrencyString := PAnsiChar (CtryInfo.CurrencyUnit);
  639. end
  640. else
  641. OSErrorWatch (RC);
  642. InitAnsi;
  643. InitInternationalGeneric;
  644. end;
  645. function SysErrorMessage(ErrorCode: Integer): String;
  646. const
  647. SysMsgFile: array [0..10] of AnsiChar = 'OSO001.MSG'#0;
  648. var
  649. OutBuf: array [0..999] of AnsiChar;
  650. RetMsgSize: cardinal;
  651. RC: cardinal;
  652. begin
  653. RC := DosGetMessage (nil, 0, @OutBuf [0], SizeOf (OutBuf),
  654. ErrorCode, @SysMsgFile [0], RetMsgSize);
  655. if RC = 0 then
  656. begin
  657. SetLength (Result, RetMsgSize);
  658. Move (OutBuf [0], Result [1], RetMsgSize);
  659. end
  660. else
  661. begin
  662. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  663. OSErrorWatch (RC);
  664. end;
  665. end;
  666. {****************************************************************************
  667. OS Utils
  668. ****************************************************************************}
  669. function GetEnvPChar (EnvVar: shortstring): PAnsiChar;
  670. (* The assembler version is more than three times as fast as Pascal. *)
  671. var
  672. P: PAnsiChar;
  673. begin
  674. EnvVar := UpCase (EnvVar);
  675. {$ASMMODE INTEL}
  676. asm
  677. cld
  678. mov edi, Environment
  679. lea esi, EnvVar
  680. xor eax, eax
  681. lodsb
  682. @NewVar:
  683. cmp byte ptr [edi], 0
  684. jz @Stop
  685. push eax { eax contains length of searched variable name }
  686. push esi { esi points to the beginning of the variable name }
  687. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  688. mov edx, edi { pointer to beginning of variable name saved in edx }
  689. mov al, '=' { searching until '=' (end of variable name) }
  690. repne
  691. scasb { scan until '=' not found }
  692. neg ecx { what was the name length? }
  693. dec ecx { corrected }
  694. dec ecx { exclude the '=' character }
  695. pop esi { restore pointer to beginning of variable name }
  696. pop eax { restore length of searched variable name }
  697. push eax { and save both of them again for later use }
  698. push esi
  699. cmp ecx, eax { compare length of searched variable name with name }
  700. jnz @NotEqual { ... of currently found variable, jump if different }
  701. xchg edx, edi { pointer to current variable name restored in edi }
  702. repe
  703. cmpsb { compare till the end of variable name }
  704. xchg edx, edi { pointer to beginning of variable contents in edi }
  705. jz @Equal { finish if they're equal }
  706. @NotEqual:
  707. xor eax, eax { look for 00h }
  708. mov ecx, -1 { it _must_ be found }
  709. repne
  710. scasb { scan until found }
  711. pop esi { restore pointer to beginning of variable name }
  712. pop eax { restore length of searched variable name }
  713. jmp @NewVar { ... or continue with new variable otherwise }
  714. @Stop:
  715. xor eax, eax
  716. mov P, eax { Not found - return nil }
  717. jmp @End
  718. @Equal:
  719. pop esi { restore the stack position }
  720. pop eax
  721. mov P, edi { place pointer to variable contents in P }
  722. @End:
  723. end ['eax','ecx','edx','esi','edi'];
  724. GetEnvPChar := P;
  725. end;
  726. {$ASMMODE ATT}
  727. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  728. begin
  729. GetEnvironmentVariable := GetEnvPChar (EnvVar);
  730. end;
  731. Function GetEnvironmentVariableCount : Integer;
  732. begin
  733. (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
  734. GetEnvironmentVariableCount := EnvC;
  735. end;
  736. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  737. begin
  738. Result:=FPCGetEnvStrFromP (EnvP, Index);
  739. end;
  740. procedure Sleep (Milliseconds: cardinal);
  741. begin
  742. DosSleep (Milliseconds);
  743. end;
  744. function SysTimerTick: QWord;
  745. var
  746. L: cardinal;
  747. begin
  748. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  749. SysTimerTick := L;
  750. end;
  751. function ExecuteProcess (const Path: RawByteString;
  752. const ComLine: RawByteString;Flags:TExecuteFlags=[]): integer;
  753. var
  754. E: EOSError;
  755. CommandLine: RawByteString;
  756. Args0, Args: {$IFDEF FPC_DOTTEDUNITS}OS2Api.{$endif}DosCalls.PByteArray;
  757. ObjNameBuf: PAnsiChar;
  758. ArgSize: word;
  759. Res: TResultCodes;
  760. ObjName: shortstring;
  761. RC: cardinal;
  762. ExecAppType: cardinal;
  763. MaxArgsSize: PtrUInt; (* Amount of memory reserved for arguments in bytes. *)
  764. MaxArgsSizeInc: word;
  765. const
  766. ObjBufSize = 512;
  767. function StartSession: cardinal;
  768. var
  769. HQ: THandle;
  770. SPID, STID, QName: shortstring;
  771. SID, PID: cardinal;
  772. SD: TStartData;
  773. RD: TRequestData;
  774. PCI: PChildInfo;
  775. CISize: cardinal;
  776. Prio: byte;
  777. begin
  778. Result := $FFFFFFFF;
  779. FillChar (SD, SizeOf (SD), 0);
  780. SD.Length := SizeOf (SD);
  781. SD.Related := ssf_Related_Child;
  782. if FileExists (Path) then
  783. (* Full path necessary for starting different executable files from current *)
  784. (* directory. *)
  785. CommandLine := ExpandFileName (Path)
  786. else
  787. CommandLine := Path;
  788. SD.PgmName := PAnsiChar (CommandLine);
  789. if ComLine <> '' then
  790. SD.PgmInputs := PAnsiChar (ComLine);
  791. if ExecInheritsHandles in Flags then
  792. SD.InheritOpt := ssf_InhertOpt_Parent;
  793. Str (GetProcessID, SPID);
  794. Str (ThreadID, STID);
  795. QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
  796. SD.TermQ := @QName [1];
  797. SD.ObjectBuffer := ObjNameBuf;
  798. SD.ObjectBuffLen := ObjBufSize;
  799. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  800. if RC <> 0 then
  801. begin
  802. Move (QName [1], ObjNameBuf^, Length (QName));
  803. OSErrorWatch (RC);
  804. end
  805. else
  806. begin
  807. RC := DosStartSession (SD, SID, PID);
  808. if (RC = 0) or (RC = 457) then
  809. begin
  810. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  811. if RC = 0 then
  812. begin
  813. Result := PCI^.Return;
  814. RC := DosCloseQueue (HQ);
  815. if RC <> 0 then
  816. OSErrorWatch (RC);
  817. RC := DosFreeMem (PCI);
  818. if RC <> 0 then
  819. OSErrorWatch (RC);
  820. FreeMem (ObjNameBuf, ObjBufSize);
  821. end
  822. else
  823. begin
  824. OSErrorWatch (RC);
  825. RC := DosCloseQueue (HQ);
  826. OSErrorWatch (RC);
  827. end;
  828. end
  829. else
  830. begin
  831. OSErrorWatch (RC);
  832. RC := DosCloseQueue (HQ);
  833. if RC <> 0 then
  834. OSErrorWatch (RC);
  835. end;
  836. end;
  837. end;
  838. begin
  839. Result := integer ($FFFFFFFF);
  840. ObjName := '';
  841. GetMem (ObjNameBuf, ObjBufSize);
  842. FillChar (ObjNameBuf^, ObjBufSize, 0);
  843. RC := DosQueryAppType (PAnsiChar (Path), ExecAppType);
  844. if RC <> 0 then
  845. begin
  846. OSErrorWatch (RC);
  847. if (RC = 190) or (RC = 191) then
  848. Result := StartSession;
  849. end
  850. else
  851. begin
  852. if (ApplicationType and 3 = ExecAppType and 3) then
  853. (* DosExecPgm should work... *)
  854. begin
  855. MaxArgsSize := Length (ComLine) + Length (Path) + 256; (* More than enough *)
  856. if MaxArgsSize > high (word) then
  857. Exit;
  858. if ComLine = '' then
  859. begin
  860. Args0 := nil;
  861. Args := nil;
  862. end
  863. else
  864. begin
  865. GetMem (Args0, MaxArgsSize);
  866. Args := Args0;
  867. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  868. (* should not cross 64K boundary. *)
  869. while ((PtrUInt (Args) + MaxArgsSize) and $FFFF) < MaxArgsSize do
  870. begin
  871. MaxArgsSizeInc := MaxArgsSize -
  872. ((PtrUInt (Args) + MaxArgsSize) and $FFFF);
  873. Inc (MaxArgsSize, MaxArgsSizeInc);
  874. if MaxArgsSize > high (word) then
  875. Exit;
  876. ReallocMem (Args0, MaxArgsSize);
  877. Inc (pointer (Args), MaxArgsSizeInc);
  878. end;
  879. ArgSize := 0;
  880. Move (Path [1], Args^ [ArgSize], Length (Path));
  881. Inc (ArgSize, Length (Path));
  882. Args^ [ArgSize] := 0;
  883. Inc (ArgSize);
  884. {Now do the real arguments.}
  885. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  886. Inc (ArgSize, Length (ComLine));
  887. Args^ [ArgSize] := 0;
  888. Inc (ArgSize);
  889. Args^ [ArgSize] := 0;
  890. end;
  891. Res.ExitCode := $FFFFFFFF;
  892. RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res,
  893. PAnsiChar (Path));
  894. if RC <> 0 then
  895. OSErrorWatch (RC);
  896. if Args0 <> nil then
  897. FreeMem (Args0, MaxArgsSize);
  898. if RC = 0 then
  899. begin
  900. Result := Res.ExitCode;
  901. FreeMem (ObjNameBuf, ObjBufSize);
  902. end
  903. end
  904. end;
  905. if RC <> 0 then
  906. begin
  907. ObjName := StrPas (ObjNameBuf);
  908. FreeMem (ObjNameBuf, ObjBufSize);
  909. if ComLine = '' then
  910. CommandLine := Path
  911. else
  912. CommandLine := Path + ' ' + ComLine;
  913. if ObjName = '' then
  914. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
  915. else
  916. E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
  917. E.ErrorCode := Result;
  918. raise E;
  919. end;
  920. end;
  921. function ExecuteProcess (const Path: RawByteString;
  922. const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
  923. var
  924. CommandLine: AnsiString;
  925. I: integer;
  926. begin
  927. Commandline := '';
  928. for I := 0 to High (ComLine) do
  929. if Pos (' ', ComLine [I]) <> 0 then
  930. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  931. else
  932. CommandLine := CommandLine + ' ' + Comline [I];
  933. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  934. end;
  935. function GetTickCount: LongWord;
  936. var
  937. L: cardinal;
  938. begin
  939. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  940. GetTickCount := L;
  941. end;
  942. function GetTickCount64: QWord;
  943. var
  944. Freq2: cardinal;
  945. T: QWord;
  946. begin
  947. DosTmrQueryFreq (Freq2);
  948. DosTmrQueryTime (T);
  949. GetTickCount64 := T div (QWord (Freq2) div 1000);
  950. {$NOTE GetTickCount64 takes 20 microseconds on 1GHz CPU, GetTickCount not measurable}
  951. end;
  952. const
  953. OrigOSErrorWatch: TOSErrorWatch = nil;
  954. procedure TrackLastOSError (Error: cardinal);
  955. begin
  956. LastOSError := Error;
  957. OrigOSErrorWatch (Error);
  958. end;
  959. function GetLastOSError: Integer;
  960. begin
  961. GetLastOSError := Integer (LastOSError);
  962. end;
  963. {****************************************************************************
  964. Initialization code
  965. ****************************************************************************}
  966. Initialization
  967. InitExceptions; { Initialize exceptions. OS independent }
  968. InitInternational; { Initialize internationalization settings }
  969. OnBeep:=@SysBeep;
  970. LastOSError := 0;
  971. OrigOSErrorWatch := TOSErrorWatch (SetOSErrorTracking (@TrackLastOSError));
  972. InitTZ;
  973. InitTZ2;
  974. Finalization
  975. FreeTerminateProcs;
  976. DoneExceptions;
  977. end.