Browse Source

[add][wip] Refs #5 Ignore unicode chars when --ascii, but curses fails to print them
[add] batch-put elements in wrappedBuffer
[add] some tests

isundil 9 years ago
parent
commit
d5caeac355
7 changed files with 185 additions and 11 deletions
  1. 2 0
      include/params.hh
  2. 6 1
      include/streamConsumer.hh
  3. 35 0
      include/wrappedBuffer.hpp
  4. 1 1
      src/main.cpp
  5. 12 7
      src/params.cpp
  6. 34 2
      src/streamConsumer.cpp
  7. 95 0
      test/src/wrapped.cpp

+ 2 - 0
include/params.hh

@@ -17,10 +17,12 @@ class Params
         static void usage(const std::string &) noexcept;
 
         const std::string &getProgName() const;
+        bool isIgnoringUnicode() const;
 
     private:
         std::basic_istream<char> *input;
         const std::string progName;
         std::list<std::string> params;
+        bool ignoreUnicode;
 };
 

+ 6 - 1
include/streamConsumer.hh

@@ -2,6 +2,7 @@
 
 #include <istream>
 #include "config.h"
+#include "params.hh"
 #include "jsonObject.hh"
 #include "jsonArray.hh"
 #include "jsonPrimitive.hh"
@@ -12,9 +13,11 @@ class StreamConsumer
     public:
         virtual ~StreamConsumer();
 
-        static StreamConsumer *read(std::istream &stream);
+        static StreamConsumer *read(std::istream &stream, const Params *params=nullptr);
         JSonElement * const getRoot() const;
 
