/* * Navit, a modular navigation system. * Copyright (C) 2005-2008 Navit Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @file attr.c * @brief Attribute handling code * * Structures and functions for working with attributes. * * @author Navit Team * @date 2005-2014 */ #include #include #include #include #include "debug.h" #include "item.h" #include "coord.h" #include "transform.h" #include "color.h" #include "attr.h" #include "map.h" #include "config.h" #include "endianess.h" #include "util.h" #include "types.h" #include "xmlconfig.h" struct attr_name { enum attr_type attr; char *name; }; /** List of attr_types with their names as strings. */ static struct attr_name attr_names[]={ #define ATTR2(x,y) ATTR(y) #define ATTR(x) { attr_##x, #x }, #define ATTR_UNUSED /* Unused attr_types not needed here.*/ #include "attr_def.h" #undef ATTR_UNUSED #undef ATTR2 #undef ATTR }; static GHashTable *attr_hash; void attr_create_hash(void) { int i; attr_hash=g_hash_table_new(g_str_hash, g_str_equal); for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) { g_hash_table_insert(attr_hash, attr_names[i].name, GINT_TO_POINTER(attr_names[i].attr)); } } void attr_destroy_hash(void) { g_hash_table_destroy(attr_hash); attr_hash=NULL; } /** * @brief Converts a string to an attr_type * * This function reads a string and returns the corresponding attr_type. * * @param name The attribute name * @return The corresponding {@code attr_type}, or {@code attr_none} if the string specifies a nonexistent or invalid attribute type. */ enum attr_type attr_from_name(const char *name) { int i; if (attr_hash) return GPOINTER_TO_INT(g_hash_table_lookup(attr_hash, name)); for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) { if (! strcmp(attr_names[i].name, name)) return attr_names[i].attr; } return attr_none; } static int attr_match(enum attr_type search, enum attr_type found); /** * @brief Converts an attr_type to a string * * @param attr The attribute type to be converted. * @return The attribute name, or NULL if an invalid value was passed as {@code attr}. * The calling function should create a copy of the string if it needs to alter it or relies on the * string being available permanently. */ char * attr_to_name(enum attr_type attr) { int i; for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) { if (attr_names[i].attr == attr) return attr_names[i].name; } return NULL; } /** * @brief Creates an attribute from text information * * This function creates an attribute from two strings specifying the name and * the value. * * @param name The name of the new attribute * @param value The value of the new attribute * @return The new attribute */ struct attr * attr_new_from_text(const char *name, const char *value) { enum attr_type attr; struct attr *ret; struct coord_geo *g; struct coord c; enum item_type item_type; char *pos,*type_str,*str,*tok; int min,max,count; ret=g_new0(struct attr, 1); dbg(lvl_debug,"enter name='%s' value='%s'\n", name, value); attr=attr_from_name(name); ret->type=attr; switch (attr) { case attr_item_type: ret->u.item_type=item_from_name(value); break; case attr_item_types: count=0; type_str=g_strdup(value); str=type_str; while ((tok=strtok(str, ","))) { ret->u.item_types=g_realloc(ret->u.item_types, (count+2)*sizeof(enum item_type)); item_type=item_from_name(tok); if (item_type!=type_none) { ret->u.item_types[count++]=item_type; ret->u.item_types[count]=type_none; } else { dbg(lvl_error,"Unknown item type '%s' ignored.\n",tok); } str=NULL; } 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); str=type_str; while ((tok=strtok(str, ","))) { ret->u.dash=g_realloc(ret->u.dash, (count+2)*sizeof(int)); ret->u.dash[count++]=g_ascii_strtoull(tok,NULL,0); ret->u.dash[count]=0; str=NULL; } g_free(type_str); break; case attr_order: case attr_sequence_range: case attr_angle_range: case attr_speed_range: pos=strchr(value, '-'); min=0; max=32767; if (! pos) { sscanf(value,"%d",&min); max=min; } else if (pos == value) sscanf(value,"-%d",&max); else sscanf(value,"%d-%d",&min, &max); ret->u.range.min=min; ret->u.range.max=max; break; default: if (attr >= attr_type_string_begin && attr <= attr_type_string_end) { ret->u.str=g_strdup(value); break; } if (attr >= attr_type_int_begin && attr <= attr_type_int_end) { 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(lvl_error, "Relative possibly-relative attribute with invalid value %li\n", ret->u.num); } ret->u.num += 0x60000000; } else { if ((ret->u.num > 0x40000000) || (ret->u.num < -0x40000000)) { dbg(lvl_error, "Non-relative possibly-relative attribute with invalid value %li\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 ret->u.num=0; } break; } if (attr >= attr_type_color_begin && attr <= attr_type_color_end) { struct color *color=g_new0(struct color, 1); int r,g,b,a; ret->u.color=color; if(strlen(value)==7){ sscanf(value,"#%02x%02x%02x", &r, &g, &b); color->r = (r << 8) | r; color->g = (g << 8) | g; color->b = (b << 8) | b; color->a = (65535); } else if(strlen(value)==9){ sscanf(value,"#%02x%02x%02x%02x", &r, &g, &b, &a); color->r = (r << 8) | r; color->g = (g << 8) | g; color->b = (b << 8) | b; color->a = (a << 8) | a; } else { dbg(lvl_error,"color %s has unknown format\n",value); } break; } if (attr >= attr_type_coord_geo_begin && attr <= attr_type_coord_geo_end) { g=g_new(struct coord_geo, 1); ret->u.coord_geo=g; coord_parse(value, projection_mg, &c); transform_to_geo(projection_mg, &c, g); break; } dbg(lvl_debug,"default\n"); g_free(ret); ret=NULL; } return ret; } /** * @brief Converts access flags to a human-readable string. * * @param flags The flags as a number * @return The flags in human-readable form */ static char * flags_to_text(int flags) { char *ret=g_strdup_printf("0x%x:",flags); if (flags & AF_ONEWAY) ret=g_strconcat_printf(ret,"%sAF_ONEWAY",ret?"|":""); if (flags & AF_ONEWAYREV) ret=g_strconcat_printf(ret,"%sAF_ONEWAYREV",ret?"|":""); if (flags & AF_SEGMENTED) ret=g_strconcat_printf(ret,"%sAF_SEGMENTED",ret?"|":""); if (flags & AF_ROUNDABOUT) ret=g_strconcat_printf(ret,"%sAF_ROUNDABOUT",ret?"|":""); if (flags & AF_ROUNDABOUT_VALID) ret=g_strconcat_printf(ret,"%sAF_ROUNDABOUT_VALID",ret?"|":""); if (flags & AF_ONEWAY_EXCEPTION) ret=g_strconcat_printf(ret,"%sAF_ONEWAY_EXCEPTION",ret?"|":""); if (flags & AF_SPEED_LIMIT) ret=g_strconcat_printf(ret,"%sAF_SPEED_LIMIT",ret?"|":""); if (flags & AF_RESERVED1) ret=g_strconcat_printf(ret,"%sAF_RESERVED1",ret?"|":""); if (flags & AF_SIZE_OR_WEIGHT_LIMIT) ret=g_strconcat_printf(ret,"%sAF_SIZE_OR_WEIGHT_LIMIT",ret?"|":""); if (flags & AF_THROUGH_TRAFFIC_LIMIT) ret=g_strconcat_printf(ret,"%sAF_THROUGH_TRAFFIC_LIMIT",ret?"|":""); if (flags & AF_TOLL) ret=g_strconcat_printf(ret,"%sAF_TOLL",ret?"|":""); if (flags & AF_SEASONAL) ret=g_strconcat_printf(ret,"%sAF_SEASONAL",ret?"|":""); if (flags & AF_UNPAVED) ret=g_strconcat_printf(ret,"%sAF_UNPAVED",ret?"|":""); if (flags & AF_FORD) ret=g_strconcat_printf(ret,"%sAF_FORD",ret?"|":""); if (flags & AF_UNDERGROUND) ret=g_strconcat_printf(ret,"%sAF_UNDERGROUND",ret?"|":""); if (flags & AF_DANGEROUS_GOODS) ret=g_strconcat_printf(ret,"%sAF_DANGEROUS_GOODS",ret?"|":""); if ((flags & AF_ALL) == AF_ALL) return g_strconcat_printf(ret,"%sAF_ALL",ret?"|":""); if ((flags & AF_ALL) == AF_MOTORIZED_FAST) return g_strconcat_printf(ret,"%sAF_MOTORIZED_FAST",ret?"|":""); if (flags & AF_EMERGENCY_VEHICLES) ret=g_strconcat_printf(ret,"%sAF_EMERGENCY_VEHICLES",ret?"|":""); if (flags & AF_TRANSPORT_TRUCK) ret=g_strconcat_printf(ret,"%sAF_TRANSPORT_TRUCK",ret?"|":""); if (flags & AF_DELIVERY_TRUCK) ret=g_strconcat_printf(ret,"%sAF_DELIVERY_TRUCK",ret?"|":""); if (flags & AF_PUBLIC_BUS) ret=g_strconcat_printf(ret,"%sAF_PUBLIC_BUS",ret?"|":""); if (flags & AF_TAXI) ret=g_strconcat_printf(ret,"%sAF_TAXI",ret?"|":""); if (flags & AF_HIGH_OCCUPANCY_CAR) ret=g_strconcat_printf(ret,"%sAF_HIGH_OCCUPANCY_CAR",ret?"|":""); if (flags & AF_CAR) ret=g_strconcat_printf(ret,"%sAF_CAR",ret?"|":""); if (flags & AF_MOTORCYCLE) ret=g_strconcat_printf(ret,"%sAF_MOTORCYCLE",ret?"|":""); if (flags & AF_MOPED) ret=g_strconcat_printf(ret,"%sAF_MOPED",ret?"|":""); if (flags & AF_HORSE) ret=g_strconcat_printf(ret,"%sAF_HORSE",ret?"|":""); if (flags & AF_BIKE) ret=g_strconcat_printf(ret,"%sAF_BIKE",ret?"|":""); if (flags & AF_PEDESTRIAN) ret=g_strconcat_printf(ret,"%sAF_PEDESTRIAN",ret?"|":""); return ret; } /** * @brief Converts attribute data to human-readable text * * @param attr The attribute to be formatted * @param sep The separator to insert between a numeric value and its unit. If NULL, nothing will be inserted. * @param fmt Set to {@code attr_format_with_units} if {@code attr} is of type {@code attr_destination_length} * or {@code attr_destination_time} or a group type which might contain attributes of those types. Ignored for * all other attribute types. * @param def_fmt Not used * @param map The translation map. This is only needed for string type attributes or group type * attributes which might contain strings. It can be NULL for other attribute types. If a string * type attribute is encountered and {@code map} is NULL, the string will be returned unchanged. */ char * attr_to_text_ext(struct attr *attr, char *sep, enum attr_format fmt, enum attr_format def_fmt, struct map *map) { char *ret; enum attr_type type=attr->type; if (!sep) sep=""; if (type >= attr_type_item_begin && type <= attr_type_item_end) { struct item *item=attr->u.item; struct attr type, data; if (! item) return g_strdup("(nil)"); if (! item->map || !map_get_attr(item->map, attr_type, &type, NULL)) type.u.str=""; if (! item->map || !map_get_attr(item->map, attr_data, &data, NULL)) data.u.str=""; return g_strdup_printf("type=0x%x id=0x%x,0x%x map=%p (%s:%s)", item->type, item->id_hi, item->id_lo, item->map, type.u.str, data.u.str); } if (type >= attr_type_string_begin && type <= attr_type_string_end) { if (map) { char *mstr; if (attr->u.str) { mstr=map_convert_string(map, attr->u.str); ret=g_strdup(mstr); map_convert_free(mstr); } else ret=g_strdup("(null)"); } else ret=g_strdup(attr->u.str); return ret; } if (type == attr_flags || type == attr_through_traffic_flags) return flags_to_text(attr->u.num); if (type == attr_destination_length) { if (fmt == attr_format_with_units) { double distance=attr->u.num; if (distance > 10000) return g_strdup_printf("%.0f%skm",distance/1000,sep); return g_strdup_printf("%.1f%skm",distance/1000,sep); } } if (type == attr_destination_time) { if (fmt == attr_format_with_units) { int seconds=(attr->u.num+5)/10; int minutes=seconds/60; int hours=minutes/60; int days=hours/24; hours%=24; minutes%=60; seconds%=60; if (days) return g_strdup_printf("%d:%02d:%02d:%02d",days,hours,minutes,seconds); if (hours) return g_strdup_printf("%02d:%02d:%02d",hours,minutes,seconds); return g_strdup_printf("%02d:%02d",minutes,seconds); } } if (type >= attr_type_int_begin && type <= attr_type_int_end) return g_strdup_printf("%ld", attr->u.num); if (type >= attr_type_int64_begin && type <= attr_type_int64_end) return g_strdup_printf(LONGLONG_FMT, *attr->u.num64); if (type >= attr_type_double_begin && type <= attr_type_double_end) 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]); } if (type == attr_item_id) { int *data=attr->u.data; return g_strdup_printf("0x%x,0x%x",data[0],data[1]); } if (type == attr_item_types) { enum item_type *item_types=attr->u.item_types; char *sep="",*ret=NULL; while (item_types && *item_types) { ret=g_strconcat_printf(ret,"%s%s",sep,item_to_name(*item_types++)); sep=","; } return ret; } if (type >= attr_type_group_begin && type <= attr_type_group_end) { int i=0; char *ret=g_strdup(""); char *sep=""; while (attr->u.attrs[i].type) { char *val=attr_to_text_ext(&attr->u.attrs[i], sep, fmt, def_fmt, map); ret=g_strconcat_printf(ret,"%s%s=%s",sep,attr_to_name(attr->u.attrs[i].type),val); g_free(val); sep=" "; i++; } return ret; } if (type >= attr_type_item_type_begin && type <= attr_type_item_type_end) { return g_strdup_printf("0x%ld[%s]",attr->u.num,item_to_name(attr->u.num)); } return g_strdup_printf("(no text[%s])", attr_to_name(type)); } /** * @brief Converts an attribute to a string that can be displayed * * This function is just a wrapper around {@code attr_to_text_ext()}. * * @param attr The attribute to convert * @param map The translation map, see {@code attr_to_text_ext()} * @param pretty Not used */ char * attr_to_text(struct attr *attr, struct map *map, int pretty) { return attr_to_text_ext(attr, NULL, attr_format_default, attr_format_default, map); } /** * @brief Searches for an attribute of a given type * * This function searches an array of pointers to attributes for a given * attribute type and returns the first match. * * @param attrs Points to the array of attribute pointers to be searched * @param last Not used * @param attr_type The attribute type to search for. Generic types (such as * attr_any or attr_any_xml) are NOT supported. * @return Pointer to the first matching attribute, or NULL if no match was found. */ struct attr * attr_search(struct attr **attrs, struct attr *last, enum attr_type attr) { dbg(lvl_info, "enter attrs=%p\n", attrs); while (*attrs) { dbg(lvl_debug,"*attrs=%p\n", *attrs); if ((*attrs)->type == attr) { return *attrs; } attrs++; } 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; } } /** * @brief Generic get function * * This function searches an attribute list for an attribute of a given type and * stores it in the attr parameter. If no match is found in attrs and the * def_attrs argument is supplied, def_attrs is searched for the attribute type * and the first match (if any) is returned. *

