New patch to cope both with libgps18 and libgps19
[navit-package] / navit / attr.c
index c55ed6c..ad9013d 100644 (file)
@@ -57,6 +57,11 @@ attr_from_name(const char *name)
        return attr_none;
 }
 
+
+static int attr_match(enum attr_type search, enum attr_type found);
+
+
+
 char *
 attr_to_name(enum attr_type attr)
 {
@@ -99,6 +104,18 @@ attr_new_from_text(const char *name, const char *value)
                }
                g_free(type_str);
                break;
+       case attr_attr_types:
+               count=0;
+               type_str=g_strdup(value);
+               str=type_str;
+               while ((tok=strtok(str, ","))) {
+                       ret->u.attr_types=g_realloc(ret->u.attr_types, (count+2)*sizeof(enum attr_type));
+                       ret->u.attr_types[count++]=attr_from_name(tok);
+                       ret->u.attr_types[count]=attr_none;
+                       str=NULL;
+               }
+               g_free(type_str);
+               break;
        case attr_dash:
                count=0;
                type_str=g_strdup(value);
@@ -130,12 +147,30 @@ attr_new_from_text(const char *name, const char *value)
                break;
        default:
                if (attr >= attr_type_string_begin && attr <= attr_type_string_end) {
-                       ret->u.str=(char *)value;
+                       ret->u.str=g_strdup(value);
                        break;
                }
                if (attr >= attr_type_int_begin && attr <= attr_type_int_end) {
-                       ret->u.num=atoi(value);
-                       if (attr >= attr_type_boolean_begin) { // also check for yes and no
+                       if (value[0] == '0' && value[1] == 'x')
+                               ret->u.num=strtoul(value, NULL, 0);
+                       else
+                               ret->u.num=strtol(value, NULL, 0);
+                       
+                       if ((attr >= attr_type_rel_abs_begin) && (attr < attr_type_boolean_begin)) {
+                               /* Absolute values are from -0x40000000 - 0x40000000, with 0x0 being 0 (who would have thought that?)
+                                        Relative values are from 0x40000001 - 0x80000000, with 0x60000000 being 0 */
+                               if (strchr(value, '%')) {
+                                       if ((ret->u.num > 0x20000000) || (ret->u.num < -0x1FFFFFFF)) {
+                                               dbg(0, "Relative possibly-relative attribute with invalid value %i\n", ret->u.num);
+                                       }
+
+                                       ret->u.num += 0x60000000;
+                               } else {
+                                       if ((ret->u.num > 0x40000000) || (ret->u.num < -0x40000000)) {
+                                               dbg(0, "Non-relative possibly-relative attribute with invalid value %i\n", ret->u.num);
+                                       }
+                               }
+                       } else  if (attr >= attr_type_boolean_begin) { // also check for yes and no
                                if (g_ascii_strcasecmp(value,"no") && g_ascii_strcasecmp(value,"0") && g_ascii_strcasecmp(value,"false")) 
                                        ret->u.num=1;
                                else
@@ -209,6 +244,8 @@ attr_to_text(struct attr *attr, struct map *map, int pretty)
                        ret=g_strdup(attr->u.str);
                return ret;
        }
+       if (type == attr_flags)
+               return g_strdup_printf("0x%x", attr->u.num);
        if (type >= attr_type_int_begin && type <= attr_type_int_end) 
                return g_strdup_printf("%d", attr->u.num);
        if (type >= attr_type_int64_begin && type <= attr_type_int64_end) 
@@ -217,6 +254,18 @@ attr_to_text(struct attr *attr, struct map *map, int pretty)
                return g_strdup_printf("%f", *attr->u.numd);
        if (type >= attr_type_object_begin && type <= attr_type_object_end) 
                return g_strdup_printf("(object[%s])", attr_to_name(type));
+       if (type >= attr_type_color_begin && type <= attr_type_color_end) {
+               if (attr->u.color->a != 65535) 
+                       return g_strdup_printf("#%02x%02x%02x%02x", attr->u.color->r>>8,attr->u.color->g>>8,attr->u.color->b>>8, attr->u.color->a>>8);
+               else
+                       return g_strdup_printf("#%02x%02x%02x", attr->u.color->r>>8,attr->u.color->g>>8,attr->u.color->b>>8);
+       }
+       if (type >= attr_type_coord_geo_begin && type <= attr_type_coord_geo_end) 
+               return g_strdup_printf("%f %f",attr->u.coord_geo->lng,attr->u.coord_geo->lat);
+       if (type == attr_zipfile_ref_block) {
+               int *data=attr->u.data;
+               return g_strdup_printf("0x%x,0x%x,0x%x",data[0],data[1],data[2]);
+       }
        return g_strdup_printf("(no text[%s])", attr_to_name(type));    
 }
 
@@ -234,16 +283,41 @@ attr_search(struct attr **attrs, struct attr *last, enum attr_type attr)
        return NULL;
 }
 
