Resolve bug with short commands
| | |
| | | *.out |
| | | *.app |
| | | *.test |
| | | examples/*/test |
| | | |
| | | # Backup files |
| | | *~ |
| | |
| | | #include "scpi/error.h" |
| | | |
| | | |
| | | static size_t patternSeparatorPos(const char * pattern, size_t len); |
| | | static size_t cmdSeparatorPos(const char * cmd, size_t len); |
| | | static size_t cmdTerminatorPos(const char * cmd, size_t len); |
| | | static size_t cmdlineSeparatorPos(const char * cmd, size_t len); |
| | | static const char * cmdlineSeparator(const char * cmd, size_t len); |
| | | static const char * cmdlineTerminator(const char * cmd, size_t len); |
| | | static const char * cmdlineNext(const char * cmd, size_t len); |
| | | static bool_t cmdMatch(const char * pattern, const char * cmd, size_t len); |
| | | |
| | | static void paramSkipBytes(scpi_t * context, size_t num); |
| | | static void paramSkipWhitespace(scpi_t * context); |
| | |
| | | return result; |
| | | } |
| | | */ |
| | | |
| | | /** |
| | | * Find pattern separator position |
| | | * @param pattern |
| | | * @param len - max search length |
| | | * @return position of separator or len |
| | | */ |
| | | size_t patternSeparatorPos(const char * pattern, size_t len) { |
| | | |
| | | char * separator = strnpbrk(pattern, len, "?:[]"); |
| | | if (separator == NULL) { |
| | | return len; |
| | | } else { |
| | | return separator - pattern; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Find command separator position |
| | | * @param cmd - input command |
| | | * @param len - max search length |
| | | * @return position of separator or len |
| | | */ |
| | | size_t cmdSeparatorPos(const char * cmd, size_t len) { |
| | | char * separator = strnpbrk(cmd, len, ":?"); |
| | | size_t result; |
| | | if (separator == NULL) { |
| | | result = len; |
| | | } else { |
| | | result = separator - cmd; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Find command termination character |
| | |
| | | } |
| | | |
| | | /** |
| | | * Compare pattern and command |
| | | * @param pattern |
| | | * @param cmd - command |
| | | * @param len - max search length |
| | | * @return TRUE if pattern matches, FALSE otherwise |
| | | */ |
| | | bool_t cmdMatch(const char * pattern, const char * cmd, size_t len) { |
| | | int result = FALSE; |
| | | |
| | | const char * pattern_ptr = pattern; |
| | | int pattern_len = SCPI_strnlen(pattern, len); |
| | | const char * pattern_end = pattern + pattern_len; |
| | | |
| | | const char * cmd_ptr = cmd; |
| | | size_t cmd_len = SCPI_strnlen(cmd, len); |
| | | const char * cmd_end = cmd + cmd_len; |
| | | |
| | | while (1) { |
| | | int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_end - pattern_ptr); |
| | | int cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr); |
| | | |
| | | if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos)) { |
| | | pattern_ptr = pattern_ptr + pattern_sep_pos; |
| | | cmd_ptr = cmd_ptr + cmd_sep_pos; |
| | | result = TRUE; |
| | | |
| | | /* command is complete */ |
| | | if ((pattern_ptr == pattern_end) && (cmd_ptr >= cmd_end)) { |
| | | break; |
| | | } |
| | | |
| | | /* pattern complete, but command not */ |
| | | if ((pattern_ptr == pattern_end) && (cmd_ptr < cmd_end)) { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | |
| | | /* command complete, but pattern not */ |
| | | if (cmd_ptr >= cmd_end) { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | |
| | | /* both command and patter contains command separator at this position */ |
| | | if ((pattern_ptr[0] == cmd_ptr[0]) && ((pattern_ptr[0] == ':') || (pattern_ptr[0] == '?'))) { |
| | | pattern_ptr = pattern_ptr + 1; |
| | | cmd_ptr = cmd_ptr + 1; |
| | | } else { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | } else { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * Write data to SCPI output |
| | | * @param context |
| | | * @param data |
| | |
| | | } |
| | | |
| | | /** |
| | | * Zapis nove radky na SCPI vystup |
| | | * Conditionaly write "New Line" |
| | | * @param context |
| | | * @return pocet zapsanych znaku |
| | | * @return number of characters written |
| | | */ |
| | | static size_t writeNewLine(scpi_t * context) { |
| | | if (context->output_count > 0) { |
| | |
| | | |
| | | for (i = 0; context->cmdlist[i].pattern != NULL; i++) { |
| | | cmd = &context->cmdlist[i]; |
| | | if (cmdMatch(cmd->pattern, cmdline_ptr, cmd_len)) { |
| | | if (matchCommand(cmd->pattern, cmdline_ptr, cmd_len)) { |
| | | context->paramlist.cmd = cmd; |
| | | context->paramlist.parameters = cmdline_ptr + cmd_len; |
| | | context->paramlist.length = cmdline_len - cmd_len; |
| | |
| | | #include "utils.h" |
| | | |
| | | static size_t patternSeparatorShortPos(const char * pattern, size_t len); |
| | | static size_t patternSeparatorPos(const char * pattern, size_t len); |
| | | static size_t cmdSeparatorPos(const char * cmd, size_t len); |
| | | |
| | | /** |
| | | * Find the first occurrence in str of a character in set. |
| | |
| | | return len; |
| | | } |
| | | |
| | | /** |
| | | * is colon or not. add by hmm 2013.4.1 |
| | | * @param cmd - command |
| | | * @return |
| | | */ |
| | | static bool_t iscolon(const char * cmd) { |
| | | char* pColon = ":"; |
| | | if(0 == SCPI_strncasecmp(cmd, pColon, 1)) |
| | | { |
| | | return TRUE; |
| | | } |
| | | return FALSE; |
| | | } |
| | | |
| | | /** |
| | | * Count colon from the beggining add by hmm 2013.4.1 |
| | | * @param cmd - command |
| | | * @param len - max search length |
| | | * @return number of colon |
| | | */ |
| | | size_t skipColon(const char * cmd, size_t len) { |
| | | size_t i; |
| | | for (i = 0; i < len; i++) { |
| | | if (!iscolon(&cmd[i])) { |
| | | return i; |
| | | } |
| | | } |
| | | return len; |
| | | } |
| | | |
| | | /** |
| | | * Pattern is composed from upper case an lower case letters. This function |
| | |
| | | } |
| | | |
| | | /** |
| | | * Find pattern separator position |
| | | * @param pattern |
| | | * @param len - max search length |
| | | * @return position of separator or len |
| | | */ |
| | | size_t patternSeparatorPos(const char * pattern, size_t len) { |
| | | |
| | | char * separator = strnpbrk(pattern, len, "?:[]"); |
| | | if (separator == NULL) { |
| | | return len; |
| | | } else { |
| | | return separator - pattern; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Find command separator position |
| | | * @param cmd - input command |
| | | * @param len - max search length |
| | | * @return position of separator or len |
| | | */ |
| | | size_t cmdSeparatorPos(const char * cmd, size_t len) { |
| | | char * separator = strnpbrk(cmd, len, ":?"); |
| | | size_t result; |
| | | if (separator == NULL) { |
| | | result = len; |
| | | } else { |
| | | result = separator - cmd; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Match pattern and str. Pattern is in format UPPERCASElowercase |
| | | * @param pattern |
| | | * @param pattern_len |
| | |
| | | compareStr(pattern, pattern_sep_pos_short, str, str_len); |
| | | } |
| | | |
| | | /** |
| | | * Compare pattern and command |
| | | * @param pattern |
| | | * @param cmd - command |
| | | * @param len - max search length |
| | | * @return TRUE if pattern matches, FALSE otherwise |
| | | */ |
| | | bool_t matchCommand(const char * pattern, const char * cmd, size_t len) { |
| | | int result = FALSE; |
| | | |
| | | const char * pattern_ptr = pattern; |
| | | int pattern_len = strlen(pattern); |
| | | const char * pattern_end = pattern + pattern_len; |
| | | |
| | | const char * cmd_ptr = cmd; |
| | | size_t cmd_len = SCPI_strnlen(cmd, len); |
| | | const char * cmd_end = cmd + cmd_len; |
| | | |
| | | while (1) { |
| | | int pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_end - pattern_ptr); |
| | | int cmd_sep_pos = cmdSeparatorPos(cmd_ptr, cmd_end - cmd_ptr); |
| | | |
| | | if (matchPattern(pattern_ptr, pattern_sep_pos, cmd_ptr, cmd_sep_pos)) { |
| | | pattern_ptr = pattern_ptr + pattern_sep_pos; |
| | | cmd_ptr = cmd_ptr + cmd_sep_pos; |
| | | result = TRUE; |
| | | |
| | | /* command is complete */ |
| | | if ((pattern_ptr == pattern_end) && (cmd_ptr >= cmd_end)) { |
| | | break; |
| | | } |
| | | |
| | | /* pattern complete, but command not */ |
| | | if ((pattern_ptr == pattern_end) && (cmd_ptr < cmd_end)) { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | |
| | | /* command complete, but pattern not */ |
| | | if (cmd_ptr >= cmd_end) { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | |
| | | /* both command and patter contains command separator at this position */ |
| | | if ((pattern_ptr[0] == cmd_ptr[0]) && ((pattern_ptr[0] == ':') || (pattern_ptr[0] == '?'))) { |
| | | pattern_ptr = pattern_ptr + 1; |
| | | cmd_ptr = cmd_ptr + 1; |
| | | } else { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | } else { |
| | | result = FALSE; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | #if !HAVE_STRNLEN |
| | | /* use FreeBSD strnlen */ |
| | |
| | | bool_t locateText(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; |
| | | bool_t locateStr(const char * str1, size_t len1, const char ** str2, size_t * len2) LOCAL; |
| | | size_t skipWhitespace(const char * cmd, size_t len) LOCAL; |
| | | size_t skipColon(const char * cmd, size_t len) LOCAL; |
| | | bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) LOCAL; |
| | | bool_t matchCommand(const char * pattern, const char * cmd, size_t len) LOCAL; |
| | | |
| | | #if !HAVE_STRNLEN |
| | | size_t BSD_strnlen(const char *s, size_t maxlen); |
| | |
| | | TEST_MATCH_PATTERN("AB", "a", FALSE); |
| | | } |
| | | |
| | | void test_matchCommand() { |
| | | bool_t result; |
| | | |
| | | #define TEST_MATCH_COMMAND(p, s, r) \ |
| | | do { \ |
| | | result = matchCommand(p, s, strlen(s)); \ |
| | | CU_ASSERT_EQUAL(result, r); \ |
| | | } while(0) \ |
| | | |
| | | TEST_MATCH_COMMAND("A", "a", TRUE); |
| | | TEST_MATCH_COMMAND("Ab", "a", TRUE); |
| | | TEST_MATCH_COMMAND("Ab", "ab", TRUE); |
| | | TEST_MATCH_COMMAND("Ab", "aB", TRUE); |
| | | TEST_MATCH_COMMAND("AB", "a", FALSE); |
| | | TEST_MATCH_COMMAND("ABc:AACddd", "ab:aac", TRUE); |
| | | TEST_MATCH_COMMAND("ABc:AACddd", "abc:aac", TRUE); |
| | | TEST_MATCH_COMMAND("ABc:AACddd", "abc:aacddd", TRUE); |
| | | TEST_MATCH_COMMAND("ABc:AACddd", "abc:aacdd", FALSE); |
| | | TEST_MATCH_COMMAND("ABc:AACddd", "a:aac", FALSE); |
| | | } |
| | | |
| | | int main() { |
| | | CU_pSuite pSuite = NULL; |
| | | |
| | |
| | | || (NULL == CU_add_test(pSuite, "locateText", test_locateText)) |
| | | || (NULL == CU_add_test(pSuite, "locateStr", test_locateStr)) |
| | | || (NULL == CU_add_test(pSuite, "matchPattern", test_matchPattern)) |
| | | || (NULL == CU_add_test(pSuite, "matchCommand", test_matchCommand)) |
| | | ) { |
| | | CU_cleanup_registry(); |
| | | return CU_get_error(); |