Add:Core:Improved commands
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Wed, 25 Mar 2009 20:45:52 +0000 (20:45 +0000)
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Wed, 25 Mar 2009 20:45:52 +0000 (20:45 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@2172 ffa7fe5e-494d-0410-b361-a75ebd5db220

navit/navit/attr.c
navit/navit/attr_def.h
navit/navit/binding/dbus/binding_dbus.c
navit/navit/binding/dbus/eval.py [new file with mode: 0755]
navit/navit/command.c
navit/navit/command.h
navit/navit/navigation.c
navit/navit/navit.c
navit/navit/route.c
navit/navit/route.h
navit/navit/xmlconfig.c

index bcd1bef..b8a1722 100644 (file)
@@ -297,6 +297,38 @@ attr_generic_add_attr(struct attr **attrs, struct attr *attr)
        return curr;
 }
 
+enum attr_type
+attr_type_begin(enum attr_type type)
+{
+       if (type < attr_type_item_begin)
+               return attr_none;
+       if (type < attr_type_int_begin)
+               return attr_type_item_begin;
+       if (type < attr_type_string_begin)
+               return attr_type_int_begin;
+       if (type < attr_type_special_begin)
+               return attr_type_string_begin;
+       if (type < attr_type_double_begin)
+               return attr_type_special_begin;
+       if (type < attr_type_coord_geo_begin)
+               return attr_type_double_begin;
+       if (type < attr_type_color_begin)
+               return attr_type_coord_geo_begin;
+       if (type < attr_type_object_begin)
+               return attr_type_color_begin;
+       if (type < attr_type_coord_begin)
+               return attr_type_object_begin;
+       if (type < attr_type_pcoord_begin)
+               return attr_type_coord_begin;
+       if (type < attr_type_callback_begin)
+               return attr_type_pcoord_begin;
+       if (type < attr_type_int64_begin)
+               return attr_type_callback_begin;
+       if (type <= attr_type_int64_end)
+               return attr_type_int64_begin;
+       return attr_none;
+}
+
 int
 attr_data_size(struct attr *attr)
 {
index 2476621..1358dd9 100644 (file)
@@ -108,6 +108,7 @@ ATTR(message_maxnum)
 ATTR(pitch)
 ATTR(roll)
 ATTR(yaw)
+ATTR(route_status)
 ATTR2(0x00028000,type_boolean_begin)
 /* boolean */
 ATTR(overwrite)
@@ -202,6 +203,8 @@ ATTR(municipality_name)
 ATTR(county_name)
 ATTR(state_name)
 ATTR(message)
+ATTR(callbacks)
+ATTR(enable_expression)
 ATTR2(0x0003ffff,type_string_end)
 ATTR2(0x00040000,type_special_begin)
 ATTR(order)
index f580670..ec5918b 100644 (file)
@@ -32,6 +32,7 @@
 #include "item.h"
 #include "attr.h"
 #include "layout.h"
+#include "command.h"
 
 
 static DBusConnection *connection;
@@ -683,6 +684,36 @@ request_navit_set_destination(DBusConnection *connection, DBusMessage *message)
        return empty_reply(connection, message);
 }
 
