xref: /freebsd/contrib/llvm-project/llvm/lib/Support/VersionTuple.cpp (revision d63a631e72441687910b8ec4a9396ac5d05029fb)
1  //===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  //
9  // This file implements the VersionTuple class, which represents a version in
10  // the form major[.minor[.subminor]].
11  //
12  //===----------------------------------------------------------------------===//
13  #include "llvm/Support/VersionTuple.h"
14  #include "llvm/Support/raw_ostream.h"
15  
16  using namespace llvm;
17  
18  std::string VersionTuple::getAsString() const {
19    std::string Result;
20    {
21      llvm::raw_string_ostream Out(Result);
22      Out << *this;
23    }
24    return Result;
25  }
26  
27  raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) {
28    Out << V.getMajor();
29    if (Optional<unsigned> Minor = V.getMinor())
30      Out << '.' << *Minor;
31    if (Optional<unsigned> Subminor = V.getSubminor())
32      Out << '.' << *Subminor;
33    if (Optional<unsigned> Build = V.getBuild())
34      Out << '.' << *Build;
35    return Out;
36  }
37  
38  static bool parseInt(StringRef &input, unsigned &value) {
39    assert(value == 0);
40    if (input.empty())
41      return true;
42  
43    char next = input[0];
44    input = input.substr(1);
45    if (next < '0' || next > '9')
46      return true;
47    value = (unsigned)(next - '0');
48  
49    while (!input.empty()) {
50      next = input[0];
51      if (next < '0' || next > '9')
52        return false;
53      input = input.substr(1);
54      value = value * 10 + (unsigned)(next - '0');
55    }
56  
57    return false;
58  }
59  
60  bool VersionTuple::tryParse(StringRef input) {
61    unsigned major = 0, minor = 0, micro = 0, build = 0;
62  
63    // Parse the major version, [0-9]+
64    if (parseInt(input, major))
65      return true;
66  
67    if (input.empty()) {
68      *this = VersionTuple(major);
69      return false;
70    }
71  
72    // If we're not done, parse the minor version, \.[0-9]+
73    if (input[0] != '.')
74      return true;
75    input = input.substr(1);
76    if (parseInt(input, minor))
77      return true;
78  
79    if (input.empty()) {
80      *this = VersionTuple(major, minor);
81      return false;
82    }
83  
84    // If we're not done, parse the micro version, \.[0-9]+
85    if (input[0] != '.')
86      return true;
87    input = input.substr(1);
88    if (parseInt(input, micro))
89      return true;
90  
91    if (input.empty()) {
92      *this = VersionTuple(major, minor, micro);
93      return false;
94    }
95  
96    // If we're not done, parse the micro version, \.[0-9]+
97    if (input[0] != '.')
98      return true;
99    input = input.substr(1);
100    if (parseInt(input, build))
101      return true;
102  
103    // If we have characters left over, it's an error.
104    if (!input.empty())
105      return true;
106  
107    *this = VersionTuple(major, minor, micro, build);
108    return false;
109  }
110