gpib_parser_strutils.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. #include "gpib_parser_casts.h"
  2. #include "gpib_parser_validators_numbers.h" // Validators for numbers
  3. #include "gpib_parser_chars.h" // Service characters definitions
  4. #include "gpib_parser_validators.h"
  5. #include "gpib_parser_numutils.h"
  6. #include "gpib_parser_strutils.h"
  7. #include <stdlib.h> // atoi
  8. #include "usb\utils.h" // s_memcpy()
  9. //------------------------------------------------------------------------------
  10. static char SCPIBuffer[ STRCACHE_BUFFER_SIZE ];
  11. //------------------------------------------------------------------------------
  12. // GPIB_StrChkFormat:
  13. // Checks the string @str limited by @length characters for matching to the format @mode.
  14. // In case all of the characters til the end of string (not far than @length characters) are
  15. // match to the format @mode, function returns TRUE. otherwise, it returns FALSE.
  16. BOOL GPIB_StrChkFormat( const char * str, int length, const eStringCheckMode_t mode )
  17. {
  18. // return FALSE in case @str is NULL, or @length is zero
  19. if( NULL == str || 0 >= length )
  20. return FALSE;
  21. // result by default is FALSE
  22. BOOL rval = FALSE;
  23. // Check til the end of string limited by @length
  24. // Every step decrement @length and increment @str
  25. for( (void)0; (length > 0); length --, str ++ )
  26. {
  27. // Check for the end-of-string
  28. // Check for the end-of-line
  29. if( IsEndOfString( *str ) || IsEndOfLine( *str ) )
  30. break; // If found, interrupt the processing and return the current result
  31. switch( mode )
  32. {
  33. case eSCM_DEC: rval = IsDemicalChar( *str ); break;
  34. case eSCM_HEX: rval = IsHexademicalChar( *str ); break;
  35. case eSCM_FLOAT: rval = IsFloatChar( *str ); break;
  36. case eSCM_EXP: rval = IsExponentialChar( *str ); break;
  37. case eSCM_BIN: rval = IsBinaryChar( *str ); break;
  38. case eSCM_MNEMONIC: rval = IsCharacter( *str ) || IsNumber( *str ); break;
  39. case eSCM_DIGIT: rval = IsDigit( *str ); break;
  40. }
  41. // In case of first unsuccessful result, break and return current result (false)
  42. if( !(rval) ) break;
  43. }
  44. return rval;
  45. }
  46. //---------------------------
  47. // @GPIB_StrCopyToCache:
  48. // Caches the given string @source into the internal buffer and returns the new pointer
  49. char * GPIB_StrCopyToCache( const char * source, size_t length )
  50. {
  51. char * dest;
  52. if( length+1 <= STRCACHE_BUFFER_SIZE )
  53. dest = &SCPIBuffer[0];
  54. else
  55. dest = NULL;
  56. if( !IsCorrectPointer (dest) )
  57. dest = NULL;
  58. else
  59. {
  60. s_memcpy( dest, source, length );
  61. strucase( dest, length - 1 );
  62. dest [ length ] = 0;
  63. }
  64. return dest;
  65. }
  66. // GPIB_GetStringEnd:
  67. // Searches for the end of the string @gpibstr until the end of @gpibstr is reached
  68. // or @length characters is processed
  69. // Note: the string must be quotted in single or double quotes.
  70. const char * GPIB_GetStringEnd( const char * gpibstr, size_t length )
  71. {
  72. // It is assumed the quotted string can not be shorter than 2 characters
  73. if( (NULL == gpibstr) || (2 > length) )
  74. return NULL;
  75. // detect the quotting mode: single or doulbe
  76. eQuoteMode_t qMode = eqmNone;
  77. if( IsSingleQuote( *gpibstr ) )
  78. {
  79. qMode = eqmSingle;
  80. }
  81. else
  82. if( IsDoubleQuote( *gpibstr ) )
  83. {
  84. qMode = eqmDouble;
  85. }
  86. else
  87. {
  88. return NULL;
  89. }
  90. const char * end = NULL; // end of the string pointer
  91. BOOL bQuoteOpened = FALSE;
  92. // for each of @length characters in the string
  93. for( const char * iter = gpibstr; iter != (gpibstr + length); ++iter )
  94. {
  95. // If the current parameter is end-of-line or end-of-string,
  96. // and the cycle is still counting, it means error condition,
  97. // due to @length is specified incorrectly.
  98. if( IsEndOfString( *iter ) || IsEndOfLine( *iter ) )
  99. {
  100. return NULL;
  101. }
  102. if( IsQuote(*iter,qMode) )
  103. {
  104. // If the quotted string opened (opening quote passed)
  105. if( bQuoteOpened )
  106. {
  107. // End-of-quotted string found
  108. end = ++iter;
  109. break;
  110. }
  111. else
  112. {
  113. // The quotted string opened
  114. bQuoteOpened = TRUE;
  115. }
  116. }
  117. }
  118. return end;
  119. }
  120. // GPIB_GetParameterEnd:
  121. // Searches for the end signature of the parameter in @string until the
  122. // end of @string string is reached or @length characters is processed.
  123. // The first "white" character is treated as an end signature.
  124. // Does not support SCPI DataBlock format.
  125. const char * GPIB_GetParameterEnd( const char * string, size_t length )
  126. {
  127. if( (NULL == string) || (0 == length) )
  128. return NULL;
  129. const char * end = (string + length); // end of the string pointer
  130. // for each of @length characters in the string
  131. for( const char * iter = string; iter != end; ++iter )
  132. {
  133. // If the current parameter is end-of-line, end-of-string or white-character
  134. // then it means the end of the parameter reached.
  135. if( IsEndOfString( *iter ) || IsEndOfLine( *iter ) || IsWhiteChar( *iter ) )
  136. {
  137. return iter;
  138. }
  139. // If the current parameter is an argument separator then
  140. // it means the end of the parameter reached.
  141. if( IsArgSeparatorChar( *iter ) )
  142. {
  143. return iter;
  144. }
  145. }
  146. // Neither end-of-line, end-of-string or white-character found.
  147. // The end of the parameter is out of string.
  148. return end;
  149. }
  150. // GPIB_StrChr:
  151. // Searches a character @chr in the string beginning from @str and limited by @end.
  152. // If the function faces a null-character or end-of-line condition, it stops searching.
  153. // Function returns the pointer to the found character in @str, or NULL if not found.
  154. const char * GPIB_StrChr( const char * str, const char chr, const char * end )
  155. {
  156. for( const char * iter = str; iter != end; ++iter )
  157. {
  158. // Check the limits
  159. if( IsEndOfString( *iter ) || IsEndOfLine( *iter ) )
  160. {
  161. // end-of-string condition: interrupt the searching
  162. // end-of-line condition: interrupt the searching
  163. break;
  164. }
  165. if( chr == *iter )
  166. {
  167. return iter;
  168. }
  169. }
  170. // not found
  171. return NULL;
  172. }
  173. // GPIB_StrLen:
  174. // Calculates the length of string.
  175. // The function assumes that the string ends with either end-of-line character
  176. // or end-of-string character.
  177. size_t GPIB_StrLen( const char * str )
  178. {
  179. if( NULL == str )
  180. return 0;
  181. for( const char * iter = str; (void)iter, !0; ++iter )
  182. {
  183. // Check the limits
  184. if( IsEndOfString( *iter ) || IsEndOfLine( *iter ) )
  185. {
  186. // end-of-string condition: end the searching
  187. // end-of-line condition: end the searching
  188. return SubPointers( iter, str );
  189. }
  190. }
  191. // never reachs this point
  192. return 0;
  193. }
  194. // GPIB_CheckHeader:
  195. // Check if the given @header is valid GPIB header.
  196. // Returns TRUE if it is, and FALSE otherwise.
  197. //BOOL GPIB_CheckHeader( const char * header )
  198. BOOL GPIB_CheckHeader( const char * header, const char * end )
  199. {
  200. if( NULL == header )
  201. return FALSE;
  202. // disallow the number in the beginning of @header
  203. if( IsNUMBER( *header ) )
  204. return FALSE;
  205. BOOL rval = TRUE;
  206. // allow one 'MANDATORY' signature (by default '*', e.g "*IDN?") in
  207. // the beginning of the string
  208. if( GPIB_CHAR_MANDATORY_IEEE488_SIGN == *header )
  209. {
  210. // skip only the first MANDATORY character
  211. ++ header;
  212. }
  213. for( const char * iter = header; (void)iter, !0; ++iter )
  214. {
  215. // Check the end condition
  216. if( iter == end )
  217. {
  218. (void)rval;
  219. break;
  220. }
  221. // Check the limits
  222. if( IsEndOfString( *iter ) || IsEndOfLine( *iter ) )
  223. {
  224. // end-of-string condition: interrupt validating
  225. // end-of-line condition: interrupt validating
  226. break;
  227. }
  228. // check if the character is valid for the GPIB header body
  229. if( ! IsValid_GPIBHeaderBodyChar( *iter ) )
  230. {
  231. // if at least one character is invalid, break and return FALSE
  232. rval = FALSE;
  233. break;
  234. }
  235. }
  236. return rval;
  237. }
  238. // GPIB_HeaderCompare:
  239. // Compares a couple of GPIB command headers.
  240. // Note: the comparation is case insensitive.
  241. // @headerTree - the original command header, including an optional command
  242. // signature (if required), e.g. optional "[SYSTem]" or mandatory "SYST"
  243. // @headerUser - actually entered command header
  244. // Note: for optional headers it is not required a paired ']' in the end of header.
  245. // Returns TRUE if headers are identical, and FALSE otherwise.
  246. BOOL GPIB_HeaderCompare( const char * headerTree, const char * headerUser )
  247. {
  248. BOOL bOptional = FALSE;
  249. BOOL bFirst = TRUE;
  250. //size_t strlen_Tree = GPIB_StrLen( headerTree );
  251. //size_t strlen_User = GPIB_StrLen( headerUser );
  252. if( IsOptionalHeader(headerTree) )
  253. {
  254. headerTree++;
  255. bOptional = TRUE;
  256. }
  257. const char * iter_tree;
  258. const char * iter_user;
  259. // For each character in the original string @headerTree and the
  260. // entered string @headerUser simultaneosly.
  261. for( iter_tree = headerTree, // iterator for original string
  262. iter_user = headerUser, // iterator for entered string
  263. bFirst = TRUE; // the first character sign
  264. (void)iter_tree, //
  265. (void)iter_user, //
  266. !0; // do this cycle forever
  267. ++iter_tree, // next character in the original string
  268. ++iter_user, // next character in the entered string
  269. bFirst = FALSE ) // reset @bFirst after the first character in the string
  270. {
  271. // Check the limits:
  272. // If the end of original string is faced.
  273. if( IsEndOfString( *iter_tree ) || IsEndOfLine( *iter_tree ) )
  274. {
  275. // and the end of the entered string is faced too
  276. if( IsEndOfString( *iter_user ) || IsEndOfLine( *iter_user ) )
  277. {
  278. // headers are identical due to all the characters til
  279. // the end of both strings are identical.
  280. return TRUE;
  281. }
  282. }
  283. else
  284. // The end of original string is NOT faced yet.
  285. {
  286. // But if the end of the entered string is faced
  287. if( IsEndOfString( *iter_user ) || IsEndOfLine( *iter_user ) )
  288. {
  289. // end of compare
  290. // strings mismatch
  291. // But wait, let's check for the optional header signature in
  292. // the end of original string (by default, ']')
  293. // Check if the header is optional
  294. if( bOptional )
  295. {
  296. // yes, it is optional
  297. // check if the next character in the original string is
  298. // a closing sign of optional header (by default, ']')
  299. if( GPIB_CHAR_OPTIONALHEADER_ENDSIGN == *iter_tree )
  300. {
  301. // yes, it is.
  302. // Actually, the headers are identical til the
  303. // closing sign.
  304. // ignore the rest part of original string, and
  305. // assume the headers are identical
  306. return TRUE;
  307. }
  308. }
  309. // No choice left: headers mismatch
  310. break;
  311. }
  312. }
  313. // Check for optional marker (by default, '[') in the beginning of the original string
  314. if( (bFirst) && (GPIB_CHAR_OPTIONALHEADER_SIGN == *iter_tree) )
  315. {
  316. // This header is a header of optional SCPI-subsystem
  317. bOptional = TRUE;
  318. // skip this character
  319. iter_tree++;
  320. // continue the comparation
  321. continue;
  322. }
  323. // characters mismatch
  324. // Note: comparation is case insensetive.
  325. if( tolower(*iter_tree) != tolower(*iter_user) )
  326. {
  327. // strings mismatch
  328. break;
  329. }
  330. }
  331. // headers mismatch
  332. return FALSE;
  333. }
  334. // GPIB_StringToNumber:
  335. // Converts the string into a number
  336. // @str - source string pointer
  337. // @chars - number of characters to be converted (can not be greater than 10)
  338. // @pReturn - pointer to the receiving variable, can be NULL
  339. // Result: TRUE in case of success, FALSE otherwise.
  340. // In case the given number is valid and @pReturn is NULL, function just return TRUE
  341. // This behaviour can be used to validate numbers without parsing.
  342. BOOL GPIB_StringToNumber( const char * str, size_t chars, int32_t * pReturn )
  343. {
  344. char buffer[ 11 ] = {0};
  345. if( chars > 10 )
  346. return FALSE; // too long string
  347. if( chars == 0 )
  348. return FALSE; // too short string
  349. // validate the string
  350. BOOL allow_sign = TRUE; // flag: allow the sign operator (plus/minus)
  351. BOOL allow_space = TRUE; // flag: allow the space
  352. BOOL allow_digit = TRUE; // flag: allow a digit
  353. BOOL digits = FALSE; // flag: digits detected
  354. for( const char * iter = str; iter != (str+chars); ++iter )
  355. {
  356. if( '\0' == *iter )
  357. break;
  358. // the space faced
  359. if( ' ' == *iter )
  360. {
  361. // if the space is allowed
  362. if( allow_space )
  363. {
  364. // if digits already faced
  365. if( digits )
  366. {
  367. // allow only spaces til the end
  368. allow_digit = FALSE;
  369. }
  370. continue;
  371. }
  372. else
  373. {
  374. return FALSE; // error: space is unexpected
  375. }
  376. }
  377. // the sign faced
  378. if( '+' == *iter || '-' == *iter )
  379. {
  380. if( allow_sign )
  381. {
  382. allow_sign = FALSE; // only one operator is allowed
  383. allow_space = FALSE; // disallow the space after the operator
  384. continue;
  385. }
  386. return FALSE; // error: extra sign operator
  387. }
  388. // a digit faced
  389. if( IsDigit( *iter ) )
  390. {
  391. if( allow_digit )
  392. {
  393. allow_sign = FALSE; // operator must be before any digit
  394. allow_space = TRUE; // allow any amount of spaces after last digit
  395. digits = TRUE; // digits faced
  396. continue;
  397. }
  398. return FALSE; // error: separated tokens detected
  399. }
  400. return FALSE; // error by default. the "continue" must prevent this return
  401. }
  402. // here: the string contains a valid number
  403. // if @pReturn is NULL, just return the result of validating
  404. if( NULL == pReturn )
  405. return TRUE;
  406. s_memcpy( buffer, str, chars );
  407. buffer[chars] = '\0'; // null terminator
  408. *pReturn = atoi( buffer );
  409. return TRUE;
  410. }
  411. // IsDataBlock:
  412. // The data transfer block validator: Binary transfer format (IEEE488.2)
  413. // Format: the data block consist of the following elements: '#', N, Z, DATA
  414. // '#' - data block signature character;
  415. // N - a demical digit, amount of digits in Z;
  416. // Z - a demical number (multi-digit), the size of binary bytes in DATA.
  417. // DATA - binary data bytes.
  418. // e.g. "#213Hello, world!"
  419. // N=2 - amount of digits in Z
  420. // Z=13 - amount of binary bytes (strlen(DATA)=13)
  421. // DATA = "Hello, world!"
  422. //
  423. // @begin - the string to validate
  424. // @length - the length of string @begin
  425. // @p_nsize - optional pointer which will be filled up with the datablock size in bytes
  426. // @pRetCode - optional pointer to store either the error variable to be filled with the
  427. // error code, or in case sucess the binary data payload size in bytes.
  428. // *pRetCode can be:
  429. // > (err_IsDataBlock_Success) - success (never returns);
  430. // > (err_IsDataBlock_NotFound) - datablock not found;
  431. // > (err_IsDataBlock_Invalid) - datablock found, but has invalid format
  432. // > (err_IsDataBlock_Trimmed) - datablock found, but it is trimmed
  433. // > (err_IsDataBlock_Huge) - datablock found, but it's too large
  434. // > the binary payload size
  435. //
  436. // Returns TRUE only if the datablock format is valid, all the parameter of datablock
  437. // are valid and do not violates any ranges.
  438. BOOL IsDataBlock( const char * begin, size_t length, size_t * p_nsize, int * pRetCode )
  439. {
  440. int error = 0;
  441. size_t N = 0;
  442. int32_t Z = 0;
  443. const char * iter = NULL;
  444. // at least 2 bytes required
  445. if( NULL == begin || 2 > length )
  446. {
  447. // invalid parameters
  448. // error: datablock not found
  449. error = err_IsDataBlock_NotFound;
  450. goto L_IsDataBlock_ERR;
  451. }
  452. // check the signature
  453. if( GPIB_CHAR_DATATABLE_SIGN != *begin )
  454. {
  455. // invalid: no signature
  456. // error: datablock not found
  457. error = err_IsDataBlock_NotFound;
  458. goto L_IsDataBlock_ERR;
  459. }
  460. iter = begin;
  461. { // decrease length and shift iterator: '#'
  462. length--;
  463. iter++;
  464. }
  465. if( !IsDemicalChar( *iter ) )
  466. {
  467. // invalid: "N" must be a demical digit (amount of characters in "Z")
  468. // error: datablock not found
  469. error = err_IsDataBlock_NotFound;
  470. goto L_IsDataBlock_ERR;
  471. }
  472. N = DecCharToNum( *iter ); // number of characters in "Z"
  473. { // decrease length and shift iterator: 'N'
  474. length--;
  475. iter++;
  476. }
  477. if( N == 0 )
  478. {
  479. // invalid: N can not be zero
  480. // error: datablock found with invalid format
  481. error = err_IsDataBlock_Invalid;
  482. goto L_IsDataBlock_ERR;
  483. }
  484. if( (length == 0) || (length < N) )
  485. {
  486. // empty data block
  487. // error: trimmed datablock found
  488. error = err_IsDataBlock_Trimmed;
  489. goto L_IsDataBlock_ERR;
  490. }
  491. // check the int32 overflow condition:
  492. // If N=9, it means Z is less than 1000000000
  493. // and there no necessary to provide any checks.
  494. // Lets choose this way.
  495. if( N > 9 )
  496. {
  497. // integer overflow
  498. // error: datablock is too large.
  499. error = err_IsDataBlock_Huge;
  500. goto L_IsDataBlock_ERR;
  501. }
  502. // validate "Z" - must be a demical digits
  503. if( !GPIB_StrChkFormat( iter, N, eSCM_DIGIT ) )
  504. {
  505. // invalid: invalid format of "Z"
  506. // error: datablock found with invalid format
  507. error = err_IsDataBlock_Invalid;
  508. goto L_IsDataBlock_ERR;
  509. }
  510. Z = 0;
  511. // Parse the number "Z"
  512. if( !GPIB_StringToNumber( iter, N, &Z ) )
  513. {
  514. // invalid number "Z"
  515. // error: datablock found with invalid format
  516. error = err_IsDataBlock_Invalid;
  517. goto L_IsDataBlock_ERR;
  518. }
  519. { // decrease length and shift iterator: 'Z'
  520. length-=N;
  521. iter+=N;
  522. }
  523. // check if the datablock fits into the given string
  524. if( Z > length )
  525. {
  526. // trimmed data block
  527. // error: trimmed datablock found
  528. error = err_IsDataBlock_Trimmed;
  529. goto L_IsDataBlock_ERR;
  530. }
  531. // Okay, it seems to be valid...
  532. { // decrease length and shift iterator: 'DATA'
  533. length-=Z;
  534. iter+=Z;
  535. }
  536. // if @p_nsize is specified
  537. if( NULL != p_nsize )
  538. *p_nsize = SubPointers( iter, begin ); // store the datablock size in bytes
  539. // store the binary data size into @error
  540. if( NULL != pRetCode ) *pRetCode = Z;
  541. return TRUE;
  542. L_IsDataBlock_ERR:
  543. if( NULL != pRetCode ) *pRetCode = error;
  544. return FALSE;
  545. }
  546. // #########################################################################
  547. // #########################################################################
  548. // #########################################################################
  549. // #########################################################################
  550. // #########################################################################
  551. // #########################################################################
  552. // #########################################################################
  553. // #########################################################################
  554. // #########################################################################
  555. //-----------------------------------
  556. /*
  557. char * s_strchrex( char * str, char chr, char * end )
  558. {
  559. register char * strp = str;
  560. char * ret = NULL;
  561. while(ret==NULL)
  562. { if((unsigned int)end <= (unsigned int)str) break;
  563. if(*strp==chr) ret = strp;
  564. strp++;
  565. }
  566. return ret;
  567. }
  568. */
  569. /*
  570. char * strterm( char * source, unsigned int length )
  571. {
  572. //<W><W><W>AAAA<W><W><0> -> <W><W><W>AAAA<0>
  573. while(!IsWhiteChar(*source) && length--)
  574. source++;
  575. if(length>0) *source = 0x00;
  576. return source;
  577. }
  578. */
  579. //-----------------------------------
  580. /*
  581. int strsep( char * source, unsigned int length )
  582. {
  583. int first = 0;
  584. //<W><W>BBBBB<W><W>AAAA<W><W><0> -> <W><W><W>AAAA<0>
  585. while(IsWhiteChar(*source) && length--) source++;
  586. first = length;
  587. while(!IsWhiteChar(*source) && length--)
  588. source++;
  589. if(length>0) *source = 0x00;
  590. return first;
  591. }
  592. */
  593. // ===================================== Ïðåîáðàçîâàíèå ÷èñåë â ñòðîêè ===========================
  594. // -----------------------
  595. //
  596. //
  597. //
  598. //
  599. //
  600. /*
  601. // ------------------- FloatsToString --------------
  602. //
  603. // Èñïîëüçîâàíèå:
  604. //
  605. // char buffer[32];
  606. // float f1,f2,f3,f4,f5,f6,f7,f8=3.142;
  607. // GPIB_PrintFloat( buffer, 32, 1000, 8, &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8 );
  608. // ^^^^ òî÷íîòü ïîñëå çàïÿòîé
  609. //
  610. // buffer=="0.000,0.000,0.000,0.000,0.000,0.000,0.000,3.142"
  611. unsigned int GPIB_PrintFloatEx( char * out, int buffersize, unsigned int accuracy, int count, float * f1, ...)
  612. {
  613. int l=0,c=0;
  614. unsigned char buffer[10] = {0};
  615. while( count-- && c<buffersize )
  616. {
  617. if(c){
  618. *(out+c) = ',';
  619. c++;}
  620. l = Float2StrEx( f1, buffer, 10, accuracy);
  621. s_memcpy( out+c, buffer, l );
  622. c+=l;
  623. f1++;
  624. }
  625. return c;
  626. }
  627. */
  628. /*
  629. unsigned int GPIB_PrintHex( char * out, int buffersize, int count, int * hex1, ...)
  630. {
  631. int c=0;
  632. while( count-- && c < buffersize )
  633. {
  634. if(c)
  635. c+= snprintf( out+c, buffersize-c, "," );
  636. c+= snprintf( out+c, buffersize-c, "%x", *hex1 );
  637. hex1++;
  638. }
  639. return c;
  640. }
  641. */
  642. // ---------------------------------------------------------------------------------------------
  643. /*
  644. unsigned int GPIB_PrintBin( char * out, int buffersize, int count, unsigned int bin, ...)
  645. {
  646. int c=0;
  647. unsigned int * bin1 = &bin;
  648. unsigned int mask;
  649. while( count-- && c < buffersize )
  650. {
  651. if(c)
  652. c+= snprintf( out+c, buffersize-c, "," );
  653. // -----------------------------
  654. if( (c < buffersize) ) *(out+c++) = '0';
  655. if( (c < buffersize) ) *(out+c++) = 'b';
  656. mask = 0x80000000; // 0b10000000000000000000000000000000
  657. while( mask && (c < buffersize) )
  658. {
  659. if( mask & *bin1 )
  660. *(out+c++) = '1';
  661. else
  662. *(out+c++) = '0';
  663. if( mask & (1<<0) )
  664. mask = 0x00000000;
  665. else
  666. mask>>=1;
  667. }
  668. // -----------------------------
  669. bin1++;
  670. }
  671. return c;
  672. }
  673. */
  674. /*
  675. // ------------ s_printf ----------------------------------
  676. // Ïîääåðæêà ñïåöèôèêàòîðîâ:
  677. // 0 %c - char
  678. // 1 %s - string
  679. // 2 %d - int
  680. // 3 %u - unsigned int
  681. // 4 %f - float (!)
  682. // 5 %x - hex
  683. // 6 %b - bin
  684. // 7 %o - oct
  685. // 8 %e - scientific number
  686. // -------------------------- ÇÍÀ×ÅÍÈß ÏÅÐÅÄÀÞÒÑß ÏÎ ÓÊÀÇÀÒÅËÞ !
  687. unsigned int s_nprintf( char * out, int buffersize, char * spec, /_* char , int , float , unsigned *_/... )
  688. {
  689. // Ïðè ïåðåäà÷å ïàðàìåòðîâ ÷åðåç ñòåê â ôóíêöèþ, êîòîðàÿ íå èìååò ôîðìàëüíûõ àðãóìåíòîâ
  690. // äåéñòâóåò ïðàâèëî ïðèâåäåíèÿ float->double. Double íà ñòåêå âûðâàíèâàåòñÿ ïî 8 áàéò
  691. //
  692. //
  693. char * pointer = (char*)(&spec)+sizeof(char*);
  694. unsigned int c = 0; // -- êîëè÷åñòâî âûâîäèìûõ â áóôåð ñèìâîëîâ
  695. unsigned int k = 0; // -- äëÿ öèêëà ïî ñïåöèôèêàòîðàì
  696. unsigned int z = 0; // -- äëÿ ïîèñêà ñïåöèôèêàòîðà
  697. int t = 0;
  698. char * s, * __s; // -- õðàíèò ñäâèã ïî spec
  699. int zmin = -1; // -- äëÿ ïîèñêà ñïåöèôèêàòîðà
  700. #define fc 9
  701. unsigned char specs[fc] = { 'c', 's', 'd', 'u', 'f', 'x', 'b', 'o', 'e' };
  702. while( c < buffersize && *spec && t!=-1)
  703. if(*spec == '%'){
  704. // ------------ îïðåäåëåíèå òèïà ------------
  705. for(k=0,t=-1,zmin=-1;k<=fc;k++)
  706. if( (__s= GPIB_StrChr( spec, specs[k], NULL)) || (__s= GPIB_StrChr( spec, 0x20 + specs[k], NULL))) // ucase support also
  707. {
  708. z=(unsigned int)__s - (unsigned int)spec;
  709. if(zmin > z || zmin ==-1)
  710. { zmin = z;
  711. t=k; // òèï
  712. s=__s; // îïðåäåëÿåò êîíåö ñïåöèôèêàòîðà
  713. }
  714. }
  715. //--------------------------------------------
  716. switch(t)
  717. {
  718. case 0: // %c
  719. // -- char ïðåîáðàçîâàí ê int
  720. c+=snprintf( out+c, buffersize-c, "%c", *((int *)pointer));
  721. pointer+=sizeof(unsigned int);
  722. spec = s+1;
  723. break;
  724. case 1: // %s
  725. c+=snprintf( out+c, buffersize-c, "%s", (char *)pointer);
  726. pointer+=sizeof(char*);
  727. spec = s+1;
  728. break;
  729. case 2: // %d
  730. c+=snprintf( out+c, buffersize-c, "%d", *((int *)pointer));
  731. pointer+=sizeof(int);
  732. spec = s+1;
  733. break;
  734. case 3: // %u
  735. c+=snprintf( out+c, buffersize-c, "%u", *((unsigned int *)pointer));
  736. pointer+=sizeof(unsigned int);
  737. spec = s+1;
  738. break;
  739. case 4: // %f
  740. // case 8: // %e
  741. if((int)pointer&0x07) pointer+= (int)pointer%8; // Ñòàíäàðòíîå ïðîäâèæåíèå òèïîâ. Åñëè ââîäèòü ôóíêöèþ áåç ôîðìàëüíûõ
  742. // ïàðàìåòðîâ, òî float áóäåò ïðåîáðàçîâàí ê double, char ê int è ò.ï.
  743. // double âåñèò 8 áàéò, ïîýòîìó íàäî ýòî ó÷èòûâàòü ïðè ïåðåäâèæåíèè óêàçàòåëÿ
  744. c+=snprintf( out+c, buffersize-c, "%lf", *((double *)pointer));
  745. pointer+=sizeof(double); // double!
  746. spec = s+1;
  747. break;
  748. case 5: // %x
  749. c+=snprintf( out+c, buffersize-c, "%x", *((unsigned int *)pointer));
  750. pointer+=sizeof(unsigned int);
  751. spec = s+1;
  752. break;
  753. case 6: // %b
  754. c+=GPIB_PrintBin( out+c, buffersize-c, 1, *((unsigned int*)pointer));
  755. pointer+=sizeof(unsigned int); // double!
  756. spec = s+1;
  757. break;
  758. case 7: // %o
  759. c+=snprintf( out+c, buffersize-c, "%o", *((unsigned int *)pointer));
  760. pointer+=sizeof(unsigned int);
  761. spec = s+1;
  762. break;
  763. case 8: // %e
  764. c+=snprintf( out+c, buffersize-c, "%e", *((double*)pointer));
  765. pointer+=sizeof(double);
  766. spec = s+1;
  767. break;
  768. default:
  769. if( t==-1) break;
  770. spec = s+1;
  771. }
  772. } else
  773. {snprintf( out+c, buffersize-c, "%c", *(spec++) ); c++;}
  774. return c;
  775. }
  776. */