Mercurial > ecos
diff host/libcdl/cdlmisc.cxx @ 76:435cced73e2f ecos-v1_3_1-release
eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
| author | jlarmour |
|---|---|
| date | Tue, 28 Mar 2000 14:10:45 +0000 |
| parents | |
| children | 6736c52df507 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/host/libcdl/cdlmisc.cxx @@ -0,0 +1,1033 @@ +//{{{ Banner + +//============================================================================ +// +// cdlmisc.cxx +// +// Implementation of the various CDL utility member functions. +// +//============================================================================ +//####COPYRIGHTBEGIN#### +// +// ---------------------------------------------------------------------------- +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// +// This file is part of the eCos host tools. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ---------------------------------------------------------------------------- +// +//####COPYRIGHTEND#### +//============================================================================ +//#####DESCRIPTIONBEGIN#### +// +// Author(s): bartv +// Contact(s): bartv +// Date: 1998/03/04 +// Version: 0.01 +// +//####DESCRIPTIONEND#### +//============================================================================ + +//}}} +//{{{ #include's + +// ---------------------------------------------------------------------------- +#include "cdlconfig.h" + +// Get the infrastructure types, assertions, tracing and similar +// facilities. +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/cyg_trac.h> + +// <cdlcore.hxx> defines everything implemented in this module. +// It implicitly supplies <string>, <vector> and <map> because +// the class definitions rely on these headers. +#include <cdlcore.hxx> + +// For access to the isdigit(), isupper(), tolower(), ... functions +#include <cctype> + +// For access to sprintf(), specifically double to string conversions. +#include <cstdio> + +// For access to strtod() +#include <cstdlib> + +// strtod() involves errno... +#include <cerrno> + +// For access to fmod() +#include <cmath> + +// For access to DBL_DIG +#include <cfloat> + +//}}} + +//{{{ Cdl::is_valid_xxx() + +// --------------------------------------------------------------------------- + +bool +Cdl::is_valid_value_flavor(CdlValueFlavor data) +{ + bool result = false; + + switch(data) { + case CdlValueFlavor_None : + case CdlValueFlavor_Bool : + case CdlValueFlavor_BoolData : + case CdlValueFlavor_Data : + result = true; + break; + + default: + break; + } + + return result; +} + +bool +Cdl::is_valid_value_source(CdlValueSource data) +{ + bool result = false; + + switch(data) { + case CdlValueSource_Default : + case CdlValueSource_User : + case CdlValueSource_Wizard : + case CdlValueSource_Inferred : + result = true; + break; + + default: + break; + } + + return result; +} + +// ---------------------------------------------------------------------------- +// For now CDL names are restricted to what is acceptable to the C +// preprocessor. This may cause problems in future, e.g. i18n. + +bool +Cdl::is_valid_cdl_name(const std::string& name) +{ + CYG_REPORT_FUNCNAMETYPE("Cdl::is_valid_cdl_name", "result %d"); + + bool result = is_valid_c_preprocessor_symbol(name); + + CYG_REPORT_RETVAL(result); + return result; +} + +bool +Cdl::is_valid_c_preprocessor_symbol(const std::string& symbol) +{ + CYG_REPORT_FUNCNAMETYPE("Cdl::is_valid_c_preprocessor_symbol", "result %d"); + + bool result = true; + if ("" == symbol) { + result = false; + } else { + // A valid preprocessor symbol should begin with either an underscore + // or a letter. It should then be followed by some number of underscores, + // letters, or digits. + // + // In some locales isalpha() may succeed for characters which are not + // legal for C preprocessor symbols. Instead ASCII is assumed here. + if (('_' != symbol[0]) && + !(('a' <= symbol[0]) && (symbol[0] <= 'z')) && + !(('A' <= symbol[0]) && (symbol[0] <= 'Z'))) { + + result = false; + } else { + for (unsigned int i = 1; i < symbol.size(); i++) { + if (('_' != symbol[i]) && + !(('a' <= symbol[i]) && (symbol[i] <= 'z')) && + !(('A' <= symbol[i]) && (symbol[i] <= 'Z')) && + !(('0' <= symbol[i]) && (symbol[i] <= '9'))) { + + result = false; + break; + } + } + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +//}}} +//{{{ Cdl::xxx_to_yyy() - strings, ints, doubles, ... + +// --------------------------------------------------------------------------- +// Conversion routines between strings, integers, doubles, bools, ... +// +// Conversions to/from integers are complicated somewhat because the +// data type in question is cdl_int. In the initial implementation this +// is 64 bits. In the long term it will be arbitrary precision and +// the conversion routines will need to be reimplemented. +// +// ASCII rather than EBCDIC is assumed. +// +// Some of the routines may fail, e.g. string to integer conversions. +// Others are guaranteed to succeed. + +//{{{ string_to_integer() + +// ---------------------------------------------------------------------------- +bool +Cdl::string_to_integer(std::string data, cdl_int& target) +{ + CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_integer", "success %d"); + + bool negative = false; + // Life is a bit easier if I can check for '\0' + const char* ptr = data.c_str(); + + // Not essential but harmless. + while (isspace(*ptr)) + ptr++; + + if ('-' == *ptr) { + negative = true; + ptr++; + } + + cdl_int acc = 0; + if ('0' == *ptr) { + // This happens sufficiently often to be worth a special case. + if ('\0' == ptr[1]) { + target = 0; + CYG_REPORT_RETVAL(true); + return true; + } + // Hex is always worth supporting. + if (('x' == ptr[1]) || ('X' == ptr[1])) { + ptr++; ptr++; + if (!isxdigit(*ptr)) { + CYG_REPORT_RETVAL(false); + return false; + } + while (isxdigit(*ptr)) { + cdl_int new_acc = acc * 16; + if (isdigit(*ptr)) { + new_acc += (*ptr - '0'); + } else if (('a' <= *ptr) && (*ptr <= 'f')) { + new_acc += (*ptr + 10 - 'a'); + } else if (('A' <= *ptr) && (*ptr <= 'F')) { + new_acc += (*ptr + 10 - 'A'); + } else { + CYG_FAIL("this platform's implementation of isxdigit() is broken"); + } + if (new_acc < acc) { + CYG_REPORT_RETVAL(false); + return false; + } + acc = new_acc; + ptr++; + } + if ('\0' != *ptr) { + CYG_REPORT_RETVAL(false); + return false; + } + if (negative) { + cdl_int new_acc = 0 - acc; + if (new_acc > 0) { + CYG_REPORT_RETVAL(false); + return false; + } else { + acc = new_acc; + } + } + target = acc; + CYG_REPORT_RETVAL(true); + return true; + } + + // Octal? Oh well, might as well be complete. + if (('0' <= ptr[1]) && (ptr[1] <= '7')) { + ptr++; + do { + cdl_int new_acc = 8 * acc; + new_acc += (*ptr - '0'); + if (new_acc < acc) { + CYG_REPORT_RETVAL(false); + return false; + } + acc = new_acc; + ptr++; + } while (('0' <= *ptr) && (*ptr <= '7')); + if ('\0' != *ptr) { + CYG_REPORT_RETVAL(false); + return false; + } + if (negative) { + cdl_int new_acc = 0 - acc; + if (new_acc > 0) { + CYG_REPORT_RETVAL(false); + return false; + } + else { + acc = new_acc; + } + } + target = acc; + CYG_REPORT_RETVAL(true); + return true; + } + + // Drop through for the case of a decimal. + } + + while(isdigit(*ptr)) { + cdl_int new_acc = 10 * acc; + new_acc += (*ptr - '0'); + if (new_acc < acc) { + CYG_REPORT_RETVAL(false); + return false; + } + acc = new_acc; + ptr++; + } + if ('\0' != *ptr) { + CYG_REPORT_RETVAL(false); + return false; + } + if (negative) { + cdl_int new_acc = 0 - acc; + if (new_acc > 0) { + CYG_REPORT_RETVAL(false); + return false; + } else { + acc = new_acc; + } + } + target = acc; + CYG_REPORT_RETVAL(true); + return true; +} + +//}}} +//{{{ string_to_double() + +// ---------------------------------------------------------------------------- +// There is no point in doing this the hard way, just use standard +// library calls. +// +// There is an obvious question as to how much precision can get lost +// doing the conversion to a string. In practice this should not matter +// too much, since the expression handling code generally keeps the +// original double precision lying around to be re-used. However it may +// be desirable to keep the libcdl behaviour in synch with Tcl's +// tcl_precision variable. + +bool +Cdl::string_to_double(std::string value, double& target) +{ + CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_double", "success %d"); + + bool result = true; + const char* start_ptr = value.c_str(); + char* end_ptr; + int old_errno = errno; + + errno = 0; + double conv = strtod(start_ptr, &end_ptr); + if (0 != errno) { + CYG_ASSERT(ERANGE == errno, "standard-compliant C library"); + result = false; + } else if ('\0' != *end_ptr) { + result = false; + } else { + target = conv; + result = true; + } + + errno = old_errno; + CYG_REPORT_RETVAL(result); + return result; +} + +//}}} +//{{{ string_to_bool() + +// ---------------------------------------------------------------------------- +// Conversions to and from bools. The only real issue here is exactly +// what strings should be accepted as synonyms for true and false. +// It is not actually clear that these functions are useful. +bool +Cdl::string_to_bool(std::string data, bool& target) +{ + CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_bool", "success %d"); + + // Arguably there should be a precondition ( "" != data ) + bool result = false; + + // What is truth ? + if (( data == "1" ) || (data == "true") || + ( data == "True") || (data == "TRUE") ) { + result = true; + target = true; + } else if ((data == "0" ) || (data == "false") || + (data == "False") || (data == "FALSE") ) { + result = true; + target = false; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +//}}} + +//{{{ integer_to_string() + +// ---------------------------------------------------------------------------- + +std::string +Cdl::integer_to_string(cdl_int value, CdlValueFormat format) +{ + std::string result; + Cdl::integer_to_string(value, result, format); + return result; +} + +void +Cdl::integer_to_string(cdl_int value, std::string& target, CdlValueFormat format) +{ + CYG_REPORT_FUNCNAME("Cdl::integer_to_string"); + CYG_REPORT_FUNCARG2XV((long) value, format); + + // Optimise this special case. + if (0 == value) { + if (CdlValueFormat_Hex == format) { + target = "0x0"; + } else { + target = "0"; + } + CYG_REPORT_RETVAL(true); + return; + } + + // A local buffer to construct partial strings. This avoids + // unnecessary std::string reallocation. + // 64 bits and three bits at a time for octal numbers gives 21 digits, + // plus spares for the leading '0' and the terminator. + char local_buf[24]; + char *local_ptr = &(local_buf[23]); + *local_ptr-- = '\0'; + + if (CdlValueFormat_Hex == format) { + + // Output the data as 0x... with either 8 or 16 digits, + // depending on the size. + int i; + for (i = 0; i < 8; i++) { + int tmp = (int) (value & 0x0F); + value = value >> 4; + if (tmp < 10) { + *local_ptr-- = '0' + tmp; + } else { + *local_ptr-- = 'A' + (tmp - 10); + } + } + // Beware of right shifts that preserve the sign bit. + { + int tmp1 = (value & 0x0FFFF); + int tmp2 = ((value >> 16) & 0x0FFFF); + value = (tmp2 << 16) + tmp1; + } + if (value != 0) { + for (i = 0; i < 8; i++) { + int tmp = (int) (value & 0x0F); + value = value >> 4; + if (tmp < 10) { + *local_ptr-- = '0' + tmp; + } else { + *local_ptr-- = 'A' + (tmp - 10); + } + } + } + *local_ptr-- = 'x'; + *local_ptr = '0'; + target = std::string(local_ptr); + + } else if (CdlValueFormat_Octal == format) { + + // Simply output the data three bits at a time, do not worry about any + // particular width restrictions. However it is necessary to worry + // about masking. + cdl_int mask = 0x1FFFFFFF; + mask = (mask << 16) | 0x0FFFF; + mask = (mask << 16) | 0x0FFFF; + + target = ""; + while (value > 0) { + int tmp = value & 0x07; + value = (value >> 3) & mask; + *local_ptr-- = '0' + tmp; + } + *local_ptr = '0'; + target = std::string(local_ptr); + + } else { + // A simple decimal number + // Switch to positive arithmetic. + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + // Only MININT cannot be converted using the above line + if (value < 0) { + target = "-9223372036854775808"; + CYG_REPORT_RETVAL(true); + return; + } + } + + while (value > 0) { + int rem = (int) (value % 10); + value = value / 10; + *local_ptr-- = '0' + rem; + } + if (negative) { + *local_ptr-- = '-'; + } + local_ptr++; + target = std::string(local_ptr); + } + + CYG_REPORT_RETURN(); + return; +} + +//}}} +//{{{ double_to_string() + +// ---------------------------------------------------------------------------- + +std::string +Cdl::double_to_string(double value, CdlValueFormat format) +{ + std::string result; + Cdl::double_to_string(value, result, format); + return result; +} + +void +Cdl::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::string +Cdl::bool_to_string(bool value) +{ + std::string result; + Cdl::bool_to_string(value, result); + return result; +} + +void +Cdl::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. +double +Cdl::integer_to_double(cdl_int value) +{ + CYG_REPORT_FUNCNAME("Cdl::integer_to_double"); + + double result = (double) value; + + CYG_REPORT_RETURN(); + return result; +} + +void +Cdl::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 here +bool +Cdl::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 } +}; + +bool +Cdl::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; +} + +bool +Cdl::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 } +}; + +bool +Cdl::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; +} + +bool +Cdl::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.h +std::string +Cdl::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; + +void +Cdl::set_interactive(bool value) +{ + CYG_REPORT_FUNCNAME("Cdl::set_interactive"); + CYG_REPORT_FUNCARG1D(value); + + interactive = value; +} + +bool +Cdl::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 bool +is_separator(int ch) +{ + return ('.' == ch) || ('-' == ch) || ('_' == ch); +} + +int +Cdl::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::string +Cdl::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; +} + +//}}}