+static DBusHandlerResult
+request_navit_evaluate(DBusConnection *connection, DBusMessage *message)
+{
+       struct pcoord pc;
+       struct navit *navit;
+       char *command;
+       char *result;
+       struct attr attr;
+       DBusMessage *reply;
+       int error;
+
+       navit = object_get_from_message(message, "navit");
+       if (! navit)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       attr.type=attr_navit;
+       attr.u.navit=navit;
+        if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &command, DBUS_TYPE_INVALID))
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       result=command_evaluate_to_string(&attr, command, &error);
+       reply = dbus_message_new_method_return(message);
+       if (error)
+               dbus_message_append_args(reply, DBUS_TYPE_INT32, &error, DBUS_TYPE_INVALID);
+       else
+               dbus_message_append_args(reply, DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID);
+       dbus_connection_send (connection, reply, NULL);
+       dbus_message_unref (reply);
+       return DBUS_HANDLER_RESULT_HANDLED;
+}
+
 struct dbus_method {
        char *path;
        char *method;
@@ -713,6 +744,7 @@ struct dbus_method {
        {".navit",  "set_destination",     "ss",      "coordinates,comment",                     "",   "",      request_navit_set_destination},
        {".navit",  "set_destination",     "(is)s",   "(projection,coordinates)comment",         "",   "",      request_navit_set_destination},
        {".navit",  "set_destination",     "(iii)s",  "(projection,longitude,latitude)comment",  "",   "",      request_navit_set_destination},
+       {".navit",  "evaluate",            "s",       "command",                                 "s",  "",     request_navit_evaluate},
 #if 0
     {".navit",  "toggle_announcer",    "",        "",                                        "",   "",      request_navit_toggle_announcer},
        {".navit",  "toggle_announcer",    "i",       "",                                        "",   "",      request_navit_toggle_announcer},
diff --git a/navit/navit/binding/dbus/eval.py b/navit/navit/binding/dbus/eval.py
new file mode 100755 (executable)
index 0000000..2255f96
--- /dev/null
@@ -0,0 +1,12 @@
+#! /usr/bin/python
+import dbus
+import sys
+bus = dbus.SessionBus()
+conn = bus.get_object('org.navit_project.navit',
+                       '/org/navit_project/navit')
+iface = dbus.Interface(conn, dbus_interface='org.navit_project.navit');
+iter=iface.iter();
+navit=bus.get_object('org.navit_project.navit', conn.get_navit(iter));
+iface.iter_destroy(iter);
+navit_iface = dbus.Interface(navit, dbus_interface='org.navit_project.navit.navit');
+print navit_iface.evaluate(sys.argv[1]);
index 8a387ce..8594aa8 100644 (file)
@@ -1,4 +1,3 @@
-
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
@@ -35,6 +34,7 @@ struct result {
        int varlen;
        char *attrn;
        int attrnlen;
+       int allocated;
 };
 
 struct context {
@@ -51,6 +51,11 @@ enum error {
 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 char *
 get_op(struct context *ctx, int test, ...)
 {
@@ -206,12 +211,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;
 }
@@ -220,7 +227,7 @@ 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;
@@ -237,8 +244,10 @@ eval_value(struct context *ctx, struct result *res) {
                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) {
@@ -259,6 +268,19 @@ 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;
 }
 
@@ -428,6 +450,7 @@ eval_equality(struct context *ctx, struct result *res)
                        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)));
+               result_free(&tmp);
        }
 }
 
@@ -610,17 +633,44 @@ void command(struct attr *attr, char *expr)
 #endif
 
 void
-command_evaluate_to_void(struct attr *attr, char *expr)
+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, 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;
+
+       command_evaluate_to(attr, expr, &ctx, &res);
+       if (error)
+               *error=ctx.error;
+       if (!ctx.error)
+               ret=get_string(&ctx, &res);
+       if (ctx.error)
+               return NULL;
+       else
+               return ret;
 }
 
 void
index cecfbd1..7dea058 100644 (file)
@@ -6,7 +6,9 @@ struct command_table {
 
 #define command_cast(x) (int (*)(void *, char *, struct attr **, struct attr ***))(x)
 
-void command_evaluate_to_void(struct attr *attr, char *expr);
+void command_evaluate_to_void(struct attr *attr, char *expr, int **error);
+char *command_evaluate_to_string(struct attr *attr, char *expr, int **error);
+int command_evaluate_to_int(struct attr *attr, char *expr, int **error);
 void command_evaluate(struct attr *attr, char *expr);
 void command_add_table(struct callback_list *cbl, struct command_table *table, int count, void *data);
 
index b0ea6fb..5e6927a 100644 (file)
@@ -1660,7 +1660,7 @@ navigation_call_callbacks(struct navigation *this_, int force_speech)
 }
 
 static void
-navigation_update(struct navigation *this_, int mode)
+navigation_update(struct navigation *this_, struct route *route, struct attr *attr)
 {
        struct map *map;
        struct map_rect *mr;
@@ -1668,12 +1668,14 @@ navigation_update(struct navigation *this_, int mode)
        struct item *sitem;                     /* Holds the corresponding item from the actual map */
        struct attr street_item,street_direction;
        struct navigation_itm *itm;
-       int incr=0,first=1;
+       int mode,incr=0,first=1;
+       if (attr->type != attr_route_status)
+               return;
 
        dbg(1,"enter %d\n", mode);
-       if (mode < 2 || mode == 4
+       if (attr->u.num == route_status_no_destination || attr->u.num == route_status_not_found || attr->u.num == route_status_path_done_new
                navigation_flush(this_);
-       if (mode < 2)
+       if (attr->u.num != route_status_path_done_new && attr->u.num != route_status_path_done_incremental)
                return;
                
        if (! this_->route)
@@ -2144,9 +2146,12 @@ navigation_map_new(struct map_methods *meth, struct attr **attrs)
 void
 navigation_set_route(struct navigation *this_, struct route *route)
 {
+       struct attr callback;
        this_->route=route;
-       this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route, this_);
-       route_add_callback(route, this_->route_cb);
+       this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route_status, this_);
+       callback.type=attr_callback;
+       callback.u.callback=this_->route_cb;
+       route_add_attr(route, &callback);
 }
 
 void
index aaf17a3..d94d0f8 100644 (file)
@@ -212,12 +212,15 @@ navit_draw_displaylist(struct navit *this_)
 }
 
 static void
