sysutils.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  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: string): 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 FindFirst (const Path: string; Attr: longint; out Rslt: TSearchRec): longint;
  169. var SR: PSearchRec;
  170. FStat: PFileFindBuf3L;
  171. Count: cardinal;
  172. Err: cardinal;
  173. I: cardinal;
  174. begin
  175. New (FStat);
  176. Rslt.FindHandle := THandle ($FFFFFFFF);
  177. Count := 1;
  178. if FSApi64 then
  179. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  180. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandardL)
  181. else
  182. Err := DosFindFirst (PChar (Path), Rslt.FindHandle,
  183. Attr and FindResvdMask, FStat, SizeOf (FStat^), Count, ilStandard);
  184. if (Err = 0) and (Count = 0) then
  185. Err := 18;
  186. FindFirst := -Err;
  187. if Err = 0 then
  188. begin
  189. Rslt.ExcludeAttr := 0;
  190. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  191. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  192. if FSApi64 then
  193. begin
  194. Rslt.Size := FStat^.FileSize;
  195. Rslt.Name := FStat^.Name;
  196. Rslt.Attr := FStat^.AttrFile;
  197. end
  198. else
  199. begin
  200. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  201. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  202. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  203. end;
  204. end
  205. else
  206. FindClose(Rslt);
  207. Dispose (FStat);
  208. end;
  209. function FindNext (var Rslt: TSearchRec): longint;
  210. var
  211. SR: PSearchRec;
  212. FStat: PFileFindBuf3L;
  213. Count: cardinal;
  214. Err: cardinal;
  215. begin
  216. New (FStat);
  217. Count := 1;
  218. Err := DosFindNext (Rslt.FindHandle, FStat, SizeOf (FStat^), Count);
  219. if (Err = 0) and (Count = 0) then
  220. Err := 18;
  221. FindNext := -Err;
  222. if Err = 0 then
  223. begin
  224. Rslt.ExcludeAttr := 0;
  225. TRec (Rslt.Time).T := FStat^.TimeLastWrite;
  226. TRec (Rslt.Time).D := FStat^.DateLastWrite;
  227. if FSApi64 then
  228. begin
  229. Rslt.Size := FStat^.FileSize;
  230. Rslt.Name := FStat^.Name;
  231. Rslt.Attr := FStat^.AttrFile;
  232. end
  233. else
  234. begin
  235. Rslt.Size := PFileFindBuf3 (FStat)^.FileSize;
  236. Rslt.Name := PFileFindBuf3 (FStat)^.Name;
  237. Rslt.Attr := PFileFindBuf3 (FStat)^.AttrFile;
  238. end;
  239. end;
  240. Dispose (FStat);
  241. end;
  242. procedure FindClose (var F: TSearchrec);
  243. var
  244. SR: PSearchRec;
  245. begin
  246. DosFindClose (F.FindHandle);
  247. F.FindHandle := 0;
  248. end;
  249. function FileGetDate (Handle: THandle): longint;
  250. var
  251. FStat: TFileStatus3;
  252. Time: Longint;
  253. RC: cardinal;
  254. begin
  255. RC := DosQueryFileInfo(Handle, ilStandard, @FStat, SizeOf(FStat));
  256. if RC = 0 then
  257. begin
  258. Time := FStat.TimeLastWrite + longint (FStat.DateLastWrite) shl 16;
  259. if Time = 0 then
  260. Time := FStat.TimeCreation + longint (FStat.DateCreation) shl 16;
  261. end else
  262. Time:=0;
  263. FileGetDate:=Time;
  264. end;
  265. function FileSetDate (Handle: THandle; Age: longint): longint;
  266. var
  267. FStat: PFileStatus3;
  268. RC: cardinal;
  269. begin
  270. New (FStat);
  271. RC := DosQueryFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  272. if RC <> 0 then
  273. FileSetDate := -1
  274. else
  275. begin
  276. FStat^.DateLastAccess := Hi (Age);
  277. FStat^.DateLastWrite := Hi (Age);
  278. FStat^.TimeLastAccess := Lo (Age);
  279. FStat^.TimeLastWrite := Lo (Age);
  280. RC := DosSetFileInfo (Handle, ilStandard, FStat, SizeOf (FStat^));
  281. if RC <> 0 then
  282. FileSetDate := -1
  283. else
  284. FileSetDate := 0;
  285. end;
  286. Dispose (FStat);
  287. end;
  288. function FileGetAttr (const FileName: RawByteString): longint;
  289. var
  290. FS: PFileStatus3;
  291. SystemFileName: RawByteString;
  292. begin
  293. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  294. New(FS);
  295. Result:=-DosQueryPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^));
  296. If Result=0 Then Result:=FS^.attrFile;
  297. Dispose(FS);
  298. end;
  299. function FileSetAttr (const Filename: RawByteString; Attr: longint): longint;
  300. Var
  301. FS: PFileStatus3;
  302. SystemFileName: RawByteString;
  303. Begin
  304. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  305. New(FS);
  306. FillChar(FS, SizeOf(FS^), 0);
  307. FS^.AttrFile:=Attr;
  308. Result:=-DosSetPathInfo(PChar (SystemFileName), ilStandard, FS, SizeOf(FS^), 0);
  309. Dispose(FS);
  310. end;
  311. function DeleteFile (const FileName: RawByteString): boolean;
  312. var
  313. SystemFileName: RawByteString;
  314. Begin
  315. SystemFileName:=ToSingleByteFileSystemEncodedFileName(Filename);
  316. Result:=(DosDelete(PChar (FileName))=0);
  317. End;
  318. function RenameFile (const OldName, NewName: RawByteString): boolean;
  319. var
  320. OldSystemFileName, NewSystemFileName: RawByteString;
  321. Begin
  322. OldSystemFileName:=ToSingleByteFileSystemEncodedFileName(OldName);
  323. NewSystemFileName:=ToSingleByteFileSystemEncodedFileName(NewName);
  324. Result:=(DosMove(PChar (OldSystemFileName), PChar (NewSystemFileName))=0);
  325. End;
  326. {****************************************************************************
  327. Disk Functions
  328. ****************************************************************************}
  329. function DiskFree (Drive: byte): int64;
  330. var FI: TFSinfo;
  331. RC: cardinal;
  332. begin
  333. {In OS/2, we use the filesystem information.}
  334. RC := DosQueryFSInfo (Drive, 1, FI, SizeOf (FI));
  335. if RC = 0 then
  336. DiskFree := int64 (FI.Free_Clusters) *
  337. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  338. else
  339. DiskFree := -1;
  340. end;
  341. function DiskSize (Drive: byte): int64;
  342. var FI: TFSinfo;
  343. RC: cardinal;
  344. begin
  345. {In OS/2, we use the filesystem information.}
  346. RC := DosQueryFSinfo (Drive, 1, FI, SizeOf (FI));
  347. if RC = 0 then
  348. DiskSize := int64 (FI.Total_Clusters) *
  349. int64 (FI.Sectors_Per_Cluster) * int64 (FI.Bytes_Per_Sector)
  350. else
  351. DiskSize := -1;
  352. end;
  353. function DirectoryExists (const Directory: RawByteString): boolean;
  354. var
  355. L: longint;
  356. begin
  357. { no need to convert to DefaultFileSystemEncoding, FileGetAttr will do that }
  358. if Directory = '' then
  359. Result := false
  360. else
  361. begin
  362. if ((Length (Directory) = 2) or
  363. (Length (Directory) = 3) and
  364. (Directory [3] in AllowDirectorySeparators)) and
  365. (Directory [2] in AllowDriveSeparators) and
  366. (UpCase (Directory [1]) in ['A'..'Z']) then
  367. (* Checking attributes for 'x:' is not possible but for 'x:.' it is. *)
  368. L := FileGetAttr (Directory + '.')
  369. else if (Directory [Length (Directory)] in AllowDirectorySeparators) and
  370. (Length (Directory) > 1) and
  371. (* Do not remove '\' in '\\' (invalid path, possibly broken UNC path). *)
  372. not (Directory [Length (Directory) - 1] in AllowDirectorySeparators) then
  373. L := FileGetAttr (Copy (Directory, 1, Length (Directory) - 1))
  374. else
  375. L := FileGetAttr (Directory);
  376. Result := (L > 0) and (L and faDirectory = faDirectory);
  377. end;
  378. end;
  379. {****************************************************************************
  380. Time Functions
  381. ****************************************************************************}
  382. procedure GetLocalTime (var SystemTime: TSystemTime);
  383. var
  384. DT: DosCalls.TDateTime;
  385. begin
  386. DosGetDateTime(DT);
  387. with SystemTime do
  388. begin
  389. Year:=DT.Year;
  390. Month:=DT.Month;
  391. Day:=DT.Day;
  392. Hour:=DT.Hour;
  393. Minute:=DT.Minute;
  394. Second:=DT.Second;
  395. MilliSecond:=DT.Sec100;
  396. end;
  397. end;
  398. {****************************************************************************
  399. Misc Functions
  400. ****************************************************************************}
  401. procedure sysbeep;
  402. begin
  403. // Maybe implement later on ?
  404. end;
  405. {****************************************************************************
  406. Locale Functions
  407. ****************************************************************************}
  408. procedure InitAnsi;
  409. var I: byte;
  410. Country: TCountryCode;
  411. begin
  412. for I := 0 to 255 do
  413. UpperCaseTable [I] := Chr (I);
  414. Move (UpperCaseTable, LowerCaseTable, SizeOf (UpperCaseTable));
  415. FillChar (Country, SizeOf (Country), 0);
  416. DosMapCase (SizeOf (UpperCaseTable), Country, @UpperCaseTable);
  417. for I := 0 to 255 do
  418. if UpperCaseTable [I] <> Chr (I) then
  419. LowerCaseTable [Ord (UpperCaseTable [I])] := Chr (I);
  420. end;
  421. procedure InitInternational;
  422. var Country: TCountryCode;
  423. CtryInfo: TCountryInfo;
  424. Size: cardinal;
  425. RC: cardinal;
  426. begin
  427. Size := 0;
  428. FillChar (Country, SizeOf (Country), 0);
  429. FillChar (CtryInfo, SizeOf (CtryInfo), 0);
  430. RC := DosQueryCtryInfo (SizeOf (CtryInfo), Country, CtryInfo, Size);
  431. if RC = 0 then
  432. begin
  433. DateSeparator := CtryInfo.DateSeparator;
  434. case CtryInfo.DateFormat of
  435. 1: begin
  436. ShortDateFormat := 'd/m/y';
  437. LongDateFormat := 'dd" "mmmm" "yyyy';
  438. end;
  439. 2: begin
  440. ShortDateFormat := 'y/m/d';
  441. LongDateFormat := 'yyyy" "mmmm" "dd';
  442. end;
  443. 3: begin
  444. ShortDateFormat := 'm/d/y';
  445. LongDateFormat := 'mmmm" "dd" "yyyy';
  446. end;
  447. end;
  448. TimeSeparator := CtryInfo.TimeSeparator;
  449. DecimalSeparator := CtryInfo.DecimalSeparator;
  450. ThousandSeparator := CtryInfo.ThousandSeparator;
  451. CurrencyFormat := CtryInfo.CurrencyFormat;
  452. CurrencyString := PChar (CtryInfo.CurrencyUnit);
  453. end;
  454. InitAnsi;
  455. InitInternationalGeneric;
  456. end;
  457. function SysErrorMessage(ErrorCode: Integer): String;
  458. begin
  459. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  460. end;
  461. {****************************************************************************
  462. OS Utils
  463. ****************************************************************************}
  464. function GetEnvPChar (EnvVar: shortstring): PChar;
  465. (* The assembler version is more than three times as fast as Pascal. *)
  466. var
  467. P: PChar;
  468. begin
  469. EnvVar := UpCase (EnvVar);
  470. {$ASMMODE INTEL}
  471. asm
  472. cld
  473. mov edi, Environment
  474. lea esi, EnvVar
  475. xor eax, eax
  476. lodsb
  477. @NewVar:
  478. cmp byte ptr [edi], 0
  479. jz @Stop
  480. push eax { eax contains length of searched variable name }
  481. push esi { esi points to the beginning of the variable name }
  482. mov ecx, -1 { our character ('=' - see below) _must_ be found }
  483. mov edx, edi { pointer to beginning of variable name saved in edx }
  484. mov al, '=' { searching until '=' (end of variable name) }
  485. repne
  486. scasb { scan until '=' not found }
  487. neg ecx { what was the name length? }
  488. dec ecx { corrected }
  489. dec ecx { exclude the '=' character }
  490. pop esi { restore pointer to beginning of variable name }
  491. pop eax { restore length of searched variable name }
  492. push eax { and save both of them again for later use }
  493. push esi
  494. cmp ecx, eax { compare length of searched variable name with name }
  495. jnz @NotEqual { ... of currently found variable, jump if different }
  496. xchg edx, edi { pointer to current variable name restored in edi }
  497. repe
  498. cmpsb { compare till the end of variable name }
  499. xchg edx, edi { pointer to beginning of variable contents in edi }
  500. jz @Equal { finish if they're equal }
  501. @NotEqual:
  502. xor eax, eax { look for 00h }
  503. mov ecx, -1 { it _must_ be found }
  504. repne
  505. scasb { scan until found }
  506. pop esi { restore pointer to beginning of variable name }
  507. pop eax { restore length of searched variable name }
  508. jmp @NewVar { ... or continue with new variable otherwise }
  509. @Stop:
  510. xor eax, eax
  511. mov P, eax { Not found - return nil }
  512. jmp @End
  513. @Equal:
  514. pop esi { restore the stack position }
  515. pop eax
  516. mov P, edi { place pointer to variable contents in P }
  517. @End:
  518. end ['eax','ecx','edx','esi','edi'];
  519. GetEnvPChar := P;
  520. end;
  521. {$ASMMODE ATT}
  522. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  523. begin
  524. GetEnvironmentVariable := GetEnvPChar (EnvVar);
  525. end;
  526. Function GetEnvironmentVariableCount : Integer;
  527. begin
  528. (* Result:=FPCCountEnvVar(EnvP); - the amount is already known... *)
  529. GetEnvironmentVariableCount := EnvC;
  530. end;
  531. Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
  532. begin
  533. Result:=FPCGetEnvStrFromP (EnvP, Index);
  534. end;
  535. procedure Sleep (Milliseconds: cardinal);
  536. begin
  537. DosSleep (Milliseconds);
  538. end;
  539. function SysTimerTick: QWord;
  540. var
  541. L: cardinal;
  542. begin
  543. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  544. SysTimerTick := L;
  545. end;
  546. function ExecuteProcess (const Path: AnsiString; const ComLine: AnsiString;Flags:TExecuteFlags=[]):
  547. integer;
  548. var
  549. E: EOSError;
  550. CommandLine: ansistring;
  551. Args0, Args: DosCalls.PByteArray;
  552. ObjNameBuf: PChar;
  553. ArgSize: word;
  554. Res: TResultCodes;
  555. ObjName: shortstring;
  556. RC: cardinal;
  557. ExecAppType: cardinal;
  558. const
  559. MaxArgsSize = 3072; (* Amount of memory reserved for arguments in bytes. *)
  560. ObjBufSize = 512;
  561. function StartSession: cardinal;
  562. var
  563. HQ: THandle;
  564. SPID, STID, QName: shortstring;
  565. SID, PID: cardinal;
  566. SD: TStartData;
  567. RD: TRequestData;
  568. PCI: PChildInfo;
  569. CISize: cardinal;
  570. Prio: byte;
  571. begin
  572. Result := $FFFFFFFF;
  573. FillChar (SD, SizeOf (SD), 0);
  574. SD.Length := SizeOf (SD);
  575. SD.Related := ssf_Related_Child;
  576. if FileExists (Path) then
  577. (* Full path necessary for starting different executable files from current *)
  578. (* directory. *)
  579. CommandLine := ExpandFileName (Path)
  580. else
  581. CommandLine := Path;
  582. SD.PgmName := PChar (CommandLine);
  583. if ComLine <> '' then
  584. SD.PgmInputs := PChar (ComLine);
  585. if ExecInheritsHandles in Flags then
  586. SD.InheritOpt := ssf_InhertOpt_Parent;
  587. Str (GetProcessID, SPID);
  588. Str (ThreadID, STID);
  589. QName := '\QUEUES\FPC_ExecuteProcess_p' + SPID + 't' + STID + '.QUE'#0;
  590. SD.TermQ := @QName [1];
  591. SD.ObjectBuffer := ObjNameBuf;
  592. SD.ObjectBuffLen := ObjBufSize;
  593. RC := DosCreateQueue (HQ, quFIFO or quConvert_Address, @QName [1]);
  594. if RC <> 0 then
  595. Move (QName [1], ObjNameBuf^, Length (QName))
  596. else
  597. begin
  598. RC := DosStartSession (SD, SID, PID);
  599. if (RC = 0) or (RC = 457) then
  600. begin
  601. RC := DosReadQueue (HQ, RD, CISize, PCI, 0, 0, Prio, 0);
  602. if RC = 0 then
  603. begin
  604. Result := PCI^.Return;
  605. DosCloseQueue (HQ);
  606. DosFreeMem (PCI);
  607. FreeMem (ObjNameBuf, ObjBufSize);
  608. end
  609. else
  610. DosCloseQueue (HQ);
  611. end
  612. else
  613. DosCloseQueue (HQ);
  614. end;
  615. end;
  616. begin
  617. Result := integer ($FFFFFFFF);
  618. ObjName := '';
  619. GetMem (ObjNameBuf, ObjBufSize);
  620. FillChar (ObjNameBuf^, ObjBufSize, 0);
  621. if (DosQueryAppType (PChar (Path), ExecAppType) = 0) and
  622. (ApplicationType and 3 = ExecAppType and 3) then
  623. (* DosExecPgm should work... *)
  624. begin
  625. if ComLine = '' then
  626. begin
  627. Args0 := nil;
  628. Args := nil;
  629. end
  630. else
  631. begin
  632. GetMem (Args0, MaxArgsSize);
  633. Args := Args0;
  634. (* Work around a bug in OS/2 - argument to DosExecPgm *)
  635. (* should not cross 64K boundary. *)
  636. if ((PtrUInt (Args) + 1024) and $FFFF) < 1024 then
  637. Inc (pointer (Args), 1024);
  638. ArgSize := 0;
  639. Move (Path [1], Args^ [ArgSize], Length (Path));
  640. Inc (ArgSize, Length (Path));
  641. Args^ [ArgSize] := 0;
  642. Inc (ArgSize);
  643. {Now do the real arguments.}
  644. Move (ComLine [1], Args^ [ArgSize], Length (ComLine));
  645. Inc (ArgSize, Length (ComLine));
  646. Args^ [ArgSize] := 0;
  647. Inc (ArgSize);
  648. Args^ [ArgSize] := 0;
  649. end;
  650. Res.ExitCode := $FFFFFFFF;
  651. RC := DosExecPgm (ObjNameBuf, ObjBufSize, 0, Args, nil, Res, PChar (Path));
  652. if Args0 <> nil then
  653. FreeMem (Args0, MaxArgsSize);
  654. if RC = 0 then
  655. begin
  656. Result := Res.ExitCode;
  657. FreeMem (ObjNameBuf, ObjBufSize);
  658. end
  659. else
  660. begin
  661. if (RC = 190) or (RC = 191) then
  662. Result := StartSession;
  663. end;
  664. end
  665. else
  666. Result := StartSession;
  667. if RC <> 0 then
  668. begin
  669. ObjName := StrPas (ObjNameBuf);
  670. FreeMem (ObjNameBuf, ObjBufSize);
  671. if ComLine = '' then
  672. CommandLine := Path
  673. else
  674. CommandLine := Path + ' ' + ComLine;
  675. if ObjName = '' then
  676. E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, RC])
  677. else
  678. E := EOSError.CreateFmt (SExecuteProcessFailed + ' (' + ObjName + ')', [CommandLine, RC]);
  679. E.ErrorCode := Result;
  680. raise E;
  681. end;
  682. end;
  683. function ExecuteProcess (const Path: AnsiString;
  684. const ComLine: array of AnsiString;Flags:TExecuteFlags=[]): integer;
  685. var
  686. CommandLine: AnsiString;
  687. I: integer;
  688. begin
  689. Commandline := '';
  690. for I := 0 to High (ComLine) do
  691. if Pos (' ', ComLine [I]) <> 0 then
  692. CommandLine := CommandLine + ' ' + '"' + ComLine [I] + '"'
  693. else
  694. CommandLine := CommandLine + ' ' + Comline [I];
  695. ExecuteProcess := ExecuteProcess (Path, CommandLine);
  696. end;
  697. function GetTickCount: LongWord;
  698. var
  699. L: cardinal;
  700. begin
  701. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  702. GetTickCount := L;
  703. end;
  704. function GetTickCount64: QWord;
  705. var
  706. L: cardinal;
  707. begin
  708. DosQuerySysInfo (svMsCount, svMsCount, L, 4);
  709. GetTickCount64 := L;
  710. end;
  711. {****************************************************************************
  712. Initialization code
  713. ****************************************************************************}
  714. Initialization
  715. InitExceptions; { Initialize exceptions. OS independent }
  716. InitInternational; { Initialize internationalization settings }
  717. OnBeep:=@SysBeep;
  718. Finalization
  719. DoneExceptions;
  720. end.