redir.pp 28 KB

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