From: Loic Dachary Date: Sat, 21 Dec 2013 12:58:44 +0000 (+0100) Subject: common: implement get_str_map to parse key/values X-Git-Tag: v0.75~48^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a44a57a7c3843a3c765c5a7dbdc7e438dda104cc;p=ceph.git common: implement get_str_map to parse key/values 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 --- diff --git a/src/common/Makefile.am b/src/common/Makefile.am index b90d26adb5d7..b8efc84ac9f2 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -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 index 000000000000..a17cf77120c9 --- /dev/null +++ b/src/common/str_map.cc @@ -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 + * + * Author: Loic Dachary + * + * 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 + +#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 *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::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 pairs; + get_str_list(str, "\t\n ", pairs); + for (list::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; +} diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 6e076600e273..26f98a800f3b 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -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 index 000000000000..efae903d6387 --- /dev/null +++ b/src/include/str_map.h @@ -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 + * + * Author: Loic Dachary + * + * 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 +#include +#include + +/** + * 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 *str_map); + +#endif diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 0ca314fccc1c..bda6472a62eb 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -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 index 000000000000..f60f0d8bd05a --- /dev/null +++ b/src/test/common/test_str_map.cc @@ -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 + * + * Author: Loic Dachary + * + * 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 +#include + +#include "include/str_map.h" + +using namespace std; + +TEST(str_map, json) { + map 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 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 str_map; + ASSERT_EQ(0, get_str_map("that", ss, &str_map)); + ASSERT_EQ(1u, str_map.size()); + ASSERT_EQ("", str_map["that"]); + } + { + map 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: + */