gpib_parser_numutils.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. #include <stdio.h>
  2. #include "gpib_parser_casts.h"
  3. #include "gpib_parser_validators_numbers.h" // Validators for numbers
  4. #include "gpib_parser_chars.h" // Service characters definitions
  5. #include "gpib_parser_validators.h"
  6. #include "gpib_parser_numutils.h"
  7. #include <math.h>
  8. // -----------------------------------------------------------------------------
  9. // GPIB_ParseNumbers parses a string and retrieves numbers
  10. // E.g. it processes the following strings: "100, 5", " 10 , 5 ", " 1, 0"
  11. //
  12. // +----<-<-<-------------------<-<-<--------------------------<-<-<---+
  13. // | |
  14. // | {next} {next} |
  15. // +----<-<-<----+ +-----<-<-<-----+ |
  16. // | | | | |
  17. // | +-------+ | {number?} | +--------+ | {end?} +-------+ |
  18. // (string)->-+->| space |--+------+-----+-->| number |--+----+->--+-->| comma |--+
  19. // | +-------+ | |{yes}| +--------+ | | | +-------+
  20. // | | | | | | |
  21. // +---->->->----+ | +----->->->-----+ | +--->->->--(exit)
  22. // {no space} | {no more numbers} | {no comma}
  23. // {no} | |
  24. // +-->->->--(error exit} +--->->->--(success exit)
  25. // {no number} {end}
  26. //
  27. // Note: GPIB standard assumes the string ends with end-of-line character ('\n')
  28. //
  29. // @str - specifies the string to be parsed
  30. // @type - specifies the parsing mode: float or integer
  31. // @count - specifies the exact number of the expecting numbers in the string.
  32. // Note: you must provide enough pointers after @pvalue1 to store all the numbers
  33. //
  34. // Return value: in case of error - negative error code
  35. // in case of success - zero
  36. // in case of warning - positive code which means amount of remaining unparsed numbers
  37. int GPIB_ParseNumbers( const char * str, eGPIB_ParseNumbers_type_t type, size_t count, int * pAnchorValue, ... )
  38. {
  39. int rval = 0;
  40. size_t nsys = 0; // numeric system code: none(0), bin(2), octal(8), dec(10), hex(16)
  41. float * * pointer_to_pointer_to_float = ( (float**) &pAnchorValue );
  42. int * * pointer_to_pointer_to_int = ( (int**) &pAnchorValue );
  43. BOOL bExpectNumber = TRUE; // @bExpectNumber: the flag telling that the next character must be a part of number
  44. // Let's the parse begins!
  45. // Til the end of string and while @count is greater than zero
  46. while( !IsEndOfLine( *str ) && (count > 0) )
  47. {
  48. // Check for "white" character
  49. if( IsWhiteChar( *str ))
  50. {
  51. // Skip it and check the next character
  52. str++;
  53. continue;
  54. }
  55. // the character is not "white" for sure since we skipped all the "white" chars.
  56. // check for the numbers separator (by default is comma)
  57. if( GPIB_CHAR_NUMSEPARATOR_SIGN == *str )
  58. {
  59. if( bExpectNumber )
  60. {
  61. // error: while a part of the number expected the separator faced
  62. rval = -1;
  63. break;
  64. }
  65. else
  66. {
  67. (void)nsys; // do not change @nsys
  68. str++; // go forward to the next character
  69. bExpectNumber = TRUE; // do expect the next character is a part of the number
  70. pointer_to_pointer_to_float++; // move the pointer to the next receiving cell
  71. pointer_to_pointer_to_int++; // move the pointer to the next receiving cell
  72. }
  73. }
  74. // Check for ordinar number in demical system (float or integer)
  75. if( !IsFloatChar( *str ) )
  76. {
  77. // hmmm, it does not relate to ordinary number...
  78. // check for the numeric system prefix!
  79. if( IsNumericSystem( str ) )
  80. {
  81. // success, prefix presents
  82. // retrieve the numeric system code
  83. nsys = GetNumericSystemBase( str );
  84. }
  85. else
  86. {
  87. // prefix is absent
  88. nsys = 0;
  89. }
  90. }
  91. else
  92. {
  93. nsys = 10; // assume this number is in demical numeric system
  94. }
  95. // the character is not "white" and is not separator for sure.
  96. // the character is a part of the number for sure
  97. if( !bExpectNumber )
  98. {
  99. // but the number is unexpected now
  100. // error
  101. rval = -1;
  102. break;
  103. }
  104. count--;
  105. switch( nsys )
  106. {
  107. case 2: // binary
  108. case 8: // octal
  109. case 16: // hexademical
  110. {
  111. uint32_t num; // retrieved number from @ConvertNumerationSystem()
  112. // convert the number into demical system
  113. if( ConvertNumerationSystem( str, nsys, &num, &str ) )
  114. {
  115. switch(type)
  116. {
  117. // the integer conversion is choosed
  118. case USBTMC_PARSENUMBERS_TYPE_INT:
  119. // store the number into the cell
  120. (*pointer_to_pointer_to_int)[0] = (int)num;
  121. break;
  122. // the float conversion is choosed
  123. case USBTMC_PARSENUMBERS_TYPE_FLOAT:
  124. default:
  125. // store the number into the cell
  126. (*pointer_to_pointer_to_float)[0] = (float)num;
  127. }
  128. bExpectNumber = FALSE; // Since now the number is unexpected
  129. }
  130. else
  131. {
  132. // error: can not convert the number
  133. nsys = 0; // error
  134. rval = -1;
  135. }
  136. }
  137. break;
  138. case 10:
  139. {
  140. switch(type)
  141. {
  142. // the integer conversion is choosed
  143. case USBTMC_PARSENUMBERS_TYPE_INT:
  144. // store the number into the cell
  145. (*pointer_to_pointer_to_int)[0] = atoi( str );
  146. break;
  147. // the float conversion is choosed
  148. case USBTMC_PARSENUMBERS_TYPE_FLOAT:
  149. default:
  150. // store the number into the cell
  151. (*pointer_to_pointer_to_float)[0] = atoi( str );
  152. }
  153. }
  154. break;
  155. default:
  156. rval = -1; // unknown numeric system
  157. nsys = 0; // error
  158. }
  159. // check if the numeric system detected
  160. // Also, @nsys=0 is a error signature to break from [while]
  161. if( 0 == nsys )
  162. {
  163. // error: invalid character
  164. rval = -1;
  165. break;
  166. }
  167. }
  168. return rval; // amount of unparsed numbers
  169. }
  170. // ConvertNumerationSystem:
  171. // String to Number conversion.
  172. // Input string format: <ns_prefix><ns_number>[, <ns_prefix><ns_number>...]
  173. // where:
  174. // @ns_prefix - is a numeric system prefix:
  175. // "#H" or "#h" - for the number in hexademical format;
  176. // "#B" or "#B" - for the number in binary format;
  177. // "#O" or "#o" - for the number in octal format;
  178. // @ns_number - the number in the one of the described above numeric systems;
  179. // E.g, #B10001, #HDEADBEEF
  180. // @str is a input string containing one or more numbers split up with the separator
  181. // @nsys specifies the source numeric system. Can be zero to detect the system automatically.
  182. // The return value is TRUE in case the number is parsed successfully and written into @pResult
  183. // The return value is FALSE, in case the numeric system is not detected or unknown, or
  184. // if input string contains invalid characters for the number (but actually non-white-characters)
  185. // The return value is FALSE if even the parsed number overflows the receiving cell (int)
  186. // The function parses until the first "white" character is faced.
  187. // In case of success (TRUE), the function modifies the @ppEnd in order to point to the last
  188. // character parsed in @str.
  189. #define ConvertNumerationSystem_limit_nsyshex 8
  190. #define ConvertNumerationSystem_limit_nsysoct 11
  191. #define ConvertNumerationSystem_limit_nsysbin 32
  192. BOOL ConvertNumerationSystem( const char * str, int nsys, uint32_t * pResult, const char * * ppEnd )
  193. {
  194. if( 0 == nsys )
  195. nsys = GetNumericSystemBase( str );
  196. // skip the prefix
  197. str += GPIB_NUMBER_NSYSPREFIX_SIZE;
  198. size_t idx = 0; // current position
  199. uint32_t result = 0; // the result
  200. const char * iter; // iterator for @str
  201. // search for the end of the number
  202. for( iter = str; !IsEndOfNumber( *iter ); ++iter, ++idx )
  203. {
  204. // check the character for if it relates to the assumed numeric system.
  205. switch( nsys )
  206. {
  207. //----------------------
  208. // Binary system
  209. case 2:
  210. // the next bin character is coming
  211. if( idx > ConvertNumerationSystem_limit_nsysbin )
  212. {
  213. // the limit exceeding (32 chars): the number can not be converted
  214. return FALSE;
  215. }
  216. else
  217. if( IsBinaryChar( *iter ) )
  218. {
  219. result <<= 1;
  220. result |= 0x1 & (BinCharToNum( *iter ));
  221. break;
  222. }
  223. else
  224. return FALSE; // invalid character for binary numeric system
  225. //----------------------
  226. // Octal system
  227. case 8:
  228. // the next oct character is coming
  229. if( idx > ConvertNumerationSystem_limit_nsysoct )
  230. {
  231. // the limit exceeding (11 chars): the number can not be converted
  232. return FALSE;
  233. }
  234. else
  235. if( IsOctalChar( *iter ) )
  236. {
  237. if( ConvertNumerationSystem_limit_nsysoct == idx )
  238. if( IsOCT_Int32Overflow( *iter ) )
  239. {
  240. // 32-bit integer overflow
  241. return FALSE;
  242. }
  243. result <<= 3;
  244. result |= 0x7 & (OctCharToNum( *iter ));
  245. break;
  246. }
  247. else
  248. return FALSE; // invalid character for octal numeric system
  249. //----------------------
  250. // Hex system
  251. case 16:
  252. // the next hex character is coming
  253. if( idx > ConvertNumerationSystem_limit_nsyshex )
  254. {
  255. // the limit exceeding (8 chars): the number can not be converted
  256. return FALSE;
  257. }
  258. else
  259. if( IsHexademicalChar( *iter ) )
  260. {
  261. result <<= 4;
  262. result |= 0xF & (HexCharToNum( *iter ));
  263. break;
  264. }
  265. else
  266. return FALSE; // invalid character for hexademical numeric system
  267. break;
  268. }
  269. }
  270. // store the result
  271. if( NULL != pResult )
  272. *pResult = result;
  273. // store the iterator
  274. if( NULL != ppEnd)
  275. *ppEnd = iter;
  276. return TRUE;
  277. }
  278. size_t GPIB_Integer2Str( int32_t value, char * strBuf, size_t strBufSize, uint32_t compound_format )
  279. {
  280. size_t nSym = 0;
  281. sFormatInt2Str_t * format = (sFormatInt2Str_t*)(&compound_format);
  282. if( format->nLeadDigits > 10 ) // 10 digits max for int32_t
  283. return 0; // error
  284. if( 0 != format->nLeadDigits )
  285. {
  286. char formatstr[8] = { '\0' };
  287. snprintf( formatstr, sizeof(formatstr), "%c%c%d%c", '%', '0', format->nLeadDigits, 'd' );
  288. nSym = snprintf( strBuf, strBufSize, formatstr, value );
  289. }
  290. else
  291. {
  292. nSym = snprintf( strBuf, strBufSize, "%d", value );
  293. }
  294. if( nSym >= strBufSize )
  295. return 0; // error
  296. return nSym;
  297. }
  298. size_t GPIB_Float2Str( float value, char * strBuf, size_t strBufSize, uint32_t compound_format )
  299. {
  300. return GPIB_Double2Str( (double)value, strBuf, strBufSize, compound_format );
  301. }
  302. size_t GPIB_Double2Str( double value, char * strBuf, size_t strBufSize, uint32_t compound_format )
  303. {
  304. size_t nSym = 0;
  305. sFormatDouble2Str_t * format = (sFormatDouble2Str_t*)(&compound_format);
  306. if( 0 != format->bSciFormat )
  307. {
  308. // science format
  309. {
  310. char formatStr[16] = {0};
  311. size_t n = format->nFracDigits;
  312. if( 0 == n ) n = 10;
  313. snprintf( formatStr, sizeof(formatStr) - 1,
  314. "%c%c%d%c", '%', '.', n, 'e' );
  315. int rc = snprintf( strBuf, strBufSize,
  316. formatStr, value );
  317. if( rc < 0 )
  318. return 0;
  319. if( rc >= strBufSize )
  320. return 0;
  321. return (size_t)(rc);
  322. }
  323. /*
  324. bool sign = false;
  325. bool zero = false;
  326. if( value < 0 )
  327. {
  328. sign = true;
  329. value = -value;
  330. }
  331. // exponent part of science format,
  332. // e.g. for 0.0325: 0.0325 = 3.25e-2; exp = -2
  333. // e.g. for -15.993: -15.993 = -1.5993e+1; exp = 1
  334. // e.g. for 2.775: 2.775 = 2.775e+0; exp = 0
  335. int exp = 0;
  336. if( (value <= 1.0e-99) || (0.0 == value) )
  337. {
  338. exp = 0;
  339. (void)value;
  340. zero = true;
  341. }
  342. else
  343. if( (value <= 1) || (value >= 10) )
  344. {
  345. exp = (int)log10( value );
  346. value /= pow( 10, exp );
  347. }
  348. if( value < 1 && (value > 1.0e-99) ) // value less than 1.0e-99 is considered as zero
  349. {
  350. value *= (double)10.0;
  351. exp--;
  352. }
  353. else
  354. if( value >= 10 )
  355. {
  356. value /= (double)10.0;
  357. exp++;
  358. }
  359. // The function prints the value X.XXXXXXXXXXe+N
  360. // It is required to round the value up to 10 signs
  361. // 7.9999999999e+1 = 7.99999999990e+1
  362. // 7.99999999990e+1 + 0.00000000005 = 7.99999999995e+1
  363. // 7.99999999995e+1 => 8.0e+8
  364. //value += 5.0 * pow( 10, exp - 9);
  365. if( !zero )
  366. {
  367. value += 5.0e-11;
  368. }
  369. size_t expChars = 1; // 1 char for exp=0, "0"
  370. // expChars: amount of demical characters of @exp
  371. if( 0 != exp )
  372. {
  373. expChars = (size_t)ceil( log10( abs( exp ) ) );
  374. }
  375. if( 0 == format->nFracDigits )
  376. {
  377. format->nFracDigits = 10;
  378. }
  379. // science format
  380. if( format->nFracDigits // fractional part
  381. + 1 // integer part
  382. + 1 // dot
  383. + (sign?1:0) // sign
  384. + 2 // e+ or e-
  385. + expChars
  386. > strBufSize )
  387. {
  388. // not enough free space in the buffer
  389. return 0;
  390. }
  391. // print a sign
  392. if( sign )
  393. {
  394. if( strBufSize > 0 )
  395. {
  396. strBuf[nSym] = '-';
  397. nSym++;
  398. strBufSize--;
  399. }
  400. else
  401. {
  402. nSym = 0;
  403. goto L_Double2Str_EXIT;
  404. }
  405. }
  406. if( strBufSize > 0 )
  407. {
  408. int i = (int)value;
  409. strBuf[nSym] = '0' + i;
  410. strBufSize--;
  411. nSym++;
  412. //if( i > 9 ) asm("bkpt #0");
  413. value -= i; // substract integer part
  414. }
  415. else
  416. {
  417. nSym = 0;
  418. goto L_Double2Str_EXIT;
  419. }
  420. if( strBufSize > 0 )
  421. {
  422. strBuf[nSym] = '.';
  423. nSym++;
  424. strBufSize--;
  425. }
  426. else
  427. {
  428. nSym = 0;
  429. goto L_Double2Str_EXIT;
  430. }
  431. if( strBufSize > 0 )
  432. {
  433. size_t fracDigits = format->nFracDigits;
  434. if( fracDigits == 0 )
  435. fracDigits = 10;
  436. while( fracDigits > 0 )
  437. {
  438. value *= 10;
  439. int digit = (int)(value);
  440. value -= digit;
  441. if( fracDigits > 0 )
  442. fracDigits--;
  443. if( strBufSize > 0 )
  444. {
  445. strBuf[nSym] = ('0' + digit);
  446. nSym++;
  447. strBufSize--;
  448. }
  449. else
  450. {
  451. nSym = 0;
  452. goto L_Double2Str_EXIT;
  453. }
  454. }
  455. }
  456. else
  457. {
  458. nSym = 0;
  459. goto L_Double2Str_EXIT;
  460. }
  461. if( 2 + expChars <= strBufSize )
  462. {
  463. strBuf[nSym] = 'e';
  464. nSym++;
  465. strBuf[nSym] = ((exp<0)?'-':'+');
  466. nSym++;
  467. exp = abs(exp);
  468. do
  469. {
  470. if( 0 == strBufSize )
  471. {
  472. nSym = 0;
  473. goto L_Double2Str_EXIT;
  474. }
  475. int digit = 0;
  476. int power = 0;
  477. if( exp != 0 )
  478. {
  479. power = (int)log10( exp );
  480. power = (int)pow( 10, power );
  481. digit = (exp / power);
  482. }
  483. strBuf[nSym] = '0' + digit;
  484. nSym++;
  485. strBufSize--;
  486. exp -= power * digit;
  487. }
  488. while( exp > 0 );
  489. }
  490. else
  491. {
  492. nSym = 0;
  493. goto L_Double2Str_EXIT;
  494. }
  495. */
  496. }
  497. else
  498. {
  499. // float point format
  500. if( 0 == format->nFracDigits )
  501. {
  502. format->nFracDigits = 8;
  503. }
  504. {
  505. char formatStr[16] = {0};
  506. if( 0 == format->nLeadDigits )
  507. snprintf( formatStr, sizeof(formatStr)-1,
  508. "%c%c%d%c", '%', '.', format->nFracDigits, 'f' );
  509. else
  510. snprintf( formatStr, sizeof(formatStr)-1,
  511. "%c%d%c%d%c", '%', format->nLeadDigits, '.', format->nFracDigits, 'f' );
  512. int rc = snprintf( strBuf, strBufSize,
  513. formatStr, value );
  514. if( rc < 0 )
  515. return 0;
  516. if( rc >= strBufSize )
  517. return 0;
  518. return (size_t)rc;
  519. }
  520. /*
  521. if( format->nFracDigits
  522. + format->nLeadDigits
  523. + 1 // dot
  524. + (0>value?1:0) // sign
  525. > strBufSize )
  526. {
  527. // not enough free space in the buffer
  528. return 0;
  529. }
  530. // print a sign
  531. if( value < 0 )
  532. {
  533. strBuf[nSym] = '-';
  534. nSym++;
  535. strBufSize--;
  536. value = -value;
  537. }
  538. // Process leading zeros
  539. {
  540. size_t leadDigits = 1;
  541. // for numbers @value greater than 1 or equal the one,
  542. // the amount of leading digits can be caluculated as following.
  543. // Otherwise, for numbers less than 1, this amount is 1.
  544. // e.g. leadDigits =3 for 100.2
  545. // leadDigits =2 for 97.8
  546. // leadDigits =1 for 1.999
  547. // leadDigits =1 for 1.000
  548. // leadDigits =1 for 0.538
  549. if( value >= 1 )
  550. {
  551. // calculate amount of leading integer digits of the @value
  552. leadDigits = (int)ceil( log10( value ) );
  553. }
  554. else
  555. {
  556. // The value is less than 1.
  557. // In this case a leading zero must be added.
  558. if( format->nLeadDigits == 0 )
  559. {
  560. // If @nLeadDigits not specified,
  561. // it is required to make the next condition true,
  562. // to peform adding a leading zero
  563. //format->nLeadDigits = (1 + leadDigits);
  564. }
  565. }
  566. // Specified number of lead digits in the format
  567. // greater than actual count of lead digits: need to
  568. // add leading zeros.
  569. if( (leadDigits < format->nLeadDigits) )
  570. {
  571. //if( format->nLeadDigits == 0 )
  572. // (void)leadDigits; // do not change value
  573. //else
  574. leadDigits = format->nLeadDigits - leadDigits;
  575. // add leading zeros
  576. while( leadDigits > 0 )
  577. {
  578. strBuf[nSym] = '0';
  579. nSym++;
  580. strBufSize--;
  581. leadDigits--;
  582. }
  583. }
  584. }
  585. {
  586. int power = 1;
  587. if( value > 1e-99 ) // the value less than 1e-99 is considered as zero
  588. {
  589. power = (int)pow( 10, (int)log10( value ) );
  590. }
  591. if( 0 == power )
  592. {
  593. strBuf[nSym] = ('0');
  594. nSym++;
  595. strBufSize--;
  596. }
  597. while( power > 0 )
  598. {
  599. int digit = (int)value / power;
  600. value -= digit * power;
  601. power /= 10;
  602. if( strBufSize > 0 )
  603. {
  604. strBuf[nSym] = ('0' + digit);
  605. nSym++;
  606. strBufSize--;
  607. }
  608. else
  609. {
  610. nSym = 0;
  611. goto L_Double2Str_EXIT;
  612. }
  613. }
  614. }
  615. if( strBufSize > 0 )
  616. {
  617. strBuf[nSym] = '.';
  618. nSym++;
  619. strBufSize--;
  620. }
  621. {
  622. size_t fracDigits = format->nFracDigits;
  623. while( fracDigits > 0 )
  624. {
  625. value *= 10;
  626. int digit = (int)(value);
  627. value -= digit;
  628. if( fracDigits > 0 )
  629. fracDigits--;
  630. if( strBufSize > 0 )
  631. {
  632. strBuf[nSym] = ('0' + digit);
  633. nSym++;
  634. strBufSize--;
  635. }
  636. else
  637. {
  638. nSym = 0;
  639. goto L_Double2Str_EXIT;
  640. }
  641. }
  642. }
  643. */
  644. }
  645. //L_Double2Str_EXIT:
  646. return nSym;
  647. }