Redirecting Print()
BlitzMax Forums/BlitzMax Programming/Redirecting Print()| 
 | ||
| I want to capture Print commands so I can write the output to a log file, and to the console output.  How can this be done?:  The Print and Input commands can be redirected by setting the StandardIOStream Global to an alternative Stream Object.  | 
| 
 | ||
| Ah, it's this easy: StandardIOStream =new TMyStream Type TMyStream Extends TStream Method WriteLine(s$) AddTextAreaText(Gadget_Console,s+"~n") AppLog(s) EndMethod EndType | 
| 
 | ||
| just overload print 
EX.
Function Print(s$)
	DebugLog("!!"+s)
End Function
 | 
| 
 | ||
| . | 
| 
 | ||
| . | 
| 
 | ||
| 
SuperStrict
Import brl.standardio
Import brl.filesystem
Import brl.system
Type TLogPrintStream Extends TCStandardIO
	
	Field file:String
	
	Method New()
		StandardIOStream = TTextStream.Create(Self, TTextStream.UTF8)
	End Method
	Method SetLogFile(url:String)
		Local f:TStream = OpenFile(url)
		If f
			file = url
		Else
			CreateFile(url)
			f = OpenFile(url)
			If f
				file = url
			EndIf
		EndIf
		f.Seek(f.Size())
		f.WriteLine("__________________")
		f.WriteLine("|BEGIN LOG        |")
		f.WriteLine("|Date: " + CurrentDate() + "|")
		f.WriteLine("|Time: " + CurrentTime()+"   |")
		f.WriteLine("|_________________|")
		f.Close()
		
	End Method
	
	Method Write:Int(buf:Byte Ptr, count:Int)
		If (file)
					
			Local Log:TStream = OpenStream(file, 1, 1)
			Log.Seek(Log.Size())
		
			For Local n:Int = 0 Until Count
				Log.WriteByte(buf[n])
			Next
			
			Log.Close()
		End If
		
		Return Super.Write(buf, count)
	EndMethod
End Type
New TLogPrintStream.SetLogFile("log.txt")
 | 
| 
 | ||
| Here's an even better method.  This allows you to stack up custom print redirectors, and you can just mix and match as many as you want, without worrying about interference: New TConsoleStream Type TConsoleStream Extends TStream Field oldstream:TStream Method New() oldstream=StandardIOStream StandardIOStream=Self EndMethod Method WriteLine(s$) AddTextAreaText GADGET_console,s+"~n" oldstream.WriteLine(s) EndMethod EndType | 
| 
 | ||
| @Leadwerks: Just as a suggestion, wouldn't it be much better to do a real stream to handle console redirection? SuperStrict TConsoleStream.CreateConsoleStream(New TCStandardIO, TTextStream.UTF8, True) Print "Hello world!" Type TConsoleStream Extends TTextStream Field AdditionalRedirection(Text:String) 'Function pointer Function CreateConsoleStream:TConsoleStream(stream:TStream, encoding:Int, MakeStandardIoStream:Int = False) Local MyStream:TConsoleStream = New TConsoleStream MyStream._encoding = encoding MyStream.SetStream(stream) If MakeStandardIoStream = True Then StandardIOStream = MyStream EndIf Return MyStream End Function Method WriteLine(s:String) AddTextAreaText GADGET_console,s+"~n" If additionalRedirection <> Null Then AdditionalRedirection(s) Super.WriteLine(s) EndMethod EndType Just a suggestion. | 
| 
 | ||
| I'm very confused.  Is this code correct?: Module leadwerks.logstream
Import brl.standardio
Import brl.filesystem
Strict
Global LogStreamEnabled:Int=True
Private
New TLogStream
Type TLogStream Extends TCStandardIO
	
	Field oldstream:TStream
	Field logstream:TStream
	Field writestreamopenfailed:Int
	
	Method New()
		oldstream=StandardIOStream
		StandardIOStream=Self
	EndMethod
	
	Method WriteLine(s:String)
		If LogStreamEnabled
			oldstream.WriteLine(s)
			If Not logstream
				If writestreamopenfailed Return
				Local sarr:String[]
				Local file:String
				sarr=StripAll(AppFile).split(".")
				file=sarr[0]+".log"
				logstream=WriteFile(file)
				If Not logstream
					writestreamopenfailed=True
					Return
				EndIf
				logstream.WriteLine(s)
			EndIf
		EndIf	
	EndMethod
	
EndType
Public | 
| 
 | ||
| Yes, as long as those are really the only imports that this needs (I've tested as a non module). Also, I don't know how you can determine the order on wich the modules are imported on BlitzMax, so the StandardIoStream = self, could be overwritten by the Standadio global assigment (if that's executed later). I mean, is there any way to determine execution order of imports? Other that that, it looks ok to me, except that writting to the application folder usually involves virtualization on Vista or Win7. | 
| 
 | ||
| @ziggy: Because imports have to be done before anything else, it will always have been set to the default stream before your code can do anything. EDIT: Ah.. I see what you mean. I guess the module containing the overriding stream would have to be imported after brl.standardio? | 
| 
 | ||
| Yes, that's the point. Not sure if this can be ensured somehow. The best way to do it, I think, would be to make the StandardIOStream redirection as a function call called from the program using the TLogStream module. |