yaubil.c
changeset 0 7707b26e82fd
child 1 320e4393785a
equal deleted inserted replaced
-1:000000000000 0:7707b26e82fd
       
     1 /*
       
     2  * yaubil.c             -- Yet Another Useless Built-In Language
       
     3  *
       
     4  * Copyrigth (C) 2009      Myhailo Danylenko <isbear@ukrpost.net>
       
     5  *
       
     6  * This program is free software; you can redistribute it and/or modify
       
     7  * it under the terms of the GNU General Public License as published by
       
     8  * the Free Software Foundation; either version 2 of the License, or (at
       
     9  * your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but
       
    12  * WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14  * General Public License for more details.
       
    15  *
       
    16  * You should have received a copy of the GNU General Public License
       
    17  * along with this program; if not, write to the Free Software
       
    18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
       
    19  * USA
       
    20  */
       
    21 
       
    22 #include <glib.h>
       
    23 #include <gmodule.h>
       
    24 #include <string.h>
       
    25 
       
    26 #include "commands.h"
       
    27 #include "compl.h"
       
    28 #include "logprint.h"
       
    29 #include "settings.h"
       
    30 
       
    31 static gboolean ifresult = TRUE;
       
    32 
       
    33 #define MSGPREFIX "yaubil: "
       
    34 
       
    35 #define TYPE_UNDEF ( 0 )
       
    36 #define TYPE_STR   ( 1 )
       
    37 #define TYPE_INT   ( 2 )
       
    38 
       
    39 #define STATE_LVALUE ( 1 )
       
    40 #define STATE_OP     ( 2 )
       
    41 #define STATE_RVALUE ( 3 )
       
    42 
       
    43 typedef struct {
       
    44 	int   type;
       
    45 	int   int_value;
       
    46 	char *str_value;
       
    47 } value_t;
       
    48 
       
    49 typedef struct {
       
    50 	char op;
       
    51 	gboolean (*handler) (value_t *l, value_t *r);
       
    52 } op_t;
       
    53 
       
    54 static int check_value_type (const char *value)
       
    55 {
       
    56 	if (value) {
       
    57 		const char *e;
       
    58 		gboolean    integer = (*value == '-') ? FALSE : (g_ascii_isdigit (*value) ? TRUE : FALSE);
       
    59 
       
    60 		if (integer) {
       
    61 			for (e = value + 1; *e; ++e) {
       
    62 				if (g_ascii_isdigit (*e))
       
    63 					integer = TRUE;
       
    64 				else {
       
    65 					integer = FALSE;
       
    66 					break;
       
    67 				}
       
    68 			}
       
    69 		}
       
    70 
       
    71 		if (integer)
       
    72 			return TYPE_INT;
       
    73 		else
       
    74 			return TYPE_STR;
       
    75 	} else
       
    76 		return TYPE_UNDEF;
       
    77 }
       
    78 
       
    79 static gboolean op_concat (value_t *l, value_t *r)
       
    80 {
       
    81 	GString *res = g_string_new (NULL);;
       
    82 
       
    83 	if (l->type == TYPE_INT)
       
    84 		g_string_append_printf (res, "%d", l->int_value);
       
    85 	else if (l->type == TYPE_STR)
       
    86 		g_string_append (res, l->str_value);
       
    87 
       
    88 	if (r->type == TYPE_INT)
       
    89 		g_string_append_printf (res, "%d", r->int_value);
       
    90 	else if (r->type == TYPE_STR)
       
    91 		g_string_append (res, r->str_value);
       
    92 	
       
    93 	l->type = TYPE_STR;
       
    94 	g_free (l->str_value);
       
    95 	l->str_value = g_string_free (res, FALSE);
       
    96 
       
    97 	return TRUE;
       
    98 }
       
    99 
       
   100 static gboolean op_plus (value_t *l, value_t *r)
       
   101 {
       
   102 	if (l->type == TYPE_UNDEF) {
       
   103 		l->type      = TYPE_INT;
       
   104 		l->int_value = 0;
       
   105 	}
       
   106 	if (r->type == TYPE_UNDEF) {
       
   107 		r->type      = TYPE_INT;
       
   108 		r->int_value = 0;
       
   109 	}
       
   110 	
       
   111 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   112 		l->type      = TYPE_INT;
       
   113 		l->int_value = atoi (l->str_value);
       
   114 		// not free value here
       
   115 	}
       
   116 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   117 		r->type      = TYPE_INT;
       
   118 		r->int_value = atoi (r->str_value);
       
   119 		// not free value here
       
   120 	}
       
   121 
       
   122 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   123 		// integer
       
   124 		l->int_value += r->int_value;
       
   125 		g_free (l->str_value);
       
   126 		l->str_value = NULL;
       
   127 		g_free (r->str_value);
       
   128 		r->str_value = NULL;
       
   129 	} else {
       
   130 		// convert both to strings
       
   131 		if (l->type == TYPE_INT) {
       
   132 			l->type = TYPE_STR;
       
   133 			if (!l->str_value)
       
   134 				l->str_value = g_strdup_printf ("%d", l->int_value);
       
   135 		}
       
   136 		if (r->type == TYPE_INT) {
       
   137 			r->type = TYPE_STR;
       
   138 			if (!r->str_value)
       
   139 				r->str_value = g_strdup_printf ("%d", r->int_value);
       
   140 		}
       
   141 
       
   142 		{
       
   143 			char *tmp = l->str_value;
       
   144 			l->str_value = g_strdup_printf ("%s%s", tmp, r->str_value);
       
   145 			g_free (tmp);
       
   146 		}
       
   147 	}
       
   148 
       
   149 	return TRUE;
       
   150 }
       
   151 
       
   152 static gboolean op_minus (value_t *l, value_t *r)
       
   153 {
       
   154 	if (l->type == TYPE_UNDEF) {
       
   155 		l->type      = TYPE_INT;
       
   156 		l->int_value = 0;
       
   157 	}
       
   158 	if (r->type == TYPE_UNDEF) {
       
   159 		r->type      = TYPE_INT;
       
   160 		r->int_value = 0;
       
   161 	}
       
   162 	
       
   163 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   164 		l->type      = TYPE_INT;
       
   165 		l->int_value = atoi (l->str_value);
       
   166 		g_free (l->str_value);
       
   167 		l->str_value = NULL;
       
   168 	}
       
   169 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   170 		r->type      = TYPE_INT;
       
   171 		r->int_value = atoi (r->str_value);
       
   172 		g_free (r->str_value);
       
   173 		r->str_value = NULL;
       
   174 	}
       
   175 
       
   176 	if (l->type == TYPE_INT && r->type == TYPE_INT)
       
   177 		l->int_value -= r->int_value;
       
   178 	else
       
   179 		return FALSE;
       
   180 
       
   181 	return TRUE;
       
   182 }
       
   183 
       
   184 static gboolean op_multiply (value_t *l, value_t *r)
       
   185 {
       
   186 	if (l->type == TYPE_UNDEF) {
       
   187 		l->type      = TYPE_INT;
       
   188 		l->int_value = 0;
       
   189 	}
       
   190 	if (r->type == TYPE_UNDEF) {
       
   191 		r->type      = TYPE_INT;
       
   192 		r->int_value = 0;
       
   193 	}
       
   194 	
       
   195 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   196 		l->type      = TYPE_INT;
       
   197 		l->int_value = atoi (l->str_value);
       
   198 		// not free value here
       
   199 	}
       
   200 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   201 		r->type      = TYPE_INT;
       
   202 		r->int_value = atoi (r->str_value);
       
   203 		g_free (r->str_value);
       
   204 		r->str_value = NULL;
       
   205 	}
       
   206 
       
   207 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   208 		l->int_value *= r->int_value;
       
   209 		g_free (l->str_value);
       
   210 		l->str_value = NULL;
       
   211 	} else if (r->type == TYPE_INT) {
       
   212 		GString *res = g_string_new (NULL);
       
   213 		int      i;
       
   214 		for (i = r->int_value; i; --i)
       
   215 			g_string_append (res, l->str_value);
       
   216 		g_free (l->str_value);
       
   217 		l->str_value = g_string_free (res, FALSE);
       
   218 	} else
       
   219 		return FALSE;
       
   220 
       
   221 	return TRUE;
       
   222 }
       
   223 
       
   224 static gboolean op_divide (value_t *l, value_t *r)
       
   225 {
       
   226 	if (l->type == TYPE_UNDEF) {
       
   227 		l->type      = TYPE_INT;
       
   228 		l->int_value = 0;
       
   229 	}
       
   230 	if (r->type == TYPE_UNDEF) {
       
   231 		r->type      = TYPE_INT;
       
   232 		r->int_value = 0;
       
   233 	}
       
   234 	
       
   235 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   236 		l->type      = TYPE_INT;
       
   237 		l->int_value = atoi (l->str_value);
       
   238 		g_free (l->str_value);
       
   239 		l->str_value = NULL;
       
   240 	}
       
   241 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   242 		r->type      = TYPE_INT;
       
   243 		r->int_value = atoi (r->str_value);
       
   244 		g_free (r->str_value);
       
   245 		r->str_value = NULL;
       
   246 	}
       
   247 
       
   248 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   249 		if (r->int_value == 0) {
       
   250 			scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "/: Error: division by zero.");
       
   251 			return FALSE;
       
   252 		}
       
   253 		l->int_value /= r->int_value;
       
   254 	} else
       
   255 		return FALSE;
       
   256 
       
   257 	return TRUE;
       
   258 }
       
   259 
       
   260 static gboolean op_remain (value_t *l, value_t *r)
       
   261 {
       
   262 	if (l->type == TYPE_UNDEF) {
       
   263 		l->type      = TYPE_INT;
       
   264 		l->int_value = 0;
       
   265 	}
       
   266 	if (r->type == TYPE_UNDEF) {
       
   267 		r->type      = TYPE_INT;
       
   268 		r->int_value = 0;
       
   269 	}
       
   270 	
       
   271 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   272 		l->type      = TYPE_INT;
       
   273 		l->int_value = atoi (l->str_value);
       
   274 		g_free (l->str_value);
       
   275 		l->str_value = NULL;
       
   276 	}
       
   277 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   278 		r->type      = TYPE_INT;
       
   279 		r->int_value = atoi (r->str_value);
       
   280 		g_free (r->str_value);
       
   281 		r->str_value = NULL;
       
   282 	}
       
   283 
       
   284 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   285 		if (r->int_value == 0) {
       
   286 			scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "%%: Error: division by zero.");
       
   287 			return FALSE;
       
   288 		}
       
   289 		l->int_value %= r->int_value;
       
   290 	} else
       
   291 		return FALSE;
       
   292 
       
   293 	return TRUE;
       
   294 }
       
   295 
       
   296 static gboolean op_equal (value_t *l, value_t *r)
       
   297 {
       
   298 	if (l->type == TYPE_UNDEF) {
       
   299 		l->type      = TYPE_INT;
       
   300 		l->int_value = 0;
       
   301 	}
       
   302 	if (r->type == TYPE_UNDEF) {
       
   303 		r->type      = TYPE_INT;
       
   304 		r->int_value = 0;
       
   305 	}
       
   306 	
       
   307 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   308 		l->type      = TYPE_INT;
       
   309 		l->int_value = atoi (l->str_value);
       
   310 		// not free value here
       
   311 	}
       
   312 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   313 		r->type      = TYPE_INT;
       
   314 		r->int_value = atoi (r->str_value);
       
   315 		// not free value here
       
   316 	}
       
   317 
       
   318 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   319 		// integer
       
   320 		l->int_value = (l->int_value == r->int_value) ? 1 : 0;
       
   321 		g_free (l->str_value);
       
   322 		l->str_value = NULL;
       
   323 		g_free (r->str_value);
       
   324 		r->str_value = NULL;
       
   325 	} else {
       
   326 		// convert both to strings
       
   327 		if (l->type == TYPE_INT) {
       
   328 			l->type = TYPE_STR;
       
   329 			if (!l->str_value)
       
   330 				l->str_value = g_strdup_printf ("%d", l->int_value);
       
   331 		}
       
   332 		if (r->type == TYPE_INT) {
       
   333 			r->type = TYPE_STR;
       
   334 			if (!r->str_value)
       
   335 				r->str_value = g_strdup_printf ("%d", r->int_value);
       
   336 		}
       
   337 
       
   338 		{
       
   339 			char *tmp = l->str_value;
       
   340 			l->type      = TYPE_INT;
       
   341 			l->int_value = (g_strcmp0 (l->str_value, r->str_value) == 0) ? 1 : 0;
       
   342 			g_free (tmp);
       
   343 		}
       
   344 	}
       
   345 
       
   346 	return TRUE;
       
   347 }
       
   348 
       
   349 static gboolean op_lt (value_t *l, value_t *r)
       
   350 {
       
   351 	if (l->type == TYPE_UNDEF) {
       
   352 		l->type      = TYPE_INT;
       
   353 		l->int_value = 0;
       
   354 	}
       
   355 	if (r->type == TYPE_UNDEF) {
       
   356 		r->type      = TYPE_INT;
       
   357 		r->int_value = 0;
       
   358 	}
       
   359 	
       
   360 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   361 		l->type      = TYPE_INT;
       
   362 		l->int_value = atoi (l->str_value);
       
   363 		// not free value here
       
   364 	}
       
   365 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   366 		r->type      = TYPE_INT;
       
   367 		r->int_value = atoi (r->str_value);
       
   368 		// not free value here
       
   369 	}
       
   370 
       
   371 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   372 		// integer
       
   373 		l->int_value = (l->int_value < r->int_value) ? 1 : 0;
       
   374 		g_free (l->str_value);
       
   375 		l->str_value = NULL;
       
   376 		g_free (r->str_value);
       
   377 		r->str_value = NULL;
       
   378 	} else {
       
   379 		// convert both to strings
       
   380 		if (l->type == TYPE_INT) {
       
   381 			l->type = TYPE_STR;
       
   382 			if (!l->str_value)
       
   383 				l->str_value = g_strdup_printf ("%d", l->int_value);
       
   384 		}
       
   385 		if (r->type == TYPE_INT) {
       
   386 			r->type = TYPE_STR;
       
   387 			if (!r->str_value)
       
   388 				r->str_value = g_strdup_printf ("%d", r->int_value);
       
   389 		}
       
   390 
       
   391 		{
       
   392 			char *tmp = l->str_value;
       
   393 			l->type      = TYPE_INT;
       
   394 			l->int_value = (g_strcmp0 (l->str_value, r->str_value) < 0) ? 1 : 0;
       
   395 			g_free (tmp);
       
   396 		}
       
   397 	}
       
   398 
       
   399 	return TRUE;
       
   400 }
       
   401 
       
   402 static gboolean op_gt (value_t *l, value_t *r)
       
   403 {
       
   404 	if (l->type == TYPE_UNDEF) {
       
   405 		l->type      = TYPE_INT;
       
   406 		l->int_value = 0;
       
   407 	}
       
   408 	if (r->type == TYPE_UNDEF) {
       
   409 		r->type      = TYPE_INT;
       
   410 		r->int_value = 0;
       
   411 	}
       
   412 	
       
   413 	if (l->type == TYPE_STR && check_value_type (l->str_value) == TYPE_INT) {
       
   414 		l->type      = TYPE_INT;
       
   415 		l->int_value = atoi (l->str_value);
       
   416 		// not free value here
       
   417 	}
       
   418 	if (r->type == TYPE_STR && check_value_type (r->str_value) == TYPE_INT) {
       
   419 		r->type      = TYPE_INT;
       
   420 		r->int_value = atoi (r->str_value);
       
   421 		// not free value here
       
   422 	}
       
   423 
       
   424 	if (l->type == TYPE_INT && r->type == TYPE_INT) {
       
   425 		// integer
       
   426 		l->int_value = (l->int_value > r->int_value) ? 1 : 0;
       
   427 		g_free (l->str_value);
       
   428 		l->str_value = NULL;
       
   429 		g_free (r->str_value);
       
   430 		r->str_value = NULL;
       
   431 	} else {
       
   432 		// convert both to strings
       
   433 		if (l->type == TYPE_INT) {
       
   434 			l->type = TYPE_STR;
       
   435 			if (!l->str_value)
       
   436 				l->str_value = g_strdup_printf ("%d", l->int_value);
       
   437 		}
       
   438 		if (r->type == TYPE_INT) {
       
   439 			r->type = TYPE_STR;
       
   440 			if (!r->str_value)
       
   441 				r->str_value = g_strdup_printf ("%d", r->int_value);
       
   442 		}
       
   443 
       
   444 		{
       
   445 			char *tmp = l->str_value;
       
   446 			l->type      = TYPE_INT;
       
   447 			l->int_value = (g_strcmp0 (l->str_value, r->str_value) > 0) ? 1 : 0;
       
   448 			g_free (tmp);
       
   449 		}
       
   450 	}
       
   451 
       
   452 	return TRUE;
       
   453 }
       
   454 
       
   455 static op_t operators[] = {
       
   456 	{ '.', op_concat   },
       
   457 	{ '+', op_plus     },
       
   458 	{ '-', op_minus    },
       
   459 	{ '*', op_multiply },
       
   460 	{ '/', op_divide   },
       
   461 	{ '%', op_remain   },
       
   462 	{ '=', op_equal    },
       
   463 	{ '<', op_lt       },
       
   464 	{ '>', op_gt       },
       
   465 	{ 0,   NULL        },
       
   466 };
       
   467 
       
   468 static void destroy_value (value_t *value)
       
   469 {
       
   470 	if (value->str_value)
       
   471 		g_free (value->str_value);
       
   472 	g_free (value);
       
   473 }
       
   474 
       
   475 static value_t *process_expression (const char *str, gsize len)
       
   476 {
       
   477 	const char *strend = str + len;
       
   478 	const char *p;
       
   479 	op_t       *op     = NULL;
       
   480 	int         state  = STATE_LVALUE;
       
   481 	value_t     val    = {
       
   482 		.type      = TYPE_UNDEF,
       
   483 		.int_value = 0,
       
   484 		.str_value = NULL,
       
   485 	};
       
   486 
       
   487 	for (p = str; *p && p < strend; ++p) {
       
   488 		switch (state) {
       
   489 		case STATE_LVALUE:
       
   490 		case STATE_RVALUE:
       
   491 
       
   492 			if (*p == ' ')
       
   493 				break;
       
   494 
       
   495 			{
       
   496 				value_t rval = {
       
   497 					.type      = TYPE_UNDEF,
       
   498 					.int_value = 0,
       
   499 					.str_value = NULL,
       
   500 				};
       
   501 
       
   502 				if (g_ascii_isdigit (*p) || *p == '-') { // integer // XXX: no unary operators for now...
       
   503 
       
   504 					const char *e;
       
   505 
       
   506 					rval.type = TYPE_INT;
       
   507 
       
   508 					for (e = p + 1; g_ascii_isdigit (*e) && e < strend; ++e); // TODO: does atoi handle 0x etc? then also allow this?
       
   509 					
       
   510 					{
       
   511 						char *v = g_strndup (p, e - p);
       
   512 						rval.int_value = atoi (v);
       
   513 						g_free (v);
       
   514 					}
       
   515 
       
   516 					p = e - 1;
       
   517 
       
   518 				} else if (*p == '"') { // string
       
   519 
       
   520 					const char *e;
       
   521 
       
   522 					rval.type = TYPE_STR;
       
   523 
       
   524 					{
       
   525 						gboolean  finished = FALSE;
       
   526 						gboolean  escape   = FALSE;
       
   527 						GString  *v        = g_string_new (NULL);
       
   528 
       
   529 						for (e = p + 1; *e && e < strend; ++e) {
       
   530 							switch (*e) {
       
   531 							case '\\':
       
   532 								if (!escape)
       
   533 									escape = TRUE;
       
   534 								else
       
   535 									escape = FALSE;
       
   536 								break;
       
   537 							case '"':
       
   538 								if (!escape) {
       
   539 									finished = TRUE;
       
   540 									break;
       
   541 								} else
       
   542 									escape = FALSE;
       
   543 								break;
       
   544 							default:
       
   545 								escape = FALSE;
       
   546 								break;
       
   547 							}
       
   548 
       
   549 							if (finished)
       
   550 								break;
       
   551 
       
   552 							if (!escape)
       
   553 								g_string_append_c (v, *e);
       
   554 						};
       
   555 
       
   556 						if (!finished) {
       
   557 							scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: Unmatched quote.");
       
   558 							g_string_free (v, TRUE);
       
   559 							g_free (val.str_value);
       
   560 							return NULL;
       
   561 						}
       
   562 
       
   563 						rval.str_value = g_string_free (v, FALSE);
       
   564 					}
       
   565 
       
   566 					p = e;
       
   567 
       
   568 				} else if (g_ascii_isalpha (*p)) { // variable (MUST start from alpha)
       
   569 
       
   570 					const char *e;
       
   571 
       
   572 					for (e = p + 1; (g_ascii_isalnum (*e) || *e == '-' || *e == '_') && e < strend; ++e);
       
   573 
       
   574 					char       *name = g_strndup (p, e - p);
       
   575 					const char *value = settings_opt_get (name);
       
   576 					g_free (name);
       
   577 
       
   578 					rval.type = check_value_type (value);
       
   579 					if (rval.type == TYPE_INT)
       
   580 						rval.int_value = atoi (value);
       
   581 					else if (rval.type == TYPE_STR)
       
   582 						rval.str_value = g_strdup (value);
       
   583 
       
   584 					p = e - 1;
       
   585 
       
   586 				} else if (*p == '(') {
       
   587 					
       
   588 					const char *e;
       
   589 
       
   590 					{
       
   591 						int      l        = 0;
       
   592 						gboolean finished = FALSE;
       
   593 						
       
   594 						// XXX maybe we should just pass end of line and let it return real length...
       
   595 						for (e = p + 1; e < strend; ++e) {
       
   596 							if (*e == '(')
       
   597 								++l;
       
   598 							else if (*e == ')') {
       
   599 								--l;
       
   600 								if (l < 0) {
       
   601 									finished = TRUE;
       
   602 									break;
       
   603 								}
       
   604 							}
       
   605 						}
       
   606 
       
   607 						if (!finished) {
       
   608 							scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: Unmatched parenthesis.");
       
   609 							g_free (val.str_value);
       
   610 							return NULL;
       
   611 						}
       
   612 					}
       
   613 
       
   614 					{
       
   615 						value_t *n = process_expression (p + 1, e - p - 1);
       
   616 						
       
   617 						if (!n) {
       
   618 							scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: Error in subexpression.");
       
   619 							g_free (val.str_value);
       
   620 							return NULL;
       
   621 						}
       
   622 
       
   623 						rval.type      = n->type;
       
   624 						rval.int_value = n->int_value;
       
   625 						rval.str_value = g_strdup (n->str_value);
       
   626 						destroy_value (n);
       
   627 					}
       
   628 
       
   629 					p = e;
       
   630 
       
   631 				} else {
       
   632 					scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: unrecognized symbols.");
       
   633 					g_free (val.str_value);
       
   634 					return NULL;
       
   635 				}
       
   636 
       
   637 				if (state == STATE_RVALUE) {
       
   638 					if (op->handler) {
       
   639 						if (!op->handler (&val, &rval)) {
       
   640 							scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: operand argument types mismatch.");
       
   641 							g_free (val.str_value);
       
   642 							g_free (rval.str_value);
       
   643 							return NULL;
       
   644 						}
       
   645 					}
       
   646 					g_free (rval.str_value);
       
   647 				} else {
       
   648 					val.type      = rval.type;
       
   649 					val.int_value = rval.int_value;
       
   650 					val.str_value = rval.str_value;
       
   651 				}
       
   652 				
       
   653 				state = STATE_OP;
       
   654 			}
       
   655 
       
   656 			break;
       
   657 
       
   658 		case STATE_OP:
       
   659 
       
   660 			if (*p == ' ')
       
   661 				break;
       
   662 
       
   663 			{
       
   664 				op_t     *operator;
       
   665 				gboolean  found    = FALSE;
       
   666 
       
   667 				for (operator = operators; operator->op; ++operator) {
       
   668 					if (operator->op == *p) {
       
   669 						op    = operator;
       
   670 						found = TRUE;
       
   671 						break;
       
   672 					}
       
   673 				}
       
   674 
       
   675 				if (!found) {
       
   676 					scr_LogPrint (LPRINT_NORMAL, MSGPREFIX "Error: unknown operator.");
       
   677 					g_free (val.str_value);
       
   678 				}
       
   679 			}
       
   680 
       
   681 			state = STATE_RVALUE;
       
   682 
       
   683 			break;
       
   684 		default:
       
   685 			break;
       
   686 		}
       
   687 	}
       
   688 
       
   689 	{ // return value
       
   690 		value_t *rval = g_new (value_t, 1);
       
   691 
       
   692 		rval->type      = val.type;
       
   693 		rval->int_value = val.int_value;
       
   694 		rval->str_value = val.str_value;
       
   695 
       
   696 		return rval;
       
   697 	}
       
   698 }
       
   699 
       
   700 static void do_eval (char *arg)
       
   701 {
       
   702 	value_t *val = process_expression (arg, strlen (arg));
       
   703 
       
   704 	if (!val) {
       
   705 		scr_LogPrint (LPRINT_NORMAL, "eval: Evaluation error.");
       
   706 		return;
       
   707 	}
       
   708 
       
   709 	if (val->type == TYPE_STR)
       
   710 		process_command (val->str_value, TRUE);
       
   711 	else
       
   712 		scr_LogPrint (LPRINT_NORMAL, "eval: Expression does not result in string.");
       
   713 
       
   714 	destroy_value (val);
       
   715 }
       
   716 
       
   717 static void do_let (char *arg)
       
   718 {
       
   719 	char     *varname;
       
   720 	value_t  *value;
       
   721 	int       namelen;
       
   722 	char     *val     = strchr (arg, '=');
       
   723 
       
   724 	if (!val) {
       
   725 		scr_LogPrint (LPRINT_NORMAL, "let: Syntax error: no equal sign in line.");
       
   726 		return;
       
   727 	}
       
   728 	
       
   729 	{
       
   730 		char *p = val;
       
   731 
       
   732 		for (p = val - 1; p >= arg && *p == ' '; --p);
       
   733 		if (p < arg) {
       
   734 			scr_LogPrint (LPRINT_NORMAL, "let: Syntax error: no destination variable name specified.");
       
   735 			return;
       
   736 		}
       
   737 
       
   738 		namelen = p + 1 - arg;
       
   739 	}
       
   740 
       
   741 	// evaluate expression
       
   742 	value = process_expression (val + 1, strlen (val + 1));
       
   743 
       
   744 	if (!value) {
       
   745 		scr_LogPrint (LPRINT_NORMAL, "let: Evaluation error.");
       
   746 		return;
       
   747 	}
       
   748 
       
   749 	if (value->type == TYPE_INT) {
       
   750 		value->type      = TYPE_STR;
       
   751 		value->str_value = g_strdup_printf ("%d", value->int_value);
       
   752 	}
       
   753 
       
   754 	{ // assign value
       
   755 		char *varname = g_strndup (arg, namelen);
       
   756 
       
   757 		if (value->str_value)
       
   758 			settings_set (SETTINGS_TYPE_OPTION, varname, value->str_value);
       
   759 		else
       
   760 			settings_del (SETTINGS_TYPE_OPTION, varname);
       
   761 
       
   762 		g_free (varname);
       
   763 	}
       
   764 
       
   765 	destroy_value (value);
       
   766 }
       
   767 
       
   768 static void do_if (char *arg)
       
   769 {
       
   770 	value_t *val = process_expression (arg, strlen (arg));
       
   771 
       
   772 	if (!val) {
       
   773 		scr_LogPrint (LPRINT_NORMAL, "if: Evaluation error.");
       
   774 		return;
       
   775 	}
       
   776 
       
   777 	if (val->type == TYPE_UNDEF) {
       
   778 		val->type = TYPE_INT;
       
   779 		val->int_value = 0;
       
   780 	}
       
   781 	if (val->type == TYPE_STR && check_value_type (val->str_value) == TYPE_INT) {
       
   782 		val->type = TYPE_INT;
       
   783 		val->int_value = atoi (val->str_value);
       
   784 		g_free (val->str_value);
       
   785 		val->str_value = NULL;
       
   786 	}
       
   787 
       
   788 	if (val->type == TYPE_INT)
       
   789 		ifresult = val->int_value ? TRUE : FALSE;
       
   790 	else if (val->str_value)
       
   791 		ifresult = TRUE;
       
   792 	else
       
   793 		ifresult = FALSE;
       
   794 
       
   795 	destroy_value (val);
       
   796 }
       
   797 
       
   798 static void do_then (char *arg)
       
   799 {
       
   800 	if (ifresult)
       
   801 		process_command (arg, TRUE);
       
   802 }
       
   803 
       
   804 static void do_else (char *arg)
       
   805 {
       
   806 	if (!ifresult)
       
   807 		process_command (arg, TRUE);
       
   808 }
       
   809 
       
   810 static void do_multi (char *arg)
       
   811 {
       
   812 	char *end;
       
   813 	char *start = arg;
       
   814 	
       
   815 	for (end = strchr (start, ';'); end; end = strchr (start, ';')) {
       
   816 
       
   817 		// execute command
       
   818 		char *command = g_strndup (start, end - start);
       
   819 		process_command (command, TRUE);
       
   820 		g_free (command);
       
   821 
       
   822 		// skip leading spaces
       
   823 		for (start = end + 1; *start == ' '; ++start);
       
   824 	}
       
   825 
       
   826 	if (*start)
       
   827 		process_command (start, TRUE);
       
   828 }
       
   829 
       
   830 const gchar *g_module_check_init (GModule *module)
       
   831 {
       
   832 	cmd_add ("multi", "", COMPL_CMD, COMPL_CMD, do_multi, NULL);
       
   833 	cmd_add ("if", "", 0, 0, do_if, NULL);
       
   834 	cmd_add ("then", "", COMPL_CMD, COMPL_CMD, do_then, NULL);
       
   835 	cmd_add ("else", "", COMPL_CMD, COMPL_CMD, do_else, NULL);
       
   836 	cmd_add ("eval", "", 0, 0, do_eval, NULL);
       
   837 	cmd_add ("let", "", 0, 0, do_let, NULL);
       
   838 
       
   839 	return NULL;
       
   840 }
       
   841 
       
   842 void g_module_unload (GModule *module)
       
   843 {
       
   844 	cmd_del ("multi");
       
   845 	cmd_del ("if");
       
   846 	cmd_del ("then");
       
   847 	cmd_del ("else");
       
   848 	cmd_del ("eval");
       
   849 	cmd_del ("let");
       
   850 }
       
   851 
       
   852 /* The End */