📄 interp.cxx
字号:
}//}}}//{{{ CdlInterpreter:: variables // ----------------------------------------------------------------------------// Provide some more stubs, this time for accessing Tcl global variables.voidCdlInterpreterBody::set_variable(std::string name, std::string value){ CYG_REPORT_FUNCNAME("CdlInterpreter::set_variable"); CYG_REPORT_FUNCARG2("this %p, name %s", this, name.c_str()); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != name); if (0 == Tcl_SetVar(tcl_interp, const_cast<char*>(name.c_str()), const_cast<char*>(value.c_str()), TCL_GLOBAL_ONLY)) { throw std::bad_alloc(); } CYG_REPORT_RETURN();}voidCdlInterpreterBody::unset_variable(std::string name){ CYG_REPORT_FUNCNAME("CdlInterpreter::unset_variable"); CYG_REPORT_FUNCARG2("this %p, name %s", this, name.c_str()); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != name); Tcl_UnsetVar(tcl_interp, const_cast<char*>(name.c_str()), TCL_GLOBAL_ONLY); CYG_REPORT_RETURN();}std::stringCdlInterpreterBody::get_variable(std::string name){ CYG_REPORT_FUNCNAME("CdlInterpreter::get_variable"); CYG_REPORT_FUNCARG2("this %p, name %s", this, name.c_str()); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != name); std::string result = ""; char *tmp = Tcl_GetVar(tcl_interp, const_cast<char*>(name.c_str()), TCL_GLOBAL_ONLY); if (0 != tmp) { result = tmp; } CYG_REPORT_RETURN(); return result;}//}}}//{{{ CdlInterpreter:: assoc data // ----------------------------------------------------------------------------// Associated data. It is useful to be able to store some C++ data with// Tcl interpreters, so that the implementations of various commands// can retrieve details of the current state. Tcl provides the necessary// underlying support via routines Tcl_SetAssocData() etc., and the// routines here are just stubs for the underlying Tcl ones.voidCdlInterpreterBody::set_assoc_data(const char* key, ClientData data, Tcl_InterpDeleteProc* del_proc){ CYG_REPORT_FUNCNAME("CdlInterpreter::set_assoc_data"); CYG_REPORT_FUNCARG3("this %p, key %s, data %p", this, key, data); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC((0 != key) && ('\0' != key[0])); Tcl_SetAssocData(tcl_interp, const_cast<char*>(key), del_proc, data); CYG_REPORT_RETURN();}ClientDataCdlInterpreterBody::get_assoc_data(const char* key){ CYG_REPORT_FUNCNAMETYPE("CdlInterpreter::get_assoc_data", "result %p"); CYG_REPORT_FUNCARG2("this %p, key %s", this, key); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC((0 != key) && ('\0' != key[0])); ClientData result = Tcl_GetAssocData(tcl_interp, const_cast<char*>(key), 0); CYG_REPORT_RETVAL(result); return result;}voidCdlInterpreterBody::delete_assoc_data(const char* key){ CYG_REPORT_FUNCNAME("CdlInterpreter::delete_assoc_data"); CYG_REPORT_FUNCARG2("this %p, key %s", this, key); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC((0 != key) && ('\0' != key[0])); Tcl_DeleteAssocData(tcl_interp, const_cast<char*>(key)); CYG_REPORT_RETURN();}//}}}//{{{ CdlInterpreter:: file I/O // ----------------------------------------------------------------------------// Tcl provides file I/O facilities that are already known to be portable// to the platforms of interest.boolCdlInterpreterBody::is_directory(std::string name){ CYG_REPORT_FUNCNAMETYPE("CdlInterpreter::is_directory", "result %d"); CYG_REPORT_FUNCARG1XV(this); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != name); bool result = false; std::string command = "file isdirectory \"" + name + "\""; std::string tcl_result; if ((TCL_OK == this->eval(command, tcl_result)) && ("1" == tcl_result)) { result = true; } CYG_REPORT_RETVAL(result); return result;}boolCdlInterpreterBody::is_file(std::string name){ CYG_REPORT_FUNCNAMETYPE("CdlInterpreter::is_file", "result %d"); CYG_REPORT_FUNCARG1XV(this); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != name); bool result = false; std::string command = "file isfile \"" + name + "\""; std::string tcl_result; if ((TCL_OK == this->eval(command, tcl_result)) && ("1" == tcl_result)) { result = true; } CYG_REPORT_RETVAL(result); return result;}// ----------------------------------------------------------------------------voidCdlInterpreterBody::locate_subdirs(std::string directory, std::vector<std::string>& result){ CYG_REPORT_FUNCNAME("CdlInterpreter::locate_subdirs"); CYG_REPORT_FUNCARG2XV(this, &result); CYG_PRECONDITION_THISC(); static char locate_subdirs_script[] = "\set pattern [file join \"$::cdl_locate_subdirs_path\" * .] \n\set result {} \n\foreach entry [glob -nocomplain -- $pattern] { \n\ set entry [file tail [file dirname $entry]] \n\ if {$entry != \"CVS\"} { \n\ lappend result $entry \n\ } \n\} \n\return $result \n\"; std::string tcl_result = ""; set_variable("::cdl_locate_subdirs_path", directory); if (TCL_OK != eval(locate_subdirs_script, tcl_result)) { CYG_FAIL("Internal error evaluating Tcl script"); } int count; char** array; if (TCL_OK != Tcl_SplitList(tcl_interp, const_cast<char*>(tcl_result.c_str()), &count, &array)) { throw std::bad_alloc(); } for (int i = 0; i < count; i++) { result.push_back(array[i]); } Tcl_Free((char*) array); CYG_REPORT_RETURN();}// ----------------------------------------------------------------------------// Locating all subdirs requires some simple recursionvoidCdlInterpreterBody::locate_all_subdirs(std::string directory, std::vector<std::string>& result){ CYG_REPORT_FUNCNAME("CdlInterpreter::locate_all_subdirs"); CYG_REPORT_FUNCARG2XV(this, &result); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != directory); std::vector<std::string> subdirs; locate_subdirs(directory, subdirs); std::vector<std::string>::const_iterator i, j; for (i = subdirs.begin(); i != subdirs.end(); i++) { result.push_back(*i); std::vector<std::string> its_subdirs; locate_all_subdirs(directory + "/" + *i, its_subdirs); for (j = its_subdirs.begin(); j != its_subdirs.end(); j++) { result.push_back(*i + "/" + *j); } } CYG_REPORT_RETURN();}// ----------------------------------------------------------------------------// Locating the files in a particular subdirectory. This requires another// simple Tcl script.voidCdlInterpreterBody::locate_files(std::string directory, std::vector<std::string>& result){ CYG_REPORT_FUNCNAME("CdlInterpreter::locate_files"); CYG_REPORT_FUNCARG2XV(this, &result); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != directory); static char locate_files_script[] = "\set pattern [file join \"$::cdl_locate_files_path\" *] \n\set result {} \n\foreach entry [glob -nocomplain -- $pattern] { \n\ if ([file isdirectory $entry]) { \n\ continue \n\ } \n\ lappend result [file tail $entry] \n\ } \n\return $result \n\"; std::string tcl_result; set_variable("::cdl_locate_files_path", directory); if (TCL_OK != eval(locate_files_script, tcl_result)) { CYG_FAIL("Internal error evaluating Tcl script"); } int count; char** array; if (TCL_OK != Tcl_SplitList(tcl_interp, const_cast<char*>(tcl_result.c_str()), &count, &array)) { throw std::bad_alloc(); } for (int i = 0; i < count; i++) { result.push_back(array[i]); } Tcl_Free((char*) array); CYG_REPORT_RETURN();}// ----------------------------------------------------------------------------// Locating all files can be achieved by combining locate_all_subdirs()// and locate_files().voidCdlInterpreterBody::locate_all_files(std::string directory, std::vector<std::string>& result){ CYG_REPORT_FUNCNAME("CdlInterpreter::locate_all_files"); CYG_REPORT_FUNCARG2XV(this, &result); CYG_PRECONDITION_THISC(); CYG_PRECONDITIONC("" != directory); std::vector<std::string> files; std::vector<std::string>::const_iterator i, j; locate_files(directory, files); for (i = files.begin(); i != files.end(); i++) { result.push_back(*i); } std::vector<std::string> all_subdirs; locate_all_subdirs(directory, all_subdirs); for (i = all_subdirs.begin(); i != all_subdirs.end(); i++) { std::vector<std::string> subdir_files; locate_files(directory + "/" + *i, subdir_files); for (j = subdir_files.begin(); j != subdir_files.end(); j++) { result.push_back(*i + "/" + *j); } } CYG_REPORT_RETURN();}// ----------------------------------------------------------------------------// Write some data to a file, throwing an I/O exception on failure. This// functionality is needed whenever savefile data is generated, it is// convenient to have a utility function to do the job. Also, performing// the Tcl_Write involves passing const data as a non-const argument:// if this ever causes problems in future it is a good idea to isolate// the problem here.voidCdlInterpreterBody::write_data(Tcl_Channel chan, std::string data) throw(CdlInputOutputException){ CYG_REPORT_FUNCNAME("CdlInterpreter::write_data"); CYG_REPORT_FUNCARG2XV(this, chan); CYG_PRECONDITION_THISC(); if (-1 == Tcl_Write(chan, const_cast<char*>(data.data()), data.size())) { std::string msg = "Unexpected error writing to file " + this->get_filename() + " : " + Tcl_PosixError(tcl_interp); throw CdlInputOutputException(msg); } CYG_REPORT_RETURN();}//}}}//{{{ CdlInterpreter:: quote() etc. // ----------------------------------------------------------------------------// Given a string, quote it in such a way that the Tcl interpreter will// process it as a single word, but keep the result as human-readable// as possible. If there are no special characters then just return the// string itself. Otherwise quoting is necessary.//// The choice is between braces and double quotes. Generally braces// are better and more consistent, but there is a problem if the// string argument itself contains braces. These could be// backslash-escaped, but the Tcl interpreter will not automatically// remove the backslashes so we would end up with a discrepancy// between the original data and what is seen by the parser. In this// case quote marks have to be used instead.//// NOTE: this code may not behave sensibly when it comes to i18n// issues.std::stringCdlInterpreterBody::quote(std::string src){ CYG_REPORT_FUNCNAME("CdlInterpreter::quote"); std::string result = ""; bool contains_specials = false; unsigned int i; if (0 == src.size()) { // An empty string. The best way to represent this is an empty // set of quotes. result = "\"\""; CYG_REPORT_RETURN(); return result; } if ('#' == src[0]) { contains_specials = true; } for (i = 0; (i < src.size()) && !contains_specials; i++) { if (isspace(src[i])) { contains_specials = true; break; } switch(src[i]) { case '{': case '}': case '\\': case '$': case '"': case '[': case ']': case '#': case ';': contains_specials = true; break; default: break; } } if (!contains_specials) { result = src; } else{ // If the data is a multiline item, it is better to start it in column 0. // Unfortunately there is the question of what to do with the opening // quote. Putting it on the current line, followed by a backslash-escaped // newline, introduces a space into the string. If the string begins with // a space anyway then arguably this would be harmless, but it could // be confusing to the user. Putting the opening double quote into column 0 // means that the first line of data is indented relative to the rest of // the data, but still appears to be the best alternative. if (src.find('\n') != std::string::npos) { result += "\\\n"; } result += '\"'; for (i = 0; i < src.size(); i++) { switch(src[i]) { case '\\': case '$': case '"': case '[': case ']': result += '\\'; result += src[i]; break; default: result += src[i]; break; } } result += '\"'; } CYG_REPORT_RETURN(); return result;}// ----------------------------------------------------------------------------// Given some data which may be multiline, return a string which corresponds// to that data turned into a comment.std::stringCdlInterpreterBody::multiline_comment(const std::string& orig, int first_indent, int second_indent){ CYG_REPORT_FUNCNAME("CdlInterpreter::multiline_comment"); std::string indent = std::string(first_indent, ' ') + "# " + std::string(second_indent, ' '); std::string result = ""; bool indent_needed = true; std::string::const_iterator str_i; for (str_i = orig.begin(); str_i != orig.end(); str_i++) { if (indent_needed) { result += indent; indent_needed = false; } result += *str_i; if ('\n' == *str_i) { indent_needed = true; } } CYG_REPORT_RETURN(); return result;}// ----------------------------------------------------------------------------// Given some data, append it to the current line and add additional commented// and indented lines as required.std::stringCdlInterpreterBody::extend_comment(const std::string& orig, int first_indent, int second_indent){ CYG_REPORT_FUNCNAME("CdlInterpreter::extend_comment"); std::string indent = std::string(first_indent, ' ') + "# " + std::string(second_indent, ' '); std::string result = ""; bool indent_needed = false; std::string::const_iterator str_i; for (str_i = orig.begin(); str_i != orig.end(); str_i++) { if (indent_needed) { result += indent; indent_needed = false; } result += *str_i; if ('\n' == *str_i) { indent_needed = true; } } CYG_REPORT_RETURN(); return result;}//}}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -