Jan Breuer
2015-08-04 7f3d9c0c0238b1fec92fff04f87730668100b73b
libscpi/src/parser.c
@@ -43,6 +43,8 @@
#include "lexer_private.h"
#include "scpi/error.h"
#include "scpi/constants.h"
#include "scpi/utils.h"
#include "scpi/debug.h"
/**
 * Write data to SCPI output
@@ -75,7 +77,7 @@
 */
static size_t writeDelimiter(scpi_t * context) {
    if (context->output_count > 0) {
        return writeData(context, ",", 2);
        return writeData(context, ",", 1);
    } else {
        return 0;
    }
@@ -89,9 +91,25 @@
static size_t writeNewLine(scpi_t * context) {
    if (context->output_count > 0) {
        size_t len;
        len = writeData(context, "\r\n", 2);
#ifndef SCPI_LINE_ENDING
#error no termination character defined
#endif
        len = writeData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING));
        flushData(context);
        return len;
    } else {
        return 0;
    }
}
/**
 * Conditionaly write ";"
 * @param context
 * @return number of characters written
 */
static size_t writeSemicolon(scpi_t * context) {
    if (context->output_count > 0) {
        return writeData(context, ";", 1);
    } else {
        return 0;
    }
@@ -105,6 +123,9 @@
    const scpi_command_t * cmd = context->param_list.cmd;
    lex_state_t * state = &context->param_list.lex_state;
    /* conditionaly write ; */
    writeSemicolon(context);
    context->cmd_error = FALSE;
    context->output_count = 0;
    context->input_count = 0;
@@ -116,9 +137,6 @@
            SCPI_ErrorPush(context, SCPI_ERROR_EXECUTION_ERROR);
        }
    }
    /* conditionaly write new line */
    writeNewLine(context);
    /* set error if command callback did not read all parameters */
    if (state->pos < (state->buffer + state->len) && !context->cmd_error) {
@@ -137,7 +155,7 @@
    for (i = 0; context->cmdlist[i].pattern != NULL; i++) {
        cmd = &context->cmdlist[i];
        if (matchCommand(cmd->pattern, header, len)) {
        if (matchCommand(cmd->pattern, header, len, NULL, 0)) {
            context->param_list.cmd = cmd;
            return TRUE;
        }
@@ -152,16 +170,18 @@
 * @param len - command line length
 * @return 1 if the last evaluated command was found
 */
int SCPI_Parse(scpi_t * context, const char * data, int len) {
int SCPI_Parse(scpi_t * context, char * data, int len) {
    int result = 0;
    scpi_parser_state_t * state;
    int r;
    scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0};
    if (context == NULL) {
        return -1;
    }
    state = &context->parser_state;
    context->output_count = 0;
    while (1) {
        result = 0;
@@ -171,6 +191,9 @@
        if (state->programHeader.type == SCPI_TOKEN_INVALID) {
            SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER);
        } else if (state->programHeader.len > 0) {
            composeCompoundCommand(&cmd_prev, &state->programHeader);
            if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) {
                context->param_list.lex_state.buffer = state->programData.ptr;
@@ -183,6 +206,7 @@
                processCommand(context);
                result = 1;
                cmd_prev = state->programHeader;
            } else {
                SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
            }
@@ -196,6 +220,10 @@
        }
    }
    /* conditionaly write new line */
    writeNewLine(context);
    return result;
}
@@ -258,15 +286,16 @@
        while (1) {
            cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
            totcmdlen += cmdlen;
            if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) break;
            if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN) break;
            if (totcmdlen >= context->buffer.position) break;
        }
        if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) {
            result = SCPI_Parse(context, context->buffer.data, totcmdlen);
            memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
            context->buffer.position -= totcmdlen;
            if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) {
                result = SCPI_Parse(context, context->buffer.data, totcmdlen);
                memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen);
                context->buffer.position -= totcmdlen;
                totcmdlen = 0;
            } else {
                if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN) break;
                if (totcmdlen >= context->buffer.position) break;
            }
        }
    }
@@ -302,7 +331,7 @@
/**
 * Return prefix of nondecimal base
 * @param base
 * @return
 * @return
 */
