aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-05-23 00:36:15 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-05-24 17:56:03 +0300
commitb39e27a9f1ab04cb67ffad1d2c7e7ae089d5e8c4 (patch)
treed79f6d16d451f081af3a7014e3b629a3d85ca3fc
parente3c8b1c5273e20a6c20b5ba923cdcea919340950 (diff)
Add package_name class
-rw-r--r--libbpkg/manifest.cxx63
-rw-r--r--libbpkg/manifest.hxx13
-rw-r--r--libbpkg/package-name.cxx59
-rw-r--r--libbpkg/package-name.hxx194
4 files changed, 266 insertions, 63 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index 3e9a4fa..b7c3a75 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -17,7 +17,7 @@
#include <libbutl/path.mxx>
#include <libbutl/base64.mxx>
#include <libbutl/utility.mxx> // casecmp(), lcase(), alpha(),
- // alnum(), digit(), xdigit()
+ // digit(), xdigit()
#include <libbutl/manifest-parser.mxx>
#include <libbutl/manifest-serializer.mxx>
#include <libbutl/standard-version.mxx>
@@ -870,44 +870,6 @@ namespace bpkg
return o;
}
- // Package name.
- //
- static const strings illegal_pkg_names ({
- "build",
- "con", "prn", "aux", "nul",
- "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
- "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"});
-
- static const string legal_pkg_chars ("_+-.");
-
- void
- validate_package_name (const string& name)
- {
- if (name.size () < 2)
- throw invalid_argument ("length is less than two characters");
-
- if (find (illegal_pkg_names.begin (), illegal_pkg_names.end (), name) !=
- illegal_pkg_names.end ())
- throw invalid_argument ("illegal name");
-
- if (!alpha (name.front ()))
- throw invalid_argument ("illegal first character (must be alphabetic)");
-
- // Here we rely on the fact that the name length >= 2.
- //
- for (auto i (name.cbegin () + 1), e (name.cend () - 1); i != e; ++i)
- {
- char c (*i);
-
- if (!(alnum(c) || legal_pkg_chars.find (c) != string::npos))
- throw invalid_argument ("illegal character");
- }
-
- if (!alnum (name.back ()))
- throw invalid_argument (
- "illegal last character (must be alphabetic or digit)");
- }
-
// pkg_package_manifest
//
static void
@@ -986,14 +948,12 @@ namespace bpkg
try
{
- validate_package_name (v);
+ m.name = package_name (move (v));
}
catch (const invalid_argument& e)
{
bad_value (string ("invalid package name: ") + e.what ());
}
-
- m.name = move (v);
}
else if (n == "version")
{
@@ -1266,11 +1226,11 @@ namespace bpkg
ne = i + 1;
}
- string nm (i == e ? move (lv) : string (b, ne));
+ package_name nm;
try
{
- validate_package_name (nm);
+ nm = package_name (i == e ? move (lv) : string (b, ne));
}
catch (const invalid_argument& e)
{
@@ -1419,16 +1379,10 @@ namespace bpkg
auto bad_value ([&s](const string& d) {
throw serialization (s.name (), d);});
- try
- {
- validate_package_name (name);
- }
- catch (const invalid_argument& e)
- {
- bad_value (string ("invalid package name: ") + e.what ());
- }
+ if (name.empty ())
+ bad_value ("empty package name");
- s.next ("name", name);
+ s.next ("name", name.string ());
s.next ("version", version.string ());
if (priority)
@@ -1750,7 +1704,8 @@ namespace bpkg
auto bad_value = [&p, &s](const string& d)
{
throw serialization (
- s.name (), d + " for " + p.name + "-" + p.version.string ());
+ s.name (),
+ d + " for " + p.name.string () + "-" + p.version.string ());
};
if (p.description && p.description->file)
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 97239db..82e580d 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -18,6 +18,8 @@
#include <libbutl/optional.mxx>
#include <libbutl/manifest-forward.hxx>
+#include <libbpkg/package-name.hxx>
+
#include <libbpkg/export.hxx>
#include <libbpkg/version.hxx>
@@ -313,7 +315,7 @@ namespace bpkg
struct dependency
{
- std::string name;
+ package_name name;
butl::optional<dependency_constraint> constraint;
};
@@ -376,13 +378,6 @@ namespace bpkg
comment (std::move (c)) {}
};
- // Check if the package name complies with the specification (see the bpkg
- // manual for details) and throw std::invalid_argument if that's not the
- // case.
- //
- LIBBPKG_EXPORT void
- validate_package_name (const std::string&);
-
class LIBBPKG_EXPORT package_manifest
{
public:
@@ -391,7 +386,7 @@ namespace bpkg
using url_type = bpkg::url;
using email_type = bpkg::email;
- std::string name;
+ package_name name;
version_type version;
butl::optional<priority_type> priority;
std::string summary;
diff --git a/libbpkg/package-name.cxx b/libbpkg/package-name.cxx
new file mode 100644
index 0000000..c90d861
--- /dev/null
+++ b/libbpkg/package-name.cxx
@@ -0,0 +1,59 @@
+// file : libbpkg/package-name.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <libbpkg/package-name.hxx>
+
+#include <string>
+#include <vector>
+#include <utility> // move()
+#include <algorithm> // find()
+#include <stdexcept> // invalid_argument
+
+#include <libbutl/utility.mxx> // alpha(), alnum()
+
+using namespace std;
+using namespace butl;
+
+namespace bpkg
+{
+ // package_name
+ //
+ static const vector<string> illegal_pkg_names ({
+ "build",
+ "con", "prn", "aux", "nul",
+ "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
+ "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"});
+
+ static const string legal_pkg_chars ("_+-.");
+
+ package_name::
+ package_name (std::string&& nm)
+ {
+ if (nm.size () < 2)
+ throw invalid_argument ("length is less than two characters");
+
+ if (find (illegal_pkg_names.begin (), illegal_pkg_names.end (), nm) !=
+ illegal_pkg_names.end ())
+ throw invalid_argument ("illegal name");
+
+ if (!alpha (nm.front ()))
+ throw invalid_argument ("illegal first character (must be alphabetic)");
+
+ // Here we rely on the fact that the name length >= 2.
+ //
+ for (auto i (nm.cbegin () + 1), e (nm.cend () - 1); i != e; ++i)
+ {
+ char c (*i);
+
+ if (!(alnum(c) || legal_pkg_chars.find (c) != string::npos))
+ throw invalid_argument ("illegal character");
+ }
+
+ if (!alnum (nm.back ()))
+ throw invalid_argument (
+ "illegal last character (must be alphabetic or digit)");
+
+ value_ = move (nm);
+ }
+}
diff --git a/libbpkg/package-name.hxx b/libbpkg/package-name.hxx
new file mode 100644
index 0000000..6c7ec6c
--- /dev/null
+++ b/libbpkg/package-name.hxx
@@ -0,0 +1,194 @@
+// file : libbpkg/package-name.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef LIBBPKG_PACKAGE_NAME_HXX
+#define LIBBPKG_PACKAGE_NAME_HXX
+
+#include <string>
+#include <utility> // move()
+#include <ostream>
+
+#include <libbutl/utility.mxx> // casecmp()
+
+#include <libbpkg/export.hxx>
+#include <libbpkg/version.hxx>
+
+namespace bpkg
+{
+ class LIBBPKG_EXPORT package_name
+ {
+ public:
+ // Create package name from string verifying that it complied with the
+ // specification and throwing std::invalid_argument if that's not the
+ // case. Note that in this case the passed value is guaranteed to be
+ // unchanged.
+ //
+ explicit
+ package_name (const std::string& s): package_name (std::string (s)) {}
+
+ explicit
+ package_name (std::string&&);
+
+ // Create a special empty package name.
+ //
+ package_name () = default;
+
+ // Create an arbitrary string that can be used in contexts that expect
+ // a package name. For example, a package name pattern for use in ODB query
+ // expressions.
+ //
+ enum raw_string_type {raw_string};
+ package_name (std::string s, raw_string_type): value_ (std::move (s)) {}
+
+ bool
+ empty () const noexcept {return value_.empty ();}
+
+ const std::string&
+ string () const& noexcept {return value_;}
+
+ // Moves the underlying package name string out of the package name object.
+ // The object becomes empty. Usage: std::move (name).string ().
+ //
+ std::string
+ string () && {std::string r; r.swap (this->value_); return r;}
+
+ // Compare ignoring case. Note that a string is not checked to be a valid
+ // package name.
+ //
+ int compare (const package_name& n) const {return compare (n.value_);}
+ int compare (const std::string& n) const {return compare (n.c_str ());}
+ int compare (const char* n) const {return butl::casecmp (value_, n);}
+
+ private:
+ std::string value_;
+ };
+
+ inline bool
+ operator< (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) < 0;
+ }
+
+ inline bool
+ operator> (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) > 0;
+ }
+
+ inline bool
+ operator== (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) == 0;
+ }
+
+ inline bool
+ operator<= (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) <= 0;
+ }
+
+ inline bool
+ operator>= (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) >= 0;
+ }
+
+ inline bool
+ operator!= (const package_name& x, const package_name& y)
+ {
+ return x.compare (y) != 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator< (const package_name& x, const T& y)
+ {
+ return x.compare (y) < 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator> (const package_name& x, const T& y)
+ {
+ return x.compare (y) > 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator== (const package_name& x, const T& y)
+ {
+ return x.compare (y) == 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator<= (const package_name& x, const T& y)
+ {
+ return x.compare (y) <= 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator>= (const package_name& x, const T& y)
+ {
+ return x.compare (y) >= 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator!= (const package_name& x, const T& y)
+ {
+ return x.compare (y) != 0;
+ }
+
+ template <typename T>
+ inline auto
+ operator< (const T& x, const package_name& y)
+ {
+ return y > x;
+ }
+
+ template <typename T>
+ inline auto
+ operator> (const T& x, const package_name& y)
+ {
+ return y < x;
+ }
+
+ template <typename T>
+ inline auto
+ operator== (const T& x, const package_name& y)
+ {
+ return y == x;
+ }
+
+ template <typename T>
+ inline auto
+ operator<= (const T& x, const package_name& y)
+ {
+ return y >= x;
+ }
+
+ template <typename T>
+ inline auto
+ operator>= (const T& x, const package_name& y)
+ {
+ return y <= x;
+ }
+
+ template <typename T>
+ inline auto
+ operator!= (const T& x, const package_name& y)
+ {
+ return y != x;
+ }
+
+ inline std::ostream&
+ operator<< (std::ostream& os, const package_name& v)
+ {
+ return os << v.string ();
+ }
+}
+
+#endif // LIBBPKG_PACKAGE_NAME_HXX