-navit_redraw_route(struct navit *this_, int updated)
+navit_redraw_route(struct navit *this_, struct route *route, struct attr *attr)
 {
-       dbg(1,"enter %d\n", updated);
+       int updated;
+       if (attr->type != attr_route_status)
+               return;
+       updated=attr->u.num;
        if (this_->ready != 3)
                return;
-       if (updated <= 3)
+       if (updated != route_status_path_done_new)
                return;
        if (this_->vehicle) {
                if (this_->vehicle->follow_curr == 1)
@@ -1300,8 +1303,11 @@ navit_init(struct navit *this_)
                navit_add_former_destinations_from_file(this_);
        }
        if (this_->route) {
-               this_->route_cb=callback_new_attr_1(callback_cast(navit_redraw_route), attr_route, this_);
-               route_add_callback(this_->route, this_->route_cb);
+               struct attr callback;
+               this_->route_cb=callback_new_attr_1(callback_cast(navit_redraw_route), attr_route_status, this_);
+               callback.type=attr_callback;
+               callback.u.callback=this_->route_cb;
+               route_add_attr(this_->route, &callback);
        }
        if (this_->navigation) {
                if (this_->speech) {
@@ -1656,6 +1662,7 @@ navit_get_attr(struct navit *this_, enum attr_type type, struct attr *attr, stru
 {
        struct message *msg;
        int len,offset;
+       int ret=1;
 
        switch (type) {
        case attr_message:
@@ -1704,9 +1711,11 @@ navit_get_attr(struct navit *this_, enum attr_type type, struct attr *attr, stru
                break;
        case attr_graphics:
                attr->u.graphics=this_->gra;
-               return (attr->u.graphics != NULL);
+               ret=(attr->u.graphics != NULL);
+               break;
        case attr_gui:
                attr->u.gui=this_->gui;
+               ret=(attr->u.gui != NULL);
                break;
        case attr_layout:
                if (iter) {
@@ -1795,7 +1804,7 @@ navit_get_attr(struct navit *this_, enum attr_type type, struct attr *attr, stru
                return 0;
        }
        attr->type=type;
-       return 1;
+       return ret;
 }
 
 static int
index c162bd5..065a273 100644 (file)
@@ -221,9 +221,10 @@ struct route {
        struct map *graph_map;
        struct callback * route_graph_done_cb ; /**< Callback when route graph is done */
        struct callback * route_graph_flood_done_cb ; /**< Callback when route graph flooding is done */
-       struct callback_list *cbl     /**< Callback list to call when route changes */
+       struct callback_list *cbl2;     /**< Callback list to call when route changes */
        int destination_distance;       /**< Distance to the destination at which the destination is considered "reached" */
        struct route_preferences preferences; /**< Routing preferences */
+       int route_status;               /**< Route Status */
 };
 
 /**
@@ -398,7 +399,7 @@ route_new(struct attr *parent, struct attr **attrs)
        } else {
                this->destination_distance = 50; // Default value
        }
-       this->cbl=callback_list_new();
+       this->cbl2=callback_list_new();
        this->preferences.flags_forward_mask=AF_ONEWAYREV|AF_CAR;
        this->preferences.flags_reverse_mask=AF_ONEWAY|AF_CAR;
        this->preferences.flags=AF_CAR;
@@ -650,22 +651,25 @@ static void
 route_path_update_done(struct route *this, int new_graph)
 {
        struct route_path *oldpath=this->path2;
-       int val;
+       struct attr route_status;
+       route_status.type=attr_route_status;
        if (this->path2 && this->path2->in_use) {
                this->path2->update_required=1+new_graph;
                return;
        }
+       route_status.u.num=route_status_building_path;
+       route_set_attr(this, &route_status);
 
        this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, &this->preferences);
        route_path_destroy(oldpath);
        if (this->path2) {
-               if (new_graph)
-                       val=4;
+               if (!new_graph && this->path2->updated)
+                       route_status.u.num=route_status_path_done_incremental;
                else
-                       val=2+!this->path2->updated;
+                       route_status.u.num=route_status_path_done_new;
        } else
-               val=1;
-       callback_list_call_attr_1(this->cbl, attr_route, (void *)val);
+               route_status.u.num=route_status_not_found;
+       route_set_attr(this, &route_status);
 }
 
 /**
@@ -914,8 +918,12 @@ route_set_destination(struct route *this, struct pcoord *dst)
                this->dst=route_find_nearest_street(this->ms, dst);
                if(this->dst)
                        route_info_distances(this->dst, dst->pro);
-       } else 
-               callback_list_call_attr_1(this->cbl, attr_route, (void *)0);
+       } else  {
+               struct attr route_status;
+               route_status.type=attr_route_status;
+               route_status.u.num=route_status_no_destination;
+               route_set_attr(this, &route_status);
+       }
        profile(1,"find_nearest_street");
 
        /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
@@ -1233,7 +1241,7 @@ route_path_add_line(struct route_path *this, struct coord *start, struct coord *
        struct route_path_segment *segment;
        int seg_size,seg_dat_size;
 
-       dbg(0,"line from 0x%x,0x%x-0x%x,0x%x\n", start->x, start->y, end->x, end->y);
+       dbg(1,"line from 0x%x,0x%x-0x%x,0x%x\n", start->x, start->y, end->x, end->y);
        seg_size=sizeof(*segment) + sizeof(struct coord) * ccnt;
         seg_dat_size=sizeof(struct route_segment_data);
         segment=g_malloc0(seg_size + seg_dat_size);
@@ -1270,7 +1278,7 @@ static int
 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath, struct route_graph_segment *rgs, int dir, struct route_info *pos, struct route_info *dst)
 {
        struct route_path_segment *segment;
-       int i, ccnt, extra=0, ret=1;
+       int i, ccnt, extra=0, ret=0;
        struct coord *c,*cd,ca[2048];
        int offset=1;
        int seg_size,seg_dat_size;
@@ -1278,12 +1286,15 @@ route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpa
                offset=RSD_OFFSET(&rgs->data);
 
        dbg(1,"enter (0x%x,0x%x) dir=%d pos=%p dst=%p\n", rgs->data.item.id_hi, rgs->data.item.id_lo, dir, pos, dst);
-       if (oldpath && !pos) {
+       if (oldpath) {
                segment=item_hash_lookup(oldpath->path_hash, &rgs->data.item);
                if (segment && segment->direction == dir) {
                        segment = route_extract_segment_from_path(oldpath, &rgs->data.item, offset);
-                       if (segment) 
-                               goto linkold;
+                       if (segment) {
+                               ret=1;
+                               if (!pos)
+                                       goto linkold;
+                       }
                }
        }
 
@@ -1356,7 +1367,6 @@ route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpa
                route_check_roundabout(rgs, 13, (dir < 1), NULL);
        }
 
-       ret=0;
        memcpy(segment->data, &rgs->data, seg_dat_size);
 
 linkold:
@@ -1955,10 +1965,14 @@ route_graph_update_done(struct route *this, struct callback *cb)
 static void
 route_graph_update(struct route *this, struct callback *cb)
 {
+       struct attr route_status;
+
+       route_status.type=attr_route_status;
        route_graph_destroy(this->graph);
        callback_destroy(this->route_graph_done_cb);
        this->route_graph_done_cb=callback_new_2(callback_cast(route_graph_update_done), this, cb);
-       callback_list_call_attr_1(this->cbl, attr_route, (void *)0);
+       route_status.u.num=route_status_building_graph;
+       route_set_attr(this, &route_status);
        this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c, this->route_graph_done_cb);
 }
 
@@ -2800,29 +2814,67 @@ route_set_projection(struct route *this_, enum projection pro)
 {
 }
 
-void
-route_add_callback(struct route *this_, struct callback *cb)
+int
+route_set_attr(struct route *this_, struct attr *attr)
+{
+       int attr_updated=0;
+       switch (attr->type) {
+       case attr_route_status:
+               attr_updated = (this_->route_status != attr->u.num);
+               this_->route_status = attr->u.num;
+               break;
+       default:
+               return 0;
+       }
+       if (attr_updated)
+               callback_list_call_attr_2(this_->cbl2, attr->type, this_, attr);
+       return 1;
+}
+
+int
+route_add_attr(struct route *this_, struct attr *attr)
 {
-       callback_list_add(this_->cbl, cb);
+       switch (attr->type) {
+       case attr_callback:
+               dbg(0,"add\n");
+               callback_list_add(this_->cbl2, attr->u.callback);
+               return 1;
+       default:
+               return 0;
+       }
 }
 
-void
-route_remove_callback(struct route *this_, struct callback *cb)
+int
+route_remove_attr(struct route *this_, struct attr *attr)
 {
-       callback_list_remove(this_->cbl, cb);
+       switch (attr->type) {
+       case attr_callback:
+               callback_list_remove(this_->cbl2, attr->u.callback);
+               return 1;
+       default:
+               return 0;
+       }
 }
 
 int
 route_get_attr(struct route *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
 {
+       int ret=1;
        switch (type) {
        case attr_map:
                attr->u.map=route_get_map(this_);
-               return attr->u.map != NULL;
+               ret=(attr->u.map != NULL);
+               break;
+       case attr_route_status:
+               attr->u.num=this_->route_status;
+               break;
        default:
                return 0;
        }
+       attr->type=type;
+       return ret;
 }
+
 void
 route_init(void)
 {
index 1f323e1..0b14c28 100644 (file)
 #ifndef NAVIT_ROUTE_H
 #define NAVIT_ROUTE_H
 
+enum route_status {
+       route_status_no_destination=0,
+       route_status_not_found=1|2,
+       route_status_building_path=1|4,
+       route_status_building_graph=1|4|8,
+       route_status_path_done_new=1|16,
+       route_status_path_done_incremental=1|32,
+};
+
 struct route_crossing {
        long segid;
        int dir;
@@ -110,8 +119,10 @@ struct map *route_get_graph_map(struct route *route);
 void route_toggle_routegraph_display(struct route *route);
 void route_set_projection(struct route *this_, enum projection pro);
 int route_destination_reached(struct route *this);
-void route_add_callback(struct route *this_, struct callback *cb);
-void route_remove_callback(struct route *this_, struct callback *cb);
+int route_set_attr(struct route *this_, struct attr *attr);
+int route_add_attr(struct route *this_, struct attr *attr);
+int route_remove_attr(struct route *this_, struct attr *attr);
+int route_get_attr(struct route *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter);
 void route_init(void);
 int route_pos_contains(struct route *this, struct item *item);
 struct coord route_get_coord_dist(struct route *this_, int dist);
index 4d4f138..e8d3203 100644 (file)
@@ -288,7 +288,7 @@ static struct object_func object_funcs[] = {
        { attr_plugin,     NEW(plugin_new)},
        { attr_polygon,    NEW(polygon_new),  NULL, NULL, NULL, NULL, ADD(element_add_attr)},
        { attr_polyline,   NEW(polyline_new), NULL, NULL, NULL, NULL, ADD(element_add_attr)},
-       { attr_route,      NEW(route_new)},
+       { attr_route,      NEW(route_new), GET(route_get_attr)},
        { attr_speech,     NEW(speech_new), GET(speech_get_attr), NULL, NULL, SET(speech_set_attr)},
        { attr_text,       NEW(text_new)},
        { attr_tracking,   NEW(tracking_new)},