| return c; | return c; | ||||
| } | } | ||||
| int BXParser::peek() { | |||||
| return buf_.peek(); | |||||
| } | |||||
| int BXParser::peek2() { | |||||
| return buf_.peek2(); | |||||
| } | |||||
| BXParser::Operator BXParser::readOperator() { | BXParser::Operator BXParser::readOperator() { | ||||
| int ch2 = peek2(); | |||||
| int ch2 = peek(2); | |||||
| if (peek() == ':' && ch2 == '=') { | if (peek() == ':' && ch2 == '=') { | ||||
| skip(); // ':' | skip(); // ':' | ||||
| skip(); // '=' | skip(); // '=' | ||||
| break; | break; | ||||
| default: | default: | ||||
| if (ch == ':' && peek2() == '=') | |||||
| if (ch == ':' && peek(2) == '=') | |||||
| return success; | return success; | ||||
| content.push_back(get()); | content.push_back(get()); |
| static const int FLAG_NONE = 0; | static const int FLAG_NONE = 0; | ||||
| static const int FLAG_ONE_LINE = 1 << 0; | static const int FLAG_ONE_LINE = 1 << 0; | ||||
| BXParser(std::istream &stream, int flags, int line = 1, int ch = 1): | |||||
| BXParser(bufio::IStream &stream, int flags, int line = 1, int ch = 1): | |||||
| flags_(flags), line_(line), ch_(ch), buf_(stream) {} | flags_(flags), line_(line), ch_(ch), buf_(stream) {} | ||||
| void parse(BXVariables &vars); | void parse(BXVariables &vars); | ||||
| void parseList(const BXVariables &vars, std::vector<std::string> &values); | void parseList(const BXVariables &vars, std::vector<std::string> &values); | ||||
| int get(); | int get(); | ||||
| int peek(); | |||||
| int peek2(); | |||||
| int peek(size_t count = 1) { return buf_.peek(count); } | |||||
| void skip(char expected); | void skip(char expected); | ||||
| void skip() { get(); } | void skip() { get(); } | ||||
| class BXWriter { | class BXWriter { | ||||
| public: | public: | ||||
| BXWriter(std::ostream &stream): buf_(stream) {} | |||||
| BXWriter(bufio::OStream &stream): buf_(stream) {} | |||||
| void write(const BXVariables &vars); | void write(const BXVariables &vars); | ||||
| BXVariables cachedVariables; | BXVariables cachedVariables; | ||||
| try { | try { | ||||
| std::ifstream f = sys::ifstream(confPath); | |||||
| bufio::IFStream f(confPath); | |||||
| BXParser parser(f, BXParser::FLAG_NONE); | BXParser parser(f, BXParser::FLAG_NONE); | ||||
| parser.parse(cachedVariables); | parser.parse(cachedVariables); | ||||
| } catch (BXParseError &err) { | } catch (BXParseError &err) { | ||||
| sys::mkdirp(dirPath); | sys::mkdirp(dirPath); | ||||
| std::ofstream f = sys::ofstream(confPath(outDir)); | |||||
| bufio::OFStream f(confPath(outDir)); | |||||
| BXWriter writer(f); | BXWriter writer(f); | ||||
| writer.write(newCachedVars); | writer.write(newCachedVars); | ||||
| return variables_; | return variables_; | ||||
| } | } | ||||
| std::ifstream f = sys::ifstream(path_); | |||||
| bufio::IFStream f(path_); | |||||
| BXParser parser(f, BXParser::FLAG_ONE_LINE); | BXParser parser(f, BXParser::FLAG_ONE_LINE); | ||||
| while (f.good()) { | |||||
| while (parser.peek() != EOF) { | |||||
| if (startsWith(parser, "//#bx")) { | if (startsWith(parser, "//#bx")) { | ||||
| parser.parse(variables_); | parser.parse(variables_); | ||||
| } else { | } else { | ||||
| while (f.good() && parser.get() != '\n'); | |||||
| while (parser.peek() != EOF && parser.get() != '\n'); | |||||
| } | } | ||||
| } | } | ||||
| BXVariables cachedVariables; | BXVariables cachedVariables; | ||||
| try { | try { | ||||
| std::ifstream f = sys::ifstream(confPath); | |||||
| bufio::IFStream f(confPath); | |||||
| BXParser parser(f, BXParser::FLAG_NONE); | BXParser parser(f, BXParser::FLAG_NONE); | ||||
| parser.parse(cachedVariables); | parser.parse(cachedVariables); | ||||
| } catch (BXParseError &err) { | } catch (BXParseError &err) { | ||||
| { "command", command}, | { "command", command}, | ||||
| }; | }; | ||||
| std::ofstream f = sys::ofstream(confPath(outDir)); | |||||
| bufio::OFStream f(confPath(outDir)); | |||||
| BXWriter writer(f); | BXWriter writer(f); | ||||
| writer.write(newCachedVars); | writer.write(newCachedVars); | ||||
| #pragma once | #pragma once | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <fstream> | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| namespace bufio { | namespace bufio { | ||||
| class IStream { | |||||
| public: | |||||
| virtual size_t read(char *buf, size_t maxlen) = 0; | |||||
| }; | |||||
| class IFStream: public IStream { | |||||
| public: | |||||
| IFStream(const char *path); | |||||
| IFStream(const std::string &path): IFStream(path.c_str()) {} | |||||
| size_t read(char *buf, size_t maxlen) override; | |||||
| private: | |||||
| std::ifstream is_; | |||||
| }; | |||||
| class ISStream: public IStream { | |||||
| public: | |||||
| ISStream(const std::string &str): str_(str) {} | |||||
| size_t read(char *buf, size_t maxlen) override; | |||||
| private: | |||||
| size_t idx_ = 0; | |||||
| const std::string &str_; | |||||
| }; | |||||
| class OStream { | |||||
| public: | |||||
| virtual void write(const char *buf, size_t len) = 0; | |||||
| }; | |||||
| class OFStream: public OStream { | |||||
| public: | |||||
| OFStream(const char *path); | |||||
| OFStream(const std::string &path): OFStream(path.c_str()) {} | |||||
| void write(const char *buf, size_t len) override; | |||||
| private: | |||||
| std::ofstream os_; | |||||
| }; | |||||
| template<size_t bufsiz = 1024> | template<size_t bufsiz = 1024> | ||||
| class IBuf { | class IBuf { | ||||
| public: | public: | ||||
| IBuf(std::istream &is): is_(is) {} | |||||
| IBuf(IStream &is): is_(is) {} | |||||
| char get(); | char get(); | ||||
| int peek(); | |||||
| int peek2(); | |||||
| int peek(size_t count = 1); | |||||
| private: | private: | ||||
| std::istream &is_; | |||||
| IStream &is_; | |||||
| char buf_[bufsiz]; | char buf_[bufsiz]; | ||||
| size_t idx_ = 0; | size_t idx_ = 0; | ||||
| size_t len_ = 0; | size_t len_ = 0; | ||||
| template<size_t bufsiz = 1024> | template<size_t bufsiz = 1024> | ||||
| class OBuf { | class OBuf { | ||||
| public: | public: | ||||
| OBuf(std::ostream &os): os_(os) {} | |||||
| OBuf(OStream &os): os_(os) {} | |||||
| ~OBuf(); | ~OBuf(); | ||||
| void put(char ch); | void put(char ch); | ||||
| void put(const std::string &str) { put(str.c_str(), str.size()); } | void put(const std::string &str) { put(str.c_str(), str.size()); } | ||||
| private: | private: | ||||
| std::ostream &os_; | |||||
| OStream &os_; | |||||
| char buf_[bufsiz]; | char buf_[bufsiz]; | ||||
| size_t idx_ = 0; | size_t idx_ = 0; | ||||
| }; | }; | ||||
| /* | |||||
| * IFStream | |||||
| */ | |||||
| inline IFStream::IFStream(const char *path) { | |||||
| is_.exceptions(std::ifstream::badbit); | |||||
| is_.open(path); | |||||
| if (!is_.good()) { | |||||
| throw std::system_error(errno, std::generic_category(), path); | |||||
| } | |||||
| } | |||||
| inline size_t IFStream::read(char *buf, size_t maxlen) { | |||||
| is_.read(buf, maxlen); | |||||
| return is_.gcount(); | |||||
| } | |||||
| /* | |||||
| * ISStream | |||||
| */ | |||||
| inline size_t ISStream::read(char *buf, size_t maxlen) { | |||||
| size_t left = str_.size() - idx_; | |||||
| size_t len = maxlen < left ? maxlen : left; | |||||
| idx_ += len; | |||||
| memcpy(buf, str_.c_str(), len); | |||||
| return len; | |||||
| } | |||||
| /* | |||||
| * OFStream | |||||
| */ | |||||
| inline OFStream::OFStream(const char *path) { | |||||
| os_.exceptions(std::ofstream::badbit); | |||||
| os_.open(path); | |||||
| if (!os_.good()) { | |||||
| throw std::system_error(errno, std::generic_category(), path); | |||||
| } | |||||
| } | |||||
| inline void OFStream::write(const char *buf, size_t len) { | |||||
| os_.write(buf, len); | |||||
| } | |||||
| /* | /* | ||||
| * IBuf | * IBuf | ||||
| */ | */ | ||||
| } | } | ||||
| idx_ = 0; | idx_ = 0; | ||||
| is_.read(buf_, sizeof(buf_)); | |||||
| len_ = is_.gcount(); | |||||
| len_ = is_.read(buf_, sizeof(buf_)); | |||||
| if (len_ == 0) { | if (len_ == 0) { | ||||
| return EOF; | return EOF; | ||||
| } | } | ||||
| } | } | ||||
| template<size_t bufsiz> | template<size_t bufsiz> | ||||
| inline int IBuf<bufsiz>::peek() { | |||||
| if (idx_ < len_) { | |||||
| return buf_[idx_]; | |||||
| inline int IBuf<bufsiz>::peek(size_t count) { | |||||
| size_t offset = count - 1; | |||||
| if (idx_ + offset < len_) { | |||||
| return buf_[idx_ + offset]; | |||||
| } else { | } else { | ||||
| return is_.peek(); | |||||
| } | |||||
| } | |||||
| len_ -= idx_; | |||||
| memcpy(buf_, buf_ + idx_, len_); | |||||
| idx_ = 0; | |||||
| len_ += is_.read(buf_ + len_, sizeof(buf_) - len_); | |||||
| if (len_ <= offset) { | |||||
| return EOF; | |||||
| } | |||||
| template<size_t bufsiz> | |||||
| inline int IBuf<bufsiz>::peek2() { | |||||
| if (idx_ + 1 < len_) { | |||||
| return buf_[idx_ + 1]; | |||||
| } else if (idx_ < len_) { | |||||
| return is_.peek(); | |||||
| } else { | |||||
| is_.get(); | |||||
| int ch = is_.peek(); | |||||
| is_.unget(); | |||||
| return ch; | |||||
| return buf_[idx_ + offset]; | |||||
| } | } | ||||
| } | } | ||||
| subvars = variables; | subvars = variables; | ||||
| varsptr = &subvars; | varsptr = &subvars; | ||||
| std::ifstream stream = sys::ifstream("build.bx"); | |||||
| bufio::IFStream stream("build.bx"); | |||||
| BXParser parser(stream, BXParser::FLAG_NONE); | BXParser parser(stream, BXParser::FLAG_NONE); | ||||
| parser.parse(subvars); | parser.parse(subvars); | ||||
| std::unique_ptr<DepNode> buildDepTree(const std::string &outDir, BXVariables variables) { | std::unique_ptr<DepNode> buildDepTree(const std::string &outDir, BXVariables variables) { | ||||
| // Read config from file | // Read config from file | ||||
| if (sys::fileExists("build.bx")) { | if (sys::fileExists("build.bx")) { | ||||
| std::ifstream stream = sys::ifstream("build.bx"); | |||||
| bufio::IFStream stream("build.bx"); | |||||
| BXParser parser(stream, BXParser::FLAG_NONE); | BXParser parser(stream, BXParser::FLAG_NONE); | ||||
| parser.parse(variables); | parser.parse(variables); | ||||
| } | } |
| class Writer { | class Writer { | ||||
| public: | public: | ||||
| Writer(std::ostream &stream): buf_(stream) {} | |||||
| Writer(bufio::OStream &stream): buf_(stream) {} | |||||
| ~Writer(); | ~Writer(); | ||||
| void write( | void write( |
| auto buildVariables = [&]() -> BXVariables { | auto buildVariables = [&]() -> BXVariables { | ||||
| BXVariables variables; | BXVariables variables; | ||||
| if (sys::fileExists(path + "/.config.bx")) { | if (sys::fileExists(path + "/.config.bx")) { | ||||
| std::ifstream f = sys::ifstream(path + "/.config.bx"); | |||||
| bufio::IFStream f(path + "/.config.bx"); | |||||
| BXParser parser(f, BXParser::FLAG_NONE); | BXParser parser(f, BXParser::FLAG_NONE); | ||||
| parser.parse(variables); | parser.parse(variables); | ||||
| } | } | ||||
| for (auto &pair: kwargs) { | for (auto &pair: kwargs) { | ||||
| std::stringstream ss(pair.second); | |||||
| bufio::ISStream ss(pair.second); | |||||
| BXParser parser(ss, BXParser::FLAG_NONE); | BXParser parser(ss, BXParser::FLAG_NONE); | ||||
| auto &list = variables[pair.first]; | auto &list = variables[pair.first]; | ||||
| list.clear(); | list.clear(); | ||||
| } | } | ||||
| if (kwargs.size() > 0) { | if (kwargs.size() > 0) { | ||||
| std::ofstream f = sys::ofstream(path + "/.config.bx"); | |||||
| bufio::OFStream f(path + "/.config.bx"); | |||||
| BXWriter w(f); | BXWriter w(f); | ||||
| w.write(variables); | w.write(variables); | ||||
| } | } | ||||
| }; | }; | ||||
| auto buildCompileCommands = [&](DepNode &root) { | auto buildCompileCommands = [&](DepNode &root) { | ||||
| std::ofstream f = sys::ofstream(path + "/compile_commands.json"); | |||||
| bufio::OFStream f(path + "/compile_commands.json"); | |||||
| compdb::Writer w(f); | compdb::Writer w(f); | ||||
| root.writeCompDB(path, w); | root.writeCompDB(path, w); | ||||
| sys::symlink(path + "/compile_commands.json", "compile_commands.json"); | sys::symlink(path + "/compile_commands.json", "compile_commands.json"); | ||||
| sys::rmrf(path); | sys::rmrf(path); | ||||
| sys::rmrf("compile_commands.json"); | sys::rmrf("compile_commands.json"); | ||||
| sys::mkdirp(path); | sys::mkdirp(path); | ||||
| std::ofstream f = sys::ofstream(path + "/.config.bx"); | |||||
| bufio::OFStream f(path + "/.config.bx"); | |||||
| BXWriter w(f); | BXWriter w(f); | ||||
| w.write(variables); | w.write(variables); | ||||
| return std::string(dir); | return std::string(dir); | ||||
| } | } | ||||
| std::ofstream ofstream(const std::string &path) { | |||||
| std::ofstream f; | |||||
| f.exceptions(std::ofstream::badbit); | |||||
| f.open(path); | |||||
| if (!f.good()) { | |||||
| throw std::system_error(errno, std::generic_category(), path); | |||||
| } | |||||
| return f; | |||||
| } | |||||
| std::ifstream ifstream(const std::string &path) { | |||||
| std::ifstream f; | |||||
| f.exceptions(std::ifstream::badbit); | |||||
| f.open(path); | |||||
| if (!f.good()) { | |||||
| throw std::system_error(errno, std::generic_category(), path); | |||||
| } | |||||
| return f; | |||||
| } | |||||
| } | } |
| void symlink(const std::string &from, const std::string &to); | void symlink(const std::string &from, const std::string &to); | ||||
| std::string dirname(const std::string &path); | std::string dirname(const std::string &path); | ||||
| std::ofstream ofstream(const std::string &path); | |||||
| std::ifstream ifstream(const std::string &path); | |||||
| } | } |