📄 cdlcore.hxx
字号:
//}}}//{{{ Cdl class // ---------------------------------------------------------------------------// The sole purpose of this class is to provide some utility functions with// reasonable namespace protection, without requiring that the compiler// implements namespaces.class Cdl { public: static bool is_valid_value_flavor(CdlValueFlavor); static bool is_valid_value_source(CdlValueSource); static bool is_valid_cdl_name(const std::string&); static bool is_valid_c_preprocessor_symbol(const std::string&); static bool string_to_integer(std::string, cdl_int&); static bool string_to_double(std::string, double&); static bool string_to_bool(std::string, bool&); static void integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default); static std::string integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default); static void double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default); static std::string double_to_string(double, CdlValueFormat = CdlValueFormat_Default); static void bool_to_string(bool, std::string&); static std::string bool_to_string(bool); static void integer_to_double(cdl_int, double&); static double integer_to_double(cdl_int); static bool double_to_integer(double, cdl_int&); static bool string_to_flavor(std::string, CdlValueFlavor&); static bool flavor_to_string(CdlValueFlavor, std::string&); static bool string_to_source(std::string, CdlValueSource&); static bool source_to_string(CdlValueSource, std::string&); static std::string get_library_version(); static void set_interactive(bool = true); static bool is_interactive(); static bool truth() { return true; } static bool falsehood() { return false; } // return values are -1,0,1 just like strcmp(). The most recent // version is the smallest. static int compare_versions(std::string, std::string); // Also provide an STL-friendly comparison class class version_cmp { public: bool operator()(const std::string& v1, const std::string& v2) const { return Cdl::compare_versions(v1,v2) < 0; } }; // It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL // and turn it into a short form, i.e. kernel. static std::string get_short_form(const std::string&); private: static bool interactive;};//}}}//{{{ CdlInterpreter class // ----------------------------------------------------------------------------// libcdl requires access to a Tcl interpreter. For now the standard// interpreter is used. In the long run it may be better to use a// custom parser in places, if only to improve the diagnostics messages// that users see.//// Consider the case of software CDL (other CDL variants will have// similar requirements). A Tcl interpreter is needed to read in the// data for a given package. It will also be needed at various stages// when the data is being manipulated, e.g. to display a custom dialog// or to execute e.g. a check_proc or a define_proc. Each package// should run in its own safe interpreter with limited capabilities:// file I/O is limited to read-only, but read-write in the build and// install trees; network I/O is out of the question, at least until// appropriate security support is added to the CDL language itself.// However the interpreter should be extended with additional commands// like cdl_get and cdl_set to access the configuration data.//// For security and robustness reasons it is desirable to have// separate interpreters for the various packages. This leads to the// concept of a master interpreter for the entire configuration, and a// group of slave interpreters, one per package. In this model it// is convenient to have the configuration and package entities// associated directly with the interpreter. Note that a single// application may have several configurations loaded in memory,// so there may be several master interpreters.//// Some applications will want to support the graphical side of CDL,// i.e. custom dialogs and wizards. This means linking in Tk, not to// mention X11 (or the Windows equivalents), and making some/all of// the Tk commands available to the safe interpreter. Arguably// commands like toplevel should always be disabled. Not all clients// of libcdl will want the overheads of linking with Tk and X, so this// has to be made optional.//// The approach taken is as follows://// 1) there is a class CdlInterpreter which provides access to Tcl// interpreters. Amongst other things it takes care of converting// between C and C++ strings.//// 2) every toplevel needs its own CdlInterpreter. The application// code should supply this interpreter itself when the toplevel// is instantiated, allowing it to decide whether or not Tk should// be available.//// 3) each loadable gets its own safe slave interpreter, derived from// the toplevel's interpreter.// NOTE: initially the slave interpreters are not actually safe. It// is not clear in the long term to what extent per-loadable// interpreters need to be sandboxes, there are issues such as// doing the equivalent of autoconf tests.class CdlInterpreterBody{ friend class CdlTest; public: CYGDBG_DECLARE_MEMLEAK_COUNTER(); // This is how a top-level (i.e. per-toplevel) interpreter // should get created. static CdlInterpreter make(Tcl_Interp* = 0); // Create a slave interpreter for reading in the data in e.g. a // cdl_package CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true); // Make the interpreter safe, a one-way operation. void make_safe(); // The destructor is public. virtual ~CdlInterpreterBody(); // Add or remove commands from an interpreter. This provides // a more C++-friendly implementation of Tcl's // CreateCommand() and DeleteCommand(). void add_command(std::string, CdlInterpreterCommand); void remove_command(std::string); // In the libcdl world it is also convenient to swap whole sets of // commands in and out. This is achieved by push and pop operations. // push returns the old set (0 at the toplevel). pop restores // the old set. std::vector<CdlInterpreterCommandEntry>* push_commands(std::vector<CdlInterpreterCommandEntry>&); void pop_commands(std::vector<CdlInterpreterCommandEntry>*); std::vector<CdlInterpreterCommandEntry>* get_pushed_commands() const; // Similarly, allow variables to be set, unset and queried void set_variable(std::string, std::string); void unset_variable(std::string); std::string get_variable(std::string); // FIXME: add support for variable traces. These are needed // for cdl_value and similar utilities. // Provide hooks into the AssocData() facilities associated with // Tcl interpreters. This makes it possible to store arbitrary // data with an interpreter, e.g. to keep track of current state. void set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0); void delete_assoc_data(const char*); ClientData get_assoc_data(const char*); // Evaluate a string as Tcl code. The return value comes from Tcl, e.g. // TCL_OK or TCL_ERROR. The result string is also available. int eval(std::string, std::string&); // Ditto for any Tcl code that comes from CDL files int eval_cdl_code(const cdl_tcl_code, std::string&); // And support for evaluating an entire file int eval_file(std::string, std::string&); // For use by commands implemented in C++, a way of setting the result void set_result(std::string); // And a utility to get the result as well. This is useful for e.g. // Tcl_OpenFileChannel which leaves a result string in the interpreter std::string get_result(); // A utility to quote data that is going to end up in a TCL script. static std::string quote(std::string); // Turn some multiline data into a comment. static std::string multiline_comment(const std::string&, int, int = 0); // Add some data to a comment, allowing for newlines if necessary static std::string extend_comment(const std::string&, int, int = 0); // Write some data to a savefile, throwing an exception on error void write_data(Tcl_Channel, std::string) throw(CdlInputOutputException); // File-related utilities. void locate_subdirs(std::string, std::vector<std::string>&); void locate_all_subdirs(std::string, std::vector<std::string>&); void locate_files(std::string, std::vector<std::string>&); void locate_all_files(std::string, std::vector<std::string>&); bool is_directory(std::string); bool is_file(std::string); // When parsing a CDL script it is convenient to keep track of // a number of items: // // 1) the toplevel, e.g. the entire configuration // 2) the loadable, e.g. the current package // 3) the parent of whatever is being processed at the moment // 4) the entity, i.e. the thingamajig that is being processed. // 5) the current file // 6) an error reporting function // // This gives the various commands embedded in the Tcl interpreter // enough information to do their job. Additional information can // be provided via assoc_data() // // There should be only one call to set_toplevel(), for the // master interpreter. All slaves inherit this, and the toplevel // cannot be changed again. // // The loadable field is filled in via make_slave() // // For some members push and pop functions are more appropriate // than set. CdlToplevel get_toplevel() const; CdlLoadable get_loadable() const; CdlContainer get_container() const; CdlNode get_node() const; std::string get_filename() const; CdlDiagnosticFnPtr get_error_fn_ptr() const; CdlDiagnosticFnPtr get_warning_fn_ptr() const; CdlTransaction get_transaction() const; void set_toplevel(CdlToplevel); void set_transaction(CdlTransaction); CdlContainer push_container(CdlContainer); void pop_container(CdlContainer); CdlNode push_node(CdlNode); void pop_node(CdlNode); std::string push_filename(std::string); void pop_filename(std::string); CdlDiagnosticFnPtr push_error_fn_ptr(CdlDiagnosticFnPtr); void pop_error_fn_ptr(CdlDiagnosticFnPtr); CdlDiagnosticFnPtr push_warning_fn_ptr(CdlDiagnosticFnPtr); void pop_warning_fn_ptr(CdlDiagnosticFnPtr); // Some command implementations may want to access other Tcl library // routines such as Tcl_SplitList(). This requires convenient access // to the underlying Tcl interpreter. Tcl_Interp* get_tcl_interpreter() const; // For use by the assertion macros. bool check_this(cyg_assert_class_zeal = cyg_quick) const; private: // This is the Tcl command proc that gets registered for all // CdlInterpreterCommand instances. static int tcl_command_proc(ClientData, Tcl_Interp*, int, char*[]); // This key is used to access the CdlInterpreter assoc data. static char* cdlinterpreter_assoc_data_key; // Do not allow static instances of a Cdl interpreter. There are too // many possible failure conditions. Cdl interpreters can only be // created dynamically via make(), which will invoke this. CdlInterpreterBody(Tcl_Interp*); // Default constructor, copy constructor and assignment are illegal CdlInterpreterBody(); CdlInterpreterBody(const CdlInterpreterBody&); CdlInterpreterBody& operator=(const CdlInterpreterBody&); Tcl_Interp* tcl_interp; // The underlying Tcl interpreter bool owns_interp; // Was the Tcl interpreter created by the library? std::vector<CdlInterpreter> slaves; // All slave interpreters CdlInterpreter parent; // Or else the parent CdlToplevel toplevel; // Data that gets used during the parsing process CdlTransaction transaction; CdlLoadable loadable; CdlContainer container; CdlNode node; std::string filename; CdlDiagnosticFnPtr error_fn_ptr; CdlDiagnosticFnPtr warning_fn_ptr; std::vector<CdlInterpreterCommandEntry>* current_commands; // for push() and pop() enum { CdlInterpreterBody_Invalid = 0, CdlInterpreterBody_Magic = 0x0be67689 } cdlinterpreterbody_cookie;};//}}}//{{{ CdlReference/Referrer classes // ---------------------------------------------------------------------------// CDL objects are organised primarily in a tree hierarchy. For// example a package contains components, components contain options,// and so on. The tree hierarchy tends to change rather infrequently,// so it makes sense to have a quick way of navigating between// entities without continuously having to do hash-table lookups. In// addition it is very desirable to make the connectivity
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -