319 lines
10 KiB
Plaintext
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
|