process.inc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. {
  2. Unix Process .inc.
  3. }
  4. uses
  5. Unix,
  6. Baseunix;
  7. resourcestring
  8. SErrNoSuchProgram = 'Executable not found: "%s"';
  9. Const
  10. PriorityConstants : Array [TProcessPriority] of Integer =
  11. (20,20,0,-20);
  12. Const
  13. GeometryOption : String = '-geometry';
  14. TitleOption : String ='-title';
  15. procedure TProcess.CloseProcessHandles;
  16. begin
  17. // Do nothing. Win32 call.
  18. end;
  19. Function TProcess.PeekExitStatus : Boolean;
  20. begin
  21. Result:=fpWaitPid(Handle,pcint(@FExitCode),WNOHANG)=Handle;
  22. If Result then
  23. FExitCode:=wexitstatus(FExitCode)
  24. else
  25. FexitCode:=0;
  26. end;
  27. Type
  28. TPCharArray = Array[Word] of pchar;
  29. PPCharArray = ^TPcharArray;
  30. Function StringsToPCharList(List : TStrings) : PPChar;
  31. Var
  32. I : Integer;
  33. S : String;
  34. begin
  35. I:=(List.Count)+1;
  36. GetMem(Result,I*sizeOf(PChar));
  37. PPCharArray(Result)^[List.Count]:=Nil;
  38. For I:=0 to List.Count-1 do
  39. begin
  40. S:=List[i];
  41. Result[i]:=StrNew(PChar(S));
  42. end;
  43. end;
  44. Procedure FreePCharList(List : PPChar);
  45. Var
  46. I : integer;
  47. begin
  48. I:=0;
  49. While List[i]<>Nil do
  50. begin
  51. StrDispose(List[i]);
  52. Inc(I);
  53. end;
  54. FreeMem(List);
  55. end;
  56. Procedure CommandToList(S : String; List : TStrings);
  57. Function GetNextWord : String;
  58. Const
  59. WhiteSpace = [' ',#8,#10];
  60. Literals = ['"',''''];
  61. Var
  62. Wstart,wend : Integer;
  63. InLiteral : Boolean;
  64. LastLiteral : char;
  65. begin
  66. WStart:=1;
  67. While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do
  68. Inc(WStart);
  69. WEnd:=WStart;
  70. InLiteral:=False;
  71. LastLiteral:=#0;
  72. While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do
  73. begin
  74. if S[Wend] in Literals then
  75. If InLiteral then
  76. InLiteral:=Not (S[Wend]=LastLiteral)
  77. else
  78. begin
  79. InLiteral:=True;
  80. LastLiteral:=S[Wend];
  81. end;
  82. inc(wend);
  83. end;
  84. Result:=Copy(S,WStart,WEnd-WStart);
  85. if (Length(Result) > 0)
  86. and (Result[1] = Result[Length(Result)]) // if 1st char = last char and..
  87. and (Result[1] in Literals) then // it's one of the literals, then
  88. Result:=Copy(Result, 2, Length(Result) - 2); //delete the 2 (but not others in it)
  89. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  90. inc(Wend);
  91. Delete(S,1,WEnd-1);
  92. end;
  93. Var
  94. W : String;
  95. begin
  96. While Length(S)>0 do
  97. begin
  98. W:=GetNextWord;
  99. If (W<>'') then
  100. List.Add(W);
  101. end;
  102. end;
  103. Function MakeCommand(P : TProcess) : PPchar;
  104. Const
  105. SNoCommandLine = 'Cannot execute empty command-line';
  106. Var
  107. Cmd : String;
  108. S : TStringList;
  109. G : String;
  110. begin
  111. if (P.ApplicationName='') then
  112. begin
  113. If (P.CommandLine='') then
  114. Raise EProcess.Create(SNoCommandline);
  115. Cmd:=P.CommandLine;
  116. end
  117. else
  118. begin
  119. If (P.CommandLine='') then
  120. Cmd:=P.ApplicationName
  121. else
  122. Cmd:=P.CommandLine;
  123. end;
  124. S:=TStringList.Create;
  125. try
  126. CommandToList(Cmd,S);
  127. if poNewConsole in P.Options then
  128. begin
  129. S.Insert(0,'-e');
  130. If (P.ApplicationName<>'') then
  131. begin
  132. S.Insert(0,P.ApplicationName);
  133. S.Insert(0,'-title');
  134. end;
  135. if suoUseCountChars in P.StartupOptions then
  136. begin
  137. S.Insert(0,Format('%dx%d',[P.dwXCountChars,P.dwYCountChars]));
  138. S.Insert(0,'-geometry');
  139. end;
  140. S.Insert(0,'xterm');
  141. end;
  142. if (P.ApplicationName<>'') then
  143. begin
  144. S.Add(TitleOption);
  145. S.Add(P.ApplicationName);
  146. end;
  147. G:='';
  148. if (suoUseSize in P.StartupOptions) then
  149. g:=format('%dx%d',[P.dwXSize,P.dwYsize]);
  150. if (suoUsePosition in P.StartupOptions) then
  151. g:=g+Format('+%d+%d',[P.dwX,P.dwY]);
  152. if G<>'' then
  153. begin
  154. S.Add(GeometryOption);
  155. S.Add(g);
  156. end;
  157. Result:=StringsToPcharList(S);
  158. Finally
  159. S.free;
  160. end;
  161. end;
  162. Function GetLastError : Integer;
  163. begin
  164. Result:=-1;
  165. end;
  166. Type
  167. TPipeEnd = (peRead,peWrite);
  168. TPipePair = Array[TPipeEnd] of cint;
  169. Procedure CreatePipes(Var HI,HO,HE : TPipePair; CE : Boolean);
  170. Procedure CreatePair(Var P : TPipePair);
  171. begin
  172. If not CreatePipeHandles(P[peRead],P[peWrite]) then
  173. Raise EProcess.Create('Failed to create pipes');
  174. end;
  175. Procedure ClosePair(Var P : TPipePair);
  176. begin
  177. if (P[peRead]<>-1) then
  178. FileClose(P[peRead]);
  179. if (P[peWrite]<>-1) then
  180. FileClose(P[peWrite]);
  181. end;
  182. begin
  183. HO[peRead]:=-1;HO[peWrite]:=-1;
  184. HI[peRead]:=-1;HI[peWrite]:=-1;
  185. HE[peRead]:=-1;HE[peWrite]:=-1;
  186. Try
  187. CreatePair(HO);
  188. CreatePair(HI);
  189. If CE then
  190. CreatePair(HE);
  191. except
  192. ClosePair(HO);
  193. ClosePair(HI);
  194. If CE then
  195. ClosePair(HE);
  196. Raise;
  197. end;
  198. end;
  199. Procedure TProcess.Execute;
  200. Var
  201. HI,HO,HE : TPipePair;
  202. PID : Longint;
  203. FEnv : PPChar;
  204. Argv : PPChar;
  205. fd : Integer;
  206. PName : String;
  207. begin
  208. If (poUsePipes in FProcessOptions) then
  209. CreatePipes(HI,HO,HE,Not (poStdErrToOutPut in FProcessOptions));
  210. Try
  211. if FEnvironment.Count<>0 then
  212. FEnv:=StringsToPcharList(FEnvironment)
  213. else
  214. FEnv:=Nil;
  215. Try
  216. Argv:=MakeCommand(Self);
  217. Try
  218. If (Argv<>Nil) and (ArgV[0]<>Nil) then
  219. PName:=StrPas(Argv[0])
  220. else
  221. begin
  222. // This should never happen, actually.
  223. PName:=ApplicationName;
  224. If (PName='') then
  225. PName:=CommandLine;
  226. end;
  227. if not FileExists(PName) then begin
  228. PName := FileSearch(Pname,fpgetenv('PATH'));
  229. if Length(PName) = 0 then
  230. raise EProcess.CreateFmt(SErrNoSuchProgram,[PName]);
  231. end;
  232. Pid:=fpfork;
  233. if Pid<0 then
  234. Raise EProcess.Create('Failed to Fork process');
  235. if (PID>0) then
  236. begin
  237. // Parent process. Copy process information.
  238. FProcessHandle:=PID;
  239. FThreadHandle:=PID;
  240. FProcessId:=PID;
  241. //FThreadId:=PID;
  242. end
  243. else
  244. begin
  245. { We're in the child }
  246. if (FCurrentDirectory<>'') then
  247. ChDir(FCurrentDirectory);
  248. if PoUsePipes in Options then
  249. begin
  250. fpclose(HI[peWrite]);
  251. fpdup2(HI[peRead],0);
  252. fpclose(HO[peRead]);
  253. fpdup2(HO[peWrite],1);
  254. if (poStdErrToOutPut in Options) then
  255. fpdup2(HO[peWrite],2)
  256. else
  257. begin
  258. fpclose(HE[peRead]);
  259. fpdup2(HE[peWrite],2);
  260. end
  261. end
  262. else if poNoConsole in Options then
  263. begin
  264. fd:=FileOpen('/dev/null',fmOpenReadWrite);
  265. fpdup2(fd,0);
  266. fpdup2(fd,1);
  267. fpdup2(fd,2);
  268. end;
  269. if (poRunSuspended in Options) then
  270. sigraise(SIGSTOP);
  271. if FEnv<>Nil then
  272. fpexecve(PName,Argv,Fenv)
  273. else
  274. fpexecv(PName,argv);
  275. Halt(127);
  276. end
  277. Finally
  278. FreePcharList(Argv);
  279. end;
  280. Finally
  281. If (FEnv<>Nil) then
  282. FreePCharList(FEnv);
  283. end;
  284. Finally
  285. if POUsePipes in FProcessOptions then
  286. begin
  287. FileClose(HO[peWrite]);
  288. FileClose(HI[peRead]);
  289. if Not (poStdErrToOutPut in FProcessOptions) then
  290. FileClose(HE[peWrite]);
  291. CreateStreams(HI[peWrite],HO[peRead],HE[peRead]);
  292. end;
  293. end;
  294. FRunning:=True;
  295. if not (csDesigning in ComponentState) and // This would hang the IDE !
  296. (poWaitOnExit in FProcessOptions) and
  297. not (poRunSuspended in FProcessOptions) then
  298. WaitOnExit;
  299. end;
  300. Function TProcess.WaitOnExit : Boolean;
  301. Var
  302. R : Dword;
  303. begin
  304. R:=fpWaitPid(Handle,pcint(@FExitCode),0);
  305. Result:=(R=Handle);
  306. If Result then
  307. FExitCode:=WExitStatus(FExitCode);
  308. FRunning:=False;
  309. end;
  310. Function TProcess.Suspend : Longint;
  311. begin
  312. If fpkill(Handle,SIGSTOP)<>0 then
  313. Result:=-1
  314. else
  315. Result:=1;
  316. end;
  317. Function TProcess.Resume : LongInt;
  318. begin
  319. If fpKill(Handle,SIGCONT)<>0 then
  320. Result:=-1
  321. else
  322. Result:=0;
  323. end;
  324. Function TProcess.Terminate(AExitCode : Integer) : Boolean;
  325. begin
  326. Result:=False;
  327. Result:=fpkill(Handle,SIGTERM)=0;
  328. If Result then
  329. begin
  330. If Running then
  331. Result:=fpkill(Handle,SIGKILL)=0;
  332. end;
  333. GetExitStatus;
  334. end;
  335. Procedure TProcess.SetShowWindow (Value : TShowWindowOptions);
  336. begin
  337. FShowWindow:=Value;
  338. end;