| | |
| | | /*- |
| | | * Copyright (c) 2013 Jan Breuer |
| | | * Richard.hmm |
| | | * Copyright (c) 2012 Jan Breuer |
| | | * BSD 2-Clause License |
| | | * |
| | | * All Rights Reserved |
| | | * Copyright (c) 2012-2018, Jan Breuer, Richard.hmm |
| | | * All rights reserved. |
| | | * |
| | | * Redistribution and use in source and binary forms, with or without |
| | | * modification, are permitted provided that the following conditions are |
| | | * met: |
| | | * 1. Redistributions of source code must retain the above copyright notice, |
| | | * this list of conditions and the following disclaimer. |
| | | * 2. Redistributions in binary form must reproduce the above copyright |
| | | * notice, this list of conditions and the following disclaimer in the |
| | | * documentation and/or other materials provided with the distribution. |
| | | * modification, are permitted provided that the following conditions are met: |
| | | * |
| | | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
| | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| | | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE |
| | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| | | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| | | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| | | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| | | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | * * Redistributions of source code must retain the above copyright notice, this |
| | | * list of conditions and the following disclaimer. |
| | | * |
| | | * * Redistributions in binary form must reproduce the above copyright notice, |
| | | * this list of conditions and the following disclaimer in the documentation |
| | | * and/or other materials provided with the distribution. |
| | | * |
| | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| | | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| | | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| | | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| | | */ |
| | | |
| | | /** |
| | |
| | | #include <string.h> |
| | | #include <ctype.h> |
| | | #include <math.h> |
| | | |
| | | #include "utils_private.h" |
| | | #include "scpi/utils.h" |
| | | |
| | |
| | | } else { |
| | | |
| | | switch (base) { |
| | | case 2: |
| | | x = 0x80000000L; |
| | | break; |
| | | case 8: |
| | | x = 0x40000000L; |
| | | break; |
| | | default: |
| | | case 10: |
| | | base = 10; |
| | | x = 1000000000L; |
| | | break; |
| | | case 16: |
| | | x = 0x10000000L; |
| | | break; |
| | | case 2: |
| | | x = 0x80000000L; |
| | | break; |
| | | case 8: |
| | | x = 0x40000000L; |
| | | break; |
| | | default: |
| | | case 10: |
| | | base = 10; |
| | | x = 1000000000L; |
| | | break; |
| | | case 16: |
| | | x = 0x10000000L; |
| | | break; |
| | | } |
| | | |
| | | /* add sign for numbers in base 10 */ |
| | |
| | | } else { |
| | | |
| | | switch (base) { |
| | | case 2: |
| | | x = 0x8000000000000000ULL; |
| | | break; |
| | | case 8: |
| | | x = 0x8000000000000000ULL; |
| | | break; |
| | | default: |
| | | case 10: |
| | | x = 10000000000000000000ULL; |
| | | base = 10; |
| | | break; |
| | | case 16: |
| | | x = 0x1000000000000000ULL; |
| | | break; |
| | | case 2: |
| | | x = 0x8000000000000000ULL; |
| | | break; |
| | | case 8: |
| | | x = 0x8000000000000000ULL; |
| | | break; |
| | | default: |
| | | case 10: |
| | | x = 10000000000000000000ULL; |
| | | base = 10; |
| | | break; |
| | | case 16: |
| | | x = 0x1000000000000000ULL; |
| | | break; |
| | | } |
| | | |
| | | /* add sign for numbers in base 10 */ |
| | |
| | | pattern_sep_pos_short = patternSeparatorShortPos(pattern, new_pattern_len); |
| | | |
| | | return compareStrAndNum(pattern, new_pattern_len, str, str_len, num) || |
| | | compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num); |
| | | compareStrAndNum(pattern, pattern_sep_pos_short, str, str_len, num); |
| | | } else { |
| | | |
| | | pattern_sep_pos_short = patternSeparatorShortPos(pattern, pattern_len); |
| | | |
| | | return compareStr(pattern, pattern_len, str, str_len) || |
| | | compareStr(pattern, pattern_sep_pos_short, str, str_len); |
| | | compareStr(pattern, pattern_sep_pos_short, str, str_len); |
| | | } |
| | | } |
| | | |
| | |
| | | while (pattern_len) { |
| | | pattern_sep_pos = patternSeparatorPos(pattern_ptr, pattern_len); |
| | | switch (pattern_ptr[pattern_sep_pos]) { |
| | | case '[': |
| | | brackets++; |
| | | break; |
| | | case ']': |
| | | brackets--; |
| | | break; |
| | | default: |
| | | break; |
| | | case '[': |
| | | brackets++; |
| | | break; |
| | | case ']': |
| | | brackets--; |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | SKIP_PATTERN(pattern_sep_pos + 1); |
| | | if (brackets == 0) { |
| | |
| | | |
| | | /* both command and patter contains command separator at this position */ |
| | | if ((pattern_len > 0) |
| | | && ((pattern_ptr[0] == cmd_ptr[0]) |
| | | && ((pattern_ptr[0] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == ':'))) { |
| | | SKIP_PATTERN(1); |
| | | SKIP_CMD(1); |
| | | } else if ((pattern_len > 1) |
| | | && (pattern_ptr[1] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == '[') |
| | | && (pattern_ptr[1] == ':')) { |
| | | && (pattern_ptr[1] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == '[') |
| | | && (pattern_ptr[1] == ':')) { |
| | | SKIP_PATTERN(2); /* for skip '[' in "[:" */ |
| | | SKIP_CMD(1); |
| | | brackets++; |
| | | } else if ((pattern_len > 1) |
| | | && (pattern_ptr[1] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == ']') |
| | | && (pattern_ptr[1] == ':')) { |
| | | && (pattern_ptr[1] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == ']') |
| | | && (pattern_ptr[1] == ':')) { |
| | | SKIP_PATTERN(2); /* for skip ']' in "]:" */ |
| | | SKIP_CMD(1); |
| | | brackets--; |
| | | } else if ((pattern_len > 2) |
| | | && (pattern_ptr[2] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == ']') |
| | | && (pattern_ptr[1] == '[') |
| | | && (pattern_ptr[2] == ':')) { |
| | | && (pattern_ptr[2] == cmd_ptr[0]) |
| | | && (pattern_ptr[0] == ']') |
| | | && (pattern_ptr[1] == '[') |
| | | && (pattern_ptr[2] == ':')) { |
| | | SKIP_PATTERN(3); /* for skip '][' in "][:" */ |
| | | SKIP_CMD(1); |
| | | /* brackets++; */ |
| | |
| | | SKIP_PATTERN(2); /* for skip ']' in "]:" , pattern_ptr continue, while cmd_ptr remain unchanged */ |
| | | brackets--; |
| | | } else if ((pattern_len > 2) && (pattern_ptr[0] == ']') |
| | | && (pattern_ptr[1] == '[') |
| | | && (pattern_ptr[2] == ':')) { |
| | | && (pattern_ptr[1] == '[') |
| | | && (pattern_ptr[2] == ':')) { |
| | | SKIP_PATTERN(3); /* for skip ']' in "][:" , pattern_ptr continue, while cmd_ptr remain unchanged */ |
| | | /* brackets++; */ |
| | | /* brackets--; */ |
| | |
| | | * |
| | | * prev and current should be in the same memory buffer |
| | | */ |
| | | |
| | | //组合复合SCPI命令 |
| | | scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) { |
| | | size_t i; |
| | | |
| | |
| | | return TRUE; |
| | | |
| | | /* Common command or command root - nothing to do */ |
| | | // 当前命令是公共命令(*)或根命令(:) |
| | | if (current->ptr[0] == '*' || current->ptr[0] == ':') |
| | | return TRUE; |
| | | |
| | |
| | | |
| | | current->ptr -= i; |
| | | current->len += i; |
| | | //复合命令组合 |
| | | memmove(current->ptr, prev->ptr, i); |
| | | return TRUE; |
| | | } |
| | |
| | | #if USE_MEMORY_ALLOCATION_FREE && !HAVE_STRNDUP |
| | | char *OUR_strndup(const char *s, size_t n) { |
| | | size_t len = SCPIDEFINE_strnlen(s, n); |
| | | char * result = malloc(len + 1); |
| | | //msvc下需要强转 |
| | | char * result =(char*) malloc(len + 1); |
| | | if (!result) { |
| | | return NULL; |
| | | } |
| | |
| | | */ |
| | | uint16_t SCPI_Swap16(uint16_t val) { |
| | | return ((val & 0x00FF) << 8) | |
| | | ((val & 0xFF00) >> 8); |
| | | ((val & 0xFF00) >> 8); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | uint32_t SCPI_Swap32(uint32_t val) { |
| | | return ((val & 0x000000FFul) << 24) | |
| | | ((val & 0x0000FF00ul) << 8) | |
| | | ((val & 0x00FF0000ul) >> 8) | |
| | | ((val & 0xFF000000ul) >> 24); |
| | | ((val & 0x0000FF00ul) << 8) | |
| | | ((val & 0x00FF0000ul) >> 8) | |
| | | ((val & 0xFF000000ul) >> 24); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | uint64_t SCPI_Swap64(uint64_t val) { |
| | | return ((val & 0x00000000000000FFull) << 56) | |
| | | ((val & 0x000000000000FF00ull) << 40) | |
| | | ((val & 0x0000000000FF0000ull) << 24) | |
| | | ((val & 0x00000000FF000000ull) << 8) | |
| | | ((val & 0x000000FF00000000ull) >> 8) | |
| | | ((val & 0x0000FF0000000000ull) >> 24) | |
| | | ((val & 0x00FF000000000000ull) >> 40) | |
| | | ((val & 0xFF00000000000000ull) >> 56); |
| | | ((val & 0x000000000000FF00ull) << 40) | |
| | | ((val & 0x0000000000FF0000ull) << 24) | |
| | | ((val & 0x00000000FF000000ull) << 8) | |
| | | ((val & 0x000000FF00000000ull) >> 8) | |
| | | ((val & 0x0000FF0000000000ull) >> 24) | |
| | | ((val & 0x00FF000000000000ull) >> 40) | |
| | | ((val & 0xFF00000000000000ull) >> 56); |
| | | } |
| | | |
| | | |
| | | // 解析模式,将每个部分保存到 segments 中 |
| | | int parse_pattern(const char* pattern, Segment segments[], int max_segments) { |
| | | int seg_count = 0; |
| | | const char* p = pattern; |
| | | |
| | | while (*p && seg_count < max_segments) { |
| | | if (*p == '[') { |
| | | // 处理可变段([]) |
| | | segments[seg_count].is_variable = TRUE; |
| | | segments[seg_count].is_required = FALSE; // []是可选的 |
| | | segments[seg_count].is_option = FALSE; |
| | | p++; // 跳过'[' |
| | | |
| | | int i = 0; |
| | | while (*p && *p != ']' && i < sizeof(segments[seg_count].text) - 1) { |
| | | segments[seg_count].text[i++] = toupper(*p++); |
| | | } |
| | | segments[seg_count].text[i] = '\0'; // 结束符 |
| | | |
| | | if (*p == ']') { |
| | | p++; // 跳过']' |
| | | } |
| | | } |
| | | else if (*p == '<') { |
| | | // 处理必选段(<>) |
| | | segments[seg_count].is_variable = TRUE; |
| | | segments[seg_count].is_required = TRUE; // <>是必选的 |
| | | segments[seg_count].is_option = FALSE; |
| | | p++; // 跳过'<' |
| | | |
| | | int i = 0; |
| | | while (*p && *p != '>' && i < sizeof(segments[seg_count].text) - 1) { |
| | | segments[seg_count].text[i++] = toupper(*p++); |
| | | } |
| | | segments[seg_count].text[i] = '\0'; // 结束符 |
| | | |
| | | if (*p == '>') { |
| | | p++; // 跳过'>' |
| | | } |
| | | } |
| | | else if (*p == '|') { |
| | | // 处理竖线分隔的多选部分(|) |
| | | segments[seg_count].is_variable = TRUE; |
| | | segments[seg_count].is_required = TRUE; // 选项是必选的 |
| | | segments[seg_count].is_option = TRUE; // 这表示选项组 |
| | | p++; // 跳过'|' |
| | | |
| | | int i = 0; |
| | | while (*p && *p != '|' && *p != '>' && *p != '[' && *p != ']' && i < sizeof(segments[seg_count].text) - 1) { |
| | | segments[seg_count].text[i++] = toupper(*p++); |
| | | } |
| | | segments[seg_count].text[i] = '\0'; // 结束符 |
| | | |
| | | // 跳过'|'继续处理下一个选项 |
| | | if (*p == '|') { |
| | | p++; // 跳过'|' |
| | | } |
| | | } |
| | | else { |
| | | // 处理固定段 |
| | | segments[seg_count].is_variable = FALSE; |
| | | segments[seg_count].is_required = TRUE; // 固定段必选 |
| | | segments[seg_count].is_option = FALSE; |
| | | int i = 0; |
| | | while (*p && *p != '[' && *p != '<' && *p != '|' && *p != ':' && i < sizeof(segments[seg_count].text) - 1) { |
| | | segments[seg_count].text[i++] = toupper(*p++); |
| | | } |
| | | segments[seg_count].text[i] = '\0'; // 结束符 |
| | | } |
| | | |
| | | seg_count++; |
| | | } |
| | | |
| | | return seg_count; |
| | | } |
| | | |
| | | // 匹配命令字符串是否符合模式 |
| | | bool match_command(const char* command, Segment segments[], int seg_count) { |
| | | const char* cmd = command; |
| | | int current_seg = 0; |
| | | |
| | | while (*cmd && current_seg < seg_count) { |
| | | // 按冒号分隔命令 |
| | | if (*cmd == ':') { |
| | | cmd++; // 跳过分隔符 |
| | | continue; |
| | | } |
| | | |
| | | size_t seg_len = strlen(segments[current_seg].text); |
| | | |
| | | if (segments[current_seg].is_variable) { |
| | | // 可变段 - 跳过对应长度的字符 |
| | | int i = 0; |
| | | while (*cmd && *cmd != ':' && i < seg_len) { |
| | | cmd++; |
| | | i++; |
| | | } |
| | | } |
| | | else if (segments[current_seg].is_option) { |
| | | // 选项组 - 必须匹配其中一个选项 |
| | | bool matched = FALSE; |
| | | const char* options[] = { segments[current_seg].text, NULL }; |
| | | for (int i = 0; options[i]; i++) { |
| | | if (strncasecmp(cmd, options[i], strlen(options[i])) == 0) { |
| | | matched = TRUE; |
| | | break; |
| | | } |
| | | } |
| | | if (!matched) { |
| | | return FALSE; |
| | | } |
| | | cmd += strlen(options[0]); |
| | | } |
| | | else { |
| | | // 固定段 - 必须精确匹配 |
| | | if (strncasecmp(cmd, segments[current_seg].text, seg_len) != 0) { |
| | | return FALSE; |
| | | } |
| | | cmd += seg_len; // 跳过匹配的部分 |
| | | } |
| | | |
| | | current_seg++; |
| | | } |
| | | |
| | | // 检查是否处理完所有命令和所有段 |
| | | return (*cmd == '\0') && (current_seg == seg_count); |
| | | } |
| | | |
| | | // 测试匹配函数 |
| | | bool test_match(const char* pattern, const char* command) |
| | | { |
| | | |
| | | Segment segments[MAX_SEGMENTS]; |
| | | int seg_count = parse_pattern(pattern, segments, MAX_SEGMENTS); |
| | | return match_command(command, segments, seg_count); |
| | | } |