+static int
+attr_match(enum attr_type search, enum attr_type found)
+{
+       switch (search) {
+       case attr_any:
+               return 1;
+       case attr_any_xml:
+               switch (found) {
+               case attr_callback:
+                       return 0;
+               default:
+                       return 1;
+               }
+       default:
+               return search == found;
+       }
+}
+
 int
 attr_generic_get_attr(struct attr **attrs, struct attr **def_attrs, enum attr_type type, struct attr *attr, struct attr_iter *iter)
 {
        while (attrs && *attrs) {
-               if ((*attrs)->type == type) {
+               if (attr_match(type,(*attrs)->type)) {
                        *attr=**attrs;
-                       return 1;
+                       if (!iter)
+                               return 1;
+                       if (*((void **)iter) < (void *)attrs) {
+                               *((void **)iter)=(void *)attrs;
+                               return 1;
+                       }
                }
                attrs++;
        }
+       if (type == attr_any || type == attr_any_xml)
+               return 0;
        while (def_attrs && *def_attrs) {
                if ((*def_attrs)->type == type) {
                        *attr=**def_attrs;
@@ -295,6 +369,64 @@ attr_generic_add_attr(struct attr **attrs, struct attr *attr)
        return curr;
 }
 
+struct attr **
+attr_generic_remove_attr(struct attr **attrs, struct attr *attr)
+{
+       struct attr **curr=attrs;
+       int i,j,count=0,found=0;
+       while (curr && *curr) {
+               if ((*curr)->type == attr->type && (*curr)->u.data == attr->u.data)
+                       found=1;
+               curr++;
+               count++;
+       }
+       if (!found)
+               return attrs;
+       curr=g_new0(struct attr *, count);
+       j=0;
+       for (i = 0 ; i < count ; i++) {
+               if (attrs[i]->type != attr->type || attrs[i]->u.data != attr->u.data)
+                       curr[j++]=attrs[i];
+               else
+                       attr_free(attrs[i]);
+       }
+       curr[j]=NULL;
+       g_free(attrs);
+       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)
 {
@@ -312,6 +444,16 @@ attr_data_size(struct attr *attr)
                return sizeof(*attr->u.num64);
        if (attr->type == attr_order)
                return sizeof(attr->u.range);
+       if (attr->type == attr_item_types) {
+               int i=0;
+               while (attr->u.item_types[i++] != type_none);
+               return i*sizeof(enum item_type);
+       }
+       if (attr->type == attr_attr_types) {
+               int i=0;
+               while (attr->u.attr_types[i++] != attr_none);
+               return i*sizeof(enum attr_type);
+       }
        dbg(0,"size for %s unknown\n", attr_to_name(attr->type));
        return 0;
 }
@@ -354,10 +496,11 @@ attr_data_set_le(struct attr * attr, void * data)
 void
 attr_free(struct attr *attr)
 {
-       if (attr->type == attr_position_coord_geo)
-               g_free(attr->u.coord_geo);
-       if (attr->type >= attr_type_color_begin && attr->type <= attr_type_color_end) 
-               g_free(attr->u.color);
+       if (!attr)
+               return;
+       if (!(attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) && 
+           !(attr->type >= attr_type_object_begin && attr->type <= attr_type_object_end))
+               g_free(attr->u.data);
        g_free(attr);
 }
 
@@ -404,3 +547,78 @@ attr_list_dup(struct attr **attrs)
                ret[i]=attr_dup(attrs[i]);
        return ret;
 }
+
+
+int
+attr_from_line(char *line, char *name, int *pos, char *val_ret, char *name_ret)
+{
+       int len=0,quoted;
+       char *p,*e,*n;
+
+       dbg(1,"get_tag %s from %s\n", name, line); 
+       if (name)
+               len=strlen(name);
+       if (pos) 
+               p=line+*pos;
+       else
+               p=line;
+       for(;;) {
+               while (*p == ' ') {
+                       p++;
+               }
+               if (! *p)
+                       return 0;
+               n=p;
+               e=strchr(p,'=');
+               if (! e)
+                       return 0;
+               p=e+1;
+               quoted=0;
+               while (*p) {
+                       if (*p == ' ' && !quoted)
+                               break;
+                       if (*p == '"')
+                               quoted=1-quoted;
+                       p++;
+               }
+               if (name == NULL || (e-n == len && !strncmp(n, name, len))) {
+                       if (name_ret) {
+                               len=e-n;
+                               strncpy(name_ret, n, len);
+                               name_ret[len]='\0';
+                       }
+                       e++;
+                       len=p-e;
+                       if (e[0] == '"') {
+                               e++;
+                               len-=2;
+                       }
+                       strncpy(val_ret, e, len);
+                       val_ret[len]='\0';
+                       if (pos)
+                               *pos=p-line;
+                       return 1;
+               }
+       }       
+       return 0;
+}
+
+int
+attr_types_contains(enum attr_type *types, enum attr_type type)
+{
+       while (types && *types != attr_none) {
+               if (*types == type)
+                       return 1;
+               types++;
+       }
+       return 0;
+}
+
+int
+attr_types_contains_default(enum attr_type *types, enum attr_type type, int deflt)
+{
+       if (!types) {
+               return deflt;
+       }
+       return attr_types_contains(types, type);        
+}