Diff of /trunk/src/osm.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 28 by achadwick, Wed Dec 24 14:17:20 2008 UTC revision 175 by harbaum, Wed Jun 10 09:24:47 2009 UTC
# Line 17  Line 17 
17   * along with OSM2Go.  If not, see <http://www.gnu.org/licenses/>.   * along with OSM2Go.  If not, see <http://www.gnu.org/licenses/>.
18   */   */
19    
 #define OSM_STREAM_PARSER  
   
20  #include <stdio.h>  #include <stdio.h>
21  #include <stdlib.h>  #include <stdlib.h>
22  #include <string.h>  #include <string.h>
# Line 37  Line 35 
35  #error "Tree not enabled in libxml"  #error "Tree not enabled in libxml"
36  #endif  #endif
37    
 /* determine where a node/way/relation read from the osm file */  
 /* is inserted into the internal database */  
 // #define OSM_SORT_ID  
 #define OSM_SORT_LAST  
 // #define OSM_SORT_FIRST  
   
38  /* ------------------------- bounds handling --------------------- */  /* ------------------------- bounds handling --------------------- */
39    
40  static void osm_bounds_free(bounds_t *bounds) {  static void osm_bounds_free(bounds_t *bounds) {
# Line 55  static void osm_bounds_dump(bounds_t *bo Line 47  static void osm_bounds_dump(bounds_t *bo
47           bounds->ll_min.lon, bounds->ll_max.lon);           bounds->ll_min.lon, bounds->ll_max.lon);
48  }  }
49    
 #ifndef OSM_STREAM_PARSER  
 static bounds_t *osm_parse_osm_bounds(osm_t *osm,  
                      xmlDocPtr doc, xmlNode *a_node) {  
   char *prop;  
   
   if(osm->bounds) {  
     errorf(NULL, "Doubly defined bounds");  
     return NULL;  
   }  
   
   bounds_t *bounds = g_new0(bounds_t, 1);  
   
   bounds->ll_min.lat = bounds->ll_min.lon = NAN;  
   bounds->ll_max.lat = bounds->ll_max.lon = NAN;  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlat"))) {  
     bounds->ll_min.lat = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlat"))) {  
     bounds->ll_max.lat = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlon"))) {  
     bounds->ll_min.lon = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlon"))) {  
     bounds->ll_max.lon = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||  
      isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {  
     errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",  
            bounds->ll_min.lat, bounds->ll_min.lon,  
            bounds->ll_max.lat, bounds->ll_max.lon);  
   
     osm_bounds_free(bounds);  
     return NULL;  
   }  
   
   
   /* calculate map zone which will be used as a reference for all */  
   /* drawing/projection later on */  
   pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,  
                    (bounds->ll_max.lon + bounds->ll_min.lon)/2 };  
   
   pos2lpos_center(&center, &bounds->center);  
   
   /* the scale is needed to accomodate for "streching" */  
   /* by the mercartor projection */  
   bounds->scale = cos(DEG2RAD(center.lat));  
   
   pos2lpos_center(&bounds->ll_min, &bounds->min);  
   bounds->min.x -= bounds->center.x;  
   bounds->min.y -= bounds->center.y;  
   bounds->min.x *= bounds->scale;  
   bounds->min.y *= bounds->scale;  
   
   pos2lpos_center(&bounds->ll_max, &bounds->max);  
   bounds->max.x -= bounds->center.x;  
   bounds->max.y -= bounds->center.y;  
   bounds->max.x *= bounds->scale;  
   bounds->max.y *= bounds->scale;  
   
   return bounds;  
 }  
 #endif  
   
