📄 cdlmisc.cxx
字号:
CYG_REPORT_RETURN(); return;}//}}}//{{{ double_to_string() // ----------------------------------------------------------------------------std::stringCdl::double_to_string(double value, CdlValueFormat format){ std::string result; Cdl::double_to_string(value, result, format); return result;}voidCdl::double_to_string(double value, std::string& result, CdlValueFormat format){ CYG_REPORT_FUNCNAME("Cdl::double_to_String"); char buf[256]; // This should be plenty :-) sprintf(buf, "%.*G", DBL_DIG, value); result = buf; CYG_UNUSED_PARAM(CdlValueFormat, format); CYG_REPORT_RETURN();}//}}}//{{{ bool_to_string() // ----------------------------------------------------------------------------// Should the string results be 1/0 or true/false? Not that// it really matters. The testcase in cdl1.cxx expects 1/0.std::stringCdl::bool_to_string(bool value){ std::string result; Cdl::bool_to_string(value, result); return result;}voidCdl::bool_to_string(bool value, std::string& target){ CYG_REPORT_FUNCNAME("Cdl::bool_to_string"); CYG_REPORT_FUNCARG1( "value arg %ld", (long) value); if (value) target = "1"; else target = "0"; CYG_REPORT_RETURN();}//}}}//{{{ integer_to_double() // ----------------------------------------------------------------------------// Currently integer to double cannot fail, although there may well be loss// of accurary. Eventually cdl_int may be an arbitrary precision integer// in which case conversion to double is not guaranteed.doubleCdl::integer_to_double(cdl_int value){ CYG_REPORT_FUNCNAME("Cdl::integer_to_double"); double result = (double) value; CYG_REPORT_RETURN(); return result;}voidCdl::integer_to_double(cdl_int value, double& target){ CYG_REPORT_FUNCNAME("Cdl::integer_to_double"); target = (double) value; CYG_REPORT_RETURN();}//}}}//{{{ double_to_integer() // Conversion from double to integer is only allowed if there is no loss// of data. modf() is useful hereboolCdl::double_to_integer(double value, cdl_int& target){ CYG_REPORT_FUNCNAMETYPE("Cdl::double_to_integer", "result %d"); bool result = false; double integral; double frac; frac = modf(value, &integral); if (0.0 == frac) { // Looking good, but integral may still be too big. cdl_int tmp = (cdl_int) integral; if (tmp == value) { // No fraction, no loss of data, everything looking good target = tmp; result = true; } } CYG_REPORT_RETVAL(result); return result;}//}}}//}}}//{{{ Cdl::xxx_to_yyy() - CDL-specific data types // ----------------------------------------------------------------------------// Conversions between strings and flavors.static struct { char* name; CdlValueFlavor flavor;} valid_flavors[] = { { "none", CdlValueFlavor_None }, { "bool", CdlValueFlavor_Bool }, { "booldata", CdlValueFlavor_BoolData }, { "data", CdlValueFlavor_Data }, { 0, CdlValueFlavor_Invalid }};boolCdl::string_to_flavor(std::string name, CdlValueFlavor& target){ CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_flavor", "success %d"); bool result = false; // First convert the argument to lower case. Arguably this is incorrect, // Tcl is a case-sensitive language, but the conversion is unlikely ever // to be harmfull. for (std::string::iterator str_i = name.begin(); str_i != name.end(); str_i++) { if (isupper(*str_i)) { *str_i = tolower(*str_i); } } // Now look for a match in the table. int match = -1; int i; const char* c_str = name.c_str(); int len = strlen(c_str); for (i = 0; 0 != valid_flavors[i].name; i++) { if (0 == strncmp(c_str, valid_flavors[i].name, len)) { // Check for an ambiguous string match. // This cannot actually happen with the current flavor names. if ( -1 != match) { break; } match = i; } } if (-1 != match) { target = valid_flavors[match].flavor; result = true; } CYG_REPORT_RETVAL(result); return result;}boolCdl::flavor_to_string(CdlValueFlavor flavor, std::string& target){ CYG_REPORT_FUNCNAMETYPE("Cdl::flavor_to_string", "success %d"); bool result = false; for (int i = 0; 0 != valid_flavors[i].name; i++) { if (flavor == valid_flavors[i].flavor) { target = valid_flavors[i].name; result = true; break; } } CYG_REPORT_RETVAL(result); return result;}// ----------------------------------------------------------------------------// Similar support for value sources.static struct { char* name; CdlValueSource source;} valid_sources[] = { { "default", CdlValueSource_Default }, { "inferred", CdlValueSource_Inferred }, { "wizard", CdlValueSource_Wizard }, { "user", CdlValueSource_User }, { 0, CdlValueSource_Invalid }};boolCdl::string_to_source(std::string name, CdlValueSource& target){ CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_source", "success %d"); bool result = false; // First convert the argument to lower case. Arguably this is incorrect, // Tcl is a case-sensitive language, but the conversion is unlikely ever // to be harmfull. for (std::string::iterator str_i = name.begin(); str_i != name.end(); str_i++) { if (isupper(*str_i)) { *str_i = tolower(*str_i); } } // Now look for a match in the table. int match = -1; int i; const char* c_str = name.c_str(); int len = strlen(c_str); for (i = 0; 0 != valid_sources[i].name; i++) { if (0 == strncmp(c_str, valid_sources[i].name, len)) { // Check for an ambiguous string match. // This cannot actually happen with the current source names. if ( -1 != match) { break; } match = i; } } if (-1 != match) { target = valid_sources[match].source; result = true; } CYG_REPORT_RETVAL(result); return result;}boolCdl::source_to_string(CdlValueSource source, std::string& target){ CYG_REPORT_FUNCNAMETYPE("Cdl::source_to_string", "success %d"); bool result = false; for (int i = 0; 0 != valid_sources[i].name; i++) { if (source == valid_sources[i].source) { target = valid_sources[i].name; result = true; break; } } CYG_REPORT_RETVAL(result); return result;}//}}}//{{{ Cdl::get_library_version() // ----------------------------------------------------------------------------// The version of the library actually lives inside configure.in. It gets// exported into cdlconfig.hstd::stringCdl::get_library_version(void){ return std::string(CYGNUM_LIBCDL_VERSION);}//}}}//{{{ Cdl::set_interactive() // ----------------------------------------------------------------------------// Some CDL scripts and some bits of the library may want to adapt depending// on whether or not the application is running fully interactively or in// batch mode. The primary distinction is that a batch program should never// attempt to obtain user input, whether via Tk widgets or by other means.bool Cdl::interactive = false;voidCdl::set_interactive(bool value){ CYG_REPORT_FUNCNAME("Cdl::set_interactive"); CYG_REPORT_FUNCARG1D(value); interactive = value;}boolCdl::is_interactive(void){ CYG_REPORT_FUNCNAMETYPE("Cdl::is_interactive", "interactive %d"); CYG_REPORT_RETVAL(interactive); return interactive;}//}}}//{{{ Cdl::compare_versions() // ----------------------------------------------------------------------------// Packages may need to impose constraints on which versions of other// packages they can coexist with. This requires some way of achieving// a partial ordering of version numbers. Unfortunately there are many// different ways of specifying a version number, and we cannot impose// a single model on all third party package developers. Instead this// routine performs some semi-intelligent comparisons of two version// strings which should work in the vast majority of cases.//// The return value is as per strcmp(), -1 if the first entry is// smaller (i.e. the more recent and hence hopefully the first in// a list), +1 if the second entry is smaller, 0 if the two are// identical.//// There is a big ambiguity between "derived" versions and "experimental"// versions. Something like v0.3beta is experimental, i.e. it is older// than the full release v0.3. On the other hand v0.3.p1 is a patched// version of v0.3 and hence newer. This code uses the presence or otherwise// of a separator to decide between the two cases.// A utility routine which checks whether or not a character counts// as a separator. Currently the characters . - and _ are all accepted// as field separators.//// Arguably - should not be accepted as a separator. Instead if it preceeds// a digit it could be interpreted as part of a prerelease number.static boolis_separator(int ch){ return ('.' == ch) || ('-' == ch) || ('_' == ch);} intCdl::compare_versions(std::string arg1, std::string arg2){ CYG_REPORT_FUNCNAMETYPE("Cdl::compare_versions", "result %d"); if (arg1 == arg2) { CYG_REPORT_RETVAL(0); return 0; } // The version number "current" is special, it always indicates the most // recent version e.g. as checked out from a CVS repository. if ("current" == arg1) { CYG_REPORT_RETVAL(-1); return -1; } if ("current" == arg2) { CYG_REPORT_RETVAL(1); return 1; } const char* ptr1 = arg1.c_str(); const char* ptr2 = arg2.c_str(); int num1 = 0; int num2 = 0; // If both strings start with 'v' or 'V', skip this. A minor variation in // case at the start of a string should be ignored. if ((('v' == *ptr1) || ('V' == *ptr1)) && (('v' == *ptr2) || ('V' == *ptr2))) { ptr1++; ptr2++; } // Now process the rest of the version string, one unit at a time. while (1) { if (('\0' == *ptr1) && ('\0' == *ptr2)) { // Both strings have terminated at the same time. There // may have been some spurious leading zeroes in numbers, // or irrelevant differences in the separators. CYG_REPORT_RETVAL(0); return 0; } if ('\0' == *ptr1) { // The first string has ended first. If the second string currently // points at a separator then arg2 is a derived version, e.g. // v0.3.p1, and hence newer. Otherwise arg2 is an experimental // version v0.3beta and hence older. if (is_separator(*ptr2)) { CYG_REPORT_RETVAL(1); return 1; } else { CYG_REPORT_RETVAL(-1); return -1; } } if ('\0' == *ptr2) { // As per the previous test. if (is_separator(*ptr1)) { CYG_REPORT_RETVAL(-1); return -1; } else { CYG_REPORT_RETVAL(1); return 1; } } // If both strings currently point at numerical data, do a conversion and // a numerical comparison. if (isdigit(*ptr1) && isdigit(*ptr2)) { num1 = 0; num2 = 0; // Strictly speaking there should be some overflow tests here, but it // is not worth the trouble. do { num1 = (10 * num1) + (*ptr1++ - '0'); } while(isdigit(*ptr1)); do { num2 = (10 * num2) + (*ptr2++ - '0'); } while(isdigit(*ptr2)); // v2.0 is newer than v1.0 if (num1 < num2) { CYG_REPORT_RETVAL(1); return 1; } else if (num1 > num2) { CYG_REPORT_RETVAL(-1); return -1; } else { continue; } } // Non-numerical data. If the two characters are the same then // move on. Note: this has to happen after numerical conversions // to distinguish v10.0 and v1.0 if (*ptr1 == *ptr2) { ptr1++; ptr2++; continue; } // If both strings are currently at a separator then move on. All // separators can be used interchangeably. if (is_separator(*ptr1) && is_separator(*ptr2)) { ptr1++; ptr2++; continue; } // If only one string is at a separator, special action // is needed. v1.1alpha is interpreted as earlier than // v1.1, but v1.1.3 is a later release. if (is_separator(*ptr1)) { return -1; } else if (is_separator(*ptr2)) { return 1; } // Two different characters, e.g. v1.0alpha vs. v1.0beta if (*ptr1 < *ptr2) { CYG_REPORT_RETVAL(1); return 1; } else { CYG_REPORT_RETVAL(-1); return -1; } } // Not reachable.}//}}}//{{{ Cdl::get_short_form() // ----------------------------------------------------------------------------// It is occasionally useful to take a full CDL name such as CYgpkg_KERNEL// and turn it into a short form such as "kernel". This involves discarding// everything up to and including the first underscore, then lowercasing// all subsequent characters.std::stringCdl::get_short_form(const std::string& original){ CYG_REPORT_FUNCNAME("CdlMisc::get_short_form"); std::string result = ""; unsigned int size = original.size(); unsigned int i; for (i = 0; i < size; i++) { if ('_' == original[i]) { i++; break; } } // Either at end of string, or just past the first underscore for ( ; i < size; i++) { if (isupper(original[i])) { result += tolower(original[i]); } else { result += original[i]; } } CYG_REPORT_RETURN(); return result;}//}}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -