307 lines
5 KiB
C#
307 lines
5 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using AspClassic.Scripting.Utils;
|
|
|
|
namespace AspClassic.Scripting.Runtime;
|
|
|
|
public sealed class SharedIO
|
|
{
|
|
private sealed class StreamProxy : Stream
|
|
{
|
|
private readonly ConsoleStreamType _type;
|
|
|
|
private readonly SharedIO _io;
|
|
|
|
public override bool CanRead => _type == ConsoleStreamType.Input;
|
|
|
|
public override bool CanSeek => false;
|
|
|
|
public override bool CanWrite => !CanRead;
|
|
|
|
public override long Length
|
|
{
|
|
get
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
public override long Position
|
|
{
|
|
get
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
set
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
public StreamProxy(SharedIO io, ConsoleStreamType type)
|
|
{
|
|
_io = io;
|
|
_type = type;
|
|
}
|
|
|
|
public override void Flush()
|
|
{
|
|
_io.GetStream(_type).Flush();
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
return _io.GetStream(_type).Read(buffer, offset, count);
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
_io.GetStream(_type).Write(buffer, offset, count);
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
private readonly object _mutex = new object();
|
|
|
|
private Stream _inputStream;
|
|
|
|
private Stream _outputStream;
|
|
|
|
private Stream _errorStream;
|
|
|
|
private TextReader _inputReader;
|
|
|
|
private TextWriter _outputWriter;
|
|
|
|
private TextWriter _errorWriter;
|
|
|
|
private Encoding _inputEncoding;
|
|
|
|
public Stream InputStream
|
|
{
|
|
get
|
|
{
|
|
InitializeInput();
|
|
return _inputStream;
|
|
}
|
|
}
|
|
|
|
public Stream OutputStream
|
|
{
|
|
get
|
|
{
|
|
InitializeOutput();
|
|
return _outputStream;
|
|
}
|
|
}
|
|
|
|
public Stream ErrorStream
|
|
{
|
|
get
|
|
{
|
|
InitializeErrorOutput();
|
|
return _errorStream;
|
|
}
|
|
}
|
|
|
|
public TextReader InputReader
|
|
{
|
|
get
|
|
{
|
|
InitializeInput();
|
|
return _inputReader;
|
|
}
|
|
}
|
|
|
|
public TextWriter OutputWriter
|
|
{
|
|
get
|
|
{
|
|
InitializeOutput();
|
|
return _outputWriter;
|
|
}
|
|
}
|
|
|
|
public TextWriter ErrorWriter
|
|
{
|
|
get
|
|
{
|
|
InitializeErrorOutput();
|
|
return _errorWriter;
|
|
}
|
|
}
|
|
|
|
public Encoding InputEncoding
|
|
{
|
|
get
|
|
{
|
|
InitializeInput();
|
|
return _inputEncoding;
|
|
}
|
|
}
|
|
|
|
public Encoding OutputEncoding
|
|
{
|
|
get
|
|
{
|
|
InitializeOutput();
|
|
return _outputWriter.Encoding;
|
|
}
|
|
}
|
|
|
|
public Encoding ErrorEncoding
|
|
{
|
|
get
|
|
{
|
|
InitializeErrorOutput();
|
|
return _errorWriter.Encoding;
|
|
}
|
|
}
|
|
|
|
internal SharedIO()
|
|
{
|
|
}
|
|
|
|
private void InitializeInput()
|
|
{
|
|
if (_inputStream != null)
|
|
{
|
|
return;
|
|
}
|
|
lock (_mutex)
|
|
{
|
|
if (_inputStream == null)
|
|
{
|
|
_inputStream = ConsoleInputStream.Instance;
|
|
_inputEncoding = Console.InputEncoding;
|
|
_inputReader = Console.In;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitializeOutput()
|
|
{
|
|
if (_outputStream != null)
|
|
{
|
|
return;
|
|
}
|
|
lock (_mutex)
|
|
{
|
|
if (_outputStream == null)
|
|
{
|
|
_outputStream = Console.OpenStandardOutput();
|
|
_outputWriter = Console.Out;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitializeErrorOutput()
|
|
{
|
|
if (_errorStream == null)
|
|
{
|
|
Stream value = Console.OpenStandardError();
|
|
Interlocked.CompareExchange(ref _errorStream, value, null);
|
|
Interlocked.CompareExchange(ref _errorWriter, Console.Error, null);
|
|
}
|
|
}
|
|
|
|
public void SetOutput(Stream stream, TextWriter writer)
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
_outputStream = stream;
|
|
_outputWriter = writer;
|
|
}
|
|
}
|
|
|
|
public void SetErrorOutput(Stream stream, TextWriter writer)
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
_errorStream = stream;
|
|
_errorWriter = writer;
|
|
}
|
|
}
|
|
|
|
public void SetInput(Stream stream, TextReader reader, Encoding encoding)
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
_inputStream = stream;
|
|
_inputReader = reader;
|
|
_inputEncoding = encoding;
|
|
}
|
|
}
|
|
|
|
public void RedirectToConsole()
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
_inputEncoding = null;
|
|
_inputStream = null;
|
|
_outputStream = null;
|
|
_errorStream = null;
|
|
_inputReader = null;
|
|
_outputWriter = null;
|
|
_errorWriter = null;
|
|
}
|
|
}
|
|
|
|
public Stream GetStream(ConsoleStreamType type)
|
|
{
|
|
return type switch
|
|
{
|
|
ConsoleStreamType.Input => InputStream,
|
|
ConsoleStreamType.Output => OutputStream,
|
|
ConsoleStreamType.ErrorOutput => ErrorStream,
|
|
_ => throw Error.InvalidStreamType(type),
|
|
};
|
|
}
|
|
|
|
public TextWriter GetWriter(ConsoleStreamType type)
|
|
{
|
|
return type switch
|
|
{
|
|
ConsoleStreamType.Output => OutputWriter,
|
|
ConsoleStreamType.ErrorOutput => ErrorWriter,
|
|
_ => throw Error.InvalidStreamType(type),
|
|
};
|
|
}
|
|
|
|
public Encoding GetEncoding(ConsoleStreamType type)
|
|
{
|
|
return type switch
|
|
{
|
|
ConsoleStreamType.Input => InputEncoding,
|
|
ConsoleStreamType.Output => OutputEncoding,
|
|
ConsoleStreamType.ErrorOutput => ErrorEncoding,
|
|
_ => throw Error.InvalidStreamType(type),
|
|
};
|
|
}
|
|
|
|
public TextReader GetReader(out Encoding encoding)
|
|
{
|
|
lock (_mutex)
|
|
{
|
|
TextReader inputReader = InputReader;
|
|
encoding = InputEncoding;
|
|
return inputReader;
|
|
}
|
|
}
|
|
|
|
public Stream GetStreamProxy(ConsoleStreamType type)
|
|
{
|
|
return new StreamProxy(this, type);
|
|
}
|
|
}
|