50  /* ------------------------- user handling --------------------- */  /* ------------------------- user handling --------------------- */
51    
52  void osm_users_free(user_t *user) {  void osm_users_free(user_t *user) {
# Line 150  void osm_users_dump(user_t *user) { Line 69  void osm_users_dump(user_t *user) {
69  }  }
70    
71  static user_t *osm_user(osm_t *osm, char *name) {  static user_t *osm_user(osm_t *osm, char *name) {
72      if(!name) return NULL;
73    
74    /* search through user list */    /* search through user list */
75    user_t **user = &osm->user;    user_t **user = &osm->user;
# Line 171  static user_t *osm_user(osm_t *osm, char Line 91  static user_t *osm_user(osm_t *osm, char
91    
92  static  static
93  time_t convert_iso8601(const char *str) {  time_t convert_iso8601(const char *str) {
94      if(!str) return 0;
95    
96    tzset();    tzset();
97    
98    struct tm ctime;    struct tm ctime;
# Line 305  void osm_node_dump(node_t *node) { Line 227  void osm_node_dump(node_t *node) {
227    char buf[64];    char buf[64];
228    struct tm tm;    struct tm tm;
229    
230    printf("Id:      %lu\n", node->id);    printf("Id:      "ITEM_ID_FORMAT"\n", node->id);
231    printf("User:    %s\n", node->user?node->user->name:"<unspecified>");    printf("User:    %s\n", node->user?node->user->name:"<unspecified>");
232    printf("Visible: %s\n", node->visible?"yes":"no");    printf("Visible: %s\n", node->visible?"yes":"no");
233    
# Line 324  void osm_nodes_dump(node_t *node) { Line 246  void osm_nodes_dump(node_t *node) {
246    }    }
247  }  }
248    
 #ifndef OSM_STREAM_PARSER  
 static node_t *osm_parse_osm_node(osm_t *osm,  
                           xmlDocPtr doc, xmlNode *a_node) {  
   xmlNode *cur_node = NULL;  
   
   /* allocate a new node structure */  
   node_t *node = g_new0(node_t, 1);  
   node->pos.lat = node->pos.lon = NAN;  
   
   char *prop;  
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {  
     node->id = strtoul(prop, NULL, 10);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lat"))) {  
     node->pos.lat = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lon"))) {  
     node->pos.lon = g_ascii_strtod(prop, NULL);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {  
     node->user = osm_user(osm, prop);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {  
     node->visible = (strcasecmp(prop, "true") == 0);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {  
     node->time = convert_iso8601(prop);  
     xmlFree(prop);  
   }  
   
   /* scan for tags and attach a list of tags */  
   tag_t **tag = &node->tag;  
   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {  
     if (cur_node->type == XML_ELEMENT_NODE) {  
       if(strcasecmp((char*)cur_node->name, "tag") == 0) {  
         /* attach tag to node */  
         *tag = osm_parse_osm_tag(osm, doc, cur_node);  
         if(*tag) tag = &((*tag)->next);  
       } else  
         printf("found unhandled osm/node/%s\n", cur_node->name);  
     }  
   }  
   
   pos2lpos(osm->bounds, &node->pos, &node->lpos);  
   
   return node;  
 }  
 #endif  
   
249  /* ------------------- way handling ------------------- */  /* ------------------- way handling ------------------- */
250    
251  void osm_node_chain_free(node_chain_t *node_chain) {  void osm_node_chain_free(node_chain_t *node_chain) {
# Line 397  void osm_node_chain_free(node_chain_t *n Line 260  void osm_node_chain_free(node_chain_t *n
260  }  }
261    
262  void osm_way_free(way_t *way) {  void osm_way_free(way_t *way) {
263    //  printf("freeing way #%ld\n", way->id);    //  printf("freeing way #" ITEM_ID_FORMAT "\n", way->id);
264    
265    osm_node_chain_free(way->node_chain);    osm_node_chain_free(way->node_chain);
266    osm_tags_free(way->tag);    osm_tags_free(way->tag);
# Line 442  void osm_way_dump(way_t *way) { Line 305  void osm_way_dump(way_t *way) {
305    char buf[64];    char buf[64];
306    struct tm tm;    struct tm tm;
307    
308    printf("Id:      %lu\n", way->id);    printf("Id:      "ITEM_ID_FORMAT"\n", way->id);
309    printf("User:    %s\n", way->user?way->user->name:"<unspecified>");    printf("User:    %s\n", way->user?way->user->name:"<unspecified>");
310    printf("Visible: %s\n", way->visible?"yes":"no");    printf("Visible: %s\n", way->visible?"yes":"no");
311    node_chain_t *node_chain = way->node_chain;    node_chain_t *node_chain = way->node_chain;
312    while(node_chain) {    while(node_chain) {
313      printf("  Node:  %lu\n", node_chain->node->id);      printf("  Node:  "ITEM_ID_FORMAT"\n", node_chain->node->id);
314      node_chain = node_chain->next;      node_chain = node_chain->next;
315    }    }
316    
# Line 475  node_chain_t *osm_parse_osm_way_nd(osm_t Line 338  node_chain_t *osm_parse_osm_way_nd(osm_t
338      node_chain_t *node_chain = g_new0(node_chain_t, 1);      node_chain_t *node_chain = g_new0(node_chain_t, 1);
339    
340      /* search matching node */      /* search matching node */
341      node_chain->node = osm->node;      node_chain->node = osm_get_node_by_id(osm, id);
342      while(node_chain->node && node_chain->node->id != id)      if(!node_chain->node) printf("Node id " ITEM_ID_FORMAT " not found\n", id);
343        node_chain->node = node_chain->node->next;      else                  node_chain->node->ways++;
   
     if(!node_chain->node) printf("Node id %lu not found\n", id);  
   
     if(node_chain->node)  
       node_chain->node->ways++;  
344    
345      xmlFree(prop);      xmlFree(prop);
346    
# Line 492  node_chain_t *osm_parse_osm_way_nd(osm_t Line 350  node_chain_t *osm_parse_osm_way_nd(osm_t
350    return NULL;    return NULL;
351  }  }
352    
 #ifndef OSM_STREAM_PARSER  
 static way_t *osm_parse_osm_way(osm_t *osm,  
                           xmlDocPtr doc, xmlNode *a_node) {  
   xmlNode *cur_node = NULL;  
   
   /* allocate a new way structure */  
   way_t *way = g_new0(way_t, 1);  
   
   char *prop;  
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {  
     way->id = strtoul(prop, NULL, 10);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {  
     way->user = osm_user(osm, prop);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {  
     way->visible = (strcasecmp(prop, "true") == 0);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {  
     way->time = convert_iso8601(prop);  
     xmlFree(prop);  
   }  
   
   /* scan for tags/nodes and attach their lists */  
   tag_t **tag = &way->tag;  
   node_chain_t **node_chain = &way->node_chain;  
   
   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {  
     if (cur_node->type == XML_ELEMENT_NODE) {  
       if(strcasecmp((char*)cur_node->name, "tag") == 0) {  
         /* attach tag to node */  
         *tag = osm_parse_osm_tag(osm, doc, cur_node);  
         if(*tag) tag = &((*tag)->next);  
       } else if(strcasecmp((char*)cur_node->name, "nd") == 0) {  
         *node_chain = osm_parse_osm_way_nd(osm, doc, cur_node);  
         if(*node_chain)  
           node_chain = &((*node_chain)->next);  
       } else  
         printf("found unhandled osm/node/%s\n", cur_node->name);  
     }  
   }  
   
   return way;  
 }  
 #endif  
   
353  /* ------------------- relation handling ------------------- */  /* ------------------- relation handling ------------------- */
354    
355  void osm_member_free(member_t *member) {  void osm_member_free(member_t *member) {
# Line 559  void osm_members_free(member_t *member) Line 365  void osm_members_free(member_t *member)
365    }    }
366  }  }
367    
368    void osm_relation_free(relation_t *relation) {
369      osm_tags_free(relation->tag);
370      osm_members_free(relation->member);
371    
372      g_free(relation);
373    }
374    
375  static void osm_relations_free(relation_t *relation) {  static void osm_relations_free(relation_t *relation) {
376    while(relation) {    while(relation) {
377      relation_t *next = relation->next;      relation_t *next = relation->next;
378        osm_relation_free(relation);
     osm_tags_free(relation->tag);  
     osm_members_free(relation->member);  
   
     g_free(relation);  
379      relation = next;      relation = next;
380    }    }
381  }  }
# Line 577  void osm_relations_dump(relation_t *rela Line 386  void osm_relations_dump(relation_t *rela
386      char buf[64];      char buf[64];
387      struct tm tm;      struct tm tm;
388    
389      printf("Id:      %lu\n", relation->id);      printf("Id:      "ITEM_ID_FORMAT"\n", relation->id);
390      printf("User:    %s\n",      printf("User:    %s\n",
391             relation->user?relation->user->name:"<unspecified>");             relation->user?relation->user->name:"<unspecified>");
392      printf("Visible: %s\n", relation->visible?"yes":"no");      printf("Visible: %s\n", relation->visible?"yes":"no");
393    
394      member_t *member = relation->member;      member_t *member = relation->member;
395      while(member) {      while(member) {
396        switch(member->type) {        switch(member->object.type) {
397        case ILLEGAL:        case ILLEGAL:
398        case NODE_ID:        case NODE_ID:
399        case WAY_ID:        case WAY_ID:
# Line 592  void osm_relations_dump(relation_t *rela Line 401  void osm_relations_dump(relation_t *rela
401          break;          break;
402    
403        case NODE:        case NODE:
404          if(member->node)          if(member->object.node)
405            printf(" Member: Node, id = %lu, role = %s\n",            printf(" Member: Node, id = " ITEM_ID_FORMAT ", role = %s\n",
406                   member->node->id, member->role);                   member->object.node->id, member->role);
407          break;          break;
408    
409        case WAY:        case WAY:
410          if(member->way)          if(member->object.way)
411          printf(" Member: Way, id = %lu, role = %s\n",            printf(" Member: Way, id = " ITEM_ID_FORMAT ", role = %s\n",
412                 member->way->id, member->role);                   member->object.way->id, member->role);
413          break;          break;
414    
415        case RELATION:        case RELATION:
416          if(member->relation)          if(member->object.relation)
417          printf(" Member: Relation, id = %lu, role = %s\n",            printf(" Member: Relation, id = " ITEM_ID_FORMAT ", role = %s\n",
418                 member->relation->id, member->role);                   member->object.relation->id, member->role);
419          break;          break;
420        }        }
421    
# Line 627  member_t *osm_parse_osm_relation_member( Line 436  member_t *osm_parse_osm_relation_member(
436                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
437    char *prop;    char *prop;
438    member_t *member = g_new0(member_t, 1);    member_t *member = g_new0(member_t, 1);
439    member->type = ILLEGAL;    member->object.type = ILLEGAL;
440    
441    if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) {    if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) {
442      if(strcasecmp(prop, "way") == 0)           member->type = WAY;      if(strcasecmp(prop, "way") == 0)           member->object.type = WAY;
443      else if(strcasecmp(prop, "node") == 0)     member->type = NODE;      else if(strcasecmp(prop, "node") == 0)     member->object.type = NODE;
444      else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;      else if(strcasecmp(prop, "relation") == 0) member->object.type = RELATION;
445      xmlFree(prop);      xmlFree(prop);
446    }    }
447    
448    if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {    if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) {
449      item_id_t id = strtoul(prop, NULL, 10);      item_id_t id = strtoul(prop, NULL, 10);
450    
451      switch(member->type) {      switch(member->object.type) {
452      case ILLEGAL:      case ILLEGAL:
453        printf("Unable to store illegal type\n");        printf("Unable to store illegal type\n");
454        break;        break;
455    
456      case WAY:      case WAY:
457        /* search matching way */        /* search matching way */
458        member->way = osm->way;        member->object.way = osm_get_way_by_id(osm, id);
459        while(member->way && member->way->id != id)        if(!member->object.way) {
460          member->way = member->way->next;          member->object.type = WAY_ID;
461            member->object.id = id;
       if(!member->way) {  
         member->type = WAY_ID;  
         member->id = id;  
462        }        }
463        break;        break;
464    
465      case NODE:      case NODE:
466        /* search matching node */        /* search matching node */
467        member->node = osm->node;        member->object.node = osm_get_node_by_id(osm, id);
468        while(member->node && member->node->id != id)        if(!member->object.node) {
469          member->node = member->node->next;          member->object.type = NODE_ID;
470            member->object.id = id;
       if(!member->node) {  
         member->type = NODE_ID;  
         member->id = id;  
471        }        }
472        break;        break;
473    
474      case RELATION:      case RELATION:
475        /* search matching relation */        /* search matching relation */
476        member->relation = osm->relation;        member->object.relation = osm_get_relation_by_id(osm, id);
477        while(member->relation && member->relation->id != id)        if(!member->object.relation) {
478          member->relation = member->relation->next;          member->object.type = NODE_ID;
479            member->object.id = id;
       if(!member->relation) {  
         member->type = NODE_ID;  
         member->id = id;  
480        }        }
481        break;        break;
482    
# Line 697  member_t *osm_parse_osm_relation_member( Line 497  member_t *osm_parse_osm_relation_member(
497    return member;    return member;
498  }  }
499    
500  #ifndef OSM_STREAM_PARSER  /* ------------------ osm handling ----------------- */
 static relation_t *osm_parse_osm_relation(osm_t *osm,  
                           xmlDocPtr doc, xmlNode *a_node) {  
   xmlNode *cur_node = NULL;  
   
   /* allocate a new relation structure */  
   relation_t *relation = g_new0(relation_t, 1);  
   
   char *prop;  
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) {  
     relation->id = strtoul(prop, NULL, 10);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) {  
     relation->user = osm_user(osm, prop);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) {  
     relation->visible = (strcasecmp(prop, "true") == 0);  
     xmlFree(prop);  
   }  
   
   if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) {  
     relation->time = convert_iso8601(prop);  
     xmlFree(prop);  
   }  
   
   /* scan for tags and attach a list of tags */  
   tag_t **tag = &relation->tag;  
   member_t **member = &relation->member;  
   
   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {  
     if (cur_node->type == XML_ELEMENT_NODE) {  
       if(strcasecmp((char*)cur_node->name, "tag") == 0) {  
         /* attach tag to node */  
         *tag = osm_parse_osm_tag(osm, doc, cur_node);  
         if(*tag) tag = &((*tag)->next);  
       } else if(strcasecmp((char*)cur_node->name, "member") == 0) {  
         *member = osm_parse_osm_relation_member(osm, doc, cur_node);  
         if(*member) member = &((*member)->next);  
       } else  
         printf("found unhandled osm/node/%s\n", cur_node->name);  
     }  
   }  
   
   return relation;  
 }  
   
 /* ----------------------- generic xml handling -------------------------- */  
   
 /* parse loc entry */  
 static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) {  
   xmlNode *cur_node = NULL;  
   
   for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {  
     if (cur_node->type == XML_ELEMENT_NODE) {  
       if(strcasecmp((char*)cur_node->name, "bounds") == 0)  
         osm->bounds = osm_parse_osm_bounds(osm, doc, cur_node);  
       else if(strcasecmp((char*)cur_node->name, "node") == 0) {  
         /* parse node and attach it to chain */  
         node_t *new = osm_parse_osm_node(osm, doc, cur_node);  
         if(new) {  
           node_t **node = &osm->node;  
   
 #ifdef OSM_SORT_ID  
           /* search chain of nodes */  
           while(*node && ((*node)->id < new->id))  
             node = &(*node)->next;  
 #endif  
   
 #ifdef OSM_SORT_LAST  
           while(*node) node = &(*node)->next;  
 #endif  
   
           /* insert into chain */  
           new->next = *node;  
           *node = new;  
         }  
       } else if(strcasecmp((char*)cur_node->name, "way") == 0) {  
         /* parse way and attach it to chain */  
         way_t *new = osm_parse_osm_way(osm, doc, cur_node);  
         if(new) {  
           way_t **way = &osm->way;  
   
 #ifdef OSM_SORT_ID  
           /* insert into chain */  
           while(*way && ((*way)->id < new->id))  
             way = &(*way)->next;  
 #endif  
   
 #ifdef OSM_SORT_LAST  
           while(*way) way = &(*way)->next;  
 #endif  
   
           /* insert into chain */  
           new->next = *way;  
           *way = new;  
         }  
       } else if(strcasecmp((char*)cur_node->name, "relation") == 0) {  
         /* parse relation and attach it to chain */  
         relation_t *new = osm_parse_osm_relation(osm, doc, cur_node);  
         if(new) {  
           relation_t **relation = &osm->relation;  
   
 #ifdef OSM_SORT_ID  
           /* search chain of ways */  
           while(*relation && ((*relation)->id < new->id))  
             relation = &(*relation)->next;  
 #endif  
   
 #ifdef OSM_SORT_LAST  
           while(*relation) relation = &(*relation)->next;  
 #endif  
501    
502            /* insert into chain */  /* the two hash tables eat over 512kBytes memory and may thus be */
503            new->next = *relation;  /* freed at any time. osm2go can work without them (albeit slower) */
504            *relation = new;  static void hash_table_free(hash_table_t *table) {
505          }    if(!table) return;
506        } else  
507          printf("found unhandled osm/%s\n", cur_node->name);    int i;
508      for(i=0;i<65536;i++) {
509        hash_item_t *item = table->hash[i];
510        while(item) {
511          hash_item_t *next = item->next;
512          g_free(item);
513          item = next;
514      }      }
515    }    }
516  }  }
517    
518  /* parse root element and search for "osm" */  void osm_hash_tables_free(osm_t *osm) {
519  static osm_t *osm_parse_root(xmlDocPtr doc, xmlNode * a_node) {    hash_table_free(osm->node_hash);
520    osm_t *osm;    osm->node_hash = NULL;
521    xmlNode *cur_node = NULL;    hash_table_free(osm->way_hash);
522      osm->way_hash = NULL;
   /* allocate memory to hold osm file description */  
   osm = g_new0(osm_t, 1);  
   
   for (cur_node = a_node; cur_node; cur_node = cur_node->next) {  
     if (cur_node->type == XML_ELEMENT_NODE) {  
       /* parse osm osm file ... */  
       if(strcasecmp((char*)cur_node->name, "osm") == 0)  
         osm_parse_osm(osm, doc, cur_node);  
       else  
         printf("found unhandled %s\n", cur_node->name);  
     }  
   }  
   
   return osm;  
523  }  }
524    
 static osm_t *osm_parse_doc(xmlDocPtr doc) {  
   osm_t *osm;  
   
   /* Get the root element node */  
   xmlNode *root_element = xmlDocGetRootElement(doc);  
   
   osm = osm_parse_root(doc, root_element);  
   
   /*free the document */  
   xmlFreeDoc(doc);  
   
   /*  
    * Free the global variables that may  
    * have been allocated by the parser.  
    */  
   xmlCleanupParser();  
   
   return osm;  
 }  
 #endif  
   
 /* ------------------ osm handling ----------------- */  
   
525  void osm_free(icon_t **icon, osm_t *osm) {  void osm_free(icon_t **icon, osm_t *osm) {
526    if(!osm) return;    if(!osm) return;
527    
528      osm_hash_tables_free(osm);
529    
530    if(osm->bounds)   osm_bounds_free(osm->bounds);    if(osm->bounds)   osm_bounds_free(osm->bounds);
531    if(osm->user)     osm_users_free(osm->user);    if(osm->user)     osm_users_free(osm->user);
532    if(osm->way)      osm_ways_free(osm->way);    if(osm->way)      osm_ways_free(osm->way);
# Line 887  void osm_dump(osm_t *osm) { Line 543  void osm_dump(osm_t *osm) {
543    osm_relations_dump(osm->relation);    osm_relations_dump(osm->relation);
544  }  }
545    
546  #ifdef OSM_STREAM_PARSER  /* -------------------------- stream parser ------------------- */
 /* -------------------------- stream parser tests ------------------- */  
547    
548  #include <libxml/xmlreader.h>  #include <libxml/xmlreader.h>
549    
# Line 1024  static node_t *process_node(xmlTextReade Line 679  static node_t *process_node(xmlTextReade
679      xmlFree(prop);      xmlFree(prop);
680    }    }
681    
682      /* new in api 0.6: */
683      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) {
684        node->version = strtoul(prop, NULL, 10);
685        xmlFree(prop);
686      }
687    
688    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) {
689      node->pos.lat = g_ascii_strtod(prop, NULL);      node->pos.lat = g_ascii_strtod(prop, NULL);
690      xmlFree(prop);      xmlFree(prop);
# Line 1051  static node_t *process_node(xmlTextReade Line 712  static node_t *process_node(xmlTextReade
712    
713    pos2lpos(osm->bounds, &node->pos, &node->lpos);    pos2lpos(osm->bounds, &node->pos, &node->lpos);
714    
715      /* append node to end of hash table if present */
716      if(osm->node_hash) {
717        hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)];
718        while(*item) item = &(*item)->next;
719    
720        *item = g_new0(hash_item_t, 1);
721        (*item)->data.node = node;
722      }
723    
724    /* just an empty element? then return the node as it is */    /* just an empty element? then return the node as it is */
725    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
726      return node;      return node;
# Line 1088  static node_chain_t *process_nd(xmlTextR Line 758  static node_chain_t *process_nd(xmlTextR
758      node_chain_t *node_chain = g_new0(node_chain_t, 1);      node_chain_t *node_chain = g_new0(node_chain_t, 1);
759    
760      /* search matching node */      /* search matching node */
761      node_chain->node = osm->node;      node_chain->node = osm_get_node_by_id(osm, id);
762      while(node_chain->node && node_chain->node->id != id)      if(!node_chain->node) printf("Node id " ITEM_ID_FORMAT " not found\n", id);
763        node_chain->node = node_chain->node->next;      else                  node_chain->node->ways++;
   
     if(!node_chain->node) printf("Node id %lu not found\n", id);  
   
     if(node_chain->node)  
       node_chain->node->ways++;  
