| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- #include <stdio.h>
- #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 <math.h>
- // -----------------------------------------------------------------------------
- // 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: <ns_prefix><ns_number>[, <ns_prefix><ns_number>...]
- // 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;
- }
|