#include #include "gpib_parser_casts.h" #include "gpib_parser_validators_numbers.h" // Validators for numbers #include "gpib_parser_chars.h" // Service characters definitions #include "gpib_parser_validators.h" #include "gpib_parser_numutils.h" #include // ----------------------------------------------------------------------------- // GPIB_ParseNumbers parses a string and retrieves numbers // E.g. it processes the following strings: "100, 5", " 10 , 5 ", " 1, 0" // // +----<-<-<-------------------<-<-<--------------------------<-<-<---+ // | | // | {next} {next} | // +----<-<-<----+ +-----<-<-<-----+ | // | | | | | // | +-------+ | {number?} | +--------+ | {end?} +-------+ | // (string)->-+->| space |--+------+-----+-->| number |--+----+->--+-->| comma |--+ // | +-------+ | |{yes}| +--------+ | | | +-------+ // | | | | | | | // +---->->->----+ | +----->->->-----+ | +--->->->--(exit) // {no space} | {no more numbers} | {no comma} // {no} | | // +-->->->--(error exit} +--->->->--(success exit) // {no number} {end} // // Note: GPIB standard assumes the string ends with end-of-line character ('\n') // // @str - specifies the string to be parsed // @type - specifies the parsing mode: float or integer // @count - specifies the exact number of the expecting numbers in the string. // Note: you must provide enough pointers after @pvalue1 to store all the numbers // // Return value: in case of error - negative error code // in case of success - zero // in case of warning - positive code which means amount of remaining unparsed numbers int GPIB_ParseNumbers( const char * str, eGPIB_ParseNumbers_type_t type, size_t count, int * pAnchorValue, ... ) { int rval = 0; size_t nsys = 0; // numeric system code: none(0), bin(2), octal(8), dec(10), hex(16) float * * pointer_to_pointer_to_float = ( (float**) &pAnchorValue ); int * * pointer_to_pointer_to_int = ( (int**) &pAnchorValue ); BOOL bExpectNumber = TRUE; // @bExpectNumber: the flag telling that the next character must be a part of number // Let's the parse begins! // Til the end of string and while @count is greater than zero while( !IsEndOfLine( *str ) && (count > 0) ) { // Check for "white" character if( IsWhiteChar( *str )) { // Skip it and check the next character str++; continue; } // the character is not "white" for sure since we skipped all the "white" chars. // check for the numbers separator (by default is comma) if( GPIB_CHAR_NUMSEPARATOR_SIGN == *str ) { if( bExpectNumber ) { // error: while a part of the number expected the separator faced rval = -1; break; } else { (void)nsys; // do not change @nsys str++; // go forward to the next character bExpectNumber = TRUE; // do expect the next character is a part of the number pointer_to_pointer_to_float++; // move the pointer to the next receiving cell pointer_to_pointer_to_int++; // move the pointer to the next receiving cell } } // Check for ordinar number in demical system (float or integer) if( !IsFloatChar( *str ) ) { // hmmm, it does not relate to ordinary number... // check for the numeric system prefix! if( IsNumericSystem( str ) ) { // success, prefix presents // retrieve the numeric system code nsys = GetNumericSystemBase( str ); } else { // prefix is absent nsys = 0; } } else { nsys = 10; // assume this number is in demical numeric system } // the character is not "white" and is not separator for sure. // the character is a part of the number for sure if( !bExpectNumber ) { // but the number is unexpected now // error rval = -1; break; } count--; switch( nsys ) { case 2: // binary case 8: // octal case 16: // hexademical { uint32_t num; // retrieved number from @ConvertNumerationSystem() // convert the number into demical system if( ConvertNumerationSystem( str, nsys, &num, &str ) ) { switch(type) { // the integer conversion is choosed case USBTMC_PARSENUMBERS_TYPE_INT: // store the number into the cell (*pointer_to_pointer_to_int)[0] = (int)num; break; // the float conversion is choosed case USBTMC_PARSENUMBERS_TYPE_FLOAT: default: // store the number into the cell (*pointer_to_pointer_to_float)[0] = (float)num; } bExpectNumber = FALSE; // Since now the number is unexpected } else { // error: can not convert the number nsys = 0; // error rval = -1; } } break; case 10: { switch(type) { // the integer conversion is choosed case USBTMC_PARSENUMBERS_TYPE_INT: // store the number into the cell (*pointer_to_pointer_to_int)[0] = atoi( str ); break; // the float conversion is choosed case USBTMC_PARSENUMBERS_TYPE_FLOAT: default: // store the number into the cell (*pointer_to_pointer_to_float)[0] = atoi( str ); } } break; default: rval = -1; // unknown numeric system nsys = 0; // error } // check if the numeric system detected // Also, @nsys=0 is a error signature to break from [while] if( 0 == nsys ) { // error: invalid character rval = -1; break; } } return rval; // amount of unparsed numbers } // ConvertNumerationSystem: // String to Number conversion. // Input string format: [, ...] // where: // @ns_prefix - is a numeric system prefix: // "#H" or "#h" - for the number in hexademical format; // "#B" or "#B" - for the number in binary format; // "#O" or "#o" - for the number in octal format; // @ns_number - the number in the one of the described above numeric systems; // E.g, #B10001, #HDEADBEEF // @str is a input string containing one or more numbers split up with the separator // @nsys specifies the source numeric system. Can be zero to detect the system automatically. // The return value is TRUE in case the number is parsed successfully and written into @pResult // The return value is FALSE, in case the numeric system is not detected or unknown, or // if input string contains invalid characters for the number (but actually non-white-characters) // The return value is FALSE if even the parsed number overflows the receiving cell (int) // The function parses until the first "white" character is faced. // In case of success (TRUE), the function modifies the @ppEnd in order to point to the last // character parsed in @str. #define ConvertNumerationSystem_limit_nsyshex 8 #define ConvertNumerationSystem_limit_nsysoct 11 #define ConvertNumerationSystem_limit_nsysbin 32 BOOL ConvertNumerationSystem( const char * str, int nsys, uint32_t * pResult, const char * * ppEnd ) { if( 0 == nsys ) nsys = GetNumericSystemBase( str ); // skip the prefix str += GPIB_NUMBER_NSYSPREFIX_SIZE; size_t idx = 0; // current position uint32_t result = 0; // the result const char * iter; // iterator for @str // search for the end of the number for( iter = str; !IsEndOfNumber( *iter ); ++iter, ++idx ) { // check the character for if it relates to the assumed numeric system. switch( nsys ) { //---------------------- // Binary system case 2: // the next bin character is coming if( idx > ConvertNumerationSystem_limit_nsysbin ) { // the limit exceeding (32 chars): the number can not be converted return FALSE; } else if( IsBinaryChar( *iter ) ) { result <<= 1; result |= 0x1 & (BinCharToNum( *iter )); break; } else return FALSE; // invalid character for binary numeric system //---------------------- // Octal system case 8: // the next oct character is coming if( idx > ConvertNumerationSystem_limit_nsysoct ) { // the limit exceeding (11 chars): the number can not be converted return FALSE; } else if( IsOctalChar( *iter ) ) { if( ConvertNumerationSystem_limit_nsysoct == idx ) if( IsOCT_Int32Overflow( *iter ) ) { // 32-bit integer overflow return FALSE; } result <<= 3; result |= 0x7 & (OctCharToNum( *iter )); break; } else return FALSE; // invalid character for octal numeric system //---------------------- // Hex system case 16: // the next hex character is coming if( idx > ConvertNumerationSystem_limit_nsyshex ) { // the limit exceeding (8 chars): the number can not be converted return FALSE; } else if( IsHexademicalChar( *iter ) ) { result <<= 4; result |= 0xF & (HexCharToNum( *iter )); break; } else return FALSE; // invalid character for hexademical numeric system break; } } // store the result if( NULL != pResult ) *pResult = result; // store the iterator if( NULL != ppEnd) *ppEnd = iter; return TRUE; } size_t GPIB_Integer2Str( int32_t value, char * strBuf, size_t strBufSize, uint32_t compound_format ) { size_t nSym = 0; sFormatInt2Str_t * format = (sFormatInt2Str_t*)(&compound_format); if( format->nLeadDigits > 10 ) // 10 digits max for int32_t return 0; // error if( 0 != format->nLeadDigits ) { char formatstr[8] = { '\0' }; snprintf( formatstr, sizeof(formatstr), "%c%c%d%c", '%', '0', format->nLeadDigits, 'd' ); nSym = snprintf( strBuf, strBufSize, formatstr, value ); } else { nSym = snprintf( strBuf, strBufSize, "%d", value ); } if( nSym >= strBufSize ) return 0; // error return nSym; } size_t GPIB_Float2Str( float value, char * strBuf, size_t strBufSize, uint32_t compound_format ) { return GPIB_Double2Str( (double)value, strBuf, strBufSize, compound_format ); } size_t GPIB_Double2Str( double value, char * strBuf, size_t strBufSize, uint32_t compound_format ) { size_t nSym = 0; sFormatDouble2Str_t * format = (sFormatDouble2Str_t*)(&compound_format); if( 0 != format->bSciFormat ) { // science format { char formatStr[16] = {0}; size_t n = format->nFracDigits; if( 0 == n ) n = 10; snprintf( formatStr, sizeof(formatStr) - 1, "%c%c%d%c", '%', '.', n, 'e' ); int rc = snprintf( strBuf, strBufSize, formatStr, value ); if( rc < 0 ) return 0; if( rc >= strBufSize ) return 0; return (size_t)(rc); } /* bool sign = false; bool zero = false; if( value < 0 ) { sign = true; value = -value; } // exponent part of science format, // e.g. for 0.0325: 0.0325 = 3.25e-2; exp = -2 // e.g. for -15.993: -15.993 = -1.5993e+1; exp = 1 // e.g. for 2.775: 2.775 = 2.775e+0; exp = 0 int exp = 0; if( (value <= 1.0e-99) || (0.0 == value) ) { exp = 0; (void)value; zero = true; } else if( (value <= 1) || (value >= 10) ) { exp = (int)log10( value ); value /= pow( 10, exp ); } if( value < 1 && (value > 1.0e-99) ) // value less than 1.0e-99 is considered as zero { value *= (double)10.0; exp--; } else if( value >= 10 ) { value /= (double)10.0; exp++; } // The function prints the value X.XXXXXXXXXXe+N // It is required to round the value up to 10 signs // 7.9999999999e+1 = 7.99999999990e+1 // 7.99999999990e+1 + 0.00000000005 = 7.99999999995e+1 // 7.99999999995e+1 => 8.0e+8 //value += 5.0 * pow( 10, exp - 9); if( !zero ) { value += 5.0e-11; } size_t expChars = 1; // 1 char for exp=0, "0" // expChars: amount of demical characters of @exp if( 0 != exp ) { expChars = (size_t)ceil( log10( abs( exp ) ) ); } if( 0 == format->nFracDigits ) { format->nFracDigits = 10; } // science format if( format->nFracDigits // fractional part + 1 // integer part + 1 // dot + (sign?1:0) // sign + 2 // e+ or e- + expChars > strBufSize ) { // not enough free space in the buffer return 0; } // print a sign if( sign ) { if( strBufSize > 0 ) { strBuf[nSym] = '-'; nSym++; strBufSize--; } else { nSym = 0; goto L_Double2Str_EXIT; } } if( strBufSize > 0 ) { int i = (int)value; strBuf[nSym] = '0' + i; strBufSize--; nSym++; //if( i > 9 ) asm("bkpt #0"); value -= i; // substract integer part } else { nSym = 0; goto L_Double2Str_EXIT; } if( strBufSize > 0 ) { strBuf[nSym] = '.'; nSym++; strBufSize--; } else { nSym = 0; goto L_Double2Str_EXIT; } if( strBufSize > 0 ) { size_t fracDigits = format->nFracDigits; if( fracDigits == 0 ) fracDigits = 10; while( fracDigits > 0 ) { value *= 10; int digit = (int)(value); value -= digit; if( fracDigits > 0 ) fracDigits--; if( strBufSize > 0 ) { strBuf[nSym] = ('0' + digit); nSym++; strBufSize--; } else { nSym = 0; goto L_Double2Str_EXIT; } } } else { nSym = 0; goto L_Double2Str_EXIT; } if( 2 + expChars <= strBufSize ) { strBuf[nSym] = 'e'; nSym++; strBuf[nSym] = ((exp<0)?'-':'+'); nSym++; exp = abs(exp); do { if( 0 == strBufSize ) { nSym = 0; goto L_Double2Str_EXIT; } int digit = 0; int power = 0; if( exp != 0 ) { power = (int)log10( exp ); power = (int)pow( 10, power ); digit = (exp / power); } strBuf[nSym] = '0' + digit; nSym++; strBufSize--; exp -= power * digit; } while( exp > 0 ); } else { nSym = 0; goto L_Double2Str_EXIT; } */ } else { // float point format if( 0 == format->nFracDigits ) { format->nFracDigits = 8; } { char formatStr[16] = {0}; if( 0 == format->nLeadDigits ) snprintf( formatStr, sizeof(formatStr)-1, "%c%c%d%c", '%', '.', format->nFracDigits, 'f' ); else snprintf( formatStr, sizeof(formatStr)-1, "%c%d%c%d%c", '%', format->nLeadDigits, '.', format->nFracDigits, 'f' ); int rc = snprintf( strBuf, strBufSize, formatStr, value ); if( rc < 0 ) return 0; if( rc >= strBufSize ) return 0; return (size_t)rc; } /* if( format->nFracDigits + format->nLeadDigits + 1 // dot + (0>value?1:0) // sign > strBufSize ) { // not enough free space in the buffer return 0; } // print a sign if( value < 0 ) { strBuf[nSym] = '-'; nSym++; strBufSize--; value = -value; } // Process leading zeros { size_t leadDigits = 1; // for numbers @value greater than 1 or equal the one, // the amount of leading digits can be caluculated as following. // Otherwise, for numbers less than 1, this amount is 1. // e.g. leadDigits =3 for 100.2 // leadDigits =2 for 97.8 // leadDigits =1 for 1.999 // leadDigits =1 for 1.000 // leadDigits =1 for 0.538 if( value >= 1 ) { // calculate amount of leading integer digits of the @value leadDigits = (int)ceil( log10( value ) ); } else { // The value is less than 1. // In this case a leading zero must be added. if( format->nLeadDigits == 0 ) { // If @nLeadDigits not specified, // it is required to make the next condition true, // to peform adding a leading zero //format->nLeadDigits = (1 + leadDigits); } } // Specified number of lead digits in the format // greater than actual count of lead digits: need to // add leading zeros. if( (leadDigits < format->nLeadDigits) ) { //if( format->nLeadDigits == 0 ) // (void)leadDigits; // do not change value //else leadDigits = format->nLeadDigits - leadDigits; // add leading zeros while( leadDigits > 0 ) { strBuf[nSym] = '0'; nSym++; strBufSize--; leadDigits--; } } } { int power = 1; if( value > 1e-99 ) // the value less than 1e-99 is considered as zero { power = (int)pow( 10, (int)log10( value ) ); } if( 0 == power ) { strBuf[nSym] = ('0'); nSym++; strBufSize--; } while( power > 0 ) { int digit = (int)value / power; value -= digit * power; power /= 10; if( strBufSize > 0 ) { strBuf[nSym] = ('0' + digit); nSym++; strBufSize--; } else { nSym = 0; goto L_Double2Str_EXIT; } } } if( strBufSize > 0 ) { strBuf[nSym] = '.'; nSym++; strBufSize--; } { size_t fracDigits = format->nFracDigits; while( fracDigits > 0 ) { value *= 10; int digit = (int)(value); value -= digit; if( fracDigits > 0 ) fracDigits--; if( strBufSize > 0 ) { strBuf[nSym] = ('0' + digit); nSym++; strBufSize--; } else { nSym = 0; goto L_Double2Str_EXIT; } } } */ } //L_Double2Str_EXIT: return nSym; }