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