internal Node Scalar(object self, MutableString value) { MutableString taguri = _TagUri.Target(_TagUri, _context, self); MutableString styleStr = ToYamlStyle(_context, self) as MutableString; char style = '\0'; if (!MutableString.IsNullOrEmpty(styleStr)) { style = styleStr.GetChar(0); } return(Scalar( taguri != null ? taguri.ConvertToString() : "", value != null ? value.ConvertToString() : "", style )); }
public static Node ToYamlNode(MutableString /*!*/ self, [NotNull] RubyRepresenter /*!*/ rep) { if (RubyOps.IsTrue(_IsBinaryData.Target(_IsBinaryData, rep.Context, self))) { return(rep.BaseCreateNode(self.ConvertToBytes())); } string str = self.ConvertToString(); RubyArray props = RubyRepresenter.ToYamlProperties(rep.Context, self); if (props.Count == 0) { MutableString taguri = RubyRepresenter.TagUri(rep.Context, self); char style = (char)0; if (str.StartsWith(":")) { style = '"'; } else { MutableString styleStr = RubyRepresenter.ToYamlStyle(rep.Context, self) as MutableString; if (styleStr != null && styleStr.Length > 0) { style = styleStr.GetChar(0); } } return(rep.Scalar(taguri != null ? taguri.ConvertToString() : "", str, style)); } Hash map = new Hash(rep.Context); map.Add(MutableString.Create("str"), str); RubyRepresenter.AddYamlProperties(rep.Context, self, map, props); return(rep.Map(self, map)); }
public static CharacterMap/*!*/ Create(MutableString/*!*/ from, MutableString/*!*/ to) { Debug.Assert(!from.IsEmpty); int fromLength = from.GetCharCount(); bool complemental = from.StartsWith('^') && fromLength > 1; // TODO: kcodings // TODO: surrogates // TODO: max - min > threshold int min, max; if (from.IsBinaryEncoded || from.IsAscii()) { min = 0; max = 255; } else { min = Int32.MaxValue; max = -1; for (int i = (complemental ? 1 : 0); i < fromLength; i++) { int c = from.GetChar(i); if (c < min) { min = c; } if (c > max) { max = c; } } } BitArray map; char[] image; if (complemental || to.IsEmpty) { image = null; map = MakeBitmap(from, fromLength, complemental, min, max); } else { map = null; image = new char[max - min + 1]; // no need to initialize the array: Debug.Assert(Unmapped == 0); bool needMap = false; var toEnum = ExpandRanges(to, 0, to.GetCharCount(), true).GetEnumerator(); foreach (var f in ExpandRanges(from, 0, fromLength, false)) { toEnum.MoveNext(); needMap |= (image[f - min] = toEnum.Current) == Unmapped; } if (needMap) { map = MakeBitmap(from, fromLength, false, min, max); } } return new CharacterMap(map, image, complemental ? to.GetLastChar() : -1, complemental, min, max); }
public static int Ord(MutableString/*!*/ str) { if (str.IsEmpty) { throw RubyExceptions.CreateArgumentError("empty string"); } char c1 = str.GetChar(0); if (!Char.IsSurrogate(c1)) { return (int)c1; } char c2; if (Tokenizer.IsHighSurrogate(c1) && str.GetCharCount() > 1 && Tokenizer.IsLowSurrogate(c2 = str.GetChar(1))) { return Tokenizer.ToCodePoint(c1, c2); } throw RubyExceptions.CreateArgumentError("invalid byte sequence in {0}", str.Encoding); }
private static bool EndsWith(MutableString/*!*/ str, MutableString/*!*/ terminator) { int offset = str.Length - terminator.Length; if (offset < 0) { return false; } if (str.IsBinary) { for (int i = 0; i < terminator.Length; i++) { if (str.GetChar(offset + i) != terminator.GetChar(i)) { return false; } } } else { for (int i = 0; i < terminator.Length; i++) { if (str.GetByte(offset + i) != terminator.GetByte(i)) { return false; } } } return true; }
private static MutableString InternalChomp(MutableString/*!*/ self, MutableString separator) { if (separator == null) { return self.Clone(); } // Remove multiple trailing CR/LFs if (separator.Length == 0) { return ChompTrailingCarriageReturns(self, false).TaintBy(self); } // Remove single trailing CR/LFs MutableString result = self.Clone(); int length = result.Length; if (separator.Length == 1 && separator.GetChar(0) == '\n') { if (length > 1 && result.GetChar(length - 2) == '\r' && result.GetChar(length - 1) == '\n') { result.Remove(length - 2, 2); } else if (length > 0 && (self.GetChar(length - 1) == '\n' || result.GetChar(length - 1) == '\r')) { result.Remove(length - 1, 1); } } else if (EndsWith(result, separator)) { result.Remove(length - separator.Length, separator.Length); } return result; }
private static string/*!*/ StripWhitespace(MutableString/*!*/ str) { int i = 0; while (i < str.Length) { char c = str.GetChar(i); if (c == ' ' || c == '_' || c == '\t' || c == '\n' || c == '\r') { i += 1; } else { return str.GetSlice(i).ConvertToString().Replace("_", ""); } } return str.ConvertToString().Replace("_", ""); }
public static bool SwapCaseChar(MutableString/*!*/ self, int index) { char current = self.GetChar(index); if (current >= 'A' && current <= 'Z') { self.SetChar(index, Char.ToLower(current)); return true; } else if (current >= 'a' && current <= 'z') { self.SetChar(index, Char.ToUpper(current)); return true; } return false; }
// TODO: remove recursion public static void IncrementAlphaNumericChar(MutableString/*!*/ str, int index) { char c = str.GetChar(index); if (c == 'z' || c == 'Z' || c == '9') { int nextIndex = GetIndexOfRightmostAlphaNumericCharacter(str, index - 1); if (c == 'z') { str.SetChar(index, 'a'); if (nextIndex == -1) str.Insert(index, "a"); else IncrementAlphaNumericChar(str, nextIndex); } else if (c == 'Z') { str.SetChar(index, 'A'); if (nextIndex == -1) str.Insert(index, "A"); else IncrementAlphaNumericChar(str, nextIndex); } else { str.SetChar(index, '0'); if (nextIndex == -1) str.Insert(index, "1"); else IncrementAlphaNumericChar(str, nextIndex); } } else { IncrementChar(str, index); } }
private static void GetTrimRange(MutableString/*!*/ str, bool left, bool right, out int leftIndex, out int rightIndex) { GetTrimRange( str.Length, !left ? (Func<int, bool>)null : (i) => Char.IsWhiteSpace(str.GetChar(i)), !right ? (Func<int, bool>)null : (i) => { char c = str.GetChar(i); return Char.IsWhiteSpace(c) || c == '\0'; }, out leftIndex, out rightIndex ); }
// Expand directory path - these cases exist: // // 1. Empty string or nil means return current directory // 2. ~ with non-existent HOME directory throws exception // 3. ~, ~/ or ~\ which expands to HOME // 4. ~foo is left unexpanded // 5. Expand to full path if path is a relative path // // No attempt is made to determine whether the path is valid or not // Returned path is always canonicalized to forward slashes private static MutableString/*!*/ ExpandPath(RubyContext/*!*/ context, MutableString/*!*/ path) { PlatformAdaptationLayer pal = context.DomainManager.Platform; int length = path.Length; bool raisingRubyException = false; try { if (path == null || length == 0) return RubyUtils.CanonicalizePath(MutableString.Create(Directory.GetCurrentDirectory())); if (path.GetChar(0) == '~') { if (length == 1 || (path.GetChar(1) == Path.DirectorySeparatorChar || path.GetChar(1) == Path.AltDirectorySeparatorChar)) { string homeDirectory = pal.GetEnvironmentVariable("HOME"); if (homeDirectory == null) { raisingRubyException = true; throw RubyExceptions.CreateArgumentError("couldn't find HOME environment -- expanding `~'"); } if (length <= 2) { path = MutableString.Create(homeDirectory); } else { path = MutableString.Create(Path.Combine(homeDirectory, path.GetSlice(2).ConvertToString())); } return RubyUtils.CanonicalizePath(path); } else { return path; } } else { string pathStr = path.ConvertToString(); MutableString result = RubyUtils.CanonicalizePath(MutableString.Create(Path.GetFullPath(pathStr))); // Path.GetFullPath("c:/winDOWS/foo") returns "c:/winDOWS/foo", but Path.GetFullPath("c:/winDOWS/~") returns "c:/Windows/~". // So we special-case it as this is not the Ruby behavior. Also, the Ruby behavior is very complicated about when it // matches the case of the input argument, and when it matches the case of the file system. It can match the file system case // for part of the result and not the rest. So we restrict the special-case to a very limited scenarios that unblock real-world code. if (pathStr[pathStr.Length - 1] == '~' && String.Compare(pathStr, result.ConvertToString(), true) == 0) { result = path.Clone(); } return result; } } catch (Exception e) { if (raisingRubyException) { throw; } // Re-throw exception as a reasonable Ruby exception throw RubyErrno.CreateEINVAL(path.ConvertToString(), e); } }
private static object InternalCount(MutableString/*!*/ self, MutableString[]/*!*/ ranges) { BitArray map = new RangeParser(ranges).Parse(); int count = 0; for (int i = 0; i < self.Length; i++) { if (map.Get(self.GetChar(i))) count++; } return ScriptingRuntimeHelpers.Int32ToObject(count); }
private static MutableString/*!*/ TrimTrailingSlashes(MutableString/*!*/ path) { int offset = path.Length - 1; while (offset > 0) { if (path.GetChar(offset) != '/' && path.GetChar(offset) != '\\') break; --offset; } return path.GetSlice(0, offset + 1); }
// Expand directory path - these cases exist: // // 1. Empty string or nil means return current directory // 2. ~ with non-existent HOME directory throws exception // 3. ~, ~/ or ~\ which expands to HOME // 4. ~foo is left unexpanded // 5. Expand to full path if path is a relative path // // No attempt is made to determine whether the path is valid or not // Returned path is always canonicalized to forward slashes private static MutableString/*!*/ ExpandPath(RubyContext/*!*/ context, MutableString/*!*/ path) { PlatformAdaptationLayer pal = context.DomainManager.Platform; int length = path.Length; try { if (path == null || length == 0) return Glob.CanonicalizePath(MutableString.Create(Directory.GetCurrentDirectory())); if (length == 1 && path.GetChar(0) == '~') return Glob.CanonicalizePath(MutableString.Create(Path.GetFullPath(pal.GetEnvironmentVariable("HOME")))); if (path.GetChar(0) == '~' && (path.GetChar(1) == Path.DirectorySeparatorChar || path.GetChar(1) == Path.AltDirectorySeparatorChar)) { string homeDirectory = pal.GetEnvironmentVariable("HOME"); return Glob.CanonicalizePath(length < 3 ? MutableString.Create(homeDirectory) : MutableString.Create(Path.Combine(homeDirectory, path.GetSlice(2).ConvertToString()))); } else { return Glob.CanonicalizePath(MutableString.Create(Path.GetFullPath(path.ConvertToString()))); } } catch (Exception e) { // Re-throw exception as a reasonable Ruby exception throw new Errno.InvalidError(path.ConvertToString(), e); } }
// Expand directory path - these cases exist: // // 1. Empty string or nil means return current directory // 2. ~ with non-existent HOME directory throws exception // 3. ~, ~/ or ~\ which expands to HOME // 4. ~foo is left unexpanded // 5. Expand to full path if path is a relative path // // No attempt is made to determine whether the path is valid or not // Returned path is always canonicalized to forward slashes private static MutableString/*!*/ ExpandPath(RubyContext/*!*/ context, MutableString/*!*/ path) { PlatformAdaptationLayer pal = context.DomainManager.Platform; int length = path.Length; bool raisingRubyException = false; try { if (path == null || length == 0) return Glob.CanonicalizePath(MutableString.Create(Directory.GetCurrentDirectory())); if (path.GetChar(0) == '~') { if (length == 1 || (path.GetChar(1) == Path.DirectorySeparatorChar || path.GetChar(1) == Path.AltDirectorySeparatorChar)) { string homeDirectory = pal.GetEnvironmentVariable("HOME"); if (homeDirectory == null) { raisingRubyException = true; throw RubyExceptions.CreateArgumentError("couldn't find HOME environment -- expanding `~'"); } if (length <= 2) { path = MutableString.Create(homeDirectory); } else { path = MutableString.Create(Path.Combine(homeDirectory, path.GetSlice(2).ConvertToString())); } return Glob.CanonicalizePath(path); } else { return path; } } else { return Glob.CanonicalizePath(MutableString.Create(Path.GetFullPath(path.ConvertToString()))); } } catch (Exception e) { if (raisingRubyException) { throw; } // Re-throw exception as a reasonable Ruby exception throw new Errno.InvalidError(path.ConvertToString(), e); } }
internal static MutableString/*!*/ AppendEscapeForwardSlash(MutableString/*!*/ result, MutableString/*!*/ pattern) { int first = 0; int i = SkipToUnescapedForwardSlash(pattern, 0); while (i >= 0) { Debug.Assert(i < pattern.Length); Debug.Assert(pattern.GetChar(i) == '/' && (i == 0 || pattern.GetChar(i - 1) != '\\')); result.Append(pattern, first, i - first); result.Append('\\'); first = i; // include forward slash in the next append i = SkipToUnescapedForwardSlash(pattern, i + 1); } result.Append(pattern, first, pattern.Length - first); return result; }
private static int SkipToUnescapedForwardSlash(MutableString/*!*/ pattern, int i) { while (i < pattern.Length) { i = pattern.IndexOf('/', i); if (i <= 0) { return i; } if (pattern.GetChar(i - 1) != '\\') { return i; } i++; } return -1; }
public static int GetIndexOfRightmostAlphaNumericCharacter(MutableString/*!*/ str, int index) { for (int i = index; i >= 0; --i) if (Char.IsLetterOrDigit(str.GetChar(i))) return i; return -1; }
public static bool DownCaseChar(MutableString/*!*/ self, int index) { char current = self.GetChar(index); if (current >= 'A' && current <= 'Z') { self.SetChar(index, current.ToLowerInvariant()); return true; } return false; }
private static RubyArray/*!*/ InternalSplit(MutableString/*!*/ self, MutableString separator, StringSplitOptions options, int maxComponents) { if (separator == null || separator.Length == 1 && separator.GetChar(0) == ' ') { return WhitespaceSplit(self, maxComponents); } if (maxComponents <= 0) { maxComponents = Int32.MaxValue; } RubyArray result = new RubyArray(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1); bool keepEmpty = (options & StringSplitOptions.RemoveEmptyEntries) != StringSplitOptions.RemoveEmptyEntries; int selfLength = self.Length; int i = 0; int next; while (maxComponents > 1 && i < selfLength && (next = IndexOf(self, separator, i)) != -1) { if (next > i || keepEmpty) { result.Add(self.CreateInstance().Append(self, i, next - i).TaintBy(self)); maxComponents--; } i = next + separator.Length; } if (i < selfLength || keepEmpty) { result.Add(self.CreateInstance().Append(self, i, selfLength - i).TaintBy(self)); } return result; }
internal static RubyRegexOptions StringToRegexEncoding(MutableString encoding) { if (MutableString.IsNullOrEmpty(encoding)) { return RubyRegexOptions.NONE; } switch (encoding.GetChar(0)) { case 'N': case 'n': return RubyRegexOptions.FIXED; case 'E': case 'e': return RubyRegexOptions.EUC; case 'S': case 's': return RubyRegexOptions.SJIS; case 'U': case 'u': return RubyRegexOptions.UTF8; } return RubyRegexOptions.NONE; }
private static MutableString SqueezeMutableString(MutableString/*!*/ str, MutableString[]/*!*/ ranges) { // if squeezeAll is true then there should be no ranges, and vice versa Assert.NotNull(str, ranges); // convert the args into a map of characters to be squeezed (same algorithm as count) BitArray map = null; if (ranges.Length > 0) { map = new RangeParser(ranges).Parse(); } // Do the squeeze in place int j = 1, k = 1; while (j < str.Length) { if (str.GetChar(j) == str.GetChar(j-1) && (ranges.Length == 0 || map.Get(str.GetChar(j)))) { j++; } else { str.SetChar(k, str.GetChar(j)); j++; k++; } } if (j > k) { str.Remove(k, j - k); } // if not modified return null return j == k ? null : str; }
private static void AppendDirectoryName(MutableString/*!*/ result, MutableString/*!*/ name) { int resultLength = result.GetCharCount(); int i; for (i = resultLength - 1; i >= 0; i--) { if (!IsDirectorySeparator(result.GetChar(i))) { break; } } if (i == resultLength - 1) { if (!IsDirectorySeparator(name.GetFirstChar())) { result.Append(DirectorySeparatorChar); } result.Append(name); } else if (IsDirectorySeparator(name.GetFirstChar())) { result.Replace(i + 1, resultLength - i - 1, name); } else { result.Append(name); } }
private static MutableString/*!*/ TrInternal(MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ from, [DefaultProtocol, NotNull]MutableString/*!*/ to, bool squeeze) { MutableString result = self.CreateInstance().TaintBy(self); IntervalParser parser = new IntervalParser(from); // TODO: a single pass to generate both? MutableString source = parser.ParseSequence(); BitArray bitmap = parser.Parse(); MutableString dest = new IntervalParser(to).ParseSequence(); int lastChar = dest.GetLastChar(); char? lastTranslated = null; for (int i = 0; i < self.Length; i++) { char c = self.GetChar(i); if (bitmap.Get(c)) { char? thisTranslated = null; int index = source.IndexOf(c); if (index >= dest.Length) { if (lastChar != -1) { thisTranslated = (char)lastChar; } } else { thisTranslated = dest.GetChar(index); } if (thisTranslated != null && (!squeeze || lastTranslated == null || lastTranslated.Value != thisTranslated)) { result.Append(thisTranslated.Value); } lastTranslated = thisTranslated; } else { result.Append(c); lastTranslated = null; } } return result; }
public MutableString ReadLine(MutableString/*!*/ separator, RubyEncoding encoding, bool preserveEndOfLines) { int c = ReadByteNormalizeEoln(preserveEndOfLines); if (c == -1) { return null; } int separatorOffset = 0; MutableString result = MutableString.CreateMutable(encoding); do { result.Append((char)c); if (c == separator.GetChar(separatorOffset)) { if (separatorOffset == separator.Length - 1) { break; } separatorOffset++; } else if (separatorOffset > 0) { separatorOffset = 0; } c = ReadByteNormalizeEoln(preserveEndOfLines); } while (c != -1); return result; }
public static MutableString/*!*/ Center(MutableString/*!*/ self, [DefaultProtocol]int length, [Optional, DefaultProtocol]MutableString padding) { if (padding != null && padding.Length == 0) { throw RubyExceptions.CreateArgumentError("zero width padding"); } if (self.Length >= length) { return self; } if (padding == null) { padding = _DefaultPadding; } char[] charArray = new char[length]; int n = (length - self.Length) / 2; for (int i = 0; i < n; i++) { charArray[i] = padding.GetChar(i % padding.Length); } for (int i = 0; i < self.Length; i++) { charArray[n + i] = self.GetChar(i); } int m = length - self.Length - n; for (int i = 0; i < m; i++) { charArray[n + self.Length + i] = padding.GetChar(i % padding.Length); } return self.CreateInstance().Append(new String(charArray)).TaintBy(self).TaintBy(padding); }
public override int Peek() { return(_str.GetChar(_pos)); }
private static MutableString/*!*/ ChompTrailingCarriageReturns(MutableString/*!*/ str, bool removeCarriageReturnsToo) { int end = str.Length; while (true) { if (end > 1) { if (str.GetChar(end - 1) == '\n') { end -= str.GetChar(end - 2) == '\r' ? 2 : 1; } else if (removeCarriageReturnsToo && str.GetChar(end - 1) == '\r') { end -= 1; } else { break; } } else if (end > 0) { if (str.GetChar(end - 1) == '\n' || str.GetChar(end - 1) == '\r') { end -= 1; } break; } else { break; } } return str.GetSlice(0, end); }
private static MutableString/*!*/ ChopInteral(MutableString/*!*/ self) { if (self.Length == 1 || self.GetChar(self.Length - 2) != '\r' || self.GetChar(self.Length - 1) != '\n') { self.Remove(self.Length - 1, 1); } else { self.Remove(self.Length - 2, 2); } return self; }
internal static IEnumerable<char>/*!*/ ExpandRanges(MutableString/*!*/ str, int start, int end, bool infinite) { int rangeMax = -1; char c = '\0'; int i = start; char lookahead = str.GetChar(start); while (true) { if (c < rangeMax) { // next character of the current range: c++; } else if (i < end) { c = lookahead; i++; lookahead = (i < end) ? str.GetChar(i) : '\0'; if (lookahead == '-' && i + 1 < end) { // range: rangeMax = str.GetChar(i + 1); i += 2; lookahead = (i < end) ? str.GetChar(i) : '\0'; if (c > rangeMax) { continue; } } else { rangeMax = -1; } } else { break; } yield return c; } if (infinite) { while (true) { yield return c; } } }
private static void AppendReplacementExpression(MutableString input, GroupCollection/*!*/ groups, MutableString/*!*/ result, MutableString/*!*/ replacement) { int backslashCount = 0; for (int i = 0; i < replacement.Length; i++) { char c = replacement.GetChar(i); if (c == '\\') backslashCount++; else if (backslashCount == 0) result.Append(c); else { AppendBackslashes(backslashCount, result, 0); // Odd number of \'s + digit means insert replacement expression if ((backslashCount & 1) == 1) { if (Char.IsDigit(c)) { AppendGroupByIndex(groups, c - '0', backslashCount, result); } else if (c == '&') { AppendGroupByIndex(groups, groups.Count - 1, backslashCount, result); } else if (c == '`') { // Replace with everything in the input string BEFORE the match result.Append(input, 0, groups[0].Index); } else if (c == '\'') { // Replace with everything in the input string AFTER the match int start = groups[0].Index + groups[0].Length; result.Append(input, start, input.Length - start); } else if (c == '+') { // Replace last character in last successful match group AppendLastCharOfLastMatchGroup(groups, result); } else { // unknown escaped replacement char, go ahead and replace untouched result.Append('\\'); result.Append(c); } } else { // Any other # of \'s or a non-digit character means insert literal \'s and character AppendBackslashes(backslashCount, result, 1); result.Append(c); } backslashCount = 0; } } AppendBackslashes(backslashCount, result, 1); }
public MutableString ReadLine(MutableString separator) { AssertOpenedForReading(); int c = ReadByteNormalizeEoln(); if (c == -1) { return null; } int separatorOffset = 0; MutableString result = MutableString.CreateMutable(); do { result.Append((char)c); if (separator != null && c == separator.GetChar(separatorOffset)) { if (separatorOffset == separator.Length - 1) { break; } separatorOffset++; } else if (separatorOffset > 0) { separatorOffset = 0; } c = ReadByteNormalizeEoln(); } while (c != -1); return result; }
private static MutableString/*!*/ InternalDelete(MutableString/*!*/ self, MutableString[]/*!*/ ranges) { BitArray map = new RangeParser(ranges).Parse(); MutableString result = self.CreateInstance().TaintBy(self); for (int i = 0; i < self.Length; i++) { if (!map.Get(self.GetChar(i))) { result.Append(self.GetChar(i)); } } return result; }