2个文件已修改
2个文件已添加
467 ■■■■ 已修改文件
libscpi/inc/scpi/externinterface.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/externinterface.h 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils.c 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/src/utils_private.h 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
libscpi/inc/scpi/externinterface.cpp
New file
@@ -0,0 +1,2 @@
#include "externinterface.h"
libscpi/inc/scpi/externinterface.h
New file
@@ -0,0 +1,253 @@
#ifndef EXTERNINTERFACE_H
#define EXTERNINTERFACE_H
#include <iostream>
#include<vector>
#ifdef __cplusplus
extern "C"
{
#endif
namespace SCPIPASER
{
class Segment {
public:
    //必填
    bool is_required = false;
    //变量 [:Measure] 这种的为变量 会置为TRUE
    bool is_variable = false;
    //是否有嵌套形式
    bool is_nested = false;
    // 可选组的数量
    int variableSize = 0;
    std::vector<std::string> options;
    // std::vector<Segment> sub_segments; // 用于存储嵌套的可选组
};
class PatternParser
{
private:
    static void trim_whitespace(std::string& str)
    {
        auto not_space = [](int ch) { return !std::isspace(ch); };
        str.erase(str.begin(), std::find_if(str.begin(), str.end(), not_space));
        str.erase(std::find_if(str.rbegin(), str.rend(), not_space).base(), str.end());
    }
    static std::vector<std::string> split_options(const std::string& input) {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find('|');
        while (end != std::string::npos) {
            std::string token = input.substr(start, end - start);
            trim_whitespace(token);
            //token = remove_colon(token); // 移除冒号
            if (!token.empty()) result.push_back(token);
            start = end + 1;
            end = input.find('|', start);
        }
        std::string last_token = input.substr(start);
        trim_whitespace(last_token);
        last_token = remove_colon(last_token); // 移除冒号
        if (!last_token.empty()) result.push_back(last_token);
        return result;
    }
    static std::string remove_colon(const std::string& input) {
        std::string result;
        for (char ch : input) {
            if (ch != ':') {
                result += ch;
            }
        }
        return result;
    }
public:
    static std::vector<std::string> parse_input_data(const std::string& input)
    {
        std::vector<std::string> result;
        size_t start = 0;
        size_t end = input.find(':');
        while (end != std::string::npos)
        {
            result.push_back(input.substr(start, end - start));
            start = end + 1;
            end = input.find(':', start);
        }
        result.push_back(input.substr(start));
        return result;
    }
    static bool match_all_segments(std::vector<std::string> stringList, std::vector<Segment> vecSegment)
    {
        int currentIndex = 0;
        for (int i =0;i<vecSegment.size();i++)
        {
            auto currentSegment = vecSegment[i];
            //严格匹配
            if (currentSegment.is_required)
            {
                for (auto option : currentSegment.options)
                {
                    if (stringList[currentIndex] != option)
                    {
                        //std::cout << "参数匹配失败  " << stringList[currentIndex] << "   option :  " << option;
                        return false;
                    }
                    else
                    {
                        //std::cout << "参数匹配成功 " << stringList[currentIndex] << "   option :  " << option<<std::endl;
                        currentIndex += 1;
                    }
                    break;
                }
            }
            //可选组
            else if (currentSegment.is_variable)
            {
                //如果有可选组的情况下 且参数长度一直 则匹配可选项内容 否则的话跳过
                if (stringList.size() == vecSegment.size())
                {
                    auto vecTempSegments = currentSegment.options;
                    for (auto option : vecTempSegments)
                    {
                        if (stringList[currentIndex] != option)
                        {
                            //std::cout << "参数匹配失败  " << stringList[currentIndex] << "   option :  " << option;
                            return false;
                        }
                        else
                        {
                            //std::cout << "参数匹配成功 " << stringList[currentIndex] << "   option :  " << option << std::endl;
                            currentIndex += 1;
                        }
                        break;
                    }
                }
            }
            //可变参
            else
            {
                //std::cout << "可变参数: "<< stringList[currentIndex] << " " << currentSegment.options[0] << std::endl;
                currentIndex += 1;
            }
        }
        return true;
    }
    static std::vector<Segment> extract_all_segments(const std::string& pattern)
    {
        std::vector<Segment> segments;
        size_t pos = 0;
        const size_t len = pattern.length();
        while (pos < len)
        {
            while (pos < len && std::isspace(pattern[pos])) ++pos;
            if (pos >= len) break;
            if (pattern[pos] == '<') {
                size_t end_pos = pattern.find('>', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.is_variable = false; // `<...>` 不被视为变量
                segment.options = split_options(content);
                // 检查是否包含 `:`
                if (content.find(':') != std::string::npos) {
                    segment.is_required = true; // 如果包含 `:`
                }
                else {
                    segment.is_required = false; // 如果不包含 `:`
                }
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else if (pattern[pos] == '[')
            {
                size_t end_pos = pattern.find(']', pos);
                if (end_pos == std::string::npos) break;
                std::string content = pattern.substr(pos + 1, end_pos - pos - 1);
                trim_whitespace(content);
                Segment segment;
                segment.variableSize += 1;
                segment.is_required = false;
                segment.is_variable = true;
                segment.options = split_options(content);
                segments.push_back(segment);
                pos = end_pos + 1;
            }
            else
            {
                size_t next_lt = pattern.find('<', pos);
                size_t next_lb = pattern.find('[', pos);
                size_t next_special = std::min(next_lt, next_lb);
                std::string content;
                if (next_special != std::string::npos)
                {
                    content = pattern.substr(pos, next_special - pos);
                }
                else
                {
                    content = pattern.substr(pos);
                }
                trim_whitespace(content);
                if (!content.empty())
                {
                    // 用 ':' 拆分参数
                    size_t start = 0;
                    size_t end = content.find(':');
                    while (end != std::string::npos)
                    {
                        std::string token = content.substr(start, end - start);
                        trim_whitespace(token);
                        if (!token.empty())
                        {
                            Segment segment;
                            segment.is_required = true; // 明确标记为必填项
                            segment.is_variable = false; // 普通文本不视为变量
                            segment.options.push_back(token);
                            segments.push_back(segment);
                        }
                        start = end + 1;
                        end = content.find(':', start);
                    }
                    // 处理最后一个部分
                    std::string last_token = content.substr(start);
                    trim_whitespace(last_token);
                    if (!last_token.empty())
                    {
                        Segment segment;
                        segment.is_required = true;
                        segment.is_variable = false;
                        segment.options.push_back(last_token);
                        segments.push_back(segment);
                    }
                }
                pos = (next_special != std::string::npos) ? next_special : len;
            }
        }
        return segments;
    }
};
}
#ifdef __cplusplus
}
#endif
#endif // EXTERNINTERFACE_H
libscpi/src/utils.c
@@ -1146,139 +1146,98 @@
}
// 解析模式,将每个部分保存到 segments 中
int parse_pattern(const char* pattern, Segment segments[], int max_segments) {
    int seg_count = 0;
    const char* p = pattern;
// 用于提取并处理选项的函数
int extract_required_options(const char* pattern, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int max_tags) {
    const char* start = strchr(pattern, '<');  // 查找第一个 '<'
    const char* end = NULL;
    int tag_count = 0;
    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++;  // 跳过'['
    // 处理 <...> 内的选项
    while (start != NULL && tag_count < max_tags)
    {
        end = strchr(start, '>');  // 查找对应的 '>'
            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';  // 结束符
        if (end == NULL) {
            break;  // 如果没有找到 '>',则退出
        }
        seg_count++;
    }
        // 提取 <...> 中的内容
        int len = end - start - 1;
        if (len > 0 && len < MAX_OPTION_LEN) {
            char buffer[MAX_OPTION_LEN];
            strncpy(buffer, start + 1, len);  // 复制 '<' 和 '>' 之间的内容
            buffer[len] = '\0';  // 结束符
    return seg_count;
}
            // 处理 | 分隔符,提取多个选项
            char* token = strtok(buffer, "|");
            int option_count = 0;
            while (token && option_count < MAX_OPTION_LEN) {
                // 去除 token 中的 "[:", "]" 和空格
                char* p = token;
                while (*p == ' ' || *p == '[' || *p == ':') p++;  // 去除前导空格和 [:
                char* q = p + strlen(p) - 1;
                while (q > p && (*q == ' ' || *q == ']')) q--;  // 去除尾随空格和 ]
                *(q + 1) = '\0';  // 确保结尾是'\0'
// 匹配命令字符串是否符合模式
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;
                // 拷贝选项到 options 数组
                if (option_count < MAX_OPTION_LEN) {  // 确保不会越界
                    strncpy(options[tag_count][option_count], p, MAX_OPTION_LEN - 1);
                    options[tag_count][option_count][MAX_OPTION_LEN - 1] = '\0';  // 确保结束符
                    option_count++;
                }
                token = strtok(NULL, "|");
            }
            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++;
        // 移动到下一个 '<' 位置,继续查找
        start = strchr(end + 1, '<');
        tag_count++;
    }
    // 检查是否处理完所有命令和所有段
    return (*cmd == '\0') && (current_seg == seg_count);
    return tag_count;
}
// 用于检查输入是否能匹配每一组选项
int match_input_to_options(const char* input, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int num_tags) {
    char input_copy[MAX_INPUT_LEN];
    strncpy(input_copy, input, MAX_INPUT_LEN - 1);
    input_copy[MAX_INPUT_LEN - 1] = '\0';  // 确保结尾是'\0'
    // 拆分输入字符串,按 ":" 分割
    char* token = strtok(input_copy, ":");
    int group_idx = 0;
    // 对每一组进行匹配
    while (token != NULL && group_idx < num_tags) {
        int match_found = 0;
        // 检查当前组的每个选项是否与输入的 token 匹配
        printf("Checking input token: '%s' against group %d options\n", token, group_idx + 1); // Debug info
        for (int i = 0; i < MAX_OPTION_LEN && options[group_idx][i][0] != '\0'; i++) {
            printf("  Comparing with option: '%s'\n", options[group_idx][i]); // Debug info
            if (strcmp(options[group_idx][i], token) == 0) {
                match_found = 1;
                break;
            }
        }
        // 如果当前组的某个选项没有匹配上,返回 false
        if (!match_found) {
            return 0;  // 不匹配
        }
        // 处理下一个输入部分
        token = strtok(NULL, ":");
        group_idx++;
    }
    return (group_idx == num_tags);
}
// 测试匹配函数
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);
    char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN] = { {{0}} };
    int num_tags = extract_required_options(pattern, options, MAX_TAGS);
    return match_input_to_options(command, options, num_tags);
}
libscpi/src/utils_private.h
@@ -79,18 +79,11 @@
scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) LOCAL;
#define MAX_SEGMENTS 16
typedef struct {
    bool is_variable;  // 是否为可变部分(用[]括起来的)
    bool is_required;  // 是否为必选部分(用<>括起来的)
    bool is_option;    // 是否为选项组部分(用|分隔)
    char text[32];     // 段内容(不包含[]或<>)
} Segment;
//匹配[:MEASure][:VOLTage]
int parse_pattern(const char* pattern, Segment segments[], int max_segments);
bool match_command(const char* command, Segment segments[], int seg_count);
#define MAX_OPTION_LEN 256
#define MAX_TAGS 10
#define MAX_INPUT_LEN 256
int extract_required_options(const char* pattern, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int max_tags);
int match_input_to_options(const char* input, char options[MAX_TAGS][MAX_OPTION_LEN][MAX_OPTION_LEN], int num_tags);
bool test_match(const char* pattern, const char* command);