sysutils.pp 25 KB

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