sysutils.pp 28 KB

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