From f1cd7de018b623d19a8f42ac47f0271a28eedcce Mon Sep 17 00:00:00 2001
From: Jan Breuer <jan.breuer@jaybee.cz>
Date: 周日, 19 4月 2015 06:43:16 +0800
Subject: [PATCH] Implement Traversal of the Header Tree. Solve #22

---
 libscpi/src/lexer.c              |    2 
 libscpi/inc/scpi/types.h         |    6 +-
 libscpi/src/parser_private.h     |    2 
 libscpi/src/parser.c             |   11 ++++-
 libscpi/test/test_lexer_parser.c |    8 ++--
 libscpi/src/utils_private.h      |    1 
 libscpi/inc/scpi/parser.h        |    2 
 libscpi/test/test_parser.c       |   30 +++++++++++++--
 libscpi/src/utils.c              |   45 ++++++++++++++++++++++
 9 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/libscpi/inc/scpi/parser.h b/libscpi/inc/scpi/parser.h
index 7940ea6..2cb4f73 100644
--- a/libscpi/inc/scpi/parser.h
+++ b/libscpi/inc/scpi/parser.h
@@ -47,7 +47,7 @@
     void SCPI_Init(scpi_t * context);
 
     int SCPI_Input(scpi_t * context, const char * data, int len);
-    int SCPI_Parse(scpi_t * context, const char * data, int len);
+    int SCPI_Parse(scpi_t * context, char * data, int len);
 
 
     size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len);
diff --git a/libscpi/inc/scpi/types.h b/libscpi/inc/scpi/types.h
index 4851d9e..8f829b3 100644
--- a/libscpi/inc/scpi/types.h
+++ b/libscpi/inc/scpi/types.h
@@ -161,14 +161,14 @@
 
     struct _scpi_token_t {
         scpi_token_type_t type;
-        const char * ptr;
+        char * ptr;
         int len;
     };
     typedef struct _scpi_token_t scpi_token_t;
 
     struct _lex_state_t {
-        const char * buffer;
-        const char * pos;
+        char * buffer;
+        char * pos;
         int len;
     };
     typedef struct _lex_state_t lex_state_t;
diff --git a/libscpi/src/lexer.c b/libscpi/src/lexer.c
index e7dc48d..c0505cc 100644
--- a/libscpi/src/lexer.c
+++ b/libscpi/src/lexer.c
@@ -506,7 +506,7 @@
  * @return 
  */
 int scpiLex_DecimalNumericProgramData(lex_state_t * state, scpi_token_t * token) {
-    const char * rollback;
+    char * rollback;
     token->ptr = state->pos;
 
     if (skipMantisa(state)) {
diff --git a/libscpi/src/parser.c b/libscpi/src/parser.c
index 80a4a00..9017bca 100644
--- a/libscpi/src/parser.c
+++ b/libscpi/src/parser.c
@@ -152,10 +152,11 @@
  * @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;
@@ -171,6 +172,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 +187,7 @@
                 processCommand(context);
 
                 result = 1;
+                cmd_prev = state->programHeader;
             } else {
                 SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER);
             }
@@ -414,7 +419,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;
@@ -934,7 +939,7 @@
  * @param len
  * @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;
diff --git a/libscpi/src/parser_private.h b/libscpi/src/parser_private.h
index b34c15d..de95865 100644
--- a/libscpi/src/parser_private.h
+++ b/libscpi/src/parser_private.h
@@ -45,7 +45,7 @@
 
     int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) LOCAL;
     int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) LOCAL;
-    int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, const char * buffer, int len) LOCAL;
+    int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) LOCAL;
 
 #ifdef	__cplusplus
 }
diff --git a/libscpi/src/utils.c b/libscpi/src/utils.c
index c40ddb6..710d8e0 100644
--- a/libscpi/src/utils.c
+++ b/libscpi/src/utils.c
@@ -441,6 +441,51 @@
     return result;
 }
 
+/**
+ * Compose command from previsou command anc current command
+ *
+ * @param prev pointer to previous command
+ * @param current pointer of current command
+ *
+ * prev and current should be in the same memory buffer
+ */
+scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current) {
+    size_t i;
+
+    /* Invalid input */
+    if (current == NULL || current->ptr == NULL || current->len == 0)
+        return FALSE;
+
+    /* no previous command - nothing to do*/
+    if (prev->ptr == NULL || prev->len == 0)
+        return TRUE;
+
+    /* Common command or command root - nothing to do */
+    if (current->ptr[0] == '*' || current->ptr[0] == ':')
+        return TRUE;
+
+    /* Previsou command was common command - nothing to do */
+    if (prev->ptr[0] == '*')
+        return TRUE;
+
+    /* Find last occurence of ':' */
+    for (i = prev->len; i > 0; i--) {
+        if (prev->ptr[i - 1] == ':') {
+            break;
+        }
+    }
+
+    /* Previous command was simple command - nothing to do*/
+    if (i == 0)
+        return TRUE;
+
+    current->ptr -= i;
+    current->len += i;
+    memmove(current->ptr, prev->ptr, i);
+    return TRUE;
+}
+
+
 
 #if !HAVE_STRNLEN
 /* use FreeBSD strnlen */
