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