1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "lix/libstore/names.hh"
#include "lix/libutil/regex.hh"
#include "lix/libutil/strings.hh"

#include <regex>


namespace nix {


struct Regex
{
    std::regex regex;
};


DrvName::DrvName()
{
    name = "";
}


/* 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(std::string_view s) : hits(0)
{
    name = fullName = std::string(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 = s.substr(0, i);
            version = s.substr(i + 1);
            break;
        }
    }
}


DrvName::~DrvName()
{ }


bool DrvName::matches(const DrvName & n)
{
    if (name != "*") {
        if (!regex) {
            regex = std::make_unique<Regex>();
            regex->regex = nix::regex::parse(name, std::regex::extended);
        }
        if (!std::regex_match(n.name, regex->regex)) return false;
    }
    if (version != "" && version != n.version) return false;
    return true;
}


std::string_view nextComponent(std::string_view::const_iterator & p,
    const std::string_view::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. */
    auto s = p;
    if (isdigit(*p))
        while (p != end && isdigit(*p)) p++;
    else
        while (p != end && (!isdigit(*p) && *p != '.' && *p != '-'))
            p++;

    return std::string_view(&*s, size_t(p - s));
}


static bool componentsLT(const std::string_view c1, const std::string_view c2)
{
    auto n1 = string2Int<int>(c1);
    auto n2 = string2Int<int>(c2);

    if (n1 && n2) return *n1 < *n2;
    else if (c1 == "" && n2) 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 (n2) return true;
    else if (n1) return false;
    else return c1 < c2;
}


std::strong_ordering compareVersions(const std::string_view v1, const std::string_view v2)
{
    auto p1 = v1.begin();
    auto p2 = v2.begin();

    while (p1 != v1.end() || p2 != v2.end()) {
        auto c1 = nextComponent(p1, v1.end());
        auto c2 = nextComponent(p2, v2.end());
        if (componentsLT(c1, c2)) return std::strong_ordering::less;
        else if (componentsLT(c2, c1)) return std::strong_ordering::greater;
    }

    return std::strong_ordering::equal;
}


DrvNames drvNamesFromArgs(const Strings & opArgs)
{
    DrvNames result;
    for (auto & i : opArgs)
        result.emplace_back(i);
    return result;
}


}