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