]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: implement get_str_map to parse key/values
authorLoic Dachary <loic@dachary.org>
Sat, 21 Dec 2013 12:58:44 +0000 (13:58 +0100)
committerLoic Dachary <loic@dachary.org>
Sun, 22 Dec 2013 22:43:54 +0000 (23:43 +0100)
It is capable of parsing json or key=value pairs. The prototype is made
to look like get_str_list. The implementation is in common + include and
use .h. It will probably be moved to common and use .hpp instead, along
with str_list.{cc,h}.

Signed-off-by: Loic Dachary <loic@dachary.org>
src/common/Makefile.am
src/common/str_map.cc [new file with mode: 0644]
src/include/Makefile.am
src/include/str_map.h [new file with mode: 0644]
src/test/Makefile.am
src/test/common/test_str_map.cc [new file with mode: 0644]

index b90d26adb5d767354c5d4d028e165f7f33e1f56d..b8efc84ac9f2ed8eee0f25c6e6e652c4eae5eb6f 100644 (file)
@@ -29,6 +29,7 @@ libcommon_la_SOURCES = \
        common/safe_io.c \
        common/snap_types.cc \
        common/str_list.cc \
+       common/str_map.cc \
        common/errno.cc \
        common/RefCountedObj.cc \
        common/blkdev.cc \
diff --git a/src/common/str_map.cc b/src/common/str_map.cc
new file mode 100644 (file)
index 0000000..a17cf77
--- /dev/null
@@ -0,0 +1,68 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ */
+
+#include <errno.h>
+
+#include "include/str_map.h"
+#include "include/str_list.h"
+
+#include "json_spirit/json_spirit.h"
+
+using namespace std;
+
+int get_str_map(const string &str,
+                stringstream &ss,
+                map<string,string> *str_map)
+{
+  json_spirit::mValue json;
+  try {
+    // try json parsing first
+
+    json_spirit::read_or_throw(str, json);
+
+    if (json.type() != json_spirit::obj_type) {
+      ss << str << " must be a JSON object but is of type "
+        << json.type() << " instead";
+      return -EINVAL;
+    }
+
+    json_spirit::mObject o = json.get_obj();
+
+    for (map<string, json_spirit::mValue>::iterator i = o.begin();
+        i != o.end();
+        ++i) {
+      (*str_map)[i->first] = i->second.get_str();
+    }
+    
+  } catch (json_spirit::Error_position &e) {
+    // fallback to key=value format
+
+    list<string> pairs;
+    get_str_list(str, "\t\n ", pairs);
+    for (list<string>::iterator i = pairs.begin(); i != pairs.end(); i++) {
+      size_t equal = i->find('=');
+      if (equal == string::npos)
+       (*str_map)[*i] = string();
+      else {
+       const string key = i->substr(0, equal);
+       equal++;
+       const string value = i->substr(equal);
+       (*str_map)[key] = value;
+      }
+    }
+  }
+  return 0;
+}
index 6e076600e273cb001f5dfd2513b3af389a5a54ee..26f98a800f3bb15d565c47786ee3a332b97da148 100644 (file)
@@ -59,6 +59,7 @@ noinst_HEADERS += \
        include/rbd_types.h \
        include/statlite.h \
        include/str_list.h \
+       include/str_map.h \
        include/stringify.h \
        include/triple.h \
        include/types.h \
