📄 cdlmisc.cxx
字号:
//{{{ 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() // ---------------------------------------------------------------------------boolCdl::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;}boolCdl::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.boolCdl::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;}boolCdl::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() // ----------------------------------------------------------------------------boolCdl::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.boolCdl::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.boolCdl::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::stringCdl::integer_to_string(cdl_int value, CdlValueFormat format){ std::string result; Cdl::integer_to_string(value, result, format); return result;}voidCdl::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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -