1221339Sdim//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
2221339Sdim//
3221339Sdim//                     The LLVM Compiler Infrastructure
4221339Sdim//
5221339Sdim// This file is distributed under the University of Illinois Open Source
6221339Sdim// License. See LICENSE.TXT for details.
7221339Sdim//
8221339Sdim//===----------------------------------------------------------------------===//
9221339Sdim//
10221339Sdim// This file implements the VersionTuple class, which represents a version in
11221339Sdim// the form major[.minor[.subminor]].
12221339Sdim//
13221339Sdim//===----------------------------------------------------------------------===//
14221339Sdim#include "clang/Basic/VersionTuple.h"
15221339Sdim#include "llvm/Support/raw_ostream.h"
16221339Sdim
17221339Sdimusing namespace clang;
18221339Sdim
19221339Sdimstd::string VersionTuple::getAsString() const {
20221339Sdim  std::string Result;
21221339Sdim  {
22221339Sdim    llvm::raw_string_ostream Out(Result);
23221339Sdim    Out << *this;
24221339Sdim  }
25221339Sdim  return Result;
26221339Sdim}
27221339Sdim
28226890Sdimraw_ostream& clang::operator<<(raw_ostream &Out,
29221339Sdim                                     const VersionTuple &V) {
30221339Sdim  Out << V.getMajor();
31252723Sdim  if (Optional<unsigned> Minor = V.getMinor())
32221339Sdim    Out << '.' << *Minor;
33252723Sdim  if (Optional<unsigned> Subminor = V.getSubminor())
34221339Sdim    Out << '.' << *Subminor;
35221339Sdim  return Out;
36221339Sdim}
37245431Sdim
38245431Sdimstatic bool parseInt(StringRef &input, unsigned &value) {
39245431Sdim  assert(value == 0);
40245431Sdim  if (input.empty()) return true;
41245431Sdim
42245431Sdim  char next = input[0];
43245431Sdim  input = input.substr(1);
44245431Sdim  if (next < '0' || next > '9') return true;
45245431Sdim  value = (unsigned) (next - '0');
46245431Sdim
47245431Sdim  while (!input.empty()) {
48245431Sdim    next = input[0];
49245431Sdim    if (next < '0' || next > '9') return false;
50245431Sdim    input = input.substr(1);
51245431Sdim    value = value * 10 + (unsigned) (next - '0');
52245431Sdim  }
53245431Sdim
54245431Sdim  return false;
55245431Sdim}
56245431Sdim
57245431Sdimbool VersionTuple::tryParse(StringRef input) {
58245431Sdim  unsigned major = 0, minor = 0, micro = 0;
59245431Sdim
60245431Sdim  // Parse the major version, [0-9]+
61245431Sdim  if (parseInt(input, major)) return true;
62245431Sdim
63245431Sdim  if (input.empty()) {
64245431Sdim    *this = VersionTuple(major);
65245431Sdim    return false;
66245431Sdim  }
67245431Sdim
68245431Sdim  // If we're not done, parse the minor version, \.[0-9]+
69245431Sdim  if (input[0] != '.') return true;
70245431Sdim  input = input.substr(1);
71245431Sdim  if (parseInt(input, minor)) return true;
72245431Sdim
73245431Sdim  if (input.empty()) {
74245431Sdim    *this = VersionTuple(major, minor);
75245431Sdim    return false;
76245431Sdim  }
77245431Sdim
78245431Sdim  // If we're not done, parse the micro version, \.[0-9]+
79245431Sdim  if (input[0] != '.') return true;
80245431Sdim  input = input.substr(1);
81245431Sdim  if (parseInt(input, micro)) return true;
82245431Sdim
83245431Sdim  // If we have characters left over, it's an error.
84245431Sdim  if (!input.empty()) return true;
85245431Sdim
86245431Sdim  *this = VersionTuple(major, minor, micro);
87245431Sdim  return false;
88245431Sdim}
89