sysutils.pp 23 KB

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