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