sysutils.pp 22 KB

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