/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // using System; using System.Collections; using System.Diagnostics; using System.IO; using Pipe = Microsoft.Singularity.Io.Tty; using FileSystem.Utils; using Microsoft.Contracts; using Microsoft.SingSharp.Reflection; using Microsoft.Singularity.Applications; using Microsoft.Singularity.Io; using Microsoft.Singularity.Directory; using Microsoft.Singularity.Configuration; using Microsoft.Singularity.Channels; [assembly: Transform(typeof(ApplicationResourceTransform))] namespace Microsoft.Singularity.Applications { [ConsoleCategory(HelpMessage="Display a screen full of text", DefaultAction=true)] internal class Parameters { [InputEndpoint("data")] public readonly TRef Stdin; [OutputEndpoint("data")] public readonly TRef Stdout; [Endpoint] public readonly TRef nsRef; [StringArrayParameter( "files", HelpMessage="Files to be listed.")] internal string[] fileSet; reflective internal Parameters(); internal int AppMain() { return More.AppMain(this); } } class More { internal static int pageCounter; internal static Terminal! terminal; internal static long fileSize; internal static long bytesRead; [ Conditional("DEBUG_MORE") ] static void DebugPrint(string format, params object [] args) { DebugStub.Print(String.Format(format, args)); } [ Conditional("DEBUG_MORE") ] static void DebugWriteLine(string format, params object [] args) { DebugPrint(format, args); DebugStub.Print("\n"); } [ Conditional("DEBUG_MORE") ] static void DebugReadLine() { Console.ReadLine(); } internal static int AppMain(Parameters! config) { // constants //int szLineCount = 0; int displayfile = 0; int consoleWidth = 0; int consoleHeight = 0; pageCounter = 0; terminal = new Terminal(); DirectoryServiceContract.Imp dsRoot = ((!)config.nsRef).Acquire(); if (dsRoot == null) { throw new Exception("Unable to acquire handle to the Directory Service root"); } dsRoot.RecvSuccess(); // TODO need to dynamically get window size consoleHeight = 47; // allow for "activity" line on top of Singularity console.... consoleWidth = 79; assume config.fileSet != null; string szSrcLine; bool ok; if (config.fileSet.Length <= 0) { //stdin while ((szSrcLine = Console.ReadLine()) != null) { ok = PageText(szSrcLine, consoleHeight, consoleWidth, true); if (!ok) break; } delete dsRoot; return 0; } for (displayfile = 0; displayfile < config.fileSet.Length; displayfile++) { string filename = config.fileSet[displayfile]; if (filename == null) continue; // check that file exists ErrorCode error; FileAttributesRecord fileAttributes; ok = FileUtils.GetAttributes(filename, dsRoot, out fileAttributes, out error); if (ok) { if (fileAttributes.Type == NodeType.IoMemory || fileAttributes.Type == NodeType.File) { fileSize = fileAttributes.FileSize; // Open file RO for now FileStream fsInput = new FileStream(dsRoot, filename, FileMode.Open, FileAccess.Read); StreamReader srInput = new StreamReader(fsInput); while ((szSrcLine = srInput.ReadLine()) != null) { ok = PageText(szSrcLine, consoleHeight, consoleWidth, false); if (!ok) break; } srInput.Close(); fsInput.Close(); // Display the file by pages // TODO: change PageText to return between pages so can recheck for // screen dimension changes (?) if (displayfile <= config.fileSet.Length - 2) // offset by 2 due to index offset plus increment hasn't happened yet { Console.WriteLine(""); Console.Write("-- for next file --"); int key; do { key = Console.Read(); if (key == -1) { delete dsRoot; return 0; } } while ((char)key != '\n'); } } else if (fileAttributes.Type == NodeType.Directory) { // check that it's not a directory Console.WriteLine("\n{0} - is a directory.", filename); } } // ok else { // not a directory, but file doesn't exist, print error message Console.WriteLine("\n{0} - file not found.", filename); } } delete dsRoot; return 0; } ////////////////////////////////////////////////////////////// // Write out prompt and wait for input // After acquiring the input remove the prompt from the console ////////////////////////////////////////////////////////////// static int GetInput(int PAGELENGTH, bool processingStdin) { int counter = 0; int key; if (processingStdin) { Console.Write("-- -- "); key = Console.Read(); if ((char)key == '\n' ) Console.Write("\n"); } else { double temp = 0; if (fileSize != 0) { temp = (double) (bytesRead * 100) / (double)fileSize; } else { temp = 100; } Console.Write("-- ({0}%) -- ", (int)temp); key = Console.Read(); } // get rid of the -- line if ((char)key == '\n') { terminal.GenerateAndSendEscapeSequence(Pipe.EscapeCodes.UP); } Console.Write("\r"); terminal.GenerateAndSendEscapeSequence(Pipe.EscapeCodes.ERASE_FROM_CURSOR); if (key == -1) return -1; switch (Char.ToLower((char)key)) { case 'q': return -1; default: if ((char)key == '\n') counter = PAGELENGTH ; // advance by 1 break; } return counter; } // PageText - display text a page at a time static bool PageText(string! workString, int PAGELENGTH, int PAGEWIDTH, bool processingStdin) { string[] lines; int remainder = 0; int linesinline = 0; // Split the line into the requisite number of lines // needed based on page width if (workString.Length <= PAGEWIDTH) { lines = new string[1]; lines[0] = workString; } else { int fullLines = workString.Length / PAGEWIDTH; remainder = workString.Length % PAGEWIDTH; linesinline = fullLines; if (remainder != 0) linesinline++; lines = new string[linesinline]; int pos = 0; for (int i = 0; i < fullLines; i++) { lines[i] = workString.Substring(pos,PAGEWIDTH); pos += PAGEWIDTH; } if (remainder != 0) { lines[fullLines] = workString.Substring(pos); } } // write the lines out pausing where necessary for (int i = 0; i < lines.Length; i++) { string s = lines[i]; assert s!= null; Console.WriteLine(s); pageCounter++; bytesRead += s.Length; if (pageCounter >= PAGELENGTH) { pageCounter = GetInput(PAGELENGTH, processingStdin); if (pageCounter == -1) return false; } } lines = null; return true; } // end of PageText } }