Example #1
0
        /// <summary>
        /// Finds the last match whose index is less than or equal to "start".
        /// Captures are ordered in the same way as with forward match. This is different from .NET reverse matching.
        /// Start is a number of bytes if kcode is given, otherwise it's a number of characters.
        /// </summary>
        public MatchData LastMatch(MutableString /*!*/ input, int start)
        {
            string       str;
            RubyEncoding kcode = null;
            Regex        regex = Transform(ref kcode, input, 0, out str);

            Debug.Assert(str != null);

            if (kcode != null)
            {
                int    byteCount;
                byte[] bytes = input.GetByteArray(out byteCount);

                if (start < 0)
                {
                    start += byteCount;
                }

                // GetCharCount returns the number of whole characters:
                start = (start >= byteCount) ? str.Length : kcode.Encoding.GetCharCount(bytes, 0, start + 1) - 1;
            }
            else
            {
                if (start < 0)
                {
                    start += str.Length;
                }

                if (start > str.Length)
                {
                    start = str.Length;
                }
            }

            Match match;

            if (_hasGAnchor)
            {
                // This only makes some \G anchors work. It seems that CLR doesn't support \G if preceeded by some characters.
                // For example, this works in MRI but doesn't in CLR: "abcabczzz".rindex(/.+\G.+/, 3)
                match = regex.Match(str, start);
            }
            else
            {
                match = LastMatch(regex, str, start);
                if (match == null)
                {
                    return(null);
                }
            }
            return(MatchData.Create(match, input, true, str));
        }
Example #2
0
        /// <summary>
        /// Reads <paramref name="count"/> bytes from the stream and appends them to the given <paramref name="buffer"/>.
        /// If <paramref name="count"/> is <c>Int32.MaxValue</c> the stream is read to the end.
        /// Unless <paramref name="preserveEndOfLines"/> is set the line endings in the appended data are normalized to "\n".
        /// </summary>
        public int AppendBytes(MutableString /*!*/ buffer, int count, bool preserveEndOfLines)
        {
            ContractUtils.RequiresNotNull(buffer, "buffer");
            ContractUtils.Requires(count >= 0, "count");

            if (count == 0)
            {
                return(0);
            }

            bool readAll = count == Int32.MaxValue;

            buffer.SwitchToBytes();
            int initialBufferSize = buffer.GetByteCount();

            if (preserveEndOfLines)
            {
                AppendRawBytes(buffer, count);
            }
            else
            {
                // allocate 3 more bytes at the end for a backstop and possible LF:
                byte[] bytes = Utils.EmptyBytes;

                int  done = initialBufferSize;
                bool eof;
                do
                {
                    AppendRawBytes(buffer, readAll ? 1024 : count);
                    int end       = buffer.GetByteCount();
                    int bytesRead = end - done;
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    eof = bytesRead < count;

                    buffer.EnsureCapacity(end + 3);
                    int byteCount;
                    bytes = buffer.GetByteArray(out byteCount);

                    if (bytes[end - 1] == CR && PeekByte(0) == LF)
                    {
                        ReadByte();
                        bytes[end++] = LF;
                    }

                    // insert backstop:
                    bytes[end]     = CR;
                    bytes[end + 1] = LF;

                    int last = IndexOfCrLf(bytes, done);
                    count -= last - done;
                    done   = last;
                    while (last < end)
                    {
                        int next  = IndexOfCrLf(bytes, last + 2);
                        int chunk = next - last - 1;
                        Buffer.BlockCopy(bytes, last + 1, bytes, done, chunk);
                        done  += chunk;
                        count -= chunk;
                        last   = next;
                    }
                    buffer.Remove(done);
                } while (readAll || count > 0 && !eof);
            }

            if (readAll)
            {
                buffer.TrimExcess();
            }

            return(buffer.GetByteCount() - initialBufferSize);
        }