redir.pp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288
  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. Result:=false;
  705. IOstatus:=0;
  706. P := TProcess.Create(nil);
  707. try
  708. P.CommandLine:=Progname + ' ' + ComLine;
  709. P.InputDescriptor.FileName:=RedirStdIn;
  710. P.OutputDescriptor.FileName:=RedirStdOut;
  711. if RedirStdErr='stdout' then
  712. P.Options:=P.options+[poStdErrToOutput]
  713. else
  714. P.ErrorDescriptor.FileName:=RedirStdErr;
  715. try
  716. P.Execute;
  717. Result:=P.WaitOnExit(max_count);
  718. except
  719. on e : exception do
  720. begin
  721. IOStatus:=2;
  722. writeln(stderr,'ExecuteRedir generated an exception: ',E.Message);
  723. end;
  724. end;
  725. if Result then
  726. ExecuteResult:=P.ExitCode
  727. else if (IOStatus<>0) then
  728. ExecuteResult:=IOStatus*1000
  729. else
  730. begin
  731. Writeln(stderr,'Terminate requested for ',Progname,' ',ComLine);
  732. { Issue it also to output, so it gets added to log file
  733. if ExecuteRedir is in use }
  734. Writeln('Terminate requested for ',Progname,' ',ComLine);
  735. Repeat
  736. P.Terminate(255);
  737. Sleep(10);
  738. Until not P.Running;
  739. ExecuteResult:=1000+P.ExitCode;
  740. end;
  741. Result:=ExecuteResult=0;
  742. finally
  743. P.Free;
  744. end;
  745. end;
  746. {$ELSE}
  747. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  748. Begin
  749. RedirErrorOut:=0; RedirErrorIn:=0; RedirErrorError:=0;
  750. ExecuteResult:=0;
  751. IOStatus:=0;
  752. if RedirStdIn<>'' then
  753. ChangeRedirIn(RedirStdIn);
  754. if RedirStdOut<>'' then
  755. ChangeRedirOut(RedirStdOut,false);
  756. if RedirStdErr<>'stderr' then
  757. ChangeRedirError(RedirStdErr,false);
  758. DosExecute(ProgName,ComLine);
  759. RestoreRedirOut;
  760. RestoreRedirIn;
  761. RestoreRedirError;
  762. ExecuteRedir:=(IOStatus=0) and (RedirErrorOut=0) and
  763. (RedirErrorIn=0) and (RedirErrorError=0) and
  764. (ExecuteResult=0);
  765. End;
  766. {$ENDIF}
  767. {............................................................................}
  768. procedure RedirDisableAll;
  769. begin
  770. If RedirChangedIn and not InRedirDisabled then
  771. DisableRedirIn;
  772. If RedirChangedOut and not OutRedirDisabled then
  773. DisableRedirOut;
  774. If RedirChangedError and not ErrorRedirDisabled then
  775. DisableRedirError;
  776. end;
  777. {............................................................................}
  778. procedure RedirEnableAll;
  779. begin
  780. If RedirChangedIn and InRedirDisabled then
  781. EnableRedirIn;
  782. If RedirChangedOut and OutRedirDisabled then
  783. EnableRedirOut;
  784. If RedirChangedError and ErrorRedirDisabled then
  785. EnableRedirError;
  786. end;
  787. procedure InitRedir;
  788. begin
  789. end;
  790. {$else not implemented}
  791. {*****************************************************************************
  792. Fake
  793. *****************************************************************************}
  794. {$IFDEF SHELL_IMPLEMENTED}
  795. {$I-}
  796. function FileExist(const FileName : PathStr) : Boolean;
  797. var
  798. f : file;
  799. Attr : word;
  800. begin
  801. Assign(f, FileName);
  802. GetFAttr(f, Attr);
  803. FileExist := DosError = 0;
  804. end;
  805. function CompleteDir(const Path: string): string;
  806. begin
  807. { keep c: untouched PM }
  808. if (Path<>'') and (Path[Length(Path)]<>DirSep) and
  809. (Path[Length(Path)]<>':') then
  810. CompleteDir:=Path+DirSep
  811. else
  812. CompleteDir:=Path;
  813. end;
  814. function LocateExeFile(var FileName:string): boolean;
  815. var
  816. {$IFDEF USEDOS}
  817. dir,s,d,n,e : shortstring;
  818. {$ELSE USEDOS}
  819. dir,s,d,n,e : string;
  820. {$ENDIF USEDOS}
  821. i : longint;
  822. begin
  823. LocateExeFile:=False;
  824. if FileExist(FileName) then
  825. begin
  826. LocateExeFile:=true;
  827. Exit;
  828. end;
  829. Fsplit(Filename,d,n,e);
  830. if (e='') and FileExist(FileName+exeext) then
  831. begin
  832. FileName:=FileName+exeext;
  833. LocateExeFile:=true;
  834. Exit;
  835. end;
  836. {$ifdef macos}
  837. S:=GetEnv('Commands');
  838. {$else}
  839. S:=GetEnv('PATH');
  840. {$endif}
  841. While Length(S)>0 do
  842. begin
  843. i:=1;
  844. While (i<=Length(S)) and not (S[i] in ListSep) do
  845. Inc(i);
  846. Dir:=CompleteDir(Copy(S,1,i-1));
  847. if i<Length(S) then
  848. Delete(S,1,i)
  849. else
  850. S:='';
  851. if FileExist(Dir+FileName) then
  852. Begin
  853. FileName:=Dir+FileName;
  854. LocateExeFile:=true;
  855. Exit;
  856. End;
  857. end;
  858. end;
  859. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  860. var
  861. CmdLine2: string;
  862. begin
  863. {$ifdef macos}
  864. if Lowercase(RedirStdIn) = 'stdin' then RedirStdIn := 'Dev:StdIn';
  865. if Lowercase(RedirStdOut) = 'stdout' then RedirStdOut := 'Dev:Output';
  866. if Lowercase(RedirStdOut) = 'stderr' then RedirStdOut := 'Dev:Error';
  867. if Lowercase(RedirStdErr) = 'stdout' then RedirStdErr := 'Dev:Output';
  868. if Lowercase(RedirStdErr) = 'stderr' then RedirStdErr := 'Dev:Error';
  869. {$endif macos}
  870. CmdLine2 := ComLine;
  871. if RedirStdIn <> '' then CmdLine2 := CmdLine2 + ' < ' + RedirStdIn;
  872. {$ifndef macos}
  873. if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
  874. if RedirStdErr <> '' then
  875. begin
  876. if RedirStdErr = RedirStdOut then
  877. CmdLine2 := CmdLine2 + ' 2>&1'
  878. else
  879. CmdLine2 := CmdLine2 + ' 2> ' + RedirStdErr;
  880. end;
  881. {$else macos}
  882. if RedirStdErr <> RedirStdOut then
  883. if RedirStdOut <> '' then CmdLine2 := CmdLine2 + ' > ' + RedirStdOut;
  884. if RedirStdErr <> '' then
  885. begin
  886. if RedirStdErr = RedirStdOut then
  887. CmdLine2 := CmdLine2 + ' ' + #183 + ' ' + RedirStdErr {#183 is "capital sigma" char in MacRoman}
  888. else
  889. CmdLine2 := CmdLine2 + ' ' + #179 + ' ' + RedirStdErr; {#179 is "greater or equal" char in MacRoman}
  890. end;
  891. {$endif macos}
  892. DosExecute (ProgName, CmdLine2);
  893. ExecuteRedir:=(IOStatus=0) and (ExecuteResult=0);
  894. end;
  895. {$ELSE SHELL_IMPLEMENTED}
  896. function ExecuteRedir (Const ProgName, ComLine : String; RedirStdIn, RedirStdOut, RedirStdErr: String): boolean;
  897. begin
  898. ExecuteRedir:=false;
  899. end;
  900. {$ENDIF SHELL_IMPLEMENTED}
  901. function ChangeRedirOut(Const Redir : String; AppendToFile : Boolean) : Boolean;
  902. begin
  903. ChangeRedirOut:=false;
  904. end;
  905. procedure RestoreRedirOut;
  906. begin
  907. end;
  908. procedure DisableRedirOut;
  909. begin
  910. end;
  911. procedure EnableRedirOut;
  912. begin
  913. end;
  914. function ChangeRedirIn(Const Redir : String) : Boolean;
  915. begin
  916. ChangeRedirIn:=false;
  917. end;
  918. procedure RestoreRedirIn;
  919. begin
  920. end;
  921. procedure DisableRedirIn;
  922. begin
  923. end;
  924. procedure EnableRedirIn;
  925. begin
  926. end;
  927. function ChangeRedirError(Const Redir : String; AppendToFile : Boolean) : Boolean;
  928. begin
  929. ChangeRedirError:=false;
  930. end;
  931. procedure RestoreRedirError;
  932. begin
  933. end;
  934. procedure DisableRedirError;
  935. begin
  936. end;
  937. procedure EnableRedirError;
  938. begin
  939. end;
  940. procedure RedirDisableAll;
  941. begin
  942. end;
  943. procedure RedirEnableAll;
  944. begin
  945. end;
  946. procedure InitRedir;
  947. begin
  948. end;
  949. {$endif not implemented}
  950. {............................................................................}
  951. {$ifdef UNIX}
  952. function TransformfpSystemToShell(s:cint):cint;
  953. // transforms standarized (fp)System(3) result to the conventions of the old Unix.shell function.
  954. begin
  955. if s=-1 then exit(-1);
  956. if wifexited(s) then
  957. TransformfpSystemToShell:=wexitstatus(s)
  958. else if (s>0) then
  959. TransformfpSystemToShell:=-s
  960. else
  961. TransformfpSystemToShell:=s;
  962. end;
  963. {$endif def UNIX}
  964. {****************************************************************************
  965. Helpers
  966. ****************************************************************************}
  967. {$ifdef USES_UNIT_PROCESS}
  968. const
  969. max_count = 60000; { should be 60 seconds }
  970. function ExecuteProcess(const Path: string; const ComLine: string; Flags:TExecuteFlags=[]): integer;
  971. var
  972. P: TProcess;
  973. counter : longint;
  974. TerminateSentCount : longint;
  975. begin
  976. result := -1;
  977. TerminateSentCount:=0;
  978. P := TProcess.Create(nil);
  979. try
  980. P.CommandLine := Path + ' ' + ComLine;
  981. P.InheritHandles:=(execinheritshandles in flags);
  982. P.Execute;
  983. {$if FPC_FULLVERSION < 30100}
  984. {$ifdef Windows}
  985. WaitForSingleObject(P.ProcessHandle,max_count);
  986. counter:=max_count;
  987. {$else not Windows}
  988. counter:=0;
  989. {$endif not Windows}
  990. {$else}
  991. P.WaitOnExit(max_count);
  992. counter:=max_count;
  993. {$endif}
  994. while P.Running do
  995. begin
  996. if counter>max_count then
  997. begin
  998. P.Terminate(255);
  999. if TerminateSentCount=0 then
  1000. { also write ComLine in order to know which test is not ended in time }
  1001. begin
  1002. Writeln(stderr,'Terminate requested for ',Path,' ',ComLine);
  1003. { Issue it also to output, so it gets added to log file
  1004. if ExecuteRedir is in use }
  1005. Writeln('Terminate requested for ',Path,' ',ComLine);
  1006. end;
  1007. Inc(TerminateSentCount);
  1008. end;
  1009. Sleep(1);
  1010. inc(counter);
  1011. end;
  1012. { Be sure to return a non-zero value if Terminate was requested }
  1013. if (TerminateSentCount>0) and (P.ExitStatus>=0) then
  1014. result := 1000 + P.ExitStatus
  1015. else
  1016. result := P.ExitStatus;
  1017. finally
  1018. P.Free;
  1019. end;
  1020. end;
  1021. {$endif HAS_UNIT_PROCESS}
  1022. procedure DosExecute(ProgName, ComLine : String);
  1023. Begin
  1024. {$IfDef MsDos}
  1025. SmallHeap;
  1026. {$EndIf MsDos}
  1027. {$ifdef usedos}
  1028. SwapVectors;
  1029. {$endif usedos}
  1030. { Must use shell/fpsystem() for *nix for the wildcard expansion (PFV) }
  1031. {$ifdef UNIX}
  1032. IOStatus:=0;
  1033. ExecuteResult:=Transformfpsystemtoshell(fpsystem((FixPath(Progname)+' '+Comline)));
  1034. if ExecuteResult<0 then
  1035. begin
  1036. IOStatus:=(-ExecuteResult) and $7f;
  1037. ExecuteResult:=((-ExecuteResult) and $ff00) shr 8;
  1038. end;
  1039. {$else}
  1040. {$ifdef windows}
  1041. { Avoid dialog boxes if dll loading fails }
  1042. SetErrorMode(SEM_FAILCRITICALERRORS);
  1043. {$endif windows}
  1044. If UseComSpec then
  1045. begin
  1046. {$ifndef usedos}
  1047. try
  1048. ExecuteResult:=ExecuteProcess (Getenvironmentvariable('COMSPEC'),'/C '+FixPath(progname)+' '+Comline,[ExecInheritsHandles])
  1049. except
  1050. on e : exception do
  1051. IOStatus:=2;
  1052. end;
  1053. {$else}
  1054. DosError:=0;
  1055. Exec (Getenv('COMSPEC'),'/C '+FixPath(progname)+' '+Comline);
  1056. IOStatus:=DosError;
  1057. ExecuteResult:=DosExitCode;
  1058. {$endif}
  1059. end
  1060. else
  1061. begin
  1062. if LocateExeFile(progname) then
  1063. begin
  1064. {$ifndef usedos}
  1065. try
  1066. ExecuteResult:=ExecuteProcess(ProgName,Comline,[execinheritshandles])
  1067. except
  1068. on e : exception do
  1069. IOStatus:=2;
  1070. end;
  1071. {$else}
  1072. doserror:=0;
  1073. {$ifdef macos}
  1074. Dos.Exec(''''+ProgName+'''',Comline); {Quotes needed !}
  1075. {$else}
  1076. Dos.Exec(ProgName,Comline);
  1077. {$endif}
  1078. IOStatus:=DosError;
  1079. ExecuteResult:=DosExitCode;
  1080. {$endif}
  1081. end
  1082. else
  1083. IOStatus:=2
  1084. ;
  1085. end;
  1086. {$ifdef windows}
  1087. SetErrorMode(0);
  1088. {$endif windows}
  1089. {$endif}
  1090. {$ifdef usedos}
  1091. SwapVectors;
  1092. {$endif}
  1093. {$ifdef CPU86}
  1094. { reset the FPU }
  1095. {$asmmode att}
  1096. asm
  1097. fninit
  1098. end;
  1099. {$endif CPU86}
  1100. {$IfDef MsDos}
  1101. Fullheap;
  1102. {$EndIf MsDos}
  1103. End;
  1104. {*****************************************************************************
  1105. Initialize
  1106. *****************************************************************************}
  1107. initialization
  1108. New(FIn); New(FOut); New(FErr);
  1109. finalization
  1110. Dispose(FIn); Dispose(FOut); Dispose(FErr);
  1111. End.