Fix:Android:Corrected and added keycodes
[navit-package] / navit / command.c
index 2a84998..a9e13fd 100644 (file)
@@ -1,9 +1,10 @@
-
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include <glib.h>
 #include "item.h"
+#include "xmlconfig.h"
 #include "main.h"
 #include "navit.h"
 #include "vehicle.h"
 #include "debug.h"
 #include "callback.h"
 #include "command.h"
+#include "event.h"
+#include "navit_nls.h"
 
 /*
-gui.fullscreen()
+gui.fullscreen=!gui.fullscreen
 gui.menu()
 gui.get_data() 
 zoom_in() 
@@ -33,6 +36,7 @@ struct result {
        int varlen;
        char *attrn;
        int attrnlen;
+       int allocated;
 };
 
 struct context {
@@ -42,18 +46,50 @@ struct context {
        struct result res;
 };
 
+struct command_saved_cb {
+       struct callback *cb;
+       struct attr attr;
+};
+
+struct command_saved {
+       struct context ctx;
+       struct result res;
+       char *command;                          // The command string itself
+       struct event_idle *idle_ev;             // Event to update this command
+       struct callback *idle_cb;
+       struct callback *register_cb;                   // Callback to register all the callbacks
+       struct event_idle *register_ev;         // Idle event to register all the callbacks
+       struct attr navit;
+       int num_cbs;
+       struct command_saved_cb *cbs;           // List of callbacks for this saved command
+       struct callback *cb; // Callback that should be called when we re-evaluate
+       int error;
+};
+
 enum error {
-       no_error=0,missing_closing_brace, missing_colon, wrong_type, illegal_number_format, illegal_character, missing_closing_bracket, invalid_type
+       no_error=0,missing_closing_brace, missing_colon, wrong_type, illegal_number_format, illegal_character, missing_closing_bracket, invalid_type, not_ready
 };
 
 static void eval_comma(struct context *ctx, struct result *res);
 static struct attr ** eval_list(struct context *ctx);
 
+static void
+result_free(struct result *res)
+{
+}
+
+static int command_register_callbacks(struct command_saved *cs);
+
 static char *
 get_op(struct context *ctx, int test, ...)
 {
        char *op,*ret=NULL;
        va_list ap;
+
+       while (g_ascii_isspace(*ctx->expr)) {
+               ctx->expr++;
+       }
+
        va_start(ap, test);
        while ((op = va_arg(ap, char *))) {
                if (!strncmp(ctx->expr, op, strlen(op))) {
@@ -67,11 +103,11 @@ get_op(struct context *ctx, int test, ...)
        return ret;
 }
 
-static int
+/*static int
 is_int(struct result *res)
 {
        return 1;
-}
+}*/
 
 static int
 is_double(struct result *res)
@@ -82,6 +118,7 @@ is_double(struct result *res)
 static void
 dump(struct result *res)
 {
+#if 0
        char object[res->varlen+1];
        char attribute[res->attrnlen+1];
        if (res->var)
@@ -92,6 +129,7 @@ dump(struct result *res)
        attribute[res->attrnlen]='\0';
        dbg(0,"type:%s\n", attr_to_name(res->attr.type));
        dbg(0,"attribute '%s' from '%s'\n", attribute, object);
+#endif
 }
 
 static enum attr_type
@@ -105,20 +143,12 @@ command_attr_type(struct result *res)
 }
 
 static int