diff --git a/libscpi/src/utils_private.h b/libscpi/src/utils_private.h
index ed624f3..255136b 100644
--- a/libscpi/src/utils_private.h
+++ b/libscpi/src/utils_private.h
@@ -63,6 +63,7 @@
     size_t skipWhitespace(const char * cmd, size_t len) LOCAL;
     scpi_bool_t matchPattern(const char * pattern, size_t pattern_len, const char * str, size_t str_len) LOCAL;
     scpi_bool_t matchCommand(const char * pattern, const char * cmd, size_t len) LOCAL;
+    scpi_bool_t composeCompoundCommand(const scpi_token_t * prev, scpi_token_t * current);
 
 #if !HAVE_STRNLEN
     size_t BSD_strnlen(const char *s, size_t maxlen);
diff --git a/libscpi/test/test_lexer_parser.c b/libscpi/test/test_lexer_parser.c
index d11496c..9ea883f 100644
--- a/libscpi/test/test_lexer_parser.c
+++ b/libscpi/test/test_lexer_parser.c
@@ -82,7 +82,7 @@
 #endif
 
 #define TEST_TOKEN(s, f, o, l, t) do {          \
-    const char * str = s;                       \
+    char * str = s;                             \
     lexfn_t fn = f;                             \
     int offset = o;                             \
     int len = l;                                \
@@ -211,7 +211,7 @@
 
 
 #define TEST_ALL_TOKEN(s, f, o, l, t, c) do {   \
-    const char * str = s;                       \
+    char * str = s;                             \
     lexfn2_t fn = f;                            \
     int offset = o;                             \
     int len = l;                                \
@@ -244,10 +244,10 @@
 
 
 #define TEST_DETECT(s, h, hl, ht, d, dc, t) do {                                \
-    const char * str = s;                                                       \
+    char * str = s;                                                             \
     scpi_parser_state_t state;                                                  \
     int result;                                                                 \
-    result = scpiParser_detectProgramMessageUnit(&state, str, strlen(str));           \
+    result = scpiParser_detectProgramMessageUnit(&state, str, strlen(str));     \
     CU_ASSERT_EQUAL(state.programHeader.ptr, str + h);                          \
     CU_ASSERT_EQUAL(state.programHeader.len, hl);                               \
     CU_ASSERT_EQUAL(state.programHeader.type, ht);                              \
diff --git a/libscpi/test/test_parser.c b/libscpi/test/test_parser.c
index f747271..cee918f 100644
--- a/libscpi/test/test_parser.c
+++ b/libscpi/test/test_parser.c
@@ -30,6 +30,20 @@
     return SCPI_RES_OK;
 }
 
+scpi_result_t test_treeA(scpi_t* context) {
+
+    SCPI_ResultInt(context, 10);
+
+    return SCPI_RES_OK;
+}
+
+scpi_result_t test_treeB(scpi_t* context) {
+
+    SCPI_ResultInt(context, 20);
+
+    return SCPI_RES_OK;
+}
+
 static const scpi_command_t scpi_commands[] = {
     /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */
     { .pattern = "*CLS", .callback = SCPI_CoreCls,},
@@ -57,7 +71,10 @@
 
     { .pattern = "STATus:PRESet", .callback = SCPI_StatusPreset,},
     
-    { .pattern = "TEXTfunction", .callback = text_function,},
+    { .pattern = "TEXTfunction?", .callback = text_function,},
+
+    { .pattern = "TEST:TREEA?", .callback = test_treeA,},
+    { .pattern = "TEST:TREEB?", .callback = test_treeB,},
 
     SCPI_CMD_LIST_END
 };
@@ -193,10 +210,15 @@
     TEST_INPUT("", "MA,IN,0,VER\r\n");
     output_buffer_clear();
     
+    /* Test ctree traversal */
+    TEST_INPUT("TEST:TREEA?;TREEB?\r\n", "10\r\n20\r\n");
+    output_buffer_clear();
+
+    TEST_INPUT("TEST:TREEA?;:TEXT? \"PARAM1\", \"PARAM2\"\r\n", "10\r\n\"PARAM2\"\r\n");
+    output_buffer_clear();
+
     CU_ASSERT_EQUAL(err_buffer_pos, 0);
     error_buffer_clear();
-    
-    // TODO: Compound commands A:B;C -> A:B; A:C
 }
 
 void testErrorHandling(void) {
@@ -215,7 +237,7 @@
     TEST_ERROR("IDN?\r\n", "", SCPI_ERROR_UNDEFINED_HEADER);
     TEST_ERROR("*ESE\r\n", "", SCPI_ERROR_MISSING_PARAMETER);
     TEST_ERROR("*IDN? 12\r\n", "MA,IN,0,VER\r\n", SCPI_ERROR_PARAMETER_NOT_ALLOWED);
-    TEST_ERROR("TEXT \"PARAM1\", \"PARAM2\"\r\n", "\"PARAM2\"\r\n", 0);
+    TEST_ERROR("TEXT? \"PARAM1\", \"PARAM2\"\r\n", "\"PARAM2\"\r\n", 0);
 
     // TODO: SCPI_ERROR_INVALID_SEPARATOR
     // TODO: SCPI_ERROR_INVALID_SUFFIX

--
Gitblit v1.9.1