redir.pp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. {
  2. This file is part of the Free Pascal Test Suite
  3. Copyright (c) 1999-2000 by Pierre Muller
  4. Unit to redirect output and error to files
  5. Adapted from code donated to public domain by Schwartz Gabriel 20/03/1993
  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 Redir;
  13. Interface
  14. {$mode objfpc}
  15. {$H+}
  16. {$R-}
  17. {$ifndef Linux}
  18. {$ifndef Unix}
  19. {$S-}
  20. {$endif}
  21. {$endif}
  22. {$ifdef Go32v2}
  23. {$define implemented}
  24. {$endif}
  25. {$ifdef OS2}
  26. {$define implemented}
  27. {$endif}
  28. {$ifdef windows}
  29. {$define implemented}
  30. {$if (FPC_FULLVERSION > 30300)}
  31. {$define EXECUTEREDIR_USES_PROCESS}
  32. {$ENDIF}
  33. {$define USES_UNIT_PROCESS}
  34. {$endif}
  35. {$IFDEF UNIX}
  36. {$define implemented}
  37. {$ifndef MACOS}
  38. {$if (FPC_FULLVERSION > 30300)}
  39. {$define EXECUTEREDIR_USES_PROCESS}
  40. {$ENDIF}
  41. {$define USES_UNIT_PROCESS}
  42. {$endif}
  43. {$ENDIF}
  44. Var
  45. IOStatus : Integer;
  46. RedirErrorOut,RedirErrorIn,
  47. RedirErrorError : Integer;
  48. ExecuteResult : Longint;
  49. {------------------------------------------------------------------------------}
  50. procedure InitRedir;
  51. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  52. procedure DosExecute(ProgName, ComLine : String);
  53. function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
  54. procedure RestoreRedirOut;
  55. procedure DisableRedirOut;
  56. procedure EnableRedirOut;
  57. function ChangeRedirIn(Const Redir : String) : Boolean;
  58. procedure RestoreRedirIn;
  59. procedure DisableRedirIn;
  60. procedure EnableRedirIn;
  61. function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
  62. procedure RestoreRedirError;
  63. procedure DisableRedirError;
  64. procedure EnableRedirError;
  65. procedure RedirDisableAll;
  66. procedure RedirEnableAll;
  67. { unused in UNIX }
  68. const
  69. UseComSpec : boolean = true;
  70. Implementation
  71. //or defined(windows)
  72. {$if defined(macos) or defined(shell_implemented) or defined(go32v2)}
  73. {$define usedos}
  74. {$endif}
  75. {$if defined(windows) and not defined(usedos)}
  76. {$ifdef ver2_4}
  77. {$define redirexecuteprocess}
  78. {$endif}
  79. {$endif}
  80. Uses
  81. {$ifdef go32v2}
  82. go32,
  83. {$endif go32v2}
  84. {$ifdef windows}
  85. windows,
  86. {$endif windows}
  87. {$IFDEF OS2}
  88. {$IFNDEF EMX}
  89. DosCalls,
  90. {$ENDIF EMX}
  91. {$ENDIF OS2}
  92. {$ifdef unix}
  93. baseunix,
  94. unix,
  95. {$endif unix}
  96. {$ifdef redirexecuteprocess}
  97. sysconst,
  98. {$endif}
  99. {$ifdef USES_UNIT_PROCESS}
  100. process,
  101. {$endif USES_UNIT_PROCESS}
  102. {$ifdef usedos}
  103. dos;
  104. {$else}
  105. sysutils;
  106. {$endif}
  107. Const
  108. {$ifdef UNIX}
  109. DirSep='/';
  110. listsep = [';',':'];
  111. exeext = '';
  112. {$else UNIX}
  113. {$ifdef MACOS}
  114. DirSep=':';
  115. listsep = [','];
  116. exeext = '';
  117. {$else MACOS}
  118. DirSep='\';
  119. listsep = [';'];
  120. exeext = '.exe';
  121. {$endif MACOS}
  122. {$endif UNIX}
  123. {$ifndef usedos}
  124. { code from: }
  125. { Lithuanian Text Tool version 0.9.0 (2001-04-19) }
  126. { Copyright (c) 1999-2001 Marius Gedminas <[email protected]> }
  127. { (GPLv2 or later) }
  128. function FExpand(const S: string): string;
  129. begin
  130. FExpand := ExpandFileName(S);
  131. end;
  132. type
  133. PathStr = string;
  134. DirStr = string;
  135. NameStr = string;
  136. ExtStr = string;
  137. procedure FSplit(Path: PathStr; var Dir: DirStr; var Name: NameStr; var Ext: ExtStr);
  138. begin
  139. Dir := ExtractFilePath(Path);
  140. Name := ChangeFileExt(ExtractFileName(Path), '');
  141. Ext := ExtractFileExt(Path);
  142. end;
  143. {$endif}
  144. var
  145. FIN,FOUT,FERR : ^File;
  146. RedirStdErrToStdOut,
  147. RedirChangedOut,
  148. RedirChangedIn : Boolean;
  149. RedirChangedError : Boolean;
  150. InRedirDisabled,OutRedirDisabled,ErrorRedirDisabled : Boolean;
  151. {*****************************************************************************
  152. Helpers
  153. *****************************************************************************}
  154. function FixPath(const s:string):string;
  155. var
  156. i : longint;
  157. begin
  158. { Fix separator }
  159. setlength(fixpath,length(s));
  160. for i:=1 to length(s) do
  161. if s[i] in ['/','\'] then
  162. fixpath[i]:=DirSep
  163. else
  164. fixpath[i]:=s[i];
  165. end;
  166. {*****************************************************************************
  167. Dos
  168. *****************************************************************************}
  169. {$ifdef implemented}
  170. {$ifndef usedos}
  171. {$if defined(ver2_4_0) or defined(ver2_4_1)}
  172. Type
  173. TExecuteFlags= set of (ExecInheritsHandles);
  174. {$ifdef redirexecuteprocess}
  175. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  176. // win specific function
  177. var
  178. SI: TStartupInfo;
  179. PI: TProcessInformation;
  180. Proc : THandle;
  181. l : DWord;
  182. CommandLine : ansistring;
  183. e : EOSError;
  184. ExecInherits : longbool;
  185. begin
  186. FillChar(SI, SizeOf(SI), 0);
  187. SI.cb:=SizeOf(SI);
  188. SI.wShowWindow:=1;
  189. { always surround the name of the application by quotes
  190. so that long filenames will always be accepted. But don't
  191. do it if there are already double quotes, since Win32 does not
  192. like double quotes which are duplicated!
  193. }
  194. if pos('"',path)=0 then
  195. CommandLine:='"'+path+'"'
  196. else
  197. CommandLine:=path;
  198. if ComLine <> '' then
  199. CommandLine:=Commandline+' '+ComLine+#0
  200. else
  201. CommandLine := CommandLine + #0;
  202. ExecInherits:=ExecInheritsHandles in Flags;
  203. if not CreateProcess(nil, pchar(CommandLine),
  204. Nil, Nil, ExecInherits,$20, Nil, Nil, SI, PI) then
  205. begin
  206. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  207. e.ErrorCode:=GetLastError;
  208. raise e;
  209. end;
  210. Proc:=PI.hProcess;
  211. if WaitForSingleObject(Proc, dword($ffffffff)) <> $ffffffff then
  212. begin
  213. GetExitCodeProcess(Proc,l);
  214. CloseHandle(Proc);
  215. CloseHandle(PI.hThread);
  216. result:=l;
  217. end
  218. else
  219. begin
  220. e:=EOSError.CreateFmt(SExecuteProcessFailed,[CommandLine,GetLastError]);
  221. e.ErrorCode:=GetLastError;
  222. CloseHandle(Proc);
  223. CloseHandle(PI.hThread);
  224. raise e;
  225. end;
  226. end;
  227. {$else}
  228. {$ifndef USES_UNIT_PROCESS}
  229. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString;Flags:TExecuteFlags=[]):integer;
  230. begin
  231. result:=ExecuteProcess(path,comline);
  232. end;
  233. {$endif ndef USES_UNIT_PROCESS}
  234. {$endif}
  235. {$ifend}
  236. {$endif}
  237. {$ifndef windows}
  238. var
  239. TempHOut, TempHIn,TempHError : longint;
  240. {$endif ndef windows}
  241. {
  242. For Unix the following functions exist
  243. Function fpdup(oldfile:longint;var newfile:longint):Boolean;
  244. Function fpdup2(oldfile,newfile:longint):Boolean;
  245. Function fpClose(fd:longint):boolean;
  246. }
  247. {$ifdef go32v2}
  248. function fpdup(fh : longint) : longint;
  249. var
  250. Regs : Registers;
  251. begin
  252. Regs.ah:=$45;
  253. Regs.bx:=fh;
  254. MsDos (Regs);
  255. If (Regs.Flags and fCarry)=0 then
  256. fpdup:=Regs.Ax
  257. else
  258. fpdup:=-1;
  259. end;
  260. function fpdup2(fh,nh : longint) : longint;
  261. var
  262. Regs : Registers;
  263. begin
  264. fpdup2:=0;
  265. If fh=nh then
  266. exit;
  267. Regs.ah:=$46;
  268. Regs.bx:=fh;
  269. Regs.cx:=nh;
  270. MsDos (Regs);
  271. If (Regs.Flags and fCarry)<>0 then
  272. fpdup2:=-1;
  273. end;
  274. Function fpclose (Handle : Longint) : boolean;
  275. var Regs: registers;
  276. begin
  277. Regs.Eax := $3e00;
  278. Regs.Ebx := Handle;
  279. MsDos(Regs);
  280. fpclose:=(Regs.Flags and fCarry)=0;
  281. end;
  282. {$endif def go32v2}
  283. {$ifdef windows}
  284. Function fpclose (Handle : Longint) : boolean;
  285. begin
  286. { Do we need this ?? }
  287. fpclose:=true;
  288. end;
  289. {$endif}
  290. {$IFDEF OS2}
  291. {$IFDEF EMX}
  292. {$ASMMODE INTEL}
  293. function fpDup (FH: longint): longint; assembler;
  294. asm
  295. mov ebx, eax
  296. mov ah, 45h
  297. call syscall
  298. jnc @fpdup_end
  299. mov eax, -1
  300. @fpdup_end:
  301. end;
  302. function fpDup2 (FH, NH: longint): longint; assembler;
  303. asm
  304. cmp eax, edx
  305. jnz @fpdup2_go
  306. mov eax, 0
  307. jmp @fpdup2_end
  308. @fpdup2_go:
  309. push ebx
  310. mov ebx, eax
  311. mov ecx, edx
  312. mov ah, 46h
  313. call syscall
  314. pop ebx
  315. jnc @fpdup2_end
  316. mov eax, -1
  317. @fpdup2_end:
  318. end;
  319. function fpClose (Handle: longint): boolean; assembler;
  320. asm
  321. push ebx
  322. mov ebx, eax
  323. mov ah, 3Eh
  324. call syscall
  325. pop ebx
  326. mov eax, 1
  327. jnc @fpclose_end
  328. dec eax
  329. end;
  330. {$ASMMODE DEFAULT}
  331. {$ELSE EMX}
  332. function fpDup (FH: longint): longint;
  333. var
  334. NH: THandle;
  335. begin
  336. NH := THandle (-1);
  337. if DosDupHandle (THandle (FH), NH) = 0 then
  338. fpDup := longint (NH)
  339. else
  340. fpDup := -1;
  341. end;
  342. function fpDup2 (FH, NH: longint): longint;
  343. begin
  344. if FH = NH then
  345. fpDup2 := 0
  346. else
  347. if DosDupHandle (THandle (FH), THandle (NH)) <> 0 then
  348. fpDup2 := -1;
  349. end;
  350. function fpClose (Handle: longint): boolean;
  351. begin
  352. fpClose := DosClose (THandle (Handle)) = 0;
  353. end;
  354. {$ENDIF EMX}
  355. {$ENDIF OS2}
  356. {$I-}
  357. function FileExist(const FileName : PathStr) : Boolean;
  358. {$ifdef usedos}
  359. var
  360. f : file;
  361. Attr : word;
  362. {$endif}
  363. begin
  364. {$ifdef usedos}
  365. Assign(f, FileName);
  366. GetFAttr(f, Attr);
  367. FileExist := DosError = 0;
  368. {$else}
  369. FileExist := Sysutils.FileExists(filename);
  370. {$endif}
  371. end;
  372. function CompleteDir(const Path: string): string;
  373. begin
  374. { keep c: untouched PM }
  375. if (Path<>'') and (Path[Length(Path)]<>DirSep) and
  376. (Path[Length(Path)]<>':') then
  377. CompleteDir:=Path+DirSep
  378. else
  379. CompleteDir:=Path;
  380. end;
  381. function LocateExeFile(var FileName:string): boolean;
  382. var
  383. dir,s: string;
  384. d: dirstr;
  385. n: namestr;
  386. e: extstr;
  387. i : longint;
  388. begin
  389. LocateExeFile:=False;
  390. if FileExist(FileName) then
  391. begin
  392. LocateExeFile:=true;
  393. Exit;
  394. end;
  395. Fsplit(Filename,d,n,e);
  396. if (e='') and FileExist(FileName+exeext) then
  397. begin
  398. FileName:=FileName+exeext;
  399. LocateExeFile:=true;
  400. Exit;
  401. end;
  402. {$ifdef usedos}
  403. S:=GetEnv('PATH');
  404. {$else}
  405. S:=GetEnvironmentVariable('PATH');
  406. {$endif}
  407. While Length(S)>0 do
  408. begin
  409. i:=1;
  410. While (i<=Length(S)) and not (S[i] in ListSep) do
  411. Inc(i);
  412. Dir:=CompleteDir(Copy(S,1,i-1));
  413. if i<Length(S) then
  414. Delete(S,1,i)
  415. else
  416. S:='';
  417. if FileExist(Dir+FileName) then
  418. Begin
  419. FileName:=Dir+FileName;
  420. LocateExeFile:=true;
  421. Exit;
  422. End;
  423. end;
  424. end;
  425. {............................................................................}
  426. function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
  427. begin
  428. ChangeRedirOut:=False;
  429. If Redir = '' then Exit;
  430. Assign (FOUT^, Redir);
  431. If AppendToFile and FileExist(Redir) then
  432. Begin
  433. Reset(FOUT^,1);
  434. Seek(FOUT^,FileSize(FOUT^));
  435. End else Rewrite (FOUT^);
  436. RedirErrorOut:=IOResult;
  437. IOStatus:=RedirErrorOut;
  438. If IOStatus <> 0 then Exit;
  439. {$ifndef FPC}
  440. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  441. OldHandleOut:=Handles^[StdOutputHandle];
  442. Handles^[StdOutputHandle]:=Handles^[FileRec (FOUT^).Handle];
  443. ChangeRedirOut:=True;
  444. OutRedirDisabled:=False;
  445. {$else}
  446. {$ifdef windows}
  447. if SetStdHandle(Std_Output_Handle,FileRec(FOUT^).Handle) then
  448. {$else not windows}
  449. TempHOut:=fpdup(StdOutputHandle);
  450. fpdup2(FileRec(FOUT^).Handle,StdOutputHandle);
  451. if (TempHOut<>UnusedHandle) and
  452. (StdOutputHandle<>UnusedHandle) then
  453. {$endif not windows}
  454. begin
  455. ChangeRedirOut:=True;
  456. OutRedirDisabled:=False;
  457. end;
  458. {$endif def FPC}
  459. RedirChangedOut:=True;
  460. end;
  461. function ChangeRedirIn(Const Redir : String) : Boolean;
  462. begin
  463. ChangeRedirIn:=False;
  464. If Redir = '' then Exit;
  465. Assign (FIN^, Redir);
  466. Reset(FIN^,1);
  467. RedirErrorIn:=IOResult;
  468. IOStatus:=RedirErrorIn;
  469. If IOStatus <> 0 then Exit;
  470. {$ifndef FPC}
  471. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  472. OldHandleIn:=Handles^[StdInputHandle];
  473. Handles^[StdInputHandle]:=Handles^[FileRec (FIN^).Handle];
  474. ChangeRedirIn:=True;
  475. InRedirDisabled:=False;
  476. {$else}
  477. {$ifdef windows}
  478. if SetStdHandle(Std_Input_Handle,FileRec(FIN^).Handle) then
  479. {$else not windows}
  480. TempHIn:=fpdup(StdInputHandle);
  481. fpdup2(FileRec(FIn^).Handle,StdInputHandle);
  482. if (TempHIn<>UnusedHandle) and
  483. (StdInputHandle<>UnusedHandle) then
  484. {$endif not windows}
  485. begin
  486. ChangeRedirIn:=True;
  487. InRedirDisabled:=False;
  488. end;
  489. {$endif def FPC}
  490. RedirChangedIn:=True;
  491. end;
  492. function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
  493. var
  494. PF : ^File;
  495. begin
  496. ChangeRedirError:=False;
  497. If Redir = '' then
  498. Exit;
  499. RedirStdErrToStdOut:=(Redir='stdout');
  500. if RedirStdErrToStdOut then
  501. begin
  502. PF:=FOut;
  503. end
  504. else
  505. begin
  506. Assign (FERR^, Redir);
  507. If AppendToFile and FileExist(Redir) then
  508. Begin
  509. Reset(FERR^,1);
  510. Seek(FERR^,FileSize(FERR^));
  511. End
  512. else
  513. Rewrite (FERR^);
  514. RedirErrorError:=IOResult;
  515. IOStatus:=RedirErrorError;
  516. If IOStatus <> 0 then Exit;
  517. PF:=FErr;
  518. end;
  519. {$ifndef FPC}
  520. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  521. OldHandleError:=Handles^[StdErrorHandle];
  522. Handles^[StdErrorHandle]:=Handles^[FileRec (PF^).Handle];
  523. ChangeRedirError:=True;
  524. ErrorRedirDisabled:=False;
  525. {$else}
  526. {$ifdef windows}
  527. if SetStdHandle(Std_Error_Handle,FileRec(PF^).Handle) then
  528. {$else not windows}
  529. TempHError:=fpdup(StdErrorHandle);
  530. fpdup2(FileRec(PF^).Handle,StdErrorHandle);
  531. if (TempHError<>UnusedHandle) and
  532. (StdErrorHandle<>UnusedHandle) then
  533. {$endif not windows}
  534. begin
  535. ChangeRedirError:=True;
  536. ErrorRedirDisabled:=False;
  537. end;
  538. {$endif}
  539. RedirChangedError:=True;
  540. end;
  541. procedure RestoreRedirOut;
  542. begin
  543. If not RedirChangedOut then Exit;
  544. {$ifdef windows}
  545. SetStdHandle(Std_Output_Handle,StdOutputHandle);
  546. {$else not windows}
  547. fpdup2(TempHOut,StdOutputHandle);
  548. {$endif not windows}
  549. Close (FOUT^);
  550. {$ifndef windows}
  551. fpclose(TempHOut);
  552. {$endif ndef windows}
  553. RedirChangedOut:=false;
  554. end;
  555. {............................................................................}
  556. procedure RestoreRedirIn;
  557. begin
  558. If not RedirChangedIn then Exit;
  559. {$ifndef FPC}
  560. Handles^[StdInputHandle]:=OldHandleIn;
  561. OldHandleIn:=StdInputHandle;
  562. {$else}
  563. {$ifdef windows}
  564. SetStdHandle(Std_Input_Handle,StdInputHandle);
  565. {$else not windows}
  566. fpdup2(TempHIn,StdInputHandle);
  567. {$endif not windows}
  568. {$endif}
  569. Close (FIn^);
  570. {$ifndef windows}
  571. fpclose(TempHIn);
  572. {$endif ndef windows}
  573. RedirChangedIn:=false;
  574. end;
  575. {............................................................................}
  576. procedure DisableRedirIn;
  577. begin
  578. If not RedirChangedIn then Exit;
  579. If InRedirDisabled then Exit;
  580. {$ifndef FPC}
  581. Handles^[StdInputHandle]:=OldHandleIn;
  582. {$else}
  583. {$ifdef windows}
  584. SetStdHandle(Std_Input_Handle,StdInputHandle);
  585. {$else not windows}
  586. fpdup2(TempHIn,StdInputHandle);
  587. {$endif not windows}
  588. {$endif}
  589. InRedirDisabled:=True;
  590. end;
  591. {............................................................................}
  592. procedure EnableRedirIn;
  593. begin
  594. If not RedirChangedIn then Exit;
  595. If not InRedirDisabled then Exit;
  596. {$ifndef FPC}
  597. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  598. Handles^[StdInputHandle]:=Handles^[FileRec (FIn^).Handle];
  599. {$else}
  600. {$ifdef windows}
  601. SetStdHandle(Std_Input_Handle,FileRec(FIn^).Handle);
  602. {$else not windows}
  603. fpdup2(FileRec(FIn^).Handle,StdInputHandle);
  604. {$endif not windows}
  605. {$endif}
  606. InRedirDisabled:=False;
  607. end;
  608. {............................................................................}
  609. procedure DisableRedirOut;
  610. begin
  611. If not RedirChangedOut then Exit;
  612. If OutRedirDisabled then Exit;
  613. {$ifndef FPC}
  614. Handles^[StdOutputHandle]:=OldHandleOut;
  615. {$else}
  616. {$ifdef windows}
  617. SetStdHandle(Std_Output_Handle,StdOutputHandle);
  618. {$else not windows}
  619. fpdup2(TempHOut,StdOutputHandle);
  620. {$endif not windows}
  621. {$endif}
  622. OutRedirDisabled:=True;
  623. end;
  624. {............................................................................}
  625. procedure EnableRedirOut;
  626. begin
  627. If not RedirChangedOut then Exit;
  628. If not OutRedirDisabled then Exit;
  629. {$ifndef FPC}
  630. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  631. Handles^[StdOutputHandle]:=Handles^[FileRec (FOut^).Handle];
  632. {$else}
  633. {$ifdef windows}
  634. SetStdHandle(Std_Output_Handle,FileRec(FOut^).Handle);
  635. {$else not windows}
  636. fpdup2(FileRec(FOut^).Handle,StdOutputHandle);
  637. {$endif not windows}
  638. {$endif}
  639. OutRedirDisabled:=False;
  640. end;
  641. {............................................................................}
  642. procedure RestoreRedirError;
  643. begin
  644. If not RedirChangedError then Exit;
  645. {$ifndef FPC}
  646. Handles^[StdErrorHandle]:=OldHandleError;
  647. OldHandleError:=StdErrorHandle;
  648. {$else}
  649. {$ifdef windows}
  650. SetStdHandle(Std_Error_Handle,StdErrorHandle);
  651. {$else not windows}
  652. fpdup2(TempHError,StdErrorHandle);
  653. {$endif not windows}
  654. {$endif}
  655. { don't close when redirected to STDOUT }
  656. if not RedirStdErrToStdOut then
  657. Close (FERR^);
  658. {$ifndef windows}
  659. fpclose(TempHError);
  660. {$endif ndef windows}
  661. RedirChangedError:=false;
  662. end;
  663. {............................................................................}
  664. procedure DisableRedirError;
  665. begin
  666. If not RedirChangedError then Exit;
  667. If ErrorRedirDisabled then Exit;
  668. {$ifndef FPC}
  669. Handles^[StdErrorHandle]:=OldHandleError;
  670. {$else}
  671. {$ifdef windows}
  672. SetStdHandle(Std_Error_Handle,StdErrorHandle);
  673. {$else not windows}
  674. fpdup2(TempHError,StdErrorHandle);
  675. {$endif not windows}
  676. {$endif}
  677. ErrorRedirDisabled:=True;
  678. end;
  679. {............................................................................}
  680. procedure EnableRedirError;
  681. begin
  682. If not RedirChangedError then Exit;
  683. If not ErrorRedirDisabled then Exit;
  684. {$ifndef FPC}
  685. Handles:=Ptr (prefseg, PWord (Ptr (prefseg, $34))^);
  686. Handles^[StdErrorHandle]:=Handles^[FileRec (FErr^).Handle];
  687. {$else}
  688. {$ifdef windows}
  689. SetStdHandle(Std_Error_Handle,FileRec(FErr^).Handle);
  690. {$else not windows}
  691. fpdup2(FileRec(FERR^).Handle,StdErrorHandle);
  692. {$endif not windows}
  693. {$endif}
  694. ErrorRedirDisabled:=False;
  695. end;
  696. {............................................................................}
  697. {$ifdef EXECUTEREDIR_USES_PROCESS}
  698. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  699. const
  700. max_count = 60000;
  701. var
  702. P : TProcess;
  703. begin
  704. P := TProcess.Create(nil);
  705. try
  706. P.CommandLine:=Progname + ' ' + ComLine;
  707. P.InputDescriptor.FileName:=RedirStdIn;
  708. P.OutputDescriptor.FileName:=RedirStdOut;
  709. if RedirStdErr='stdout' then
  710. P.Options:=P.options+[poStdErrToOutput]
  711. else
  712. P.ErrorDescriptor.FileName:=RedirStdErr;
  713. P.Execute;
  714. Result:=P.WaitOnExit(max_count);
  715. if Result then
  716. ExecuteResult:=P.ExitCode
  717. else
  718. begin
  719. Writeln(stderr,'Terminate requested for ',Progname,' ',ComLine);
  720. { Issue it also to output, so it gets added to log file
  721. if ExecuteRedir is in use }
  722. Writeln('Terminate requested for ',Progname,' ',ComLine);
  723. Repeat
  724. P.Terminate(255);
  725. Sleep(10);
  726. Until not P.Running;
  727. ExecuteResult:=1000+P.ExitCode;
  728. end;
  729. Result:=ExecuteResult=0;
  730. finally
  731. P.Free;
  732. end;
  733. end;
  734. {$ELSE}
  735. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  736. Begin
  737. RedirErrorOut:=0; RedirErrorIn:=0; RedirErrorError:=0;
  738. ExecuteResult:=0;
  739. IOStatus:=0;
  740. if RedirStdIn<>'' then
  741. ChangeRedirIn(RedirStdIn);
  742. if RedirStdOut<>'' then
  743. ChangeRedirOut(RedirStdOut,false);
  744. if RedirStdErr<>'stderr' then
  745. ChangeRedirError(RedirStdErr,false);
  746. DosExecute(ProgName,ComLine);
  747. RestoreRedirOut;
  748. RestoreRedirIn;
  749. RestoreRedirError;
  750. ExecuteRedir:=(IOStatus=0) and (RedirErrorOut=0) and
  751. (RedirErrorIn=0) and (RedirErrorError=0) and
  752. (ExecuteResult=0);
  753. End;
  754. {$ENDIF}
  755. {............................................................................}
  756. procedure RedirDisableAll;
  757. begin
  758. If RedirChangedIn and not InRedirDisabled then
  759. DisableRedirIn;
  760. If RedirChangedOut and not OutRedirDisabled then
  761. DisableRedirOut;
  762. If RedirChangedError and not ErrorRedirDisabled then
  763. DisableRedirError;
  764. end;
  765. {............................................................................}
  766. procedure RedirEnableAll;
  767. begin
  768. If RedirChangedIn and InRedirDisabled then
  769. EnableRedirIn;
  770. If RedirChangedOut and OutRedirDisabled then
  771. EnableRedirOut;
  772. If RedirChangedError and ErrorRedirDisabled then
  773. EnableRedirError;
  774. end;
  775. procedure InitRedir;
  776. begin
  777. end;
  778. {$else not implemented}
  779. {*****************************************************************************
  780. Fake
  781. *****************************************************************************}
  782. {$IFDEF SHELL_IMPLEMENTED}
  783. {$I-}
  784. function FileExist(const FileName : PathStr) : Boolean;
  785. var
  786. f : file;
  787. Attr : word;
  788. begin
  789. Assign(f, FileName);
  790. GetFAttr(f, Attr);
  791. FileExist := DosError = 0;
  792. end;
  793. function CompleteDir(const Path: string): string;
  794. begin
  795. { keep c: untouched PM }
  796. if (Path<>'') and (Path[Length(Path)]<>DirSep) and
  797. (Path[Length(Path)]<>':') then
  798. CompleteDir:=Path+DirSep
  799. else
  800. CompleteDir:=Path;
  801. end;
  802. function LocateExeFile(var FileName:string): boolean;
  803. var
  804. {$IFDEF USEDOS}
  805. dir,s,d,n,e : shortstring;
  806. {$ELSE USEDOS}
  807. dir,s,d,n,e : string;
  808. {$ENDIF USEDOS}
  809. i : longint;
  810. begin
  811. LocateExeFile:=False;
  812. if FileExist(FileName) then
  813. begin
  814. LocateExeFile:=true;
  815. Exit;
  816. end;
  817. Fsplit(Filename,d,n,e);
  818. if (e='') and FileExist(FileName+exeext) then
  819. begin
  820. FileName:=FileName+exeext;
  821. LocateExeFile:=true;
  822. Exit;
  823. end;
  824. {$ifdef macos}
  825. S:=GetEnv('Commands');
  826. {$else}
  827. S:=GetEnv('PATH');
  828. {$endif}
  829. While Length(S)>0 do
  830. begin
  831. i:=1;
  832. While (i<=Length(S)) and not (S[i] in ListSep) do
  833. Inc(i);
  834. Dir:=CompleteDir(Copy(S,1,i-1));
  835. if i<Length(S) then
  836. Delete(S,1,i)
  837. else
  838. S:='';
  839. if FileExist(Dir+FileName) then
  840. Begin
  841. FileName:=Dir+FileName;
  842. LocateExeFile:=true;
  843. Exit;
  844. End;
  845. end;
  846. end;
  847. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  848. var
  849. CmdLine2: string;
  850. begin
  851. {$ifdef macos}
  852. if Lowercase(RedirStdIn) = 'stdin' then RedirStdIn := 'Dev:StdIn';
  853. if Lowercase(RedirStdOut) = 'stdout' then RedirStdOut := 'Dev:Output';
  854. if Lowercase(RedirStdOut) = 'stderr' then RedirStdOut := 'Dev:Error';
  855. if Lowercase(RedirStdErr) = 'stdout' then RedirStdErr := 'Dev:Output';
  856. if Lowercase(RedirStdErr) = 'stderr' then RedirStdErr := 'Dev:Error';
  857. {$endif macos}
  858. CmdLine2 := ComLine;
  859. if RedirStdIn <> '' then CmdLine2 := CmdLine2 + ' < ' + RedirStdIn;
  860. {$ifndef macos}
  861. if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
  862. if RedirStdErr <> '' then
  863. begin
  864. if RedirStdErr = RedirStdOut then
  865. CmdLine2 := CmdLine2 + ' 2>&1'
  866. else
  867. CmdLine2 := CmdLine2 + ' 2> ' + RedirStdErr;
  868. end;
  869. {$else macos}
  870. if RedirStdErr <> RedirStdOut then
  871. if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
  872. if RedirStdErr <> '' then
  873. begin
  874. if RedirStdErr = RedirStdOut then
  875. CmdLine2 := CmdLine2 + ' ' + #183 + ' ' + RedirStdErr {#183 is "capital sigma" char in MacRoman}
  876. else
  877. CmdLine2 := CmdLine2 + ' ' + #179 + ' ' + RedirStdErr; {#179 is "greater or equal" char in MacRoman}
  878. end;
  879. {$endif macos}
  880. DosExecute (ProgName, CmdLine2);
  881. ExecuteRedir:=(IOStatus=0) and (ExecuteResult=0);
  882. end;
  883. {$ELSE SHELL_IMPLEMENTED}
  884. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  885. begin
  886. ExecuteRedir:=false;
  887. end;
  888. {$ENDIF SHELL_IMPLEMENTED}
  889. function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
  890. begin
  891. ChangeRedirOut:=false;
  892. end;
  893. procedure RestoreRedirOut;
  894. begin
  895. end;
  896. procedure DisableRedirOut;
  897. begin
  898. end;
  899. procedure EnableRedirOut;
  900. begin
  901. end;
  902. function ChangeRedirIn(Const Redir : String) : Boolean;
  903. begin
  904. ChangeRedirIn:=false;
  905. end;
  906. procedure RestoreRedirIn;
  907. begin
  908. end;
  909. procedure DisableRedirIn;
  910. begin
  911. end;
  912. procedure EnableRedirIn;
  913. begin
  914. end;
  915. function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
  916. begin
  917. ChangeRedirError:=false;
  918. end;
  919. procedure RestoreRedirError;
  920. begin
  921. end;
  922. procedure DisableRedirError;
  923. begin
  924. end;
  925. procedure EnableRedirError;
  926. begin
  927. end;
  928. procedure RedirDisableAll;
  929. begin
  930. end;
  931. procedure RedirEnableAll;
  932. begin
  933. end;
  934. procedure InitRedir;
  935. begin
  936. end;
  937. {$endif not implemented}
  938. {............................................................................}
  939. {$ifdef UNIX}
  940. function TransformfpSystemToShell(s:cint):cint;
  941. // transforms standarized (fp)System(3) result to the conventions of the old Unix.shell function.
  942. begin
  943. if s=-1 then exit(-1);
  944. if wifexited(s) then
  945. TransformfpSystemToShell:=wexitstatus(s)
  946. else if (s>0) then
  947. TransformfpSystemToShell:=-s
  948. else
  949. TransformfpSystemToShell:=s;
  950. end;
  951. {$endif def UNIX}
  952. {****************************************************************************
  953. Helpers
  954. ****************************************************************************}
  955. {$ifdef USES_UNIT_PROCESS}
  956. const
  957. max_count = 60000; { should be 60 seconds }
  958. function ExecuteProcess(const Path: string; const ComLine: string; Flags:TExecuteFlags=[]): integer;
  959. var
  960. P: TProcess;
  961. counter : longint;
  962. TerminateSentCount : longint;
  963. begin
  964. result := -1;
  965. TerminateSentCount:=0;
  966. P := TProcess.Create(nil);
  967. try
  968. P.CommandLine := Path + ' ' + ComLine;
  969. P.InheritHandles:=(execinheritshandles in flags);
  970. P.Execute;
  971. {$if FPC_FULLVERSION < 30100}
  972. {$ifdef Windows}
  973. WaitForSingleObject(P.ProcessHandle,max_count);
  974. counter:=max_count;
  975. {$else not Windows}
  976. counter:=0;
  977. {$endif not Windows}
  978. {$else}
  979. P.WaitOnExit(max_count);
  980. counter:=max_count;
  981. {$endif}
  982. while P.Running do
  983. begin
  984. if counter>max_count then
  985. begin
  986. P.Terminate(255);
  987. if TerminateSentCount=0 then
  988. { also write ComLine in order to know which test is not ended in time }
  989. begin
  990. Writeln(stderr,'Terminate requested for ',Path,' ',ComLine);
  991. { Issue it also to output, so it gets added to log file
  992. if ExecuteRedir is in use }
  993. Writeln('Terminate requested for ',Path,' ',ComLine);
  994. end;
  995. Inc(TerminateSentCount);
  996. end;
  997. Sleep(1);
  998. inc(counter);
  999. end;
  1000. { Be sure to return a non-zero value if Terminate was requested }
  1001. if (TerminateSentCount>0) and (P.ExitStatus>=0) then
  1002. result := 1000 + P.ExitStatus
  1003. else
  1004. result := P.ExitStatus;
  1005. finally
  1006. P.Free;
  1007. end;
  1008. end;
  1009. {$endif HAS_UNIT_PROCESS}
  1010. procedure DosExecute(ProgName, ComLine : String);
  1011. Begin
  1012. {$IfDef MsDos}
  1013. SmallHeap;
  1014. {$EndIf MsDos}
  1015. {$ifdef usedos}
  1016. SwapVectors;
  1017. {$endif usedos}
  1018. { Must use shell/fpsystem() for *nix for the wildcard expansion (PFV) }
  1019. {$ifdef UNIX}
  1020. IOStatus:=0;
  1021. ExecuteResult:=Transformfpsystemtoshell(fpsystem((FixPath(Progname)+' '+Comline)));
  1022. if ExecuteResult<0 then
  1023. begin
  1024. IOStatus:=(-ExecuteResult) and $7f;
  1025. ExecuteResult:=((-ExecuteResult) and $ff00) shr 8;
  1026. end;
  1027. {$else}
  1028. {$ifdef windows}
  1029. { Avoid dialog boxes if dll loading fails }
  1030. SetErrorMode(SEM_FAILCRITICALERRORS);
  1031. {$endif windows}
  1032. If UseComSpec then
  1033. begin
  1034. {$ifndef usedos}
  1035. try
  1036. ExecuteResult:=ExecuteProcess (Getenvironmentvariable('COMSPEC'),'/C '+FixPath(progname)+' '+Comline,[ExecInheritsHandles])
  1037. except
  1038. on e : exception do
  1039. IOStatus:=2;
  1040. end;
  1041. {$else}
  1042. DosError:=0;
  1043. Exec (Getenv('COMSPEC'),'/C '+FixPath(progname)+' '+Comline);
  1044. IOStatus:=DosError;
  1045. ExecuteResult:=DosExitCode;
  1046. {$endif}
  1047. end
  1048. else
  1049. begin
  1050. if LocateExeFile(progname) then
  1051. begin
  1052. {$ifndef usedos}
  1053. try
  1054. ExecuteResult:=ExecuteProcess(ProgName,Comline,[execinheritshandles])
  1055. except
  1056. on e : exception do
  1057. IOStatus:=2;
  1058. end;
  1059. {$else}
  1060. doserror:=0;
  1061. {$ifdef macos}
  1062. Dos.Exec(''''+ProgName+'''',Comline); {Quotes needed !}
  1063. {$else}
  1064. Dos.Exec(ProgName,Comline);
  1065. {$endif}
  1066. IOStatus:=DosError;
  1067. ExecuteResult:=DosExitCode;
  1068. {$endif}
  1069. end
  1070. else
  1071. IOStatus:=2
  1072. ;
  1073. end;
  1074. {$ifdef windows}
  1075. SetErrorMode(0);
  1076. {$endif windows}
  1077. {$endif}
  1078. {$ifdef usedos}
  1079. SwapVectors;
  1080. {$endif}
  1081. {$ifdef CPU86}
  1082. { reset the FPU }
  1083. {$asmmode att}
  1084. asm
  1085. fninit
  1086. end;
  1087. {$endif CPU86}
  1088. {$IfDef MsDos}
  1089. Fullheap;
  1090. {$EndIf MsDos}
  1091. End;
  1092. {*****************************************************************************
  1093. Initialize
  1094. *****************************************************************************}
  1095. initialization
  1096. New(FIn); New(FOut); New(FErr);
  1097. finalization
  1098. Dispose(FIn); Dispose(FOut); Dispose(FErr);
  1099. End.