aboutsummaryrefslogtreecommitdiff
path: root/saga/expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'saga/expr.cpp')
-rw-r--r--saga/expr.cpp464
1 files changed, 464 insertions, 0 deletions
diff --git a/saga/expr.cpp b/saga/expr.cpp
new file mode 100644
index 0000000000..32aca92b7f
--- /dev/null
+++ b/saga/expr.cpp
@@ -0,0 +1,464 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+/*
+ Description:
+
+ Expression parsing module, and string handling functions
+
+ Notes:
+
+ EXPR_ParseArgs() lifted wholesale from SDL win32 initialization code by
+ Sam Lantinga
+*/
+
+#include "reinherit.h"
+
+/*
+ Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+
+/*
+ Begin module
+\*--------------------------------------------------------------------------*/
+#include "expr.h"
+
+namespace Saga {
+
+char *EXPR_ErrMsg[] = {
+
+ "Invalid error state.",
+ "No Error",
+ "Memory allocation failed",
+ "Illegal variable name",
+ "Expected \'=\' or \'(\' in expression",
+ "Expected \'(\' in function call",
+ "Illegal \'(\', identifier is not function",
+ "Expected a value to assign",
+ "Unterminated string literal",
+ "Unmatched parenthesis in function call",
+ "Error reading value string",
+ "Expected a number or boolean",
+ "Unknown variable or function"
+};
+
+enum EXPR_Errors {
+
+ EXERR_ASSERT,
+ EXERR_NONE,
+ EXERR_MEM,
+ EXERR_ILLEGAL,
+ EXERR_EXPR,
+ EXERR_FUNC,
+ EXERR_NOTFUNC,
+ EXERR_RVALUE,
+ EXERR_LITERAL,
+ EXERR_PAREN,
+ EXERR_STRING,
+ EXERR_NUMBER,
+ EXERR_NOTFOUND
+};
+
+static enum EXPR_Errors EXPR_ErrorState;
+
+int EXPR_GetError(char **err_str)
+/*--------------------------------------------------------------------------*\
+ Returns the appropriate expression parser error string given an error code.
+\*--------------------------------------------------------------------------*/
+{
+
+ *err_str = EXPR_ErrMsg[EXPR_ErrorState];
+
+ return EXPR_ErrorState;
+}
+
+int
+EXPR_Parse(const char **exp_pp, int *len, R_CVAR_P * expr_cvar, char **rvalue)
+/*--------------------------------------------------------------------------*\
+ Parses an interactive expression.
+ Sets 'expr_cvar' to the cvar/cfunction identifier input by the user, and
+ 'rvalue' to the corresponding rvalue ( in an expression ) or argument string
+ ( in a function call ).
+
+ Memory pointed to by rvalue after return must be explicitly freed by the
+ caller.
+\*--------------------------------------------------------------------------*/
+{
+
+ int i;
+ int in_char;
+ int equ_offset;
+ int rvalue_offset;
+
+ char *lvalue_str;
+ int lvalue_len;
+
+ char *rvalue_str;
+ int rvalue_len;
+
+ const char *scan_p;
+ int scan_len;
+
+ const char *expr_p;
+ int expr_len;
+ int test_char = '\0';
+ int have_func = 0;
+
+ R_CVAR_P lvalue_cvar;
+
+ expr_p = *exp_pp;
+ expr_len = strlen(*exp_pp);
+
+ scan_p = *exp_pp;
+ scan_len = expr_len;
+
+ /**lvalue = NULL;*/
+ *rvalue = NULL;
+
+ EXPR_ErrorState = EXERR_ASSERT;
+
+ for (i = 0; i <= scan_len; i++, scan_p++) {
+
+ in_char = *scan_p;
+
+ if ((i == 0) && isdigit(in_char)) {
+ /* First character of a valid identifier cannot be a digit */
+ EXPR_ErrorState = EXERR_ILLEGAL;
+ return R_FAILURE;
+ }
+
+ /* If we reach a character that isn't valid in an identifier... */
+ if ((!isalnum(in_char)) && ((in_char != '_'))) {
+
+ /* then eat remaining whitespace, if any */
+ equ_offset = strspn(scan_p, R_EXPR_WHITESPACE);
+
+ test_char = scan_p[equ_offset];
+ /* and test for the only valid characters after an identifier */
+ if ((test_char != '=') &&
+ (test_char != '\0') && (test_char != '(')) {
+
+ if ((equ_offset == 0)
+ && ((scan_p - expr_p) != expr_len)) {
+ EXPR_ErrorState = EXERR_ILLEGAL;
+ } else {
+ EXPR_ErrorState = EXERR_EXPR;
+ }
+ return R_FAILURE;
+ }
+
+ break;
+ }
+ }
+
+ lvalue_len = (scan_p - expr_p);
+ lvalue_str = (char *)malloc(lvalue_len + 1);
+
+ if (lvalue_str == NULL) {
+ EXPR_ErrorState = EXERR_MEM;
+ return R_FAILURE;
+ }
+
+ strncpy(lvalue_str, expr_p, lvalue_len);
+ lvalue_str[lvalue_len] = 0;
+
+ /* We now have the lvalue, so attempt to find it */
+ lvalue_cvar = CVAR_Find(lvalue_str);
+ if (lvalue_cvar == NULL) {
+ EXPR_ErrorState = EXERR_NOTFOUND;
+ return R_FAILURE;
+ }
+ if (lvalue_str) {
+ free(lvalue_str);
+ lvalue_str = NULL;
+ }
+
+ /* Skip parsed character, if any */
+ scan_p += equ_offset + 1;
+ scan_len = (scan_p - expr_p);
+
+ /* Check if the 'cvar' is really a function */
+ have_func = CVAR_IsFunc(lvalue_cvar);
+
+ if (test_char == '(') {
+
+ if (have_func) {
+
+ rvalue_str =
+ EXPR_ReadString(&scan_p, &rvalue_len, ')');
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ /*CON_Print( "Read function parameters \"%s\".", rvalue_str ); */
+ *expr_cvar = lvalue_cvar;
+ *rvalue = rvalue_str;
+
+ scan_len = (scan_p - expr_p);
+
+ *exp_pp = scan_p;
+ *len -= scan_len;
+
+ EXPR_ErrorState = EXERR_NONE;
+ return R_SUCCESS;
+ } else {
+ EXPR_ErrorState = EXERR_PAREN;
+ return R_FAILURE;
+ }
+ } else {
+ EXPR_ErrorState = EXERR_NOTFUNC;
+ return R_FAILURE;
+ }
+
+ }
+
+ /* Eat more whitespace */
+ rvalue_offset = strspn(scan_p, R_EXPR_WHITESPACE);
+
+ if (rvalue_offset + i == expr_len) {
+ /* Only found single lvalue */
+ *expr_cvar = lvalue_cvar;
+ *exp_pp = scan_p;
+ *len -= scan_len;
+ return R_SUCCESS;
+ }
+
+ scan_p += rvalue_offset;
+ scan_len = (scan_p - expr_p) + 1;
+
+ in_char = *scan_p;
+
+ in_char = toupper(in_char);
+
+ switch (in_char) {
+
+ case '\"':
+ scan_p++;
+ scan_len--;
+ rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, '\"');
+
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ break;
+ } else {
+ EXPR_ErrorState = EXERR_LITERAL;
+ return R_FAILURE;
+ }
+ break;
+
+#if 0
+ case 'Y': /* Y[es] */
+ case 'T': /* T[rue] */
+
+ break;
+
+ case 'N': /* N[o] */
+ case 'F': /* F[alse] */
+
+ break;
+#endif
+
+ default:
+
+ if (isdigit(in_char) || (in_char == '-') || (in_char == '+')) {
+
+ rvalue_str = EXPR_ReadString(&scan_p, &rvalue_len, 0);
+
+ if (rvalue_str != NULL) {
+ /* Successfully read string */
+ break;
+ } else {
+ EXPR_ErrorState = EXERR_STRING;
+ return R_FAILURE;
+ }
+ } else {
+ EXPR_ErrorState = EXERR_NUMBER;
+ return R_FAILURE;
+ }
+
+ break;
+
+ }
+
+ *expr_cvar = lvalue_cvar;
+ *rvalue = rvalue_str;
+
+ scan_len = (scan_p - expr_p);
+
+ *exp_pp = scan_p;
+ *len -= scan_len;
+
+ EXPR_ErrorState = EXERR_NONE;
+ return R_SUCCESS;
+
+}
+
+char *EXPR_ReadString(const char **string_p, int *len, int term_char)
+/****************************************************************************\
+ Reads in a string of characters from '*string_p' until 'term_char' is
+ encountered. If 'term_char' == 0, the function reads characters until
+ whitespace is encountered.
+ Upon reading a string, the function modifies *string_p and len based on
+ the number of characters read.
+\****************************************************************************/
+{
+
+ int string_len;
+ char *str_p;
+ char *term_p;
+
+ const char *scan_p;
+ int in_char;
+
+ if (term_char > 0) {
+
+ term_p = strchr(*string_p, term_char);
+
+ if (term_p == NULL) {
+ return NULL;
+ }
+
+ string_len = (int)(term_p - *string_p);
+
+ str_p = (char *)malloc(string_len + 1);
+
+ if (str_p == NULL) {
+ return NULL;
+ }
+
+ strncpy(str_p, *string_p, string_len);
+ str_p[string_len] = 0;
+
+ *string_p += (string_len + 1); /* Add 1 for terminating char */
+ *len -= (string_len + 1);
+
+ } else {
+
+ scan_p = *string_p;
+ string_len = 0;
+
+ while (scan_p) {
+
+ in_char = *scan_p++;
+
+ if (!isspace(in_char)) {
+ string_len++;
+ } else if (string_len) {
+
+ str_p = (char *)malloc(string_len + 1);
+
+ if (str_p == NULL) {
+ return NULL;
+ }
+
+ strncpy(str_p, *string_p, string_len);
+ str_p[string_len] = 0;
+
+ *string_p += string_len;
+ *len -= string_len;
+ break;
+
+ } else {
+ return NULL;
+ }
+ }
+
+ }
+
+ return str_p;
+}
+
+int EXPR_GetArgs(char *cmd_str, char ***expr_argv)
+/****************************************************************************\
+ Parses the string 'cmd_str' into argc/argv format, returning argc.
+ The resulting argv pointers point into the 'cmd_str' string, so any argv
+ entries should not be used after cmd_str is deallocated.
+
+ Memory pointed to by expr_argv must be explicitly freed by the caller.
+\****************************************************************************/
+{
+
+ int expr_argc;
+
+ expr_argc = EXPR_ParseArgs(cmd_str, NULL);
+ *expr_argv = (char **)malloc((expr_argc + 1) * sizeof(**expr_argv));
+
+ if (expr_argv == NULL) {
+ return R_FAILURE;
+ }
+
+ EXPR_ParseArgs(cmd_str, *expr_argv);
+
+ return expr_argc;
+
+}
+
+int EXPR_ParseArgs(char *cmd_str, char **argv)
+{
+
+ char *bufp;
+ int argc;
+
+ argc = 0;
+ for (bufp = cmd_str; *bufp;) {
+ /* Skip leading whitespace */
+ while (isspace(*bufp)) {
+ ++bufp;
+ }
+ /* Skip over argument */
+ if (*bufp == '"') {
+ ++bufp;
+ if (*bufp) {
+ if (argv) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while (*bufp && (*bufp != '"')) {
+ ++bufp;
+ }
+ } else {
+ if (*bufp) {
+ if (argv) {
+ argv[argc] = bufp;
+ }
+ ++argc;
+ }
+ /* Skip over word */
+ while (*bufp && !isspace(*bufp)) {
+ ++bufp;
+ }
+ }
+ if (*bufp) {
+ if (argv) {
+ *bufp = '\0';
+ }
+ ++bufp;
+ }
+ }
+ if (argv) {
+ argv[argc] = NULL;
+ }
+ return (argc);
+}
+
+} // End of namespace Saga