+        StreamConsumer *withConfig(const Params *);
+
     private:
         StreamConsumer(std::istream &stream);
         /**
@@ -26,9 +29,11 @@ class StreamConsumer
         JSonObject *readObject(JSonContainer *parent);
         JSonArray *readArray(JSonContainer *parent);
         bool ignoreChar(char c) const noexcept;
+        void appendUnicode(const char [4], std::string &);
 
         std::istream &stream;
         JSonElement *root;
+        const Params *params;
 
         WrappedBuffer<char, ERROR_HISTORY_LEN> history;
 

+ 35 - 0
include/wrappedBuffer.hpp

@@ -1,5 +1,6 @@
 #pragma once
 
+#include <string.h>
 #include <string>
 
 template <typename T, int SIZE =10>
@@ -10,6 +11,7 @@ class WrappedBuffer
         virtual ~WrappedBuffer();
 
         void put(T item);
+        void put(T item[], unsigned int count);
         void pop_back();
 
         unsigned int size() const;
@@ -55,6 +57,39 @@ void WrappedBuffer<T, SIZE>::put(T item)
     }
 }
 
+template<typename T, int SIZE>
+void WrappedBuffer<T, SIZE>::put(T items[], unsigned int count)
+{
+    unsigned int newSize = size() + count;
+
+    if (!count)
+        return;
+    while (count > SIZE)
+    {
+        count -= SIZE;
+        items += SIZE;
+    }
+    if (curW + count >= SIZE)
+    {
+        if (curW +1 != SIZE)
+        {
+            memcpy(&buffer[curW +1], items, sizeof(T) * (SIZE - curW -1));
+            items += (SIZE - curW -1);
+            count -= (SIZE - curW -1);
+        }
+        curW = -1;
+    }
+    memcpy(&buffer[curW +1], items, sizeof(T) * count);
+    curW += count;
+    if (curW == SIZE)
+    {
+        curW = 0;
+        curR = 1;
+    }
+    else if (newSize >= SIZE)
+        curR = (curW +1) % SIZE;
+}
+
 template<typename T, int SIZE>
 void WrappedBuffer<T, SIZE>::pop_back()
 {

+ 1 - 1
src/main.cpp

@@ -13,7 +13,7 @@ void run(Params *params)
 
     try
     {
-        stream = StreamConsumer::read(params->getInput());
+        stream = StreamConsumer::read(params->getInput(), params);
         root = stream->getRoot();
         if (!root)
             throw EofException();

+ 12 - 7
src/params.cpp

@@ -7,6 +7,7 @@ Params::Params(int ac, char **av) :progName(*av), params(std::list<std::string>(
 {
     bool written = false;
     std::stringstream *input = nullptr;
+    ignoreUnicode = false;
 
     while (*(++av))
     {
@@ -30,6 +31,8 @@ Params::Params(int ac, char **av) :progName(*av), params(std::list<std::string>(
             {
                 input = new std::stringstream();
             }
+            else if (tmp == "--ascii")
+                ignoreUnicode = true;
             else
                 throw std::runtime_error("Invalid argument: " +tmp);
         }
@@ -59,17 +62,19 @@ std::basic_istream<char> &Params::getInput() const
     return std::cin;
 }
 
-bool Params::isValid() const
-{
-    return true;
-}
-
 void Params::usage(const std::string &progName) noexcept
 {
-    std::cout << "Usage: " << progName << " [-f filename] read input from file instead of stdin" << std::endl;
-    std::cout << "Usage: " << progName << " -- [INPUT] (read input from argument line)" << std::endl;
+    std::cout << "Usage: " << progName << " [OPTIONS] [--] INPUT" << std::endl;
+    std::cout << "\t\t-f filename\tread input from (filename) instead of stdin" << std::endl;
+    std::cout << "\t\t--ascii\tignore unicode values" << std::endl;
 }
 
+bool Params::isValid() const
+{ return true; }
+
+bool Params::isIgnoringUnicode() const
+{ return ignoreUnicode; }
+
 const std::string &Params::getProgName() const
 { return progName; }
 

+ 34 - 2
src/streamConsumer.cpp

@@ -13,9 +13,15 @@ StreamConsumer::~StreamConsumer()
         delete root;
 }
 
-StreamConsumer *StreamConsumer::read(std::istream &stream)
+StreamConsumer *StreamConsumer::withConfig(const Params *p)
 {
-    StreamConsumer *inst = new StreamConsumer(stream);
+    params = p;
+    return this;
+}
+
+StreamConsumer *StreamConsumer::read(std::istream &stream, const Params *config)
+{
+    StreamConsumer *inst = (new StreamConsumer(stream))->withConfig(config);
     inst->root = inst->readNext(nullptr);
     return inst;
 }
@@ -137,6 +143,25 @@ JSonElement *StreamConsumer::consumeToken(JSonContainer *parent, std::string &bu
                     buf += c;
                     escaped = false;
                 }
+                else if (c == 'u')
+                {
+                    if (params && params->isIgnoringUnicode())
+                    {
+                        buf += "\\u";
+                        escaped = false;
+                    }
+                    else
+                    {
+                        char unicodeBuf[4];
+                        stream.read(unicodeBuf, 4);
+                        std::streamsize gcount = stream.gcount();
+                        history.put(unicodeBuf, gcount);
+                        if (gcount != 4)
+                            break;
+                        appendUnicode(unicodeBuf, buf);
+                        escaped = false;
+                    }
+                }
                 else
                     throw JsonEscapedException(c, stream.tellg(), history);
             }
@@ -225,6 +250,13 @@ JSonElement *StreamConsumer::consumeToken(JSonContainer *parent, std::string &bu
     return nullptr;
 }
 
+void StreamConsumer::appendUnicode(const char unicode[4], std::string &buf)
+{
+    std::string rawHex = { '0', 'x', unicode[0], unicode[1], unicode[2], unicode[3], '\0' };
+    wchar_t unichar = std::stoul(rawHex, nullptr, 16);
+    buf += unichar;
+}
+
 bool StreamConsumer::ignoreChar(char c) const noexcept
 {
     return (c <= 32 || c >= 127 || c == '\n');

+ 95 - 0
test/src/wrapped.cpp

@@ -144,12 +144,107 @@ bool testBorder()
     return _testBorder(test);
 }
 
+bool _testBatch(WrappedBuffer<char, 3> &test)
+{
+    char buf[] = {'a', 'b', 'c', 'd', 'e'};
+
+    test.put(buf, 2);
+    if (test.size() != 2)
+        FAILED(test.size(), "!=", 2);
+    if (test.toString() != "ab")
+        FAILED(test.toString(), "!=", "ab");
+    test.put(&buf[2], 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "bcd")
+        FAILED(test.toString(), "!=", "bcd");
+    test.put(&buf[2], 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "dcd")
+        FAILED(test.toString(), "!=", "dcd");
+    test.put(&buf[3], 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "dde")
+        FAILED(test.toString(), "!=", "dde");
+    test.put(&buf[2], 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "ecd")
+        FAILED(test.toString(), "!=", "ecd");
+    test.put(buf, 3);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "abc")
+        FAILED(test.toString(), "!=", "abc");
+    test.put(buf, 5);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "cde")
+        FAILED(test.toString(), "!=", "cde");
+
+    test.pop_back();
+    if (test.size() != 2)
+        FAILED(test.size(), "!=", 2);
+    if (test.toString() != "cd")
+        FAILED(test.toString(), "!=", "cd");
+    test.put(buf, 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "dab")
+        FAILED(test.toString(), "!=", "dab");
+
+    test.pop_back();
+    if (test.size() != 2)
+        FAILED(test.size(), "!=", 2);
+    if (test.toString() != "da")
+        FAILED(test.toString(), "!=", "da");
+    test.put(buf, 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "aab")
+        FAILED(test.toString(), "!=", "aab");
+
+    test.pop_back();
+    if (test.size() != 2)
+        FAILED(test.size(), "!=", 2);
+    if (test.toString() != "aa")
+        FAILED(test.toString(), "!=", "aa");
+    test.put(&buf[1], 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "abc")
+        FAILED(test.toString(), "!=", "abc");
+
+    test.pop_back();
+    if (test.size() != 2)
+        FAILED(test.size(), "!=", 2);
+    if (test.toString() != "ab")
+        FAILED(test.toString(), "!=", "ab");
+    test.put(buf, 2);
+    if (test.size() != 3)
+        FAILED(test.size(), "!=", 3);
+    if (test.toString() != "bab")
+        FAILED(test.toString(), "!=", "bab");
+    return true;
+}
+
+bool testBatch()
+{
+    WrappedBuffer<char, 3> test;
+
+    return _testBatch(test);
+}
+
 int main()
 {
     if (!simpleTest())
         exit(EXIT_FAILURE);
     if (!testBorder())
         exit(EXIT_FAILURE);
+    if (!testBatch())
+        exit(EXIT_FAILURE);
     exit(EXIT_SUCCESS);
 }