764    
765      xmlFree(prop);      xmlFree(prop);
766    
# Line 1117  static way_t *process_way(xmlTextReaderP Line 782  static way_t *process_way(xmlTextReaderP
782      xmlFree(prop);      xmlFree(prop);
783    }    }
784    
785      /* new in api 0.6: */
786      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) {
787        way->version = strtoul(prop, NULL, 10);
788        xmlFree(prop);
789      }
790    
791    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
792      way->user = osm_user(osm, prop);      way->user = osm_user(osm, prop);
793      xmlFree(prop);      xmlFree(prop);
# Line 1132  static way_t *process_way(xmlTextReaderP Line 803  static way_t *process_way(xmlTextReaderP
803      xmlFree(prop);      xmlFree(prop);
804    }    }
805    
806      /* append way to end of hash table if present */
807      if(osm->way_hash) {
808        hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)];
809        while(*item) item = &(*item)->next;
810    
811        *item = g_new0(hash_item_t, 1);
812        (*item)->data.way = way;
813      }
814    
815    /* just an empty element? then return the way as it is */    /* just an empty element? then return the way as it is */
816    /* (this should in fact never happen as this would be a way without nodes) */    /* (this should in fact never happen as this would be a way without nodes) */
817    if(xmlTextReaderIsEmptyElement(reader))    if(xmlTextReaderIsEmptyElement(reader))
# Line 1168  static way_t *process_way(xmlTextReaderP Line 848  static way_t *process_way(xmlTextReaderP
848  static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) {  static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) {
849    char *prop;    char *prop;
850    member_t *member = g_new0(member_t, 1);    member_t *member = g_new0(member_t, 1);
851    member->type = ILLEGAL;    member->object.type = ILLEGAL;
852    
853    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) {
854      if(strcasecmp(prop, "way") == 0)           member->type = WAY;      if(strcasecmp(prop, "way") == 0)           member->object.type = WAY;
855      else if(strcasecmp(prop, "node") == 0)     member->type = NODE;      else if(strcasecmp(prop, "node") == 0)     member->object.type = NODE;
856      else if(strcasecmp(prop, "relation") == 0) member->type = RELATION;      else if(strcasecmp(prop, "relation") == 0) member->object.type = RELATION;
857      xmlFree(prop);      xmlFree(prop);
858    }    }
859    
860    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) {
861      item_id_t id = strtoul(prop, NULL, 10);      item_id_t id = strtoul(prop, NULL, 10);
862    
863      switch(member->type) {      switch(member->object.type) {
864      case ILLEGAL:      case ILLEGAL:
865        printf("Unable to store illegal type\n");        printf("Unable to store illegal type\n");
866        break;        break;
867    
868      case WAY:      case WAY:
869        /* search matching way */        /* search matching way */
870        member->way = osm->way;        member->object.way = osm_get_way_by_id(osm, id);
871        while(member->way && member->way->id != id)        if(!member->object.way) {
872          member->way = member->way->next;          member->object.type = WAY_ID;
873            member->object.id = id;
       if(!member->way) {  
         member->type = WAY_ID;  
         member->id = id;  
874        }        }
875        break;        break;
876    
877      case NODE:      case NODE:
878        /* search matching node */        /* search matching node */
879        member->node = osm->node;        member->object.node = osm_get_node_by_id(osm, id);
880        while(member->node && member->node->id != id)        if(!member->object.node) {
881          member->node = member->node->next;          member->object.type = NODE_ID;
882            member->object.id = id;
       if(!member->node) {  
         member->type = NODE_ID;  
         member->id = id;  
883        }        }
884        break;        break;
885    
886      case RELATION:      case RELATION:
887        /* search matching relation */        /* search matching relation */
888        member->relation = osm->relation;        member->object.relation = osm_get_relation_by_id(osm, id);
889        while(member->relation && member->relation->id != id)        if(!member->object.relation) {
890          member->relation = member->relation->next;          member->object.type = NODE_ID;
891            member->object.id = id;
       if(!member->relation) {  
         member->type = NODE_ID;  
         member->id = id;  
892        }        }
893        break;        break;
894    
# Line 1248  static relation_t *process_relation(xmlT Line 919  static relation_t *process_relation(xmlT
919      xmlFree(prop);      xmlFree(prop);
920    }    }
921    
922      /* new in api 0.6: */
923      if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) {
924        relation->version = strtoul(prop, NULL, 10);
925        xmlFree(prop);
926      }
927    
928    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {    if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) {
929      relation->user = osm_user(osm, prop);      relation->user = osm_user(osm, prop);
930      xmlFree(prop);      xmlFree(prop);
# Line 1282  static relation_t *process_relation(xmlT Line 959  static relation_t *process_relation(xmlT
959    
960      if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {      if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
961        char *subname = (char*)xmlTextReaderConstName(reader);        char *subname = (char*)xmlTextReaderConstName(reader);
962        if(strcasecmp(subname, "nd") == 0) {        if(strcasecmp(subname, "member") == 0) {
963          *member = process_member(reader, osm);          *member = process_member(reader, osm);
964          if(*member) member = &(*member)->next;          if(*member) member = &(*member)->next;
965        } else if(strcasecmp(subname, "tag") == 0) {        } else if(strcasecmp(subname, "tag") == 0) {
# Line 1300  static relation_t *process_relation(xmlT Line 977  static relation_t *process_relation(xmlT
977  static osm_t *process_osm(xmlTextReaderPtr reader) {  static osm_t *process_osm(xmlTextReaderPtr reader) {
978    /* alloc osm structure */    /* alloc osm structure */
979    osm_t *osm = g_new0(osm_t, 1);    osm_t *osm = g_new0(osm_t, 1);
980      osm->node_hash = g_new0(hash_table_t, 1);
981      osm->way_hash = g_new0(hash_table_t, 1);
982    
983    node_t **node = &osm->node;    node_t **node = &osm->node;
984    way_t **way = &osm->way;    way_t **way = &osm->way;
# Line 1382  static osm_t *process_file(const char *f Line 1061  static osm_t *process_file(const char *f
1061    return osm;    return osm;
1062  }  }
1063    
1064  /* ----------------------- end of stream parser tests ------------------- */  /* ----------------------- end of stream parser ------------------- */
 #endif  
1065    
1066  #include <sys/time.h>  #include <sys/time.h>
1067    
1068  osm_t *osm_parse(char *filename) {  osm_t *osm_parse(char *path, char *filename) {
1069    
1070    struct timeval start;    struct timeval start;
1071    gettimeofday(&start, NULL);    gettimeofday(&start, NULL);
1072    
1073    LIBXML_TEST_VERSION;    LIBXML_TEST_VERSION;
1074    
 #ifdef OSM_STREAM_PARSER  
1075    // use stream parser    // use stream parser
1076    osm_t *osm = process_file(filename);    osm_t *osm = NULL;
1077    xmlCleanupParser();    if(filename[0] == '/')
1078        osm = process_file(filename);
1079  #else    else {
1080    // parse into a tree      char *full = g_strjoin(NULL, path, filename, NULL);
1081    /* parse the file and get the DOM */      osm = process_file(full);
1082    xmlDoc *doc = NULL;      g_free(full);
   if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) {  
     xmlErrorPtr errP = xmlGetLastError();  
     errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message);  
     return NULL;  
1083    }    }
1084    
1085    osm_t *osm = osm_parse_doc(doc);    xmlCleanupParser();
 #endif  
1086    
1087    struct timeval end;    struct timeval end;
1088    gettimeofday(&end, NULL);    gettimeofday(&end, NULL);
# Line 1504  gboolean osm_node_has_value(node_t *node Line 1176  gboolean osm_node_has_value(node_t *node
1176  gboolean osm_node_has_tag(node_t *node) {  gboolean osm_node_has_tag(node_t *node) {
1177    tag_t *tag = node->tag;    tag_t *tag = node->tag;
1178    
1179      /* created_by tags don't count as real tags */
1180    if(tag && strcasecmp(tag->key, "created_by") == 0)    if(tag && strcasecmp(tag->key, "created_by") == 0)
1181      tag = tag->next;      tag = tag->next;
1182    
# Line 1526  static void osm_generate_tags(tag_t *tag Line 1199  static void osm_generate_tags(tag_t *tag
1199    while(tag) {    while(tag) {
1200      /* make sure "created_by" tag contains our id */      /* make sure "created_by" tag contains our id */
1201      if(strcasecmp(tag->key, "created_by") == 0) {      if(strcasecmp(tag->key, "created_by") == 0) {
1202        g_free(tag->value);        if(strcasecmp(tag->value, PACKAGE " v" VERSION) != 0) {
1203        tag->value = g_strdup(PACKAGE " v" VERSION);          g_free(tag->value);
1204            tag->value = g_strdup(PACKAGE " v" VERSION);
1205          }
1206      }      }
1207    
1208      xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);      xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL);
# Line 1538  static void osm_generate_tags(tag_t *tag Line 1213  static void osm_generate_tags(tag_t *tag
1213  }  }
1214    
1215  /* build xml representation for a way */  /* build xml representation for a way */
1216  char *osm_generate_xml(osm_t *osm, type_t type, void *item) {  static char *osm_generate_xml(osm_t *osm, item_id_t changeset,
1217                           type_t type, void *item) {
1218    char str[32];    char str[32];
1219    xmlChar *result = NULL;    xmlChar *result = NULL;
1220    int len = 0;    int len = 0;
# Line 1547  char *osm_generate_xml(osm_t *osm, type_ Line 1223  char *osm_generate_xml(osm_t *osm, type_
1223    
1224    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");    xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1225    xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");    xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");
   xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5");  
   xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION);  
1226    xmlDocSetRootElement(doc, root_node);    xmlDocSetRootElement(doc, root_node);
1227    
1228    switch(type) {    switch(type) {
# Line 1562  char *osm_generate_xml(osm_t *osm, type_ Line 1236  char *osm_generate_xml(osm_t *osm, type_
1236          snprintf(str, sizeof(str), "%u", (unsigned)node->id);          snprintf(str, sizeof(str), "%u", (unsigned)node->id);
1237          xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str);          xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str);
1238        }        }
1239        g_ascii_dtostr(str, sizeof(str), node->pos.lat);        snprintf(str, sizeof(str), "%u", (unsigned)node->version);
1240          xmlNewProp(node_node, BAD_CAST "version", BAD_CAST str);
1241          snprintf(str, sizeof(str), "%u", (unsigned)changeset);
1242          xmlNewProp(node_node, BAD_CAST "changeset", BAD_CAST str);
1243          g_ascii_formatd(str, sizeof(str), LL_FORMAT, node->pos.lat);
1244        xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str);        xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str);
1245        g_ascii_dtostr(str, sizeof(str), node->pos.lon);        g_ascii_formatd(str, sizeof(str), LL_FORMAT, node->pos.lon);
1246        xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str);        xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str);
1247        osm_generate_tags(node->tag, node_node);        osm_generate_tags(node->tag, node_node);
1248      }      }
# Line 1576  char *osm_generate_xml(osm_t *osm, type_ Line 1254  char *osm_generate_xml(osm_t *osm, type_
1254        xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL);        xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL);
1255        snprintf(str, sizeof(str), "%u", (unsigned)way->id);        snprintf(str, sizeof(str), "%u", (unsigned)way->id);
1256        xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str);        xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str);
1257          snprintf(str, sizeof(str), "%u", (unsigned)way->version);
1258          xmlNewProp(way_node, BAD_CAST "version", BAD_CAST str);
1259          snprintf(str, sizeof(str), "%u", (unsigned)changeset);
1260          xmlNewProp(way_node, BAD_CAST "changeset", BAD_CAST str);
1261    
1262        node_chain_t *node_chain = way->node_chain;        node_chain_t *node_chain = way->node_chain;
1263        while(node_chain) {        while(node_chain) {
1264          xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL);          xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL);
1265          char *str = g_strdup_printf("%ld", node_chain->node->id);          char *str = g_strdup_printf(ITEM_ID_FORMAT, node_chain->node->id);
1266          xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str);          xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str);
1267          g_free(str);          g_free(str);
1268          node_chain = node_chain->next;          node_chain = node_chain->next;
# Line 1597  char *osm_generate_xml(osm_t *osm, type_ Line 1279  char *osm_generate_xml(osm_t *osm, type_
1279                                          BAD_CAST "relation", NULL);                                          BAD_CAST "relation", NULL);
1280        snprintf(str, sizeof(str), "%u", (unsigned)relation->id);        snprintf(str, sizeof(str), "%u", (unsigned)relation->id);
1281        xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str);        xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str);
1282          snprintf(str, sizeof(str), "%u", (unsigned)relation->version);
1283          xmlNewProp(rel_node, BAD_CAST "version", BAD_CAST str);
1284          snprintf(str, sizeof(str), "%u", (unsigned)changeset);
1285          xmlNewProp(rel_node, BAD_CAST "changeset", BAD_CAST str);
1286    
1287        member_t *member = relation->member;        member_t *member = relation->member;
1288        while(member) {        while(member) {
1289          xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL);          xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL);
1290          char *str = NULL;          char *str = NULL;
1291    
1292          switch(member->type) {          switch(member->object.type) {
1293          case NODE:          case NODE:
1294            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node");            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node");
1295            str = g_strdup_printf("%ld", member->node->id);            str = g_strdup_printf(ITEM_ID_FORMAT, member->object.node->id);
1296            break;            break;
1297    
1298          case WAY:          case WAY:
1299            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way");            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way");
1300            str = g_strdup_printf("%ld", member->way->id);            str = g_strdup_printf(ITEM_ID_FORMAT, member->object.way->id);
1301            break;            break;
1302    
1303          case RELATION:          case RELATION:
1304            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation");            xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation");
1305            str = g_strdup_printf("%ld", member->relation->id);            str = g_strdup_printf(ITEM_ID_FORMAT, member->object.relation->id);
1306            break;            break;
1307    
1308          default:          default:
# Line 1656  char *osm_generate_xml(osm_t *osm, type_ Line 1342  char *osm_generate_xml(osm_t *osm, type_
1342  }  }
1343    
1344  /* build xml representation for a node */  /* build xml representation for a node */
1345  char *osm_generate_xml_node(osm_t *osm, node_t *node) {  char *osm_generate_xml_node(osm_t *osm, item_id_t changeset, node_t *node) {
1346    return osm_generate_xml(osm, NODE, node);    return osm_generate_xml(osm, changeset, NODE, node);
1347  }  }
1348    
1349  /* build xml representation for a way */  /* build xml representation for a way */
1350  char *osm_generate_xml_way(osm_t *osm, way_t *way) {  char *osm_generate_xml_way(osm_t *osm, item_id_t changeset, way_t *way) {
1351    return osm_generate_xml(osm, WAY, way);    return osm_generate_xml(osm, changeset, WAY, way);
1352  }  }
1353    
1354  /* build xml representation for a relation */  /* build xml representation for a relation */
1355  char *osm_generate_xml_relation(osm_t *osm, relation_t *relation) {  char *osm_generate_xml_relation(osm_t *osm, item_id_t changeset,
1356    return osm_generate_xml(osm, RELATION, relation);                                  relation_t *relation) {
1357      return osm_generate_xml(osm, changeset, RELATION, relation);
1358  }  }
1359    
1360    /* build xml representation for a changeset */
1361    char *osm_generate_xml_changeset(osm_t *osm, char *comment) {
1362      xmlChar *result = NULL;
1363      int len = 0;
1364    
1365      /* tags for this changeset */
1366      tag_t tag_comment = {
1367        .key = "comment", .value = comment, .next = NULL };
1368      tag_t tag_creator = {
1369        .key = "created_by", .value = PACKAGE " v" VERSION, .next = &tag_comment };
1370    
1371      LIBXML_TEST_VERSION;
1372    
1373      xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
1374      xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm");
1375      xmlDocSetRootElement(doc, root_node);
1376    
1377      xmlNodePtr cs_node = xmlNewChild(root_node, NULL, BAD_CAST "changeset", NULL);
1378      osm_generate_tags(&tag_creator, cs_node);
1379    
1380      xmlDocDumpFormatMemoryEnc(doc, &result, &len, "UTF-8", 1);
1381      xmlFreeDoc(doc);
1382      xmlCleanupParser();
1383    
1384      //  puts("xml encoding result:");
1385      //  puts((char*)result);
1386    
1387      return (char*)result;
1388    }
1389    
1390    
1391    /* the following three functions are eating much CPU power */
1392    /* as they search the objects lists. Hashing is supposed to help */
1393  node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {  node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) {
1394      if(id > 0 && osm->node_hash) {
1395        // use hash table if present
1396        hash_item_t *item = osm->node_hash->hash[ID2HASH(id)];
1397        while(item) {
1398          if(item->data.node->id == id)
1399            return item->data.node;
1400    
1401          item = item->next;
1402        }
1403      }
1404    
1405      /* use linear search if no hash tables are present or search in hash table failed */
1406    node_t *node = osm->node;    node_t *node = osm->node;
1407    while(node) {    while(node) {
1408      if(node->id == id)      if(node->id == id)
1409        return node;        return node;
1410    
1411      node = node->next;      node = node->next;
1412    }    }
1413    
1414    return NULL;    return NULL;
1415  }  }
1416    
1417  way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {  way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) {
1418      if(id > 0 && osm->way_hash) {
1419        // use hash table if present
1420        hash_item_t *item = osm->way_hash->hash[ID2HASH(id)];
1421        while(item) {
1422          if(item->data.way->id == id)
1423            return item->data.way;
1424    
1425          item = item->next;
1426        }
1427      }
1428    
1429      /* use linear search if no hash tables are present or search on hash table failed */
1430    way_t *way = osm->way;    way_t *way = osm->way;
1431    while(way) {    while(way) {
1432      if(way->id == id)      if(way->id == id)
1433        return way;        return way;
1434    
1435      way = way->next;      way = way->next;
1436    }    }
1437    
1438    return NULL;    return NULL;
1439  }  }
1440    
1441  relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {  relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) {
1442      // use linear search
1443    relation_t *relation = osm->relation;    relation_t *relation = osm->relation;
1444    while(relation) {    while(relation) {
1445      if(relation->id == id)      if(relation->id == id)
# Line 1750  item_id_t osm_new_node_id(osm_t *osm) { Line 1497  item_id_t osm_new_node_id(osm_t *osm) {
1497    return 0;    return 0;
1498  }  }
1499    
1500    item_id_t osm_new_relation_id(osm_t *osm) {
1501      item_id_t id = -1;
1502    
1503      while(TRUE) {
1504        gboolean found = FALSE;
1505        relation_t *relation = osm->relation;
1506        while(relation) {
1507          if(relation->id == id)
1508            found = TRUE;
1509    
1510          relation = relation->next;
1511        }
1512    
1513        /* no such id so far -> use it */
1514        if(!found) return id;
1515    
1516        id--;
1517      }
1518      g_assert(0);
1519      return 0;
1520    }
1521    
1522  node_t *osm_node_new(osm_t *osm, gint x, gint y) {  node_t *osm_node_new(osm_t *osm, gint x, gint y) {
1523    printf("Creating new node\n");    printf("Creating new node\n");
1524    
1525    node_t *node = g_new0(node_t, 1);    node_t *node = g_new0(node_t, 1);
1526      node->version = 1;
1527    node->lpos.x = x;    node->lpos.x = x;
1528    node->lpos.y = y;    node->lpos.y = y;
1529    node->visible = TRUE;    node->visible = TRUE;
1530    node->time = time(NULL);    node->time = time(NULL);
1531    
   /* add created_by tag */  
   node->tag = g_new0(tag_t, 1);  
   node->tag->key = g_strdup("created_by");  
   node->tag->value = g_strdup(PACKAGE " v" VERSION);  
   
1532    /* convert screen position back to ll */    /* convert screen position back to ll */
1533    lpos2pos(osm->bounds, &node->lpos, &node->pos);    lpos2pos(osm->bounds, &node->lpos, &node->pos);
1534    
# Line 1786  void osm_node_attach(osm_t *osm, node_t Line 1551  void osm_node_attach(osm_t *osm, node_t
1551    *lnode = node;    *lnode = node;
1552  }  }
1553    
1554    void osm_node_restore(osm_t *osm, node_t *node) {
1555      printf("Restoring node\n");
1556    
1557      /* attach to end of node list */
1558      node_t **lnode = &osm->node;
1559      while(*lnode) lnode = &(*lnode)->next;
1560      *lnode = node;
1561    }
1562    
1563  way_t *osm_way_new(void) {  way_t *osm_way_new(void) {
1564    printf("Creating new way\n");    printf("Creating new way\n");
1565    
1566    way_t *way = g_new0(way_t, 1);    way_t *way = g_new0(way_t, 1);
1567      way->version = 1;
1568    way->visible = TRUE;    way->visible = TRUE;
1569    way->flags = OSM_FLAG_NEW;    way->flags = OSM_FLAG_NEW;
1570    way->time = time(NULL);    way->time = time(NULL);
1571    
   /* add created_by tag */  
   way->tag = g_new0(tag_t, 1);  
   way->tag->key = g_strdup("created_by");  
   way->tag->value = g_strdup(PACKAGE " v" VERSION);  
   
1572    return way;    return way;
1573  }  }
1574    
# Line 1822  way_chain_t *osm_node_delete(osm_t *osm, Line 1592  way_chain_t *osm_node_delete(osm_t *osm,
1592    
1593    /* new nodes aren't stored on the server and are just deleted permanently */    /* new nodes aren't stored on the server and are just deleted permanently */
1594    if(node->flags & OSM_FLAG_NEW) {    if(node->flags & OSM_FLAG_NEW) {
1595      printf("About to delete NEW node #%ld -> force permanent delete\n",      printf("About to delete NEW node #" ITEM_ID_FORMAT
1596             node->id);             " -> force permanent delete\n", node->id);
1597      permanently = TRUE;      permanently = TRUE;
1598    }    }
1599    
# Line 1859  way_chain_t *osm_node_delete(osm_t *osm, Line 1629  way_chain_t *osm_node_delete(osm_t *osm,
1629    }    }
1630    
1631    if(!permanently) {    if(!permanently) {
1632      printf("mark node #%ld as deleted\n", node->id);      printf("mark node #" ITEM_ID_FORMAT " as deleted\n", node->id);
1633      node->flags |= OSM_FLAG_DELETED;      node->flags |= OSM_FLAG_DELETED;
1634    } else {    } else {
1635      printf("permanently delete node #%ld\n", node->id);      printf("permanently delete node #" ITEM_ID_FORMAT "\n", node->id);
1636    
1637      /* remove it from the chain */      /* remove it from the chain */
1638      node_t **cnode = &osm->node;      node_t **cnode = &osm->node;
# Line 1903  relation_chain_t *osm_node_to_relation(o Line 1673  relation_chain_t *osm_node_to_relation(o
1673    
1674      member_t *member = relation->member;      member_t *member = relation->member;
1675      while(member) {      while(member) {
1676        switch(member->type) {        switch(member->object.type) {
1677        case NODE:        case NODE:
1678          /* nodes are checked directly */          /* nodes are checked directly */
1679          if(member->node == node)          if(member->object.node == node)
1680            is_member = TRUE;            is_member = TRUE;
1681          break;          break;
1682    
1683        case WAY: {        case WAY: {
1684          /* ways have to be checked for the nodes they consist of */          /* ways have to be checked for the nodes they consist of */
1685          node_chain_t *chain = member->way->node_chain;          node_chain_t *chain = member->object.way->node_chain;
1686          while(chain && !is_member) {          while(chain && !is_member) {
1687            if(chain->node == node)            if(chain->node == node)
1688              is_member = TRUE;              is_member = TRUE;
# Line 1950  relation_chain_t *osm_way_to_relation(os Line 1720  relation_chain_t *osm_way_to_relation(os
1720    
1721      member_t *member = relation->member;      member_t *member = relation->member;
1722      while(member) {      while(member) {
1723        switch(member->type) {        switch(member->object.type) {
1724        case WAY: {        case WAY: {
1725          /* ways can be check directly */          /* ways can be check directly */
1726          if(member->way == way)          if(member->object.way == way)
1727            is_member = TRUE;            is_member = TRUE;
1728        } break;        } break;
1729    
# Line 2015  gboolean osm_position_within_bounds(osm_ Line 1785  gboolean osm_position_within_bounds(osm_
1785  /* be deleted */  /* be deleted */
1786  void osm_node_remove_from_relation(osm_t *osm, node_t *node) {  void osm_node_remove_from_relation(osm_t *osm, node_t *node) {
1787    relation_t *relation = osm->relation;    relation_t *relation = osm->relation;
1788    printf("removing node #%ld from all relations:\n", node->id);    printf("removing node #" ITEM_ID_FORMAT " from all relations:\n", node->id);
1789    
1790    while(relation) {    while(relation) {
1791      member_t **member = &relation->member;      member_t **member = &relation->member;
1792      while(*member) {      while(*member) {
1793        if(((*member)->type == NODE) &&        if(((*member)->object.type == NODE) &&
1794           ((*member)->node == node)) {           ((*member)->object.node == node)) {
1795    
1796          printf("  from relation #%ld\n", relation->id);          printf("  from relation #" ITEM_ID_FORMAT "\n", relation->id);
1797    
1798          member_t *cur = *member;          member_t *cur = *member;
1799          *member = (*member)->next;          *member = (*member)->next;
# Line 2040  void osm_node_remove_from_relation(osm_t Line 1810  void osm_node_remove_from_relation(osm_t
1810  /* remove the given way from all relations */  /* remove the given way from all relations */
1811  void osm_way_remove_from_relation(osm_t *osm, way_t *way) {  void osm_way_remove_from_relation(osm_t *osm, way_t *way) {
1812    relation_t *relation = osm->relation;    relation_t *relation = osm->relation;
1813    printf("removing way #%ld from all relations:\n", way->id);    printf("removing way #" ITEM_ID_FORMAT " from all relations:\n", way->id);
1814    
1815    while(relation) {    while(relation) {
1816      member_t **member = &relation->member;      member_t **member = &relation->member;
1817      while(*member) {      while(*member) {
1818        if(((*member)->type == WAY) &&        if(((*member)->object.type == WAY) &&
1819           ((*member)->way == way)) {           ((*member)->object.way == way)) {
1820    
1821          printf("  from relation #%ld\n", relation->id);          printf("  from relation #" ITEM_ID_FORMAT "\n", relation->id);
1822    
1823          member_t *cur = *member;          member_t *cur = *member;
1824          *member = (*member)->next;          *member = (*member)->next;
# Line 2062  void osm_way_remove_from_relation(osm_t Line 1832  void osm_way_remove_from_relation(osm_t
1832    }    }
1833  }  }
1834    
1835    relation_t *osm_relation_new(void) {
1836      printf("Creating new relation\n");
1837    
1838      relation_t *relation = g_new0(relation_t, 1);
1839      relation->version = 1;
1840      relation->visible = TRUE;
1841      relation->flags = OSM_FLAG_NEW;
1842      relation->time = time(NULL);
1843    
1844      return relation;
1845    }
1846    
1847    void osm_relation_attach(osm_t *osm, relation_t *relation) {
1848      printf("Attaching relation\n");
1849    
1850      relation->id = osm_new_relation_id(osm);
1851      relation->flags = OSM_FLAG_NEW;
1852    
1853      /* attach to end of relation list */
1854      relation_t **lrelation = &osm->relation;
1855      while(*lrelation) lrelation = &(*lrelation)->next;
1856      *lrelation = relation;
1857    }
1858    
1859    
1860  void osm_way_delete(osm_t *osm, icon_t **icon,  void osm_way_delete(osm_t *osm, icon_t **icon,
1861                      way_t *way, gboolean permanently) {                      way_t *way, gboolean permanently) {
1862    
1863    /* new ways aren't stored on the server and are just deleted permanently */    /* new ways aren't stored on the server and are just deleted permanently */
1864    if(way->flags & OSM_FLAG_NEW) {    if(way->flags & OSM_FLAG_NEW) {
1865      printf("About to delete NEW way #%ld -> force permanent delete\n",      printf("About to delete NEW way #" ITEM_ID_FORMAT
1866             way->id);             " -> force permanent delete\n", way->id);
1867      permanently = TRUE;      permanently = TRUE;
1868    }    }
1869    
# Line 2077  void osm_way_delete(osm_t *osm, icon_t * Line 1872  void osm_way_delete(osm_t *osm, icon_t *
1872    while(*chain) {    while(*chain) {
1873    
1874      (*chain)->node->ways--;      (*chain)->node->ways--;
1875      printf("checking node #%ld (still used by %d)\n",      printf("checking node #" ITEM_ID_FORMAT " (still used by %d)\n",
1876             (*chain)->node->id, (*chain)->node->ways);             (*chain)->node->id, (*chain)->node->ways);
1877    
1878      /* this node must only be part of this way */      /* this node must only be part of this way */
# Line 2103  void osm_way_delete(osm_t *osm, icon_t * Line 1898  void osm_way_delete(osm_t *osm, icon_t *
1898    way->node_chain = NULL;    way->node_chain = NULL;
1899    
1900    if(!permanently) {    if(!permanently) {
1901      printf("mark way #%ld as deleted\n", way->id);      printf("mark way #" ITEM_ID_FORMAT " as deleted\n", way->id);
1902      way->flags |= OSM_FLAG_DELETED;      way->flags |= OSM_FLAG_DELETED;
1903    } else {    } else {
1904      printf("permanently delete way #%ld\n", way->id);      printf("permanently delete way #" ITEM_ID_FORMAT "\n", way->id);
1905    
1906      /* remove it from the chain */      /* remove it from the chain */
1907      way_t **cway = &osm->way;      way_t **cway = &osm->way;
# Line 2125  void osm_way_delete(osm_t *osm, icon_t * Line 1920  void osm_way_delete(osm_t *osm, icon_t *
1920    }    }
1921  }  }
1922    
1923  void osm_way_revert(way_t *way) {  void osm_relation_delete(osm_t *osm, relation_t *relation,
1924                             gboolean permanently) {
1925    
1926      /* new relations aren't stored on the server and are just */
1927      /* deleted permanently */
1928      if(relation->flags & OSM_FLAG_NEW) {
1929        printf("About to delete NEW relation #" ITEM_ID_FORMAT
1930               " -> force permanent delete\n", relation->id);
1931        permanently = TRUE;
1932      }
1933    
1934      /* the deletion of a relation doesn't affect the members as they */
1935      /* don't have any reference to the relation they are part of */
1936    
1937      if(!permanently) {
1938        printf("mark relation #" ITEM_ID_FORMAT " as deleted\n", relation->id);
1939        relation->flags |= OSM_FLAG_DELETED;
1940      } else {
1941        printf("permanently delete relation #" ITEM_ID_FORMAT "\n", relation->id);
1942    
1943        /* remove it from the chain */
1944        relation_t **crelation = &osm->relation;
1945        int found = 0;
1946    
1947        while(*crelation) {
1948          if(*crelation == relation) {
1949            found++;
1950            *crelation = (*crelation)->next;
1951    
1952            osm_relation_free(relation);
1953          } else
1954            crelation = &((*crelation)->next);
1955        }
1956        g_assert(found == 1);
1957      }
1958    }
1959    
1960    void osm_way_reverse(way_t *way) {
1961    node_chain_t *new = NULL;    node_chain_t *new = NULL;
1962    
1963    /* walk old chain first to last */    /* walk old chain first to last */
# Line 2143  void osm_way_revert(way_t *way) { Line 1975  void osm_way_revert(way_t *way) {
1975    way->node_chain = new;    way->node_chain = new;
1976  }  }
1977    
1978    static const char *DS_ONEWAY_FWD = "yes";
1979    static const char *DS_ONEWAY_REV = "-1";
1980    static const char *DS_LEFT_SUFFIX = ":left";
1981    static const char *DS_RIGHT_SUFFIX = ":right";
1982    
1983    /* Reverse direction-sensitive tags like "oneway". Marks the way as dirty if
1984     * anything is changed, and returns the number of flipped tags. */
1985    
1986    guint
1987    osm_way_reverse_direction_sensitive_tags (way_t *way) {
1988      tag_t *tag = way->tag;
1989      guint n_tags_altered = 0;
1990      while (tag != NULL) {
1991        char *lc_key = g_ascii_strdown(tag->key, -1);
1992        char *lc_value = g_ascii_strdown(tag->value, -1);
1993    
1994        if (strcmp(lc_key, "oneway") == 0) {
1995          // oneway={yes/true/1/-1} is unusual.
1996          // Favour "yes" and "-1".
1997          if ((strcmp(lc_value, DS_ONEWAY_FWD) == 0) ||
1998              (strcmp(lc_value, "true") == 0) ||
1999              (strcmp(lc_value, "1") == 0)) {
2000            g_free(tag->value);
2001            tag->value = g_strdup(DS_ONEWAY_REV);
2002            n_tags_altered++;
2003          }
2004          else if (strcmp(lc_value, DS_ONEWAY_REV) == 0) {
2005            g_free(tag->value);
2006            tag->value = g_strdup(DS_ONEWAY_FWD);
2007            n_tags_altered++;
2008          }
2009          else {
2010            printf("warning: unknown tag: %s=%s\n", tag->key, tag->value);
2011          }
2012        }
2013    
2014        // :left and :right suffixes
2015        else if (g_str_has_suffix(lc_key, DS_LEFT_SUFFIX)) {
2016          char *key_old = tag->key;
2017          char *lastcolon = rindex(key_old, ':');
2018          g_assert(lastcolon != NULL);
2019          *lastcolon = '\000';
2020          tag->key = g_strconcat(key_old, DS_RIGHT_SUFFIX, NULL);
2021          *lastcolon = ':';
2022          g_free(key_old);
2023          n_tags_altered++;
2024        }
2025        else if (g_str_has_suffix(lc_key, DS_RIGHT_SUFFIX)) {
2026          char *key_old = tag->key;
2027          char *lastcolon = rindex(key_old, ':');
2028          g_assert(lastcolon != NULL);
2029          *lastcolon = '\000';
2030          tag->key = g_strconcat(key_old, DS_LEFT_SUFFIX, NULL);
2031          *lastcolon = ':';
2032          g_free(key_old);
2033          n_tags_altered++;
2034        }
2035    
2036        g_free(lc_key);
2037        g_free(lc_value);
2038        tag = tag->next;
2039      }
2040      if (n_tags_altered > 0) {
2041        way->flags |= OSM_FLAG_DIRTY;
2042      }
2043      return n_tags_altered;
2044    }
2045    
2046    /* Reverse a way's role within relations where the role is direction-sensitive.
2047     * Returns the number of roles flipped, and marks any relations changed as
2048     * dirty. */
2049    
2050    static const char *DS_ROUTE_FORWARD = "forward";
2051    static const char *DS_ROUTE_REVERSE = "reverse";
2052    
2053    guint
2054    osm_way_reverse_direction_sensitive_roles(osm_t *osm, way_t *way) {
2055      relation_chain_t *rel_chain0, *rel_chain;
2056      rel_chain0 = rel_chain = osm_way_to_relation(osm, way);
2057      guint n_roles_flipped = 0;
2058    
2059      for (; rel_chain != NULL; rel_chain = rel_chain->next) {
2060        char *type = osm_tag_get_by_key(rel_chain->relation->tag, "type");
2061    
2062        // Route relations; http://wiki.openstreetmap.org/wiki/Relation:route
2063        if (strcasecmp(type, "route") == 0) {
2064    
2065          // First find the member corresponding to our way:
2066          member_t *member = rel_chain->relation->member;
2067          for (; member != NULL; member = member->next) {
2068            if (member->object.type == WAY) {
2069              if (member->object.way == way)
2070                break;
2071            }
2072            if (member->object.type == WAY_ID) {
2073              if (member->object.id == way->id)
2074                break;
2075            }
2076          }
2077          g_assert(member);  // osm_way_to_relation() broken?
2078    
2079          // Then flip its role if it's one of the direction-sensitive ones
2080          if (member->role == NULL) {
2081            printf("null role in route relation -> ignore\n");
2082          }
2083          else if (strcasecmp(member->role, DS_ROUTE_FORWARD) == 0) {
2084            g_free(member->role);
2085            member->role = g_strdup(DS_ROUTE_REVERSE);
2086            rel_chain->relation->flags |= OSM_FLAG_DIRTY;
2087            ++n_roles_flipped;
2088          }
2089          else if (strcasecmp(member->role, DS_ROUTE_REVERSE) == 0) {
2090            g_free(member->role);
2091            member->role = g_strdup(DS_ROUTE_FORWARD);
2092            rel_chain->relation->flags |= OSM_FLAG_DIRTY;
2093            ++n_roles_flipped;
2094          }
2095    
2096          // TODO: what about numbered stops? Guess we ignore them; there's no
2097          // consensus about whether they should be placed on the way or to one side
2098          // of it.
2099    
2100        }//if-route
2101    
2102    
2103      }
2104      if (rel_chain0) {
2105        g_free(rel_chain0);
2106      }
2107      return n_roles_flipped;
2108    }
2109    
2110  node_t *osm_way_get_first_node(way_t *way) {  node_t *osm_way_get_first_node(way_t *way) {
2111    node_chain_t *chain = way->node_chain;    node_chain_t *chain = way->node_chain;
2112    if(!chain) return NULL;    if(!chain) return NULL;
# Line 2200  tag_t *osm_tags_copy(tag_t *src_tag, gbo Line 2164  tag_t *osm_tags_copy(tag_t *src_tag, gbo
2164    
2165    return new_tags;    return new_tags;
2166  }  }
2167    
2168    /* return plain text of type */
2169    char *osm_object_type_string(object_t *object) {
2170      const struct { type_t type; char *name; } types[] = {
2171        { ILLEGAL,     "illegal" },
2172        { NODE,        "node" },
2173        { WAY,         "way" },
2174        { RELATION,    "relation" },
2175        { NODE_ID,     "node id" },
2176        { WAY_ID,      "way id" },
2177        { RELATION_ID, "relation id" },
2178        { 0, NULL }
2179      };
2180    
2181      int i;
2182      for(i=0;types[i].name;i++)
2183        if(object->type == types[i].type)
2184          return types[i].name;
2185    
2186      return NULL;
2187    }
2188    
2189    char *osm_object_string(object_t *object) {
2190      char *type_str = osm_object_type_string(object);
2191    
2192      if(!object)
2193        return g_strdup_printf("%s #<invalid>", type_str);
2194    
2195      switch(object->type) {
2196      case ILLEGAL:
2197        return g_strdup_printf("%s #<unspec>", type_str);
2198        break;
2199      case NODE:
2200        return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->node->id);
2201        break;
2202      case WAY:
2203        return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->way->id);
2204        break;
2205      case RELATION:
2206        return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str,
2207                               object->relation->id);
2208        break;
2209      case NODE_ID:
2210      case WAY_ID:
2211      case RELATION_ID:
2212        return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->id);
2213        break;
2214      }
2215      return NULL;
2216    }
2217    
2218    char *osm_object_id_string(object_t *object) {
2219      if(!object) return NULL;
2220    
2221      switch(object->type) {
2222      case ILLEGAL:
2223        return NULL;
2224        break;
2225      case NODE:
2226        return g_strdup_printf("#"ITEM_ID_FORMAT, object->node->id);
2227        break;
2228      case WAY:
2229        return g_strdup_printf("#"ITEM_ID_FORMAT, object->way->id);
2230        break;
2231      case RELATION:
2232        return g_strdup_printf("#"ITEM_ID_FORMAT, object->relation->id);
2233        break;
2234      case NODE_ID:
2235      case WAY_ID:
2236      case RELATION_ID:
2237        return g_strdup_printf("#"ITEM_ID_FORMAT, object->id);
2238        break;
2239      }
2240      return NULL;
2241    }
2242    
2243    tag_t *osm_object_get_tags(object_t *object) {
2244      if(!object) return NULL;
2245    
2246      switch(object->type) {
2247      case ILLEGAL:
2248        return NULL;
2249        break;
2250      case NODE:
2251        return object->node->tag;
2252        break;
2253      case WAY:
2254        return object->way->tag;
2255        break;
2256      case RELATION:
2257        return object->relation->tag;
2258        break;
2259      case NODE_ID:
2260      case WAY_ID:
2261      case RELATION_ID:
2262        return NULL;
2263        break;
2264      }
2265      return NULL;
2266    }
2267    
2268    
2269    gint osm_relation_members_num(relation_t *relation) {
2270      gint num = 0;
2271      member_t *member = relation->member;
2272      while(member) {
2273        num++;
2274        member = member->next;
2275      }
2276      return num;
2277    }
2278    
2279    void osm_object_set_flags(object_t *object, int set, int clr) {
2280    
2281      switch(object->type) {
2282      case NODE:
2283        object->node->flags |=  set;
2284        object->node->flags &= ~clr;
2285        break;
2286    
2287      case WAY:
2288        object->way->flags |=  set;
2289        object->way->flags &= ~clr;
2290        break;
2291    
2292      case RELATION:
2293        object->relation->flags |=  set;
2294        object->relation->flags &= ~clr;
2295        break;
2296    
2297      default:
2298        g_assert(0);
2299        break;
2300      }
2301    }
2302    
2303  // vim:et:ts=8:sw=2:sts=2:ai  // vim:et:ts=8:sw=2:sts=2:ai

Legend:
Removed from v.28  
changed lines
  Added in v.175