aboutsummaryrefslogtreecommitdiff
path: root/src/nix-env/names.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-env/names.cc')
-rw-r--r--src/nix-env/names.cc121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/nix-env/names.cc b/src/nix-env/names.cc
new file mode 100644
index 000000000..252b07b91
--- /dev/null
+++ b/src/nix-env/names.cc
@@ -0,0 +1,121 @@
+#include "names.hh"
+
+
+/* Parse a derivation name. The `name' part of a derivation name is
+ everything up to but not including the first dash *not* followed by
+ a letter. The `version' part is the rest (excluding the separating
+ dash). E.g., `apache-httpd-2.0.48' is parsed to (`apache-httpd',
+ '2.0.48'). */
+DrvName::DrvName(const string & s) : hits(0)
+{
+ name = fullName = s;
+ for (unsigned int i = 0; i < s.size(); ++i) {
+ /* !!! isalpha/isdigit are affected by the locale. */
+ if (s[i] == '-' && i + 1 < s.size() && !isalpha(s[i + 1])) {
+ name = string(s, 0, i);
+ version = string(s, i + 1);
+ break;
+ }
+ }
+}
+
+
+bool DrvName::matches(DrvName & n)
+{
+ if (name != "*" && name != n.name) return false;
+ if (version != "" && version != n.version) return false;
+ return true;
+}
+
+
+static string nextComponent(string::const_iterator & p,
+ const string::const_iterator end)
+{
+ /* Skip any dots and dashes (component separators). */
+ while (p != end && (*p == '.' || *p == '-')) ++p;
+
+ if (p == end) return "";
+
+ /* If the first character is a digit, consume the longest sequence
+ of digits. Otherwise, consume the longest sequence of
+ non-digit, non-separator characters. */
+ string s;
+ if (isdigit(*p))
+ while (p != end && isdigit(*p)) s += *p++;
+ else
+ while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
+ s += *p++;
+
+ return s;
+}
+
+
+#include <fstream>
+
+static bool parseInt(const string & s, int & n)
+{
+ istringstream st(s);
+ st >> n;
+ return !st.fail();
+}
+
+
+static bool componentsLT(const string & c1, const string & c2)
+{
+ int n1, n2;
+ bool c1Num = parseInt(c1, n1), c2Num = parseInt(c2, n2);
+
+ if (c1Num && c2Num) return n1 < n2;
+ else if (c1 == "" && c2Num) return true;
+ else if (c1 == "pre" && c2 != "pre") return true;
+ else if (c2 == "pre") return false;
+ /* Assume that `2.3a' < `2.3.1'. */
+ else if (c2Num) return true;
+ else if (c1Num) return false;
+ else return c1 < c2;
+}
+
+
+int compareVersions(const string & v1, const string & v2)
+{
+ string::const_iterator p1 = v1.begin();
+ string::const_iterator p2 = v2.begin();
+
+ while (p1 != v1.end() || p2 != v2.end()) {
+ string c1 = nextComponent(p1, v1.end());
+ string c2 = nextComponent(p2, v2.end());
+ if (componentsLT(c1, c2)) return -1;
+ else if (componentsLT(c2, c1)) return 1;
+ }
+
+ return 0;
+}
+
+
+static void testCompareVersions()
+{
+#define TEST(v1, v2, n) assert( \
+ compareVersions(v1, v2) == n && compareVersions(v2, v1) == -n)
+ TEST("1.0", "2.3", -1);
+ TEST("2.1", "2.3", -1);
+ TEST("2.3", "2.3", 0);
+ TEST("2.5", "2.3", 1);
+ TEST("3.1", "2.3", 1);
+ TEST("2.3.1", "2.3", 1);
+ TEST("2.3.1", "2.3a", 1);
+ TEST("2.3pre1", "2.3", -1);
+ TEST("2.3pre3", "2.3pre12", -1);
+ TEST("2.3a", "2.3c", -1);
+ TEST("2.3pre1", "2.3c", -1);
+ TEST("2.3pre1", "2.3q", -1);
+}
+
+
+DrvNames drvNamesFromArgs(const Strings & opArgs)
+{
+ DrvNames result;
+ for (Strings::const_iterator i = opArgs.begin();
+ i != opArgs.end(); ++i)
+ result.push_back(DrvName(*i));
+ return result;
+}