https://github.com/j123b567/scpi-parser
Dependents: scpi_sx127x scpi_sx127x_firstTest MLX90418_I2C_master
parser.c
00001 /*- 00002 * Copyright (c) 2012-2013 Jan Breuer, 00003 * 00004 * All Rights Reserved 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are 00008 * met: 00009 * 1. Redistributions of source code must retain the above copyright notice, 00010 * this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00018 * DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 00019 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00021 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 00022 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00023 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 00024 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /** 00029 * @file scpi_parser.c 00030 * @date Thu Nov 15 10:58:45 UTC 2012 00031 * 00032 * @brief SCPI parser implementation 00033 * 00034 * 00035 */ 00036 00037 #include <ctype.h> 00038 #include <string.h> 00039 00040 #include "scpi/config.h" 00041 #include "scpi/parser.h" 00042 #include "parser_private.h" 00043 #include "lexer_private.h" 00044 #include "scpi/error.h" 00045 #include "scpi/constants.h" 00046 #include "scpi/utils.h" 00047 00048 /** 00049 * Write data to SCPI output 00050 * @param context 00051 * @param data 00052 * @param len - lenght of data to be written 00053 * @return number of bytes written 00054 */ 00055 static size_t writeData(scpi_t * context, const char * data, size_t len) { 00056 return context->interface->write(context, data, len); 00057 } 00058 00059 /** 00060 * Flush data to SCPI output 00061 * @param context 00062 * @return 00063 */ 00064 static int flushData(scpi_t * context) { 00065 if (context && context->interface && context->interface->flush) { 00066 return context->interface->flush(context); 00067 } else { 00068 return SCPI_RES_OK; 00069 } 00070 } 00071 00072 /** 00073 * Write result delimiter to output 00074 * @param context 00075 * @return number of bytes written 00076 */ 00077 static size_t writeDelimiter(scpi_t * context) { 00078 if (context->output_count > 0) { 00079 return writeData(context, ",", 1); 00080 } else { 00081 return 0; 00082 } 00083 } 00084 00085 /** 00086 * Conditionaly write "New Line" 00087 * @param context 00088 * @return number of characters written 00089 */ 00090 static size_t writeNewLine(scpi_t * context) { 00091 if (context->output_count > 0) { 00092 size_t len; 00093 #ifndef SCPI_LINE_ENDING 00094 #error no termination character defined 00095 #endif 00096 len = writeData(context, SCPI_LINE_ENDING, strlen(SCPI_LINE_ENDING)); 00097 flushData(context); 00098 return len; 00099 } else { 00100 return 0; 00101 } 00102 } 00103 00104 /** 00105 * Conditionaly write ";" 00106 * @param context 00107 * @return number of characters written 00108 */ 00109 static size_t writeSemicolon(scpi_t * context) { 00110 if (context->output_count > 0) { 00111 return writeData(context, ";", 1); 00112 } else { 00113 return 0; 00114 } 00115 } 00116 00117 /** 00118 * Process command 00119 * @param context 00120 */ 00121 static void processCommand(scpi_t * context) { 00122 const scpi_command_t * cmd = context->param_list.cmd; 00123 lex_state_t * state = &context->param_list.lex_state; 00124 00125 /* conditionaly write ; */ 00126 writeSemicolon(context); 00127 00128 context->cmd_error = FALSE; 00129 context->output_count = 0; 00130 context->input_count = 0; 00131 00132 /* if callback exists - call command callback */ 00133 if (cmd->callback != NULL) { 00134 if ((cmd->callback(context) != SCPI_RES_OK) && !context->cmd_error) { 00135 SCPI_ErrorPush(context, SCPI_ERROR_EXECUTION_ERROR); 00136 } 00137 } 00138 00139 /* set error if command callback did not read all parameters */ 00140 if (state->pos < (state->buffer + state->len) && !context->cmd_error) { 00141 SCPI_ErrorPush(context, SCPI_ERROR_PARAMETER_NOT_ALLOWED); 00142 } 00143 } 00144 00145 /** 00146 * Cycle all patterns and search matching pattern. Execute command callback. 00147 * @param context 00148 * @result TRUE if context->paramlist is filled with correct values 00149 */ 00150 static scpi_bool_t findCommandHeader(scpi_t * context, const char * header, int len) { 00151 int32_t i; 00152 const scpi_command_t * cmd; 00153 00154 for (i = 0; context->cmdlist[i].pattern != NULL; i++) { 00155 cmd = &context->cmdlist[i]; 00156 if (matchCommand(cmd->pattern, header, len, NULL, 0)) { 00157 context->param_list.cmd = cmd; 00158 return TRUE; 00159 } 00160 } 00161 return FALSE; 00162 } 00163 00164 /** 00165 * Parse one command line 00166 * @param context 00167 * @param data - complete command line 00168 * @param len - command line length 00169 * @return 1 if the last evaluated command was found 00170 */ 00171 int SCPI_Parse(scpi_t * context, char * data, int len) { 00172 int result = 0; 00173 scpi_parser_state_t * state; 00174 int r; 00175 scpi_token_t cmd_prev = {SCPI_TOKEN_UNKNOWN, NULL, 0}; 00176 00177 if (context == NULL) { 00178 return -1; 00179 } 00180 00181 state = &context->parser_state; 00182 context->output_count = 0; 00183 00184 while (1) { 00185 result = 0; 00186 00187 r = scpiParser_detectProgramMessageUnit(state, data, len); 00188 00189 if (state->programHeader.type == SCPI_TOKEN_INVALID) { 00190 SCPI_ErrorPush(context, SCPI_ERROR_INVALID_CHARACTER); 00191 } else if (state->programHeader.len > 0) { 00192 00193 composeCompoundCommand(&cmd_prev, &state->programHeader); 00194 00195 if (findCommandHeader(context, state->programHeader.ptr, state->programHeader.len)) { 00196 00197 context->param_list.lex_state.buffer = state->programData.ptr; 00198 context->param_list.lex_state.pos = context->param_list.lex_state.buffer; 00199 context->param_list.lex_state.len = state->programData.len; 00200 context->param_list.cmd_raw.data = state->programHeader.ptr; 00201 context->param_list.cmd_raw.position = 0; 00202 context->param_list.cmd_raw.length = state->programHeader.len; 00203 00204 processCommand(context); 00205 00206 result = 1; 00207 cmd_prev = state->programHeader; 00208 } else { 00209 SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER); 00210 } 00211 } 00212 00213 if (r < len) { 00214 data += r; 00215 len -= r; 00216 } else { 00217 break; 00218 } 00219 00220 } 00221 00222 /* conditionaly write new line */ 00223 writeNewLine(context); 00224 00225 return result; 00226 } 00227 00228 /** 00229 * Initialize SCPI context structure 00230 * @param context 00231 * @param command_list 00232 * @param buffer 00233 * @param interface 00234 */ 00235 void SCPI_Init(scpi_t * context) { 00236 if (context->idn[0] == NULL) { 00237 context->idn[0] = SCPI_DEFAULT_1_MANUFACTURE; 00238 } 00239 if (context->idn[1] == NULL) { 00240 context->idn[1] = SCPI_DEFAULT_2_MODEL; 00241 } 00242 if (context->idn[2] == NULL) { 00243 context->idn[2] = SCPI_DEFAULT_3; 00244 } 00245 if (context->idn[3] == NULL) { 00246 context->idn[3] = SCPI_DEFAULT_4_REVISION; 00247 } 00248 00249 context->buffer.position = 0; 00250 SCPI_ErrorInit(context); 00251 } 00252 00253 /** 00254 * Interface to the application. Adds data to system buffer and try to search 00255 * command line termination. If the termination is found or if len=0, command 00256 * parser is called. 00257 * 00258 * @param context 00259 * @param data - data to process 00260 * @param len - length of data 00261 * @return 00262 */ 00263 int SCPI_Input(scpi_t * context, const char * data, int len) { 00264 int result = 0; 00265 size_t totcmdlen = 0; 00266 int cmdlen = 0; 00267 00268 if (len == 0) { 00269 context->buffer.data[context->buffer.position] = 0; 00270 result = SCPI_Parse(context, context->buffer.data, context->buffer.position); 00271 context->buffer.position = 0; 00272 } else { 00273 int buffer_free; 00274 00275 buffer_free = context->buffer.length - context->buffer.position; 00276 if (len > (buffer_free - 1)) { 00277 return -1; 00278 } 00279 memcpy(&context->buffer.data[context->buffer.position], data, len); 00280 context->buffer.position += len; 00281 context->buffer.data[context->buffer.position] = 0; 00282 00283 00284 while (1) { 00285 cmdlen = scpiParser_detectProgramMessageUnit(&context->parser_state, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); 00286 totcmdlen += cmdlen; 00287 00288 if (context->parser_state.termination == SCPI_MESSAGE_TERMINATION_NL) { 00289 result = SCPI_Parse(context, context->buffer.data, totcmdlen); 00290 memmove(context->buffer.data, context->buffer.data + totcmdlen, context->buffer.position - totcmdlen); 00291 context->buffer.position -= totcmdlen; 00292 totcmdlen = 0; 00293 } else { 00294 if (context->parser_state.programHeader.type == SCPI_TOKEN_UNKNOWN) break; 00295 if (totcmdlen >= context->buffer.position) break; 00296 } 00297 } 00298 } 00299 00300 return result; 00301 } 00302 00303 /* writing results */ 00304 00305 /** 00306 * Write raw string result to the output 00307 * @param context 00308 * @param data 00309 * @return 00310 */ 00311 size_t SCPI_ResultCharacters(scpi_t * context, const char * data, size_t len) { 00312 size_t result = 0; 00313 result += writeDelimiter(context); 00314 result += writeData(context, data, len); 00315 context->output_count++; 00316 return result; 00317 } 00318 00319 /** 00320 * Write integer value to the result 00321 * @param context 00322 * @param val 00323 * @return 00324 */ 00325 size_t SCPI_ResultInt(scpi_t * context, int32_t val) { 00326 return SCPI_ResultIntBase(context, val, 10); 00327 } 00328 00329 /** 00330 * Return prefix of nondecimal base 00331 * @param base 00332 * @return 00333 */ 00334 static const char * getBasePrefix(int8_t base) { 00335 switch (base) { 00336 case 2: return "#B"; 00337 case 8: return "#Q"; 00338 case 16: return "#H"; 00339 default: return NULL; 00340 } 00341 } 00342 00343 /** 00344 * Write integer value in specific base to the result 00345 * @param context 00346 * @param val 00347 * @param base 00348 * @return 00349 */ 00350 size_t SCPI_ResultIntBase(scpi_t * context, int32_t val, int8_t base) { 00351 char buffer[33]; 00352 const char * basePrefix; 00353 size_t result = 0; 00354 size_t len; 00355 00356 len = SCPI_LongToStr(val, buffer, sizeof (buffer), base); 00357 basePrefix = getBasePrefix(base); 00358 00359 result += writeDelimiter(context); 00360 if (basePrefix != NULL) { 00361 result += writeData(context, basePrefix, 2); 00362 } 00363 result += writeData(context, buffer, len); 00364 context->output_count++; 00365 return result; 00366 } 00367 00368 /** 00369 * Write double walue to the result 00370 * @param context 00371 * @param val 00372 * @return 00373 */ 00374 size_t SCPI_ResultDouble(scpi_t * context, double val) { 00375 char buffer[32]; 00376 size_t result = 0; 00377 size_t len = SCPI_DoubleToStr(val, buffer, sizeof (buffer)); 00378 result += writeDelimiter(context); 00379 result += writeData(context, buffer, len); 00380 context->output_count++; 00381 return result; 00382 00383 } 00384 00385 /** 00386 * Write string withn " to the result 00387 * @param context 00388 * @param data 00389 * @return 00390 */ 00391 size_t SCPI_ResultText(scpi_t * context, const char * data) { 00392 size_t result = 0; 00393 result += writeDelimiter(context); 00394 result += writeData(context, "\"", 1); 00395 // TODO: convert " to "" 00396 result += writeData(context, data, strlen(data)); 00397 result += writeData(context, "\"", 1); 00398 context->output_count++; 00399 return result; 00400 } 00401 00402 /** 00403 * Write arbitrary block program data to the result 00404 * @param context 00405 * @param data 00406 * @param len 00407 * @return 00408 */ 00409 size_t SCPI_ResultArbitraryBlock(scpi_t * context, const char * data, size_t len) { 00410 size_t result = 0; 00411 char block_header[12]; 00412 size_t header_len; 00413 block_header[0] = '#'; 00414 SCPI_LongToStr(len, block_header + 2, 10, 10); 00415 00416 header_len = strlen(block_header + 2); 00417 block_header[1] = (char)(header_len + '0'); 00418 00419 result += writeData(context, block_header, header_len + 2); 00420 result += writeData(context, data, len); 00421 00422 context->output_count++; 00423 return result; 00424 } 00425 00426 /** 00427 * Write boolean value to the result 00428 * @param context 00429 * @param val 00430 * @return 00431 */ 00432 size_t SCPI_ResultBool(scpi_t * context, scpi_bool_t val) { 00433 return SCPI_ResultIntBase(context, val ? 1 : 0, 10); 00434 } 00435 00436 /* parsing parameters */ 00437 00438 /** 00439 * Invalidate token 00440 * @param token 00441 * @param ptr 00442 */ 00443 static void invalidateToken(scpi_token_t * token, char * ptr) { 00444 token->len = 0; 00445 token->ptr = ptr; 00446 token->type = SCPI_TOKEN_UNKNOWN; 00447 } 00448 00449 /** 00450 * Get one parameter from command line 00451 * @param context 00452 * @param parameter 00453 * @param mandatory 00454 * @return 00455 */ 00456 scpi_bool_t SCPI_Parameter(scpi_t * context, scpi_parameter_t * parameter, scpi_bool_t mandatory) { 00457 lex_state_t * state; 00458 00459 if (!parameter) { 00460 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00461 return FALSE; 00462 } 00463 00464 invalidateToken(parameter, NULL); 00465 00466 state = &context->param_list.lex_state; 00467 00468 if (state->pos >= (state->buffer + state->len)) { 00469 if (mandatory) { 00470 SCPI_ErrorPush(context, SCPI_ERROR_MISSING_PARAMETER); 00471 } else { 00472 parameter->type = SCPI_TOKEN_PROGRAM_MNEMONIC; // TODO: select something different 00473 } 00474 return FALSE; 00475 } 00476 if (context->input_count != 0) { 00477 scpiLex_Comma(state, parameter); 00478 if (parameter->type != SCPI_TOKEN_COMMA) { 00479 invalidateToken(parameter, NULL); 00480 SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SEPARATOR); 00481 return FALSE; 00482 } 00483 } 00484 00485 context->input_count++; 00486 00487 scpiParser_parseProgramData(&context->param_list.lex_state, parameter); 00488 00489 switch (parameter->type) { 00490 case SCPI_TOKEN_HEXNUM: 00491 case SCPI_TOKEN_OCTNUM: 00492 case SCPI_TOKEN_BINNUM: 00493 case SCPI_TOKEN_PROGRAM_MNEMONIC: 00494 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 00495 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 00496 case SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA: 00497 case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA: 00498 case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA: 00499 case SCPI_TOKEN_PROGRAM_EXPRESSION: 00500 return TRUE; 00501 default: 00502 invalidateToken(parameter, NULL); 00503 SCPI_ErrorPush(context, SCPI_ERROR_INVALID_STRING_DATA); 00504 return FALSE; 00505 } 00506 } 00507 00508 /** 00509 * Detect if parameter is number 00510 * @param parameter 00511 * @param suffixAllowed 00512 * @return 00513 */ 00514 scpi_bool_t SCPI_ParamIsNumber(scpi_parameter_t * parameter, scpi_bool_t suffixAllowed) { 00515 switch (parameter->type) { 00516 case SCPI_TOKEN_HEXNUM: 00517 case SCPI_TOKEN_OCTNUM: 00518 case SCPI_TOKEN_BINNUM: 00519 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 00520 return TRUE; 00521 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 00522 return suffixAllowed; 00523 default: 00524 return FALSE; 00525 } 00526 } 00527 00528 /** 00529 * Convert parameter to integer 00530 * @param context 00531 * @param parameter 00532 * @param value result 00533 * @return TRUE if succesful 00534 */ 00535 scpi_bool_t SCPI_ParamToInt(scpi_t * context, scpi_parameter_t * parameter, int32_t * value) { 00536 00537 if (!value) { 00538 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00539 return FALSE; 00540 } 00541 00542 switch (parameter->type) { 00543 case SCPI_TOKEN_HEXNUM: 00544 return strToLong(parameter->ptr, value, 16) > 0 ? TRUE : FALSE; 00545 case SCPI_TOKEN_OCTNUM: 00546 return strToLong(parameter->ptr, value, 8) > 0 ? TRUE : FALSE; 00547 case SCPI_TOKEN_BINNUM: 00548 return strToLong(parameter->ptr, value, 2) > 0 ? TRUE : FALSE; 00549 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 00550 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 00551 return strToLong(parameter->ptr, value, 10) > 0 ? TRUE : FALSE; 00552 } 00553 return FALSE; 00554 } 00555 00556 /** 00557 * Convert parameter to double 00558 * @param context 00559 * @param parameter 00560 * @param value result 00561 * @return TRUE if succesful 00562 */ 00563 scpi_bool_t SCPI_ParamToDouble(scpi_t * context, scpi_parameter_t * parameter, double * value) { 00564 scpi_bool_t result = FALSE; 00565 int32_t valint; 00566 00567 if (!value) { 00568 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00569 return FALSE; 00570 } 00571 00572 switch (parameter->type) { 00573 case SCPI_TOKEN_HEXNUM: 00574 case SCPI_TOKEN_OCTNUM: 00575 case SCPI_TOKEN_BINNUM: 00576 result = SCPI_ParamToInt(context, parameter, &valint); 00577 *value = valint; 00578 break; 00579 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA: 00580 case SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX: 00581 result = strToDouble(parameter->ptr, value) > 0 ? TRUE : FALSE; 00582 break; 00583 } 00584 return result; 00585 } 00586 00587 /** 00588 * Read floating point parameter 00589 * @param context 00590 * @param value 00591 * @param mandatory 00592 * @return 00593 */ 00594 scpi_bool_t SCPI_ParamDouble(scpi_t * context, double * value, scpi_bool_t mandatory) { 00595 scpi_bool_t result; 00596 scpi_parameter_t param; 00597 00598 if (!value) { 00599 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00600 return FALSE; 00601 } 00602 00603 result = SCPI_Parameter(context, ¶m, mandatory); 00604 if (result) { 00605 if (SCPI_ParamIsNumber(¶m, FALSE)) { 00606 SCPI_ParamToDouble(context, ¶m, value); 00607 } else if (SCPI_ParamIsNumber(¶m, TRUE)) { 00608 SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); 00609 result = FALSE; 00610 } else { 00611 SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 00612 result = FALSE; 00613 } 00614 } 00615 return result; 00616 } 00617 00618 /** 00619 * Read integer parameter 00620 * @param context 00621 * @param value 00622 * @param mandatory 00623 * @return 00624 */ 00625 scpi_bool_t SCPI_ParamInt(scpi_t * context, int32_t * value, scpi_bool_t mandatory) { 00626 scpi_bool_t result; 00627 scpi_parameter_t param; 00628 00629 if (!value) { 00630 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00631 return FALSE; 00632 } 00633 00634 result = SCPI_Parameter(context, ¶m, mandatory); 00635 if (result) { 00636 if (SCPI_ParamIsNumber(¶m, FALSE)) { 00637 SCPI_ParamToInt(context, ¶m, value); 00638 } else if (SCPI_ParamIsNumber(¶m, TRUE)) { 00639 SCPI_ErrorPush(context, SCPI_ERROR_SUFFIX_NOT_ALLOWED); 00640 result = FALSE; 00641 } else { 00642 SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 00643 result = FALSE; 00644 } 00645 } 00646 return result; 00647 } 00648 00649 /** 00650 * Read character parameter 00651 * @param context 00652 * @param value 00653 * @param len 00654 * @param mandatory 00655 * @return 00656 */ 00657 scpi_bool_t SCPI_ParamCharacters(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { 00658 scpi_bool_t result; 00659 scpi_parameter_t param; 00660 00661 if (!value || !len) { 00662 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00663 return FALSE; 00664 } 00665 00666 result = SCPI_Parameter(context, ¶m, mandatory); 00667 if (result) { 00668 *value = param.ptr; 00669 *len = param.len; 00670 00671 // TODO: return also parameter type (ProgramMnemonic, ArbitraryBlockProgramData, SingleQuoteProgramData, DoubleQuoteProgramData 00672 } 00673 00674 return result; 00675 } 00676 00677 /** 00678 * Get arbitrary block program data and returns pointer to data 00679 * @param context 00680 * @param value result pointer to data 00681 * @param len result length of data 00682 * @param mandatory 00683 * @return 00684 */ 00685 scpi_bool_t SCPI_ParamArbitraryBlock(scpi_t * context, const char ** value, size_t * len, scpi_bool_t mandatory) { 00686 scpi_bool_t result; 00687 scpi_parameter_t param; 00688 00689 if (!value || !len) { 00690 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00691 return FALSE; 00692 } 00693 00694 result = SCPI_Parameter(context, ¶m, mandatory); 00695 if (result) { 00696 if (param.type == SCPI_TOKEN_ARBITRARY_BLOCK_PROGRAM_DATA) { 00697 *value = param.ptr; 00698 *len = param.len; 00699 } else { 00700 SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 00701 result = FALSE; 00702 } 00703 } 00704 00705 return result; 00706 } 00707 00708 scpi_bool_t SCPI_ParamCopyText(scpi_t * context, char * buffer, size_t buffer_len, size_t * copy_len, scpi_bool_t mandatory) { 00709 scpi_bool_t result; 00710 scpi_parameter_t param; 00711 size_t i_from; 00712 size_t i_to; 00713 char quote; 00714 00715 if (!buffer || !copy_len) { 00716 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00717 return FALSE; 00718 } 00719 00720 result = SCPI_Parameter(context, ¶m, mandatory); 00721 if (result) { 00722 00723 switch (param.type) { 00724 case SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA: 00725 case SCPI_TOKEN_DOUBLE_QUOTE_PROGRAM_DATA: 00726 quote = param.type == SCPI_TOKEN_SINGLE_QUOTE_PROGRAM_DATA ? '\'' : '"'; 00727 for (i_from = 0, i_to = 0; i_from < (size_t) param.len; i_from++) { 00728 if (i_from >= buffer_len) { 00729 break; 00730 } 00731 buffer[i_to] = param.ptr[i_from]; 00732 i_to++; 00733 if (param.ptr[i_from] == quote) { 00734 i_from++; 00735 } 00736 } 00737 break; 00738 default: 00739 SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 00740 result = FALSE; 00741 } 00742 } 00743 00744 return result; 00745 } 00746 00747 /** 00748 * Convert parameter to choice 00749 * @param context 00750 * @param parameter - should be PROGRAM_MNEMONIC 00751 * @param options - NULL terminated list of choices 00752 * @param value - index to options 00753 * @return 00754 */ 00755 scpi_bool_t SCPI_ParamToChoice(scpi_t * context, scpi_parameter_t * parameter, const scpi_choice_def_t * options, int32_t * value) { 00756 size_t res; 00757 scpi_bool_t result = FALSE; 00758 00759 if (!options || !value) { 00760 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00761 return FALSE; 00762 } 00763 00764 if (parameter->type == SCPI_TOKEN_PROGRAM_MNEMONIC) { 00765 for (res = 0; options[res].name; ++res) { 00766 if (matchPattern(options[res].name, strlen(options[res].name), parameter->ptr, parameter->len, NULL)) { 00767 *value = options[res].tag; 00768 result = TRUE; 00769 break; 00770 } 00771 } 00772 00773 if (!result) { 00774 SCPI_ErrorPush(context, SCPI_ERROR_ILLEGAL_PARAMETER_VALUE); 00775 } 00776 } else { 00777 SCPI_ErrorPush(context, SCPI_ERROR_DATA_TYPE_ERROR); 00778 } 00779 00780 return result; 00781 } 00782 00783 /** 00784 * Find tag in choices and returns its first textual representation 00785 * @param options specifications of choices numbers (patterns) 00786 * @param tag numerical representatio of choice 00787 * @param text result text 00788 * @return TRUE if succesfule, else FALSE 00789 */ 00790 scpi_bool_t SCPI_ChoiceToName(const scpi_choice_def_t * options, int32_t tag, const char ** text) { 00791 int i; 00792 00793 for (i = 0; options[i].name != NULL; i++) { 00794 if (options[i].tag == tag) { 00795 *text = options[i].name; 00796 return TRUE; 00797 } 00798 } 00799 00800 return FALSE; 00801 } 00802 00803 /** 00804 * Read BOOL parameter (0,1,ON,OFF) 00805 * @param context 00806 * @param value 00807 * @param mandatory 00808 * @return 00809 */ 00810 scpi_bool_t SCPI_ParamBool(scpi_t * context, scpi_bool_t * value, scpi_bool_t mandatory) { 00811 scpi_bool_t result; 00812 scpi_parameter_t param; 00813 int32_t intval; 00814 00815 scpi_choice_def_t bool_options[] = { 00816 {"OFF", 0}, 00817 {"ON", 1}, 00818 SCPI_CHOICE_LIST_END /* termination of option list */ 00819 }; 00820 00821 if (!value) { 00822 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00823 return FALSE; 00824 } 00825 00826 result = SCPI_Parameter(context, ¶m, mandatory); 00827 00828 if (result) { 00829 if (param.type == SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA) { 00830 SCPI_ParamToInt(context, ¶m, &intval); 00831 *value = intval ? TRUE : FALSE; 00832 } else { 00833 result = SCPI_ParamToChoice(context, ¶m, bool_options, &intval); 00834 if (result) { 00835 *value = intval ? TRUE : FALSE; 00836 } 00837 } 00838 } 00839 00840 return result; 00841 } 00842 00843 /** 00844 * Read value from list of options 00845 * @param context 00846 * @param options 00847 * @param value 00848 * @param mandatory 00849 * @return 00850 */ 00851 scpi_bool_t SCPI_ParamChoice(scpi_t * context, const scpi_choice_def_t * options, int32_t * value, scpi_bool_t mandatory) { 00852 scpi_bool_t result; 00853 scpi_parameter_t param; 00854 00855 if (!options || !value) { 00856 SCPI_ErrorPush(context, SCPI_ERROR_SYSTEM_ERROR); 00857 return FALSE; 00858 } 00859 00860 result = SCPI_Parameter(context, ¶m, mandatory); 00861 if (result) { 00862 result = SCPI_ParamToChoice(context, ¶m, options, value); 00863 } 00864 00865 return result; 00866 } 00867 00868 /** 00869 * Parse one parameter and detect type 00870 * @param state 00871 * @param token 00872 * @return 00873 */ 00874 int scpiParser_parseProgramData(lex_state_t * state, scpi_token_t * token) { 00875 scpi_token_t tmp; 00876 int result = 0; 00877 int wsLen; 00878 int suffixLen; 00879 int realLen = 0; 00880 realLen += scpiLex_WhiteSpace(state, &tmp); 00881 00882 if (result == 0) result = scpiLex_NondecimalNumericData(state, token); 00883 if (result == 0) result = scpiLex_CharacterProgramData(state, token); 00884 if (result == 0) { 00885 result = scpiLex_DecimalNumericProgramData(state, token); 00886 if (result != 0) { 00887 wsLen = scpiLex_WhiteSpace(state, &tmp); 00888 suffixLen = scpiLex_SuffixProgramData(state, &tmp); 00889 if (suffixLen > 0) { 00890 token->len += wsLen + suffixLen; 00891 token->type = SCPI_TOKEN_DECIMAL_NUMERIC_PROGRAM_DATA_WITH_SUFFIX; 00892 result = token->len; 00893 } 00894 } 00895 } 00896 00897 if (result == 0) result = scpiLex_StringProgramData(state, token); 00898 if (result == 0) result = scpiLex_ArbitraryBlockProgramData(state, token); 00899 if (result == 0) result = scpiLex_ProgramExpression(state, token); 00900 00901 realLen += scpiLex_WhiteSpace(state, &tmp); 00902 00903 return result + realLen; 00904 } 00905 00906 /** 00907 * Skip all parameters to correctly detect end of command line. 00908 * @param state 00909 * @param token 00910 * @param numberOfParameters 00911 * @return 00912 */ 00913 int scpiParser_parseAllProgramData(lex_state_t * state, scpi_token_t * token, int * numberOfParameters) { 00914 00915 int result; 00916 scpi_token_t tmp; 00917 int paramCount = 0; 00918 00919 token->len = -1; 00920 token->type = SCPI_TOKEN_ALL_PROGRAM_DATA; 00921 token->ptr = state->pos; 00922 00923 00924 for (result = 1; result != 0; result = scpiLex_Comma(state, &tmp)) { 00925 token->len += result; 00926 00927 if (result == 0) { 00928 token->type = SCPI_TOKEN_UNKNOWN; 00929 token->len = 0; 00930 paramCount = -1; 00931 break; 00932 } 00933 00934 result = scpiParser_parseProgramData(state, &tmp); 00935 if (tmp.type != SCPI_TOKEN_UNKNOWN) { 00936 token->len += result; 00937 } else { 00938 token->type = SCPI_TOKEN_UNKNOWN; 00939 token->len = 0; 00940 paramCount = -1; 00941 break; 00942 } 00943 paramCount++; 00944 } 00945 00946 if (token->len == -1) { 00947 token->len = 0; 00948 } 00949 00950 if (numberOfParameters != NULL) { 00951 *numberOfParameters = paramCount; 00952 } 00953 return token->len; 00954 } 00955 00956 /** 00957 * Skip complete command line - program header and parameters 00958 * @param state 00959 * @param buffer 00960 * @param len 00961 * @return 00962 */ 00963 int scpiParser_detectProgramMessageUnit(scpi_parser_state_t * state, char * buffer, int len) { 00964 lex_state_t lex_state; 00965 scpi_token_t tmp; 00966 int result = 0; 00967 00968 lex_state.buffer = lex_state.pos = buffer; 00969 lex_state.len = len; 00970 state->numberOfParameters = 0; 00971 00972 /* ignore whitespace at the begginig */ 00973 scpiLex_WhiteSpace(&lex_state, &tmp); 00974 00975 if (scpiLex_ProgramHeader(&lex_state, &state->programHeader) >= 0) { 00976 if (scpiLex_WhiteSpace(&lex_state, &tmp) > 0) { 00977 scpiParser_parseAllProgramData(&lex_state, &state->programData, &state->numberOfParameters); 00978 } else { 00979 invalidateToken(&state->programData, lex_state.pos); 00980 } 00981 } else { 00982 invalidateToken(&state->programHeader, lex_state.buffer); 00983 invalidateToken(&state->programData, lex_state.buffer); 00984 } 00985 00986 if (result == 0) result = scpiLex_NewLine(&lex_state, &tmp); 00987 if (result == 0) result = scpiLex_Semicolon(&lex_state, &tmp); 00988 00989 if (!scpiLex_IsEos(&lex_state) && (result == 0)) { 00990 lex_state.pos++; 00991 00992 state->programHeader.len = 1; 00993 state->programHeader.type = SCPI_TOKEN_INVALID; 00994 00995 invalidateToken(&state->programData, lex_state.buffer); 00996 } 00997 00998 if (SCPI_TOKEN_SEMICOLON == tmp.type) { 00999 state->termination = SCPI_MESSAGE_TERMINATION_SEMICOLON; 01000 } else if (SCPI_TOKEN_NL == tmp.type) { 01001 state->termination = SCPI_MESSAGE_TERMINATION_NL; 01002 } else { 01003 state->termination = SCPI_MESSAGE_TERMINATION_NONE; 01004 } 01005 01006 return lex_state.pos - lex_state.buffer; 01007 } 01008 01009 /** 01010 * Check current command 01011 * - suitable for one handle to multiple commands 01012 * @param context 01013 * @param cmd 01014 * @return 01015 */ 01016 scpi_bool_t SCPI_IsCmd(scpi_t * context, const char * cmd) { 01017 const char * pattern; 01018 01019 if (!context->param_list.cmd) { 01020 return FALSE; 01021 } 01022 01023 pattern = context->param_list.cmd->pattern; 01024 return matchCommand (pattern, cmd, strlen (cmd), NULL, 0); 01025 } 01026 01027 /** 01028 * Return the .tag field of the matching scpi_command_t 01029 * @param context 01030 * @return 01031 */ 01032 int32_t SCPI_CmdTag(scpi_t * context) { 01033 if (context->param_list.cmd) { 01034 return context->param_list.cmd->tag; 01035 } else { 01036 return 0; 01037 } 01038 } 01039 01040 scpi_bool_t SCPI_Match(const char * pattern, const char * value, size_t len) { 01041 return matchCommand (pattern, value, len, NULL, 0); 01042 } 01043 01044 scpi_bool_t SCPI_CommandNumbers(scpi_t * context, int32_t * numbers, size_t len) { 01045 return matchCommand (context->param_list.cmd->pattern, context->param_list.cmd_raw.data, context->param_list.cmd_raw.length, numbers, len); 01046 }
Generated on Tue Jul 12 2022 19:30:15 by 1.7.2