singrdk/base/Applications/Runtime/Singularity/Io/ConsoleInput.sg

319 lines
10 KiB
Plaintext

//////////////////////////////////////////////////////////////////////////////////
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: ConsoleInput.sg
//
// Note: Read a line or a char of the Console
//
using DirectoryService.Utils;
using System.GC;
using System.Runtime.Remoting;
using System.Threading;
using System.Collections;
using System.Diagnostics;
using Microsoft.Singularity.V1.Services;
namespace Microsoft.Singularity.Io {
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.V1.Threads;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Directory;
using System;
using System.Text;
using System.Globalization;
using System.Runtime.CompilerServices;
using Microsoft.Singularity.Extending;
using Microsoft.Singularity.Runtime;
using Microsoft.Singularity.Io;
using System.Runtime.InteropServices;
public sealed class ConsoleInput /* : ITracked, ISelectable */
{
private static TContainer<PipeLookAhead> consoleContainer;
// protected by TContainer lock.
private static char[]! readLineBuffer = new char[16];
/*
private char[]! in ExHeap side;
private UnicodePipeContract.Exp conn;
private int charCount;
private int charPos;
private ConsoleInput([Claims] UnicodePipeContract.Exp? pipe)
{
this.side = new[ExHeap] char [280];
this.charCount = 0;
this.charPos = 0;
this.conn = pipe;
base();
}
*/
private ConsoleInput() {}
private static UnicodePipeContract.Exp? GetPipe()
{
UnicodePipeContract.Exp con = null;
Endpoint * in ExHeap pipeep = Process.GetStartupEndpoint(0);
if (pipeep != null) {
con = pipeep as UnicodePipeContract.Exp;
if (con == null) {
// this cannot possibly work! the process is already started
#if DEBUG
DebugStub.WriteLine("ConsoleInput: slot 0 is not a pipe.");
#endif
Process.RetStartupEndpoint(0,pipeep);
return null;
}
else {
//DebugStub.WriteLine("ConsoleInput: connected to pipe.");
return con;
}
}
return null;
}
public static void Initialize()
{
UnicodePipeContract.Exp pipe = GetPipe();
PipeLookAhead bufferedPipe = new PipeLookAhead(pipe, 100);
ConsoleInput.consoleContainer = new TContainer<PipeLookAhead>(bufferedPipe);
}
/*
public void Dispose()
{
delete this.side;
delete this.conn;
}
void ITracked.Acquire() {
Tracing.Log(Tracing.Debug,"ConsoleInput.Acquire");
}
void ITracked.Release() {
Tracing.Log(Tracing.Debug,"ConsoleInput.Release");
}
void ITracked.Expose() {
Tracing.Log(Tracing.Debug,"ConsoleInput.Expose");
}
void ITracked.UnExpose() {
Tracing.Log(Tracing.Debug,"ConsoleInput.UnExpose");
}
*/
public static void Finalize()
{
#if DEBUG
DebugStub.WriteLine("consoleInput: finalizer called");
#endif
// TContainer<ConsoleInput> chandle = consoleContainer;
TContainer<PipeLookAhead> chandle = consoleContainer;
consoleContainer = null;
if (chandle == null) return;
PipeLookAhead co = chandle.Acquire();
co.Dispose();
}
/*
private int InternalReadChar()
{
expose (this) {
if (this.conn != null) {
if (this.charCount == 0) {
UnicodePipeContract.Exp pipe = this.conn;
tryAgain:
switch receive {
case pipe.Write(buffer,a,b):
if (b == 0) {
pipe.SendAckWrite(buffer);
goto tryAgain;
}
if (b == 1) {
int theChar = (int) buffer[a];
pipe.SendAckWrite(buffer);
return theChar;
}
else {
// switch our buffer with theirs
pipe.SendAckWrite(this.side);
this.side = buffer;
this.charPos = a+1;
this.charCount = b-1;
return (int)buffer[a];
}
case pipe.ChannelClosed():
return -1;
}
}
else {
// there are more chars in the buffer
int theChar = this.side[this.charPos++];
this.charCount--;
return theChar;
}
}
} //expose
return -1;
}
*/
public static void Close()
{
}
public static int ReadChar()
{
if (consoleContainer == null) return -1;
PipeLookAhead co = consoleContainer.Acquire();
int key = co.ReadChar();
if (key == -1) {
co.Dispose();
consoleContainer = null;
return key;
}
consoleContainer.Release(co);
return key;
} //ReadChar
////////////////////////////////////////////////////////
//
public static string ReadLine()
{
if (consoleContainer == null) return null;
PipeLookAhead bufferedPipe = consoleContainer.Acquire();
int pos = 0;
int key;
do {
key = bufferedPipe.ReadChar();
if (key == -1) {
bufferedPipe.Dispose();
consoleContainer = null;
return null;
}
if (key == '\r') {
// DebugStub.WriteLine("key {0}", key);
continue;
}
if (key == '\n') {
// DebugStub.WriteLine("key {0}", key);
break;
}
if (pos+1 >= readLineBuffer.Length){
char[] temp = new char[readLineBuffer.Length *2];
Array.Copy(readLineBuffer,temp,readLineBuffer.Length);
readLineBuffer = temp;
}
readLineBuffer[pos++] = (char) key;
if (key > 31 && key < 126) {
// DebugStub.WriteLine("key {0}", key);
}
} while (key != -1 );
string s = new string(readLineBuffer,0,pos);
//DebugStub.WriteLine("in: count={0}, s=({1})",__arglist(pos, s));
consoleContainer.Release(bufferedPipe);
return s;
} //ReadLine
/*
internal enum ReceiveTag {
Any = 1,
GetChar = 2,
}
[Selectable((int)ReceiveTag.GetChar)]
public void RecvGetChar(out int key) {
key = this.InternalReadChar();
}
/// <summary>
/// Tests if the message at the head of the queue matches the given tag. If so,
/// returns true.
///
/// If no match is possible in the future given the current message, possible must
/// be set to false.
/// Implementations are disallowed from setting possible to true
/// so that the context can chain them.
///
/// If the underlying object is an endpoint set, it also returns an object that
/// serves to extract the endpoint having the match from the set later.
///
/// Again, implementations are disallowed from setting match setMatch to null
/// so that the context can chain the calls.
///
/// </summary>
bool ISelectable.HeadMatches(int tag, ref bool possible, ref object setMatch) {
// Only handle pipe case
expose (this) {
if (this.conn != null) {
if (this.charCount == 0) {
UnicodePipeContract.Exp pipe = this.conn;
// negative tag is channel closed
int pipeTag = (tag < 0)?tag : UnicodePipeContract.Tags.Write;
return pipe.HeadMatches(pipeTag, ref possible, ref setMatch);
}
else {
// there are more chars in the buffer
if (tag < 0) {
// not closed
possible = false;
return false;
}
return true;
}
}
else {
// no pipe
possible = false;
return false;
}
} //expose
}
SyncHandle ISelectable.GetWaitHandle() {
expose (this) {
assert(this.conn != null);
return this.conn.GetWaitHandle();
}
}
*/
public static PipeLookAhead! AcquireInput() {
assert consoleContainer != null;
PipeLookAhead bufferedPipe = consoleContainer.Acquire();
return bufferedPipe;
}
public static void ReleaseInput([Claims] PipeLookAhead! bufferedPipe) {
assert consoleContainer != null;
consoleContainer.Release(bufferedPipe);
}
} //ConsoleInput
}//namespace