From e3f5e4257433c1555d5afc4c7322d09b40e78007 Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Tue, 4 Feb 2020 21:44:36 +0100 Subject: [PATCH] +LineWriter, +TokenReader --- io/LineWriter.cs | 55 +++++++++++++++++++++++++++ ln.types.csproj | 3 ++ text/TokenReader.cs | 92 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 io/LineWriter.cs create mode 100644 text/TokenReader.cs diff --git a/io/LineWriter.cs b/io/LineWriter.cs new file mode 100644 index 0000000..ec8f843 --- /dev/null +++ b/io/LineWriter.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Text; + +namespace ln.types.io +{ + public delegate void LineReceivedDelegate(object sender, string line); + + public class LineWriter : TextWriter + { + public event LineReceivedDelegate LineReceived; + public override Encoding Encoding => Encoding.UTF8; + + private void FireLineReceived(string line) => LineReceived?.Invoke(this, line); + + char[] lineBuffer = new char[8192]; + int cursor = 0; + + String CurrentLineBuffer => new string(lineBuffer, 0, cursor); + + public LineWriter() + { + } + + public override void Write(char value) + { + lock (this) + { + if (value == '\n') + { + FireLineReceived(CurrentLineBuffer); + cursor = 0; + } else if (cursor < lineBuffer.Length) + { + lineBuffer[cursor++] = value; + } + } + } + + public override void WriteLine() => Write('\n'); + public override void WriteLine(string value) + { + lock (this) + { + if (cursor > 0) + { + value = CurrentLineBuffer + value; + cursor = 0; + } + FireLineReceived(value); + } + } + + } +} diff --git a/ln.types.csproj b/ln.types.csproj index d1fe40f..bb3b22f 100644 --- a/ln.types.csproj +++ b/ln.types.csproj @@ -137,6 +137,8 @@ + + @@ -160,6 +162,7 @@ + diff --git a/text/TokenReader.cs b/text/TokenReader.cs new file mode 100644 index 0000000..ee7056b --- /dev/null +++ b/text/TokenReader.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Text; +using System.Linq; +namespace ln.types.text +{ + public class TokenReader + { + public TextReader Reader { get; } + + public TokenReader(Stream stream) + : this(new UnbufferedStreamReader(stream)) { } + public TokenReader(TextReader textReader) + { + Reader = textReader; + } + + public String Read(Func criteria) + { + StringBuilder stringBuilder = new StringBuilder(); + int ch; + while (((ch = Reader.Peek()) != -1) && criteria((char)ch)) + stringBuilder.Append((char)Reader.Read()); + + return stringBuilder.ToString(); + } + + public bool EndOfStream => Reader.Peek() == -1; + + public String Read(char validChar) => Read((ch) => ch == validChar); + public String Read(char[] validChars) => Read((ch) => validChars.Contains(ch)); + + public String ReadWhiteSpace() => Read((ch) => char.IsWhiteSpace(ch)); + public String ReadToken() => Read((ch) => char.IsLetterOrDigit(ch) || (ch == '_')); + + public String ReadValue() => Reader.Peek() == '"' ? ReadQuotedString() : ReadToken(); + + public String ReadQuotedString() + { + StringBuilder stringBuilder = new StringBuilder(); + + int nextCh = Reader.Peek(); + if (nextCh != -1) + { + if (nextCh != '"') + throw new FormatException("expected double quotes"); + Reader.Read(); + + while (((nextCh = Reader.Read()) != -1) && (nextCh != '"')) + { + if (nextCh == '\\') + nextCh = Reader.Read(); + stringBuilder.Append((char)nextCh); + } + } + + return stringBuilder.ToString(); + } + + public String ReadPath() + { + StringBuilder stringBuilder = new StringBuilder(); + string token; + + if (Reader.Peek() == '/') + stringBuilder.Append((char)Reader.Read()); + + while ((token = ReadToken()).Length > 0) + { + stringBuilder.Append(token); + + if (Reader.Peek() == '/') + stringBuilder.Append((char)Reader.Read()); + else + break; + } + + return stringBuilder.ToString(); + } + + class UnbufferedStreamReader : TextReader + { + public Stream BaseStream { get; } + + public UnbufferedStreamReader(Stream stream) + { + BaseStream = stream; + } + public override int Read() => BaseStream.ReadByte(); + } + } +}