sysutils.pp 27 KB

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