17330f729Sjoerg //===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the VersionTuple class, which represents a version in
107330f729Sjoerg // the form major[.minor[.subminor]].
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
13*82d56013Sjoerg
147330f729Sjoerg #include "llvm/Support/VersionTuple.h"
15*82d56013Sjoerg #include "llvm/ADT/StringRef.h"
167330f729Sjoerg #include "llvm/Support/raw_ostream.h"
17*82d56013Sjoerg #include <cassert>
187330f729Sjoerg
197330f729Sjoerg using namespace llvm;
207330f729Sjoerg
getAsString() const217330f729Sjoerg std::string VersionTuple::getAsString() const {
227330f729Sjoerg std::string Result;
237330f729Sjoerg {
247330f729Sjoerg llvm::raw_string_ostream Out(Result);
257330f729Sjoerg Out << *this;
267330f729Sjoerg }
277330f729Sjoerg return Result;
287330f729Sjoerg }
297330f729Sjoerg
operator <<(raw_ostream & Out,const VersionTuple & V)307330f729Sjoerg raw_ostream &llvm::operator<<(raw_ostream &Out, const VersionTuple &V) {
317330f729Sjoerg Out << V.getMajor();
327330f729Sjoerg if (Optional<unsigned> Minor = V.getMinor())
337330f729Sjoerg Out << '.' << *Minor;
347330f729Sjoerg if (Optional<unsigned> Subminor = V.getSubminor())
357330f729Sjoerg Out << '.' << *Subminor;
367330f729Sjoerg if (Optional<unsigned> Build = V.getBuild())
377330f729Sjoerg Out << '.' << *Build;
387330f729Sjoerg return Out;
397330f729Sjoerg }
407330f729Sjoerg
parseInt(StringRef & input,unsigned & value)417330f729Sjoerg static bool parseInt(StringRef &input, unsigned &value) {
427330f729Sjoerg assert(value == 0);
437330f729Sjoerg if (input.empty())
447330f729Sjoerg return true;
457330f729Sjoerg
467330f729Sjoerg char next = input[0];
477330f729Sjoerg input = input.substr(1);
487330f729Sjoerg if (next < '0' || next > '9')
497330f729Sjoerg return true;
507330f729Sjoerg value = (unsigned)(next - '0');
517330f729Sjoerg
527330f729Sjoerg while (!input.empty()) {
537330f729Sjoerg next = input[0];
547330f729Sjoerg if (next < '0' || next > '9')
557330f729Sjoerg return false;
567330f729Sjoerg input = input.substr(1);
577330f729Sjoerg value = value * 10 + (unsigned)(next - '0');
587330f729Sjoerg }
597330f729Sjoerg
607330f729Sjoerg return false;
617330f729Sjoerg }
627330f729Sjoerg
tryParse(StringRef input)637330f729Sjoerg bool VersionTuple::tryParse(StringRef input) {
647330f729Sjoerg unsigned major = 0, minor = 0, micro = 0, build = 0;
657330f729Sjoerg
667330f729Sjoerg // Parse the major version, [0-9]+
677330f729Sjoerg if (parseInt(input, major))
687330f729Sjoerg return true;
697330f729Sjoerg
707330f729Sjoerg if (input.empty()) {
717330f729Sjoerg *this = VersionTuple(major);
727330f729Sjoerg return false;
737330f729Sjoerg }
747330f729Sjoerg
757330f729Sjoerg // If we're not done, parse the minor version, \.[0-9]+
767330f729Sjoerg if (input[0] != '.')
777330f729Sjoerg return true;
787330f729Sjoerg input = input.substr(1);
797330f729Sjoerg if (parseInt(input, minor))
807330f729Sjoerg return true;
817330f729Sjoerg
827330f729Sjoerg if (input.empty()) {
837330f729Sjoerg *this = VersionTuple(major, minor);
847330f729Sjoerg return false;
857330f729Sjoerg }
867330f729Sjoerg
877330f729Sjoerg // If we're not done, parse the micro version, \.[0-9]+
887330f729Sjoerg if (input[0] != '.')
897330f729Sjoerg return true;
907330f729Sjoerg input = input.substr(1);
917330f729Sjoerg if (parseInt(input, micro))
927330f729Sjoerg return true;
937330f729Sjoerg
947330f729Sjoerg if (input.empty()) {
957330f729Sjoerg *this = VersionTuple(major, minor, micro);
967330f729Sjoerg return false;
977330f729Sjoerg }
987330f729Sjoerg
997330f729Sjoerg // If we're not done, parse the micro version, \.[0-9]+
1007330f729Sjoerg if (input[0] != '.')
1017330f729Sjoerg return true;
1027330f729Sjoerg input = input.substr(1);
1037330f729Sjoerg if (parseInt(input, build))
1047330f729Sjoerg return true;
1057330f729Sjoerg
1067330f729Sjoerg // If we have characters left over, it's an error.
1077330f729Sjoerg if (!input.empty())
1087330f729Sjoerg return true;
1097330f729Sjoerg
1107330f729Sjoerg *this = VersionTuple(major, minor, micro, build);
1117330f729Sjoerg return false;
1127330f729Sjoerg }
113