Redirecting Print()

BlitzMax Forums/BlitzMax Programming/Redirecting Print()

JoshK(Posted 2009) [#1]
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.



JoshK(Posted 2009) [#2]
Ah, it's this easy:

StandardIOStream =new TMyStream
Type TMyStream Extends TStream
	Method WriteLine(s$)
		AddTextAreaText(Gadget_Console,s+"~n")
		AppLog(s)
	EndMethod
EndType



GW(Posted 2009) [#3]
just overload print
EX.
Function Print(s$)
	DebugLog("!!"+s)
End Function



JoshK(Posted 2009) [#4]
.


Czar Flavius(Posted 2009) [#5]
.


spacerat(Posted 2009) [#6]
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")



JoshK(Posted 2009) [#7]
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



ziggy(Posted 2009) [#8]
@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.


JoshK(Posted 2009) [#9]
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



ziggy(Posted 2009) [#10]
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.


plash(Posted 2009) [#11]
@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?


ziggy(Posted 2009) [#12]
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.