From c85b624d28564a6f785b25000e2b7825592a919d Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Tue, 26 Sep 2017 20:09:31 +0200 Subject: Initial commit --- .gitignore | 1 + meson.build | 48 +++ meson_options.txt | 1 + src/args.cc | 323 +++++++++++++++++++ src/args.hh | 64 ++++ src/clock.cc | 24 ++ src/clock.hh | 13 + src/common.hh | 10 + src/fake_monitor.cc | 191 ++++++++++++ src/fake_monitor.hh | 11 + src/io.cc | 167 ++++++++++ src/io.hh | 87 ++++++ src/looper.cc | 10 + src/looper.hh | 31 ++ src/main.cc | 872 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/monitor.cc | 410 ++++++++++++++++++++++++ src/monitor.hh | 62 ++++ src/poll_looper.cc | 249 +++++++++++++++ src/poll_looper.hh | 15 + src/x.cc | 312 +++++++++++++++++++ src/x.hh | 255 +++++++++++++++ 21 files changed, 3156 insertions(+) create mode 100644 .gitignore create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 src/args.cc create mode 100644 src/args.hh create mode 100644 src/clock.cc create mode 100644 src/clock.hh create mode 100644 src/common.hh create mode 100644 src/fake_monitor.cc create mode 100644 src/fake_monitor.hh create mode 100644 src/io.cc create mode 100644 src/io.hh create mode 100644 src/looper.cc create mode 100644 src/looper.hh create mode 100644 src/main.cc create mode 100644 src/monitor.cc create mode 100644 src/monitor.hh create mode 100644 src/poll_looper.cc create mode 100644 src/poll_looper.hh create mode 100644 src/x.cc create mode 100644 src/x.hh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..c61b6f7 --- /dev/null +++ b/meson.build @@ -0,0 +1,48 @@ +project('monmon', 'cpp', + version: '0.1', + default_options: ['cpp_std=c++11']) + +cpp_optional_flags = ['-fno-rtti', '-fno-exceptions', + '-fvisibility=hidden', + '-Wall', '-Wextra', + '-Wno-missing-field-initializers', + '-Wno-maybe-uninitialized'] +cpp_flags = ['-DHAVE_CONFIG_H'] +if get_option('buildtype') == 'release' + # If asserts are disabled parameters and variables used for only that + # end up causing warnings + cpp_optional_flags += ['-Wno-unused-parameter', '-Wno-unused-variable'] + cpp_flags += '-DNDEBUG' +endif +cpp = meson.get_compiler('cpp') +foreach flag : cpp_optional_flags + if cpp.has_argument(flag) + cpp_flags += flag + endif +endforeach +add_global_arguments(cpp_flags, language: 'cpp') + +conf = configuration_data() +conf.set('VERSION', '"' + meson.project_version() + '"') +conf.set10('FAKE_MONITOR', get_option('fake_monitor')) + +xcb_deps = [dependency('xcb', version : '>= 1.10'), + dependency('xcb-image', version : '>= 0.3.8'), + dependency('xcb-event', version : '>= 0.3.8'), + dependency('xcb-ewmh', version : '>= 0.3.8'), + dependency('xcb-keysyms', version : '>= 0.3.8'), + dependency('xcb-icccm', version : '>= 0.3.8')] +dep_cairo = dependency('cairo-xcb', version : '>= 1.12.0') +dep_pango = dependency('pangocairo', version : '>= 1.40.0') +dep_icecc = dependency('icecc', version : '>= 1.1') +dep_thread = dependency('threads') + +configure_file(output: 'config.h', + configuration: conf) + +executable('monmon', + sources: ['src/main.cc', 'src/x.cc', 'src/args.cc', + 'src/poll_looper.cc', 'src/looper.cc', 'src/clock.cc', + 'src/io.cc', 'src/monitor.cc', 'src/fake_monitor.cc'], + dependencies: [dep_thread, dep_pango, dep_cairo, dep_icecc, + xcb_deps]) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..2331695 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('fake_monitor', type: 'boolean', value: false, description: 'Connect to a fake monitor to keeps generating job events') diff --git a/src/args.cc b/src/args.cc new file mode 100644 index 0000000..9b3e409 --- /dev/null +++ b/src/args.cc @@ -0,0 +1,323 @@ +#include "common.hh" + +#include +#include +#include +#include +#include +#include + +#include "args.hh" + +namespace { + +bool is_space(std::string const& str, size_t offset) { + return str[offset] == ' ' || str[offset] == '\t' || str[offset] == '\n'; +} + +bool is_separator(std::string const& str, size_t offset) { + return !((str[offset] >= '0' && str[offset] <= '9') + || (str[offset] >= 'a' && str[offset] <= 'z') + || (str[offset] >= 'A' && str[offset] <='Z')); +} + +class ArgsImpl : public Args { +public: + ArgsImpl() + : good_(true) { + } + void add(char short_opt, std::string const& long_opt, + std::string const& argument, std::string const& help) override { + assert(short_opt == '\0' || short_opts_.count(short_opt) == 0); + assert(long_opt.empty() || long_opts_.count(long_opt) == 0); + assert(long_opt.find('=') == std::string::npos); + auto const index = opts_.size(); + opts_.push_back(Option(short_opt, long_opt, argument, help)); + if (short_opt != '\0') { + short_opts_.insert(std::make_pair(short_opt, index)); + } + if (!long_opt.empty()) { + long_opts_.insert(std::make_pair(long_opt, index)); + } + } + + bool run(int argc, char** argv, std::ostream& out) override { + if (argc == 0) { + assert(false); + good_ = false; + return false; + } + auto start = strrchr(argv[0], '/'); + if (!start) { + start = argv[0]; + } else { + start++; + } + return run(start, argc, argv, out); + } + + bool run(std::string const& prg, int argc, char** argv, std::ostream& out) + override { + reset(); + + std::string opt; + for (int a = 1; a < argc; ++a) { + if (argv[a][0] == '-') { + if (argv[a][1] == '-') { + if (argv[a][2] == '\0') { + for (++a; a < argc; ++a) { + args_.push_back(argv[a]); + } + return good_; + } + size_t len = 2; + while (argv[a][len] && argv[a][len] != '=') ++len; + opt.assign(argv[a] + 2, len - 2); + auto i = long_opts_.find(opt); + if (i == long_opts_.end()) { + out << prg << ": unrecognized option '--" << opt << "'\n"; + good_ = false; + continue; + } + if (argv[a][len] == '=') { + if (opts_[i->second].argument.empty()) { + out << prg << ": option '--" << opt << "'" + << " doesn't allow an argument\n"; + good_ = false; + continue; + } else { + opts_[i->second].values.push_back(argv[a] + len + 1); + } + } else { + if (opts_[i->second].argument.empty()) { + opts_[i->second].values.push_back(""); + } else if (a + 1 == argc) { + out << prg << ": option '--" << opt << "'" + << " requires an argument\n"; + good_ = false; + continue; + } else { + opts_[i->second].values.push_back(argv[++a]); + } + } + } else { + for (auto opt = argv[a] + 1; *opt; ++opt) { + auto i = short_opts_.find(*opt); + if (i == short_opts_.end()) { + out << prg << ": invalid option -- '" << *opt << "'\n"; + good_ = false; + continue; + } + if (opts_[i->second].argument.empty()) { + opts_[i->second].values.push_back(""); + } else if (a + 1 == argc) { + out << prg << ": option requires an argument " + << " -- '" << *opt << "'\n"; + good_ = false; + continue; + } else { + opts_[i->second].values.push_back(argv[++a]); + } + } + } + } else { + args_.push_back(argv[a]); + } + } + + return good_; + } + bool good() const override { + return good_; + } + + bool is_set(char short_opt) const override { + return count(short_opt) > 0; + } + size_t count(char short_opt) const override { + auto i = short_opts_.find(short_opt); + if (i == short_opts_.end()) return 0; + return opts_[i->second].values.size(); + } + + bool is_set(std::string const& long_opt) const override { + return count(long_opt) > 0; + } + size_t count(std::string const& long_opt) const override { + auto i = long_opts_.find(long_opt); + if (i == long_opts_.end()) return 0; + return opts_[i->second].values.size(); + } + + char const* arg(char short_opt, char const* fallback) const override { + auto i = short_opts_.find(short_opt); + if (i == short_opts_.end()) return fallback; + if (opts_[i->second].values.empty()) return fallback; + if (opts_[i->second].argument.empty()) return fallback; + return opts_[i->second].values.back().c_str(); + } + + char const* arg(std::string const& long_opt, + char const* fallback) const override { + auto i = long_opts_.find(long_opt); + if (i == long_opts_.end()) return fallback; + if (opts_[i->second].values.empty()) return fallback; + if (opts_[i->second].argument.empty()) return fallback; + return opts_[i->second].values.back().c_str(); + } + + bool args(char short_opt, std::vector* out) const override { + auto i = short_opts_.find(short_opt); + if (i == short_opts_.end()) return false; + if (opts_[i->second].values.empty()) return false; + if (opts_[i->second].argument.empty()) return false; + if (out) { + *out = opts_[i->second].values; + } + return true; + } + + bool args(std::string const& long_opt, + std::vector* out) const override { + auto i = long_opts_.find(long_opt); + if (i == long_opts_.end()) return false; + if (opts_[i->second].values.empty()) return false; + if (opts_[i->second].argument.empty()) return false; + if (out) { + *out = opts_[i->second].values; + } + return true; + } + + std::vector const& arguments() const override { + return args_; + } + + void print_help(std::ostream& out) const override { + struct winsize size; + memset(&size, 0, sizeof(size)); + ioctl(STDOUT_FILENO, TIOCGWINSZ, &size); + if (size.ws_col == 0) { + print_help(out, 80); + } else { + print_help(out, size.ws_col); + } + } + + void print_help(std::ostream& out, size_t width) const override { + size_t left = 0; + for (auto const& opt : opts_) { + size_t l = 0; + if (!opt.long_opt.empty()) { + l += 6 + opt.long_opt.size(); + } else if (opt.short_opt != '\0') { + l += 2; + } else { + continue; + } + if (!opt.argument.empty()) { + l += 1 + opt.argument.size(); + } + if (l > left) left = l; + } + + size_t const need = 2 + 2 + left; + if (need + 10 > width) { + width = need + 10; + } + size_t const right = width - need; + + for (auto const& opt : opts_) { + size_t i = 0; + if (!opt.long_opt.empty()) { + if (opt.short_opt != '\0') { + out << " -" << opt.short_opt << ", "; + } else { + out << " "; + } + out << "--" << opt.long_opt; + i += 8 + opt.long_opt.size(); + } else if (opt.short_opt != '\0') { + out << " -" << opt.short_opt; + i += 4; + } else { + continue; + } + if (!opt.argument.empty()) { + out << '=' << opt.argument; + i += 1 + opt.argument.size(); + } + pad(out, need - i); + if (opt.help.size() < right) { + out << opt.help << '\n'; + } else { + i = right; + while (i > 0 && !is_separator(opt.help, i)) --i; + if (i == 0) i = right; + out << opt.help.substr(0, i) << '\n'; + while (true) { + while (i < opt.help.size() && is_space(opt.help, i)) ++i; + if (i == opt.help.size()) break; + size_t j = right - 2; + pad(out, width - j); + if (i + j >= opt.help.size()) { + out << opt.help.substr(i) << '\n'; + break; + } + while (j > 0 && !is_separator(opt.help, i + j)) --j; + if (j == 0) j = right - 2; + out << opt.help.substr(i, j) << '\n'; + i += j; + } + } + } + } + +private: + struct Option { + char const short_opt; + std::string const long_opt; + std::string const argument; + std::string const help; + + std::vector values; + + Option(char short_opt, std::string const& long_opt, + std::string const& argument, std::string const& help) + : short_opt(short_opt), long_opt(long_opt), argument(argument), + help(help) { + } + }; + bool good_; + std::unordered_map short_opts_; + std::unordered_map long_opts_; + std::vector