aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/json.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-08-26 18:55:55 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-08-29 17:29:24 +0200
commitc0a7b84748d5e27e6804117b8a57ce71269c3c66 (patch)
tree40f22e1dd5636673f764bc1f289ab254971ca95d /src/libutil/json.cc
parent9fa21765e7f267efcc65e1aa6ab21402ea6125ad (diff)
nix path-info: Add --json flag
Also, factor out JSON generation from value-to-json.{cc,hh}, and support producing indented JSON.
Diffstat (limited to 'src/libutil/json.cc')
-rw-r--r--src/libutil/json.cc171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/libutil/json.cc b/src/libutil/json.cc
new file mode 100644
index 000000000..619b1d631
--- /dev/null
+++ b/src/libutil/json.cc
@@ -0,0 +1,171 @@
+#include "json.hh"
+
+#include <iomanip>
+#include <cstring>
+
+namespace nix {
+
+void toJSON(std::ostream & str, const char * start, const char * end)
+{
+ str << '"';
+ for (auto i = start; i != end; i++)
+ if (*i == '\"' || *i == '\\') str << '\\' << *i;
+ else if (*i == '\n') str << "\\n";
+ else if (*i == '\r') str << "\\r";
+ else if (*i == '\t') str << "\\t";
+ else if (*i >= 0 && *i < 32)
+ str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) *i << std::dec;
+ else str << *i;
+ str << '"';
+}
+
+void toJSON(std::ostream & str, const std::string & s)
+{
+ toJSON(str, s.c_str(), s.c_str() + s.size());
+}
+
+void toJSON(std::ostream & str, const char * s)
+{
+ if (!s) str << "null"; else toJSON(str, s, s + strlen(s));
+}
+
+void toJSON(std::ostream & str, unsigned long n)
+{
+ str << n;
+}
+
+void toJSON(std::ostream & str, long n)
+{
+ str << n;
+}
+
+void toJSON(std::ostream & str, double f)
+{
+ str << f;
+}
+
+void toJSON(std::ostream & str, bool b)
+{
+ str << (b ? "true" : "false");
+}
+
+JSONWriter::JSONWriter(std::ostream & str, bool indent)
+ : state(new JSONState(str, indent))
+{
+ state->stack.push_back(this);
+}
+
+JSONWriter::JSONWriter(JSONState * state)
+ : state(state)
+{
+ state->stack.push_back(this);
+}
+
+JSONWriter::~JSONWriter()
+{
+ assertActive();
+ state->stack.pop_back();
+ if (state->stack.empty()) delete state;
+}
+
+void JSONWriter::comma()
+{
+ assertActive();
+ if (first) {
+ first = false;
+ } else {
+ state->str << ',';
+ }
+ if (state->indent) indent();
+}
+
+void JSONWriter::indent()
+{
+ state->str << '\n' << std::string(state->depth * 2, ' ');
+}
+
+void JSONList::open()
+{
+ state->depth++;
+ state->str << '[';
+}
+
+JSONList::~JSONList()
+{
+ state->depth--;
+ if (state->indent && !first) indent();
+ state->str << "]";
+}
+
+JSONList JSONList::list()
+{
+ comma();
+ return JSONList(state);
+}
+
+JSONObject JSONList::object()
+{
+ comma();
+ return JSONObject(state);
+}
+
+JSONPlaceholder JSONList::placeholder()
+{
+ comma();
+ return JSONPlaceholder(state);
+}
+
+void JSONObject::open()
+{
+ state->depth++;
+ state->str << '{';
+}
+
+JSONObject::~JSONObject()
+{
+ state->depth--;
+ if (state->indent && !first) indent();
+ state->str << "}";
+}
+
+void JSONObject::attr(const std::string & s)
+{
+ comma();
+ toJSON(state->str, s);
+ state->str << ':';
+ if (state->indent) state->str << ' ';
+}
+
+JSONList JSONObject::list(const std::string & name)
+{
+ attr(name);
+ return JSONList(state);
+}
+
+JSONObject JSONObject::object(const std::string & name)
+{
+ attr(name);
+ return JSONObject(state);
+}
+
+JSONPlaceholder JSONObject::placeholder(const std::string & name)
+{
+ attr(name);
+ return JSONPlaceholder(state);
+}
+
+JSONList JSONPlaceholder::list()
+{
+ assertValid();
+ first = false;
+ return JSONList(state);
+}
+
+JSONObject JSONPlaceholder::object()
+{
+ assertValid();
+ first = false;
+ return JSONObject(state);
+}
+
+}