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.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 greentea_serial->getc(); 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 11:02:55 by
