////////////////////////////////////////////////////////////////////////////////// // 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 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(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 chandle = consoleContainer; TContainer 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(); } /// /// 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. /// /// 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