Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
test_env.cpp
00001 /* 00002 * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include <ctype.h> 00019 #include <cstdio> 00020 #include <string.h> 00021 #include "mbed.h" 00022 #include "greentea-client/test_env.h" 00023 #include "greentea-client/greentea_serial.h" 00024 #include "greentea-client/greentea_metrics.h" 00025 00026 00027 /** 00028 * Generic test suite transport protocol keys 00029 */ 00030 const char* GREENTEA_TEST_ENV_END = "end"; 00031 const char* GREENTEA_TEST_ENV_EXIT = "__exit"; 00032 const char* GREENTEA_TEST_ENV_SYNC = "__sync"; 00033 const char* GREENTEA_TEST_ENV_TIMEOUT = "__timeout"; 00034 const char* GREENTEA_TEST_ENV_HOST_TEST_NAME = "__host_test_name"; 00035 const char* GREENTEA_TEST_ENV_HOST_TEST_VERSION = "__version"; 00036 00037 /** 00038 * Test suite success code strings 00039 */ 00040 const char* GREENTEA_TEST_ENV_SUCCESS = "success"; 00041 const char* GREENTEA_TEST_ENV_FAILURE = "failure"; 00042 00043 /** 00044 * Test case transport protocol start/finish keys 00045 */ 00046 const char* GREENTEA_TEST_ENV_TESTCASE_NAME = "__testcase_name"; 00047 const char* GREENTEA_TEST_ENV_TESTCASE_COUNT = "__testcase_count"; 00048 const char* GREENTEA_TEST_ENV_TESTCASE_START = "__testcase_start"; 00049 const char* GREENTEA_TEST_ENV_TESTCASE_FINISH = "__testcase_finish"; 00050 const char* GREENTEA_TEST_ENV_TESTCASE_SUMMARY = "__testcase_summary"; 00051 // Code Coverage (LCOV) transport protocol keys 00052 const char* GREENTEA_TEST_ENV_LCOV_START = "__coverage_start"; 00053 00054 /** 00055 * Auxilary functions 00056 */ 00057 static void greentea_notify_timeout(const int); 00058 static void greentea_notify_hosttest(const char *); 00059 static void greentea_notify_completion(const int); 00060 static void greentea_notify_version(); 00061 static void greentea_write_string(const char *str); 00062 00063 /** \brief Handshake with host and send setup data (timeout and host test name) 00064 * \details This function will send preamble to master. 00065 * After host test name is received master will invoke host test script 00066 * and add hos test's callback handlers to main event loop 00067 * This function is blocking. 00068 */ 00069 void GREENTEA_SETUP(const int timeout, const char *host_test_name) { 00070 greentea_metrics_setup(); 00071 // Key-value protocol handshake function. Waits for {{__sync;...}} message 00072 // Sync preamble: "{{__sync;0dad4a9d-59a3-4aec-810d-d5fb09d852c1}}" 00073 // Example value of sync_uuid == "0dad4a9d-59a3-4aec-810d-d5fb09d852c1" 00074 char _key[8] = {0}; 00075 char _value[48] = {0}; 00076 while (1) { 00077 greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value)); 00078 greentea_write_string("mbedmbedmbedmbedmbedmbedmbedmbed\r\n"); 00079 if (strcmp(_key, GREENTEA_TEST_ENV_SYNC) == 0) { 00080 // Found correct __sunc message 00081 greentea_send_kv(_key, _value); 00082 break; 00083 } 00084 } 00085 00086 greentea_notify_version(); 00087 greentea_notify_timeout(timeout); 00088 greentea_notify_hosttest(host_test_name); 00089 } 00090 00091 /** \brief Notify host (__exit message) side that test suite execution was complete 00092 * \result Test suite result 00093 * \details If __exit is not received by host side we will assume TIMEOUT 00094 */ 00095 void GREENTEA_TESTSUITE_RESULT(const int result) { 00096 greentea_notify_completion(result); 00097 } 00098 00099 /** 00100 * Test Case support 00101 */ 00102 00103 /** \brief Notify host side that test case started 00104 * \details test_case_name Test case name 00105 */ 00106 void GREENTEA_TESTCASE_START(const char *test_case_name) { 00107 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_START, test_case_name); 00108 } 00109 00110 /** \brief Notify host side that test case finished 00111 * \details test_case_name Test case name 00112 * \details result Test case result (0 -OK, non zero...) 00113 */ 00114 void GREENTEA_TESTCASE_FINISH(const char *test_case_name, const size_t passes, const size_t failed) { 00115 greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_FINISH, test_case_name, passes, failed); 00116 } 00117 00118 /** 00119 ***************************************************************************** 00120 * Auxilary functions and key-value protocol support 00121 ***************************************************************************** 00122 */ 00123 00124 00125 /** 00126 ***************************************************************************** 00127 * LCOV support 00128 ***************************************************************************** 00129 */ 00130 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE 00131 extern "C" void __gcov_flush(void); 00132 extern bool coverage_report; 00133 00134 /** 00135 * \brief Send code coverage (gcov/LCOV) notification to master 00136 * 00137 * Generates preamble of message sent to notify host about code coverage data dump. 00138 * 00139 * This function is used by mbedOS software 00140 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage 00141 * messages to host. When code coverage feature is turned on slave will 00142 * print-out code coverage data in form of key-value protocol. 00143 * Message with code coverage data will contain message name, path to code 00144 * coverage output file host will touch and fill with code coverage binary 00145 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). 00146 * 00147 * \param path to file with code coverage payload (set by gcov instrumentation) 00148 * 00149 */ 00150 void greentea_notify_coverage_start(const char *path) { 00151 printf("{{%s;%s;", GREENTEA_TEST_ENV_LCOV_START, path); 00152 } 00153 00154 /** 00155 * \brief Sufix for code coverage message to master (closing statement) 00156 * 00157 * This function is used by mbedOS software 00158 * (see: mbed-drivers/source/retarget.cpp file) to generate code coverage 00159 * messages to host. When code coverage feature is turned on slave will 00160 * print-out code coverage data in form of key-value protocol. 00161 * Message with code coverage data will contain message name, path to code 00162 * coverage output file host will touch and fill with code coverage binary 00163 * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). 00164 * 00165 * Companion function greentea_notify_coverage_start() defines code coverage message structure 00166 * 00167 */ 00168 void greentea_notify_coverage_end() { 00169 printf("}}" NL); 00170 } 00171 00172 #endif 00173 00174 /** 00175 ***************************************************************************** 00176 * Key-value protocol support 00177 ***************************************************************************** 00178 */ 00179 00180 /** 00181 * \brief Write the preamble characters to the serial port 00182 * 00183 * This function writes the preamble "{{" which is required 00184 * for key-value comunication between the target and the host. 00185 * This uses a Rawserial object, greentea_serial, which provides 00186 * a direct interface to the USBTX and USBRX serial pins and allows 00187 * the direct writing of characters using the putc() method. 00188 * This suite of functions are provided to allow for serial communication 00189 * to the host from within a thread/ISR. 00190 * 00191 */ 00192 inline void greentea_write_preamble() 00193 { 00194 greentea_serial->putc('{'); 00195 greentea_serial->putc('{'); 00196 } 00197 00198 /** 00199 * \brief Write the postamble characters to the serial port 00200 * 00201 * This function writes the postamble "{{\n" which is required 00202 * for key-value comunication between the target and the host. 00203 * This uses a Rawserial object, greentea_serial, which provides 00204 * a direct interface to the USBTX and USBRX serial pins and allows 00205 * the direct writing of characters using the putc() method. 00206 * This suite of functions are provided to allow for serial communication 00207 * to the host from within a thread/ISR. 00208 * 00209 */ 00210 inline void greentea_write_postamble() 00211 { 00212 greentea_serial->putc('}'); 00213 greentea_serial->putc('}'); 00214 greentea_serial->putc('\r'); 00215 greentea_serial->putc('\n'); 00216 } 00217 00218 /** 00219 * \brief Write a string to the serial port 00220 * 00221 * This function writes a '\0' terminated string from the target 00222 * to the host. It writes directly to the serial port using the 00223 * greentea_serial, Rawserial object. 00224 * 00225 * \param str - string value 00226 * 00227 */ 00228 inline void greentea_write_string(const char *str) 00229 { 00230 while (*str != '\0') { 00231 greentea_serial->putc(*str); 00232 str ++; 00233 } 00234 } 00235 00236 00237 /** 00238 * \brief Write an int to the serial port 00239 * 00240 * This function writes an integer value from the target 00241 * to the host. The integer value is converted to a string and 00242 * and then written character by character directly to the serial 00243 * port using the greentea_serial, Rawserial object. 00244 * sprintf() is used to convert the int to a string. Sprintf if 00245 * inherently thread safe so can be used. 00246 * 00247 * \param val - integer value 00248 * 00249 */ 00250 #define MAX_INT_STRING_LEN 15 00251 inline void greentea_write_int(const int val) 00252 { 00253 char intval[MAX_INT_STRING_LEN]; 00254 unsigned int i = 0; 00255 sprintf(intval, "%d", val); 00256 while (intval[i] != '\0') { 00257 greentea_serial->putc(intval[i]); 00258 i++; 00259 } 00260 } 00261 00262 /** 00263 * \brief Encapsulate and send key-value message from DUT to host 00264 * 00265 * This function uses underlying functions to write directly 00266 * to the serial port, (USBTX). This allows KVs to be used 00267 * from within interrupt context. 00268 * 00269 * \param key Message key (message/event name) 00270 * \param value Message payload, string value 00271 * 00272 */ 00273 void greentea_send_kv(const char *key, const char *val) { 00274 if (key && val) { 00275 greentea_write_preamble(); 00276 greentea_write_string(key); 00277 greentea_serial->putc(';'); 00278 greentea_write_string(val); 00279 greentea_write_postamble(); 00280 } 00281 } 00282 00283 /** 00284 * \brief Encapsulate and send key-value message from DUT to host 00285 * 00286 * This function uses underlying functions to write directly 00287 * to the serial port, (USBTX). This allows KVs to be used 00288 * from within interrupt context. 00289 * Last value is an integer to avoid integer to string conversion 00290 * made by the user. 00291 * 00292 * \param key Message key (message/event name) 00293 * \param value Message payload, integer value 00294 * 00295 */ 00296 void greentea_send_kv(const char *key, const int val) { 00297 if (key) { 00298 greentea_write_preamble(); 00299 greentea_write_string(key); 00300 greentea_serial->putc(';'); 00301 greentea_write_int(val); 00302 greentea_write_postamble(); 00303 } 00304 } 00305 00306 /** 00307 * \brief Encapsulate and send key-value-value message from DUT to host 00308 * 00309 * This function uses underlying functions to write directly 00310 * to the serial port, (USBTX). This allows KVs to be used 00311 * from within interrupt context. 00312 * Last value is an integer to avoid integer to string conversion 00313 * made by the user. 00314 * 00315 * \param key Message key (message/event name) 00316 * \param value Message payload, string value 00317 * \param result Send additional integer formatted data 00318 * 00319 */ 00320 void greentea_send_kv(const char *key, const char *val, const int result) { 00321 if (key) { 00322 greentea_write_preamble(); 00323 greentea_write_string(key); 00324 greentea_serial->putc(';'); 00325 greentea_write_string(val); 00326 greentea_serial->putc(';'); 00327 greentea_write_int(result); 00328 greentea_write_postamble(); 00329 00330 } 00331 } 00332 00333 /** 00334 * \brief Encapsulate and send key-value-value-value message from DUT to host 00335 * 00336 * This function uses underlying functions to write directly 00337 * to the serial port, (USBTX). This allows KVs to be used 00338 * from within interrupt context. 00339 * Last 2 values are integers to avoid integer to string conversion 00340 * made by the user. 00341 * 00342 * Names of the parameters: this function is used to send test case 00343 * name with number of passes and failures to host. But it can be used 00344 * to send any key-value-value-value (string-string-integer-integer) 00345 * set to host. 00346 * 00347 * \param key Message key (message/event name) 00348 * \param value Message payload, string value 00349 * \param passes Send additional integer formatted data 00350 * \param failures Send additional integer formatted data 00351 * 00352 */ 00353 void greentea_send_kv(const char *key, const char *val, const int passes, const int failures) { 00354 if (key) { 00355 greentea_write_preamble(); 00356 greentea_write_string(key); 00357 greentea_serial->putc(';'); 00358 greentea_write_string(val); 00359 greentea_serial->putc(';'); 00360 greentea_write_int(passes); 00361 greentea_serial->putc(';'); 00362 greentea_write_int(failures); 00363 greentea_write_postamble(); 00364 } 00365 } 00366 00367 /** 00368 * \brief Encapsulate and send key-value-value message from DUT to host 00369 * 00370 * This function uses underlying functions to write directly 00371 * to the serial port, (USBTX). This allows key-value-value to be used 00372 * from within interrupt context. 00373 * Both values are integers to avoid integer to string conversion 00374 * made by the user. 00375 * 00376 * Names of the parameters: this function is used to send number 00377 * of passes and failures to host. But it can be used to send any 00378 * key-value-value (string-integer-integer) message to host. 00379 * 00380 * \param key Message key (message/event name) 00381 * \param value Message payload, integer value 00382 * \param passes Send additional integer formatted data 00383 * \param failures Send additional integer formatted data 00384 * 00385 */ 00386 void greentea_send_kv(const char *key, const int passes, const int failures) { 00387 if (key) { 00388 greentea_write_preamble(); 00389 greentea_write_string(key); 00390 greentea_serial->putc(';'); 00391 greentea_write_int(passes); 00392 greentea_serial->putc(';'); 00393 greentea_write_int(failures); 00394 greentea_write_postamble(); 00395 } 00396 } 00397 00398 /** 00399 * \brief Send message with timeout to master in seconds 00400 * 00401 * GREENTEA_TEST_ENV_TIMEOUT message is part of preamble 00402 * sent from DUT to host during synchronisation (beginning of test 00403 * suite execution). 00404 * 00405 * Notification about total test suite timeout. Timeout is measured 00406 * from the moment of GREENTEA_TEST_ENV_TIMEOUT reception by host. 00407 * If timeout is reached host (and host test) will be stopped and 00408 * control will return to Greentea. 00409 * 00410 * \param timeout Test suite timeout in seconds 00411 * 00412 */ 00413 static void greentea_notify_timeout(const int timeout) { 00414 greentea_send_kv(GREENTEA_TEST_ENV_TIMEOUT, timeout); 00415 } 00416 00417 /** 00418 * \brief Send host test name to master 00419 * 00420 * GREENTEA_TEST_ENV_HOST_TEST_NAME message is part of preamble 00421 * sent from DUT to host during synchronisation (beginning of test 00422 * suite execution). 00423 * 00424 * Host test Python script implements host side callbacks 00425 * for key-value events sent from DUT to host. Host test's 00426 * callbacks are registered after GREENTEA_TEST_ENV_HOST_TEST_NAME 00427 * message reaches host. 00428 * 00429 * \param host_test_name Host test name, host test will be loaded by mbedhtrun 00430 */ 00431 static void greentea_notify_hosttest(const char *host_test_name) { 00432 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_NAME, host_test_name); 00433 } 00434 00435 /** 00436 * \brief Send to master information that test suite finished its execution 00437 * 00438 * GREENTEA_TEST_ENV_END and GREENTEA_TEST_ENV_EXIT messages 00439 * are sent just before test suite execution finishes (noting 00440 * else to do). You can place it just before you return from your 00441 * main() function. 00442 * 00443 * Code coverage: If MEBD_CFG_DEBUG_OPTIONS_COVERAGE is set in the 00444 * project via build configuration function will output series 00445 * of code coverage messages GREENTEA_TEST_ENV_LCOV_START with code 00446 * coverage binary data. This data is captured by Greentea and can 00447 * be used to generate LCOV reports. 00448 * 00449 * \param result Test suite result from DUT (0 - FAIl, !0 - SUCCESS) 00450 * 00451 */ 00452 static void greentea_notify_completion(const int result) { 00453 const char *val = result ? GREENTEA_TEST_ENV_SUCCESS : GREENTEA_TEST_ENV_FAILURE; 00454 #ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE 00455 coverage_report = true; 00456 __gcov_flush(); 00457 coverage_report = false; 00458 #endif 00459 greentea_metrics_report(); 00460 greentea_send_kv(GREENTEA_TEST_ENV_END, val); 00461 greentea_send_kv(GREENTEA_TEST_ENV_EXIT, 0); 00462 } 00463 00464 /** 00465 * \brief Send to master greentea-client version 00466 */ 00467 static void greentea_notify_version() { 00468 greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_VERSION, MBED_GREENTEA_CLIENT_VERSION_STRING); 00469 } 00470 00471 /** 00472 ***************************************************************************** 00473 * Parse engine for KV values which replaces scanf 00474 ***************************************************************************** 00475 * 00476 * Example usage: 00477 * 00478 * char key[10]; 00479 * char value[48]; 00480 * 00481 * greentea_parse_kv(key, value, 10, 48); 00482 * greentea_parse_kv(key, value, 10, 48); 00483 * 00484 */ 00485 00486 00487 static int gettok(char *, const int); 00488 static int getNextToken(char *, const int); 00489 static int HandleKV(char *, char *, const int, const int); 00490 static int isstring(int); 00491 static int _get_char(); 00492 00493 /** 00494 * \brief Current token of key-value protocol's tokenizer 00495 */ 00496 static int CurTok = 0; 00497 00498 /** 00499 * \enum Token enumeration for key-value protocol tokenizer 00500 * 00501 * This enum is used by key-value protocol tokenizer 00502 * to detect parts of protocol in stream. 00503 * 00504 * tok_eof ::= EOF (end of file) 00505 * tok_open ::= "{{" 00506 * tok_close ::= "}}" 00507 * tok_semicolon ::= ";" 00508 * tok_string ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function 00509 * 00510 */ 00511 enum Token { 00512 tok_eof = -1, 00513 tok_open = -2, 00514 tok_close = -3, 00515 tok_semicolon = -4, 00516 tok_string = -5 00517 }; 00518 00519 /** 00520 * \brief Read character from stream of data 00521 * 00522 * Closure for default "get character" function. 00523 * This function is used to read characters from the stream 00524 * (default is serial port RX). Key-value protocol tokenizer 00525 * will build stream of tokes used by key-value protocol to 00526 * detect valid messages. 00527 * 00528 * If EOF is received parser finishes parsing and stops. In 00529 * situation where we have serial port stream of data parsing 00530 * goes forever. 00531 * 00532 * \return Next character from the stream or EOF if stream has ended. 00533 * 00534 */ 00535 static int _get_char() { 00536 return getchar(); 00537 } 00538 00539 /** 00540 * \brief parse input string for key-value pairs: {{key;value}} 00541 * This function should replace scanf() used to 00542 * check for incoming messages from master. All data 00543 * parsed and rejected is discarded. 00544 * 00545 * \param out_key Ouput data with key 00546 * \param out_value Ouput data with value 00547 * \param out_key_size out_key total size 00548 * \param out_value_size out_value total data 00549 * 00550 * success != 0 when key-value pair was found 00551 * success == 0 when end of the stream was found 00552 * 00553 */ 00554 int greentea_parse_kv(char *out_key, 00555 char *out_value, 00556 const int out_key_size, 00557 const int out_value_size) { 00558 getNextToken(0, 0); 00559 while (1) { 00560 switch (CurTok) { 00561 case tok_eof: 00562 return 0; 00563 00564 case tok_open: 00565 if (HandleKV(out_key, out_value, out_key_size, out_value_size)) { 00566 // We've found {{ KEY ; VALUE }} expression 00567 return 1; 00568 } 00569 break; 00570 00571 default: 00572 // Load next token and pray... 00573 getNextToken(0, 0); 00574 break; 00575 } 00576 } 00577 } 00578 00579 /** 00580 * \brief Get next token from stream 00581 * 00582 * Key-value TOKENIZER feature 00583 * 00584 * This function is used by key-value parser determine 00585 * if key-value message is embedded in stream data. 00586 * 00587 * \param str Output parameters to store token string value 00588 * \param str_size Size of 'str' parameter in bytes (characters) 00589 * 00590 */ 00591 static int getNextToken(char *str, const int str_size) { 00592 return CurTok = gettok(str, str_size); 00593 } 00594 00595 /** 00596 * \brief Check if character is punctuation character 00597 * 00598 * Auxilary key-value TOKENIZER function 00599 * 00600 * Defines if character is in subset of allowed punctuation 00601 * characters which can be part of a key or value string. 00602 * Not allowed characters are: ";{}" 00603 * 00604 * \param c Input character to check 00605 * \return Return 1 if character is allowed punctuation character, otherwise return false 00606 * 00607 */ 00608 static int ispunctuation(int c) { 00609 static const char punctuation[] = "_-!@#$%^&*()=+:<>,./?\\\"'"; // No ";{}" 00610 for (size_t i=0; i< sizeof(punctuation); ++i) { 00611 if (c == punctuation[i]) { 00612 return 1; 00613 } 00614 } 00615 return 0; 00616 } 00617 00618 /** 00619 * \brief Check if character is string token character 00620 * 00621 * Auxilary key-value TOKENIZER function 00622 * 00623 * Defines if character is in subset of allowed string 00624 * token characters. 00625 * String defines set of characters which can be a key or value string. 00626 * 00627 * Allowed subset includes: 00628 * - Alphanumerical characters 00629 * - Digits 00630 * - White spaces and 00631 * - subset of punctuation characters. 00632 * 00633 * \param c Input character to check 00634 * \return Return 1 if character is allowed punctuation character, otherwise return false 00635 * 00636 */ 00637 static int isstring(int c) { 00638 return (isalpha(c) || 00639 isdigit(c) || 00640 isspace(c) || 00641 ispunctuation(c)); 00642 } 00643 00644 /** 00645 * \brief TOKENIZER of key-value protocol 00646 * 00647 * Actual key-value TOKENIZER engine 00648 * 00649 * TOKENIZER defines #Token enum to map recognized tokens to integer values. 00650 * 00651 * <TOK_EOF> ::= EOF (end of file) 00652 * <TOK_OPEN> ::= "{{" 00653 * <TOK_CLOSE> ::= "}}" 00654 * <TOK_SEMICOLON> ::= ";" 00655 * <TOK_STRING> ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function * 00656 * 00657 * \param out_str Output string with parsed token (string) 00658 * \param str_size Size of str buffer we can use 00659 * 00660 * \return Return #Token enum value used by parser to check for key-value occurrences 00661 * 00662 */ 00663 static int gettok(char *out_str, const int str_size) { 00664 static int LastChar = '!'; 00665 static int str_idx = 0; 00666 00667 // whitespace ::= 00668 while (isspace(LastChar)) { 00669 LastChar = _get_char(); 00670 } 00671 00672 // string ::= [a-zA-Z0-9_-!@#$%^&*()]+ 00673 if (isstring(LastChar)) { 00674 str_idx = 0; 00675 if (out_str && str_idx < str_size - 1) { 00676 out_str[str_idx++] = LastChar; 00677 } 00678 00679 while (isstring((LastChar = _get_char()))) 00680 if (out_str && str_idx < str_size - 1) { 00681 out_str[str_idx++] = LastChar; 00682 } 00683 if (out_str && str_idx < str_size) { 00684 out_str[str_idx] = '\0'; 00685 } 00686 00687 return tok_string; 00688 } 00689 00690 // semicolon ::= ';' 00691 if (LastChar == ';') { 00692 LastChar = _get_char(); 00693 return tok_semicolon; 00694 } 00695 00696 // open ::= '{{' 00697 if (LastChar == '{') { 00698 LastChar = _get_char(); 00699 if (LastChar == '{') { 00700 LastChar = _get_char(); 00701 return tok_open; 00702 } 00703 } 00704 00705 // close ::= '}' 00706 if (LastChar == '}') { 00707 LastChar = _get_char(); 00708 if (LastChar == '}') { 00709 //LastChar = _get_char(); 00710 return tok_close; 00711 } 00712 } 00713 00714 if (LastChar == EOF) 00715 return tok_eof; 00716 00717 // Otherwise, just return the character as its ascii value. 00718 int ThisChar = LastChar; 00719 LastChar = _get_char(); 00720 return ThisChar; 00721 } 00722 00723 /** 00724 * \brief Key-value parser 00725 * 00726 * Key-value message grammar 00727 * 00728 * <MESSAGE>: <TOK_OPEN> <TOK_STRING> <TOK_SEMICOLON> <TOK_STRING> <TOK_CLOSE> 00729 * 00730 * Examples: 00731 * message: "{{__timeout; 1000}}" 00732 * "{{__sync; 12345678-1234-5678-1234-567812345678}}" 00733 * 00734 * \param out_key Output buffer to store key string value 00735 * \param out_value Output buffer to store value string value 00736 * \param out_key_size Buffer 'out_key' buffer size 00737 * \param out_value_size Buffer 'out_value_size' buffer size 00738 * \return Returns 1 if key-value message was parsed successfully in stream of tokens from tokenizer 00739 * 00740 */ 00741 static int HandleKV(char *out_key, 00742 char *out_value, 00743 const int out_key_size, 00744 const int out_value_size) { 00745 // We already started with <open> 00746 if (getNextToken(out_key, out_key_size) == tok_string) { 00747 if (getNextToken(0, 0) == tok_semicolon) { 00748 if (getNextToken(out_value, out_value_size) == tok_string) { 00749 if (getNextToken(0, 0) == tok_close) { 00750 // <open> <string> <semicolon> <string> <close> 00751 // Found "{{KEY;VALUE}}" expression 00752 return 1; 00753 } 00754 } 00755 } 00756 } 00757 getNextToken(0, 0); 00758 return 0; 00759 }
Generated on Tue Jul 12 2022 13:16:15 by
1.7.2
