Browse Source

[add][Fix #3] warning messages for double key (last override previous)

isundil 9 năm trước cách đây
mục cha
commit
5300e7996c

+ 2 - 2
CMakeLists.txt

@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.8)
 
-add_executable(jsonstroll src/main.cpp src/jsonContainer.cpp src/params.cpp src/curseOutput.cpp src/linearHistory.cpp src/outputFlag.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObjectEntry.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
-add_executable(json_test test/src/main.cpp src/jsonContainer.cpp src/linearHistory.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObjectEntry.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
+add_executable(jsonstroll src/main.cpp src/jsonContainer.cpp src/warning.cpp src/params.cpp src/curseOutput.cpp src/linearHistory.cpp src/outputFlag.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObjectEntry.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
+add_executable(json_test test/src/main.cpp src/jsonContainer.cpp src/warning.cpp src/linearHistory.cpp src/streamConsumer.cpp src/jsonArray.cpp src/jsonObjectEntry.cpp src/jsonObject.cpp src/jsonElement.cpp src/jsonPrimitive.cpp src/jsonException.cpp)
 add_executable(wrapped_test test/src/wrapped.cpp)
 
 set_property(TARGET jsonstroll PROPERTY RUNTIME_OUTPUT_DIRECTORY bin)

+ 1 - 0
include/jsonObject.hh

@@ -13,6 +13,7 @@ class JSonObject: public JSonContainer
 
         void push(const std::string &key, JSonElement *child);
         JSonObject::const_iterator find(const std::string &key) const;
+        bool erase(const std::string &);
         bool contains(const std::string &) const;
 
         virtual JSonElement *firstChild();

+ 3 - 0
include/params.hh

@@ -9,6 +9,7 @@ class AParams
 {
     public:
         virtual bool isIgnoringUnicode() const =0;
+        virtual bool isStrict() const =0;
 };
 
 class Params: public AParams
@@ -19,6 +20,7 @@ class Params: public AParams
 
         std::basic_istream<char> &getInput() const;
         bool isValid() const;
+        bool isStrict() const;
         bool colorEnabled() const;
 
         static void usage(const std::string &) noexcept;
@@ -32,5 +34,6 @@ class Params: public AParams
         std::list<std::string> params;
         bool ignoreUnicode;
         bool colorMode;
+        bool strict;
 };
 

+ 3 - 0
include/streamConsumer.hh

@@ -6,6 +6,7 @@
 #include "jsonArray.hh"
 #include "jsonPrimitive.hh"
 #include "linearHistory.hh"
+#include "warning.hh"
 
 class StreamConsumer
 {
@@ -15,6 +16,7 @@ class StreamConsumer
 
         StreamConsumer *read();
         JSonElement * const getRoot() const;
+        const std::list<Warning> &getMessages() const;
 
         StreamConsumer *withConfig(const AParams *);
 
@@ -34,6 +36,7 @@ class StreamConsumer
         JSonElement *root;
         const AParams *params;
 
+        std::list<Warning> warnings;
         LinearHistory history;
 
     private:

+ 17 - 0
include/warning.hh

@@ -0,0 +1,17 @@
+#pragma once
+
+#include "jsonException.hh"
+
+class Warning
+{
+    public:
+        Warning(const JsonException *);
+        ~Warning();
+
+        const JsonException &operator()() const;
+        const JsonException *getPtrUnsafe() const;
+
+    private:
+        const JsonException *what;
+};
+

+ 3 - 3
src/curseOutput.cpp

@@ -163,12 +163,12 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
     bool result = true;
     cursor.first += INDENT_LEVEL;
 
-    for (std::list<JSonElement *>::const_iterator i = item->cbegin(); i != item->cend(); ++i)
+    for (JSonElement *i : *item)
     {
         result = false;
         if (containerIsObject)
         {
-            JSonObjectEntry *ent = (JSonObjectEntry*) *i;
+            JSonObjectEntry *ent = (JSonObjectEntry*) i;
             bool isContainer = (dynamic_cast<const JSonContainer *>(**ent) != nullptr);
             std::string key = ent->stringify();
             checkSelection(ent, (JSonContainer*) item, cursor);
@@ -217,7 +217,7 @@ bool CurseOutput::writeContent(std::pair<int, int> &cursor, const std::pair<unsi
         }
         else
         {
-            if (!redraw(cursor, maxSize, *i, (const JSonContainer *)item))
+            if (!redraw(cursor, maxSize, i, (const JSonContainer *)item))
                 break;
         }
         result = true;

+ 2 - 4
src/jsonArray.cpp

@@ -5,10 +5,8 @@ JSonArray::JSonArray(JSonContainer *p): JSonContainer(p)
 
 JSonArray::~JSonArray()
 {
-    for (iterator i = begin(); i != end(); ++i)
-    {
-        delete *i;
-    }
+    for (JSonElement *i : *this)
+        delete i;
 }
 
 JSonElement *JSonArray::firstChild()

+ 12 - 4
src/jsonObject.cpp

@@ -5,10 +5,8 @@ JSonObject::JSonObject(JSonContainer *p): JSonContainer(p)
 
 JSonObject::~JSonObject()
 {
-    for (iterator i = begin(); i != end(); ++i)
-    {
-        delete (*i);
-    }
+    for (JSonElement *i : *this)
+        delete i;
 }
 
 void JSonObject::push(const std::string &key, JSonElement *child)
@@ -28,6 +26,16 @@ JSonObject::const_iterator JSonObject::find(const std::string &key) const
     return it;
 }
 
+bool JSonObject::erase(const std::string &key)
+{
+    JSonObject::const_iterator it = find(key);
+    if (it == this->cend())
+        return false;
+    delete *it;
+    std::list<JSonElement *>::erase(it);
+    return true;
+}
+
 bool JSonObject::contains(const std::string &key) const
 {
     return find(key) != this->cend();

+ 14 - 3
src/main.cpp

@@ -6,6 +6,13 @@
 #include "params.hh"
 #include "jsonException.hh"
 
+void displayException(const Params *params, const JsonException &e)
+{
+    std::string buffer = e.getHistory();
+    std::cerr << params->getProgName() << ": [" << typeid(e).name() << "] at line " << e.currentLine() << " ("  << e.what() << ") while reading" << std::endl;
+    std::cerr << buffer << std::endl << std::string(buffer.size() -1, '~') << '^' << std::endl;
+}
+
 void run(Params *params)
 {
 
@@ -29,11 +36,15 @@ void run(Params *params)
     }
     catch (JsonException &e)
     {
-        std::cerr << params->getProgName() << ": [" << typeid(e).name() << "] at line " << e.currentLine() << " ("  << e.what() << ") error while reading" << std::endl;
-        std::string buffer = e.getHistory();
-        std::cerr << buffer << std::endl << std::string(buffer.size() -1, '~') << '^' << std::endl;
+        std::cerr << "Error: ";
+        displayException(params, e);
         return;
     }
+    for (Warning w : stream.getMessages())
+    {
+        std::cerr << "Warning: ";
+        displayException(params, w());
+    }
     out = new CurseOutput(root, *params);
     out->run();
     delete out;

+ 7 - 1
src/params.cpp

@@ -5,7 +5,7 @@
 #include <unistd.h>
 #include "params.hh"
 
-Params::Params(int ac, char **av) :progName(*av), params(std::list<std::string>(ac -1))
+Params::Params(int ac, char **av) :progName(*av), params(std::list<std::string>(ac -1)), strict(true)
 {
     bool written = false;
     std::stringstream *input = nullptr;
@@ -34,6 +34,8 @@ Params::Params(int ac, char **av) :progName(*av), params(std::list<std::string>(
             {
                 input = new std::stringstream();
             }
+            else if (tmp == "-W")
+                strict = false;
             else if (tmp == "--ascii")
                 ignoreUnicode = true;
             else if (tmp == "--color")
@@ -85,11 +87,15 @@ void Params::usage(const std::string &progName) noexcept
     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;
     std::cout << "\t\t--color[=MODE]\tColorize output, MODE can be always (default when ommited), never or auto (default if --color is ommited)" << std::endl;
+    std::cout << "\t\t-W\tdisable strict mode (warning does not interrupt reading)" << std::endl;
 }
 
 bool Params::isValid() const
 { return true; }
 
+bool Params::isStrict() const
+{ return strict; }
+
 bool Params::colorEnabled() const
 { return colorMode; }
 

+ 16 - 2
src/streamConsumer.cpp

@@ -1,6 +1,5 @@
 #include <iostream>
 #include <sstream>
-#include "jsonException.hh"
 #include "jsonElement.hh"
 #include "streamConsumer.hh"
 
@@ -11,6 +10,10 @@ StreamConsumer::~StreamConsumer()
 {
     if (root)
         delete root;
+    for (Warning i : warnings)
+    {
+        delete i.getPtrUnsafe();
+    }
 }
 
 StreamConsumer *StreamConsumer::withConfig(const AParams *p)
@@ -72,7 +75,15 @@ JSonObject *StreamConsumer::readObject(JSonContainer *parent)
         if (result == nullptr)
             result = new JSonObject(parent);
         else if (result->contains(key->getValue()))
-            throw JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history); //Double key
+        {
+            if (params->isStrict())
+                throw JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history);
+            else // add Warning, new key erase previous one
+            {
+                result->erase(key->getValue());
+                warnings.push_back(Warning(new JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history)));
+            }
+        }
         JSonElement *child = readNext(result);
         result->push(key->getValue(), child);
         delete keyObj;
@@ -289,3 +300,6 @@ bool StreamConsumer::ignoreChar(char c) const noexcept
     return (c <= 32 || c >= 127 || c == '\n');
 }
 
+const std::list<Warning> &StreamConsumer::getMessages() const
+{ return warnings; }
+

+ 15 - 0
src/warning.cpp

@@ -0,0 +1,15 @@
+
+#include "warning.hh"
+
+Warning::Warning(const JsonException *w): what(w)
+{ }
+
+Warning::~Warning()
+{ }
+
+const JsonException &Warning::operator()() const
+{ return *what; }
+
+const JsonException *Warning::getPtrUnsafe() const
+{ return what; }
+

+ 6 - 0
test/doubleKey.json

@@ -0,0 +1,6 @@
+{
+    "0":true, "a":true,
+    "b":true,
+    "1":true, "a":false,
+    "2":true, "a":0
+}