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
28226633Sdimraw_ostream& clang::operator<<(raw_ostream &Out,
29221339Sdim                                     const VersionTuple &V) {
30221339Sdim  Out << V.getMajor();
31249423Sdim  if (Optional<unsigned> Minor = V.getMinor())
32221339Sdim    Out << '.' << *Minor;
33249423Sdim  if (Optional<unsigned> Subminor = V.getSubminor())
34221339Sdim    Out << '.' << *Subminor;
35221339Sdim  return Out;
36221339Sdim}
37239462Sdim
38239462Sdimstatic bool parseInt(StringRef &input, unsigned &value) {
39239462Sdim  assert(value == 0);
40239462Sdim  if (input.empty()) return true;
41239462Sdim
42239462Sdim  char next = input[0];
43239462Sdim  input = input.substr(1);
44239462Sdim  if (next < '0' || next > '9') return true;
45239462Sdim  value = (unsigned) (next - '0');
46239462Sdim
47239462Sdim  while (!input.empty()) {
48239462Sdim    next = input[0];
49239462Sdim    if (next < '0' || next > '9') return false;
50239462Sdim    input = input.substr(1);
51239462Sdim    value = value * 10 + (unsigned) (next - '0');
52239462Sdim  }
53239462Sdim
54239462Sdim  return false;
55239462Sdim}
56239462Sdim
57239462Sdimbool VersionTuple::tryParse(StringRef input) {
58239462Sdim  unsigned major = 0, minor = 0, micro = 0;
59239462Sdim
60239462Sdim  // Parse the major version, [0-9]+
61239462Sdim  if (parseInt(input, major)) return true;
62239462Sdim
63239462Sdim  if (input.empty()) {
64239462Sdim    *this = VersionTuple(major);
65239462Sdim    return false;
66239462Sdim  }
67239462Sdim
68239462Sdim  // If we're not done, parse the minor version, \.[0-9]+
69239462Sdim  if (input[0] != '.') return true;
70239462Sdim  input = input.substr(1);
71239462Sdim  if (parseInt(input, minor)) return true;
72239462Sdim
73239462Sdim  if (input.empty()) {
74239462Sdim    *this = VersionTuple(major, minor);
75239462Sdim    return false;
76239462Sdim  }
77239462Sdim
78239462Sdim  // If we're not done, parse the micro version, \.[0-9]+
79239462Sdim  if (input[0] != '.') return true;
80239462Sdim  input = input.substr(1);
81239462Sdim  if (parseInt(input, micro)) return true;
82239462Sdim
83239462Sdim  // If we have characters left over, it's an error.
84239462Sdim  if (!input.empty()) return true;
85239462Sdim
86239462Sdim  *this = VersionTuple(major, minor, micro);
87239462Sdim  return false;
88239462Sdim}
89