redir.pp 28 KB

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