* Searching for attr_any or attr_any_xml is supported, but def_attrs will not * be searched in that case. *

* An iterator can be specified to get multiple attributes of the same type: * The first call will return the first match from attr; each subsequent call * with the same iterator will return the next match. After obtaining the last * match from attr, def_attrs is searched in the same manner. If no more matching * attributes are found in either of them, false is returned. * * @param attrs Points to the array of attribute pointers to be searched * @param def_attrs Points to a list of pointers to default attributes. * If an attribute is not found in attrs, the function will return the first * match from def_attrs. This parameter may be NULL. * @param type The attribute type to search for * @param attr Points to a {@code struct attr} which will receive the attribute * @param iter An iterator. This parameter may be NULL. * @return True if a matching attribute was found, false if not. */ 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 (attr_match(type,(*attrs)->type)) { *attr=**attrs; 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; return 1; } def_attrs++; } return 0; } /** * @brief Generic set function * * This function will search the list for the first attribute of the same type * as the supplied new one and replace it with that. If the list does not * contain an attribute whose type matches that of the new one, the new * attribute is inserted into the list. * * @param attrs Points to the array of attribute pointers to be updated * @param attr The new attribute. * @return Pointer to the updated attribute list */ struct attr ** attr_generic_set_attr(struct attr **attrs, struct attr *attr) { struct attr **curr=attrs; int i,count=0; while (curr && *curr) { if ((*curr)->type == attr->type) { attr_free(*curr); *curr=attr_dup(attr); return attrs; } curr++; count++; } curr=g_new0(struct attr *, count+2); for (i = 0 ; i < count ; i++) curr[i]=attrs[i]; curr[count]=attr_dup(attr); curr[count+1]=NULL; g_free(attrs); return curr; } /** * @brief Generic add function * * This function will insert a new attribute into the list. * * @param attrs Points to the array of attribute pointers to be updated * @param attr The new attribute. * @return Pointer to the updated attribute list */ struct attr ** attr_generic_add_attr(struct attr **attrs, struct attr *attr) { struct attr **curr=attrs; int i,count=0; while (curr && *curr) { curr++; count++; } curr=g_new0(struct attr *, count+2); for (i = 0 ; i < count ; i++) curr[i]=attrs[i]; curr[count]=attr_dup(attr); curr[count+1]=NULL; g_free(attrs); return curr; } struct attr ** attr_generic_add_attr_list(struct attr **attrs, struct attr **add) { while (add && *add) { attrs=attr_generic_add_attr(attrs, *add); add++; } return attrs; } struct attr ** attr_generic_prepend_attr(struct attr **attrs, struct attr *attr) { struct attr **curr=attrs; int i,count=0; while (curr && *curr) { curr++; count++; } curr=g_new0(struct attr *, count+2); for (i = 0 ; i < count ; i++) curr[i+1]=attrs[i]; curr[0]=attr_dup(attr); curr[count+1]=NULL; g_free(attrs); 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) { if (attr->type == attr_none) return 0; if (attr->type >= attr_type_string_begin && attr->type <= attr_type_string_end) return attr->u.str?strlen(attr->u.str)+1:0; if (attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) return sizeof(attr->u.num); if (attr->type >= attr_type_coord_geo_begin && attr->type <= attr_type_coord_geo_end) return sizeof(*attr->u.coord_geo); if (attr->type >= attr_type_color_begin && attr->type <= attr_type_color_end) return sizeof(*attr->u.color); if (attr->type >= attr_type_object_begin && attr->type <= attr_type_object_end) return sizeof(void *); if (attr->type >= attr_type_item_begin && attr->type <= attr_type_item_end) return sizeof(struct item); if (attr->type >= attr_type_int64_begin && attr->type <= attr_type_int64_end) return sizeof(*attr->u.num64); if (attr->type == attr_order) return sizeof(attr->u.range); if (attr->type >= attr_type_double_begin && attr->type <= attr_type_double_end) return sizeof(*attr->u.numd); 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_type_item_type_begin && attr->type <= attr_type_item_type_end) return 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(lvl_error,"size for %s unknown\n", attr_to_name(attr->type)); return 0; } void * attr_data_get(struct attr *attr) { if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) || (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end)) return &attr->u.num; if (attr->type == attr_order) return &attr->u.range; return attr->u.data; } void attr_data_set(struct attr *attr, void *data) { if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) || (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end)) attr->u.num=*((int *)data); else attr->u.data=data; } void attr_data_set_le(struct attr * attr, void * data) { if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) || (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end)) attr->u.num=le32_to_cpu(*((int *)data)); else if (attr->type == attr_order) { attr->u.num=le32_to_cpu(*((int *)data)); attr->u.range.min=le16_to_cpu(attr->u.range.min); attr->u.range.max=le16_to_cpu(attr->u.range.max); } else /* Fixme: Handle long long */ attr->u.data=data; } static void attr_free_content_do(struct attr *attr) { if (!attr) return; if (HAS_OBJECT_FUNC(attr->type)) { struct navit_object *obj=attr->u.data; if (obj && obj->func && obj->func->unref) obj->func->unref(obj); } 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); } void attr_free_content(struct attr *attr) { attr_free_content_do(attr); memset(attr,0,sizeof(*attr)); } void attr_free(struct attr *attr) { attr_free_content_do(attr); g_free(attr); } void attr_dup_content(struct attr *src, struct attr *dst) { int size; dst->type=src->type; if (src->type >= attr_type_int_begin && src->type <= attr_type_int_end) dst->u.num=src->u.num; else if (src->type >= attr_type_object_begin && src->type <= attr_type_object_end) { if (HAS_OBJECT_FUNC(src->type)) { struct navit_object *obj=src->u.data; if (obj && obj->func && obj->func->ref) { dst->u.data=obj->func->ref(obj); } else dst->u.data=obj; } else dst->u.data=src->u.data; } else { size=attr_data_size(src); if (size) { dst->u.data=g_malloc(size); memcpy(dst->u.data, src->u.data, size); } } } struct attr * attr_dup(struct attr *attr) { struct attr *ret=g_new0(struct attr, 1); attr_dup_content(attr, ret); return ret; } void attr_list_free(struct attr **attrs) { int count=0; while (attrs && attrs[count]) { attr_free(attrs[count++]); } g_free(attrs); } struct attr ** attr_list_dup(struct attr **attrs) { struct attr **ret; int i,count=0; if (!attrs) return NULL; while (attrs[count]) count++; ret=g_new0(struct attr *, count+1); for (i = 0 ; i < count ; i++) 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(lvl_debug,"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; } /** * @brief Checks if an enumeration of attribute types contains a specific attribute. * * @param types Points to a NULL-terminated array of pointers to {@code enum attr_type}, which will be searched * @param type The attr_type to be searched for * * @return True if the attribute type was found, false if it was not found or if {@code types} is empty */ 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; } /** * @brief Check if an enumeration of attribute types contains a specific attribute. * * This function is mostly identical to {@code attr_types_contains()} but returns the supplied default * value if {@code types} is empty. * * @param types Points to a NULL-terminated array of pointers to {@code enum attr_type}, which will be searched * @param type The attr_type to be searched for * @param deflt The default value to return if {@code types} is empty. * * @return True if the attribute type was found, false if it was not found, {@code deflt} if types is empty. */ 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); } /** * @brief Derive absolute value from relative attribute, given value of the whole range. * * @param attrval Value of u.num member of attribute capable of holding relative values. * @param whole Range counted as 100%. * @param treat_neg_as_rel Replace negative absolute values with whole+attr.u.num. * * @return Absolute value corresponding to given relative value. */ int attr_rel2real(int attrval, int whole, int treat_neg_as_rel) { if (attrval > ATTR_REL_MAXABS) return whole * (attrval - ATTR_REL_RELSHIFT)/100; if(treat_neg_as_rel && attrval<0 ) return whole+attrval; return attrval; }