| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027 |
- //
- // repl.cs: Support for using the compiler in interactive mode (read-eval-print loop)
- //
- // Authors:
- // Miguel de Icaza ([email protected])
- //
- // Dual licensed under the terms of the MIT X11 or GNU GPL
- //
- // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
- // Copyright 2004, 2005, 2006, 2007, 2008 Novell, Inc
- // Copyright 2011-2013 Xamarin Inc
- //
- //
- // TODO:
- // Do not print results in Evaluate, do that elsewhere in preparation for Eval refactoring.
- // Driver.PartialReset should not reset the coretypes, nor the optional types, to avoid
- // computing that on every call.
- //
- using System;
- using System.IO;
- using System.Text;
- using System.Globalization;
- using System.Collections;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Threading;
- using System.Net;
- using System.Net.Sockets;
- using System.Collections.Generic;
- using Mono.CSharp;
- namespace Mono {
- public class Driver {
- public static string StartupEvalExpression;
- static int? attach;
- static string target_host;
- static int target_port;
- static string agent;
- static string [] script_args;
- public static string [] ScriptArgs => script_args;
-
- static int Main (string [] args)
- {
- if (!SplitDriverAndScriptArguments (ref args, out script_args))
- return 1;
- var cmd = new CommandLineParser (Console.Out);
- cmd.UnknownOptionHandler += HandleExtraArguments;
- // Enable unsafe code by default
- var settings = new CompilerSettings () {
- Unsafe = true
- };
- if (!cmd.ParseArguments (settings, args))
- return 1;
- var startup_files = new string [settings.SourceFiles.Count];
- int i = 0;
- foreach (var source in settings.SourceFiles)
- startup_files [i++] = source.OriginalFullPathName;
- settings.SourceFiles.Clear ();
- TextWriter agent_stderr = null;
- ReportPrinter printer;
- if (agent != null) {
- agent_stderr = new StringWriter ();
- printer = new StreamReportPrinter (agent_stderr);
- } else {
- printer = new ConsoleReportPrinter ();
- }
- var eval = new Evaluator (new CompilerContext (settings, printer));
- eval.InteractiveBaseClass = typeof (InteractiveBaseShell);
- eval.DescribeTypeExpressions = true;
- eval.WaitOnTask = true;
- CSharpShell shell;
- #if !ON_DOTNET
- if (attach.HasValue) {
- shell = new ClientCSharpShell_v1 (eval, attach.Value);
- } else if (agent != null) {
- new CSharpAgent (eval, agent, agent_stderr).Run (startup_files);
- return 0;
- } else
- #endif
- if (target_host != null)
- shell = new ClientCSharpShell (eval, target_host, target_port);
- else
- shell = new CSharpShell (eval);
- return shell.Run (startup_files);
- }
- static bool SplitDriverAndScriptArguments (ref string [] driver_args, out string [] script_args)
- {
- // split command line arguments into two groups:
- // - anything before '--' or '-s' goes to the mcs driver, which may
- // call back into the csharp driver for further processing
- // - anything after '--' or '-s' is made available to the REPL/script
- // via the 'Args' global, similar to csi.
- // - if '-s' is used, the argument immediately following it will
- // also be processed by the mcs driver (e.g. a source file)
- int driver_args_count = 0;
- int script_args_offset = 0;
- string script_file = null;
- while (driver_args_count < driver_args.Length && script_args_offset == 0) {
- switch (driver_args [driver_args_count]) {
- case "--":
- script_args_offset = driver_args_count + 1;
- break;
- case "-s":
- if (driver_args_count + 1 >= driver_args.Length) {
- script_args = null;
- Console.Error.WriteLine ("usage is: -s SCRIPT_FILE");
- return false;
- }
- driver_args_count++;
- script_file = driver_args [driver_args_count];
- script_args_offset = driver_args_count + 1;
- break;
- default:
- driver_args_count++;
- break;
- }
- }
- if (script_args_offset > 0) {
- int script_args_count = driver_args.Length - script_args_offset;
- script_args = new string [script_args_count];
- Array.Copy (driver_args, script_args_offset, script_args, 0, script_args_count);
- } else
- script_args = Array.Empty<string> ();
- Array.Resize (ref driver_args, driver_args_count);
- if (script_file != null)
- driver_args [driver_args_count - 1] = script_file;
- return true;
- }
- static int HandleExtraArguments (string [] args, int pos)
- {
- switch (args [pos]) {
- case "-e":
- if (pos + 1 < args.Length) {
- StartupEvalExpression = args[pos + 1];
- return pos + 1;
- }
- break;
- case "--attach":
- if (pos + 1 < args.Length) {
- attach = Int32.Parse (args[1]);
- return pos + 1;
- }
- break;
- default:
- if (args [pos].StartsWith ("--server=")){
- var hostport = args [pos].Substring (9);
- int p = hostport.IndexOf (':');
- if (p == -1){
- target_host = hostport;
- target_port = 10000;
- } else {
- target_host = hostport.Substring (0,p);
- if (!int.TryParse (hostport.Substring (p), out target_port)){
- Console.Error.WriteLine ("Usage is: --server[=host[:port]");
- Environment.Exit (1);
- }
- }
- return pos + 1;
- }
- if (args [pos].StartsWith ("--client")){
- target_host = "localhost";
- target_port = 10000;
- return pos + 1;
- }
- if (args [pos].StartsWith ("--agent:")) {
- agent = args[pos];
- return pos + 1;
- } else {
- return -1;
- }
- }
- return -1;
- }
-
- }
- public class InteractiveBaseShell : InteractiveBase {
- static bool tab_at_start_completes;
-
- static InteractiveBaseShell ()
- {
- tab_at_start_completes = false;
- }
- internal static Mono.Terminal.LineEditor Editor;
-
- public static bool TabAtStartCompletes {
- get {
- return tab_at_start_completes;
- }
- set {
- tab_at_start_completes = value;
- if (Editor != null)
- Editor.TabAtStartCompletes = value;
- }
- }
- public static new string help {
- get {
- return InteractiveBase.help +
- " TabAtStartCompletes - Whether tab will complete even on empty lines\n" +
- " Args - Any command line arguments passed to csharp\n" +
- " after the '--' (stop processing) argument";
- }
- }
- public static string [] Args => Driver.ScriptArgs;
- }
-
- public class CSharpShell {
- static bool isatty = true, is_unix = false;
- protected string [] startup_files;
-
- Mono.Terminal.LineEditor editor;
- bool dumb;
- readonly Evaluator evaluator;
- public CSharpShell (Evaluator evaluator)
- {
- this.evaluator = evaluator;
- }
- protected virtual void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
- {
- // Do not about our program
- a.Cancel = true;
- evaluator.Interrupt ();
- }
-
- void SetupConsole ()
- {
- if (is_unix){
- string term = Environment.GetEnvironmentVariable ("TERM");
- dumb = term == "dumb" || term == null || isatty == false;
- } else
- dumb = false;
-
- editor = new Mono.Terminal.LineEditor ("csharp", 300) {
- HeuristicsMode = "csharp"
- };
- InteractiveBaseShell.Editor = editor;
- editor.AutoCompleteEvent += delegate (string s, int pos){
- string prefix = null;
- string complete = s.Substring (0, pos);
-
- string [] completions = evaluator.GetCompletions (complete, out prefix);
-
- return new Mono.Terminal.LineEditor.Completion (prefix, completions);
- };
-
- #if false
- //
- // This is a sample of how completions sould be implemented.
- //
- editor.AutoCompleteEvent += delegate (string s, int pos){
- // Single match: "Substring": Sub-string
- if (s.EndsWith ("Sub")){
- return new string [] { "string" };
- }
- // Multiple matches: "ToString" and "ToLower"
- if (s.EndsWith ("T")){
- return new string [] { "ToString", "ToLower" };
- }
- return null;
- };
- #endif
-
- Console.CancelKeyPress += ConsoleInterrupt;
- }
- string GetLine (bool primary)
- {
- string prompt = primary ? InteractiveBase.Prompt : InteractiveBase.ContinuationPrompt;
- if (dumb){
- if (isatty)
- Console.Write (prompt);
- return Console.ReadLine ();
- } else {
- return editor.Edit (prompt, "");
- }
- }
- delegate string ReadLiner (bool primary);
- void InitializeUsing ()
- {
- Evaluate ("using System; using System.Linq; using System.Collections.Generic; using System.Collections;");
- }
- void InitTerminal (bool show_banner)
- {
- int p = (int) Environment.OSVersion.Platform;
- is_unix = (p == 4) || (p == 128);
- isatty = !Console.IsInputRedirected && !Console.IsOutputRedirected;
- // Work around, since Console is not accounting for
- // cursor position when writing to Stderr. It also
- // has the undesirable side effect of making
- // errors plain, with no coloring.
- // Report.Stderr = Console.Out;
- SetupConsole ();
- if (isatty && show_banner)
- Console.WriteLine ("Mono C# Shell, type \"help;\" for help\n\nEnter statements below.");
- }
- void ExecuteSources (IEnumerable<string> sources, bool ignore_errors)
- {
- foreach (string file in sources){
- try {
- try {
- bool first = true;
-
- using (System.IO.StreamReader r = System.IO.File.OpenText (file)){
- ReadEvalPrintLoopWith (p => {
- var line = r.ReadLine ();
- if (first){
- if (line.StartsWith ("#!"))
- line = r.ReadLine ();
- first = false;
- }
- return line;
- });
- }
- } catch (FileNotFoundException){
- Console.Error.WriteLine ("cs2001: Source file `{0}' not found", file);
- return;
- }
- } catch {
- if (!ignore_errors)
- throw;
- }
- }
- }
-
- protected virtual void LoadStartupFiles ()
- {
- string dir = Path.Combine (
- Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
- "csharp");
- if (!Directory.Exists (dir))
- return;
- List<string> sources = new List<string> ();
- List<string> libraries = new List<string> ();
-
- foreach (string file in System.IO.Directory.GetFiles (dir)){
- string l = file.ToLower ();
-
- if (l.EndsWith (".cs"))
- sources.Add (file);
- else if (l.EndsWith (".dll"))
- libraries.Add (file);
- }
- foreach (string file in libraries)
- evaluator.LoadAssembly (file);
- ExecuteSources (sources, true);
- }
- void ReadEvalPrintLoopWith (ReadLiner readline)
- {
- string expr = null;
- while (!InteractiveBase.QuitRequested){
- string input = readline (expr == null);
- if (input == null)
- return;
- if (input == "")
- continue;
- expr = expr == null ? input : expr + "\n" + input;
-
- expr = Evaluate (expr);
- }
- }
- public int ReadEvalPrintLoop ()
- {
- if (startup_files != null && startup_files.Length == 0)
- InitTerminal (startup_files.Length == 0 && Driver.StartupEvalExpression == null);
- InitializeUsing ();
- LoadStartupFiles ();
- if (startup_files != null && startup_files.Length != 0) {
- ExecuteSources (startup_files, false);
- } else {
- if (Driver.StartupEvalExpression != null){
- ReadEvalPrintLoopWith (p => {
- var ret = Driver.StartupEvalExpression;
- Driver.StartupEvalExpression = null;
- return ret;
- });
- } else {
- ReadEvalPrintLoopWith (GetLine);
- }
-
- editor.SaveHistory ();
- }
- Console.CancelKeyPress -= ConsoleInterrupt;
-
- return 0;
- }
- protected virtual string Evaluate (string input)
- {
- bool result_set;
- object result;
- try {
- input = evaluator.Evaluate (input, out result, out result_set);
- if (result_set){
- PrettyPrint (Console.Out, result);
- Console.WriteLine ();
- }
- } catch (Exception e){
- Console.WriteLine (e);
- return null;
- }
-
- return input;
- }
- static void p (TextWriter output, string s)
- {
- output.Write (s);
- }
- static void EscapeString (TextWriter output, string s)
- {
- foreach (var c in s){
- if (c >= 32){
- output.Write (c);
- continue;
- }
- switch (c){
- case '\"':
- output.Write ("\\\""); break;
- case '\a':
- output.Write ("\\a"); break;
- case '\b':
- output.Write ("\\b"); break;
- case '\n':
- output.Write ("\n");
- break;
-
- case '\v':
- output.Write ("\\v");
- break;
-
- case '\r':
- output.Write ("\\r");
- break;
-
- case '\f':
- output.Write ("\\f");
- break;
-
- case '\t':
- output.Write ("\\t");
- break;
- default:
- output.Write ("\\x{0:x}", (int) c);
- break;
- }
- }
- }
-
- static void EscapeChar (TextWriter output, char c)
- {
- if (c == '\''){
- output.Write ("'\\''");
- return;
- }
- if (c >= 32){
- output.Write ("'{0}'", c);
- return;
- }
- switch (c){
- case '\a':
- output.Write ("'\\a'");
- break;
- case '\b':
- output.Write ("'\\b'");
- break;
-
- case '\n':
- output.Write ("'\\n'");
- break;
-
- case '\v':
- output.Write ("'\\v'");
- break;
-
- case '\r':
- output.Write ("'\\r'");
- break;
-
- case '\f':
- output.Write ("'\\f'");
- break;
-
- case '\t':
- output.Write ("'\\t");
- break;
- default:
- output.Write ("'\\x{0:x}'", (int) c);
- break;
- }
- }
- // Some types (System.Json.JsonPrimitive) implement
- // IEnumerator and yet, throw an exception when we
- // try to use them, helper function to check for that
- // condition
- static internal bool WorksAsEnumerable (object obj)
- {
- IEnumerable enumerable = obj as IEnumerable;
- if (enumerable != null){
- try {
- enumerable.GetEnumerator ();
- return true;
- } catch {
- // nothing, we return false below
- }
- }
- return false;
- }
-
- internal static void PrettyPrint (TextWriter output, object result)
- {
- if (result == null){
- p (output, "null");
- return;
- }
-
- if (result is Array){
- Array a = (Array) result;
-
- p (output, "{ ");
- int top = a.GetUpperBound (0);
- for (int i = a.GetLowerBound (0); i <= top; i++){
- PrettyPrint (output, a.GetValue (i));
- if (i != top)
- p (output, ", ");
- }
- p (output, " }");
- } else if (result is bool){
- if ((bool) result)
- p (output, "true");
- else
- p (output, "false");
- } else if (result is string){
- p (output, "\"");
- EscapeString (output, (string)result);
- p (output, "\"");
- } else if (result is IDictionary){
- IDictionary dict = (IDictionary) result;
- int top = dict.Count, count = 0;
-
- p (output, "{");
- foreach (DictionaryEntry entry in dict){
- count++;
- p (output, "{ ");
- PrettyPrint (output, entry.Key);
- p (output, ", ");
- PrettyPrint (output, entry.Value);
- if (count != top)
- p (output, " }, ");
- else
- p (output, " }");
- }
- p (output, "}");
- } else if (WorksAsEnumerable (result)) {
- int i = 0;
- p (output, "{ ");
- foreach (object item in (IEnumerable) result) {
- if (i++ != 0)
- p (output, ", ");
- PrettyPrint (output, item);
- }
- p (output, " }");
- } else if (result is char) {
- EscapeChar (output, (char) result);
- } else {
- p (output, result.ToString ());
- }
- }
- public virtual int Run (string [] startup_files)
- {
- this.startup_files = startup_files;
- return ReadEvalPrintLoop ();
- }
-
- }
- //
- // Stream helper extension methods
- //
- public static class StreamHelper {
- static DataConverter converter = DataConverter.LittleEndian;
-
- static void GetBuffer (this Stream stream, byte [] b)
- {
- int n, offset = 0;
- int len = b.Length;
- do {
- n = stream.Read (b, offset, len);
- if (n == 0)
- throw new IOException ("End reached");
- offset += n;
- len -= n;
- } while (len > 0);
- }
- public static int GetInt (this Stream stream)
- {
- byte [] b = new byte [4];
- stream.GetBuffer (b);
- return converter.GetInt32 (b, 0);
- }
- public static string GetString (this Stream stream)
- {
- int len = stream.GetInt ();
- if (len == 0)
- return "";
- byte [] b = new byte [len];
- stream.GetBuffer (b);
- return Encoding.UTF8.GetString (b);
- }
- public static void WriteInt (this Stream stream, int n)
- {
- byte [] bytes = converter.GetBytes (n);
- stream.Write (bytes, 0, bytes.Length);
- }
-
- public static void WriteString (this Stream stream, string s)
- {
- stream.WriteInt (s.Length);
- byte [] bytes = Encoding.UTF8.GetBytes (s);
- stream.Write (bytes, 0, bytes.Length);
- }
- }
-
- public enum AgentStatus : byte {
- // Received partial input, complete
- PARTIAL_INPUT = 1,
-
- // The result was set, expect the string with the result
- RESULT_SET = 2,
-
- // No result was set, complete
- RESULT_NOT_SET = 3,
-
- // Errors and warnings string follows
- ERROR = 4,
- // Stdout
- STDOUT = 5,
- }
- class ClientCSharpShell : CSharpShell {
- string target_host;
- int target_port;
-
- public ClientCSharpShell (Evaluator evaluator, string target_host, int target_port) : base (evaluator)
- {
- this.target_port = target_port;
- this.target_host = target_host;
- }
- T ConnectServer<T> (Func<NetworkStream,T> callback, Action<Exception> error)
- {
- try {
- var client = new TcpClient (target_host, target_port);
- var ns = client.GetStream ();
- T ret = callback (ns);
- ns.Flush ();
- ns.Close ();
- client.Close ();
- return ret;
- } catch (Exception e){
- error (e);
- return default(T);
- }
- }
-
- protected override string Evaluate (string input)
- {
- return ConnectServer<string> ((ns)=> {
- try {
- ns.WriteString ("EVALTXT");
- ns.WriteString (input);
- while (true) {
- AgentStatus s = (AgentStatus) ns.ReadByte ();
-
- switch (s){
- case AgentStatus.PARTIAL_INPUT:
- return input;
-
- case AgentStatus.ERROR:
- string err = ns.GetString ();
- Console.Error.WriteLine (err);
- break;
- case AgentStatus.STDOUT:
- string stdout = ns.GetString ();
- Console.WriteLine (stdout);
- break;
-
- case AgentStatus.RESULT_NOT_SET:
- return null;
-
- case AgentStatus.RESULT_SET:
- string res = ns.GetString ();
- Console.WriteLine (res);
- return null;
- }
- }
- } catch (Exception e){
- Console.Error.WriteLine ("Error evaluating expression, exception: {0}", e);
- }
- return null;
- }, (e) => {
- Console.Error.WriteLine ("Error communicating with server {0}", e);
- });
- }
-
- public override int Run (string [] startup_files)
- {
- // The difference is that we do not call Evaluator.Init, that is done on the target
- this.startup_files = startup_files;
- return ReadEvalPrintLoop ();
- }
-
- protected override void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
- {
- ConnectServer<int> ((ns)=> {
- ns.WriteString ("INTERRUPT");
- return 0;
- }, (e) => { });
- }
-
- }
- #if !ON_DOTNET
- //
- // A shell connected to a CSharpAgent running in a remote process.
- // - maybe add 'class_name' and 'method_name' arguments to LoadAgent.
- // - Support Gtk and Winforms main loops if detected, this should
- // probably be done as a separate agent in a separate place.
- //
- class ClientCSharpShell_v1 : CSharpShell {
- NetworkStream ns, interrupt_stream;
-
- public ClientCSharpShell_v1 (Evaluator evaluator, int pid)
- : base (evaluator)
- {
- // Create a server socket we listen on whose address is passed to the agent
- TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
- listener.Start ();
- TcpListener interrupt_listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
- interrupt_listener.Start ();
-
- string agent_assembly = typeof (ClientCSharpShell).Assembly.Location;
- string agent_arg = String.Format ("--agent:{0}:{1}" ,
- ((IPEndPoint)listener.Server.LocalEndPoint).Port,
- ((IPEndPoint)interrupt_listener.Server.LocalEndPoint).Port);
-
- var vm = new Attach.VirtualMachine (pid);
- vm.Attach (agent_assembly, agent_arg);
-
- /* Wait for the client to connect */
- TcpClient client = listener.AcceptTcpClient ();
- ns = client.GetStream ();
- TcpClient interrupt_client = interrupt_listener.AcceptTcpClient ();
- interrupt_stream = interrupt_client.GetStream ();
-
- Console.WriteLine ("Connected.");
- }
- //
- // A remote version of Evaluate
- //
- protected override string Evaluate (string input)
- {
- ns.WriteString (input);
- while (true) {
- AgentStatus s = (AgentStatus) ns.ReadByte ();
-
- switch (s){
- case AgentStatus.PARTIAL_INPUT:
- return input;
-
- case AgentStatus.ERROR:
- string err = ns.GetString ();
- Console.Error.WriteLine (err);
- break;
-
- case AgentStatus.RESULT_NOT_SET:
- return null;
-
- case AgentStatus.RESULT_SET:
- string res = ns.GetString ();
- Console.WriteLine (res);
- return null;
- }
- }
- }
-
- public override int Run (string [] startup_files)
- {
- // The difference is that we do not call Evaluator.Init, that is done on the target
- this.startup_files = startup_files;
- return ReadEvalPrintLoop ();
- }
-
- protected override void ConsoleInterrupt (object sender, ConsoleCancelEventArgs a)
- {
- // Do not about our program
- a.Cancel = true;
-
- interrupt_stream.WriteByte (0);
- int c = interrupt_stream.ReadByte ();
- if (c != -1)
- Console.WriteLine ("Execution interrupted");
- }
-
- }
- //
- // This is the agent loaded into the target process when using --attach.
- //
- class CSharpAgent
- {
- NetworkStream interrupt_stream;
- readonly Evaluator evaluator;
- TextWriter stderr;
-
- public CSharpAgent (Evaluator evaluator, String arg, TextWriter stderr)
- {
- this.evaluator = evaluator;
- this.stderr = stderr;
- new Thread (new ParameterizedThreadStart (Run)).Start (arg);
- }
- public void InterruptListener ()
- {
- while (true){
- int b = interrupt_stream.ReadByte();
- if (b == -1)
- return;
- evaluator.Interrupt ();
- interrupt_stream.WriteByte (0);
- }
- }
-
- public void Run (object o)
- {
- string arg = (string)o;
- string ports = arg.Substring (8);
- int sp = ports.IndexOf (':');
- int port = Int32.Parse (ports.Substring (0, sp));
- int interrupt_port = Int32.Parse (ports.Substring (sp+1));
-
- Console.WriteLine ("csharp-agent: started, connecting to localhost:" + port);
-
- TcpClient client = new TcpClient ("127.0.0.1", port);
- TcpClient interrupt_client = new TcpClient ("127.0.0.1", interrupt_port);
- Console.WriteLine ("csharp-agent: connected.");
-
- NetworkStream s = client.GetStream ();
- interrupt_stream = interrupt_client.GetStream ();
- new Thread (InterruptListener).Start ();
- try {
- // Add all assemblies loaded later
- AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
-
- // Add all currently loaded assemblies
- foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies ()) {
- // Some assemblies seem to be already loaded, and loading them again causes 'defined multiple times' errors
- if (a.GetName ().Name != "mscorlib" && a.GetName ().Name != "System.Core" && a.GetName ().Name != "System")
- evaluator.ReferenceAssembly (a);
- }
-
- RunRepl (s);
- } finally {
- AppDomain.CurrentDomain.AssemblyLoad -= AssemblyLoaded;
- client.Close ();
- interrupt_client.Close ();
- Console.WriteLine ("csharp-agent: disconnected.");
- }
- }
-
- void AssemblyLoaded (object sender, AssemblyLoadEventArgs e)
- {
- evaluator.ReferenceAssembly (e.LoadedAssembly);
- }
-
- public void RunRepl (NetworkStream s)
- {
- string input = null;
- while (!InteractiveBase.QuitRequested) {
- try {
- string error_string;
- StringWriter error_output = (StringWriter)stderr;
- string line = s.GetString ();
-
- bool result_set;
- object result;
-
- if (input == null)
- input = line;
- else
- input = input + "\n" + line;
-
- try {
- input = evaluator.Evaluate (input, out result, out result_set);
- } catch (Exception e) {
- s.WriteByte ((byte) AgentStatus.ERROR);
- s.WriteString (e.ToString ());
- s.WriteByte ((byte) AgentStatus.RESULT_NOT_SET);
- continue;
- }
-
- if (input != null){
- s.WriteByte ((byte) AgentStatus.PARTIAL_INPUT);
- continue;
- }
-
- // Send warnings and errors back
- error_string = error_output.ToString ();
- if (error_string.Length != 0){
- s.WriteByte ((byte) AgentStatus.ERROR);
- s.WriteString (error_output.ToString ());
- error_output.GetStringBuilder ().Clear ();
- }
-
- if (result_set){
- s.WriteByte ((byte) AgentStatus.RESULT_SET);
- StringWriter sr = new StringWriter ();
- CSharpShell.PrettyPrint (sr, result);
- s.WriteString (sr.ToString ());
- } else {
- s.WriteByte ((byte) AgentStatus.RESULT_NOT_SET);
- }
- } catch (IOException) {
- break;
- } catch (Exception e){
- Console.WriteLine (e);
- }
- }
- }
- }
- public class UnixUtils {
- [System.Runtime.InteropServices.DllImport ("libc", EntryPoint="isatty")]
- extern static int _isatty (int fd);
-
- public static bool isatty (int fd)
- {
- try {
- return _isatty (fd) == 1;
- } catch {
- return false;
- }
- }
- }
- #endif
- }
-
- namespace Mono.Management
- {
- interface IVirtualMachine {
- void LoadAgent (string filename, string args);
- }
- }
|