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 
14 #include "llvm/Support/VersionTuple.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include <cassert>
18 
19 using namespace llvm;
20 
getAsString() const21 std::string VersionTuple::getAsString() const {
22   std::string Result;
23   {
24     llvm::raw_string_ostream Out(Result);
25     Out << *this;
26   }
27   return Result;
28 }
29 
operator <<(raw_ostream & Out,const VersionTuple & V)30 raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) {
31   Out << V.getMajor();
32   if (Optional<unsigned> Minor = V.getMinor())
33     Out << '.' << *Minor;
34   if (Optional<unsigned> Subminor = V.getSubminor())
35     Out << '.' << *Subminor;
36   if (Optional<unsigned> Build = V.getBuild())
37     Out << '.' << *Build;
38   return Out;
39 }
40 
parseInt(StringRef & input,unsigned & value)41 static bool parseInt(StringRef &input, unsigned &value) {
42   assert(value == 0);
43   if (input.empty())
44     return true;
45 
46   char next = input[0];
47   input = input.substr(1);
48   if (next < '0' || next > '9')
49     return true;
50   value = (unsigned)(next - '0');
51 
52   while (!input.empty()) {
53     next = input[0];
54     if (next < '0' || next > '9')
55       return false;
56     input = input.substr(1);
57     value = value * 10 + (unsigned)(next - '0');
58   }
59 
60   return false;
61 }
62 
tryParse(StringRef input)63 bool VersionTuple::tryParse(StringRef input) {
64   unsigned major = 0, minor = 0, micro = 0, build = 0;
65 
66   // Parse the major version, [0-9]+
67   if (parseInt(input, major))
68     return true;
69 
70   if (input.empty()) {
71     *this = VersionTuple(major);
72     return false;
73   }
74 
75   // If we're not done, parse the minor version, \.[0-9]+
76   if (input[0] != '.')
77     return true;
78   input = input.substr(1);
79   if (parseInt(input, minor))
80     return true;
81 
82   if (input.empty()) {
83     *this = VersionTuple(major, minor);
84     return false;
85   }
86 
87   // If we're not done, parse the micro version, \.[0-9]+
88   if (input[0] != '.')
89     return true;
90   input = input.substr(1);
91   if (parseInt(input, micro))
92     return true;
93 
94   if (input.empty()) {
95     *this = VersionTuple(major, minor, micro);
96     return false;
97   }
98 
99   // If we're not done, parse the micro version, \.[0-9]+
100   if (input[0] != '.')
101     return true;
102   input = input.substr(1);
103   if (parseInt(input, build))
104     return true;
105 
106   // If we have characters left over, it's an error.
107   if (!input.empty())
108     return true;
109 
110   *this = VersionTuple(major, minor, micro, build);
111   return false;
112 }
113