-command_object_get_attr(struct attr *object, enum attr_type attr_type, struct attr *ret)
-{
-       switch (object->type) {
-       case attr_gui:
-               return gui_get_attr(object->u.gui, attr_type, ret, NULL);
-       case attr_navit:
-               return navit_get_attr(object->u.navit, attr_type, ret, NULL);
-       case attr_speech:
-               return speech_get_attr(object->u.speech, attr_type, ret, NULL);
-       case attr_vehicle:
-               return vehicle_get_attr(object->u.vehicle, attr_type, ret, NULL);
-       default:
+command_object_get_attr(struct context *ctx, struct attr *object, enum attr_type attr_type, struct attr *ret)
+{
+       struct object_func *func=object_func_lookup(object->type);
+       if (!func || !func->get_attr)
                return 0;
-       }
+       return func->get_attr(object->u.data, attr_type, ret, NULL);
 }
 
 static void
@@ -126,7 +156,7 @@ command_get_attr(struct context *ctx, struct result *res)
 {
        int result;
        enum attr_type attr_type=command_attr_type(res);
-       result=command_object_get_attr(&res->attr, attr_type, &res->attr);
+       result=command_object_get_attr(ctx, &res->attr, attr_type, &res->attr);
        if (result) {
                res->var=res->attrn;
                res->varlen=res->attrnlen;
@@ -145,17 +175,11 @@ command_set_attr(struct context *ctx, struct result *res, struct result *newres)
 {
        int result=0;
        enum attr_type attr_type=command_attr_type(res);
+       struct object_func *func=object_func_lookup(res->attr.type);
+       if (!func || !func->set_attr)
+               return;
        newres->attr.type=attr_type;
-       switch (res->attr.type) {
-       case attr_navit:
-               result=navit_set_attr(res->attr.u.navit, &newres->attr);
-               break;
-       case attr_speech:
-               result=speech_set_attr(res->attr.u.speech, &newres->attr);
-               break;
-       default:
-               break;
-       }
+       result=func->set_attr(res->attr.u.data, &newres->attr);
        *res=*newres;
 }
 
@@ -172,14 +196,11 @@ resolve_object(struct context *ctx, struct result *res)
 }
 
 static void
-resolve(struct context *ctx, struct result *res, struct attr *parent)
+resolve(struct context *ctx, struct result *res, struct attr *parent) //FIXME What is that parent for?
 {
        resolve_object(ctx, res);
-       if (res->attr.type >= attr_type_object_begin && res->attr.type <= attr_type_object_end) {
-               if (res->attrn)
-                       command_get_attr(ctx, res);
-               return;
-       }
+       if (res->attrn)
+               command_get_attr(ctx, res);
 }
 
 static double
@@ -218,12 +239,14 @@ get_string(struct context *ctx, struct result *res)
 static void
 set_double(struct context *ctx, struct result *res, double val)
 {
+       result_free(res);
        res->val=val;
 }
 
 static void
 set_int(struct context *ctx, struct result *res, int val)
 {
+       result_free(res);
        res->attr.type=attr_type_int_begin;
        res->attr.u.num=val;
 }
@@ -232,25 +255,39 @@ set_int(struct context *ctx, struct result *res, int val)
 static void
 eval_value(struct context *ctx, struct result *res) {
        char *op;
-       int dots=0;
+       int len,dots=0;
        op=ctx->expr;
        res->varlen=0;
        res->var=NULL;
        res->attrnlen=0;
        res->attrn=NULL;
-       if (op[0] >= 'a' && op[0] <= 'z') {
+
+       while (g_ascii_isspace(*op)) {
+               op++;
+       }
+
+       if ((op[0] >= 'a' && op[0] <= 'z') || op[0] == '_') {
                res->attr.type=attr_none;
                res->var=op;
-               while ((op[0] >= 'a' && op[0] <= 'z') || op[0] == '_') {
-                       res->varlen++;
-                       op++;
+               for (;;) {
+                       while ((op[0] >= 'a' && op[0] <= 'z') || op[0] == '_') {
+                               res->varlen++;
+                               op++;
+                       }
+                       if (res->varlen == 3 && !strncmp(res->var,"new",3) && op[0] == ' ') {
+                               res->varlen++;
+                               op++;
+                       } else
+                               break;
                }
                ctx->expr=op;
                return;
        }
        if ((op[0] >= '0' && op[0] <= '9') ||
-           (op[0] == '.' && op[1] >= '0' && op[1] <= '9')) {
-               while ((op[0] >= '0' && op[0] <= '9') || op[0] == '.') {
+           (op[0] == '.' && op[1] >= '0' && op[1] <= '9') ||
+           (op[0] == '-' && op[1] >= '0' && op[1] <= '9') ||
+           (op[0] == '-' && op[1] == '.' && op[2] >= '0' && op[2] <= '9')) {
+               while ((op[0] >= '0' && op[0] <= '9') || op[0] == '.' || (res->varlen == 0 && op[0] == '-')) {
                        if (op[0] == '.')
                                dots++;
                        if (dots > 1) {
@@ -271,9 +308,48 @@ eval_value(struct context *ctx, struct result *res) {
                ctx->expr=op;
                return;
        }
+       if (op[0] == '"') {
+               do {
+                       op++;
+               } while (op[0] != '"');
+               res->attr.type=attr_type_string_begin;
+               len=op-ctx->expr-1;
+               res->attr.u.str=g_malloc(len+1);
+               strncpy(res->attr.u.str, ctx->expr+1, len);
+               res->attr.u.str[len]='\0';
+               op++;
+               ctx->expr=op;
+               return;
+       }
        ctx->error=illegal_character;
 }
 
+static int
+get_next_object(struct context *ctx, struct result *res) {
+       
+       while (*ctx->expr) {
+               res->varlen = 0;
+               ctx->error = 0;
+
+               eval_value(ctx,res);
+               
+               if ((res->attr.type == attr_none) && (res->varlen > 0)) {
+                       if (ctx->expr[0] != '.') {
+                               return 1;               // 1 means "this is the final object name"
+                       } else {
+                               return 2;               // 2 means "there are more object names following" (e.g. we just hit 'vehicle' in 'vehicle.position_speed'
+                       }
+               }
+
+               if (ctx->error) {
+                       // Probably hit an operator
+                       ctx->expr++;
+               }
+       }
+
+       return 0;
+}
+
 static void
 eval_brace(struct context *ctx, struct result *res)
 {
@@ -295,7 +371,7 @@ command_call_function(struct context *ctx, struct result *res)
        if (res->attrn)
                strncpy(function, res->attrn, res->attrnlen);
        function[res->attrnlen]='\0';
-       dbg(0,"function=%s\n", function);
+       dbg(1,"function=%s\n", function);
        if (ctx->expr[0] != ')') {
                list=eval_list(ctx);    
                if (ctx->error) return;
@@ -304,16 +380,31 @@ command_call_function(struct context *ctx, struct result *res)
                ctx->error=missing_closing_brace;
                return;
        }
-       if (command_object_get_attr(&res->attr, attr_callback_list, &cbl)) {
-               int valid;
-               dbg(0,"function call %s from %s\n",function, attr_to_name(res->attr.type));
-               callback_list_call_attr_4(cbl.u.callback_list, attr_command, function, list, NULL, &valid);
+       if (!strcmp(function,"_") && list && list[0] && list[0]->type >= attr_type_string_begin && list[0]->type <= attr_type_string_end) {
+               res->attr.type=list[0]->type;
+               res->attr.u.str=g_strdup(gettext(list[0]->u.str));      
+               
+       } if (!strncmp(function,"new ",4)) {
+               enum attr_type attr_type=attr_from_name(function+4);
+               if (attr_type != attr_none) {
+                       struct object_func *func=object_func_lookup(attr_type);
+                       if (func && func->new) {
+                               res->attr.type=attr_type;
+                               res->attr.u.data=func->new(NULL, list);
+                       }
+               }
+       } else {
+               if (command_object_get_attr(ctx, &res->attr, attr_callback_list, &cbl)) {
+                       int valid;
+                       dbg(1,"function call %s from %s\n",function, attr_to_name(res->attr.type));
+                       callback_list_call_attr_4(cbl.u.callback_list, attr_command, function, list, NULL, &valid);
+               }
+               res->attr.type=attr_none;
        }
        res->var=NULL;
        res->varlen=0;
        res->attrn=NULL;
        res->attrnlen=0;
-       res->attr.type=attr_none;
 }
 
 static void
@@ -341,7 +432,7 @@ eval_postfix(struct context *ctx, struct result *res)
                                return;
                        }
                } else if (op[0] == '(') {
-                       dbg(0,"function call\n");
+                       dbg(1,"function call\n");
                        resolve_object(ctx, res);
                        command_call_function(ctx, res);
                }
@@ -433,13 +524,35 @@ eval_equality(struct context *ctx, struct result *res)
        eval_additive(ctx, res);
        if (ctx->error) return;
        for (;;) {
-               if (!(op=get_op(ctx,0,"==","!=",NULL))) return;
+               if (!(op=get_op(ctx,0,"==","!=","<=",">=","<",">",NULL))) return;
                eval_additive(ctx, &tmp);
                if (ctx->error) return;
-               if (op[0]  == '=') 
+
+               switch (op[0]) {
+               case '=':
                        set_int(ctx, res, (get_int(ctx, res) == get_int(ctx, &tmp)));
-               else
+                       break;
+               case '!':
                        set_int(ctx, res, (get_int(ctx, res) != get_int(ctx, &tmp)));
+                       break;
+               case '<':
+                       if (op[1] == '=') {
+                               set_int(ctx, res, (get_int(ctx, res) <= get_int(ctx, &tmp)));
+                       } else {
+                               set_int(ctx, res, (get_int(ctx, res) < get_int(ctx, &tmp)));
+                       }
+                       break;
+               case '>':
+                       if (op[1] == '=') {
+                               set_int(ctx, res, (get_int(ctx, res) >= get_int(ctx, &tmp)));
+                       } else {
+                               set_int(ctx, res, (get_int(ctx, res) > get_int(ctx, &tmp)));
+                       }
+                       break;
+               default:
+                       break;
+               }
+               result_free(&tmp);
        }
 }
 
@@ -562,6 +675,8 @@ eval_assignment(struct context *ctx, struct result *res)
        if (!get_op(ctx,0,"=",NULL)) return;
        eval_conditional(ctx, &tmp);
        if (ctx->error) return;
+       resolve(ctx, &tmp, NULL);
+       if (ctx->error) return;
        resolve_object(ctx, res);
        command_set_attr(ctx, res, &tmp);
 }
@@ -572,7 +687,7 @@ eval_comma(struct context *ctx, struct result *res)
 {
        struct result tmp;
 
-       eval_assignment(ctx, res);
+       eval_assignment(ctx, res);
        if (ctx->error) return;
        for (;;) {
                if (!get_op(ctx,0,",",NULL)) return;
@@ -594,6 +709,7 @@ eval_list(struct context *ctx)
                        attr_list_free(ret);
                        return NULL;
                }
+               resolve(ctx, &tmp, NULL);
                ret=attr_generic_add_attr(ret, &tmp.attr);
                if (!get_op(ctx,0,",",NULL)) return ret;
        }
@@ -621,18 +737,94 @@ void command(struct attr *attr, char *expr)
 }
 #endif
 
+static void
+command_evaluate_to(struct attr *attr, char *expr, struct context *ctx, struct result *res)
+{
+       memset(res, 0, sizeof(*res));
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->attr=attr;
+       ctx->expr=expr;
+       eval_comma(ctx,res);
+}
+
 void
-command_evaluate_to_void(struct attr *attr, char *expr)
+command_evaluate_to_void(struct attr *attr, char *expr, int **error)
 {
        struct result res;
        struct context ctx;
-       memset(&res, 0, sizeof(res));
-       memset(&ctx, 0, sizeof(ctx));
-       ctx.attr=attr;
-       ctx.error=0;
-       ctx.expr=expr;
-       eval_comma(&ctx,&res);
-       resolve(&ctx, &res, NULL);
+       command_evaluate_to(attr, expr, &ctx, &res);
+       if (!ctx.error)
+               resolve(&ctx, &res, NULL);
+       if (error)
+               *error=&ctx.error;
+
+}
+
+char *
+command_evaluate_to_string(struct attr *attr, char *expr, int **error)
+{
+       struct result res;
+       struct context ctx;
+       char *ret=NULL;
+
+       command_evaluate_to(attr, expr, &ctx, &res);
+       if (!ctx.error)
+               resolve(&ctx, &res, NULL);
+       if (!ctx.error)
+               ret=get_string(&ctx, &res);
+       if (error)
+               *error=&ctx.error;
+       if (ctx.error)
+               return NULL;
+       else
+               return ret;
+}
+
+int
+command_evaluate_to_int(struct attr *attr, char *expr, int **error)
+{
+       struct result res;
+       struct context ctx;
+       int ret=0;
+
+       command_evaluate_to(attr, expr, &ctx, &res);
+       if (!ctx.error)
+               resolve(&ctx, &res, NULL);
+       if (!ctx.error)
+               ret=get_int(&ctx, &res);
+       if (error)
+               *error=&ctx.error;
+       if (ctx.error)
+               return 0;
+       else
+               return ret;
+}
+
+int
+command_evaluate_to_boolean(struct attr *attr, char *expr, int **error)
+{
+       struct result res;
+       struct context ctx;
+       int ret=0;
+
+       command_evaluate_to(attr, expr, &ctx, &res);
+       if (!ctx.error)
+               resolve(&ctx, &res, NULL);
+       if (!ctx.error) {
+               if (res.attr.type == attr_none)
+                       ret=0;
+               else if ((res.attr.type >= attr_type_int_begin && res.attr.type <= attr_type_int_end) ||
+                        (res.attr.type >= attr_type_double_begin && res.attr.type <= attr_type_double_end))
+                       ret=get_int(&ctx, &res);
+               else 
+                       ret=res.attr.u.data != NULL;
+       }
+       if (error)
+               *error=&ctx.error;
+       if (ctx.error)
+               return 0;
+       else    
+               return ret;
 }
 
 void
@@ -688,9 +880,198 @@ command_table_call(struct command_table *table, int count, void *data, char *com
 }
 
 void
+command_add_table_attr(struct command_table *table, int count, void *data, struct attr *attr)
+{
+       attr->type=attr_callback;
+       attr->u.callback=callback_new_attr_3(callback_cast(command_table_call),attr_command, table, count, data);
+}
+
+void
 command_add_table(struct callback_list *cbl, struct command_table *table, int count, void *data)
 {
-       struct callback *cb=callback_new_attr_3(callback_cast(command_table_call),attr_command, table, count, data);
-       callback_list_add(cbl, cb);
+       struct attr attr;
+       command_add_table_attr(table, count, data, &attr);
+       callback_list_add(cbl, attr.u.callback);
+}
+
+void
+command_saved_set_cb (struct command_saved *cs, struct callback *cb)
+{
+       cs->cb = cb;
+}
+
+int
+command_saved_get_int (struct command_saved *cs)
+{
+       return get_int(&cs->ctx, &cs->res);
+}
+
+int 
+command_saved_error (struct command_saved *cs)
+{
+       return cs->error;
+}
+
+static void
+command_saved_evaluate_idle (struct command_saved *cs) 
+{
+       // Only run once at a time
+       if (cs->idle_ev) {
+               event_remove_idle(cs->idle_ev);
+               cs->idle_ev = NULL;
+       }
+
+       command_evaluate_to(&cs->navit, cs->command, &cs->ctx, &cs->res);
+
+       if (!cs->ctx.error) {
+               cs->error = 0;
+
+               if (cs->cb) {
+                       callback_call_1(cs->cb, cs);
+               }
+       } else {
+               cs->error = cs->ctx.error;
+       }
+}
+
+static void
+command_saved_evaluate(struct command_saved *cs)
+{      
+       if (cs->idle_ev) {
+               // We're already scheduled for reevaluation
+               return;
+       }
+
+       if (!cs->idle_cb) {
+               cs->idle_cb = callback_new_1(callback_cast(command_saved_evaluate_idle), cs);
+       }
+
+       cs->idle_ev = event_add_idle(100, cs->idle_cb);
+}
+
+static void
+command_saved_callbacks_changed(struct command_saved *cs)
+{
+       // For now, we delete each and every callback and then re-create them
+       int i;
+       struct object_func *func;
+       struct attr attr;
+
+       if (cs->register_ev) {
+               event_remove_idle(cs->register_ev);
+               cs->register_ev = NULL;
+       }
+
+       attr.type = attr_callback;
+
+       for (i = 0; i < cs->num_cbs; i++) {
+               func = object_func_lookup(cs->cbs[i].attr.type);
+               
+               if (!func->remove_attr) {
+                       dbg(0, "Could not remove command-evaluation callback because remove_attr is missing for type %i!\n", cs->cbs[i].attr.type);
+                       continue;
+               }
+
+               attr.u.callback = cs->cbs[i].cb;
+
+               func->remove_attr(cs->cbs[i].attr.u.data, &attr);
+               callback_destroy(cs->cbs[i].cb);
+       }
+
+       g_free(cs->cbs);
+       cs->cbs = NULL;
+       cs->num_cbs = 0;
+
+       // Now, re-create all the callbacks
+       command_register_callbacks(cs);
+}
+
+static int
+command_register_callbacks(struct command_saved *cs)
+{
+       struct attr prev,cb_attr,attr;
+       int status;
+       struct object_func *func;
+       struct callback *cb;
+       
+       attr = cs->navit;
+       cs->ctx.expr = cs->command;
+       cs->ctx.attr = &attr;
+       prev = cs->navit;       
+
+       while ((status = get_next_object(&cs->ctx, &cs->res)) != 0) {
+               resolve(&cs->ctx, &cs->res, NULL);
+
+               if (cs->ctx.error || (cs->res.attr.type == attr_none)) {
+                       // We could not resolve an object, perhaps because it has not been created
+                       return 0;
+               }
+
+               if (prev.type != attr_none) {
+                       func = object_func_lookup(prev.type);
+
+                       if (func->add_attr) {
+                               if (status == 2) { // This is not the final attribute name
+                                       cb = callback_new_attr_1(callback_cast(command_saved_callbacks_changed), cs->res.attr.type, (void*)cs);
+                                       attr = cs->res.attr;
+                               } else if (status == 1) { // This is the final attribute name
+                                       cb = callback_new_attr_1(callback_cast(command_saved_evaluate), cs->res.attr.type, (void*)cs);
+                                       cs->ctx.attr = &cs->navit;
+                               } else {
+                                       dbg(0, "Error: Strange status returned from get_next_object()\n");
+                               }
+
+                               cs->num_cbs++;
+                               cs->cbs = g_realloc(cs->cbs, (sizeof(struct command_saved_cb) * cs->num_cbs));
+                               cs->cbs[cs->num_cbs-1].cb = cb;
+                               cs->cbs[cs->num_cbs-1].attr = prev;
+                                       
+                               cb_attr.u.callback = cb;
+                               cb_attr.type = attr_callback;
+
+                               func->add_attr(prev.u.data, &cb_attr);
+
+                       } else {
+                               dbg(0, "Could not add callback because add_attr is missing for type %i}n", prev.type);
+                       }
+               }
+
+               if (status == 2) {
+                       prev = cs->res.attr;
+               } else {
+                       prev = cs->navit;
+               }
+       }
+
+       command_saved_evaluate_idle(cs);
+
+       return 1;
+}
+
+struct command_saved
+*command_saved_new(char *command, struct navit *navit, struct callback *cb)
+{
+       struct command_saved *ret;
+
+       ret = g_new0(struct command_saved, 1);
+       ret->command = g_strdup(command);
+       ret->navit.u.navit = navit;
+       ret->navit.type = attr_navit;
+       ret->cb = cb;
+       ret->error = not_ready;
+
+       if (!command_register_callbacks(ret)) {
+               // We try this as an idle call again
+               ret->register_cb = callback_new_1(callback_cast(command_saved_callbacks_changed), ret);
+               ret->register_ev = event_add_idle(300, ret->register_cb);
+       }               
+
+       return ret;
 }
 
+void 
+command_saved_destroy(struct command_saved *cs)
+{
+       g_free(cs->command);
+       g_free(cs);
+}