static const char * getBasePrefix(int8_t base) {
    switch (base) {
@@ -318,7 +347,7 @@
 * @param context
 * @param val
 * @param base
 * @return
 * @return
 */
size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base) {
    char buffer[33];
@@ -326,7 +355,7 @@
    size_t result = 0;
    size_t len;
    len = longToStr(val, buffer, sizeof (buffer), base);
    len = SCPI_LongToStr(val, buffer, sizeof (buffer), base);
    basePrefix = getBasePrefix(base);
    result += writeDelimiter(context);
@@ -347,7 +376,7 @@
size_t SCPI_ResultDouble(scpi_t * context, double val) {
    char buffer[32];
    size_t result = 0;
    size_t len = doubleToStr(val, buffer, sizeof (buffer));
    size_t len = SCPI_DoubleToStr(val, buffer, sizeof (buffer));
    result += writeDelimiter(context);
    result += writeData(context, buffer, len);
    context->output_count++;
@@ -377,14 +406,14 @@
 * @param context
 * @param data
 * @param len
 * @return
 * @return
 */
size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len) {
    size_t result = 0;
    char block_header[12];
    size_t header_len;
    block_header[0] = '#';
    longToStr(len, block_header + 2, 10, 10);
    SCPI_LongToStr(len, block_header + 2, 10, 10);
    header_len = strlen(block_header + 2);
    block_header[1] = header_len + '0';
@@ -413,7 +442,7 @@
 * @param token
 * @param ptr
 */
static void invalidateToken(scpi_token_t * token, const char * ptr) {
static void invalidateToken(scpi_token_t * token, char * ptr) {
    token->len = 0;
    token->ptr = ptr;
    token->type = SCPI_TOKEN_UNKNOWN;
@@ -424,7 +453,7 @@
 * @param context
 * @param parameter
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) {
    lex_state_t * state;
@@ -482,7 +511,7 @@
 * Detect if parameter is number
 * @param parameter
 * @param suffixAllowed
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed) {
    switch (parameter->type) {
@@ -503,7 +532,7 @@
 * @param context
 * @param parameter
 * @param value result
 * @return true if succesful
 * @return TRUE if succesful
 */
scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value) {
@@ -531,7 +560,7 @@
 * @param context
 * @param parameter
 * @param value result
 * @return true if succesful
 * @return TRUE if succesful
 */
scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value) {
    scpi_bool_t result = FALSE;
@@ -562,7 +591,7 @@
 * @param context
 * @param value
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -593,7 +622,7 @@
 * @param context
 * @param value
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -625,7 +654,7 @@
 * @param value
 * @param len
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -653,7 +682,7 @@
 * @param value result pointer to data
 * @param len result length of data
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -723,7 +752,7 @@
 * @param parameter - should be PROGRAM_MNEMONIC
 * @param options - NULL terminated list of choices
 * @param value - index to options
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value) {
    size_t res;
@@ -736,7 +765,7 @@
    if (parameter->type == SCPI_TOKEN_PROGRAM_MNEMONIC) {
        for (res = 0; options[res].name; ++res) {
            if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len)) {
            if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len, NULL)) {
                *value = options[res].tag;
                result = TRUE;
                break;
@@ -758,7 +787,7 @@
 * @param options specifications of choices numbers (patterns)
 * @param tag numerical representatio of choice
 * @param text result text
 * @return true if succesfule, else false
 * @return TRUE if succesfule, else false
 */
scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text) {
    int i;
@@ -778,7 +807,7 @@
 * @param context
 * @param value
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -819,7 +848,7 @@
 * @param options
 * @param value
 * @param mandatory
 * @return
 * @return
 */
scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory) {
    scpi_bool_t result;
@@ -842,7 +871,7 @@
 * Parse one parameter and detect type
 * @param state
 * @param token
 * @return
 * @return
 */
int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) {
    scpi_token_t tmp;
@@ -881,7 +910,7 @@
 * @param state
 * @param token
 * @param numberOfParameters
 * @return
 * @return
 */
int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) {
@@ -931,9 +960,9 @@
 * @param state
 * @param buffer
 * @param len
 * @return
 * @return
 */
int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) {
int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) {
    lex_state_t lex_state;
    scpi_token_t tmp;
    int result = 0;
@@ -984,15 +1013,17 @@
 *  - suitable for one handle to multiple commands
 * @param context
 * @param cmd
 * @return
 * @return
 */
scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) {
    const char * pattern;
    if (!context->param_list.cmd) {
        return FALSE;
    }
    const char * pattern = context->param_list.cmd->pattern;
    return matchCommand(pattern, cmd, strlen(cmd));
    pattern = context->param_list.cmd->pattern;
    return matchCommand (pattern, cmd, strlen (cmd), NULL, 0);
}
/**
@@ -1008,14 +1039,10 @@
    }
}
scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len) {
    return matchCommand (pattern, value, len, NULL, 0);
}
scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len) {
    return matchCommand (context->param_list.cmd->pattern,  context->param_list.cmd_raw.data, context->param_list.cmd_raw.length, numbers, len);
}