diff --git a/src/include/str_map.h b/src/include/str_map.h
new file mode 100644 (file)
index 0000000..efae903
--- /dev/null
@@ -0,0 +1,59 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ */
+
+#ifndef CEPH_STRMAP_H
+#define CEPH_STRMAP_H
+
+#include <map>
+#include <string>
+#include <sstream>
+
+/**
+ * Parse **str** and set **str_map** with the key/value pairs read
+ * from it. The format of **str** is either a well formed JSON object
+ * or a custom key[=value] plain text format.
+ *
+ * JSON is tried first. If successfully parsed into a JSON object, it
+ * is copied into **str_map** verbatim. If it is not a JSON object ( a
+ * string, integer etc. ), -EINVAL is returned and **ss** is set to
+ * a human readable error message.
+ *
+ * If **str** is no valid JSON, it is assumed to be a string
+ * containing white space separated key=value pairs. A white space is
+ * either space, tab or newline. The value is optional, in which case
+ * it defaults to an empty string. For example:
+ * 
+ *     insert your own=political    statement=here 
+ *
+ * will be parsed into:
+ *
+ *     { "insert": "", 
+ *       "your": "", 
+ *       "own": "policital",
+ *       "statement": "here" }
+ *
+ * Returns 0 on success.
+ *
+ * @param [in] str JSON or plain text key/value pairs
+ * @param [out] ss human readable message on error
+ * @param [out] str_map key/value pairs read from str
+ * @return **0** on success or a -EINVAL on error.
+ */
+extern int get_str_map(const std::string &str,
+                      std::stringstream &ss,
+                      std::map<std::string,std::string> *str_map);
+
+#endif
index 0ca314fccc1c206adb5b9955af7779b0c6bd2e6f..bda6472a62ebd0e95783a99da00797342f3dfc3d 100644 (file)
@@ -268,6 +268,11 @@ unittest_bloom_filter_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 unittest_bloom_filter_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 check_PROGRAMS += unittest_bloom_filter
 
+unittest_str_map_SOURCES = test/common/test_str_map.cc
+unittest_str_map_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+unittest_str_map_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
+check_PROGRAMS += unittest_str_map
+
 unittest_sharedptr_registry_SOURCES = test/common/test_sharedptr_registry.cc
 unittest_sharedptr_registry_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 unittest_sharedptr_registry_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
diff --git a/src/test/common/test_str_map.cc b/src/test/common/test_str_map.cc
new file mode 100644 (file)
index 0000000..f60f0d8
--- /dev/null
@@ -0,0 +1,70 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ */
+
+#include <errno.h>
+#include <gtest/gtest.h>
+
+#include "include/str_map.h"
+
+using namespace std;
+
+TEST(str_map, json) {
+  map<string,string> str_map;
+  stringstream ss;
+  // well formatted
+  ASSERT_EQ(0, get_str_map("{\"key\": \"value\"}", ss, &str_map));
+  ASSERT_EQ("value", str_map["key"]);
+  // well formatted but not a JSON object
+  ASSERT_EQ(-EINVAL, get_str_map("\"key\"", ss, &str_map));
+  ASSERT_NE(string::npos, ss.str().find("must be a JSON object"));
+}
+
+TEST(str_map, plaintext) {
+  stringstream ss;
+  {
+    map<string,string> str_map;
+    ASSERT_EQ(0, get_str_map(" foo=bar\t\nfrob=nitz   yeah right=   \n\t",
+                            ss, &str_map));
+    ASSERT_EQ(4u, str_map.size());
+    ASSERT_EQ("bar", str_map["foo"]);
+    ASSERT_EQ("nitz", str_map["frob"]);
+    ASSERT_EQ("", str_map["yeah"]);
+    ASSERT_EQ("", str_map["right"]);
+  }
+  {
+    map<string,string> str_map;
+    ASSERT_EQ(0, get_str_map("that", ss, &str_map));
+    ASSERT_EQ(1u, str_map.size());
+    ASSERT_EQ("", str_map["that"]);
+  }
+  {
+    map<string,string> str_map;
+    ASSERT_EQ(0, get_str_map(" \t \n ", ss, &str_map));
+    ASSERT_EQ(0u, str_map.size());
+    ASSERT_EQ(0, get_str_map("", ss, &str_map));
+    ASSERT_EQ(0u, str_map.size());
+  }
+}
+
+/* 
+ * Local Variables:
+ * compile-command: "cd ../.. ; make -j4 && 
+ *   make unittest_str_map && 
+ *   valgrind --tool=memcheck --leak-check=full \
+ *      ./unittest_str_map
+ *   "
+ * End:
+ */