Files
Giacomo Vercesi 79272adc9d CLI: check that FilePaths are actually files
Add checks that return an `llvm::Error` in case a provided path is a
directory in the case a `FilePath` was requested.
2025-05-07 16:42:34 +02:00

102 lines
2.6 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/Storage/Path.h"
namespace revng {
/// This enum is used to allow specifying via cl::init if the path should have
/// stdin/stdout as the default value.
enum class PathInit {
None,
Dash
};
namespace detail {
/// Utility class similar to std::optional, to be used as a llvm::cl::opt.
/// The DashGenerator template parameter dictates the Path that will be used
/// when the path '-' or cl::init(PathInit::Dash) are used
template<FilePath (*DashGenerator)()>
struct PathImpl {
private:
std::optional<revng::FilePath> Path;
public:
PathImpl() = default;
void setDash() { Path = DashGenerator(); }
void parse(llvm::StringRef Value) {
if (Value == "-")
Path = DashGenerator();
else
Path = FilePath::fromLocalStorage(Value);
}
llvm::Expected<std::optional<const revng::FilePath>> get() const {
if (not Path.has_value())
return std::nullopt;
if (llvm::Error Error = Path->check())
return Error;
return *Path;
}
};
/// cl::parser specialization to be used in conjunction with PathImpl, will call
/// PathImpl::parse given the input string from the command-line.
template<FilePath (*DashGenerator)()>
class PathImplParser : public llvm::cl::parser<PathImpl<DashGenerator>> {
public:
using llvm::cl::parser<PathImpl<DashGenerator>>::parser;
bool parse(llvm::cl::Option &Option,
llvm::StringRef ArgName,
const llvm::StringRef ArgValue,
PathImpl<DashGenerator> &Val) {
Val.parse(ArgValue);
return false;
}
};
template<FilePath (*DG)()>
using PathImplOpt = llvm::cl::opt<PathImpl<DG>, false, PathImplParser<DG>>;
} // namespace detail
// cl::opts for input and output revng::FilePaths
using InputPathOpt = detail::PathImplOpt<FilePath::stdin>;
using OutputPathOpt = detail::PathImplOpt<FilePath::stdout>;
} // namespace revng
namespace llvm::cl {
// These 'apply' specializations are needed to allow using cl::init(PathInit)
// with the {Input,Output}PathOpt.
template<>
inline void
apply<revng::InputPathOpt,
initializer<revng::PathInit>>(revng::InputPathOpt *O,
const initializer<revng::PathInit> &M) {
if (M.Init == revng::PathInit::Dash)
O->setDash();
}
template<>
inline void
apply<revng::OutputPathOpt,
initializer<revng::PathInit>>(revng::OutputPathOpt *O,
const initializer<revng::PathInit> &M) {
if (M.Init == revng::PathInit::Dash)
O->setDash();
}
} // namespace llvm::cl