delete: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/library/socket/tcpserver/new_tags.txt;C1473028 File: new_tags.txt =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/library/socket/tcpserver/new_tags.txt;C1473028 (server) 2/22/2010 10:39 AM +++ [no target file] @@ -1,4 +1,0 @@ -fails:TCPServer.new binds to a host and a port -fails:TCPServer.new binds to localhost and a port with either IPv4 or IPv6 -fails:TCPServer.new binds to INADDR_ANY if the hostname is empty -fails:TCPServer.new raises Errno::EADDRINUSE when address is already in use =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/library/socket/tcpsocket/new_tags.txt;C1473028 File: new_tags.txt =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/library/socket/tcpsocket/new_tags.txt;C1473028 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/External.LCA_RESTRICTED/Languages/IronRuby/mspec/ironruby-tags/library/socket/tcpsocket/new_tags.txt;Buffer7 @@ -1,4 +1,3 @@ critical:TCPSocket.new has an address once it has connected to a listening server -fails:TCPSocket.new refuses the connection when there is no server to connect to fails:TCPSocket.new connects to a listening server fails:TCPSocket.new requires local_port to be 0 when local_host is not specified =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C1594871 File: RubyTests.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C1594871 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;Buffer7 @@ -161,8 +161,9 @@ Inspect1, Inspect2, File1, - File2, - File3, + File_AppendBytes1, + File_WriteBytes1, + File_ReadLine1, Dir1, Dir2, =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/IoTests.cs;C1429753 File: IoTests.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/IoTests.cs;C1429753 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/IoTests.cs;Buffer7 @@ -53,7 +53,7 @@ } [Options(NoRuntime = true)] - public void File2() { + public void File_AppendBytes1() { string s; string crlf = "\r\n"; var stream = new TestStream(false, B( @@ -64,7 +64,7 @@ int s_crlf_count = 6; var io = new RubyBufferedStream(stream); - Assert(io.PeekByte(0) == (byte)'a'); + Assert(io.PeekByte() == (byte)'a'); var buffer = MutableString.CreateBinary(B("foo:")); Assert(io.AppendBytes(buffer, 4, false) == 4); @@ -97,7 +97,7 @@ } [Options(NoRuntime = true)] - public void File3() { + public void File_WriteBytes1() { var stream = new MemoryStream(); var io = new RubyBufferedStream(stream); @@ -118,6 +118,44 @@ stream.Seek(0, SeekOrigin.Begin); } + [Options(NoRuntime = true)] + public void File_ReadLine1() { + var stream = new TestStream(false, B( + "a\r\n\r\nbbbbbbbbbbbbbbbbbbbbb1bbbbbbbbbbbbb2bbbbbbbbbbbbbbbbbbbbb3bbbbbbbbbbbbb4\rc\nd\n\n\n\nef") + ); + + foreach (int bufferSize in new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100 }) { + stream.Seek(0, SeekOrigin.Begin); + var io = new RubyBufferedStream(stream, false, bufferSize); + + TestReadLine(io, true, "a\r\n"); + TestReadLine(io, true, "\r\n"); + TestReadLine(io, true, "bbbbbbbbbbbbbbbbbbbbb1bbbbbbbbbbbbb2bbbbbbbbbbbbbbbbbbbbb3bbbbbbbbbbbbb4\rc\n"); + TestReadLine(io, true, "d\n"); + TestReadLine(io, true, "\n"); + TestReadLine(io, true, "\n"); + TestReadLine(io, true, "\n"); + TestReadLine(io, true, "ef"); + TestReadLine(io, true, null); + + stream.Seek(0, SeekOrigin.Begin); + TestReadLine(io, false, "a\n"); + TestReadLine(io, false, "\n"); + TestReadLine(io, false, "bbbbbbbbbbbbbbbbbbbbb1bbbbbbbbbbbbb2bbbbbbbbbbbbbbbbbbbbb3bbbbbbbbbbbbb4\rc\n"); + TestReadLine(io, false, "d\n"); + TestReadLine(io, false, "\n"); + TestReadLine(io, false, "\n"); + TestReadLine(io, false, "\n"); + TestReadLine(io, false, "ef"); + TestReadLine(io, false, null); + } + } + + private void TestReadLine(RubyBufferedStream/*!*/ io, bool preserveEolns, string expected) { + var s = io.ReadLine(RubyEncoding.Binary, preserveEolns); + Assert(s == null && expected == null || s.ToString() == expected); + } + public class Pal1 : PlatformAdaptationLayer { // case sensitive public readonly Dictionary Entries = new Dictionary(); =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RubyArrayTests.cs;C1040664 File: RubyArrayTests.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RubyArrayTests.cs;C1040664 (server) 2/22/2010 3:24 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/RubyArrayTests.cs;Buffer7 @@ -95,6 +95,22 @@ a = new RubyArray(a, 0, 2); Assert(a.Count == 2); Assert((int)a[0] == 1 && (int)a[1] == 2); + + // prepare array [nil, 1, 3, nil] + RubyArray b = new RubyArray(new[] { 1, 2, 3 }); + b.RemoveAt(1); + a = new RubyArray(b); + Assert(a.Count == 2); + Assert((int)a[0] == 1 && (int)a[1] == 3); + + a = new RubyArray(b, 2, 0); + Assert(a.Count == 0); + + a = new RubyArray(new[] { 1, 2, 3 }); + AssertExceptionThrown(() => new RubyArray(null, 1, 2)); + AssertExceptionThrown(() => new RubyArray(a, -1, 2)); + AssertExceptionThrown(() => new RubyArray(a, 3, 1)); + AssertExceptionThrown(() => new RubyArray(a, 0, 4)); } [Options(NoRuntime = true)] =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C1599184 File: Initializers.Generated.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;C1599184 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializers.Generated.cs;Buffer7 @@ -7736,7 +7736,7 @@ DefineLibraryMethod(module, "zone", 0x51, 0x00000000U, - new Func(IronRuby.Builtins.RubyTimeOps.GetZone) + new Func(IronRuby.Builtins.RubyTimeOps.GetZone) ); } @@ -8724,7 +8724,7 @@ #if !SILVERLIGHT private static void LoadTCPSocket_Instance(IronRuby.Builtins.RubyModule/*!*/ module) { DefineLibraryMethod(module, "initialize", 0x12, - 0x00040008U, 0x00140028U, + 0x00040000U, 0x00140000U, new Func, IronRuby.Runtime.ConversionStorage, IronRuby.StandardLibrary.Sockets.TCPServer, IronRuby.Builtins.MutableString, System.Object, System.Int32, IronRuby.StandardLibrary.Sockets.TCPServer>(IronRuby.StandardLibrary.Sockets.TCPSocket.Reinitialize), new Func, IronRuby.Runtime.ConversionStorage, IronRuby.StandardLibrary.Sockets.TCPServer, IronRuby.Builtins.MutableString, System.Object, IronRuby.Builtins.MutableString, System.Object, IronRuby.StandardLibrary.Sockets.TCPServer>(IronRuby.StandardLibrary.Sockets.TCPSocket.Reinitialize) ); =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;C1546541 File: IoOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;C1546541 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/IoOps.cs;Buffer7 @@ -860,7 +860,9 @@ public static MutableString Gets(RubyScope/*!*/ scope, RubyIO/*!*/ self, [DefaultProtocol]MutableString separator) { MutableString result = self.ReadLineOrParagraph(separator); - KernelOps.Taint(scope.RubyContext, result); + if (result != null) { + result.IsTainted = true; + } scope.GetInnerMostClosureScope().LastInputLine = result; scope.RubyContext.InputProvider.LastInputLineNumber = ++self.LineNumber; @@ -909,8 +911,7 @@ throw RubyExceptions.NoBlockGiven(); } - KernelOps.Taint(block.RubyContext, line); - + line.IsTainted = true; context.InputProvider.LastInputLineNumber = ++self.LineNumber; object result; =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;C1599184 File: KernelOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;C1599184 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs;Buffer7 @@ -436,7 +436,8 @@ public static RubyArray/*!*/ ToA(RubyContext/*!*/ context, object self) { RubyArray result = new RubyArray(); result.Add(self); - return context.TaintObjectBy(result, self); + result.IsTainted |= context.IsObjectTainted(self); + return result; } #endregion =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyTime.cs;C1599184 File: RubyTime.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyTime.cs;C1599184 (server) 2/22/2010 1:45 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RubyTime.cs;Buffer7 @@ -779,11 +779,17 @@ } [RubyMethod("zone")] - public static MutableString/*!*/ GetZone(RubyTime/*!*/ self) { + public static MutableString/*!*/ GetZone(RubyContext/*!*/ context, RubyTime/*!*/ self) { if (self.Kind == DateTimeKind.Utc) { return MutableString.CreateAscii("UTC"); } else { - return MutableString.Create(RubyTime.GetCurrentZoneName(), RubyEncoding.UTF8); + var name = RubyTime.GetCurrentZoneName(); + if (name.IsAscii()) { + return MutableString.CreateAscii(name); + } else { + // TODO: what encoding should we use? + return MutableString.Create(name, context.GetPathEncoding()); + } } } @@ -1070,7 +1076,7 @@ result.Add((int)self.DateTime.DayOfWeek); result.Add(self.DateTime.DayOfYear); result.Add(self.GetCurrentDst(context)); - result.Add(GetZone(self)); + result.Add(GetZone(context, self)); return result; } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/StringFormatter.cs;C1475657 File: StringFormatter.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/StringFormatter.cs;C1475657 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/StringFormatter.cs;Buffer7 @@ -171,7 +171,7 @@ MutableString result = MutableString.Create(_buf.ToString(), _encoding); if (_tainted) { - KernelOps.Taint(_context, result); + result.IsTainted = true; } return result; =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs;C1561136 File: IListOps.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs;C1561136 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IListOps.cs;Buffer7 @@ -233,8 +233,9 @@ } IList result = CreateResultArray(allocateStorage, self); - if (result is RubyArray) { - ((RubyArray)result).AddCapacity(self.Count * repeat); + RubyArray array = result as RubyArray; + if (array != null) { + array.AddCapacity(self.Count * repeat); } for (int i = 0; i < repeat; ++i) { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/BasicSocket.cs;C1290543 File: BasicSocket.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/BasicSocket.cs;C1290543 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/BasicSocket.cs;Buffer7 @@ -316,7 +316,7 @@ MutableString str = MutableString.CreateBinary(received); str.Append(buffer, 0, received); - fixnumCast.Context.SetObjectTaint(str, true); + str.IsTainted = true; return str; } @@ -360,22 +360,22 @@ } // TODO: handle other invalid addresses - internal static IPHostEntry/*!*/ GetHostEntry(IPAddress/*!*/ address) { + internal static IPHostEntry/*!*/ GetHostEntry(IPAddress/*!*/ address, bool doNotReverseLookup) { Assert.NotNull(address); if (address.Equals(IPAddress.Any) || address.Equals(IPAddress.Loopback)) { - return MakeEntry(address); + return MakeEntry(address, doNotReverseLookup); } else { return Dns.GetHostEntry(address); } } // TODO: handle other invalid addresses - internal static IPHostEntry/*!*/ GetHostEntry(string/*!*/ hostNameOrAddress) { + internal static IPHostEntry/*!*/ GetHostEntry(string/*!*/ hostNameOrAddress, bool doNotReverseLookup) { Assert.NotNull(hostNameOrAddress); if (hostNameOrAddress == IPAddress.Any.ToString()) { - return MakeEntry(IPAddress.Any); + return MakeEntry(IPAddress.Any, doNotReverseLookup); } else if (hostNameOrAddress == IPAddress.Loopback.ToString()) { - return MakeEntry(IPAddress.Loopback); + return MakeEntry(IPAddress.Loopback, doNotReverseLookup); } else { return Dns.GetHostEntry(hostNameOrAddress); } @@ -390,34 +390,44 @@ return Dns.GetHostAddresses(hostNameOrAddress)[0]; } - internal static IPHostEntry/*!*/ MakeEntry(IPAddress/*!*/ address) { + internal static IPHostEntry/*!*/ MakeEntry(IPAddress/*!*/ address, bool doNotReverseLookup) { + var str = IPAddressToHostName(address, doNotReverseLookup); return new IPHostEntry() { AddressList = new[] { address }, - Aliases = new[] { address.ToString() }, - HostName = address.ToString() + Aliases = new[] { str }, + HostName = str }; } - internal static RubyArray/*!*/ GetHostByName(string/*!*/ hostNameOrAddress, bool packIpAddresses) { - return CreateHostEntryArray(GetHostEntry(hostNameOrAddress), packIpAddresses); + internal static RubyArray/*!*/ GetHostByName(RubyContext/*!*/ context, string/*!*/ hostNameOrAddress, bool packIpAddresses) { + return CreateHostEntryArray(context, GetHostEntry(hostNameOrAddress, DoNotReverseLookup(context).Value), packIpAddresses); } internal static RubyArray/*!*/ GetAddressArray(RubyContext/*!*/ context, EndPoint endPoint) { RubyArray result = new RubyArray(4); IPEndPoint ep = (IPEndPoint)endPoint; - result.Add(MutableString.CreateAscii(AddressFamilyToString(ep.AddressFamily))); result.Add(ep.Port); - if (DoNotReverseLookup(context).Value) { - result.Add(MutableString.CreateAscii(ep.Address.ToString())); + result.Add(HostNameToMutableString(context, IPAddressToHostName(ep.Address, DoNotReverseLookup(context).Value))); + result.Add(MutableString.CreateAscii(ep.Address.ToString())); + return result; + } + + internal static MutableString/*!*/ HostNameToMutableString(RubyContext/*!*/ context, string/*!*/ str) { + if (str.IsAscii()) { + return MutableString.CreateAscii(str); } else { - // TODO: MRI returns localhost rather than the local machine name here - // TODO (encoding): - result.Add(MutableString.Create(Dns.GetHostEntry(ep.Address).HostName, RubyEncoding.UTF8)); + return MutableString.Create(str, context.GetPathEncoding()); + } + } + + internal static string/*!*/ IPAddressToHostName(IPAddress/*!*/ address, bool doNotReverseLookup) { + if (address.Equals(IPAddress.Any) || doNotReverseLookup) { + return address.ToString(); + } else { + return Dns.GetHostEntry(address).HostName; } - result.Add(MutableString.CreateAscii(ep.Address.ToString())); - return result; } private static string AddressFamilyToString(AddressFamily af) { @@ -614,33 +624,34 @@ return null; } - internal static RubyArray/*!*/ CreateHostEntryArray(IPHostEntry/*!*/ hostEntry, bool packIpAddresses) { + internal static RubyArray/*!*/ CreateHostEntryArray(RubyContext/*!*/ context, IPHostEntry/*!*/ hostEntry, bool packIpAddresses) { RubyArray result = new RubyArray(4); - // Canonical Hostname - // TODO (encoding): - result.Add(MutableString.Create(hostEntry.HostName, RubyEncoding.UTF8)); + + // host name: + result.Add(HostNameToMutableString(context, hostEntry.HostName)); - // Aliases + // aliases: RubyArray aliases = new RubyArray(hostEntry.Aliases.Length); foreach (string alias in hostEntry.Aliases) { - // TODO (encoding): - aliases.Add(MutableString.Create(alias, RubyEncoding.UTF8)); + aliases.Add(HostNameToMutableString(context, alias)); } result.Add(aliases); - // Address Type - result.Add((int)hostEntry.AddressList[0].AddressFamily); - - // IP Address + // address (the first IPv4): foreach (IPAddress address in hostEntry.AddressList) { - if (packIpAddresses) { - byte[] bytes = address.GetAddressBytes(); - MutableString str = MutableString.CreateBinary(); - str.Append(bytes, 0, bytes.Length); - result.Add(str); - } else { - result.Add(MutableString.CreateAscii(address.ToString())); + if (address.AddressFamily == AddressFamily.InterNetwork) { + result.Add((int)address.AddressFamily); + if (packIpAddresses) { + byte[] bytes = address.GetAddressBytes(); + MutableString str = MutableString.CreateBinary(); + str.Append(bytes, 0, bytes.Length); + result.Add(str); + } else { + result.Add(MutableString.CreateAscii(address.ToString())); + } + break; } + } return result; } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/IPSocket.cs;C1290543 File: IPSocket.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/IPSocket.cs;C1290543 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/IPSocket.cs;Buffer7 @@ -67,7 +67,7 @@ str.Append(buffer, 0, received); var context = conversionStorage.Context; - context.SetObjectTaint(str, true); + str.IsTainted = true; return RubyOps.MakeArray2(str, GetAddressArray(context, fromEP)); } #endregion =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/Socket.cs;C1438355 File: Socket.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/Socket.cs;C1438355 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/Socket.cs;Buffer7 @@ -59,9 +59,12 @@ [DefaultParameterValue(0)]object protocol, [DefaultParameterValue(null)]object flags) { - IPHostEntry entry = (hostNameOrAddress != null) ? - GetHostEntry(ConvertToHostString(stringCast, hostNameOrAddress)) : MakeEntry(IPAddress.Any); + RubyContext context = self.Context; + IPHostEntry entry = (hostNameOrAddress != null) ? + GetHostEntry(ConvertToHostString(stringCast, hostNameOrAddress), DoNotReverseLookup(context).Value) : + MakeEntry(IPAddress.Any, DoNotReverseLookup(context).Value); + int iPort = ConvertToPortNum(stringCast, fixnumCast, port); // TODO: ignore family, the only supported families are InterNetwork and InterNetworkV6 @@ -76,13 +79,7 @@ RubyArray result = new RubyArray(9); result.Add(ToAddressFamilyString(address.AddressFamily)); result.Add(iPort); - if (DoNotReverseLookup(self.Context).Value) { - result.Add(MutableString.CreateAscii(address.ToString())); - } else { - IPHostEntry alias = GetHostEntry(address); - // TODO (encoding): - result.Add(MutableString.Create(alias.HostName, RubyEncoding.UTF8)); - } + result.Add(HostNameToMutableString(context, IPAddressToHostName(address, DoNotReverseLookup(context).Value))); result.Add(MutableString.CreateAscii(address.ToString())); result.Add((int)address.AddressFamily); result.Add(socketType); @@ -101,37 +98,35 @@ // TODO: ignore family, the only supported families are InterNetwork and InterNetworkV6 ConvertToAddressFamily(stringCast, fixnumCast, type); - IPHostEntry entry = GetHostEntry(new IPAddress(address.ConvertToBytes())); + IPHostEntry entry = GetHostEntry(new IPAddress(address.ConvertToBytes()), DoNotReverseLookup(self.Context).Value); - return CreateHostEntryArray(entry, true); + return CreateHostEntryArray(self.Context, entry, true); } [RubyMethod("gethostbyname", RubyMethodAttributes.PublicSingleton)] public static RubyArray/*!*/ GetHostByName(RubyClass/*!*/ self, int address) { - return GetHostByName(ConvertToHostString(address), true); + return GetHostByName(self.Context, ConvertToHostString(address), true); } [RubyMethod("gethostbyname", RubyMethodAttributes.PublicSingleton)] public static RubyArray/*!*/ GetHostByName(RubyClass/*!*/ self, [NotNull]BigInteger/*!*/ address) { - return GetHostByName(ConvertToHostString(address), true); + return GetHostByName(self.Context, ConvertToHostString(address), true); } [RubyMethod("gethostbyname", RubyMethodAttributes.PublicSingleton)] public static RubyArray/*!*/ GetHostByName(RubyClass/*!*/ self, [DefaultProtocol]MutableString name) { - return GetHostByName(ConvertToHostString(name), true); + return GetHostByName(self.Context, ConvertToHostString(name), true); } [RubyMethod("gethostname", RubyMethodAttributes.PublicSingleton)] public static MutableString GetHostname(RubyClass/*!*/ self) { - // TODO (encoding): - return MutableString.Create(Dns.GetHostName(), RubyEncoding.UTF8); + return HostNameToMutableString(self.Context, Dns.GetHostName()); } private static readonly MutableString/*!*/ _DefaultProtocol = MutableString.CreateAscii("tcp").Freeze(); [RubyMethod("getservbyname", RubyMethodAttributes.PublicSingleton)] - public static int GetServiceByName(RubyClass/*!*/ self, - [DefaultProtocol, NotNull]MutableString/*!*/ name, + public static int GetServiceByName(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ name, [DefaultProtocol, Optional]MutableString protocol) { if (protocol == null) { @@ -169,6 +164,8 @@ throw RubyExceptions.CreateArgumentError("First parameter must be a 3 or 4 element array"); } + RubyContext context = self.Context; + // We only support AF_INET (IP V4) family AddressFamily addressFamily = ConvertToAddressFamily(stringCast, fixnumCast, hostInfo[0]); if (addressFamily != AddressFamily.InterNetwork) { @@ -183,11 +180,10 @@ // if it exists and is not null hostInfo[3] should have an IP address // in that case we use that rather than the host name. object hostName = (hostInfo.Count > 3 && hostInfo[3] != null) ? hostInfo[3] : hostInfo[2]; - IPHostEntry entry = GetHostEntry(ConvertToHostString(stringCast, hostName)); + IPHostEntry entry = GetHostEntry(ConvertToHostString(stringCast, hostName), false); RubyArray result = new RubyArray(2); - // TODO (encoding): - result.Add(MutableString.Create(entry.HostName, RubyEncoding.UTF8)); + result.Add(HostNameToMutableString(context, entry.HostName)); if (service != null) { result.Add(MutableString.Create(service.Name)); } else { @@ -201,12 +197,11 @@ [DefaultProtocol, NotNull]MutableString/*!*/ address, [Optional]object flags) { IPEndPoint ep = UnpackSockAddr(address); - IPHostEntry entry = GetHostEntry(ep.Address); + IPHostEntry entry = GetHostEntry(ep.Address, false); ServiceName service = SearchForService(ep.Port); RubyArray result = new RubyArray(2); - // TODO (encoding): - result.Add(MutableString.Create(entry.HostName, RubyEncoding.UTF8)); + result.Add(HostNameToMutableString(self.Context, entry.HostName)); if (service != null) { result.Add(MutableString.Create(service.Name)); } else { =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPServer.cs;C1290543 File: TCPServer.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPServer.cs;C1290543 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPServer.cs;Buffer7 @@ -96,6 +96,8 @@ IPAddress listeningInterface = null; if (hostname == null) { listeningInterface = new IPAddress(0); + } else if (hostname.IsEmpty) { + listeningInterface = IPAddress.Any; } else { string hostnameStr = hostname.ConvertToString(); if (hostnameStr == IPAddress.Any.ToString()) { @@ -122,8 +124,17 @@ } Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - socket.Bind(new IPEndPoint(listeningInterface, ConvertToPortNum(stringCast, fixnumCast, port))); - socket.Listen(10); + try { + socket.Bind(new IPEndPoint(listeningInterface, ConvertToPortNum(stringCast, fixnumCast, port))); + socket.Listen(10); + } catch (SocketException e) { + switch (e.SocketErrorCode) { + case SocketError.AddressAlreadyInUse: + throw new Errno.AddressInUseError(); + default: + throw; + } + } return socket; } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPSocket.cs;C1290543 File: TCPSocket.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPSocket.cs;C1290543 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/socket/TCPSocket.cs;Buffer7 @@ -38,7 +38,7 @@ [RubyConstructor] public static TCPSocket/*!*/ CreateTCPSocket(ConversionStorage/*!*/ stringCast, ConversionStorage/*!*/ fixnumCast, - RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ remoteHost, object remotePort, [Optional]int localPort) { + RubyClass/*!*/ self, [DefaultProtocol]MutableString remoteHost, object remotePort, [Optional]int localPort) { // Not sure what the semantics should be in this case but we make sure not to blow up. // Real-world code (Server.connect_to in memcache.rb in the memcache-client gem) does do "TCPSocket.new(host, port, 0)" @@ -52,8 +52,8 @@ [RubyConstructor] public static TCPSocket/*!*/ CreateTCPSocket(ConversionStorage/*!*/ stringCast, ConversionStorage/*!*/ fixnumCast, RubyClass/*!*/ self, - [DefaultProtocol, NotNull]MutableString/*!*/ remoteHost, object remotePort, - [DefaultProtocol, NotNull]MutableString/*!*/ localHost, object localPort) { + [DefaultProtocol]MutableString remoteHost, object remotePort, + [DefaultProtocol]MutableString localHost, object localPort) { return BindLocalEndPoint( CreateTCPSocket(stringCast, fixnumCast, self, remoteHost, remotePort, 0), @@ -65,7 +65,7 @@ // Reinitialization. Not called when a factory/non-default ctor is called. [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)] public static TCPServer/*!*/ Reinitialize(ConversionStorage/*!*/ stringCast, ConversionStorage/*!*/ fixnumCast, - TCPServer/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ remoteHost, object remotePort, [Optional]int localPort) { + TCPServer/*!*/ self, [DefaultProtocol]MutableString remoteHost, object remotePort, [Optional]int localPort) { // Not sure what the semantics should be in this case but we make sure not to blow up. // Real-world code (Server.connect_to in memcache.rb in the memcache-client gem) does do "TCPSocket.new(host, port, 0)" @@ -81,22 +81,35 @@ [RubyMethod("initialize", RubyMethodAttributes.PrivateInstance)] public static TCPServer/*!*/ Reinitialize(ConversionStorage/*!*/ stringCast, ConversionStorage/*!*/ fixnumCast, TCPServer/*!*/ self, - [DefaultProtocol, NotNull]MutableString/*!*/ remoteHost, object remotePort, - [DefaultProtocol, NotNull]MutableString/*!*/ localHost, object localPort) { + [DefaultProtocol]MutableString remoteHost, object remotePort, + [DefaultProtocol]MutableString localHost, object localPort) { self.Socket = CreateSocket(remoteHost, ConvertToPortNum(stringCast, fixnumCast, remotePort)); BindLocalEndPoint(self, localHost, ConvertToPortNum(stringCast, fixnumCast, localPort)); return self; } - private static Socket/*!*/ CreateSocket(MutableString/*!*/ remoteHost, int port) { + private static Socket/*!*/ CreateSocket(MutableString remoteHost, int port) { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - socket.Connect(remoteHost.ConvertToString(), port); + try { + if (remoteHost != null) { + socket.Connect(remoteHost.ConvertToString(), port); + } else { + socket.Connect(IPAddress.Loopback, port); + } + } catch (SocketException e) { + switch (e.SocketErrorCode) { + case SocketError.ConnectionRefused: + throw new Errno.ConnectionRefusedError(); + default: + throw; + } + } return socket; } - private static TCPSocket/*!*/ BindLocalEndPoint(TCPSocket/*!*/ socket, MutableString/*!*/ localHost, int localPort) { - IPAddress localIPAddress = GetHostAddress(localHost.ConvertToString()); + private static TCPSocket/*!*/ BindLocalEndPoint(TCPSocket/*!*/ socket, MutableString localHost, int localPort) { + IPAddress localIPAddress = localHost != null ? GetHostAddress(localHost.ConvertToString()) : IPAddress.Loopback; IPEndPoint localEndPoint = new IPEndPoint(localIPAddress, localPort); socket.Socket.Bind(localEndPoint); return socket; @@ -104,7 +117,7 @@ [RubyMethod("gethostbyname", RubyMethodAttributes.PublicSingleton)] public static RubyArray/*!*/ GetHostByName(ConversionStorage/*!*/ stringCast, RubyClass/*!*/ self, object hostNameOrAddress) { - return GetHostByName(ConvertToHostString(stringCast, hostNameOrAddress), false); + return GetHostByName(self.Context, ConvertToHostString(stringCast, hostNameOrAddress), false); } } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C1586787 File: MutableString.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C1586787 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;Buffer7 @@ -111,7 +111,8 @@ } // binary (doesn't make a copy of the array): - private MutableString(byte[]/*!*/ bytes, int count, RubyEncoding/*!*/ encoding) + // used by RubyBufferedStream: + internal MutableString(byte[]/*!*/ bytes, int count, RubyEncoding/*!*/ encoding) : this(new BinaryContent(bytes, count, null), encoding) { } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyArray.cs;C1496258 File: RubyArray.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyArray.cs;C1496258 (server) 2/22/2010 3:24 PM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyArray.cs;Buffer7 @@ -81,7 +81,10 @@ public RubyArray(RubyArray/*!*/ items, int start, int count) : this(count) { - AddVector(items._content, start, count); + ContractUtils.RequiresNotNull(items, "items"); + ContractUtils.RequiresArrayRange(items.Count, start, count, "start", "count"); + + AddVector(items._content, items._start + start, count); } public RubyArray(IList/*!*/ items) =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyBufferedStream.cs;C1429753 File: RubyBufferedStream.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyBufferedStream.cs;C1429753 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyBufferedStream.cs;Buffer7 @@ -18,21 +18,50 @@ using System.IO; using IronRuby.Runtime; using Microsoft.Scripting.Utils; +using System.Collections.Generic; namespace IronRuby.Builtins { + /// + /// Not thread-safe. + /// public class RubyBufferedStream : Stream { - private const int MaxBufferSize = sizeof(uint); private readonly Stream/*!*/ _stream; - // Read buffer: if bufferSize > 0 then the next byte to read is the first (lowest) byte in the buffer: - private uint _buffer; - private int _bufferSize; + // read buffer [...xxxxxxx...] + // ^ ^ + // read pos stream pos + private byte[] _buffer; + private int _defaultBufferSize; + // the position of the first buffered byte in buffer + private int _bufferStart; + + // the number of buffered bytes + private int _bufferCount; + + // the number of bytes pushed back by ungetc: + private int _pushedBackCount; + + private bool _pushBackPreservesPosition; + private const byte CR = (byte)'\r'; private const byte LF = (byte)'\n'; - public RubyBufferedStream(Stream/*!*/ stream) { + public RubyBufferedStream(Stream/*!*/ stream) + : this(stream, false) { + } + + public RubyBufferedStream(Stream/*!*/ stream, bool pushBackPreservesPosition) + : this(stream, pushBackPreservesPosition, 0x1000) { + } + + public RubyBufferedStream(Stream/*!*/ stream, bool pushBackPreservesPosition, int bufferSize) { + ContractUtils.RequiresNotNull(stream, "stream"); + ContractUtils.Requires(bufferSize > 0, "bufferSize", "Buffer size must be positive."); + _stream = stream; + _defaultBufferSize = bufferSize; + _pushBackPreservesPosition = pushBackPreservesPosition; } public Stream/*!*/ BaseStream { @@ -40,35 +69,52 @@ } public bool DataBuffered { - get { return _bufferSize > 0; } + get { return _bufferCount > 0; } } - private byte PeekBufferByte(int i) { - Debug.Assert(i < _bufferSize); - return (byte)((_buffer >> (i * 8)) & 0xff); + private int LoadBuffer(int count) { + Debug.Assert(_bufferCount + count <= (_buffer != null ? _buffer.Length : _defaultBufferSize)); + + int bytesRead; + if (_buffer == null) { + Debug.Assert(_bufferCount == 0 && _bufferStart == 0); + _buffer = new byte[_defaultBufferSize]; + } else if (_bufferStart + _bufferCount + count > _buffer.Length) { + // shift left: + Buffer.BlockCopy(_buffer, _bufferStart, _buffer, 0, _bufferCount); + _bufferStart = 0; + } + + bytesRead = _stream.Read(_buffer, _bufferCount, count); + _bufferCount += bytesRead; + return bytesRead; } - private void LoadBufferByte(byte b) { - Debug.Assert(_bufferSize < MaxBufferSize); - _buffer |= (uint)b << (_bufferSize * 8); - _bufferSize++; + private void ConsumeBuffered(int count) { + _bufferCount -= count; + _pushedBackCount -= Math.Min(_pushedBackCount, count); + if (_bufferCount == 0) { + _bufferStart = 0; + } else { + _bufferStart += count; + } } - - private byte ReadBufferByte() { - Debug.Assert(_bufferSize > 0); - byte result = (byte)(_buffer & 0xff); - _buffer >>= 8; - _bufferSize--; - return result; + + private int ReadAheadCount { + get { return _bufferCount - _pushedBackCount; } } public void PushBack(byte b) { - if (_bufferSize == MaxBufferSize) { - throw RubyExceptions.CreateIOError("ungetc failed: not enough space in buffer"); + if (_bufferStart > 0) { + _buffer[--_bufferStart] = b; + } else if (_buffer != null) { + Utils.InsertAt(ref _buffer, _bufferCount, 0, b, 1); + } else { + _buffer = new byte[_defaultBufferSize]; + _buffer[0] = b; } - - _buffer = (_buffer << 8) | b; - _bufferSize++; + _pushedBackCount++; + _bufferCount++; } public override long Position { @@ -76,23 +122,51 @@ // TODO: this seems to be bug in MRI: you can read(0); ungetc(x); at the beginning of a stream, yet // you can't do ungetc(x) at the beginning of the stream. // (see http://redmine.ruby-lang.org/issues/show/1909) - return Math.Max(_stream.Position - _bufferSize, 0); + if (_pushBackPreservesPosition) { + return _stream.Position - ReadAheadCount; + } else { + return Math.Max(_stream.Position - _bufferCount, 0); + } } set { - // seek clears any buffer content (including ungetc): - FlushRead(); - _stream.Position = value; + ContractUtils.Requires(value >= 0, "value", "Value must be positive"); + Seek(value, SeekOrigin.Begin); } } + public override void Close() { + _buffer = null; + _bufferCount = _bufferCount = _pushedBackCount = 0; + _stream.Close(); + } + public override long Seek(long pos, SeekOrigin origin) { - FlushRead(); - return _stream.Seek(pos, origin); + if (origin == SeekOrigin.Current) { + if (_pushBackPreservesPosition) { + pos -= ReadAheadCount; + } else { + origin = SeekOrigin.Begin; + pos += Position; + } + } + + // try seek first, it may fail and we shouldn't change the buffer if so: + var result = _stream.Seek(pos, origin); + + // TODO: we might keep the buffered data if we seek within the buffered data (but not in pushed back data): + // clear any buffer content (including ungetc): + _bufferStart = _bufferCount = _pushedBackCount = 0; + + return result; } private void FlushRead() { - _buffer = 0; - _bufferSize = 0; + // unwind cached data: + if (ReadAheadCount > 0) { + Seek(-ReadAheadCount, SeekOrigin.Current); + } + + _bufferStart = _bufferCount = _pushedBackCount = 0; } public override void Write(byte[]/*!*/ buffer, int offset, int count) { @@ -138,47 +212,54 @@ } } - public int PeekByte(int i) { - Debug.Assert(i < MaxBufferSize); - if (i < _bufferSize) { - return PeekBufferByte(i); + public int PeekByte() { + return PeekByte(0); + } + + /// + /// Peeks i-th byte. Assumes small i. + /// + private int PeekByte(int i) { + Debug.Assert(i < (_buffer != null ? _buffer.Length : _defaultBufferSize)); + + if (i >= _bufferCount) { + LoadBuffer(i + 1 - _bufferCount); } - int result; - if (_stream.CanSeek) { - long oldPos = _stream.Position; - _stream.Position = Position + i; - result = _stream.ReadByte(); - _stream.Position = oldPos; - return result; + // end of stream: + if (i >= _bufferCount) { + return -1; } - while (true) { - result = _stream.ReadByte(); - if (result == -1) { - return result; - } - LoadBufferByte((byte)result); - if (i < _bufferSize) { - return result; - } - } + return _buffer[_bufferStart + i]; + } + + private byte ReadBufferByte() { + Debug.Assert(_bufferCount > 0); + var result = _buffer[_bufferStart]; + ConsumeBuffered(1); + return result; } + // TODO: read in full buffer (underlying FileStream will buffer it anyways) public override int ReadByte() { - return (_bufferSize > 0) ? ReadBufferByte() : _stream.ReadByte(); + return (_bufferCount > 0) ? ReadBufferByte() : _stream.ReadByte(); } public override int Read(byte[]/*!*/ buffer, int offset, int count) { - while (count > 0 && _bufferSize > 0) { - buffer[offset++] = ReadBufferByte(); - count--; + int c = Math.Min(_bufferCount, count); + if (c > 0) { + Buffer.BlockCopy(_buffer, _bufferStart, buffer, offset, c); + ConsumeBuffered(c); } - - return _stream.Read(buffer, offset, count); + return c + _stream.Read(buffer, offset + c, count - c); } - // count == Int32.MaxValue means means no bound + /// + /// Reads bytes from the stream and appends them to the given . + /// If is Int32.MaxValue the stream is read to the end. + /// Unless is set the line endings in the appended data are normalized to "\n". + /// public int AppendBytes(MutableString/*!*/ buffer, int count, bool preserveEndOfLines) { ContractUtils.RequiresNotNull(buffer, "buffer"); ContractUtils.Requires(count >= 0, "count"); @@ -249,9 +330,11 @@ int remaining = count; - while (_bufferSize > 0) { - buffer.Append(ReadBufferByte()); - remaining--; + if (_bufferCount > 0) { + int c = Math.Min(_bufferCount, count); + buffer.Append(_buffer, _bufferStart, c); + ConsumeBuffered(c); + remaining -= c; } if (count == Int32.MaxValue) { @@ -306,6 +389,8 @@ if (separator == null) { var result = MutableString.CreateBinary(); return AppendBytes(result, Int32.MaxValue, preserveEndOfLines) == 0 ? null : result; + } else if (separator.Length == 1 && separator.GetChar(0) == '\n') { + return ReadLine(encoding, preserveEndOfLines); } else if (separator.IsEmpty) { return ReadParagraph(encoding, preserveEndOfLines); } else { @@ -313,6 +398,74 @@ } } + public MutableString ReadLine(RubyEncoding/*!*/ encoding, bool preserveEndOfLines) { + if (_bufferCount == 0) { + if (LoadBuffer(_defaultBufferSize) == 0) { + return null; + } + } + + bool bufferResized = false; + int lf = Array.IndexOf(_buffer, LF, _bufferStart, _bufferCount); + while (lf < 0) { + int s = _bufferCount; + LoadBuffer(_buffer.Length - _bufferCount); + Debug.Assert(_bufferStart == 0); + + lf = Array.IndexOf(_buffer, LF, s, _bufferCount - s); + if (lf >= 0) { + break; + } + + // end of stream: + if (_bufferCount < _buffer.Length) { + return ConsumeLine(encoding, _bufferCount, _bufferCount, bufferResized); + } + + Array.Resize(ref _buffer, _buffer.Length << 1); + bufferResized = true; + _bufferStart = 0; + } + + int lineLength; + int consume = lf + 1 - _bufferStart; + if (!preserveEndOfLines && lf - 1 >= _bufferStart && _buffer[lf - 1] == CR) { + _buffer[lf - 1] = LF; + lineLength = consume - 1; + } else { + lineLength = consume; + } + + return ConsumeLine(encoding, lineLength, consume, bufferResized); + } + + private MutableString/*!*/ ConsumeLine(RubyEncoding/*!*/ encoding, int lineLength, int consume, bool bufferResized) { + Debug.Assert(consume >= lineLength); + Debug.Assert(consume <= _bufferCount); + + MutableString line; + if (bufferResized || _bufferStart == 0 && !Utils.IsSparse(lineLength, _buffer.Length)) { + Debug.Assert(_bufferStart == 0); + line = new MutableString(_buffer, lineLength, encoding); + + if (_bufferCount > consume) { + var newBuffer = new byte[Math.Max(_defaultBufferSize, _bufferCount - consume)]; + Buffer.BlockCopy(_buffer, consume, newBuffer, 0, _bufferCount - consume); + _buffer = newBuffer; + } else { + _buffer = null; + } + + // consume as if we kept the same buffer and then adjust start: + ConsumeBuffered(consume); + _bufferStart = 0; + } else { + line = MutableString.CreateBinary(encoding).Append(_buffer, _bufferStart, lineLength); + ConsumeBuffered(consume); + } + return line; + } + public MutableString ReadParagraph(RubyEncoding/*!*/ encoding, bool preserveEndOfLines) { var result = ReadLine(MutableString.CreateAscii("\n\n"), encoding, preserveEndOfLines); @@ -354,11 +507,6 @@ return result; } - public override void Close() { - FlushRead(); - _stream.Close(); - } - public override bool CanRead { get { return _stream.CanRead; } } =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;C1597865 File: RubyIO.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;C1597865 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyIO.cs;Buffer7 @@ -90,7 +90,7 @@ : this(context) { ContractUtils.RequiresNotNull(context, "context"); ContractUtils.RequiresNotNull(stream, "stream"); - _stream = new RubyBufferedStream(stream); + SetStream(stream); _mode = mode; _fileDescriptor = descriptor; } @@ -187,7 +187,7 @@ public void SetStream(Stream/*!*/ stream) { ContractUtils.RequiresNotNull(stream, "stream"); - _stream = new RubyBufferedStream(stream); + _stream = new RubyBufferedStream(stream, _context.RubyOptions.Compatibility >= RubyCompatibility.Ruby19); } public void RequireOpen() { @@ -408,7 +408,7 @@ } public bool IsEndOfStream() { - return GetReadableStream().PeekByte(0) == -1; + return GetReadableStream().PeekByte() == -1; } // returns the number of bytes written to the stream: =================================================================== edit: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;C1594871 File: Utils.cs =================================================================== --- $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;C1594871 (server) 2/22/2010 10:39 AM +++ Shelved Change: $/Dev10/feature/vs_langs01_s/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs;Buffer7 @@ -58,7 +58,7 @@ return -1; } - internal static bool IsAscii(this string/*!*/ str) { + public static bool IsAscii(this string/*!*/ str) { for (int i = 0; i < str.Length; i++) { if (str[i] > 0x7f) { return false; @@ -125,11 +125,16 @@ } internal static void TrimExcess(ref T[] data, int count) { - if ((long)count * 10 < (long)data.Length * 9) { + if (IsSparse(count, data.Length)) { Array.Resize(ref data, count); } } + internal static bool IsSparse(int portionSize, int totalSize) { + Debug.Assert(portionSize <= totalSize); + return (long)portionSize * 10 < (long)totalSize * 9; + } + internal static void ResizeForInsertion(ref T[]/*!*/ array, int itemCount, int index, int count) { int minLength = itemCount + count; T[] a; ===================================================================