"Fossies" - the Fresh Open Source Software Archive

Member "navit-0.5.6/navit/attr.c" (6 Mar 2021, 38847 Bytes) of package /linux/privat/navit-0.5.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "attr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.5_vs_0.5.6.

    1 /*
    2  * Navit, a modular navigation system.
    3  * Copyright (C) 2005-2008 Navit Team
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * version 2 as published by the Free Software Foundation.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the
   16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   17  * Boston, MA  02110-1301, USA.
   18  */
   19 
   20 /** @file attr.c
   21  * @brief Attribute handling code
   22  *
   23  * Structures and functions for working with attributes.
   24  *
   25  * @author Navit Team
   26  * @date 2005-2014
   27  */
   28 
   29 #include <stdlib.h>
   30 #include <string.h>
   31 #include <stdio.h>
   32 #include <glib.h>
   33 #include "debug.h"
   34 #include "item.h"
   35 #include "coord.h"
   36 #include "transform.h"
   37 #include "color.h"
   38 #include "navigation.h"
   39 #include "attr.h"
   40 #include "map.h"
   41 #include "config.h"
   42 #include "endianess.h"
   43 #include "util.h"
   44 #include "types.h"
   45 #include "xmlconfig.h"
   46 #include "layout.h"
   47 
   48 struct attr_name {
   49     enum attr_type attr;
   50     char *name;
   51 };
   52 
   53 
   54 /** List of attr_types with their names as strings. */
   55 static struct attr_name attr_names[]= {
   56 #define ATTR2(x,y) ATTR(y)
   57 #define ATTR(x) { attr_##x, #x },
   58 
   59 #define ATTR_UNUSED /* Unused attr_types not needed here.*/
   60 
   61 #include "attr_def.h"
   62 
   63 #undef ATTR_UNUSED
   64 
   65 #undef ATTR2
   66 #undef ATTR
   67 };
   68 
   69 static GHashTable *attr_hash;
   70 
   71 void attr_create_hash(void) {
   72     int i;
   73     attr_hash=g_hash_table_new(g_str_hash, g_str_equal);
   74     for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) {
   75         g_hash_table_insert(attr_hash, attr_names[i].name, GINT_TO_POINTER(attr_names[i].attr));
   76     }
   77 }
   78 
   79 void attr_destroy_hash(void) {
   80     g_hash_table_destroy(attr_hash);
   81     attr_hash=NULL;
   82 }
   83 
   84 /**
   85  * @brief Converts a string to an attr_type
   86  *
   87  * This function reads a string and returns the corresponding attr_type.
   88  *
   89  * @param name The attribute name
   90  * @return The corresponding {@code attr_type}, or {@code attr_none} if the string specifies a nonexistent or invalid attribute type.
   91  */
   92 enum attr_type attr_from_name(const char *name) {
   93     int i;
   94 
   95     if (attr_hash)
   96         return GPOINTER_TO_INT(g_hash_table_lookup(attr_hash, name));
   97     for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) {
   98         if (! strcmp(attr_names[i].name, name))
   99             return attr_names[i].attr;
  100     }
  101     return attr_none;
  102 }
  103 
  104 
  105 static int attr_match(enum attr_type search, enum attr_type found);
  106 
  107 
  108 
  109 /**
  110  * @brief Converts an attr_type to a string
  111  *
  112  * @param attr The attribute type to be converted.
  113  * @return The attribute name, or NULL if an invalid value was passed as {@code attr}.
  114  * The calling function should create a copy of the string if it needs to alter it or relies on the
  115  * string being available permanently.
  116  */
  117 char *attr_to_name(enum attr_type attr) {
  118     int i;
  119 
  120     for (i=0 ; i < sizeof(attr_names)/sizeof(struct attr_name) ; i++) {
  121         if (attr_names[i].attr == attr)
  122             return attr_names[i].name;
  123     }
  124     return NULL;
  125 }
  126 
  127 /**
  128  * @brief Creates an attribute from text information
  129  *
  130  * This function creates an attribute from two strings specifying the name and
  131  * the value.
  132  *
  133  * @param name The name of the new attribute
  134  * @param value The value of the new attribute
  135  * @return The new attribute
  136  */
  137 struct attr *
  138 attr_new_from_text(const char *name, const char *value) {
  139     enum attr_type attr;
  140     struct attr *ret;
  141     struct coord_geo *g;
  142     struct coord c;
  143     enum item_type item_type;
  144     char *pos,*type_str,*str,*tok;
  145     int min,max,count;
  146 
  147     ret=g_new0(struct attr, 1);
  148     dbg(lvl_debug,"enter name='%s' value='%s'", name, value);
  149     attr=attr_from_name(name);
  150     ret->type=attr;
  151     switch (attr) {
  152     case attr_item_type:
  153         ret->u.item_type=item_from_name(value);
  154         break;
  155     case attr_item_types:
  156         count=0;
  157         type_str=g_strdup(value);
  158         str=type_str;
  159         while ((tok=strtok(str, ","))) {
  160             ret->u.item_types=g_realloc(ret->u.item_types, (count+2)*sizeof(enum item_type));
  161             item_type=item_from_name(tok);
  162             if (item_type!=type_none) {
  163                 ret->u.item_types[count++]=item_type;
  164                 ret->u.item_types[count]=type_none;
  165             } else {
  166                 dbg(lvl_error,"Unknown item type '%s' ignored.",tok);
  167             }
  168             str=NULL;
  169         }
  170         g_free(type_str);
  171         break;
  172     case attr_attr_types:
  173         count=0;
  174         type_str=g_strdup(value);
  175         str=type_str;
  176         while ((tok=strtok(str, ","))) {
  177             ret->u.attr_types=g_realloc(ret->u.attr_types, (count+2)*sizeof(enum attr_type));
  178             ret->u.attr_types[count++]=attr_from_name(tok);
  179             ret->u.attr_types[count]=attr_none;
  180             str=NULL;
  181         }
  182         g_free(type_str);
  183         break;
  184     case attr_dash:
  185         count=0;
  186         type_str=g_strdup(value);
  187         str=type_str;
  188         while ((tok=strtok(str, ","))) {
  189             ret->u.dash=g_realloc(ret->u.dash, (count+2)*sizeof(int));
  190             ret->u.dash[count++]=g_ascii_strtoull(tok,NULL,0);
  191             ret->u.dash[count]=0;
  192             str=NULL;
  193         }
  194         g_free(type_str);
  195         break;
  196     case attr_order:
  197     case attr_sequence_range:
  198     case attr_angle_range:
  199     case attr_speed_range:
  200         pos=strchr(value, '-');
  201         min=0;
  202         max=32767;
  203         if (! pos) {
  204             sscanf(value,"%d",&min);
  205             max=min;
  206         } else if (pos == value)
  207             sscanf(value,"-%d",&max);
  208         else
  209             sscanf(value,"%d-%d",&min, &max);
  210         ret->u.range.min=min;
  211         ret->u.range.max=max;
  212         break;
  213     default:
  214         if (attr >= attr_type_string_begin && attr <= attr_type_string_end) {
  215             ret->u.str=g_strdup(value);
  216             break;
  217         }
  218         if (attr >= attr_type_int_begin && attr < attr_type_rel_abs_begin) {
  219             char *tail;
  220             if (value[0] == '0' && value[1] == 'x')
  221                 ret->u.num=strtoul(value, &tail, 0);
  222             else
  223                 ret->u.num=strtol(value, &tail, 0);
  224             if (*tail) {
  225                 dbg(lvl_error, "Incorrect value '%s' for attribute '%s';  expected a number. "
  226                     "Defaulting to 0.\n", value, name);
  227                 ret->u.num=0;
  228             }
  229             break;
  230         }
  231         if (attr >= attr_type_rel_abs_begin && attr < attr_type_boolean_begin) {
  232             char *tail;
  233             int value_is_relative=0;
  234             ret->u.num=strtol(value, &tail, 0);
  235             if (*tail) {
  236                 if (!strcmp(tail, "%")) {
  237                     value_is_relative=1;
  238                 } else {
  239                     dbg(lvl_error, "Incorrect value '%s' for attribute '%s';  expected a number or a relative value in percent. "
  240                         "Defaulting to 0.\n", value, name);
  241                     ret->u.num=0;
  242                 }
  243             }
  244             if (value_is_relative) {
  245                 if ((ret->u.num > ATTR_REL_MAXREL) || (ret->u.num < ATTR_REL_MINREL)) {
  246                     dbg(lvl_error, "Relative possibly-relative attribute with value out of range: %li", ret->u.num);
  247                 }
  248 
  249                 ret->u.num += ATTR_REL_RELSHIFT;
  250             } else {
  251                 if ((ret->u.num > ATTR_REL_MAXABS) || (ret->u.num < ATTR_REL_MINABS)) {
  252                     dbg(lvl_error, "Non-relative possibly-relative attribute with value out of range: %li", ret->u.num);
  253                 }
  254             }
  255             break;
  256         }
  257         if (attr >= attr_type_boolean_begin && attr <=  attr_type_int_end) {
  258             if (!(g_ascii_strcasecmp(value,"no") && g_ascii_strcasecmp(value,"0") && g_ascii_strcasecmp(value,"false")))
  259                 ret->u.num=0;
  260             else if (!(g_ascii_strcasecmp(value,"yes") && g_ascii_strcasecmp(value,"1") && g_ascii_strcasecmp(value,"true")))
  261                 ret->u.num=1;
  262             else {
  263                 dbg(lvl_error, "Incorrect value '%s' for attribute '%s';  expected a boolean (no/0/false or yes/1/true). "
  264                     "Defaulting to 'true'.\n", value, name);
  265                 ret->u.num=1;
  266             }
  267             break;
  268         }
  269         if (attr >= attr_type_color_begin && attr <= attr_type_color_end) {
  270             struct color *color=g_new0(struct color, 1);
  271             int r,g,b,a;
  272             ret->u.color=color;
  273             if(strlen(value)==7) {
  274                 sscanf(value,"#%02x%02x%02x", &r, &g, &b);
  275                 color->r = (r << 8) | r;
  276                 color->g = (g << 8) | g;
  277                 color->b = (b << 8) | b;
  278                 color->a = (65535);
  279             } else if(strlen(value)==9) {
  280                 sscanf(value,"#%02x%02x%02x%02x", &r, &g, &b, &a);
  281                 color->r = (r << 8) | r;
  282                 color->g = (g << 8) | g;
  283                 color->b = (b << 8) | b;
  284                 color->a = (a << 8) | a;
  285             } else {
  286                 dbg(lvl_error,"color %s has unknown format",value);
  287             }
  288             break;
  289         }
  290         if (attr >= attr_type_coord_geo_begin && attr <= attr_type_coord_geo_end) {
  291             g=g_new(struct coord_geo, 1);
  292             ret->u.coord_geo=g;
  293             coord_parse(value, projection_mg, &c);
  294             transform_to_geo(projection_mg, &c, g);
  295             break;
  296         }
  297         dbg(lvl_debug,"unknown attribute");
  298         g_free(ret);
  299         ret=NULL;
  300     }
  301     return ret;
  302 }
  303 
  304 /**
  305  * @brief Converts access flags to a human-readable string.
  306  *
  307  * @param flags The flags as a number
  308  * @return The flags in human-readable form
  309  */
  310 static char *flags_to_text(int flags) {
  311     char *ret=g_strdup_printf("0x%x:",flags);
  312     if (flags & AF_ONEWAY) ret=g_strconcat_printf(ret,"%sAF_ONEWAY",ret?"|":"");
  313     if (flags & AF_ONEWAYREV) ret=g_strconcat_printf(ret,"%sAF_ONEWAYREV",ret?"|":"");
  314     if (flags & AF_SEGMENTED) ret=g_strconcat_printf(ret,"%sAF_SEGMENTED",ret?"|":"");
  315     if (flags & AF_ROUNDABOUT) ret=g_strconcat_printf(ret,"%sAF_ROUNDABOUT",ret?"|":"");
  316     if (flags & AF_ROUNDABOUT_VALID) ret=g_strconcat_printf(ret,"%sAF_ROUNDABOUT_VALID",ret?"|":"");
  317     if (flags & AF_ONEWAY_EXCEPTION) ret=g_strconcat_printf(ret,"%sAF_ONEWAY_EXCEPTION",ret?"|":"");
  318     if (flags & AF_SPEED_LIMIT) ret=g_strconcat_printf(ret,"%sAF_SPEED_LIMIT",ret?"|":"");
  319     if (flags & AF_RESERVED1) ret=g_strconcat_printf(ret,"%sAF_RESERVED1",ret?"|":"");
  320     if (flags & AF_SIZE_OR_WEIGHT_LIMIT) ret=g_strconcat_printf(ret,"%sAF_SIZE_OR_WEIGHT_LIMIT",ret?"|":"");
  321     if (flags & AF_THROUGH_TRAFFIC_LIMIT) ret=g_strconcat_printf(ret,"%sAF_THROUGH_TRAFFIC_LIMIT",ret?"|":"");
  322     if (flags & AF_TOLL) ret=g_strconcat_printf(ret,"%sAF_TOLL",ret?"|":"");
  323     if (flags & AF_SEASONAL) ret=g_strconcat_printf(ret,"%sAF_SEASONAL",ret?"|":"");
  324     if (flags & AF_UNPAVED) ret=g_strconcat_printf(ret,"%sAF_UNPAVED",ret?"|":"");
  325     if (flags & AF_FORD) ret=g_strconcat_printf(ret,"%sAF_FORD",ret?"|":"");
  326     if (flags & AF_UNDERGROUND) ret=g_strconcat_printf(ret,"%sAF_UNDERGROUND",ret?"|":"");
  327     if (flags & AF_DANGEROUS_GOODS) ret=g_strconcat_printf(ret,"%sAF_DANGEROUS_GOODS",ret?"|":"");
  328     if ((flags & AF_ALL) == AF_ALL)
  329         return g_strconcat_printf(ret,"%sAF_ALL",ret?"|":"");
  330     if ((flags & AF_ALL) == AF_MOTORIZED_FAST)
  331         return g_strconcat_printf(ret,"%sAF_MOTORIZED_FAST",ret?"|":"");
  332     if (flags & AF_EMERGENCY_VEHICLES) ret=g_strconcat_printf(ret,"%sAF_EMERGENCY_VEHICLES",ret?"|":"");
  333     if (flags & AF_TRANSPORT_TRUCK) ret=g_strconcat_printf(ret,"%sAF_TRANSPORT_TRUCK",ret?"|":"");
  334     if (flags & AF_DELIVERY_TRUCK) ret=g_strconcat_printf(ret,"%sAF_DELIVERY_TRUCK",ret?"|":"");
  335     if (flags & AF_PUBLIC_BUS) ret=g_strconcat_printf(ret,"%sAF_PUBLIC_BUS",ret?"|":"");
  336     if (flags & AF_TAXI) ret=g_strconcat_printf(ret,"%sAF_TAXI",ret?"|":"");
  337     if (flags & AF_HIGH_OCCUPANCY_CAR) ret=g_strconcat_printf(ret,"%sAF_HIGH_OCCUPANCY_CAR",ret?"|":"");
  338     if (flags & AF_CAR) ret=g_strconcat_printf(ret,"%sAF_CAR",ret?"|":"");
  339     if (flags & AF_MOTORCYCLE) ret=g_strconcat_printf(ret,"%sAF_MOTORCYCLE",ret?"|":"");
  340     if (flags & AF_MOPED) ret=g_strconcat_printf(ret,"%sAF_MOPED",ret?"|":"");
  341     if (flags & AF_HORSE) ret=g_strconcat_printf(ret,"%sAF_HORSE",ret?"|":"");
  342     if (flags & AF_BIKE) ret=g_strconcat_printf(ret,"%sAF_BIKE",ret?"|":"");
  343     if (flags & AF_PEDESTRIAN) ret=g_strconcat_printf(ret,"%sAF_PEDESTRIAN",ret?"|":"");
  344     return ret;
  345 }
  346 
  347 /**
  348  * @brief Converts attribute data to human-readable text
  349  *
  350  * @param attr The attribute to be formatted
  351  * @param sep The separator to insert between a numeric value and its unit. If NULL, nothing will be inserted.
  352  * @param fmt Set to {@code attr_format_with_units} if {@code attr} is of type {@code attr_destination_length}
  353  * or {@code attr_destination_time} or a group type which might contain attributes of those types. Ignored for
  354  * all other attribute types.
  355  * @param def_fmt Not used
  356  * @param map The translation map. This is only needed for string type attributes or group type
  357  * attributes which might contain strings. It can be NULL for other attribute types. If a string
  358  * type attribute is encountered and {@code map} is NULL, the string will be returned unchanged.
  359  *
  360  * @return The attribute data in human-readable form. The caller is responsible for calling {@code g_free()} on
  361  * the result when it is no longer needed.
  362  */
  363 char *attr_to_text_ext(struct attr *attr, char *sep, enum attr_format fmt, enum attr_format def_fmt, struct map *map) {
  364     char *ret;
  365     enum attr_type type=attr->type;
  366 
  367     if (!sep)
  368         sep="";
  369 
  370     if (type >= attr_type_item_begin && type <= attr_type_item_end) {
  371         struct item *item=attr->u.item;
  372         struct attr type, data;
  373         if (! item)
  374             return g_strdup("(nil)");
  375         if (! item->map || !map_get_attr(item->map, attr_type, &type, NULL))
  376             type.u.str="";
  377         if (! item->map || !map_get_attr(item->map, attr_data, &data, NULL))
  378             data.u.str="";
  379         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,
  380                                type.u.str, data.u.str);
  381     }
  382     if (type >= attr_type_string_begin && type <= attr_type_string_end) {
  383         if (map) {
  384             char *mstr;
  385             if (attr->u.str) {
  386                 mstr=map_convert_string(map, attr->u.str);
  387                 ret=g_strdup(mstr);
  388                 map_convert_free(mstr);
  389             } else
  390                 ret=g_strdup("(null)");
  391 
  392         } else
  393             ret=g_strdup(attr->u.str);
  394         return ret;
  395     }
  396     if (type == attr_flags || type == attr_through_traffic_flags)
  397         return flags_to_text(attr->u.num);
  398     if (type == attr_destination_length) {
  399         if (fmt == attr_format_with_units) {
  400             double distance=attr->u.num;
  401             if (distance > 10000)
  402                 return g_strdup_printf("%.0f%skm",distance/1000,sep);
  403             return g_strdup_printf("%.1f%skm",distance/1000,sep);
  404         }
  405     }
  406     if (type == attr_destination_time) {
  407         if (fmt == attr_format_with_units) {
  408             int seconds=(attr->u.num+5)/10;
  409             int minutes=seconds/60;
  410             int hours=minutes/60;
  411             int days=hours/24;
  412             hours%=24;
  413             minutes%=60;
  414             seconds%=60;
  415             if (days)
  416                 return g_strdup_printf("%d:%02d:%02d:%02d",days,hours,minutes,seconds);
  417             if (hours)
  418                 return g_strdup_printf("%02d:%02d:%02d",hours,minutes,seconds);
  419             return g_strdup_printf("%02d:%02d",minutes,seconds);
  420         }
  421     }
  422     if (type >= attr_type_int_begin && type <= attr_type_int_end)
  423         return g_strdup_printf("%ld", attr->u.num);
  424     if (type >= attr_type_int64_begin && type <= attr_type_int64_end)
  425         return g_strdup_printf(LONGLONG_FMT, *attr->u.num64);
  426     if (type >= attr_type_double_begin && type <= attr_type_double_end)
  427         return g_strdup_printf("%f", *attr->u.numd);
  428     if (type >= attr_type_object_begin && type <= attr_type_object_end)
  429         return g_strdup_printf("(object[%s])", attr_to_name(type));
  430     if (type >= attr_type_color_begin && type <= attr_type_color_end) {
  431         if (attr->u.color->a != 65535)
  432             return g_strdup_printf("#%02x%02x%02x%02x", attr->u.color->r>>8,attr->u.color->g>>8,attr->u.color->b>>8,
  433                                    attr->u.color->a>>8);
  434         else
  435             return g_strdup_printf("#%02x%02x%02x", attr->u.color->r>>8,attr->u.color->g>>8,attr->u.color->b>>8);
  436     }
  437     if (type >= attr_type_coord_geo_begin && type <= attr_type_coord_geo_end)
  438         return g_strdup_printf("%f %f",attr->u.coord_geo->lng,attr->u.coord_geo->lat);
  439     if (type == attr_zipfile_ref_block) {
  440         int *data=attr->u.data;
  441         return g_strdup_printf("0x%x,0x%x,0x%x",data[0],data[1],data[2]);
  442     }
  443     if (type == attr_item_id) {
  444         int *data=attr->u.data;
  445         return g_strdup_printf("0x%x,0x%x",data[0],data[1]);
  446     }
  447     if (type == attr_item_types) {
  448         enum item_type *item_types=attr->u.item_types;
  449         char *sep="",*ret=NULL;
  450         while (item_types && *item_types) {
  451             ret=g_strconcat_printf(ret,"%s%s",sep,item_to_name(*item_types++));
  452             sep=",";
  453         }
  454         return ret;
  455     }
  456     if (type >= attr_type_group_begin && type <= attr_type_group_end) {
  457         int i=0;
  458         char *ret=g_strdup("");
  459         char *sep="";
  460         while (attr->u.attrs[i].type) {
  461             char *val=attr_to_text_ext(&attr->u.attrs[i], sep, fmt, def_fmt, map);
  462             ret=g_strconcat_printf(ret,"%s%s=%s",sep,attr_to_name(attr->u.attrs[i].type),val);
  463             g_free(val);
  464             sep=" ";
  465             i++;
  466         }
  467         return ret;
  468     }
  469     if (type >= attr_type_item_type_begin && type <= attr_type_item_type_end) {
  470         return g_strdup_printf("0x%ld[%s]",attr->u.num,item_to_name(attr->u.num));
  471     }
  472     if (type == attr_nav_status) {
  473         return nav_status_to_text(attr->u.num);
  474     }
  475     if (type == attr_poly_hole) {
  476         return g_strdup_printf("count=%d", attr->u.poly_hole->coord_count);
  477     }
  478     return g_strdup_printf("(no text[%s])", attr_to_name(type));
  479 }
  480 
  481 /**
  482  * @brief Converts an attribute to a string that can be displayed
  483  *
  484  * This function is just a wrapper around {@code attr_to_text_ext()}.
  485  *
  486  * @param attr The attribute to convert
  487  * @param map The translation map, see {@code attr_to_text_ext()}
  488  * @param pretty Not used
  489  */
  490 char *attr_to_text(struct attr *attr, struct map *map, int pretty) {
  491     return attr_to_text_ext(attr, NULL, attr_format_default, attr_format_default, map);
  492 }
  493 
  494 /**
  495  * @brief Searches for an attribute of a given type
  496  *
  497  * This function searches an array of pointers to attributes for a given
  498  * attribute type and returns the first match.
  499  *
  500  * @param attrs Points to the array of attribute pointers to be searched
  501  * @param attr_type The attribute type to search for. Generic types (such as
  502  * attr_any or attr_any_xml) are NOT supported.
  503  * @return Pointer to the first matching attribute, or NULL if no match was found.
  504  */
  505 struct attr *
  506 attr_search(struct attr **attrs, enum attr_type attr) {
  507     dbg(lvl_info, "enter attrs=%p", attrs);
  508     while (*attrs) {
  509         dbg(lvl_debug,"*attrs=%p", *attrs);
  510         if ((*attrs)->type == attr) {
  511             return *attrs;
  512         }
  513         attrs++;
  514     }
  515     return NULL;
  516 }
  517 
  518 static int attr_match(enum attr_type search, enum attr_type found) {
  519     switch (search) {
  520     case attr_any:
  521         return 1;
  522     case attr_any_xml:
  523         switch (found) {
  524         case attr_callback:
  525             return 0;
  526         default:
  527             return 1;
  528         }
  529     default:
  530         return search == found;
  531     }
  532 }
  533 
  534 /**
  535  * @brief Generic get function
  536  *
  537  * This function searches an attribute list for an attribute of a given type and
  538  * stores it in the attr parameter. If no match is found in attrs and the
  539  * def_attrs argument is supplied, def_attrs is searched for the attribute type
  540  * and the first match (if any) is returned.
  541  * <p>
  542  * Searching for attr_any or attr_any_xml is supported, but def_attrs will not
  543  * be searched in that case.
  544  * <p>
  545  * An iterator can be specified to get multiple attributes of the same type:
  546  * The first call will return the first match from attr; each subsequent call
  547  * with the same iterator will return the next match. After obtaining the last
  548  * match from attr, def_attrs is searched in the same manner. If no more matching
  549  * attributes are found in either of them, false is returned.
  550  *
  551  * @param attrs Points to the array of attribute pointers to be searched
  552  * @param def_attrs Points to a list of pointers to default attributes.
  553  * If an attribute is not found in attrs, the function will return the first
  554  * match from def_attrs. This parameter may be NULL.
  555  * @param type The attribute type to search for
  556  * @param attr Points to a {@code struct attr} which will receive the attribute
  557  * @param iter An iterator. This parameter may be NULL.
  558  * @return True if a matching attribute was found, false if not.
  559  */
  560 int attr_generic_get_attr(struct attr **attrs, struct attr **def_attrs, enum attr_type type, struct attr *attr,
  561                           struct attr_iter *iter) {
  562     while (attrs && *attrs) {
  563         if (attr_match(type,(*attrs)->type)) {
  564             *attr=**attrs;
  565             if (!iter)
  566                 return 1;
  567             if (*((void **)iter) < (void *)attrs) {
  568                 *((void **)iter)=(void *)attrs;
  569                 return 1;
  570             }
  571         }
  572         attrs++;
  573     }
  574     if (type == attr_any || type == attr_any_xml)
  575         return 0;
  576     while (def_attrs && *def_attrs) {
  577         if ((*def_attrs)->type == type) {
  578             *attr=**def_attrs;
  579             return 1;
  580         }
  581         def_attrs++;
  582     }
  583     return 0;
  584 }
  585 
  586 /**
  587  * @brief Generic set function
  588  *
  589  * This function will search the list for the first attribute of the same type
  590  * as the supplied new one and replace it with that. If the list does not
  591  * contain an attribute whose type matches that of the new one, the new
  592  * attribute is inserted into the list.
  593  *
  594  * @param attrs Points to the array of attribute pointers to be updated (if NULL, this function will
  595  * create a new list containing only the new attribute)
  596  * @param attr The new attribute.
  597  * @return Pointer to the updated attribute list
  598  */
  599 struct attr **
  600 attr_generic_set_attr(struct attr **attrs, struct attr *attr) {
  601     struct attr **curr=attrs;
  602     int i,count=0;
  603     dbg(lvl_debug, "enter, attrs=%p, attr=%p (%s)", attrs, attr, attr_to_name(attr->type));
  604     while (curr && *curr) {
  605         if ((*curr)->type == attr->type) {
  606             attr_free(*curr);
  607             *curr=attr_dup(attr);
  608             return attrs;
  609         }
  610         curr++;
  611         count++;
  612     }
  613     curr=g_new0(struct attr *, count+2);
  614     for (i = 0 ; i < count ; i++)
  615         curr[i]=attrs[i];
  616     curr[count]=attr_dup(attr);
  617     curr[count+1]=NULL;
  618     g_free(attrs);
  619     return curr;
  620 }
  621 
  622 /**
  623  * @brief Generic add function
  624  *
  625  * This function will insert a new attribute into the list.
  626  *
  627  * @param attrs Points to the array of attribute pointers to be updated
  628  * @param attr The new attribute.
  629  * @return Pointer to the updated attribute list
  630  */
  631 struct attr **
  632 attr_generic_add_attr(struct attr **attrs, struct attr *attr) {
  633     struct attr **curr=attrs;
  634     int i,count=0;
  635     dbg(lvl_debug, "enter, attrs=%p, attr=%p (%s)", attrs, attr, attr_to_name(attr->type));
  636     while (curr && *curr) {
  637         curr++;
  638         count++;
  639     }
  640     curr=g_new0(struct attr *, count+2);
  641     for (i = 0 ; i < count ; i++)
  642         curr[i]=attrs[i];
  643     curr[count]=attr_dup(attr);
  644     curr[count+1]=NULL;
  645     g_free(attrs);
  646     return curr;
  647 }
  648 
  649 struct attr **
  650 attr_generic_add_attr_list(struct attr **attrs, struct attr **add) {
  651     while (add && *add) {
  652         attrs=attr_generic_add_attr(attrs, *add);
  653         add++;
  654     }
  655     return attrs;
  656 }
  657 
  658 struct attr **
  659 attr_generic_prepend_attr(struct attr **attrs, struct attr *attr) {
  660     struct attr **curr=attrs;
  661     int i,count=0;
  662     while (curr && *curr) {
  663         curr++;
  664         count++;
  665     }
  666     curr=g_new0(struct attr *, count+2);
  667     for (i = 0 ; i  < count ; i++)
  668         curr[i+1]=attrs[i];
  669     curr[0]=attr_dup(attr);
  670     curr[count+1]=NULL;
  671     g_free(attrs);
  672     return curr;
  673 }
  674 
  675 /**
  676  * @brief Removes an attribute from an attribute list.
  677  *
  678  * If `attrs` contains `attr`, a new attribute list is created (which contains all attributes, except
  679  * for `attr`) and both `attrs` (the original attribute list) and `attr` are freed.
  680  *
  681  * If `attrs` does not contain `attr`, this function is a no-op.
  682  *
  683  * Attributes are matched based on their `type` and `u.data` members, thus `attr` can be a shallow copy
  684  * of the attribute, and can match multiple attributes in the list. The `attr` argument itself is not
  685  * changed.
  686  *
  687  * @param attrs The attribute list
  688  * @param attr The attribute to remove from the list
  689  *
  690  * @return The new attribute list
  691  */
  692 struct attr **
  693 attr_generic_remove_attr(struct attr **attrs, struct attr *attr) {
  694     struct attr **curr=attrs;
  695     int i,j,count=0,found=0;
  696     while (curr && *curr) {
  697         if ((*curr)->type == attr->type && (*curr)->u.data == attr->u.data)
  698             found=1;
  699         curr++;
  700         count++;
  701     }
  702     if (!found)
  703         return attrs;
  704     curr=g_new0(struct attr *, count);
  705     j=0;
  706     for (i = 0 ; i < count ; i++) {
  707         if (attrs[i]->type != attr->type || attrs[i]->u.data != attr->u.data)
  708             curr[j++]=attrs[i];
  709         else
  710             attr_free(attrs[i]);
  711     }
  712     curr[j]=NULL;
  713     g_free(attrs);
  714     return curr;
  715 }
  716 
  717 enum attr_type attr_type_begin(enum attr_type type) {
  718     if (type < attr_type_item_begin)
  719         return attr_none;
  720     if (type < attr_type_int_begin)
  721         return attr_type_item_begin;
  722     if (type < attr_type_string_begin)
  723         return attr_type_int_begin;
  724     if (type < attr_type_special_begin)
  725         return attr_type_string_begin;
  726     if (type < attr_type_double_begin)
  727         return attr_type_special_begin;
  728     if (type < attr_type_coord_geo_begin)
  729         return attr_type_double_begin;
  730     if (type < attr_type_color_begin)
  731         return attr_type_coord_geo_begin;
  732     if (type < attr_type_object_begin)
  733         return attr_type_color_begin;
  734     if (type < attr_type_coord_begin)
  735         return attr_type_object_begin;
  736     if (type < attr_type_pcoord_begin)
  737         return attr_type_coord_begin;
  738     if (type < attr_type_callback_begin)
  739         return attr_type_pcoord_begin;
  740     if (type < attr_type_int64_begin)
  741         return attr_type_callback_begin;
  742     if (type <= attr_type_int64_end)
  743         return attr_type_int64_begin;
  744     return attr_none;
  745 }
  746 
  747 int attr_data_size(struct attr *attr) {
  748     if (attr->type == attr_none)
  749         return 0;
  750     if (attr->type >= attr_type_string_begin && attr->type <= attr_type_string_end)
  751         return attr->u.str?strlen(attr->u.str)+1:0;
  752     if (attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end)
  753         return sizeof(attr->u.num);
  754     if (attr->type >= attr_type_coord_geo_begin && attr->type <= attr_type_coord_geo_end)
  755         return sizeof(*attr->u.coord_geo);
  756     if (attr->type >= attr_type_color_begin && attr->type <= attr_type_color_end)
  757         return sizeof(*attr->u.color);
  758     if (attr->type >= attr_type_object_begin && attr->type <= attr_type_object_end)
  759         return sizeof(void *);
  760     if (attr->type >= attr_type_item_begin && attr->type <= attr_type_item_end)
  761         return sizeof(struct item);
  762     if (attr->type >= attr_type_int64_begin && attr->type <= attr_type_int64_end)
  763         return sizeof(*attr->u.num64);
  764     if (attr->type == attr_order)
  765         return sizeof(attr->u.range);
  766     if (attr->type >= attr_type_double_begin && attr->type <= attr_type_double_end)
  767         return sizeof(*attr->u.numd);
  768     if (attr->type == attr_item_types) {
  769         int i=0;
  770         while (attr->u.item_types[i++] != type_none);
  771         return i*sizeof(enum item_type);
  772     }
  773     if (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end)
  774         return sizeof(enum item_type);
  775     if (attr->type == attr_attr_types) {
  776         int i=0;
  777         while (attr->u.attr_types[i++] != attr_none);
  778         return i*sizeof(enum attr_type);
  779     }
  780     if (attr->type == attr_poly_hole) {
  781         return (sizeof(attr->u.poly_hole->coord_count) + (attr->u.poly_hole->coord_count * sizeof(*attr->u.poly_hole->coord)));
  782     }
  783     dbg(lvl_error,"size for %s unknown", attr_to_name(attr->type));
  784     return 0;
  785 }
  786 
  787 void *attr_data_get(struct attr *attr) {
  788     if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) ||
  789             (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end))
  790         return &attr->u.num;
  791     if (attr->type == attr_order)
  792         return &attr->u.range;
  793     return attr->u.data;
  794 }
  795 
  796 void attr_data_set(struct attr *attr, void *data) {
  797     if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) ||
  798             (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end))
  799         attr->u.num=*((int *)data);
  800     else
  801         attr->u.data=data;
  802 }
  803 
  804 void attr_data_set_le(struct attr * attr, void * data) {
  805     if ((attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) ||
  806             (attr->type >= attr_type_item_type_begin && attr->type <= attr_type_item_type_end))
  807         attr->u.num=le32_to_cpu(*((int *)data));
  808     else if (attr->type == attr_order) {
  809         attr->u.num=le32_to_cpu(*((int *)data));
  810         attr->u.range.min=le16_to_cpu(attr->u.range.min);
  811         attr->u.range.max=le16_to_cpu(attr->u.range.max);
  812     } else
  813         /* Fixme: Handle long long */
  814         attr->u.data=data;
  815 
  816 }
  817 
  818 static void attr_free_content_do(struct attr *attr) {
  819     if (!attr)
  820         return;
  821     if (HAS_OBJECT_FUNC(attr->type)) {
  822         struct navit_object *obj=attr->u.data;
  823         if (obj && obj->func && obj->func->unref)
  824             obj->func->unref(obj);
  825     }
  826     if (!(attr->type >= attr_type_int_begin && attr->type <= attr_type_int_end) &&
  827             !(attr->type >= attr_type_object_begin && attr->type <= attr_type_object_end) &&
  828             attr->type != attr_item_type)
  829         g_free(attr->u.data);
  830 }
  831 
  832 void attr_free_content(struct attr *attr) {
  833     attr_free_content_do(attr);
  834     memset(attr,0,sizeof(*attr));
  835 }
  836 
  837 void attr_free(struct attr *attr) {
  838     attr_free_content_do(attr);
  839     g_free(attr);
  840 }
  841 
  842 void attr_free_g(struct attr *attr, void * unused) {
  843     attr_free(attr);
  844 }
  845 
  846 void attr_dup_content(struct attr *src, struct attr *dst) {
  847     int size;
  848     dst->type=src->type;
  849     if (src->type >= attr_type_int_begin && src->type <= attr_type_int_end)
  850         dst->u.num=src->u.num;
  851     else if (src->type == attr_item_type)
  852         dst->u.item_type=src->u.item_type;
  853     else if (src->type >= attr_type_object_begin && src->type <= attr_type_object_end) {
  854         if (HAS_OBJECT_FUNC(src->type)) {
  855             struct navit_object *obj=src->u.data;
  856             if (obj && obj->func && obj->func->ref) {
  857                 dst->u.data=obj->func->ref(obj);
  858             } else
  859                 dst->u.data=obj;
  860         } else
  861             dst->u.data=src->u.data;
  862     } else {
  863         size=attr_data_size(src);
  864         if (size) {
  865             dst->u.data=g_malloc(size);
  866             memcpy(dst->u.data, src->u.data, size);
  867         }
  868     }
  869 }
  870 
  871 struct attr *
  872 attr_dup(struct attr *attr) {
  873     struct attr *ret=g_new0(struct attr, 1);
  874     attr_dup_content(attr, ret);
  875     return ret;
  876 }
  877 
  878 /**
  879  * @brief Frees a list of attributes.
  880  *
  881  * This frees the pointer array as well as the attributes referenced by the pointers.
  882  *
  883  * It is safe to call this function with a NULL argument; doing so is a no-op.
  884  *
  885  * @param attrs The attribute list to free
  886  */
  887 void attr_list_free(struct attr **attrs) {
  888     int count=0;
  889     while (attrs && attrs[count]) {
  890         attr_free(attrs[count++]);
  891     }
  892     g_free(attrs);
  893 }
  894 
  895 /**
  896  * @brief Duplicates a list of attributes.
  897  *
  898  * This creates a deep copy, i.e. the attributes in the list are copied as well.
  899  *
  900  * It is safe to call this function with a NULL argument; in this case, NULL will be returned.
  901  *
  902  * @param attrs The attribute list to copy
  903  *
  904  * @return The copy of the attribute list
  905  */
  906 struct attr **
  907 attr_list_dup(struct attr **attrs) {
  908     struct attr **ret;
  909     int i,count=0;
  910 
  911     if (!attrs)
  912         return NULL;
  913 
  914     while (attrs[count])
  915         count++;
  916     ret=g_new0(struct attr *, count+1);
  917     for (i = 0 ; i < count ; i++)
  918         ret[i]=attr_dup(attrs[i]);
  919     return ret;
  920 }
  921 
  922 /**
  923  * @brief Retrieves an attribute from a line in textfile format.
  924  *
  925  * If `name` is NULL, this function returns the first attribute found; otherwise it looks for an attribute
  926  * named `name`.
  927  *
  928  * If `pos` is specified, it acts as an offset pointer: Any data in `line` before `*pos` will be skipped.
  929  * When the function returns, the value pointed to by `pos` will be incremented by the number of characters
  930  * parsed. This can be used to iteratively retrieve all attributes: declare a local variable, set it to zero,
  931  * then iteratively call this function with a pointer to the same variable until it returns false.
  932  *
  933  * `val_ret` must be allocated (and later freed) by the caller, and have sufficient capacity to hold the
  934  * parsed value including the terminating NULL character. The minimum safe size is
  935  * `strlen(line) - strlen(name) - *pos` (assuming zero for NULL pointers).
  936  *
  937  * @param[in] line The line to parse, must be non-NULL and pointing to a NUL terminated string
  938  * @param[in] name The name of the attribute to retrieve; can be NULL (see description)
  939  * @param[in,out] pos As input, if pointer is non-NULL, this argument contains the character index inside @p line from which to start the search (see description)
  940  * @param[out] val_ret Points to a buffer which will receive the value as text
  941  * @param[out] name_ret Points to a buffer which will receive the actual name of the attribute found in the line, if NULL this argument won't be used. Note that the buffer provided here should be long enough to contain the attribute name + a terminating NUL character
  942  *
  943  * @return true if successful, false in case of failure
  944  */
  945 int attr_from_line(const char *line, const char *name, int *pos, char *val_ret, char *name_ret) {
  946     int len=0,quoted,escaped;
  947     const char *p;
  948     char *e;
  949     const char *n;
  950 
  951     dbg(lvl_debug,"get_tag %s from %s", name, line);
  952     if (name)
  953         len=strlen(name);
  954     if (pos)
  955         p=line+*pos;
  956     else
  957         p=line;
  958     for(;;) {
  959         while (*p == ' ') {
  960             p++;
  961         }
  962         if (! *p)
  963             return 0;
  964         n=p;
  965         e=strchr(p,'=');
  966         if (! e)
  967             return 0;
  968         p=e+1;
  969         quoted=0;
  970         escaped=0;
  971         while (*p) {
  972             if (*p == ' ' && !quoted)
  973                 break;
  974             if (*p == '"')
  975                 quoted=1-quoted;
  976             if (*p == '\\') {   /* Next character is escaped */
  977                 escaped++;
  978                 if (*(p+1)) /* Make sure the string is not terminating just after this escape character */
  979                     p++;    /* if the string continues, skip the next character, whatever is is (space, double-quote or backslash) */
  980                 else
  981                     dbg(lvl_warning, "Trailing backslash in input string \"%s\"", line);
  982             }
  983             p++;
  984         }
  985         if (name == NULL || (e-n == len && strncmp(n, name, len)==0)) { /* We matched the searched attribute name */
  986             if (name_ret) { /* If instructed to, store the actual name into the string pointed by name_ret */
  987                 len=e-n;
  988                 strncpy(name_ret, n, len);
  989                 name_ret[len]='\0';
  990             }
  991             e++;
  992             len=p-e;
  993             if (e[0] == '"') {
  994                 e++;
  995                 len-=2;
  996             }
  997             /* Note: in the strncpy* calls below, we give a max size_t argument exactly matching the string lengh we want to copy within the source string e, so no terminating NUL char will be appended */
  998             if (escaped)
  999                 strncpy_unescape(val_ret, e, len-escaped);  /* Unescape if necessary */
 1000             else
 1001                 strncpy(val_ret, e, len);
 1002             /* Because no NUL terminating char was copied over, we manually append it here to terminate the C-string properly, just after the copied string */
 1003             val_ret[len-escaped]='\0';
 1004             if (pos)
 1005                 *pos=p-line;
 1006             return 1;
 1007         }
 1008     }
 1009     return 0;
 1010 }
 1011 
 1012 /**
 1013  * @brief Checks if an enumeration of attribute types contains a specific attribute.
 1014  *
 1015  * @param types Points to a NULL-terminated array of pointers to {@code enum attr_type}, which will be searched
 1016  * @param type The attr_type to be searched for
 1017  *
 1018  * @return True if the attribute type was found, false if it was not found or if {@code types} is empty
 1019  */
 1020 int attr_types_contains(enum attr_type *types, enum attr_type type) {
 1021     while (types && *types != attr_none) {
 1022         if (*types == type)
 1023             return 1;
 1024         types++;
 1025     }
 1026     return 0;
 1027 }
 1028 
 1029 /**
 1030  * @brief Check if an enumeration of attribute types contains a specific attribute.
 1031  *
 1032  * This function is mostly identical to {@code attr_types_contains()} but returns the supplied default
 1033  * value if {@code types} is empty.
 1034  *
 1035  * @param types Points to a NULL-terminated array of pointers to {@code enum attr_type}, which will be searched
 1036  * @param type The attr_type to be searched for
 1037  * @param deflt The default value to return if {@code types} is empty.
 1038  *
 1039  * @return True if the attribute type was found, false if it was not found, {@code deflt} if types is empty.
 1040  */
 1041 int attr_types_contains_default(enum attr_type *types, enum attr_type type, int deflt) {
 1042     if (!types) {
 1043         return deflt;
 1044     }
 1045     return attr_types_contains(types, type);
 1046 }
 1047 
 1048 /**
 1049  * @brief Derive absolute value from relative attribute, given value of the whole range.
 1050  *
 1051  * @param attrval Value of u.num member of attribute capable of holding relative values.
 1052  * @param whole Range counted as 100%.
 1053  * @param treat_neg_as_rel Replace negative absolute values with whole+attr.u.num.
 1054  *
 1055  * @return Absolute value corresponding to given relative value.
 1056  */
 1057 int attr_rel2real(int attrval, int whole, int treat_neg_as_rel) {
 1058     if (attrval > ATTR_REL_MAXABS)
 1059         return whole * (attrval - ATTR_REL_RELSHIFT)/100;
 1060     if(treat_neg_as_rel && attrval<0 )
 1061         return whole+attrval;
 1062     return attrval;
 1063 }
 1064