diff options
author | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2005-12-02 10:41:56 +0000 |
---|---|---|
committer | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2005-12-02 10:41:56 +0000 |
commit | ba8c7a19f05f6491eb7f191d44a5af8506f619cf (patch) | |
tree | 84264aa047b56e5db281be72b470c133b6f4f6f9 | |
download | navit-svn-ba8c7a19f05f6491eb7f191d44a5af8506f619cf.tar.gz |
Reorganisation
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit/src@8 ffa7fe5e-494d-0410-b361-a75ebd5db220
135 files changed, 22606 insertions, 0 deletions
diff --git a/block.c b/block.c new file mode 100644 index 00000000..c48ea3ff --- /dev/null +++ b/block.c @@ -0,0 +1,209 @@ +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <assert.h> +#include "file.h" +#include "block.h" +#include "data.h" + + +struct file_private { + int binarytree; +}; + +struct block_index_item { + unsigned long blocknum; + unsigned long blocks; +}; + +struct block_index { + unsigned long blocks; + unsigned long size; + unsigned long next; + struct block_index_item list[0]; +}; + + +struct block * +block_get(unsigned char **p) +{ + struct block *ret=(struct block *)(*p); + *p += sizeof(*ret); + return ret; +} + +struct block * +block_get_byindex(struct file *file, int idx, unsigned char **p_ret) +{ + struct block_index *blk_idx; + int blk_num,max; + + blk_idx=(struct block_index *)(file->begin+0x1000); + max=(blk_idx->size-sizeof(struct block_index))/sizeof(struct block_index_item); + while (idx >= max) { + blk_idx=(struct block_index *)(file->begin+blk_idx->next*512); + idx-=max; + } + blk_num=blk_idx->list[idx].blocknum; + + *p_ret=file->begin+blk_num*512; + return block_get(p_ret); +} + +int +block_binarytree_walk(struct block **block, unsigned char **p, struct coord *c, int ign, struct block_info *blk_inf, struct transformation *t, + void *data, void(*func)(struct block_info *, unsigned char *, unsigned char *, void *)) +{ + struct coord ca[2],cb[2]; + struct block *blk; + int blk_num,val,dx,dy; + int ret=0; + + ca[0].x=c[0].x; + ca[0].y=c[0].y; + ca[1].x=c[1].x; + ca[1].y=c[1].y; + cb[0].x=c[0].x; + cb[0].y=c[0].y; + cb[1].x=c[1].x; + cb[1].y=c[1].y; + + if (*p >= (unsigned char *)(*block)+(*block)->size) { + *block=block_get_byindex(blk_inf->file, (*block)->next, p); + *p-=20; + } + blk_num=get_long(p); + val=get_long(p); + + if (blk_num != -1) + ret++; + + if (blk_num != -1 && (t == NULL || is_visible(t, c))) { + unsigned char *t,*end; + blk=block_get_byindex(blk_inf->file, blk_num, &t); + if (c[0].x != blk->c[0].x || c[0].y != blk->c[0].y || c[1].x != blk->c[1].x || c[1].y != blk->c[1].y) { + printf("ERROR3\n"); + printf("!= 0x%lx,0x%lx-0x%lx,0x%lx\n", blk->c[0].x,blk->c[0].y,blk->c[1].x,blk->c[1].y); + } + end=(unsigned char *)blk; + end+=blk->size; + blk_inf->block=blk; + blk_inf->block_number=blk_num; + (*func)(blk_inf, t, end, data); + } + + if (val != -1) { + dx=c[1].x-c[0].x; + dy=c[0].y-c[1].y; + if (dy > dx) { + ca[0].y=val; + cb[1].y=val+1; + } else { + ca[1].x=val; + cb[0].x=val+1; + } + ret+=block_binarytree_walk(block, p, ca, ign, blk_inf, t, data, func); + ret+=block_binarytree_walk(block, p, cb, ign, blk_inf, t, data, func); + } + return ret; +} + +void +block_file_private_setup(struct file *file) +{ + int len; + unsigned char *p,*str,*t; + struct file_private *file_priv; + + file_priv=malloc(sizeof(*file_priv)); + file->private=file_priv; + memset(file_priv, 0, sizeof(*file_priv)); + + p=file->begin+0x0c; + while (*p) { + str=get_string(&p); + len=get_long(&p); + t=p; + if (! strcmp(str,"binaryTree")) { + file_priv->binarytree=get_long(&t); + } + p+=len; + } +} + +void +block_foreach_visible_linear(struct block_info *blk_inf, struct transformation *t, void *data, + void(*func)(struct block_info *blk_inf, unsigned char *, unsigned char *, void *)) +{ + unsigned char *p,*start,*end; + struct block *blk; + + blk_inf->block_number=0; + p=blk_inf->file->begin+0x2000; + while (p < blk_inf->file->end) { + blk_inf->block_number++; + start=p; + end=p; + blk=block_get(&p); + end+=blk->size; + if (blk->count == -1) + break; + if (t == NULL || is_visible(t, blk->c)) { + blk_inf->block=blk; + (*func)(blk_inf, p, end, data); + } + p=start+blk->blocks*512; + } +} + +void +block_foreach_visible(struct block_info *blk_inf, struct transformation *t, int limit, void *data, + void(*func)(struct block_info *, unsigned char *, unsigned char *, void *)) +{ + struct file_private *file_priv=blk_inf->file->private; + + if (! file_priv) { + block_file_private_setup(blk_inf->file); + file_priv=blk_inf->file->private; + } + if (! file_priv->binarytree) { + block_foreach_visible_linear(blk_inf, t, data, func); + } else { + unsigned char *p,*p2; + int dummy1,dummy2,xy,i,count; + struct block *block=block_get_byindex(blk_inf->file, file_priv->binarytree, &p); + p2=p; + dummy1=get_long(&p2); + if (block->count != -1 || dummy1 != -1) { + printf("ERROR2 0x%x\n", block->count); + } + xy=1; + p=p2; + for (i = 0 ; i < limit ; i++) { + p2=p; + dummy1=get_long(&p2); + dummy2=get_long(&p2); + assert((dummy1 == -1 && dummy2 == -1) || i < 32) ; + count=block_binarytree_walk(&block, &p, block->c, 0, blk_inf, t, data, func); + } + } +} + +int +block_get_param(struct block_info *blk_inf, struct param_list *param, int count) +{ + int i=count; + param_add_hex("Number", blk_inf->block_number, ¶m, &count); + param_add_hex("Addr", (unsigned char *)blk_inf->block-blk_inf->file->begin, ¶m, &count); + param_add_hex("Blocks", blk_inf->block->blocks, ¶m, &count); + param_add_hex("Size", blk_inf->block->size, ¶m, &count); + param_add_hex("Next", blk_inf->block->next, ¶m, &count); + param_add_hex_sig("L", blk_inf->block->c[0].x, ¶m, &count); + param_add_hex_sig("T", blk_inf->block->c[0].y, ¶m, &count); + param_add_hex_sig("R", blk_inf->block->c[1].x, ¶m, &count); + param_add_hex_sig("B", blk_inf->block->c[1].y, ¶m, &count); + param_add_hex("W", blk_inf->block->c[1].x-blk_inf->block->c[0].x, ¶m, &count); + param_add_hex("H", blk_inf->block->c[0].y-blk_inf->block->c[1].y, ¶m, &count); + param_add_hex("Count", blk_inf->block->count, ¶m, &count); + return i-count; +} diff --git a/block.h b/block.h new file mode 100644 index 00000000..a65fe935 --- /dev/null +++ b/block.h @@ -0,0 +1,30 @@ +#include "coord.h" +#include "transform.h" + +struct block { + unsigned long blocks; + unsigned long size; + unsigned long next; + struct coord c[2]; + int count; +}; + +struct block_info { + struct map_data *mdata; + struct file *file; + struct block *block; + int block_number; +}; + +struct segment { + struct block_info blk_inf; + void *data[4]; +}; + +struct param_list; + +struct block * block_get(unsigned char **p); +void block_foreach_visible(struct block_info *blk_inf, struct transformation *t, int limit, void *data, + void(*func)(struct block_info *blk_inf, unsigned char *, unsigned char *, void *)); +int block_get_param(struct block_info *blk_inf, struct param_list *param, int count); +struct block *block_get_byindex(struct file *file, int idx, unsigned char **p_ret); diff --git a/command.c b/command.c new file mode 100644 index 00000000..88d26a36 --- /dev/null +++ b/command.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <string.h> +#include "coord.h" +#include "town.h" +#include "street.h" + +/* Phonetisch + "KLEIN " -> CL + (x)(x)->x + EI:AY + E:- + F:V + G:C + H:- + I:Y + J:Y + K:C + T:D + W:V +*/ + +struct tree_hdr { + unsigned int addr; + unsigned int size; + unsigned int low; +}; + +struct tree_leaf { + unsigned int low; + unsigned int data; + unsigned char text[0]; +}; + +int +compare(char *s1, char *s2) +{ + char s1_exp, s2_exp; + for (;;) { + s1_exp=*s1++; + s2_exp=*s2++; + if (! s1_exp && ! s2_exp) + return 0; + if (s1_exp == 'A' && *s1 == 'E') { s1_exp='Ä'; s1++; } + if (s1_exp == 'O' && *s1 == 'E') { s1_exp='Ö'; s1++; } + if (s1_exp == 'U' && *s1 == 'E') { s1_exp='Ü'; s1++; } + if (s2_exp == 'A' && *s2 == 'E') { s2_exp='Ä'; s2++; } + if (s2_exp == 'O' && *s2 == 'E') { s2_exp='Ö'; s2++; } + if (s2_exp == 'U' && *s2 == 'E') { s2_exp='Ü'; s2++; } + if (s1_exp != s2_exp) + return s1_exp-s2_exp; + } +#if 0 + for (;;) { + while (*s1 && *s1 == *s2) { + s1++; + s2++; + } + if (! *s1 && ! *s2) + return 0; + if (! *s1) + return -1; + if (! *s2) + return 1; + if (*s1 < *s2 && *s2 < 0x80) + return -1; + if (*s1 > *s2 && *s1 < 0x80) + return 1; + s1_exp=*s1; + s2_exp=*s2; + if (s1_exp >= 0x80) + s1_exp=' '; + if (s2_exp >= 0x80) + s2_exp=' '; +#if 0 + if (*s1 == (unsigned char)'Ä') s1_exp='A'; + if (*s1 == (unsigned char)'Ö') s1_exp='O'; + if (*s1 == (unsigned char)'Ü') s1_exp='U'; + if (*s1 == (unsigned char)'ä') s1_exp='a'; + if (*s1 == (unsigned char)'ö') s1_exp='o'; + if (*s1 == (unsigned char)'ü') s1_exp='u'; + if (*s1 == (unsigned char)'ß') s1_exp='s'; + if (*s2 == (unsigned char)'Ä') s2_exp='A'; + if (*s2 == (unsigned char)'Ö') s2_exp='O'; + if (*s2 == (unsigned char)'Ü') s2_exp='U'; + if (*s2 == (unsigned char)'ä') s2_exp='a'; + if (*s2 == (unsigned char)'ö') s2_exp='o'; + if (*s2 == (unsigned char)'ü') s2_exp='u'; + if (*s2 == (unsigned char)'ß') s2_exp='s'; +#endif + if (s1_exp < s2_exp) + return -1; + if (s1_exp > s2_exp) + return 1; + printf("Problem %c vs %c\n", *s1, *s2); + exit(1); + } +#endif +} +void +command_goto(struct container *co, const char *arg) +{ +#if 0 + struct container *co=map->container; + struct town_list *list,*curr,*best=NULL; + int order=256; + int argc=0; + unsigned long x,y,scale; + char args[strlen(arg)+1]; + char *argv[strlen(arg)+1]; + char *tok; + + + strcpy(args, arg); + tok=strtok(args, " "); + while (tok) { + argv[argc++]=tok; + tok=strtok(NULL," "); + } + + list=NULL; + town_search_by_name(&list, co->map_data, argv[0], 0, 10000); + town_get_by_index(co->map_data, 0x311d54cb); + curr=list; + while (curr) { + if (curr->town->order < order) { + order=curr->town->order; + best=curr; + } + curr=curr->next; + } + if (best) { + printf("'%s' '%s' '%s' '%s'\n", best->town->name, best->town->district, best->town->postal_code1, best->town->postal_code2); +#if 0 + street_search_by_name(class->map_data, best->town->country, best->town->street_assoc, 0, argv[1]); +#endif + map_get_view(map, &x, &y, &scale); + x=best->town->c->x; + y=best->town->c->y; + map_set_view(map, x, y, scale); + } + town_list_free(list); +#endif +} diff --git a/command.h b/command.h new file mode 100644 index 00000000..5082fa04 --- /dev/null +++ b/command.h @@ -0,0 +1 @@ +void command_goto(struct container *co, const char *arg); diff --git a/compass.c b/compass.c new file mode 100644 index 00000000..cbfc9c68 --- /dev/null +++ b/compass.c @@ -0,0 +1,122 @@ +#include <math.h> +#include <stdio.h> +#include <glib.h> +#include "point.h" +#include "coord.h" +#include "graphics.h" +#include "transform.h" +#include "route.h" +#include "vehicle.h" +#include "container.h" + +struct compass { + struct graphics *gr; + struct graphics_gc *bg; + struct graphics_gc *white; + struct graphics_gc *green; + struct graphics_font *font; +}; + +static void +transform_rotate(struct point *center, int angle, struct point *p, int count) +{ + int i,x,y; + double dx,dy; + for (i = 0 ; i < count ; i++) + { + dx=sin(M_PI*angle/180.0); + dy=cos(M_PI*angle/180.0); + x=dy*p->x-dx*p->y; + y=dx*p->x+dy*p->y; + + p->x=center->x+x; + p->y=center->y+y; + p++; + } +} + +static void +handle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r, int dir) +{ + struct point ph[3]; + int l=r*0.4; + + ph[0].x=0; + ph[0].y=r; + ph[1].x=0; + ph[1].y=-r; + transform_rotate(p, dir, ph, 2); + gr->draw_lines(gr, gc, ph, 2); + ph[0].x=-l; + ph[0].y=-r+l; + ph[1].x=0; + ph[1].y=-r; + ph[2].x=l; + ph[2].y=-r+l; + transform_rotate(p, dir, ph, 3); + gr->draw_lines(gr, gc, ph, 3); +} + +void +compass_draw(struct compass *comp, struct container *co) +{ + struct point p; + struct coord *pos, *dest; + double *vehicle_dir,dir,distance; + int dx,dy; + char buffer[16]; + + vehicle_dir=vehicle_dir_get(co->vehicle); + comp->gr->draw_mode(comp->gr, draw_mode_begin); + p.x=0; + p.y=0; + comp->gr->draw_rectangle(comp->gr, comp->bg, &p, 60, 80); + p.x=30; + p.y=30; + comp->gr->draw_circle(comp->gr, comp->white, &p, 50); + handle(comp->gr, comp->white, &p, 20, -*vehicle_dir); + dest=route_get_destination(co->route); + if (dest) { + pos=vehicle_pos_get(co->vehicle); + dx=dest->x-pos->x; + dy=dest->y-pos->y; + dir=atan2(dx,dy)*180.0/M_PI; + printf("dx %d dy %d dir=%f vehicle_dir=%f\n", dx, dy, dir, *vehicle_dir); + dir-=*vehicle_dir; + handle(comp->gr, comp->green, &p, 20, dir); + p.x=8; + p.y=72; + distance=transform_distance(pos, dest)/1000.0; + if (distance >= 100) + sprintf(buffer,"%.0f km", distance); + else if (distance >= 10) + sprintf(buffer,"%.1f km", distance); + else + sprintf(buffer,"%.2f km", distance); + + comp->gr->draw_text(comp->gr, comp->green, NULL, comp->font, buffer, &p, 0x10000, 0); + } + comp->gr->draw_mode(comp->gr, draw_mode_end); +} + +struct compass * +compass_new(struct container *co) +{ + struct compass *this=g_new0(struct compass, 1); + struct point p; + p.x=10; + p.y=10; + this->gr=co->gra->overlay_new(co->gra, &p, 60, 80); + this->bg=this->gr->gc_new(this->gr); + this->gr->gc_set_foreground(this->bg, 0, 0, 0); + this->white=this->gr->gc_new(this->gr); + this->gr->gc_set_foreground(this->white, 0xffff, 0xffff, 0xffff); + this->gr->gc_set_linewidth(this->white, 2); + this->green=this->gr->gc_new(this->gr); + this->gr->gc_set_foreground(this->green, 0x0, 0xffff, 0x0); + this->gr->gc_set_linewidth(this->green, 2); + + this->font=this->gr->font_new(this->gr, 200); + compass_draw(this, co); + return this; +} diff --git a/compass.h b/compass.h new file mode 100644 index 00000000..3bc8ad7b --- /dev/null +++ b/compass.h @@ -0,0 +1,2 @@ +struct compass * compass_new(struct container *co); +void compass_draw(struct compass *comp, struct container *co); diff --git a/container.h b/container.h new file mode 100644 index 00000000..33433e4a --- /dev/null +++ b/container.h @@ -0,0 +1,69 @@ +enum display_index { + display_sea=0, + display_wood, + display_other, + display_other1, + display_other2, + display_other3, + display_water, + display_rail, + display_street, + display_street1, + display_street2, + display_street3, + display_street_no_pass, + display_street_route, + display_street_route_static, + display_town, + display_town1, + display_town2, + display_town3, + display_town4, + display_town5, + display_town6, + display_town7, + display_town8, + display_town9, + display_town10, + display_town11, + display_town12, + display_town13, + display_town14, + display_town15, + display_bti, + display_poi, + display_end +}; + +enum data_window_type { + data_window_type_block=0, + data_window_type_town, + data_window_type_poly, + data_window_type_street, + data_window_type_point, + data_window_type_end +}; + +struct map_flags { + int orient_north; + int track; +}; + +struct container { + struct window *win; + struct transformation *trans; + struct graphics *gra; + struct compass *compass; + struct display_list *disp[display_end]; + struct map_data *map_data; + struct menu *menu; + struct toolbar *toolbar; + struct statusbar *statusbar; + struct route *route; + struct cursor *cursor; + struct speech *speech; + struct vehicle *vehicle; + struct data_window *data_window[data_window_type_end]; + struct map_flags *flags; + struct _GtkMap *map; +}; diff --git a/coord.c b/coord.c new file mode 100644 index 00000000..8e792db8 --- /dev/null +++ b/coord.c @@ -0,0 +1,9 @@ +#include "coord.h" + +struct coord * +coord_get(unsigned char **p) +{ + struct coord *ret=(struct coord *)(*p); + *p += sizeof(*ret); + return ret; +} diff --git a/coord.h b/coord.h new file mode 100644 index 00000000..885c7919 --- /dev/null +++ b/coord.h @@ -0,0 +1,21 @@ +#ifndef COORD_H +#define COORD_H + +struct coord { + long x; + long y; +}; + +struct coord_d { + double x; + double y; +}; + +struct coord_geo { + double lng; + double lat; +}; + +struct coord * coord_get(unsigned char **p); + +#endif diff --git a/country.c b/country.c new file mode 100644 index 00000000..4f3a5d00 --- /dev/null +++ b/country.c @@ -0,0 +1,94 @@ +#include <string.h> +#include <stdio.h> +#include <glib.h> +#include "country.h" + +struct country country[]= { + {16 ,"RUS", "RU", "RUS", "Rußland"}, + {20 ,"ET", "EG", "EGY", "Ägypten"}, + {30 ,"GR", "GR", "GRC", "Griechenland"}, + {31 ,"NL", "NL", "NLD", "Niederlande"}, + {32 ,"B", "BE", "BEL", "Belgien"}, + {33 ,"F", "FR", "FRA", "Frankreich"}, + {34 ,"E", "ES", "ESP", "Spanien"}, + {36 ,"H", "HU", "HUN", "Ungarn"}, + {39 ,"I", "IT", "ITA", "Italien"}, + {40 ,"RO", "RO", "ROM", "Rumänien"}, + {41 ,"CH", "CH", "CHE", "Schweiz"}, + {43 ,"A", "AT", "AUT", "Österreich"}, + {44 ,"GB", "GB", "GBR", "Grossbritannien"}, + {45 ,"DK", "DK", "DNK", "Dänemark"}, + {47 ,"N", "NO", "NOR", "Norwegen"}, + {49 ,"D", "DE", "DEU", "Deutschland"}, + {51 ,"P", "PT", "PRT", "Portugal"}, + {52 ,"L", "LU", "LUX", "Luxemburg"}, + {71 ,"LAR", "LY", "LYB", "Libyen"}, + {76 ,"MA", "MA", "MAR", "Marokko"}, + {78 ,"TN", "TN", "TUN", "Tunesien"}, +}; + +struct country * +country_get_by_id(int id) +{ + int i; + for (i=0 ; i < sizeof(country)/sizeof(struct country); i++) { + if (id == country[i].id) { + return &country[i]; + } + } + return NULL; +} + +static int +compare(const char *name1, const char *name2, int len, int partial) +{ + if (partial) + return strncasecmp(name1, name2, len); + else + return strcasecmp(name1, name2); +} + +static int +search(int offset, const char *name, int partial, int (*func)(struct country *cou, void *data), void *data) +{ + char *col; + int i,ret,len=strlen(name); + int debug=0; + + for (i=0 ; i < sizeof(country)/sizeof(struct country); i++) { + col=G_STRUCT_MEMBER(char *,country+i,offset); + if (debug) + printf("comparing '%s'\n", col); + if (!compare(col, name, len, partial)) { + ret=(*func)(&country[i], data); + if (ret) + return 1; + } + col+=sizeof(struct country); + } + return 0; +} + +int +country_search_by_name(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data) +{ + return search(G_STRUCT_OFFSET(struct country, name), name, partial, func, data); +} + +int +country_search_by_car(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data) +{ + return search(G_STRUCT_OFFSET(struct country, car), name, partial, func, data); +} + +int +country_search_by_iso2(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data) +{ + return search(G_STRUCT_OFFSET(struct country, iso2), name, partial, func, data); +} + +int +country_search_by_iso3(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data) +{ + return search(G_STRUCT_OFFSET(struct country, iso3), name, partial, func, data); +} diff --git a/country.h b/country.h new file mode 100644 index 00000000..616a6c26 --- /dev/null +++ b/country.h @@ -0,0 +1,12 @@ +struct country { + int id; + char *car; + char *iso2; + char *iso3; + char *name; +}; +struct country * country_get_by_id(int id); +int country_search_by_name(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data); +int country_search_by_car(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data); +int country_search_by_iso2(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data); +int country_search_by_iso3(const char *name, int partial, int (*func)(struct country *cou, void *data), void *data); diff --git a/cursor.c b/cursor.c new file mode 100644 index 00000000..1f1d99e8 --- /dev/null +++ b/cursor.c @@ -0,0 +1,196 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <math.h> +#include <glib.h> +#include "coord.h" +#include "transform.h" +#include "graphics.h" +#include "statusbar.h" +#include "menu.h" +#include "vehicle.h" +#include "container.h" + + +#include "route.h" + +struct cursor { + struct container *co; + struct graphics_gc *cursor_gc; + struct point cursor_pnt; +}; + +struct coord * +cursor_pos_get(void *t) +{ + struct cursor *this=t; + return vehicle_pos_get(this->co->vehicle); +} + +static void +cursor_draw(struct cursor *this, struct point *pnt, double *speed, double *dir) +{ + int x=this->cursor_pnt.x; + int y=this->cursor_pnt.y; + int r=12,lw=2; + double dx,dy; + double fac1,fac2; + int dir_i=*dir-this->co->trans->angle; + struct point cpnt[3]; + struct graphics *gra=this->co->gra; + + if (pnt && x == pnt->x && y == pnt->y) + return; + cpnt[0]=this->cursor_pnt; + cpnt[0].x-=r+lw; + cpnt[0].y-=r+lw; + gra->draw_restore(gra, &cpnt[0], (r+lw)*2, (r+lw)*2); + if (pnt) { + gra->draw_mode(gra, draw_mode_cursor); + this->cursor_pnt=*pnt; + x=pnt->x; + y=pnt->y; + cpnt[0].x=x; + cpnt[0].y=y; + gra->draw_circle(gra, this->cursor_gc, &cpnt[0], r*2); + if (*speed > 2.5) { + dx=sin(M_PI*dir_i/180); + dy=-cos(M_PI*dir_i/180); + + fac1=0.7*r; + fac2=0.4*r; + cpnt[0].x=x-dx*fac1+dy*fac2; + cpnt[0].y=y-dy*fac1-dx*fac2; + cpnt[1].x=x+dx*r; + cpnt[1].y=y+dy*r; + cpnt[2].x=x-dx*fac1-dy*fac2; + cpnt[2].y=y-dy*fac1+dx*fac2; + gra->draw_lines(gra, this->cursor_gc, cpnt, 3); + } else { + cpnt[1]=cpnt[0]; + gra->draw_lines(gra, this->cursor_gc, cpnt, 2); + } + gra->draw_mode(gra, draw_mode_end); + } +} + +static void +cursor_map_reposition_screen(struct cursor *this, struct coord *c, double *dir, int x_new, int y_new) +{ + struct coord c_new; + struct transformation tr; + struct point pnt; + unsigned long scale; + long x,y; + int dir_i; + struct container *co=this->co; + + if (dir) + dir_i=*dir; + else + dir_i=0; + + pnt.x=co->trans->width-x_new; + pnt.y=co->trans->height-y_new; + graphics_get_view(co, &x, &y, &scale); + tr=*this->co->trans; + transform_setup(&tr, c->x, c->y, scale, dir_i); + transform_reverse(&tr, &pnt, &c_new); + printf("%lx %lx vs %lx %lx\n", c->x, c->y, c_new.x, c_new.y); + x=c_new.x; + y=c_new.y; + transform_set_angle(co->trans,dir_i); + graphics_set_view(co, &x, &y, &scale); +} + +static void +cursor_map_reposition(struct cursor *this, struct coord *c, double *dir) +{ + unsigned long scale; + long x,y; + + if (this->co->flags->orient_north) { + graphics_set_view(this->co, &c->x, &c->y, NULL); + } else { + cursor_map_reposition_screen(this, c, dir, this->co->trans->width/2, this->co->trans->height*0.8); + } +} + +static int +cursor_map_reposition_boundary(struct cursor *this, struct coord *c, double *dir, struct point *pnt) +{ + struct point pnt_new; + struct transformation *t=this->co->trans; + + pnt_new.x=-1; + if (pnt->x < 0.1*t->width) { + pnt_new.x=0.8*t->width; + pnt_new.y=t->height/2; + } + if (pnt->x > 0.9*t->width) { + pnt_new.x=0.2*t->width; + pnt_new.y=t->height/2; + } + if (pnt->y < (this->co->flags->orient_north ? 0.1 : 0.5)*t->height) { + pnt_new.x=t->width/2; + pnt_new.y=0.8*t->height; + } + if (pnt->y > 0.9*t->height) { + pnt_new.x=t->width/2; + pnt_new.y=0.2*t->height; + } + if (pnt_new.x != -1) { + if (this->co->flags->orient_north) { + cursor_map_reposition_screen(this, c, NULL, pnt_new.x, pnt_new.y); + } else { + cursor_map_reposition(this, c, dir); + } + return 1; + } + return 0; +} + +void +cursor_update(struct cursor *this) +{ + struct point pnt; + struct coord *pos; + struct vehicle *v=this->co->vehicle; + double *dir; + + if (v) { + pos=vehicle_pos_get(v); + dir=vehicle_dir_get(v); + route_set_position(this->co->route, cursor_pos_get(this->co->cursor)); + if (!transform(this->co->trans, pos, &pnt)) { + cursor_map_reposition(this, pos, dir); + transform(this->co->trans, pos, &pnt); + } + if (pnt.x < 0 || pnt.y < 0 || pnt.x >= this->co->trans->width || pnt.y >= this->co->trans->height) { + cursor_map_reposition(this, pos, dir); + transform(this->co->trans, pos, &pnt); + } + if (cursor_map_reposition_boundary(this, pos, dir, &pnt)) + transform(this->co->trans, pos, &pnt); + cursor_draw(this, &pnt, vehicle_speed_get(v), vehicle_dir_get(v)); + } +extern void compass_draw(); + compass_draw(this->co->compass, this->co); +} + +extern void *vehicle; + +struct cursor * +cursor_new(struct container *co) +{ + struct cursor *this=g_new(struct cursor,1); + this->co=co; + this->cursor_gc=co->gra->gc_new(co->gra); + co->gra->gc_set_foreground(this->cursor_gc, 0x0000, 0x0000, 0xffff); + co->gra->gc_set_linewidth(this->cursor_gc, 2); + vehicle_callback(cursor_update, this); + return this; +} diff --git a/cursor.h b/cursor.h new file mode 100644 index 00000000..46114875 --- /dev/null +++ b/cursor.h @@ -0,0 +1,5 @@ +struct cursor; +struct container; + +struct coord * cursor_pos_get(struct cursor *this); +struct cursor *cursor_new(struct container *co); @@ -0,0 +1,39 @@ +static inline unsigned char +get_char(unsigned char **p) +{ + return *((*p)++); +} + +static inline unsigned short +get_short(unsigned char **p) { + unsigned long ret; + ret=*((unsigned short *)*p); + *p+=sizeof(unsigned short); + return ret; +} + +static inline unsigned long +get_triple(unsigned char **p) { + unsigned long ret; + ret=get_short(p); + ret|=*((*p)++) << 16; + return ret; +} + + +static inline unsigned long +get_long(unsigned char **p) { + unsigned long ret; + ret=*((unsigned int *)*p); + *p+=sizeof(unsigned int); + return ret; +} + +static inline char * +get_string(unsigned char **p) +{ + char *ret=*p; + while (**p) (*p)++; + (*p)++; + return ret; +} diff --git a/data_window.c b/data_window.c new file mode 100644 index 00000000..dfcddcc2 --- /dev/null +++ b/data_window.c @@ -0,0 +1,104 @@ +#include <malloc.h> +#include <stdio.h> +#include <gtk/gtk.h> +#include "param.h" +#include "data_window.h" +#include "data_window_int.h" + +struct data_window * +data_window(char *name, struct window *parent, void(*callback)(struct data_window *, char **cols)) +{ + struct data_window *win; + + win=malloc(sizeof(*win)); + win->window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(win->window), 320, 200); + gtk_window_set_title(GTK_WINDOW(win->window), name); + + win->scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (win->scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + gtk_container_add(GTK_CONTAINER(win->window), win->scrolled_window); + + win->clist=NULL; + win->callback=callback; + if (parent) + gtk_window_set_transient_for(GTK_WINDOW((GtkWidget *)(win->window)), GTK_WINDOW(parent)); + gtk_widget_show_all(win->window); + return win; +} + +void +data_window_begin(struct data_window *win) +{ + if (win && win->clist) { + gtk_clist_clear(GTK_CLIST(win->clist)); + gtk_clist_freeze(GTK_CLIST(win->clist)); + } +} + +static void +click_column(GtkCList *clist, int column) +{ + if (column != clist->sort_column) { + gtk_clist_set_sort_type(clist, GTK_SORT_ASCENDING); + gtk_clist_set_sort_column(clist, column); + } else { + if (clist->sort_type == GTK_SORT_ASCENDING) + gtk_clist_set_sort_type(clist, GTK_SORT_DESCENDING); + else + gtk_clist_set_sort_type(clist, GTK_SORT_ASCENDING); + } + gtk_clist_sort(clist); +} + +static void +select_row(GtkCList *clist, int row, int column, GdkEventButton *event, struct data_window *win) +{ + int i; + if (win->callback) { + char *cols[20]; + for (i=0;i<20;i++) { + gtk_clist_get_text(clist, row, i, &cols[i]); + } + win->callback(win, cols); + } +} + +void +data_window_add(struct data_window *win, struct param_list *param, int count) +{ + int i; + char *column[count+1]; + char *utf8; + if (! win->clist) { + for (i = 0 ; i < count ; i++) { + column[i]=param[i].name; + } + win->clist=gtk_clist_new_with_titles(count, column); + gtk_clist_clear(GTK_CLIST(win->clist)); + gtk_container_add(GTK_CONTAINER(win->scrolled_window), win->clist); + gtk_clist_freeze(GTK_CLIST(win->clist)); + gtk_signal_connect(GTK_OBJECT(win->clist), "click-column", GTK_SIGNAL_FUNC(click_column), NULL); + gtk_signal_connect(GTK_OBJECT(win->clist), "select-row", GTK_SIGNAL_FUNC(select_row), win); + gtk_widget_show_all(win->window); + } + for (i = 0 ; i < count ; i++) { + utf8=g_locale_to_utf8(param[i].value,-1,NULL,NULL,NULL); + column[i]=utf8; + } + column[i]=NULL; + gtk_clist_append(GTK_CLIST(win->clist), column); + for (i = 0 ; i < count ; i++) { + g_free(column[i]); + } +} + +void +data_window_end(struct data_window *win) +{ + if (win && win->clist) { + gtk_clist_thaw(GTK_CLIST(win->clist)); + gtk_clist_columns_autosize (GTK_CLIST(win->clist)); + } +} diff --git a/data_window.h b/data_window.h new file mode 100644 index 00000000..86a412bb --- /dev/null +++ b/data_window.h @@ -0,0 +1,8 @@ +struct data_window; +struct param_list; +struct window; + +struct data_window *data_window(char *name, struct window *parent, void(*callback)(struct data_window *, char **cols)); +void data_window_add(struct data_window *win, struct param_list *param, int count); +void data_window_begin(struct data_window *win); +void data_window_end(struct data_window *win); diff --git a/data_window_int.h b/data_window_int.h new file mode 100644 index 00000000..c7922c2d --- /dev/null +++ b/data_window_int.h @@ -0,0 +1,7 @@ + +struct data_window { + GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *clist; + void(*callback)(struct data_window *, char **cols); +}; diff --git a/destination.c b/destination.c new file mode 100644 index 00000000..9cced769 --- /dev/null +++ b/destination.c @@ -0,0 +1,622 @@ +#include <gtk/gtk.h> +#include "coord.h" +#include "transform.h" +#include "block.h" +#include "data_window.h" +#include "country.h" +#include "town.h" +#include "street.h" +#include "street_name.h" +#include "gui/gtk/gtkeyboard.h" +#include "cursor.h" +#include "route.h" +#include "statusbar.h" +#include "unistd.h" +#include "destination.h" +#include "coord.h" +#include "container.h" + +extern gint track_focus(gpointer data); + + + +GtkWidget *entry_country, *entry_postal, *entry_city, *entry_district; +GtkWidget *entry_street, *entry_number; +GtkWidget *listbox; +int row_count=8; + +int selected; + +struct search_param { + struct map_data *map_data; + const char *country; + GHashTable *country_hash; + const char *town; + GHashTable *town_hash; + GHashTable *district_hash; + const char *street; + GHashTable *street_hash; + const char *number; + int number_low, number_high; + GtkWidget *clist; + int count; +} search_param2; + +struct destination { + struct town *town; + struct street_name *street_name; + struct coord *c; +}; + +struct country_list *country_list; + +static void +select_row(GtkCList *clist, int row, int column, GdkEventButton *event, struct data_window *win) +{ + selected=row; + printf("Selected %d\n", row); +} + +int +destination_set(struct container *co, enum destination_type type, char *text, struct coord *pos) +{ + route_set_position(co->route, cursor_pos_get(co->cursor)); + route_set_destination(co->route, pos); + graphics_redraw(co); + if (co->statusbar && co->statusbar->statusbar_route_update) + co->statusbar->statusbar_route_update(co->statusbar, co->route); + return 0; +} + +int +get_position(struct search_param *search, struct coord *c) +{ + struct destination *dest; + + if (selected == -1) + selected=0; + dest=gtk_clist_get_row_data (GTK_CLIST(search->clist), selected); + + printf("row %d dest %p dest:0x%lx,0x%lx\n", selected, dest, dest->c->x, dest->c->y); + *c=*dest->c; + return 0; +} + +void button_map(GtkWidget *widget, struct container *co) +{ + unsigned long scale; + struct coord c; + + if (!get_position(&search_param2, &c)) { + graphics_set_view(co, &c.x, &c.y, NULL); + } +} + +void button_destination(GtkWidget *widget, struct container *co) +{ + struct coord c; + + if (!get_position(&search_param2, &c)) { + route_set_position(co->route, cursor_pos_get(co->cursor)); + route_set_destination(co->route, &c); + graphics_redraw(co); + } +} + +struct dest_town { + int country; + int assoc; + char *name; + char postal_code[16]; + struct town town; +}; + +guint +destination_town_hash(gconstpointer key) +{ + const struct dest_town *hash=key; + gconstpointer hashkey=(gconstpointer)(hash->country^hash->assoc); + return g_direct_hash(hashkey); +} + +gboolean +destination_town_equal(gconstpointer a, gconstpointer b) +{ + const struct dest_town *t_a=a; + const struct dest_town *t_b=b; + if (t_a->assoc == t_b->assoc && t_a->country == t_b->country) { + if (t_a->name && t_b->name && strcmp(t_a->name, t_b->name)) + return FALSE; + return TRUE; + } + return FALSE; +} + +GHashTable * +destination_town_new(void) +{ + return g_hash_table_new_full(destination_town_hash, destination_town_equal, NULL, g_free); +} + +void +destination_town_set(const struct dest_town *town, char **rows, int full) +{ + char country[32]; + struct country *cou; + if ((cou=country_get_by_id(town->country))) { + rows[1]=cou->car; + } else { + sprintf(country,"(%d)", town->country); + rows[1]=country; + } + if (full) { + rows[4]=(char *)(town->town.postal_code2); + rows[5]=g_convert(town->town.name,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + if (town->town.district[0]) + rows[6]=g_convert(town->town.district,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + else + rows[6]=NULL; + } else { + rows[4]=(char *)(town->postal_code); + rows[5]=g_convert(town->name,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + } +} + +void +destination_town_show(gpointer key, gpointer value, gpointer user_data) +{ + struct dest_town *town=value; + struct search_param *search=(struct search_param *)user_data; + char *rows[9]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + int row; + + if (search->count > 0) { + struct destination *dest=g_new(struct destination, 1); + dest->town=&town->town; + dest->street_name=NULL; + dest->c=town->town.c; + destination_town_set(town, rows, 0); + row=gtk_clist_append(GTK_CLIST(search->clist), rows); + printf("town row %d %p dest:0x%lx,0x%lx\n", row, dest, dest->c->x, dest->c->y); + gtk_clist_set_row_data(GTK_CLIST(search->clist), row, dest); + search->count--; + } +} + +GHashTable * +destination_country_new(void) +{ + return g_hash_table_new_full(NULL, NULL, NULL, g_free); +} + +int +destination_country_add(struct country *cou, void *data) +{ + struct search_param *search=data; + struct country *cou2; + + void *first; + first=g_hash_table_lookup(search->country_hash, (void *)(cou->id)); + if (! first) { + cou2=g_new(struct country, 1); + *cou2=*cou; + g_hash_table_insert(search->country_hash, (void *)(cou->id), cou2); + } + return 0; +} + +void +destination_country_show(gpointer key, gpointer value, gpointer user_data) +{ + struct country *cou=value; + struct search_param *search=(struct search_param *)user_data; + char *rows[9]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + if (search->count > 0) { + rows[0]=cou->name; + rows[1]=cou->car; + rows[2]=cou->iso2; + rows[3]=cou->iso3; + gtk_clist_append(GTK_CLIST(search->clist), rows); + search->count--; + } +} + +int +destination_town_add(struct town *town, void *data) +{ + struct search_param *search=data; + struct dest_town *first; + + struct dest_town cmp; + char *zip1, *zip2; + + if (town->id == 0x1d546b7e) { + printf("found\n"); + } + cmp.country=town->country; + cmp.assoc=town->street_assoc; + cmp.name=town->name; + first=g_hash_table_lookup(search->town_hash, &cmp); + if (! first) { + first=g_new(struct dest_town, 1); + first->country=cmp.country; + first->assoc=cmp.assoc; + strcpy(first->postal_code, town->postal_code2); + first->name=town->name; + first->town=*town; + g_hash_table_insert(search->town_hash, first, first); + } else { + zip1=town->postal_code2; + zip2=first->postal_code; + while (*zip1 && *zip2) { + if (*zip1 != *zip2) { + while (*zip2) { + *zip2++='.'; + } + break; + } + zip1++; + zip2++; + } + } + cmp.name=NULL; + cmp.assoc=town->id; + first=g_hash_table_lookup(search->district_hash, &cmp); + if (! first) { + first=g_new(struct dest_town, 1); + first->country=cmp.country; + first->assoc=cmp.assoc; + first->name=NULL; + first->town=*town; + g_hash_table_insert(search->district_hash, first, first); + } + return 0; +} + +void +destination_town_search(gpointer key, gpointer value, gpointer user_data) +{ + struct country *cou=value; + struct search_param *search=(struct search_param *)user_data; + town_search_by_name(search->map_data, cou->id, search->town, 1, destination_town_add, search); + +} + +GHashTable * +destination_street_new(void) +{ + return g_hash_table_new_full(NULL, NULL, NULL, g_free); +} + + +int +destination_street_add(struct street_name *name, void *data) +{ + struct search_param *search=data; + struct street_name *name2; + + name2=g_new(struct street_name, 1); + *name2=*name; + g_hash_table_insert(search->street_hash, name2, name2); + return 0; +} + +static int +number_partial(int search, int ref, int ext) +{ + int max=1; + + printf("number_partial(%d,%d,%d)", search, ref, ext); + if (ref >= 10) + max=10; + if (ref >= 100) + max=100; + if (ref >= 1000) + max=1000; + while (search < max) { + search*=10; + search+=ext; + } + printf("max=%d result=%d\n", max, search); + return search; +} + +static int +check_number(int low, int high, int s_low, int s_high) +{ + printf("check_number(%d,%d,%d,%d)\n", low, high, s_low, s_high); + if (low <= s_high && high >= s_low) + return 1; + if (s_low == s_high) { + if (low <= number_partial(s_high, high, 9) && high >= number_partial(s_low, low, 0)) + return 1; + } + printf("return 0\n"); + return 0; +} + +void +destination_street_show_common(gpointer key, gpointer value, gpointer user_data, int number) +{ + struct street_name *name=value; + struct search_param *search=(struct search_param *)user_data; + char *utf8; + struct dest_town cmp; + struct dest_town *town; + int row; + char buffer[32]; + char *rows[9]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + struct street_name_info info; + struct street_name_number_info num_info; + + name->tmp_len=name->aux_len; + name->tmp_data=name->aux_data; + while (street_name_get_info(&info, name) && search->count > 0) { + struct destination *dest; + cmp.country=info.country; + cmp.assoc=info.dist; + cmp.name=NULL; + town=g_hash_table_lookup(search->district_hash, &cmp); + printf("town=%p\n", town); + if (town) { + destination_town_set(town, rows, 1); + utf8=g_convert(name->name2,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + rows[4]=utf8; + if (number) { + info.tmp_len=info.aux_len; + info.tmp_data=info.aux_data; + while (street_name_get_number_info(&num_info, &info) && search->count > 0) { + dest=g_new(struct destination, 1); + dest->town=&town->town; + dest->street_name=name; + dest->c=num_info.c; + if (check_number(num_info.first, num_info.last, search->number_low, search->number_high)) { + if (num_info.first == num_info.last) + sprintf(buffer,"%d",num_info.first); + else + sprintf(buffer,"%d-%d",num_info.first,num_info.last); + rows[8]=buffer; + printf("'%s','%s','%s','%s','%s','%s'\n", rows[0],rows[1],rows[2],rows[3],rows[4],rows[5]); + row=gtk_clist_append(GTK_CLIST(listbox), rows); + gtk_clist_set_row_data(GTK_CLIST(listbox), row, dest); + search->count--; + } + } + } else { + row=gtk_clist_append(GTK_CLIST(listbox), rows); + dest=g_new(struct destination, 1); + dest->town=&town->town; + dest->street_name=name; + dest->c=info.c; + gtk_clist_set_row_data(GTK_CLIST(listbox), row, dest); + search->count--; + } + g_free(utf8); + } else { + printf("Town for '%s' not found\n", name->name2); + } + } +} + +void +destination_street_show(gpointer key, gpointer value, gpointer user_data) +{ + destination_street_show_common(key, value, user_data, 0); +} + +void +destination_street_show_number(gpointer key, gpointer value, gpointer user_data) +{ + destination_street_show_common(key, value, user_data, 1); +} + +void +destination_street_search(gpointer key, gpointer value, gpointer user_data) +{ + const struct dest_town *town=value; + struct search_param *search=(struct search_param *)user_data; + street_name_search(search->map_data, town->country, town->assoc, search->street, 1, destination_street_add, search); +} + + + +void changed(GtkWidget *widget, struct search_param *search) +{ + const char *str; + char *empty[9]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + char *dash; + + gtk_clist_freeze(GTK_CLIST(listbox)); + gtk_clist_clear(GTK_CLIST(listbox)); + + selected=-1; + + search->count=row_count; + + str=gtk_entry_get_text(GTK_ENTRY(widget)); + + if (widget == entry_country) { + if (search->country_hash) g_hash_table_destroy(search->country_hash); + search->country_hash=NULL; + } + if (widget == entry_country || widget == entry_city) { + if (search->town_hash) g_hash_table_destroy(search->town_hash); + if (search->district_hash) g_hash_table_destroy(search->district_hash); + search->town_hash=NULL; + search->district_hash=NULL; + } + + if (widget == entry_country || widget == entry_city || widget == entry_street) { + if (search->street_hash) g_hash_table_destroy(search->street_hash); + search->street_hash=NULL; + } + + if (widget == entry_country) { + search->country_hash=destination_country_new(); + search->country=str; + country_search_by_name(str, 1, destination_country_add, search); + country_search_by_car(str, 1, destination_country_add, search); + country_search_by_iso2(str, 1, destination_country_add, search); + country_search_by_iso3(str, 1, destination_country_add, search); + g_hash_table_foreach(search->country_hash, destination_country_show, search); + } + if (widget == entry_city) { + printf("Ort: '%s'\n", str); + if (strlen(str) > 1) { + search->town=str; + search->town_hash=destination_town_new(); + search->district_hash=destination_town_new(); + g_hash_table_foreach(search->country_hash, destination_town_search, search); + g_hash_table_foreach(search->town_hash, destination_town_show, search); + } + } + if (widget == entry_street) { + printf("Street: '%s'\n", str); + search->street=str; + search->street_hash=destination_street_new(); + g_hash_table_foreach(search->town_hash, destination_street_search, search); + g_hash_table_foreach(search->street_hash, destination_street_show, search); + } + if (widget == entry_number) { + char buffer[strlen(str)+1]; + strcpy(buffer, str); + search->number=str; + dash=index(buffer,'-'); + if (dash) { + *dash++=0; + search->number_low=atoi(buffer); + if (strlen(str)) + search->number_high=atoi(dash); + else + search->number_high=10000; + } else { + if (!strlen(str)) { + search->number_low=0; + search->number_high=10000; + } else { + search->number_low=atoi(str); + search->number_high=atoi(str); + } + } + g_hash_table_foreach(search->street_hash, destination_street_show_number, search); + } + while (search->count-- > 0) { + gtk_clist_append(GTK_CLIST(listbox), empty); + } + gtk_clist_columns_autosize (GTK_CLIST(listbox)); + gtk_clist_thaw(GTK_CLIST(listbox)); +} + +int destination_address(struct container *co) +{ + GtkWidget *window2, *keyboard, *vbox, *table; + GtkWidget *label_country; + GtkWidget *label_postal, *label_city, *label_district; + GtkWidget *label_street, *label_number; + GtkWidget *hseparator1,*hseparator2; + GtkWidget *button1,*button2; + init_keyboard_stuff((char *) NULL); + int handlerid; + int i; + gchar *text[9]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + struct search_param *search=&search_param2; + +#if 0 + if (co->cursor) { + struct coord *c; + struct route_info *rt; + struct street_str *st; + struct block_info *blk; + struct street_name name; + struct town town; + + c=cursor_pos_get(co->cursor); + rt=route_find_nearest_street(co->map_data, c); + st=route_info_get_street(rt); + blk=route_info_get_block(rt); + printf("segid 0x%lx nameid 0x%lx\n", st->segid, st->nameid); + street_name_get_by_id(&name, blk->mdata, st->nameid); + printf("'%s' '%s' %d\n", name.name1, name.name2, name.segment_count); + for (i = 0 ; i < name.segment_count ; i++) { + if (name.segments[i].segid == st->segid) { + printf("found: 0x%x, 0x%x\n", name.segments[i].country, name.segments[i].segid); + town_get_by_id(&town, co->map_data, name.segments[i].country, name.townassoc); + printf("%s/%s\n", town.name, town.district); + } + } + } +#endif + + window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL); + keyboard = build_keyboard(NULL, "/usr/local/share/gtkeyboard/DE.key"); + vbox = gtk_vbox_new(FALSE, 0); + table = gtk_table_new(3, 8, FALSE); + + entry_country = gtk_entry_new(); + label_country = gtk_label_new("Land"); + entry_postal = gtk_entry_new(); + label_postal = gtk_label_new("PLZ"); + entry_city = gtk_entry_new(); + label_city = gtk_label_new("Ort"); + entry_district = gtk_entry_new(); + label_district = gtk_label_new("Ortsteil/Gemeinde"); + hseparator1 = gtk_vseparator_new(); + entry_street = gtk_entry_new(); + label_street = gtk_label_new("Strasse"); + entry_number = gtk_entry_new(); + label_number = gtk_label_new("Nummer"); + listbox = gtk_clist_new(9); + for (i=0 ; i < row_count ; i++) { + gtk_clist_append(GTK_CLIST(listbox), text); + } + gtk_clist_thaw(GTK_CLIST(listbox)); + gtk_clist_columns_autosize (GTK_CLIST(listbox)); + + hseparator2 = gtk_vseparator_new(); + button1 = gtk_button_new_with_label("Karte"); + button2 = gtk_button_new_with_label("Ziel"); + + gtk_table_attach(GTK_TABLE(table), label_country, 0, 1, 0, 1, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_postal, 1, 2, 0, 1, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_city, 2, 3, 0, 1, 0, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), entry_country, 0, 1, 1, 2, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), entry_postal, 1, 2, 1, 2, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), entry_city, 2, 3, 1, 2, 0, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), label_district, 0, 1, 2, 3, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_street, 1, 2, 2, 3, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), label_number, 2, 3, 2, 3, 0, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), entry_district, 0, 1, 3, 4, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), entry_street, 1, 2, 3, 4, 0, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), entry_number, 2, 3, 3, 4, 0, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), listbox, 0, 3, 4, 5, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0); + + gtk_table_attach(GTK_TABLE(table), button1, 0, 1, 5, 6, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0); + gtk_table_attach(GTK_TABLE(table), button2, 2, 3, 5, 6, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0); + + search->map_data=co->map_data; + search->clist=listbox; + gtk_signal_connect(GTK_OBJECT(entry_country), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(entry_postal), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(entry_city), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(entry_district), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(entry_street), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(entry_number), "changed", GTK_SIGNAL_FUNC(changed), search); + gtk_signal_connect(GTK_OBJECT(button1), "clicked", GTK_SIGNAL_FUNC(button_map), co); + gtk_signal_connect(GTK_OBJECT(button2), "clicked", GTK_SIGNAL_FUNC(button_destination), co); + gtk_widget_grab_focus(entry_city); + + gtk_container_add(GTK_CONTAINER(vbox), table); + gtk_container_add(GTK_CONTAINER(vbox), keyboard); + gtk_container_add(GTK_CONTAINER(window2), vbox); + handlerid = gtk_timeout_add(256, (GtkFunction) track_focus, NULL); + + gtk_signal_connect(GTK_OBJECT(listbox), "select-row", GTK_SIGNAL_FUNC(select_row), NULL); + + gtk_widget_show_all(window2); + + return 0; +} diff --git a/destination.h b/destination.h new file mode 100644 index 00000000..68530f8f --- /dev/null +++ b/destination.h @@ -0,0 +1,11 @@ +enum destination_type { + destination_type_town=4, + destination_type_poly=6, + destination_type_street=8, + destination_type_house=12, + destination_type_map_point=16, + destination_type_bookmark=128, +}; + +int destination_address(struct container *co); +int destination_set(struct container *co, enum destination_type type, char *text, struct coord *c); diff --git a/display.c b/display.c new file mode 100644 index 00000000..ca1874ae --- /dev/null +++ b/display.c @@ -0,0 +1,266 @@ +#include <malloc.h> +#include <math.h> +#include "display.h" +#include "graphics.h" + +struct graphics_image *icons; + +struct graphics_image * +get_icon(struct graphics *gr, char *name) +{ + struct graphics_image *curr=icons; + while (curr) { + if (! strcmp(curr->name, name) && curr->gr == gr) + return curr; + curr=curr->next; + } + curr=gr->image_new(gr, name); + curr->next=icons; + icons=curr; + return curr; +} + +static int +within_dist_point(struct point *p0, struct point *p1, int dist) +{ + if ((p0->x-p1->x)*(p0->x-p1->x) + (p0->y-p1->y)*(p0->y-p1->y) <= dist*dist) { + return 1; + } + return 0; +} + +static int +within_dist_line(struct point *p, struct point *line_p0, struct point *line_p1, int dist) +{ + int vx,vy,wx,wy; + int c1,c2; + struct point line_p; + + vx=line_p1->x-line_p0->x; + vy=line_p1->y-line_p0->y; + wx=p->x-line_p0->x; + wy=p->y-line_p0->y; + + c1=vx*wx+vy*wy; + if ( c1 <= 0 ) + return within_dist_point(p, line_p0, dist); + c2=vx*vx+vy*vy; + if ( c2 <= c1 ) + return within_dist_point(p, line_p1, dist); + + line_p.x=line_p0->x+vx*c1/c2; + line_p.y=line_p0->y+vy*c1/c2; + return within_dist_point(p, &line_p, dist); +} + +static int +within_polygon(struct point *p, struct point *poly_pnt, int count) +{ + int i, j, c = 0; + for (i = 0, j = count-1; i < count; j = i++) { + if ((((poly_pnt[i].y <= p->y) && ( p->y < poly_pnt[j].y )) || + ((poly_pnt[j].y <= p->y) && ( p->y < poly_pnt[i].y))) && + (poly_pnt->x < (poly_pnt[j].x - poly_pnt[i].x) * (p->y - poly_pnt[i].y) / (poly_pnt[j].y - poly_pnt[i].y) + poly_pnt[i].x)) { + c = !c; + } + } + return c; +} + +static int +within_dist_lines(struct point *p, struct point *line_pnt, int count, int dist) +{ + int i; + for (i = 0 ; i < count-1 ; i++) { + if (within_dist_line(p,line_pnt+i,line_pnt+i+1,dist)) { + return 1; + } + } + return 0; +} + +void +display_free(struct display_list **list, int count) +{ + struct display_list *curr,*next; + while (count--) { + curr=*list; + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } + *list++=NULL; + } +} + +void * +display_add(struct display_list **head, int type, int attr, char *label, int count, struct point *p, void (*info)(struct display_list *list, struct popup_item **item),void *data, int data_size) +{ + struct display_list *new; + int label_len=0; + + if (! data) + data_size=0; + + if (label) + label_len=strlen(label)+1; + new=g_malloc(sizeof(*new)+count*sizeof(*p)+label_len+data_size); + new->type=type; + new->attr=attr; + new->info=info; + if (label) { + new->label=(char *)new+sizeof(*new)+count*sizeof(*p); + strcpy(new->label, label); + } else + new->label=NULL; + new->count=count; + memcpy(new->p, p, count*sizeof(*p)); + if (data_size) { + new->data=(char *)new+sizeof(*new)+count*sizeof(*p)+label_len; + memcpy(new->data, data, data_size); + } else + new->data=NULL; + new->next=*head; + *head=new; + return new->data; +} + +void +display_draw(struct display_list *list, struct graphics *gr, struct graphics_gc *gc_fill, struct graphics_gc *gc_line) +{ + struct graphics_image *icon; + int r=3; + struct point p; + while (list) { + switch (list->type) { + case 0: + gr->draw_polygon(gr, gc_fill, list->p, list->count); + if (gc_line) + gr->draw_lines(gr, gc_line, list->p, list->count); + break; + case 1: + case 2: + gr->draw_lines(gr, gc_fill, list->p, list->count); + break; + case 3: + case 4: + gr->draw_circle(gr, gc_fill, list->p, r); + break; + case 5: + icon=get_icon(gr, list->label); + if (icon) { + p.x=list->p[0].x - icon->width/2; + p.y=list->p[0].y - icon->height/2; + gr->draw_image(gr, gc_fill, &p, icon); + } + else + printf("invalid icon '%s'\n", list->label); + break; + } + list=list->next; + } +} + +void +display_find(struct point *p, struct display_list **in, int in_count, int maxdist, struct display_list **out, int out_count) +{ + int i=0; + struct display_list *curr; + + while (in_count--) { + curr=*in++; + while (curr) { + switch (curr->type) { + case 0: + if (within_polygon(p, curr->p, curr->count) || + within_dist_lines(p, curr->p, curr->count, maxdist)) + { + if (i < out_count) + out[i++]=curr; + } + break; + case 1: + case 2: + if (within_dist_lines(p, curr->p, curr->count, maxdist)) + { + if (i < out_count) + out[i++]=curr; + } + break; + case 3: + case 4: + case 5: + if (within_dist_point(p, curr->p, 8)) + { + if (i < out_count) + out[i++]=curr; + } + break; + } + curr=curr->next; + } + } + if (i < out_count) + out[i]=NULL; +} + + +static void +label_line(struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, struct point *p, int count, char *label) +{ + int i,x,y,tl; + double dx,dy,l; + struct point p_t; + + tl=strlen(label)*400; + for (i = 0 ; i < count-1 ; i++) { + dx=p[i+1].x-p[i].x; + dx*=100; + dy=p[i+1].y-p[i].y; + dy*=100; + l=(int)sqrt((float)(dx*dx+dy*dy)); + if (l > tl) { + x=p[i].x; + y=p[i].y; + if (dx < 0) { + dx=-dx; + dy=-dy; + x=p[i+1].x; + y=p[i+1].y; + } + x+=(l-tl)*dx/l/200; + y+=(l-tl)*dy/l/200; + x-=dy*45/l/10; + y+=dx*45/l/10; + p_t.x=x; + p_t.y=y; +#if 0 + printf("display_text: '%s', %d, %d, %d, %d %d\n", label, x, y, dx*0x10000/l, dy*0x10000/l, l); +#endif + gr->draw_text(gr, fg, bg, font, label, &p_t, dx*0x10000/l, dy*0x10000/l); + } + } +} + +void +display_labels(struct display_list *list, struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font) +{ + struct point p; + while (list) { + if (list->label) { + switch (list->type) { + case 1: + case 2: + label_line(gr, fg, bg, font, list->p, list->count, list->label); + break; + case 3: + p.x=list->p[0].x+3; + p.y=list->p[0].y+10; + gr->draw_text(gr, fg, bg, font, list->label, &p, 0x10000, 0); + break; + } + } + list=list->next; + } +} diff --git a/display.h b/display.h new file mode 100644 index 00000000..952381f2 --- /dev/null +++ b/display.h @@ -0,0 +1,24 @@ +#include "point.h" + +struct popup_item; +struct graphics; +struct graphics_gc; +struct graphics_font; + +struct display_list { + struct display_list *next; + void *data; + int type; + int attr; + char *label; + int count; + void (*info)(struct display_list *list, struct popup_item **popup); + struct point p[0]; +}; +void *display_add(struct display_list **head, int type, int attr, char *label, int count, struct point *p, void (*info)(struct display_list *list, struct popup_item **popup), void *data, int data_size); + +void display_free(struct display_list **list, int count); + +void display_draw(struct display_list *list, struct graphics *gr, struct graphics_gc *gc_fill, struct graphics_gc *gc_line); +void display_find(struct point *pnt, struct display_list **in, int in_count, int maxdist, struct display_list **out, int out_count); +void display_labels(struct display_list *list, struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font); diff --git a/draw_info.h b/draw_info.h new file mode 100644 index 00000000..6acee92c --- /dev/null +++ b/draw_info.h @@ -0,0 +1,5 @@ +struct draw_info { + struct container *co; + int display; + int limit; +}; diff --git a/fib-1.1/Makefile.in b/fib-1.1/Makefile.in new file mode 100644 index 00000000..d4829377 --- /dev/null +++ b/fib-1.1/Makefile.in @@ -0,0 +1,116 @@ +# $Id: Makefile.in,v 1.1 2005-12-02 10:41:56 martin-s Exp $ +# + +SHELL = /bin/sh + +LIB = fib + +SRCS = fib.c +OBJS = fib.o +SOBJS = fib.so +POBJS = fib.po + +INCS = fib.h + +TESTPROG = use +TESTSRCS = use.c +TESTOBJS = use.o + +REGRESS_PROG = fibtest fibtest2 tt + +DEBUG = -g -Wall -Werror +#OPT = -O2 +PROFILE = -pg +LIBOPTS = -DFH_STATS # -DNO_FREE + +srcdir = @srcdir@ + +AFLAGS = -Wall -I$(srcdir) $(DEBUG) $(OPT) $(LIBOPTS) $(CFLAGS) + +MAJOR = 1 +ARNAME = lib$(LIB).a +SONAME = lib$(LIB).so.$(MAJOR) +PANAME = lib$(LIB)_p.a + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +LIBDIR = @libdir@ +LIBOWN = 0 +LIBGRP = 0 +LIBMOD = 0444 +INCDIR = @includedir@ +INCOWN = 0 +INCGRP = 0 +INCMOD = 0444 + +all: $(ARNAME) $(SONAME) $(PANAME) + +$(ARNAME): $(OBJS) + $(AR) rc $@ $(OBJS) + +$(SONAME): $(SOBJS) + $(CC) -shared -o $@ $(SOBJS) + +$(PANAME): $(POBJS) + $(AR) rc $@ $(POBJS) + +$(TESTPROG): $(TESTOBJS) $(ARNAME) + $(CC) -static $(CFLAGS) -o $@ $(TESTOBJS) $(ARNAME) $(PROFILE) + +deepclean: clean + rm -f Makefile config.cache config.log config.status configure + +clean: regressclean + rm -f $(ARNAME) $(OBJS) $(SONAME) $(SOBJS) $(PANAME) $(POBJS) \ + $(TESTPROG) $(TESTOBJS) .depend + +install: $(ARNAME) $(SONAME) $(PANAME) + mkdir -p -m 755 $(LIBDIR) + for i in $(ARNAME) $(SONAME) $(PANAME); do \ + cp $$i $(LIBDIR); \ + chown $(LIBOWN):$(LIBGRP) $(LIBDIR)/$$i; \ + chmod $(LIBMOD) $(LIBDIR)/$$i; \ + done + mkdir -p -m 755 $(INCDIR) + for i in $(INCS); do \ + cp $$i $(INCDIR); \ + chown $(INCOWN):$(INCGRP) $(INCDIR)/$$i; \ + chmod $(INCMOD) $(INCDIR)/$$i; \ + done + +depend: + mkdep $(AFLAGS) $(SRCS) + +$(srcdir)/configure: configure.in + cd $(srcdir) && autoconf + +Makefile: Makefile.in config.status + ./config.status + +config.status: configure + ./config.status --recheck + +regress: $(REGRESS_PROG) + @for i in $(REGRESS_PROG); do \ + echo Regression for $$i; \ + ./$$i > regress.new; \ + diff $${i}.out regress.new; \ + done + rm regress.new + +regressclean: + rm -f $(REGRESS_PROG) + +.SUFFIXES: +.SUFFIXES: .so .po .c .o +.c.so: + $(CC) -fpic $(AFLAGS) -c $< -o $@ + +.c.po: + $(CC) $(PROFILE) $(AFLAGS) -c $< -o $@ + +.c.o: + $(CC) $(CPPFLAGS) $(AFLAGS) -c $< -o $@ + +.c: $(ARNAME) + $(CC) $(CPPFLAGS) $(AFLAGS) -o $@ $< $(ARNAME) diff --git a/fib-1.1/README b/fib-1.1/README new file mode 100644 index 00000000..eabcd5f8 --- /dev/null +++ b/fib-1.1/README @@ -0,0 +1,26 @@ +Version 1.1 now supports increasing the key using the fh_replace* +functions. Previously it would simply return NULL when you tried to +increase the key. It also improves performance slightly by only calling +checkcons when we are about to use it, at extract, instead of calling it +on every insert. + +I have now fixed fh_union and it properly updates the minimum. + +Thanks to Ryan Earl for pointing out that in fh_consolidate, it is VERY +time consuming to constantly malloc/free an array of pointers. The array +is small enough that simply reallocating when more pointers are needed +is ok. + +Thanks to Thomas Eschbach and Wolfgang Guenther who have pointed out bugs +with my code. Wolfgang Guenther provided a fix which put in on the correct +track for where the bug was. They have also provided a few test programs +that exhibited other bugs which I have now integrated into my source so +that you can easily regress test the library. + +I have reciently completed a review of the code. I have made a number +of improvements with a few minor interface changes. There is another +improvement to the rh_replace* family of functions to help eliminate +redundant code. + +I'm still planning on writing a type safe memory allocator for use with +the code instead of using malloc to hopefully improve performance slightly. diff --git a/fib-1.1/configure b/fib-1.1/configure new file mode 100755 index 00000000..62eaa3d0 --- /dev/null +++ b/fib-1.1/configure @@ -0,0 +1,1045 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=fib.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:529: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 544 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:550: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 561 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:567: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 578 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:584: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:609: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 614 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:622: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 639 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 657 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 678 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:689: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +for ac_hdr in limits.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:716: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 721 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:726: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:754: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 761 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:768: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +cat > conftest.defs <<\EOF +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g +s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g +s%\[%\\&%g +s%\]%\\&%g +s%\$%$$%g +EOF +DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` +rm -f conftest.defs + + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@CPP@%$CPP%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/fib-1.1/configure.in b/fib-1.1/configure.in new file mode 100644 index 00000000..82701527 --- /dev/null +++ b/fib-1.1/configure.in @@ -0,0 +1,17 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(fib.c) + +dnl Checks for programs. + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(limits.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE + +dnl Checks for library functions. + +AC_OUTPUT(Makefile) diff --git a/fib-1.1/fh_extractmin.3 b/fib-1.1/fh_extractmin.3 new file mode 100644 index 00000000..e1492b40 --- /dev/null +++ b/fib-1.1/fh_extractmin.3 @@ -0,0 +1,97 @@ +.TH FH_EXTRACTMIN 3 "29 Mar 2000" "libfib" +.SH NAME +fh_extractmin \- extract minimum element from a Fibonacci Heap +.SH SYNOPSIS +#include <fib.h> +.PP +void * +.PD 0 +.HP 8 +.BR fh_extractmin "(struct fibheap *heap)" +.PD +.PP +void * +.PD 0 +.HP 8 +.BR fh_min "(struct fibheap *heap)" +.PD +.PP +void * +.PD 0 +.HP 8 +.BR fh_replacedata "(struct fibheap *heap, struct fibheap_el *elem, void *data)" +.PD +.PP +void * +.PD 0 +.HP 8 +.BR fh_delete "(struct fibheap *heap, struct fibheap_el *elem)" +.PD +.PP +void +.PD 0 +.HP 8 +.BR fh_deleteheap "(struct fibheap *heap)" +.PD +.PP +struct fibheap * +.PD 0 +.HP 8 +.BR fh_union "(struct fibheap *heapa, struct fibheap *heapb)" +.PD +.SH DESCRIPTION +These functions are shared between both key heaps and normal heaps. +.PP +Once a +.B elem +pointer has been passed to +.BR fh_delete (3) +that +.B elem +pointer may be reused to store another datum. +You should make sure that you destroy any copies of the pointer. +.SH RETURN VALUES +The +.B fh_extractmin +function returns the value of +.B data +that is the minimum element and removes it from the heap. +.PP +The +.B fh_min +function returns the current minimum element but does +.I not +remove it from the heap. +.PP +The +.B fh_replacedata +replaces the data in +.B elem +and returns the old data. +.PP +The +.B fh_delete +function removes +.B elem +from the heap, and returns the +.B data +that was stored in the element. +.PP +The +.B fh_deleteheap +complete destroys the heap. It does not free any user supplied +.B data +elements stored in the heap. +.PP +The +.B fh_union +function returns the union of the two heaps +.B heapa +and +.BR heapb . +.SH SEE ALSO +.BR fh_makeheap (3), +.BR fh_makekeyheap (3) +.SH AUTHORS +This library and man page was writen by John-Mark Gurney <gurney_j@efn.org>. +.SH BUGS diff --git a/fib-1.1/fh_makeheap.3 b/fib-1.1/fh_makeheap.3 new file mode 100644 index 00000000..bd867cd0 --- /dev/null +++ b/fib-1.1/fh_makeheap.3 @@ -0,0 +1,17 @@ +.TH FH_MAKEHEAP 3 "29 Mar 2000" "libfib" +.SH NAME +fh_makeheap \- make a Fibonacci Heap +.SH SYNOPSIS +.nf +#include <fib.h> +.PP +struct fibheap * +.BR fh_makeheap (void) +.fi +.SH DESCRIPTION +.SH RETURN VALUES +.SH FILES +.SH SEE ALSO +.SH AUTHORS +This library and man page was writen by John-Mark Gurney <gurney_j@efn.org>. +.SH BUGS diff --git a/fib-1.1/fh_makekeyheap.3 b/fib-1.1/fh_makekeyheap.3 new file mode 100644 index 00000000..f55d4307 --- /dev/null +++ b/fib-1.1/fh_makekeyheap.3 @@ -0,0 +1,84 @@ +.TH FH_MAKEKEYHEAP 3 "29 Mar 2000" "libfib" +.SH NAME +fh_makekeyheap \- make a Fibonacci key Heap +.SH SYNOPSIS +#include <fib.h> +.PP +struct fibheap * +.PD 0 +.HP 8 +.BR fh_makekeyheap (void) +.PD +.PP +struct fibheap_el * +.PD 0 +.HP 8 +.BR fh_insertkey "(struct fibheap *heap, int key, void *data)" +.PD +.PP +int +.PD 0 +.HP 8 +.BR fh_minkey "(struct fibheap *heap)" +.PD +.PP +void * +.PD 0 +.HP 8 +.BR fh_replacekey "(struct fibheap *heap, struct fibheap_el *elem, int key)" +.PD +.PP +void * +.PD 0 +.HP 8 +.BR fh_replacekeydata "(struct fibheap *heap, struct fibheap_el *elem, int key, void *data)" +.PD +.SH DESCRIPTION +The +.B fh_makekeyheap +function makes a Fibonacci heap which does ordering based on an +integer key that is given in addition to the data. +This menthod is useful so that you can eliminate the need to call +a comparision function to order the data in the heap. +.PP +The pointer to the structure +.B fibheap +returned by +.B fh_makekeyheap +is an opaque structure. The the pointer can only be passed to other +functions in the +.B libfib +library. +.PP +The +.B fh_insertkey +function inserts the +.B data +element into the heap with a value of +.BR key . +The pointer returned can be used in calls to functions like +.BR fh_delete (3) +to delete the key from the heap before it gets extracted via +.BR fh_extractmin (3). +.SH RETURN VALUES +The +.B fh_makekeyheap +function returns a pointer to a heap structure used to insert and extract +data elements. +.PP +The +.B fh_insertkey +functions returns a pointer to a heap element structure which can be used +to manimulate that data element in the heap. +.PP +The +.B fh_minkey +function returns the integer key of the data at the top of the heap. If you would like to view the data, see +.BR fh_min (3). +.SH SEE ALSO +.BR fh_extractmin (3) +.SH AUTHORS +This library and man page was writen by John-Mark Gurney <gurney_j@efn.org>. +.SH BUGS +A key heap does not provide a way for handling key collitions and deffering +decission to a user provided function to resolve colissions. diff --git a/fib-1.1/fib.c b/fib-1.1/fib.c new file mode 100644 index 00000000..ace5d129 --- /dev/null +++ b/fib-1.1/fib.c @@ -0,0 +1,696 @@ +/*- + * Copyright 1997-2003 John-Mark Gurney. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: fib.c,v 1.1 2005-12-02 10:41:56 martin-s Exp $ + * + */ + +#include <fib.h> +#include <fibpriv.h> + +#include <limits.h> +#include <stdlib.h> + +#define swap(type, a, b) \ + do { \ + type c; \ + c = a; \ + a = b; \ + b = c; \ + } while (0) \ + +#define INT_BITS (sizeof(int) * 8) +static inline int +ceillog2(unsigned int a) +{ + int oa; + int i; + int b; + + oa = a; + b = INT_BITS / 2; + i = 0; + while (b) { + i = (i << 1); + if (a >= (1 << b)) { + a /= (1 << b); + i = i | 1; + } else + a &= (1 << b) - 1; + b /= 2; + } + if ((1 << i) == oa) + return i; + else + return i + 1; +} + +/* + * Private Heap Functions + */ +static void +fh_deleteel(struct fibheap *h, struct fibheap_el *x) +{ + void *data; + int key; + + data = x->fhe_data; + key = x->fhe_key; + + if (!h->fh_keys) + fh_replacedata(h, x, h->fh_neginf); + else + fh_replacekey(h, x, INT_MIN); + if (fh_extractminel(h) != x) { + /* + * XXX - This should never happen as fh_replace should set it + * to min. + */ + abort(); + } + + x->fhe_data = data; + x->fhe_key = key; +} + +static void +fh_initheap(struct fibheap *new) +{ + new->fh_cmp_fnct = NULL; + new->fh_neginf = NULL; + new->fh_n = 0; + new->fh_Dl = -1; + new->fh_cons = NULL; + new->fh_min = NULL; + new->fh_root = NULL; + new->fh_keys = 0; +#ifdef FH_STATS + new->fh_maxn = 0; + new->fh_ninserts = 0; + new->fh_nextracts = 0; +#endif +} + +static void +fh_destroyheap(struct fibheap *h) +{ + h->fh_cmp_fnct = NULL; + h->fh_neginf = NULL; + if (h->fh_cons != NULL) + free(h->fh_cons); + h->fh_cons = NULL; + free(h); +} + +/* + * Public Heap Functions + */ +struct fibheap * +fh_makekeyheap() +{ + struct fibheap *n; + + if ((n = malloc(sizeof *n)) == NULL) + return NULL; + + fh_initheap(n); + n->fh_keys = 1; + + return n; +} + +struct fibheap * +fh_makeheap() +{ + struct fibheap *n; + + if ((n = malloc(sizeof *n)) == NULL) + return NULL; + + fh_initheap(n); + + return n; +} + +voidcmp +fh_setcmp(struct fibheap *h, voidcmp fnct) +{ + voidcmp oldfnct; + + oldfnct = h->fh_cmp_fnct; + h->fh_cmp_fnct = fnct; + + return oldfnct; +} + +void * +fh_setneginf(struct fibheap *h, void *data) +{ + void *old; + + old = h->fh_neginf; + h->fh_neginf = data; + + return old; +} + +struct fibheap * +fh_union(struct fibheap *ha, struct fibheap *hb) +{ + struct fibheap_el *x; + + if (ha->fh_root == NULL || hb->fh_root == NULL) { + /* either one or both are empty */ + if (ha->fh_root == NULL) { + fh_destroyheap(ha); + return hb; + } else { + fh_destroyheap(hb); + return ha; + } + } + ha->fh_root->fhe_left->fhe_right = hb->fh_root; + hb->fh_root->fhe_left->fhe_right = ha->fh_root; + x = ha->fh_root->fhe_left; + ha->fh_root->fhe_left = hb->fh_root->fhe_left; + hb->fh_root->fhe_left = x; + ha->fh_n += hb->fh_n; + /* + * we probably should also keep stats on number of unions + */ + + /* set fh_min if necessary */ + if (fh_compare(ha, hb->fh_min, ha->fh_min) < 0) + ha->fh_min = hb->fh_min; + + fh_destroyheap(hb); + return ha; +} + +void +fh_deleteheap(struct fibheap *h) +{ + /* + * We could do this even faster by walking each binomial tree, but + * this is simpler to code. + */ + while (h->fh_min != NULL) + fhe_destroy(fh_extractminel(h)); + + fh_destroyheap(h); +} + +/* + * Public Key Heap Functions + */ +struct fibheap_el * +fh_insertkey(struct fibheap *h, int key, void *data) +{ + struct fibheap_el *x; + + if ((x = fhe_newelem()) == NULL) + return NULL; + + /* just insert on root list, and make sure it's not the new min */ + x->fhe_data = data; + x->fhe_key = key; + + fh_insertel(h, x); + + return x; +} + +int +fh_minkey(struct fibheap *h) +{ + if (h->fh_min == NULL) + return INT_MIN; + return h->fh_min->fhe_key; +} + +int +fh_replacekey(struct fibheap *h, struct fibheap_el *x, int key) +{ + int ret; + + ret = x->fhe_key; + (void)fh_replacekeydata(h, x, key, x->fhe_data); + + return ret; +} + +void * +fh_replacekeydata(struct fibheap *h, struct fibheap_el *x, int key, void *data) +{ + void *odata; + int okey; + struct fibheap_el *y; + int r; + + odata = x->fhe_data; + okey = x->fhe_key; + + /* + * we can increase a key by deleting and reinserting, that + * requires O(lgn) time. + */ + if ((r = fh_comparedata(h, key, data, x)) > 0) { + /* XXX - bad code! */ + abort(); + fh_deleteel(h, x); + + x->fhe_data = data; + x->fhe_key = key; + + fh_insertel(h, x); + + return odata; + } + + x->fhe_data = data; + x->fhe_key = key; + + /* because they are equal, we don't have to do anything */ + if (r == 0) + return odata; + + y = x->fhe_p; + + if (h->fh_keys && okey == key) + return odata; + + if (y != NULL && fh_compare(h, x, y) <= 0) { + fh_cut(h, x, y); + fh_cascading_cut(h, y); + } + + /* + * the = is so that the call from fh_delete will delete the proper + * element. + */ + if (fh_compare(h, x, h->fh_min) <= 0) + h->fh_min = x; + + return odata; +} + +/* + * Public void * Heap Functions + */ +/* + * this will return these values: + * NULL failed for some reason + * ptr token to use for manipulation of data + */ +struct fibheap_el * +fh_insert(struct fibheap *h, void *data) +{ + struct fibheap_el *x; + + if ((x = fhe_newelem()) == NULL) + return NULL; + + /* just insert on root list, and make sure it's not the new min */ + x->fhe_data = data; + + fh_insertel(h, x); + + return x; +} + +void * +fh_min(struct fibheap *h) +{ + if (h->fh_min == NULL) + return NULL; + return h->fh_min->fhe_data; +} + +void * +fh_extractmin(struct fibheap *h) +{ + struct fibheap_el *z; + void *ret; + + ret = NULL; + + if (h->fh_min != NULL) { + z = fh_extractminel(h); + ret = z->fhe_data; +#ifndef NO_FREE + fhe_destroy(z); +#endif + + } + + return ret; +} + +void * +fh_replacedata(struct fibheap *h, struct fibheap_el *x, void *data) +{ + return fh_replacekeydata(h, x, x->fhe_key, data); +} + +void * +fh_delete(struct fibheap *h, struct fibheap_el *x) +{ + void *k; + + k = x->fhe_data; + if (!h->fh_keys) + fh_replacedata(h, x, h->fh_neginf); + else + fh_replacekey(h, x, INT_MIN); + fh_extractmin(h); + + return k; +} + +/* + * Statistics Functions + */ +#ifdef FH_STATS +int +fh_maxn(struct fibheap *h) +{ + return h->fh_maxn; +} + +int +fh_ninserts(struct fibheap *h) +{ + return h->fh_ninserts; +} + +int +fh_nextracts(struct fibheap *h) +{ + return h->fh_nextracts; +} +#endif + +/* + * begin of private element fuctions + */ +static struct fibheap_el * +fh_extractminel(struct fibheap *h) +{ + struct fibheap_el *ret; + struct fibheap_el *x, *y, *orig; + + ret = h->fh_min; + + orig = NULL; + /* put all the children on the root list */ + /* for true consistancy, we should use fhe_remove */ + for(x = ret->fhe_child; x != orig && x != NULL;) { + if (orig == NULL) + orig = x; + y = x->fhe_right; + x->fhe_p = NULL; + fh_insertrootlist(h, x); + x = y; + } + /* remove minimum from root list */ + fh_removerootlist(h, ret); + h->fh_n--; + + /* if we aren't empty, consolidate the heap */ + if (h->fh_n == 0) + h->fh_min = NULL; + else { + h->fh_min = ret->fhe_right; + fh_consolidate(h); + } + +#ifdef FH_STATS + h->fh_nextracts++; +#endif + + return ret; +} + +static void +fh_insertrootlist(struct fibheap *h, struct fibheap_el *x) +{ + if (h->fh_root == NULL) { + h->fh_root = x; + x->fhe_left = x; + x->fhe_right = x; + return; + } + + fhe_insertafter(h->fh_root, x); +} + +static void +fh_removerootlist(struct fibheap *h, struct fibheap_el *x) +{ + if (x->fhe_left == x) + h->fh_root = NULL; + else + h->fh_root = fhe_remove(x); +} + +static void +fh_consolidate(struct fibheap *h) +{ + struct fibheap_el **a; + struct fibheap_el *w; + struct fibheap_el *y; + struct fibheap_el *x; + int i; + int d; + int D; + + fh_checkcons(h); + + /* assign a the value of h->fh_cons so I don't have to rewrite code */ + D = h->fh_Dl + 1; + a = h->fh_cons; + + for (i = 0; i < D; i++) + a[i] = NULL; + + while ((w = h->fh_root) != NULL) { + x = w; + fh_removerootlist(h, w); + d = x->fhe_degree; + /* XXX - assert that d < D */ + while(a[d] != NULL) { + y = a[d]; + if (fh_compare(h, x, y) > 0) + swap(struct fibheap_el *, x, y); + fh_heaplink(h, y, x); + a[d] = NULL; + d++; + } + a[d] = x; + } + h->fh_min = NULL; + for (i = 0; i < D; i++) + if (a[i] != NULL) { + fh_insertrootlist(h, a[i]); + if (h->fh_min == NULL || fh_compare(h, a[i], + h->fh_min) < 0) + h->fh_min = a[i]; + } +} + +static void +fh_heaplink(struct fibheap *h, struct fibheap_el *y, struct fibheap_el *x) +{ + /* make y a child of x */ + if (x->fhe_child == NULL) + x->fhe_child = y; + else + fhe_insertbefore(x->fhe_child, y); + y->fhe_p = x; + x->fhe_degree++; + y->fhe_mark = 0; +} + +static void +fh_cut(struct fibheap *h, struct fibheap_el *x, struct fibheap_el *y) +{ + fhe_remove(x); + y->fhe_degree--; + fh_insertrootlist(h, x); + x->fhe_p = NULL; + x->fhe_mark = 0; +} + +static void +fh_cascading_cut(struct fibheap *h, struct fibheap_el *y) +{ + struct fibheap_el *z; + + while ((z = y->fhe_p) != NULL) { + if (y->fhe_mark == 0) { + y->fhe_mark = 1; + return; + } else { + fh_cut(h, y, z); + y = z; + } + } +} + +/* + * begining of handling elements of fibheap + */ +static struct fibheap_el * +fhe_newelem() +{ + struct fibheap_el *e; + + if ((e = malloc(sizeof *e)) == NULL) + return NULL; + + fhe_initelem(e); + + return e; +} + +static void +fhe_initelem(struct fibheap_el *e) +{ + e->fhe_degree = 0; + e->fhe_mark = 0; + e->fhe_p = NULL; + e->fhe_child = NULL; + e->fhe_left = e; + e->fhe_right = e; + e->fhe_data = NULL; +} + +static void +fhe_insertafter(struct fibheap_el *a, struct fibheap_el *b) +{ + if (a == a->fhe_right) { + a->fhe_right = b; + a->fhe_left = b; + b->fhe_right = a; + b->fhe_left = a; + } else { + b->fhe_right = a->fhe_right; + a->fhe_right->fhe_left = b; + a->fhe_right = b; + b->fhe_left = a; + } +} + +static inline void +fhe_insertbefore(struct fibheap_el *a, struct fibheap_el *b) +{ + fhe_insertafter(a->fhe_left, b); +} + +static struct fibheap_el * +fhe_remove(struct fibheap_el *x) +{ + struct fibheap_el *ret; + + if (x == x->fhe_left) + ret = NULL; + else + ret = x->fhe_left; + + /* fix the parent pointer */ + if (x->fhe_p != NULL && x->fhe_p->fhe_child == x) + x->fhe_p->fhe_child = ret; + + x->fhe_right->fhe_left = x->fhe_left; + x->fhe_left->fhe_right = x->fhe_right; + + /* clear out hanging pointers */ + x->fhe_p = NULL; + x->fhe_left = x; + x->fhe_right = x; + + return ret; +} + +static void +fh_checkcons(struct fibheap *h) +{ + int oDl; + + /* make sure we have enough memory allocated to "reorganize" */ + if (h->fh_Dl == -1 || h->fh_n > (1 << h->fh_Dl)) { + oDl = h->fh_Dl; + if ((h->fh_Dl = ceillog2(h->fh_n) + 1) < 8) + h->fh_Dl = 8; + if (oDl != h->fh_Dl) + h->fh_cons = (struct fibheap_el **)realloc(h->fh_cons, + sizeof *h->fh_cons * (h->fh_Dl + 1)); + if (h->fh_cons == NULL) + abort(); + } +} + +static int +fh_compare(struct fibheap *h, struct fibheap_el *a, struct fibheap_el *b) +{ + if (h->fh_keys) { + if (a->fhe_key < b->fhe_key) + return -1; + if (a->fhe_key == b->fhe_key) + return 0; + return 1; + } else + return h->fh_cmp_fnct(a->fhe_data, b->fhe_data); +} + +static int +fh_comparedata(struct fibheap *h, int key, void *data, struct fibheap_el *b) +{ + struct fibheap_el a; + + a.fhe_key = key; + a.fhe_data = data; + + return fh_compare(h, &a, b); +} + +static void +fh_insertel(struct fibheap *h, struct fibheap_el *x) +{ + fh_insertrootlist(h, x); + + if (h->fh_min == NULL || (h->fh_keys ? x->fhe_key < h->fh_min->fhe_key + : h->fh_cmp_fnct(x->fhe_data, h->fh_min->fhe_data) < 0)) + h->fh_min = x; + + h->fh_n++; + +#ifdef FH_STATS + if (h->fh_n > h->fh_maxn) + h->fh_maxn = h->fh_n; + h->fh_ninserts++; +#endif + +} diff --git a/fib-1.1/fib.h b/fib-1.1/fib.h new file mode 100644 index 00000000..d8564d3c --- /dev/null +++ b/fib-1.1/fib.h @@ -0,0 +1,64 @@ +/*- + * Copyright 1997, 1998-2003 John-Mark Gurney. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: fib.h,v 1.1 2005-12-02 10:41:56 martin-s Exp $ + * + */ + +#ifndef _FIB_H_ +#define _FIB_H_ + +struct fibheap; +struct fibheap_el; +typedef int (*voidcmp)(void *, void *); + +/* functions for key heaps */ +struct fibheap *fh_makekeyheap(void); +struct fibheap_el *fh_insertkey(struct fibheap *, int, void *); +int fh_minkey(struct fibheap *); +int fh_replacekey(struct fibheap *, struct fibheap_el *, int); +void *fh_replacekeydata(struct fibheap *, struct fibheap_el *, int, void *); + +/* functions for void * heaps */ +struct fibheap *fh_makeheap(void); +voidcmp fh_setcmp(struct fibheap *, voidcmp); +void *fh_setneginf(struct fibheap *, void *); +struct fibheap_el *fh_insert(struct fibheap *, void *); + +/* shared functions */ +void *fh_extractmin(struct fibheap *); +void *fh_min(struct fibheap *); +void *fh_replacedata(struct fibheap *, struct fibheap_el *, void *); +void *fh_delete(struct fibheap *, struct fibheap_el *); +void fh_deleteheap(struct fibheap *); +struct fibheap *fh_union(struct fibheap *, struct fibheap *); + +#ifdef FH_STATS +int fh_maxn(struct fibheap *); +int fh_ninserts(struct fibheap *); +int fh_nextracts(struct fibheap *); +#endif + +#endif /* _FIB_H_ */ diff --git a/fib-1.1/fibpriv.h b/fib-1.1/fibpriv.h new file mode 100644 index 00000000..3984b261 --- /dev/null +++ b/fib-1.1/fibpriv.h @@ -0,0 +1,98 @@ +/*- + * Copyright 1997, 1999-2003 John-Mark Gurney. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: fibpriv.h,v 1.1 2005-12-02 10:41:56 martin-s Exp $ + * + */ + +#ifndef _FIBPRIV_H_ +#define _FIBPRIV_H_ + +struct fibheap_el; + +/* + * global heap operations + */ +struct fibheap { + int (*fh_cmp_fnct)(void *, void *); + int fh_n; + int fh_Dl; + struct fibheap_el **fh_cons; + struct fibheap_el *fh_min; + struct fibheap_el *fh_root; + void *fh_neginf; + int fh_keys : 1; +#ifdef FH_STATS + int fh_maxn; + int fh_ninserts; + int fh_nextracts; +#endif +}; + +static void fh_initheap(struct fibheap *); +static void fh_insertrootlist(struct fibheap *, struct fibheap_el *); +static void fh_removerootlist(struct fibheap *, struct fibheap_el *); +static void fh_consolidate(struct fibheap *); +static void fh_heaplink(struct fibheap *h, struct fibheap_el *y, + struct fibheap_el *x); +static void fh_cut(struct fibheap *, struct fibheap_el *, struct fibheap_el *); +static void fh_cascading_cut(struct fibheap *, struct fibheap_el *); +static struct fibheap_el *fh_extractminel(struct fibheap *); +static void fh_checkcons(struct fibheap *h); +static void fh_destroyheap(struct fibheap *h); +static int fh_compare(struct fibheap *h, struct fibheap_el *a, + struct fibheap_el *b); +static int fh_comparedata(struct fibheap *h, int key, void *data, + struct fibheap_el *b); +static void fh_insertel(struct fibheap *h, struct fibheap_el *x); +static void fh_deleteel(struct fibheap *h, struct fibheap_el *x); + +/* + * specific node operations + */ +struct fibheap_el { + int fhe_degree; + int fhe_mark; + struct fibheap_el *fhe_p; + struct fibheap_el *fhe_child; + struct fibheap_el *fhe_left; + struct fibheap_el *fhe_right; + int fhe_key; + void *fhe_data; +}; + +static struct fibheap_el *fhe_newelem(void); +static void fhe_initelem(struct fibheap_el *); +static void fhe_insertafter(struct fibheap_el *a, struct fibheap_el *b); +static inline void fhe_insertbefore(struct fibheap_el *a, struct fibheap_el *b); +static struct fibheap_el *fhe_remove(struct fibheap_el *a); +#define fhe_destroy(x) free((x)) + +/* + * general functions + */ +static inline int ceillog2(unsigned int a); + +#endif /* _FIBPRIV_H_ */ diff --git a/fib-1.1/fibtest.c b/fib-1.1/fibtest.c new file mode 100644 index 00000000..c7be1e9c --- /dev/null +++ b/fib-1.1/fibtest.c @@ -0,0 +1,80 @@ +#include <stdio.h> +#include <stdlib.h> +#include "fib.h" + +int main(void) +{ + struct fibheap *a; + void *arr[10]; + int i; + + a = fh_makekeyheap(); + + for (i=1 ; i < 10 ; i++) + { + arr[i]= fh_insertkey(a,0,(void *)i); + printf("adding: 0 %d \n",i); + } + + printf(" \n"); + fh_replacekey(a, arr[1],-1); + fh_replacekey(a, arr[6],-1); + fh_replacekey(a, arr[4],-1); + fh_replacekey(a, arr[2],-1); + fh_replacekey(a, arr[8],-1); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[7],-33); +/* -> node 7 becomes root node, but is still pointed to by node 6 */ + fh_replacekey(a, arr[4],-36); + fh_replacekey(a, arr[3],-1); + fh_replacekey(a, arr[9],-81); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[6],-68); + fh_replacekey(a, arr[2],-69); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[1],-52); + fh_replacekey(a, arr[3],-2); + fh_replacekey(a, arr[4],-120); + fh_replacekey(a, arr[5],-48); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[3],-3); + fh_replacekey(a, arr[5],-63); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[5],-110); + fh_replacekey(a, arr[7],-115); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[5],-188); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[3],-4); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + printf("value(minkey) %d\n",fh_minkey(a)); + printf("id: %d\n\n", (int)fh_extractmin(a)); + + fh_deleteheap(a); + + return 0; +} diff --git a/fib-1.1/fibtest.out b/fib-1.1/fibtest.out new file mode 100644 index 00000000..285bd26b --- /dev/null +++ b/fib-1.1/fibtest.out @@ -0,0 +1,37 @@ +adding: 0 1 +adding: 0 2 +adding: 0 3 +adding: 0 4 +adding: 0 5 +adding: 0 6 +adding: 0 7 +adding: 0 8 +adding: 0 9 + +value(minkey) -1 +id: 8 + +value(minkey) -81 +id: 9 + +value(minkey) -69 +id: 2 + +value(minkey) -120 +id: 4 + +value(minkey) -68 +id: 6 + +value(minkey) -115 +id: 7 + +value(minkey) -188 +id: 5 + +value(minkey) -52 +id: 1 + +value(minkey) -4 +id: 3 + diff --git a/fib-1.1/fibtest2.c b/fib-1.1/fibtest2.c new file mode 100644 index 00000000..8a623b63 --- /dev/null +++ b/fib-1.1/fibtest2.c @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include "fib.h" + +int +main(void) { + struct fibheap *a; + void *arr[10]; + int i; + a = fh_makekeyheap(); + + for (i=1 ; i < 10 ; i++) + { + arr[i]= fh_insertkey(a,0,(void *)i); + printf("adding: 0 %d \n",i); + } + + printf(" \n"); + fh_replacekey(a, arr[1],-38); + fh_replacekey(a, arr[7],-34); + + printf("wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + fh_replacekey(a, arr[2],-55); + fh_replacekey(a, arr[5],-56); + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[4],-1); + fh_replacekey(a, arr[2],-102); + fh_replacekey(a, arr[6],-1); + fh_replacekey(a, arr[9],-1); + fh_replacekey(a, arr[8],-4); + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + fh_replacekey(a, arr[3],-74); + fh_replacekey(a, arr[8],-55); + fh_replacekey(a, arr[4],-2); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + fh_replacekey(a, arr[4],-3); + fh_replacekey(a, arr[6],-2); + fh_replacekey(a, arr[7],-99); + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + fh_replacekey(a, arr[6],-3); + fh_replacekey(a, arr[4],-4); + fh_replacekey(a, arr[8],-94); + fh_replacekey(a, arr[9],-2); + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + fh_replacekey(a, arr[6],-4); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + /*fh_replacekey(a, arr[9],-3);*/ + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + /*fh_replacekey(a, arr[9],-49);*/ + + fh_deleteheap(a); + + return 0; +} diff --git a/fib-1.1/fibtest2.out b/fib-1.1/fibtest2.out new file mode 100644 index 00000000..e9d1704f --- /dev/null +++ b/fib-1.1/fibtest2.out @@ -0,0 +1,37 @@ +adding: 0 1 +adding: 0 2 +adding: 0 3 +adding: 0 4 +adding: 0 5 +adding: 0 6 +adding: 0 7 +adding: 0 8 +adding: 0 9 + +wert(minkey) -38 +Knoten: 1 + +Wert(minkey) -56 +Knoten: 5 + +Wert(minkey) -102 +Knoten: 2 + +Wert(minkey) -74 +Knoten: 3 + +Wert(minkey) -99 +Knoten: 7 + +Wert(minkey) -94 +Knoten: 8 + +Wert(minkey) -4 +Knoten: 6 + +Wert(minkey) -4 +Knoten: 4 + +Wert(minkey) -2 +Knoten: 9 + diff --git a/fib-1.1/tt.c b/fib-1.1/tt.c new file mode 100644 index 00000000..26db1d2c --- /dev/null +++ b/fib-1.1/tt.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include "fib.h" + +int main(void) +{ + + struct fibheap *a; + void *arr[10]; + int i; + + a = fh_makekeyheap(); + + for (i=1 ; i < 8 ; i++) + { + arr[i]= fh_insertkey(a,0,(void *)i); + printf("adding: 0 %d \n",i); + } + + printf(" \n"); + + fh_replacekey(a, arr[1],-2); + fh_replacekey(a, arr[4],-3); + fh_replacekey(a, arr[7],-5); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[3],-2); + fh_replacekey(a, arr[6],-1); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[1],-9); + fh_replacekey(a, arr[5],-3); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[2],-4); + fh_replacekey(a, arr[5],-5); + fh_replacekey(a, arr[6],-3); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_replacekey(a, arr[2],-6); + fh_replacekey(a, arr[6],-6); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + printf("Wert(minkey) %d\n",fh_minkey(a)); + printf("Knoten: %d\n\n", (int)fh_extractmin(a)); + + fh_deleteheap(a); + + return 0; +} + diff --git a/fib-1.1/tt.out b/fib-1.1/tt.out new file mode 100644 index 00000000..37a8a47c --- /dev/null +++ b/fib-1.1/tt.out @@ -0,0 +1,29 @@ +adding: 0 1 +adding: 0 2 +adding: 0 3 +adding: 0 4 +adding: 0 5 +adding: 0 6 +adding: 0 7 + +Wert(minkey) -5 +Knoten: 7 + +Wert(minkey) -3 +Knoten: 4 + +Wert(minkey) -9 +Knoten: 1 + +Wert(minkey) -5 +Knoten: 5 + +Wert(minkey) -6 +Knoten: 6 + +Wert(minkey) -6 +Knoten: 2 + +Wert(minkey) -2 +Knoten: 3 + diff --git a/fib-1.1/use.c b/fib-1.1/use.c new file mode 100644 index 00000000..e8db3279 --- /dev/null +++ b/fib-1.1/use.c @@ -0,0 +1,126 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include "fib.h" + +#define TESTCASE 1 + +#define COUNT 100000 +#define DIF 1000 +#define MAXEXT 10 +#define VERBOSE 1 + +int cmp(void *, void *); + +int +cmp(void *x, void *y) +{ + int a, b; + a = (int)x; + b = (int)y; + + if (a < b) + return -1; + if (a == b) + return 0; + return 1; +} + +int +main(void) +{ +#if !TESTCASE + struct fibheap_el *w; +#else + int e, j, k; +#endif + struct fibheap *a; + int i, x; + + a = fh_makeheap(); + fh_setcmp(a, cmp); + + srandom(time(NULL)); +#if TESTCASE +#if VERBOSE + printf("inserting: "); +#endif + e = 0; + for (i = 0; i < COUNT; i++) { +#if VERBOSE + if (i) + printf(", "); +#endif + fh_insert(a, (void *)(x = random()/10)); +#if VERBOSE + printf("%d", x); +#endif + if (i - e > DIF) { + k = random() % MAXEXT; + for (j = 0; j < k; j++, e++) + printf("throwing: %d\n", (int)fh_extractmin(a)); + } + } + +#if VERBOSE + printf("\nremaining: %d\n", COUNT - e); + printf("extracting: "); +#endif + for (i = 0; i < COUNT - e; i++) { +#if VERBOSE + if (i) + printf(", "); + printf("%d", (int)fh_extractmin(a)); +#else + fh_extractmin(a); +#endif + } +#if VERBOSE + printf("\n"); +#endif + if ((int)fh_extractmin(a) == 0) + printf("heap empty!\n"); + else { + printf("heap not empty! ERROR!\n"); + exit(1); + } +#else + w = fh_insert(a, (void *)6); + printf("adding: %d\n", 6); + fh_insert(a, (void *)9); + printf("adding: %d\n", 9); + fh_insert(a, (void *)1); + printf("adding: %d\n", 1); + for(i = 0; i < 5; i++) { + x = random()/10000; + printf("adding: %d\n", x); + fh_insert(a, (void *)x); + } + fh_insert(a, (void *)4); + printf("adding: %d\n", 4); + fh_insert(a, (void *)8); + printf("adding: %d\n", 8); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("deleting: %d\n", (int)fh_delete(a, w)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + for(i = 0; i < 5; i++) { + x = random()/10000; + printf("adding: %d\n", x); + fh_insert(a, (void *)x); + } + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); + printf("first: %d\n", (int)fh_extractmin(a)); +#endif + + fh_deleteheap(a); + + return 0; +} @@ -0,0 +1,124 @@ +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <malloc.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <dirent.h> +#include <stdio.h> +#include <glib.h> +#include "file.h" + +struct file * +file_create(char *name) +{ + int fd; + struct stat stat; + struct file *file=malloc(sizeof(*file)+strlen(name)+1); + + if (! file) + return file; + fd=open(name, O_RDONLY); + if (fd < 0) { + free(file); + return NULL; + } + fstat(fd, &stat); + file->size=stat.st_size; + file->name=(char *)file+sizeof(*file); + strcpy(file->name, name); + file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + g_assert(file->begin != NULL); + if (file->begin == (void *)0xffffffff) { + perror("mmap"); + } + g_assert(file->begin != (void *)0xffffffff); + file->end=file->begin+file->size; + file->private=NULL; + close(fd); + + g_assert(file != NULL); + return file; +} + +void +file_set_readonly(struct file *file) +{ + mprotect(file->begin, file->end-file->begin, PROT_READ); +} + +void * +file_opendir(char *dir) +{ + return opendir(dir); +} + +char * +file_readdir(void *hnd) +{ + struct dirent *ent; + + ent=readdir(hnd); + if (! ent) + return NULL; + return ent->d_name; +} + +void +file_closedir(void *hnd) +{ + closedir(hnd); +} + +struct file * +file_create_caseinsensitive(char *name) +{ + char dirname[strlen(name)+1]; + char *filename; + char *p; + void *d; + struct file *ret; + + ret=file_create(name); + if (ret) + return ret; + + strcpy(dirname, name); + p=dirname+strlen(name); + while (p > dirname) { + if (*p == '/') + break; + p--; + } + *p=0; + d=file_opendir(dirname); + if (d) { + *p++='/'; + while ((filename=file_readdir(d))) { + if (!strcasecmp(filename, p)) { + strcpy(p, filename); + ret=file_create(dirname); + if (ret) + break; + } + } + file_closedir(d); + } + return ret; +} + +void +file_destroy(struct file *f) +{ + munmap(f->begin, f->size); + free(f); +} + +int +file_get_param(struct file *file, struct param_list *param, int count) +{ + int i=count; + param_add_string("Filename", file->name, ¶m, &count); + param_add_hex("Size", file->size, ¶m, &count); + return i-count; +} @@ -0,0 +1,18 @@ +#include "param.h" + +struct file { + unsigned char *begin; + unsigned char *end; + unsigned long size; + char *name; + void *private; +}; + +struct file *file_create(char *name); +void file_set_readonly(struct file *file); +struct file *file_create_caseinsensitive(char *name); +int file_get_param(struct file *file, struct param_list *param, int count); +void file_destroy(struct file *f); +void *file_opendir(char *dir); +char *file_readdir(void *hnd); +void file_closedir(void *hnd); diff --git a/graphics.c b/graphics.c new file mode 100644 index 00000000..8787e05e --- /dev/null +++ b/graphics.c @@ -0,0 +1,401 @@ +#include <glib.h> +#include "string.h" +#include "draw_info.h" +#include "graphics.h" +#include "map_data.h" +#include "coord.h" +#include "param.h" /* FIXME */ +#include "block.h" /* FIXME */ +#include "poly.h" +#include "town.h" +#include "street.h" +#include "transform.h" +#include "container.h" + + +#define GC_BACKGROUND 0 +#define GC_WOOD 1 +#define GC_TOWN_FILL 2 +#define GC_TOWN_LINE 3 +#define GC_WATER_FILL 4 +#define GC_WATER_LINE 5 +#define GC_RAIL 6 +#define GC_TEXT_FG 7 +#define GC_TEXT_BG 8 +#define GC_BLACK 9 +#define GC_STREET_SMALL 10 +#define GC_STREET_SMALL_B 11 +#define GC_PARK 12 +#define GC_BUILDING 13 +#define GC_BUILDING_2 14 +#define GC_STREET_MID 15 +#define GC_STREET_MID_B 16 +#define GC_STREET_BIG 17 +#define GC_STREET_BIG_B 18 +#define GC_STREET_BIG2 19 +#define GC_STREET_BIG2_B 20 +#define GC_STREET_BIG2_L 21 +#define GC_STREET_NO_PASS 22 +#define GC_STREET_ROUTE 23 +#define GC_LAST 24 + + +int color[][3]={ + {0xffff, 0xefef, 0xb7b7}, + {0x8e8e, 0xc7c7, 0x8d8d}, + {0xffff, 0xc8c8, 0x9595}, + {0xebeb, 0xb4b4, 0x8181}, + {0x8282, 0xc8c8, 0xeaea}, + {0x5050, 0x9696, 0xb8b8}, + {0x8080, 0x8080, 0x8080}, + {0x0, 0x0, 0x0}, + {0xffff, 0xffff, 0xffff}, + {0x0, 0x0, 0x0}, + {0xffff, 0xffff, 0xffff}, + {0xe0e0, 0xe0e0, 0xe0e0}, + {0x7c7c, 0xc3c3, 0x3434}, + {0xe6e6, 0xe6e6, 0xe6e6}, + {0xffff, 0x6666, 0x6666}, + {0xffff, 0xffff, 0x0a0a}, + {0xe0e0, 0xe0e0, 0xe0e0}, + {0xffff, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000}, + {0xffff, 0xffff, 0x0a0a}, + {0xffff, 0x0000, 0x0000}, + {0xffff, 0x0000, 0x0000}, + {0xe0e0, 0xe0e0, 0xffff}, + {0x0000, 0x0000, 0xa0a0}, +}; + +void +container_init_gra(struct container *co) +{ + struct graphics *gra=co->gra; + int i; + + gra->font=g_new0(struct graphics_font *,3); + gra->font[0]=gra->font_new(gra,140); + gra->font[1]=gra->font_new(gra,200); + gra->font[2]=gra->font_new(gra,300); + gra->gc=g_new0(struct graphics_gc *, GC_LAST); + for (i = 0 ; i < GC_LAST ; i++) { + gra->gc[i]=gra->gc_new(gra); + gra->gc_set_background(gra->gc[i], color[0][0], color[0][1], color[0][2]); + gra->gc_set_foreground(gra->gc[i], color[i][0], color[i][1], color[i][2]); + } + gra->gc_set_background(gra->gc[GC_TEXT_BG], color[7][0], color[7][1], color[7][2]); +} + +void +graphics_get_view(struct container *co, long *x, long *y, unsigned long *scale) +{ + struct transformation *t=co->trans; + if (x) *x=t->center.x; + if (y) *y=t->center.y; + if (scale) *scale=t->scale; +} + +void +graphics_set_view(struct container *co, long *x, long *y, unsigned long *scale) +{ + struct transformation *t=co->trans; + if (x) t->center.x=*x; + if (y) t->center.y=*y; + if (scale) t->scale=*scale; + graphics_redraw(co); +} + +void +graphics_draw(struct map_data *mdata, int file, struct container *co, int display, int limit, int limit2, + void(*func)(struct block_info *, unsigned char *, unsigned char *, void *)) +{ + struct draw_info info; + info.co=co; + info.display=display; + info.limit=limit; + map_data_foreach(mdata, file, co->trans, limit2, func, &info); +} + +void +graphics_redraw(struct container *co) +{ + int scale=transform_get_scale(co->trans); + int i,slimit=255,tlimit=255,plimit=255; + int bw[4],w[4],t[4]; + struct display_list **disp=co->disp; + struct graphics *gra=co->gra; + +#if 0 + printf("scale=%d center=0x%lx,0x%lx mercator scale=%f\n", scale, co->trans->center.x, co->trans->center.y, transform_scale(co->trans->center.y)); +#endif + + display_free(co->disp, display_end); + + transform_setup_source_rect(co->trans); + + gra->draw_mode(gra, draw_mode_begin); + for (i = 0 ; i < data_window_type_end; i++) { + data_window_begin(co->data_window[i]); + } + gra->gc_set_linewidth(gra->gc[GC_RAIL], 3); + + bw[0]=0; + bw[1]=0; + bw[2]=0; + bw[3]=0; + w[0]=1; + w[1]=1; + w[2]=1; + w[3]=1; + t[0]=0xf; + t[1]=0xf; + t[2]=0xf; + t[3]=0xf; + if (scale < 2) { + tlimit=0xff; + slimit=0xff; + bw[0]=17; + w[0]=15; + bw[1]=19; + w[1]=17; + bw[2]=19; + w[2]=17; + bw[3]=21; + w[3]=17; + } else if (scale < 4) { + tlimit=0xff; + slimit=0xff; + bw[0]=11; + w[0]=9; + bw[1]=13; + w[1]=11; + bw[2]=13; + w[2]=11; + bw[3]=15; + w[3]=11; + } else if (scale < 8) { + tlimit=0xff; + slimit=0xff; + bw[0]=5; + w[0]=3; + bw[1]=11; + w[1]=9; + bw[2]=11; + w[2]=9; + bw[3]=13; + w[3]=9; + t[0]=0xa; + t[1]=0xf; + } else if (scale < 16) { + tlimit=0xff; + slimit=0xff; + bw[1]=9; + w[1]=7; + bw[2]=9; + w[2]=7; + bw[3]=11; + w[3]=7; + t[0]=0x9; + t[1]=0xe; + } else if (scale < 32) { + tlimit=0xff; + slimit=0xff; + bw[1]=5; + w[1]=3; + bw[2]=5; + w[2]=3; + bw[3]=5; + w[3]=3; + t[0]=0x8; + t[1]=0xb; + } else if (scale < 64) { + tlimit=0xf; + slimit=0x6; + bw[1]=5; + w[1]=3; + bw[2]=5; + w[2]=3; + bw[3]=5; + w[3]=3; + t[0]=0x8; + t[1]=0xa; + } else if (scale < 128) { + tlimit=0xc; + slimit=0x6; + plimit=0x1e; + w[1]=3; + w[2]=3; + bw[3]=5; + w[3]=3; + t[0]=0x7; + t[1]=0xa; + } else if (scale < 256) { + tlimit=0xb; + slimit=0x5; + plimit=0x1a; + w[2]=3; + bw[3]=5; + w[3]=3; + t[0]=0x7; + t[1]=0x8; + } else if (scale < 512) { + tlimit=0x9; + slimit=0x5; + plimit=0x14; + w[1]=0; + w[2]=1; + bw[3]=3; + w[3]=1; + t[0]=0x4; + t[1]=0x7; + } else if (scale < 1024) { + tlimit=0x8; + slimit=0x4; + slimit=0x4; + plimit=0x11; + w[1]=0; + w[2]=1; + bw[3]=3; + w[3]=1; + t[0]=0x3; + t[1]=0x5; + } else if (scale < 2048) { + tlimit=0x5; + slimit=0x3; + plimit=0x10; + bw[3]=3; + w[3]=1; + t[0]=0x2; + t[1]=0x4; + } else if (scale < 4096) { + bw[3]=3; + w[3]=1; + tlimit=0x4; + slimit=0x2; + plimit=0xf; + t[0]=0x2; + t[1]=0x3; + } else if (scale < 8192) { + bw[3]=3; + w[3]=1; + tlimit=0x3; + slimit=0x2; + plimit=0xf; + t[0]=0x1; + t[1]=0x2; + } else { + bw[3]=3; + w[3]=1; + tlimit=0x2; + slimit=0x2; + plimit=0xf; + t[0]=0x1; + t[1]=0x4; + } + gra->gc_set_linewidth(gra->gc[GC_STREET_SMALL], w[0]); + gra->gc_set_linewidth(gra->gc[GC_STREET_NO_PASS], w[0]); + gra->gc_set_linewidth(gra->gc[GC_STREET_SMALL_B], bw[0]); + gra->gc_set_linewidth(gra->gc[GC_STREET_MID], w[1]); + gra->gc_set_linewidth(gra->gc[GC_STREET_MID_B], bw[1]); + gra->gc_set_linewidth(gra->gc[GC_STREET_BIG], w[2]); + gra->gc_set_linewidth(gra->gc[GC_STREET_BIG_B], bw[2]); + gra->gc_set_linewidth(gra->gc[GC_STREET_BIG2], w[3]); + gra->gc_set_linewidth(gra->gc[GC_STREET_BIG2_B], bw[3]); + gra->gc_set_linewidth(gra->gc[GC_STREET_ROUTE], w[3]+7+w[3]/2); + + profile_timer(NULL); + graphics_draw(co->map_data, file_border_ply, co, display_rail, plimit, 48, poly_draw_block); + graphics_draw(co->map_data, file_woodland_ply, co, display_wood, plimit, 48, poly_draw_block); + graphics_draw(co->map_data, file_other_ply, co, display_other, plimit, 48, poly_draw_block); + graphics_draw(co->map_data, file_town_twn, co, display_town, tlimit, 48, town_draw_block); + graphics_draw(co->map_data, file_water_ply, co, display_water, plimit, 48, poly_draw_block); + graphics_draw(co->map_data, file_sea_ply, co, display_sea, plimit, 48, poly_draw_block); + /* todo height, tunnel, bridge, street_bti ??? */ +#if 0 + graphics_draw(co->map_data, file_height_ply, co, display_other1, plimit, 48, poly_draw_block); +#endif + if (scale < 256) { + graphics_draw(co->map_data, file_rail_ply, co, display_rail, plimit, 48, poly_draw_block); + } + profile_timer("map_draw"); + plugin_call_draw(co); + profile_timer("plugin"); +#if 0 + draw_poly(map, &co->d_tunnel_ply, "Tunnel", 0, 11, plimit); +#endif + graphics_draw(co->map_data, file_street_str, co, display_street, slimit, 7, street_draw_block); + + display_draw(disp[display_sea], gra, gra->gc[GC_WATER_FILL], NULL); + display_draw(disp[display_wood], gra, gra->gc[GC_WOOD], NULL); + display_draw(disp[display_other], gra, gra->gc[GC_TOWN_FILL], gra->gc[GC_TOWN_LINE]); + display_draw(disp[display_other1], gra, gra->gc[GC_BUILDING], NULL); + display_draw(disp[display_other2], gra, gra->gc[GC_BUILDING_2], NULL); + display_draw(disp[display_other3], gra, gra->gc[GC_PARK], NULL); + display_draw(disp[display_water], gra, gra->gc[GC_WATER_FILL], gra->gc[GC_WATER_LINE]); + display_draw(disp[display_rail], gra, gra->gc[GC_RAIL], NULL); + street_route_draw(co); + display_draw(disp[display_street_route], gra, gra->gc[GC_STREET_ROUTE], NULL); + if (bw[0]) { + display_draw(disp[display_street_no_pass], gra, gra->gc[GC_STREET_SMALL_B], NULL); + display_draw(disp[display_street], gra, gra->gc[GC_STREET_SMALL_B], NULL); + } + if (bw[1]) + display_draw(disp[display_street1], gra, gra->gc[GC_STREET_MID_B], NULL); + if (bw[2]) + display_draw(disp[display_street2], gra, gra->gc[GC_STREET_BIG_B], NULL); + if (bw[3]) + display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2_B], NULL); + if (w[0]) { + display_draw(disp[display_street_no_pass], gra, gra->gc[GC_STREET_NO_PASS], NULL); + display_draw(disp[display_street], gra, gra->gc[GC_STREET_SMALL], NULL); + } + if (w[1]) + display_draw(disp[display_street1], gra, gra->gc[GC_STREET_MID], gra->gc[GC_BLACK]); + display_draw(disp[display_street2], gra, gra->gc[GC_STREET_BIG], gra->gc[GC_BLACK]); + display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2], gra->gc[GC_BLACK]); + if (w[3] > 1) + display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2_L], NULL); + + display_draw(disp[display_poi], gra, gra->gc[GC_BLACK], NULL); + + + profile_timer("display_draw"); + + if (scale < 2) { + display_labels(disp[display_street], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]); + display_labels(disp[display_street1], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]); + } + else { + display_labels(disp[display_street], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]); + display_labels(disp[display_street1], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]); + } + display_labels(disp[display_street2], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]); + display_labels(disp[display_street3], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]); + + for (i = display_town+t[1] ; i < display_town+0x10 ; i++) + display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]); + for (i = display_town+t[0] ; i < display_town+t[1] ; i++) + display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]); + for (i = display_town ; i < display_town+t[0] ; i++) + display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[2]); + + for (i = display_town ; i < display_town+0x10 ; i++) + display_draw(disp[i], gra, gra->gc[GC_BLACK], NULL); + display_draw(disp[display_bti], gra, gra->gc[GC_BLACK], NULL); + profile_timer("labels"); + gra->draw_mode(gra, draw_mode_end); + for (i = 0 ; i < data_window_type_end; i++) { + data_window_end(co->data_window[i]); + } +#if 0 + map_scrollbars_update(map); +#endif +} + +void +graphics_resize(struct container *co, int w, int h) +{ + co->trans->width=w; + co->trans->height=h; + graphics_redraw(co); +} diff --git a/graphics.h b/graphics.h new file mode 100644 index 00000000..43d583dd --- /dev/null +++ b/graphics.h @@ -0,0 +1,48 @@ + +struct point; +struct container; +struct graphics_gc; +struct graphics_font; +struct graphics_image_gra; + +struct graphics_image { + struct graphics_image *next; + struct graphics *gr; + char *name; + int height; + int width; + struct graphics_image_gra *gra; +}; + +void graphics_get_view(struct container *co, long *x, long *y, unsigned long *scale); +void graphics_set_view(struct container *co, long *x, long *y, unsigned long *scale); +void graphics_resize(struct container *co, int w, int h); +void graphics_redraw(struct container *co); + +enum draw_mode_num { + draw_mode_begin, draw_mode_end, draw_mode_cursor +}; + +struct graphics +{ + struct graphics_gra *gra; + struct graphics_font **font; + struct graphics_gc **gc; + + void (*draw_mode)(struct graphics *gr, enum draw_mode_num mode); + void (*draw_lines)(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count); + void (*draw_polygon)(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count); + void (*draw_rectangle)(struct graphics *gr, struct graphics_gc *gc, struct point *p, int w, int h); + void (*draw_circle)(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r); + void (*draw_text)(struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, unsigned char *text, struct point *p, int dx, int dy); + void (*draw_image)(struct graphics *gr, struct graphics_gc *fg, struct point *p, struct graphics_image *img); + void (*draw_restore)(struct graphics *gr, struct point *p, int w, int h); + + struct graphics_font *(*font_new)(struct graphics *gr, int size); + struct graphics_gc *(*gc_new)(struct graphics *gr); + void (*gc_set_linewidth)(struct graphics_gc *gc, int width); + void (*gc_set_foreground)(struct graphics_gc *gc, int r, int g, int b); + void (*gc_set_background)(struct graphics_gc *gc, int r, int g, int b); + struct graphics_image *(*image_new)(struct graphics *gr, char *path); + struct graphics *(*overlay_new)(struct graphics *gr, struct point *p, int w, int h); +}; diff --git a/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c b/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c new file mode 100644 index 00000000..a730cee5 --- /dev/null +++ b/graphics/gtk_drawing_area/graphics_gtk_drawing_area.c @@ -0,0 +1,607 @@ +#define GDK_ENABLE_BROKEN +#include <gtk/gtk.h> +#include <ft2build.h> +#include FT_FREETYPE_H +#include "point.h" +#include "coord.h" +#include "transform.h" +#include "graphics.h" +#include "statusbar.h" +#include "popup.h" +#include "container.h" + +struct graphics_gra { + GdkEventButton button_event; + int button_timeout; + GtkWidget *widget; + GdkDrawable *drawable; + GdkDrawable *background; + GdkColormap *colormap; + FT_Library library; + struct point p; + int width; + int height; + int library_init; + int visible; + struct graphics_gra *parent; + struct graphics_gra *overlays; + struct graphics_gra *next; + enum draw_mode_num mode; +}; + +struct graphics_font { + FT_Face face; +}; + +struct graphics_gc { + GdkGC *gc; + struct graphics_gra *gra; +}; + +struct graphics_image_gra { + GdkPixbuf *pixbuf; +}; + + +static struct graphics_font *font_new(struct graphics *gr, int size) +{ + char *filename="/usr/X11R6/lib/X11/fonts/msttcorefonts/arial.ttf"; + struct graphics_font *font=g_new(struct graphics_font, 1); + if (!gr->gra->library_init) { + FT_Init_FreeType( &gr->gra->library ); + gr->gra->library_init=1; + } + if (FT_New_Face( gr->gra->library, filename, 0, &font->face )) { + g_warning("Failed to load '%s', no labelling", filename); + g_free(font); + return NULL; + } + FT_Set_Char_Size(font->face, 0, size, 300, 300); + return font; +} + +static struct graphics_gc *gc_new(struct graphics *gr) +{ + struct graphics_gc *gc=g_new(struct graphics_gc, 1); + + gc->gc=gdk_gc_new(gr->gra->widget->window); + gc->gra=gr->gra; + return gc; +} + +static void +gc_set_linewidth(struct graphics_gc *gc, int w) +{ + gdk_gc_set_line_attributes(gc->gc, w, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); +} + +static void +gc_set_color(struct graphics_gc *gc, int r, int g, int b, int fg) +{ + GdkColor c; + c.pixel=0; + c.red=r; + c.green=g; + c.blue=b; + gdk_colormap_alloc_color(gc->gra->colormap, &c, FALSE, TRUE); + if (fg) + gdk_gc_set_foreground(gc->gc, &c); + else + gdk_gc_set_background(gc->gc, &c); +} + +static void +gc_set_foreground(struct graphics_gc *gc, int r, int g, int b) +{ + gc_set_color(gc, r, g, b, 1); +} + +static void +gc_set_background(struct graphics_gc *gc, int r, int g, int b) +{ + gc_set_color(gc, r, g, b, 0); +} + +struct graphics_image * +image_new(struct graphics *gr, char *name) +{ + GdkPixbuf *pixbuf; + struct graphics_image *ret; + + pixbuf=gdk_pixbuf_new_from_file(name, NULL); + if (! pixbuf) + return NULL; + ret=g_new0(struct graphics_image, 1); + ret->gr=gr; + ret->name=strdup(name); + ret->gra=g_new0(struct graphics_image_gra, 1); + ret->gra->pixbuf=pixbuf; + ret->width=gdk_pixbuf_get_width(ret->gra->pixbuf); + ret->height=gdk_pixbuf_get_height(ret->gra->pixbuf); + return ret; +} + +static void +draw_lines(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count) +{ + if (gr->gra->mode == draw_mode_begin || gr->gra->mode == draw_mode_end) + gdk_draw_lines(gr->gra->drawable, gc->gc, (GdkPoint *)p, count); + if (gr->gra->mode == draw_mode_end || gr->gra->mode == draw_mode_cursor) + gdk_draw_lines(gr->gra->widget->window, gc->gc, (GdkPoint *)p, count); +} + +static void +draw_polygon(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count) +{ + if (gr->gra->mode == draw_mode_begin || gr->gra->mode == draw_mode_end) + gdk_draw_polygon(gr->gra->drawable, gc->gc, TRUE, (GdkPoint *)p, count); + if (gr->gra->mode == draw_mode_end || gr->gra->mode == draw_mode_cursor) + gdk_draw_polygon(gr->gra->widget->window, gc->gc, TRUE, (GdkPoint *)p, count); +} + +static void +draw_rectangle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int w, int h) +{ + gdk_draw_rectangle(gr->gra->drawable, gc->gc, TRUE, p->x, p->y, w, h); +} + +static void +draw_circle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r) +{ + if (gr->gra->mode == draw_mode_begin || gr->gra->mode == draw_mode_end) + gdk_draw_arc(gr->gra->drawable, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360); + if (gr->gra->mode == draw_mode_end || gr->gra->mode == draw_mode_cursor) + gdk_draw_arc(gr->gra->widget->window, gc->gc, FALSE, p->x-r/2, p->y-r/2, r, r, 0, 64*360); +} + + +struct text_glyph { + int x,y,w,h; + GdkImage *shadow; + unsigned char pixmap[0]; +}; + +struct text_render { + int x1,y1; + int x2,y2; + int x3,y3; + int x4,y4; + int glyph_count; + struct text_glyph *glyph[0]; +}; + +static GdkImage * +display_text_render_shadow(struct text_glyph *g) +{ + int mask0, mask1, mask2, x, y, w=g->w, h=g->h; + int str=(g->w+9)/8; + unsigned char *shadow; + unsigned char *p, *pm=g->pixmap; + GdkImage *ret; + + shadow=malloc(str*(g->h+2)); + memset(shadow, 0, str*(g->h+2)); + for (y = 0 ; y < h ; y++) { + p=shadow+str*y; + mask0=0x4000; + mask1=0xe000; + mask2=0x4000; + for (x = 0 ; x < w ; x++) { + if (pm[x+y*w]) { + p[0]|=(mask0 >> 8); + if (mask0 & 0xff) + p[1]|=mask0; + + p[str]|=(mask1 >> 8); + if (mask1 & 0xff) + p[str+1]|=mask1; + p[str*2]|=(mask2 >> 8); + if (mask2 & 0xff) + p[str*2+1]|=mask2; + } + mask0 >>= 1; + mask1 >>= 1; + mask2 >>= 1; + if (!((mask0 >> 8) | (mask1 >> 8) | (mask2 >> 8))) { + mask0<<=8; + mask1<<=8; + mask2<<=8; + p++; + } + } + } + ret=gdk_image_new_bitmap(gdk_visual_get_system(), shadow, g->w+2, g->h+2); + return ret; +} + +static struct text_render * +display_text_render(unsigned char *text, struct graphics_font *font, int dx, int dy, int x, int y) +{ + FT_GlyphSlot slot = font->face->glyph; // a small shortcut + FT_Matrix matrix; + FT_Vector pen; + FT_UInt glyph_index; + int n,len=strlen(text); + struct text_render *ret=malloc(sizeof(*ret)+len*sizeof(struct text_glyph *)); + struct text_glyph *curr; + + ret->glyph_count=len; + + matrix.xx = dx; + matrix.xy = dy; + matrix.yx = -dy; + matrix.yy = dx; + + pen.x = 0 * 64; + pen.y = 0 * 64; + x <<= 6; + y <<= 6; + FT_Set_Transform( font->face, &matrix, &pen ); + + + for ( n = 0; n < len; n++ ) + { + + glyph_index = FT_Get_Char_Index(font->face, text[n]); + FT_Load_Glyph(font->face, glyph_index, FT_LOAD_DEFAULT ); + FT_Render_Glyph(font->face->glyph, ft_render_mode_normal ); + + curr=malloc(sizeof(*curr)+slot->bitmap.rows*slot->bitmap.pitch); + ret->glyph[n]=curr; + + curr->x=(x>>6)+slot->bitmap_left; + curr->y=(y>>6)-slot->bitmap_top; + curr->w=slot->bitmap.width; + curr->h=slot->bitmap.rows; + if (slot->bitmap.width && slot->bitmap.rows) { + memcpy(curr->pixmap, slot->bitmap.buffer, slot->bitmap.rows*slot->bitmap.pitch); + curr->shadow=display_text_render_shadow(curr); + } + else + curr->shadow=NULL; +#if 0 + printf("height=%d\n", slot->metrics.height); + printf("height2=%d\n", face->height); + printf("bbox %d %d %d %d\n", face->bbox.xMin, face->bbox.yMin, face->bbox.xMax, face->bbox.yMax); +#endif + x += slot->advance.x; + y -= slot->advance.y; + } + return ret; +} + +static void +display_text_draw(struct text_render *text, struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg) +{ + int i; + struct text_glyph *g, **gp; + + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) + { + g=*gp++; + if (g->shadow && bg) + gdk_draw_image(gr->gra->drawable, bg->gc, g->shadow, 0, 0, g->x-1, g->y-1, g->w+2, g->h+2); + } + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) + { + g=*gp++; + if (g->w && g->h) + gdk_draw_gray_image(gr->gra->drawable, fg->gc, g->x, g->y, g->w, g->h, GDK_RGB_DITHER_NONE, g->pixmap, g->w); + } +} + +static void +display_text_free(struct text_render *text) +{ + int i; + struct text_glyph **gp; + + gp=text->glyph; + i=text->glyph_count; + while (i-- > 0) { + if ((*gp)->shadow) { + gdk_image_destroy((*gp)->shadow); +#if 0 + free((*gp)->shadow->mem); +#endif + } + free(*gp++); + } + free(text); +} + +static void +draw_text(struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, unsigned char *text, struct point *p, int dx, int dy) +{ + struct text_render *t; + + if (! font) + return; + if (bg) { + gdk_gc_set_function(fg->gc, GDK_AND_INVERT); + gdk_gc_set_function(bg->gc, GDK_OR); + } + + t=display_text_render(text, font, dx, dy, p->x, p->y); + display_text_draw(t, gr, fg, bg); + display_text_free(t); + if (bg) { + gdk_gc_set_function(fg->gc, GDK_COPY); + gdk_gc_set_function(bg->gc, GDK_COPY); + } +} + +static void +draw_image(struct graphics *gr, struct graphics_gc *fg, struct point *p, struct graphics_image *img) +{ + printf("draw_image1 \n"); + gdk_draw_pixbuf(gr->gra->drawable, fg->gc, img->gra->pixbuf, 0, 0, p->x, p->y, + img->width, img->height, GDK_RGB_DITHER_NONE, 0, 0); + printf("draw_image1 end\n"); +} + +static void +overlay_draw(struct graphics_gra *parent, struct graphics_gra *overlay, int window) +{ + GdkPixbuf *pixbuf,*pixbuf2; + GtkWidget *widget=parent->widget; + guchar *pixels1, *pixels2, *p1, *p2; + int x,y; + int rowstride1,rowstride2; + int n_channels1,n_channels2; + pixbuf=gdk_pixbuf_get_from_drawable(NULL, overlay->drawable, NULL, 0, 0, 0, 0, overlay->width, overlay->height); + pixbuf2=gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf), TRUE, gdk_pixbuf_get_bits_per_sample(pixbuf), + gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); + + rowstride1 = gdk_pixbuf_get_rowstride (pixbuf); + rowstride2 = gdk_pixbuf_get_rowstride (pixbuf2); + pixels1=gdk_pixbuf_get_pixels (pixbuf); + pixels2=gdk_pixbuf_get_pixels (pixbuf2); + n_channels1 = gdk_pixbuf_get_n_channels (pixbuf); + n_channels2 = gdk_pixbuf_get_n_channels (pixbuf2); + for (y = 0 ; y < overlay->height ; y++) { + for (x = 0 ; x < overlay->width ; x++) { + p1 = pixels1 + y * rowstride1 + x * n_channels1; + p2 = pixels2 + y * rowstride2 + x * n_channels2; + p2[0]=p1[0]; + p2[1]=p1[1]; + p2[2]=p1[2]; + p2[3]=127; + } + } + if (window) + gdk_draw_pixmap(parent->drawable, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], overlay->background, 0, 0, overlay->p.x, overlay->p.y, overlay->width, overlay->height); + else + gdk_draw_pixmap(overlay->background, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], parent->drawable, overlay->p.x, overlay->p.y, 0, 0, overlay->width, overlay->height); + gdk_draw_pixbuf(parent->drawable, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], pixbuf2, 0, 0, overlay->p.x, overlay->p.y, overlay->width, overlay->height, GDK_RGB_DITHER_NONE, 0, 0); + if (window) + gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], parent->drawable, overlay->p.x, overlay->p.y, overlay->p.x, overlay->p.y, overlay->width, overlay->height); +#if 0 + gdk_draw_pixmap(gr->gra->drawable, + gr->gra->widget->style->fg_gc[GTK_WIDGET_STATE(gr->gra->widget)], + img->gra->drawable, + 0, 0, p->x, p->y, img->gra->width, img->gra->height); +#endif +} + +static void +draw_restore(struct graphics *gr, struct point *p, int w, int h) +{ + struct graphics_gra *gra=gr->gra; + GtkWidget *widget=gra->widget; + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + gra->drawable, + p->x, p->y, p->x, p->y, w, h); + +} + +static void +draw_mode(struct graphics *gr, enum draw_mode_num mode) +{ + struct graphics_gra *gra=gr->gra; + struct graphics_gra *overlay; + GtkWidget *widget=gra->widget; + + if (mode == draw_mode_begin) { + if (! gra->parent) + gdk_draw_rectangle(gr->gra->drawable, gr->gc[0]->gc, TRUE, 0, 0, gr->gra->width, gr->gra->height); + } + if (mode == draw_mode_end && gr->gra->mode == draw_mode_begin) { + if (gra->parent) { + overlay_draw(gra->parent, gra, 1); + } else { + overlay=gra->overlays; + while (overlay) { + overlay_draw(gra, overlay, 0); + overlay=overlay->next; + } + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + gra->drawable, + 0, 0, 0, 0, gra->width, gra->height); + } + } + gr->gra->mode=mode; +} + +/* Events */ + +static gint +configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data) +{ + struct container *co=user_data; + struct graphics_gra *gra=co->gra->gra; + + if (! gra->visible) + return TRUE; + if (gra->drawable != NULL) { + gdk_pixmap_unref(gra->drawable); + } + gra->width=widget->allocation.width; + gra->height=widget->allocation.height; + gra->drawable = gdk_pixmap_new(widget->window, gra->width, gra->height, -1); + graphics_resize(co, gra->width, gra->height); + return TRUE; +} + +static gint +expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data) +{ + struct container *co=user_data; + struct graphics *gr=co->gra; + + gr->gra->visible=1; + if (! gr->gra->drawable) + configure(widget, NULL, user_data); + gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE(widget)], + gr->gra->drawable, event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + + return FALSE; +} + +static gint +button_timeout(gpointer user_data) +{ + struct container *co=user_data; + int x=co->gra->gra->button_event.x; + int y=co->gra->gra->button_event.y; + int button=co->gra->gra->button_event.button; + + co->gra->gra->button_timeout=0; + popup(co, x, y, button); + + return FALSE; +} + +static gint +button_press(GtkWidget * widget, GdkEventButton * event, gpointer user_data) +{ + struct container *co=user_data; + int x=event->x; + int y=event->y; + int button=event->button; + int border=16; + long map_x,map_y,scale,x_new,y_new; + + if (button == 3) + popup(co, x, y, button); + if (button == 1) { + graphics_get_view(co, &map_x, &map_y, &scale); + if (x < border) { + x_new=map_x-co->trans->width*scale/32; + graphics_set_view(co, &x_new, NULL, NULL); + } else if (x >= co->trans->width-border) { + x_new=map_x+co->trans->width*scale/32; + graphics_set_view(co, &x_new, NULL, NULL); + } else if (y < border) { + y_new=map_y+co->trans->height*scale/32; + graphics_set_view(co, NULL, &y_new, NULL); + } else if (y >= co->trans->height-border) { + y_new=map_y-co->trans->height*scale/32; + graphics_set_view(co, NULL, &y_new, NULL); + } else { + co->gra->gra->button_event=*event; + co->gra->gra->button_timeout=g_timeout_add(500, button_timeout, co); + } + } + return FALSE; +} + +static gint +button_release(GtkWidget * widget, GdkEventButton * event, gpointer user_data) +{ + struct container *co=user_data; + if (co->gra->gra->button_timeout) + g_source_remove(co->gra->gra->button_timeout); + return FALSE; +} + +static gint +motion_notify(GtkWidget * widget, GdkEventMotion * event, gpointer user_data) +{ + struct container *co=user_data; + struct point p; + + if (co->statusbar && co->statusbar->statusbar_mouse_update) { + p.x=event->x; + p.y=event->y; + co->statusbar->statusbar_mouse_update(co->statusbar, co->trans, &p); + } + return FALSE; +} + +static struct graphics *graphics_new(void); + +static struct graphics * +overlay_new(struct graphics *gr, struct point *p, int w, int h) +{ + struct graphics *this=graphics_new(); + this->gra->drawable=gdk_pixmap_new(gr->gra->widget->window, w, h, -1); + this->gra->colormap=gr->gra->colormap; + this->gra->widget=gr->gra->widget; + this->gra->p=*p; + this->gra->width=w; + this->gra->height=h; + this->gra->parent=gr->gra; + this->gra->background=gdk_pixmap_new(gr->gra->widget->window, w, h, -1); + this->gra->next=gr->gra->overlays; + gr->gra->overlays=this->gra; + return this; +} + + + +static struct graphics * +graphics_new(void) +{ + struct graphics *this=g_new0(struct graphics,1); + this->draw_mode=draw_mode; + this->draw_lines=draw_lines; + this->draw_polygon=draw_polygon; + this->draw_rectangle=draw_rectangle; + this->draw_circle=draw_circle; + this->draw_text=draw_text; + this->draw_image=draw_image; + this->draw_restore=draw_restore; + this->gc_new=gc_new; + this->gc_set_linewidth=gc_set_linewidth; + this->gc_set_foreground=gc_set_foreground; + this->gc_set_background=gc_set_background; + this->font_new=font_new; + this->image_new=image_new; + this->overlay_new=overlay_new; + this->gra=g_new0(struct graphics_gra, 1); + + return this; +} + +struct graphics * +graphics_gtk_drawing_area_new(struct container *co, GtkWidget **widget) +{ + GtkWidget *draw; + + draw=gtk_drawing_area_new(); + struct graphics *this=graphics_new(); + this->gra->widget=draw; + this->gra->colormap=gdk_colormap_new(gdk_visual_get_system(),FALSE); + gtk_widget_set_events(draw, GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK); + gtk_signal_connect(GTK_OBJECT(draw), "expose_event", GTK_SIGNAL_FUNC(expose), co); + gtk_signal_connect(GTK_OBJECT(draw), "configure_event", GTK_SIGNAL_FUNC(configure), co); +#if 0 + gtk_signal_connect(GTK_OBJECT(draw), "realize_event", GTK_SIGNAL_FUNC(realize), co); +#endif + gtk_signal_connect(GTK_OBJECT(draw), "button_press_event", GTK_SIGNAL_FUNC(button_press), co); + gtk_signal_connect(GTK_OBJECT(draw), "button_release_event", GTK_SIGNAL_FUNC(button_release), co); + gtk_signal_connect(GTK_OBJECT(draw), "motion_notify_event", GTK_SIGNAL_FUNC(motion_notify), co); + *widget=draw; + return this; +} + diff --git a/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c b/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c new file mode 100644 index 00000000..c91e94c6 --- /dev/null +++ b/graphics/gtk_gl_ext/graphics_gtk_gl_ext.c @@ -0,0 +1,333 @@ +#include <stdlib.h> +#include <gtk/gtk.h> +#include <gtk/gtkgl.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include "point.h" +#include "graphics.h" +#include "container.h" + + +struct graphics_gra { + GtkWidget *widget; + int width; + int height; + int library_init; + int visible; + int buffer; +}; + +struct graphics_font { +}; + +struct graphics_gc { + double fr,fg,fb; + double br,bg,bb; + double width; + struct graphics_gra *gra; +}; + +static struct graphics_font *font_new(struct graphics *gr, int size) +{ + struct graphics_font *font=g_new(struct graphics_font, 1); + return font; +} + +static struct graphics_gc *gc_new(struct graphics *gr) +{ + struct graphics_gc *gc=g_new(struct graphics_gc, 1); + + gc->fr=1; + gc->fg=1; + gc->fb=1; + gc->br=0; + gc->bg=0; + gc->bb=0; + gc->width=1; + gc->gra=gr->gra; + return gc; +} + +static void +gc_set_linewidth(struct graphics_gc *gc, int w) +{ + gc->width=w; +} + +static void +gc_set_foreground(struct graphics_gc *gc, int r, int g, int b) +{ + gc->fr=r/65535.0; + gc->fg=g/65535.0; + gc->fb=b/65535.0; +} + +static void +gc_set_background(struct graphics_gc *gc, int r, int g, int b) +{ + gc->br=r/65535.0; + gc->bg=g/65535.0; + gc->bb=b/65535.0; +} + +static void +vertex(struct point *p) +{ + double x,y; + x=p->x; + y=p->y; + x/=792; + y/=469; + x-=0.5; + y=0.5-y; + glVertex3f(x,y,0); +} + +static void +draw_lines(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count) +{ + int i; + + glLineWidth(gc->width); + glColor3f(gc->fr, gc->fg, gc->fb); + glBegin(GL_LINE_STRIP); + for (i=0 ; i < count ; i++) + vertex(p++); + glEnd(); +} + +static void +draw_polygon(struct graphics *gr, struct graphics_gc *gc, struct point *p, int count) +{ + int i; + double x,y; + glColor3f(gc->fr, gc->fg, gc->fb); + glBegin(GL_POLYGON); + for (i=0 ; i < count ; i++) + vertex(p++); + glEnd(); +} + + +static void +draw_circle(struct graphics *gr, struct graphics_gc *gc, struct point *p, int r) +{ + +} + +static void +draw_text(struct graphics *gr, struct graphics_gc *fg, struct graphics_gc *bg, struct graphics_font *font, unsigned char *text, int x, int y, int dx, int dy) +{ +} + +static void +draw_begin(struct graphics *gr) +{ + printf("draw_begin\n"); + glClearColor(gr->gc[0]->br, gr->gc[0]->bg, gr->gc[0]->bb, 0); + glNewList(1, GL_COMPILE); + gr->gra->buffer=1; +} + +static void +draw_end(struct graphics *gr) +{ + printf("draw_end\n"); + glEndList(); + gr->gra->buffer=0; +} + +static void realize(GtkWidget * widget, gpointer data) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); + + GLUquadricObj *qobj; + static GLfloat light_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; + static GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; + + /*** OpenGL BEGIN ***/ + if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) + return; + + qobj = gluNewQuadric(); + gluQuadricDrawStyle(qobj, GLU_FILL); +#if 0 + glNewList(1, GL_COMPILE); + gluSphere(qobj, 1.0, 20, 20); + glBegin(GL_LINE_STRIP); + glVertex3f(0.0,0.1,0.0); + glVertex3f(0.1,0.1,0.0); + glVertex3f(0.1,0.2,0.0); + glVertex3f(0.2,0.2,0.0); + glEnd(); + glEndList(); +#endif + +#if 0 + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_POSITION, light_position); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); +#endif + + glClearColor(1.0, 1.0, 1.0, 1.0); + glClearDepth(1.0); + + glViewport(0, 0, + widget->allocation.width, widget->allocation.height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(19.0, 1.0, 1.0, 10.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); + glTranslatef(0.0, 0.0, 0.0); + + gdk_gl_drawable_gl_end(gldrawable); + /*** OpenGL END ***/ +} + +static gboolean +configure(GtkWidget * widget, GdkEventConfigure * event, gpointer user_data) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); + struct container *co=user_data; + struct graphics_gra *gra=co->gra->gra; + + + printf("configure %d %d\n",gra->width, gra->height); + gra->width=widget->allocation.width; + gra->height=widget->allocation.height; + + /*** OpenGL BEGIN ***/ + if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) + return FALSE; + + glViewport(0, 0, + widget->allocation.width, widget->allocation.height); + + gdk_gl_drawable_gl_end(gldrawable); + /*** OpenGL END ***/ + if (gra->visible) + graphics_resize(co, gra->width, gra->height); + + return TRUE; +} + +static gboolean +expose(GtkWidget * widget, GdkEventExpose * event, gpointer user_data) +{ + GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); + GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); + struct container *co=user_data; + struct graphics_gra *gra=co->gra->gra; + + printf("expose\n"); + if (! gra->visible) { + gra->visible=1; + configure(widget, NULL, user_data); + } + /*** OpenGL BEGIN ***/ + if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext)) + return FALSE; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glCallList(1); + + if (gdk_gl_drawable_is_double_buffered(gldrawable)) + gdk_gl_drawable_swap_buffers(gldrawable); + else + glFlush(); + + gdk_gl_drawable_gl_end(gldrawable); + /*** OpenGL END ***/ + + return TRUE; +} + + +struct graphics * +graphics_gtk_gl_area_new(struct container *co, GtkWidget **widget) +{ + GdkGLConfig *glconfig; + gint major, minor; + GtkWidget *drawing_area; + + struct graphics *this=g_new0(struct graphics,1); + this->draw_lines=draw_lines; + this->draw_polygon=draw_polygon; + this->draw_circle=draw_circle; + this->draw_text=draw_text; +#if 0 + this->draw_begin=draw_begin; + this->draw_end=draw_end; +#endif + this->gc_new=gc_new; + this->gc_set_linewidth=gc_set_linewidth; + this->gc_set_foreground=gc_set_foreground; + this->gc_set_background=gc_set_background; + this->font_new=font_new; + this->gra=g_new0(struct graphics_gra, 1); + + /* + * Init GtkGLExt. + */ + + gtk_gl_init(NULL, NULL); + + /* + * Query OpenGL extension version. + */ + + gdk_gl_query_version(&major, &minor); + g_print("OpenGL extension version - %d.%d\n", major, minor); + + /* + * Configure OpenGL-capable visual. + */ + + /* Try double-buffered visual */ + glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | + GDK_GL_MODE_DEPTH | + GDK_GL_MODE_DOUBLE); + if (glconfig == NULL) { + g_print("*** Cannot find the double-buffered visual.\n"); + g_print("*** Trying single-buffered visual.\n"); + + /* Try single-buffered visual */ + glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | + GDK_GL_MODE_DEPTH); + if (glconfig == NULL) { + g_print + ("*** No appropriate OpenGL-capable visual found.\n"); + exit(1); + } + } + + + drawing_area = gtk_drawing_area_new(); + + /* Set OpenGL-capability to the widget. */ + gtk_widget_set_gl_capability(drawing_area, + glconfig, + NULL, TRUE, GDK_GL_RGBA_TYPE); + + g_signal_connect_after(G_OBJECT(drawing_area), "realize", + G_CALLBACK(realize), NULL); + g_signal_connect(G_OBJECT(drawing_area), "configure_event", + G_CALLBACK(configure), co); + g_signal_connect(G_OBJECT(drawing_area), "expose_event", + G_CALLBACK(expose), co); + + *widget=drawing_area; + this->gra->widget=drawing_area; + return this; +} + + diff --git a/gtkext.h b/gtkext.h new file mode 100644 index 00000000..34059d9b --- /dev/null +++ b/gtkext.h @@ -0,0 +1 @@ +void gdk_gc_set_fill_rule(GdkGC *gc, GdkFillRule fill_rule); diff --git a/gui/gtk/gtkeyboard.c b/gui/gtk/gtkeyboard.c new file mode 100644 index 00000000..1963c839 --- /dev/null +++ b/gui/gtk/gtkeyboard.c @@ -0,0 +1,2353 @@ +/* app.c + * For use with GTKeyboard + * written by David Allen, s2mdalle@titan.vcu.edu + * http://opop.nols.com/ + * + * #define DEBUGGING at compile time for interesting info most people don't + * want to see. + */ +/* GTKeyboard - A Graphical Keyboard For X + * Copyright (C) 1999, 2000 David Allen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <signal.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <ctype.h> +#include <assert.h> +#include <time.h> +#include <sys/time.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/Xos.h> +#include <X11/extensions/shape.h> +#include <X11/Xmu/WinUtil.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <stdarg.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/types.h> + +/* The regular non-fun glib calls for distro copies of gtkeyboard. */ +# define g_new0_(t,c) g_new0(t,c) +# define g_free_(mem) g_free(mem) +# define g_new_(t,c) g_new(t,c) +# define g_strdup_(x) g_strdup(x) +# define g_malloc_(x) g_malloc(x) +# define MEM(x) ; /* Don't do anything */ + + +/* modmap.h + * Written by David Allen <s2mdalle@titan.vcu.edu> + * + * Released under the terms of the GNU General Public License + */ + + + + +#define slot_number_to_mask(x) (1<<x) + +typedef struct { + KeyCode codes[4]; +} ModmapRow; + +typedef struct { + int max_keypermod; /* Alias for the entry in XModifierMap */ + ModmapRow modifiers[8]; /* Exactly 8 entries */ +} ModmapTable; + +static int file_exists(const char *filename); +static void send_redirect_a_keysym(KeySym input); +static unsigned long find_modifier_mask(KeyCode code); +static ModmapTable *ModmapTable_new(void); +static void ModmapTable_destroy(ModmapTable * table); +static int ModmapTable_insert(ModmapTable * table, KeyCode code, int slot); +static int mask_name_to_slot_number(char *maskname); + + +/* templates.h + * + * Written by David Allen <s2mdalle@titan.vcu.edu> + * http://opop.nols.com/ + * Released under the terms of the GNU General Public License + */ + +#define MAXIMUM_ROWS 6 + +/* Abstract data types */ + +typedef struct { + KeySym lower_case; /* What happens when pressed by itself */ + KeySym upper_case; /* What happens when pressed with Shift/CL */ + KeySym alt_gr; /* Alt GR+ button -- mostly unused */ + KeyCode code; + char *aux_string; /* Cheating string holder for things that aren't + * right with XKeysymToString() -- most notably + * the F keys and the keypad keys + * This should NEVER be used in conjunction + * with foreign windows - only text insertion in + * our editing buffer + */ +} KEY; + +typedef struct { + char *tab; + char *backspace; + char *caps_lock; + char *space; + char *alt; + char *alt_gr; + char *control; + char *shift; +} KeyboardTranslation; + +typedef struct { + int row_values[MAXIMUM_ROWS]; + int keycount; + KeySym *syms; + KeyCode *codes; + KeyboardTranslation *trans; + char *name; + ModmapTable *modmap; +} KEYBOARD; + +/* Macros */ +#define NO_KEYBOARD ((KEYBOARD *)NULL) +#define NO_KEY ((KEY *)NULL) + +/* Function prototypes */ +static KEY *gtkeyboard_key_copy(KEY * key); +static KEY *gtkeyboard_keyboard_get_key(KEYBOARD * keyb, int row, int keyno); +static KEYBOARD *gtkeyboard_destroy_keyboard(KEYBOARD * input); +static KEYBOARD *read_keyboard_template(char *filename); +static KEY *gtkeyboard_destroy_key(KEY * input); +static KEY *gtkeyboard_new_key(const KeySym lower, + const KeySym upper, + const KeySym altgr, const char *alt); + + + +/* rc_file.h - A simple configuration file reader/writer header file + * by Patrick Gallot <patrick.gallot@cimlinc.com> + * + * This file is part of GTKeyboard and as such is licensed under the terms + * of the GNU General Public License. + */ + + +/* Different types that resource file varaibles can have */ +#define RC_NONE 0x0000 +#define RC_STR 0x0002 /* String */ +#define RC_PARSE_FUNC 0x0006 /* This one means that an external + * parsing function should be used + * and the resource file code + * shouldn't bother with the values + */ +typedef struct config_var { + /* These go together to specify a line in a file that could say something + * like "set foo_variable 10" or "foobar = 20" or even + * "toolbar menubar off" + */ + + gchar *Prefix; /* This could be something like "set" or "toolbar" */ + gchar *Name; /* Element name */ + gint Type; /* Type of the value */ + gpointer Val; /* Pointer to the value to store */ + /* Function pointer for custom handling -- it should have parameters + * of the "prefix" token, (usually "set"), the variable name, the + * varaible value, and the pointer we were supposed to store it in. + * The pointer is usually going to be the same as Val above + */ + int (*func) (char *prefix, char *varname, char *val, gpointer ptr); +} RCVARS; + +static int read_ConfigFile(char *filename, RCVARS * vars, int complain); + +#define CONDFREE(x) if(x){ g_free_(x); x = NULL; } + +#define FLUSH_EVERYTHING fflush(Q); fflush(stdout);\ + fflush(stderr); + +/* Toggling Defines */ +#define ON 1 +#define OFF 0 +/* Whatever the status is, FLIP IT */ +#define ISOFF(x) ( x==OFF ) + +/* In case we ever achieve portability to winblows, we can change this + * to a backslash. :) + */ +#define _DIR "/" + +#define FLUSH fflush(Q) +#define NONE NULL + +#define LEFT_MOUSE_BUTTON 1 +#define RIGHT_MOUSE_BUTTON 3 +#define MIDDLE_MOUSE_BUTTON 2 + +#define Q stderr +#define ABOUT_INFO "about.data" +#define RC_FILENAME ".gtkeyboardrc" +#define PROVIDED_RCFILE "example_configurations/defaults.gtkeyboard" +#define APPNAME "GTKeyboard" +#define CR "\n" + + + +/* adt.h + * For GTKeyboard + * written by David Allen s2mdalle@titan.vcu.edu + * http://opop.nols.com/ + * + * This file is released under the terms of the GNU General Public License. + * Please see COPYING for more details. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <errno.h> +#include <signal.h> +#include <ctype.h> +#include <assert.h> +#include <time.h> +#include <sys/time.h> + +/* Maximum number of custom colors. 10 is a good number, above that is + * really not needed per se. + */ +#define MAX_CUSTOM_COLORS 10 + +/**************************************************************************/ + +/* ADTs */ +/* Program configuration settings */ +typedef struct { + /* Changed to bits in 0.97.3 to save a little space. */ + /* Different program options - initialized in app.c changed in + * file_manip.c and messed with elsewhere. + * + * See app.c and the initialization code for comments on what they + * all mean. + */ + int REDIRECT_POLICY_IMPLICIT; + int STATUS_LOGGING; + int CAPS_LOCK; + int IGNORE_LAYOUT_FILE; + /* int ASK_REMAP_ON_EXIT; -- Deprecated for now... */ + int SHIFT; + int ALT_GR; + int NUMLOCK; + int VERBOSE; + int ALT; + int CONTROL; + int USE_KEYBOARD; + + + char *home; /* Home dir of user running the app. */ + char *tempslot; + char *extrafiles; /* Extra files, docs, default rcfile, lic. */ + char *redirect_window_name; /* Window name of redirection location. */ + char *keyboard_file; + char *cache_file; + Window redirect_window; /* Xlib window structure for redirection. */ + Window other; /* Temporary window structure for Xlib */ + + KEYBOARD *keyboard; + KEYBOARD *old_keyboard; + + /* These memory areas won't be used unless PROD isn't defined. + * When PROD isn't defined, we're not debugging, and they essentially + * keep track of the number of memory calls that I make. See also + * mem_header.h for a full definition of how they're used. + */ +#if defined(GTKEYBOARD_MEMORY_DEBUGGING) || defined(DEBUGGING) + long MEM; /* Number of bytes allocated */ + int gnew; /* Number of gnew() calls (alloc) */ + int gnew0; /* Number of gnew0() calls (alloc) */ + int gmalloc; /* Number of g_malloc() calls (alloc) */ + int gstrdup; /* Number of g_strdup() calls (alloc) */ + int gfree; /* Number of g_free() calls (free) */ +#endif +} GTKeyboardOptions; + +typedef struct { + GtkWidget *keyboard; + gint show_keyboard; +} GTKeyboardKeyboardElements; + +typedef struct { + int keyboard; +} GTKeyboardElements; + +/****************************************************************************/ + +typedef struct { + Window xwindow; /* So we can play with xlib. (our window) */ + GtkWidget *KEYBOARD; /* Container containing all keyb elements */ + + + GTKeyboardKeyboardElements keyboard_elements; + + /* If a field has a comment of "Cleaned" next to it, then it is + * either deallocated or destroyed in + * callbacks.c:gtkeyboard_mem_cleanup() via macro calls. + */ + char *custom_colors[MAX_CUSTOM_COLORS]; /* Cleaned */ + gchar *fontname; /* Cleaned */ + gchar *kfontname; /* Cleaned */ + gchar *colorname; /* Cleaned */ + gdouble saved_colors[4]; + + GtkShadowType SHADOW_TYPE; + GtkPositionType PULLOFFS_SIDE; + + GtkItemFactory *item_factory; /* Cleaned */ + GtkWidget *popup_menu; /* Cleaned */ + GdkCursor *cursor; + GtkStyle *style; + + /* Style referring to the main output text area */ + GtkStyle *textstyle; /* Cleaned */ + + /* The default GTK style */ + GtkStyle *deflt; /* Cleaned */ + + GdkFont *font; /* Cleaned */ + + /* The keyboard widget's style */ + GtkStyle *kstyle; /* Cleaned */ + + /* Keyboard font */ + GdkFont *kfont; /* Cleaned */ + + GtkTooltips *tooltips; +} GTKeyboardGUI; + +/**************************************************************************/ + +typedef struct { + int width; + int height; + int x; + int y; +} window_dimensions; + + +/* file_manip.h + * + * For use with GTKeyboard + * written by David Allen s2mdalle@titan.vcu.edu + * This file is released under the terms of the GNU General Public License + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <gtk/gtk.h> + + +#define MAX_LINE_LENGTH 128 +#define TOKEN_SIZE 50 +#define DEFAULT_RCFILE "# Default .gtkeyboardrc file written by GTKeyboard\nkeyboard main_keyboard on\nkeyboard number_pad on\nkeyboard cursor_keys on\nkeyboard f_keys on\n\nset handlebars off\n\nset word_wrap off\nset info_popups on\nset bump_amount 15\nhide buttonbar\nset random_strlen 10\nset eyecandy off\nset redirect_policy implicit\n" + + + + +#define STAT_AND_RETURN_IF_BAD(fname, someint, statstruct) \ + if(!fname)return(0);\ + someint = stat(fname, &statstruct);\ + if(someint<0) return(0); + +/* List of strings - GTKeyboard is really looking for these when it + * reads the rcfiles. These are the options it recognizes. To the user, + * they aren't case sensitive, but here, they must ALL be specified in all caps + */ +#define OPT_KEYBOARD_FILE "KEYBOARD_FILE" + + +/* Prototypes - creeping evil */ +static void parse_user_resource_file(char *filename); +static void FILE_readline(FILE * fp, char *buffer, const int maxlen); +static int setup_default_rcfile(char *file); + +/* EOF */ + +static const char *active_window_name = "CurrentWindow"; + +static Window root; +static XEvent xev; + +/* fake_timestamp is static in irxevent.c */ +static Window find_window(Window top, char *name); +static void gtkeyboard_XEvent_common_setup(XKeyEvent * xev); + +/* Various keyboards are included only for app.c and build_keyboard.c + * in master.h + */ + +/* Just make them all different - gets passed to build_an_entire_keyboard */ +/* Not used yet.. */ + +/* Local defines for what keys appear as */ + +/* + * Check the notes at the bottom of the page for an ASCII drawing of how the + * keyboard should look + * + * Each button is defined as a character string of two characters. The first + * is what you get when SHIFT || CAPS_LOCK > 0 and the second is the normal + * key function. This function loops through grabbing two characters at a + * time and then calling makekeybutton to set things up and map the + * callback to the key and so on. + * + * SPECIAL CASES WITHIN stuff[]: (Yes it's braindamaged) + * LL is the left cursor key + * RR is the right cursor key + * || is caps lock key + * \\ (or escaped, it's \\\\) is SHIFT key + * CC is control + * AA is alt + * +*/ + +/* PROTOTYPES - Most functions in build_keyboard.c are static and don't need + * prototypes here. + */ +static void keysym_callback(GtkWidget * emitter, gpointer data); +static void capslock_toggle(GtkWidget * w, gpointer data); +static void alt_toggle(GtkWidget * w, gpointer data); +static void alt_gr_toggle(GtkWidget * w, gpointer data); +static void control_toggle(GtkWidget * w, gpointer data); +static void shift_on(GtkWidget * w, gpointer data); + +typedef struct { + GtkStyle *style; + int mask; +} GTKeyboardStyle; + +typedef struct { + GtkWidget *dialog; + GdkColor *color; +} color_info; + +typedef struct { + long code; + char *name; +} binding; + + +/* Main program options - do not declare as static - all global */ +static GTKeyboardOptions options; +static GTKeyboardGUI GUI; +static GTKeyboardElements ELEMENTS; + + +#define NO_HANDLER 666 + +/* Static function prototypes */ +static void setup_default_opts(void); +static void setup_default_opts_other(void); + +#define INSTALL_DOC_DIR "/usr/local/share/gtkeyboard" + +int init_keyboard_stuff(char *input) +{ + char *filename; + char *homeptr; + + /* This sets the values in the structure GUI to default values. + * I'll add things for changing the default in that function later. + */ + setup_default_opts(); /* Handles the stuff in options */ + setup_default_opts_other(); + + /* Allocate the necessary memory to copy location of support files + * into */ + options.extrafiles = g_new0_(char, (strlen(INSTALL_DOC_DIR) + 3)); + sprintf(options.extrafiles, "%s%s", INSTALL_DOC_DIR, _DIR); + + options.keyboard = NO_KEYBOARD; + options.old_keyboard = NO_KEYBOARD; + + /* End if */ + homeptr = getenv("HOME"); + + if (homeptr) { + options.home = g_strdup_(getenv("HOME")); + } /* End if */ + else + options.home = NULL; + + filename = + g_new0_(char, strlen(options.home) + 5 + strlen(RC_FILENAME)); + sprintf(filename, "%s%s%s", (options.home ? options.home : "/tmp"), + _DIR, RC_FILENAME); + + /* This parses ALL user preferences from ~/.gtkeyboardrc into various + * structures - the important parts of this are in rc_file.h and + * file_manip.c + */ + + parse_user_resource_file(filename); + + CONDFREE(filename); + + return (1); +} /* End init_keyboard_stuff */ + +/* This gets called once at setup to initialize all the GUI but + * non-keyboard related opts + * Shouldn't return anything or allocate any memory, it just sets + * things to "reasonable" defaults. + */ +static void setup_default_opts_other(void) +{ + /* Here's where you get to set all of the defaults for GUI structure + * members. + */ + GUI.SHADOW_TYPE = GTK_SHADOW_ETCHED_OUT; + GUI.PULLOFFS_SIDE = GTK_POS_LEFT; + GUI.cursor = (GdkCursor *) NULL; + GUI.fontname = (gchar *) NULL; + GUI.kfontname = (gchar *) NULL; + GUI.colorname = (gchar *) NULL; + GUI.textstyle = (GtkStyle *) NULL; + GUI.style = (GtkStyle *) NULL; + GUI.font = (GdkFont *) NULL; + GUI.kfont = (GdkFont *) NULL; + GUI.deflt = (GtkStyle *) NULL; + GUI.xwindow = (Window) NULL; + GUI.popup_menu = (GtkWidget *) NULL; + GUI.item_factory = (GtkItemFactory *) NULL; + + GUI.keyboard_elements.show_keyboard = ON; + + GUI.keyboard_elements.keyboard = (GtkWidget *) NULL; + + return; +} /* End setup_default_opts_other */ + +/* This gets called once at startup, sets all the initial values for + * options.whatever stuff + */ +static void setup_default_opts(void) +{ + /* All screen ELEMENTS on by default */ + + ELEMENTS.keyboard = 1; + + /* Set up some default values for program parameters + * Can be changed by parse_rcfile later. Hopefully these are reasonable. + */ + options.other = (Window) NULL; + options.redirect_window = (Window) NULL; + options.home = (char *) NULL; + options.redirect_window_name = (char *) NULL; + options.tempslot = (char *) NULL; + options.keyboard_file = (char *) NULL; + + + /* options.ASK_REMAP_ON_EXIT = OFF; *//* Currently deprecated */ + options.STATUS_LOGGING = OFF; /* Save the status window */ + options.CAPS_LOCK = OFF; /* Caps lock starts at OFF */ + options.SHIFT = OFF; /* Shift starts at OFF */ + options.ALT_GR = OFF; /* Alt-GR key status */ + options.CONTROL = OFF; /* Control button at OFF */ + options.NUMLOCK = OFF; /* Numlock starts at OFF */ + options.ALT = OFF; /* Alt key starts at OFF */ + options.VERBOSE = OFF; /* Spew messages */ + options.REDIRECT_POLICY_IMPLICIT = ON; /* Default to implicit redir */ + options.IGNORE_LAYOUT_FILE = OFF; /* Dont ignore layout file */ + +} /* End setup_default_opts */ + + + +#define BUILD_KEYBOARD_C + +static char *string_special_cases(KeySym input); + +static void rotate_keyboard_definitions(KEYBOARD * new_keyboard) +{ + if (!new_keyboard) { + fprintf(stderr, + "rotate_keyboard_definitions Error: Bad keyboard.\n"); + fflush(stderr); + return; + } + + /* End if */ + /* If there is an old definition laying around, destroy it to free + * up the memory. + */ + if (options.old_keyboard) { + options.old_keyboard = + gtkeyboard_destroy_keyboard(options.old_keyboard); +#ifdef REMAPPING_DEBUGGING + fprintf(Q, "Rotated old keyboard out..."); + fflush(Q); +#endif /* REMAPPING_DEBUGGING */ + } + + /* End if */ + /* Copy the current keyboard definition to the 'old' keyboard */ + options.old_keyboard = options.keyboard; + + /* Make the argument to this function the 'current' keyboard */ + options.keyboard = new_keyboard; + +#ifdef REMAPPING_DEBUGGING + fprintf(Q, "Old keyboard is now %s, Current keyboard is now %s\n", + (options.old_keyboard ? "valid" : "dead"), + (options.keyboard ? "valid" : "dead")); + fflush(Q); +#endif /* REMAPPING_DEBUGGING */ + + return; +} /* End rotate_keyboard_definitions() */ + +/* This destroys the key attached as object data to a lot of the buttons + * when they get destroyed + */ +static void destroy_key_widget_data(GtkObject *object, gpointer data) +{ + KEY *key = (KEY *) data; + + if (!key) { + fprintf(stderr, + "GTKeyboard error (destroy_key_widget_data) "); + fprintf(stderr, "data == NULL!\n"); + fflush(stderr); + return; + } + /* End if */ + key = gtkeyboard_destroy_key(key); +} /* End destroy_key_widget_data() */ + +/* Call this for every widget that has a KEY structure as its object data + * this makes sure that when the widget is destroyed, destroy_key_widget_data + * gets called on the object data + */ +static void connect_destroy_signal(GtkWidget * widget, gpointer data) +{ +#if 0 + gtk_signal_connect_full(GTK_OBJECT(widget), + "destroy", + GTK_SIGNAL_FUNC(destroy_key_widget_data), + (GtkCallbackMarshal) + gtk_signal_default_marshaller, data, + (GtkDestroyNotify) destroy_key_widget_data, + FALSE, TRUE); +#endif + gtk_signal_connect(GTK_OBJECT(widget), + "destroy", + GTK_SIGNAL_FUNC(destroy_key_widget_data), + data); +} /* End connect_destroy_signal() */ + +static gint triple_callback(GtkWidget * emitter, GdkEvent * event, + gpointer data) +{ + KEY *k = (KEY *) data; + KEY *key = NO_KEY; + + if (!k) { + fprintf(stderr, + "GTKeyboard internal error: %s: NULL \"KEY\" arg.\n", + "(triple_callback)"); + fflush(stderr); + return TRUE; + } + /* End if */ + if (event->type == GDK_BUTTON_PRESS) { + key = gtkeyboard_key_copy(k); + + if (event->button.button == LEFT_MOUSE_BUTTON) { + /* Regular keypress, deal with it as normal */ + keysym_callback((GtkWidget *) NULL, + (gpointer) key); + key = gtkeyboard_destroy_key(key); + return TRUE; + } /* End if */ + else if (event->button.button == MIDDLE_MOUSE_BUTTON) { + KeySym lower, upper; + + /* Always generate the "Alt-GR" keysym */ + if (!key->alt_gr || key->alt_gr == NoSymbol) { + key->alt_gr = key->lower_case; + } /* End if */ + key->lower_case = key->upper_case = key->alt_gr; + + /* Not sure whether this is upper case or lower case. Try to + * find out by seeing if what XConvertCase returns is the same + * or different. + */ + XConvertCase(key->alt_gr, &lower, &upper); + + /* If upper is the same as alt_gr, then we need shift to be + * on. Otherwise leave it however it is + */ + if (key->alt_gr == upper) + options.SHIFT = ON; + + keysym_callback((GtkWidget *) NULL, + (gpointer) key); + /* Free the memory */ + key = gtkeyboard_destroy_key(key); + return TRUE; + } /* End else if */ + else if (event->button.button == RIGHT_MOUSE_BUTTON) { + /* Always generate the "uppercase" Keysym */ + key->lower_case = key->alt_gr = key->upper_case; + + options.SHIFT = ON; + + keysym_callback((GtkWidget *) NULL, + (gpointer) key); + key = gtkeyboard_destroy_key(key); + return TRUE; + } /* End if */ + else { + key = gtkeyboard_destroy_key(key); + return FALSE; + } /* End else */ + } + + /* End if */ + /* Tell calling code that we have not handled this event; pass it on. */ + return FALSE; +} /* End triple_callback() */ + +static void keysym_callback(GtkWidget * emitter, gpointer data) +{ + KEY *key = (KEY *) data; + KeySym sym; + char *keyname = (char *) NULL; + char *altkeyname = (char *) NULL; + KeySym lower = (KeySym) NULL, upper = (KeySym) NULL; + +#ifdef PARANOID_DEBUGGING + fprintf(Q, "keysym_callback(): Got (%s, %s, %s).\n", + XKeysymToString(key->lower_case), + XKeysymToString(key->upper_case), + XKeysymToString(key->alt_gr)); + fflush(Q); +#endif /* PARANOID_DEBUGGING */ + + /* Determine which of the syms in the KEY * structure to use. */ + keyname = XKeysymToString(key->lower_case); + altkeyname = XKeysymToString(key->alt_gr); + + if (options.ALT_GR) { + sym = key->alt_gr; + /* We have only three symbols, and we have to generate + * the fourth one for cyrillic letters. + */ + if (strstr(altkeyname, "Cyrillic_")) { + XConvertCase(sym, &lower, &upper); + + if (options.SHIFT || options.CAPS_LOCK) { + sym = upper; + } /* End if */ + } /* End if */ + } /* End if */ + else if (strstr(keyname, "KP")) { + if (options.NUMLOCK) + sym = key->upper_case; + else + sym = key->lower_case; + } /* End else if */ + else if (options.SHIFT) + sym = key->upper_case; + else if (options.CAPS_LOCK) { + if (isalpha((char) key->upper_case)) + sym = key->upper_case; + else + sym = key->lower_case; + } /* End else if */ + else + sym = key->lower_case; + + if (options.redirect_window_name) { + send_redirect_a_keysym(sym); + + } + /* End if */ + return; +} /* End keysym_callback() */ + +static int isspecial(KeySym input) +{ + char *ptr = XKeysymToString(input); + + if (input == NoSymbol || !ptr) + return (1); + if (strstr(ptr, "_L") || strstr(ptr, "_R")) + return (1); + if (strstr(ptr, "ontrol") || strstr(ptr, "Alt")) + return (1); + if (strstr(ptr, "ode")) + return (1); + if (strstr(ptr, "Tab") || strstr(ptr, "Lock") + || strstr(ptr, "pace")) + return (1); + + return (0); +} /* End isspecial */ + +GtkWidget *build_keyboard(GtkWidget * input, char *filename) +{ + /* NEW BUILD_KEYBOARD() */ + GtkWidget *mainbox = gtk_vbox_new(FALSE, 0); + GtkWidget *hbox = (GtkWidget *) NULL; + GtkWidget *button = (GtkWidget *) NULL; + char *name = (char *) NULL; + char *altname = (char *) NULL; + GtkWidget *align = (GtkWidget *) NULL; + char label[512]; + char tooltip_label[1024]; + char *errbuf = NULL; + char *utf8, *ptr; + int rowno; + int index; + char letter = '\0'; + char cyrletter = '\0'; + KEY *key; + KeySym s; + KeySym altlower, altupper; + + /* Create the current keyboard in a new place. -- This takes care of + * destroying our old ones for us. + */ + rotate_keyboard_definitions(read_keyboard_template(filename)); + + if (!options.keyboard) { + fprintf(stderr, "Couldn't read keyboard: Bummer.\n"); + fflush(stderr); + + errbuf = g_new0(char, strlen(filename) + 100); + sprintf(errbuf, + "Couldn't create keyboard from file:\n%s!\nCheck the file format!", + filename); + + button = gtk_button_new_with_label(errbuf); + + CONDFREE(errbuf); + + return (button); + } /* End if */ + else if (options.keyboard->keycount <= 0) { + errbuf = g_new0(char, strlen(filename) + 100); + sprintf(errbuf, + "Couldn't create keyboard from file:\n%s!\nCheck the file format!", + filename); + + button = gtk_button_new_with_label(errbuf); + CONDFREE(errbuf); + return (button); + } + /* End else if */ + for (rowno = 0; rowno < MAXIMUM_ROWS; rowno++) { + hbox = gtk_hbox_new(FALSE, 0); + align = gtk_alignment_new(0.5, 0.5, 0, 0); + + for (index = 0; + index < options.keyboard->row_values[rowno]; + index++) { + key = + gtkeyboard_keyboard_get_key(options.keyboard, + rowno, index); + + letter = (int) key->upper_case; + name = XKeysymToString(key->upper_case); + altname = XKeysymToString(key->alt_gr); + + if (key->upper_case == XK_Mode_switch || + key->lower_case == XK_Mode_switch) { + sprintf(label, " Alt Gr"); + } /* End if */ + else if (strstr(altname, "Cyrillic_")) { + /* We have only lower case letter, let us + * ask X to convert it to upper case. + */ + XConvertCase(key->alt_gr, &altlower, + &altupper); + + /* FIXME: Yes, this is totally wrong method to get + * the cyrillic letter. It just happen to to + * yield the right letter in koi8-r encoding. + */ + cyrletter = (char) altupper; + if (!isalpha(letter)) { + sprintf(label, " %c \n %c %c", + (char) key->upper_case, + (char) key->lower_case, + cyrletter); + } /* End if */ + else { + sprintf(label, " %c \n %c", + (char) key->upper_case, + cyrletter); + } /* End else */ + } /* End else if */ + else if ((isalnum(letter) || ispunct(letter)) + && (letter > 0)) { + if (!isalpha(letter)) + sprintf(label, " %c \n %c", + (char) key->upper_case, + (char) key->lower_case); + else + sprintf(label, " %c \n", + (char) key->upper_case); + } /* End if */ + else if (letter != 0) { + if (!iscntrl(letter) + && !isspecial(key->upper_case) + && letter != ' ') + sprintf(label, " %c \n %c", + (char) key->upper_case, + (char) key->lower_case); + else { + ptr = + string_special_cases(key-> + lower_case); + strncpy(label, ptr, 512); + g_free_(ptr); + } /* End else */ + } /* End else if */ + else { + ptr = + string_special_cases(key->lower_case); + strncpy(label, ptr, 512); + g_free_(ptr); + } /* End else */ + + s = key->lower_case; + +#if 0 + utf8 = + g_locale_to_utf8(label, -1, NULL, NULL, NULL); +#else + utf8=g_convert(label,-1,"utf-8","iso8859-1",NULL,NULL,NULL); +#endif + /* Make the correct key, and attach the correct signal + * function to it. Toggle/normal button/function + */ + if (s == XK_Caps_Lock || s == XK_Control_L || + s == XK_Control_R || s == XK_Alt_L || + s == XK_Alt_R || s == XK_Mode_switch) + button = + gtk_toggle_button_new_with_label(utf8); + else + button = gtk_button_new_with_label(utf8); + + g_free(utf8); + GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); + if (key->code != 0) + sprintf(tooltip_label, + "KeyCode %d:\n%s\n%s\n%s", + key->code, + XKeysymToString(key->lower_case), + XKeysymToString(key->upper_case), + XKeysymToString(key->alt_gr)); + else + sprintf(tooltip_label, + "KeyCode unknown:\n%s\n%s\n%s", + XKeysymToString(key->lower_case), + XKeysymToString(key->upper_case), + XKeysymToString(key->alt_gr)); + + switch (key->lower_case) { + case XK_Caps_Lock: + gtk_signal_connect(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC + (capslock_toggle), + input); + /* Key unused in signalling */ + key = gtkeyboard_destroy_key(key); + break; + case XK_Alt_L: + case XK_Alt_R: + gtk_signal_connect(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC + (alt_toggle), NULL); + /* Key unused in signalling */ + key = gtkeyboard_destroy_key(key); + break; + case XK_Control_L: + case XK_Control_R: + gtk_signal_connect(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC + (control_toggle), NULL); + /* Key unused in signalling */ + key = gtkeyboard_destroy_key(key); + break; + case XK_Shift_L: + case XK_Shift_R: + gtk_signal_connect(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC + (shift_on), NULL); + /* Key unused in signalling */ + key = gtkeyboard_destroy_key(key); + break; + case XK_Mode_switch: + gtk_signal_connect(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC + (alt_gr_toggle), NULL); + /* Key unused in signalling */ + key = gtkeyboard_destroy_key(key); + break; + default: + gtk_signal_connect(GTK_OBJECT(button), + "button_press_event", + GTK_SIGNAL_FUNC + (triple_callback), key); + connect_destroy_signal(button, key); + break; + } /* End switch */ + + gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, + FALSE, 0); + } /* End for */ + + gtk_container_add(GTK_CONTAINER(align), hbox); + gtk_box_pack_start(GTK_BOX(mainbox), align, FALSE, FALSE, + 0); + } /* End for */ + + if (filename) { + if (options.keyboard_file) { + /* We just built a complete keyboard with this file, so save its + * name for future use. + */ + /* This weird indirect freeing and copying of the string is + * due to the fact that the filename argument to this function + * may in fact be options.keyboard_file itself, so in that + * case it wouldn't be that bright to try to free it and + * copy something that's pointing to the same location. So + * instead we copy it to an intermediate spot, free the + * original, and copy the new value back. + * + * When the value actually is options.keyboard_file, we do a + * bit of redundant work, but oh well. + */ + char *tptr; + tptr = g_strdup_(filename); + g_free_(options.keyboard_file); + options.keyboard_file = g_strdup_(tptr); + g_free_(tptr); +#if 0 + fprintf(Q, + "options.keyboard_file set to be \"%s\"\n", + options.keyboard_file); + fflush(Q); +#endif + } /* End if */ + else { + /* No need to free it - just copy */ + options.keyboard_file = g_strdup_(filename); + fprintf(Q, + "options.keyboard_file set to be \"%s\"\n", + options.keyboard_file); + fflush(Q); + } /* End else */ + } + + /* End if */ + /* gtk_widget_show_all(mainbox); */ + return (mainbox); +} /* End build_keyboard() */ + +static char *string_special_cases(KeySym input) +{ + char label[1024]; + int len, x; + char *ptr; + + if (input == XK_space) { + sprintf(label, + " \n"); + } /* End if */ + else { + /* Space out the output a bit depending on string target + * length so the buttons will look right. + */ + ptr = XKeysymToString(input); + if (strlen(ptr) > 4) + sprintf(label, " %s \n", ptr); + else + sprintf(label, " %s \n", ptr); + } /* End else */ + + len = strlen(label); + + /* Special cases */ + if (strstr(label, "Control") || strstr(label, "control")) { + strcpy(label, " Ctrl "); + } /* End if */ + else if (input == XK_Mode_switch) + strcpy(label, " Alt Gr"); + else { + /* Remove the sillyness from XK_ names from the string. */ + for (x = 0; x < len; x++) { + /* Make everything uppercase */ + label[x] = toupper(label[x]); + + /* Get rid of the _R or _L that may be there. */ + if (label[x] == '_' && + (label[x + 1] == 'R' || label[x + 1] == 'L')) { + label[x] = '\0'; + } /* End if */ + } /* End for */ + } /* End else */ + + ptr = g_strdup_(label); + + return (ptr); +} /* End string_special_cases() */ + + +#define MODE_WRITE + +/* Do not allow both MODE_WRITE and MODE_APPEND to be defined. If both are + * defined, default to MODE_WRITE. The End Of Earth As We Know It (TM) occurs + * (or maybe just a compile error) MODE_WRITE is spiffier. + */ +#ifdef MODE_APPEND +# ifdef MODE_WRITE +# undef MODE_APPEND +# endif /* MODE_WRITE */ +#endif /* MODE_APPEND */ + +#ifndef __USE_GNU +# define __USE_GNU +#endif /* __USE_GNU */ + + +static void alt_gr_toggle(GtkWidget * w, gpointer data) +{ + if (ISOFF(options.ALT_GR)) { + options.ALT_GR = ON; + } /* End if */ + else { + options.ALT_GR = OFF; + } /* End else */ +} /* End alt_gr_toggle */ + +static void control_toggle(GtkWidget * w, gpointer data) +{ + if (ISOFF(options.CONTROL)) { + options.CONTROL = ON; + } /* End if */ + else { + options.CONTROL = OFF; + } /* End else */ +} /* End control_toggle */ + +static void alt_toggle(GtkWidget * w, gpointer data) +{ + if (ISOFF(options.ALT)) { + options.ALT = ON; + } /* End if */ + else { + options.ALT = OFF; + } /* End else */ +} /* End alt_toggle */ + +static void capslock_toggle(GtkWidget * w, gpointer data) +{ + if (options.redirect_window_name) + send_redirect_a_keysym(XK_Caps_Lock); + + /* Whatever it currently is, swtich it */ + if (ISOFF(options.CAPS_LOCK)) { + options.CAPS_LOCK = ON; + } /* End if */ + else { + options.CAPS_LOCK = OFF; + } /* End else */ +} /* End capslock_toggle */ + +static void shift_on(GtkWidget * w, gpointer data) +{ + /* Turn shift on */ + options.SHIFT = ON; + +} /* End shift_on */ + +/* This parses the user resource file via read_ConfigFile. This function + * doesn't actually do much other than define all of the structures for + * parsing in one place and actually doing the function calls. This is + * where you need to tweak command options. + */ +static void parse_user_resource_file(char *filename) +{ + RCVARS rc_parse_values[] = { + {"set", OPT_KEYBOARD_FILE, RC_STR, &options.keyboard_file, + NULL}, + {NULL, NULL, RC_NONE, NULL, NULL} + }; /* End rc_parse_values */ + + if (!file_exists(filename)) { + fprintf(stderr, + "Your resource file doesn't seem to exist.\n"); + fprintf(stderr, "I'll create one for you at \"%s\"\n", + filename); + fflush(stderr); + setup_default_rcfile(filename); + } + /* End if */ + read_ConfigFile(filename, rc_parse_values, 1); +} /* End parse_user_resource_file() */ + +/* Read one line from the specified file pointer and return it as + * as a pointer to char and so on. + */ +static void FILE_readline(FILE * fp, char *buffer, const int maxlen) +{ + int index = 0; + int x; + char tmp; + + do { + x = fread(&tmp, sizeof(char), 1, fp); + if ((x == 0) || (tmp == '\n')) + buffer[index] = '\0'; /* Terminate the string with a NULL */ + else + buffer[index++] = tmp; /* Add the character */ + if (!(index < maxlen)) { + fprintf(Q, + "Error on FILE_readline: index >= maxlen\n"); + fflush(Q); + return; + } /* End if */ + } while ((x != 0) && (tmp != '\n')); + return; +} /* End FILE_readline */ + +/* Copies a default rcfile from somewhere to the input filename */ +static int setup_default_rcfile(char *file) +{ + FILE *fp; + FILE *dflt; + char buffer[1024]; + char buffer2[1024]; + + if ((fp = fopen(file, "w")) == NULL) { + fprintf(Q, "Couldn't open %s for writing - cannot create ", + file); + fprintf(Q, "default .gtkeyboardrc!\n"); + fflush(Q); + return (0); + } /* End if */ + else { + /* Try to open the distribution-provided rcfile first */ + sprintf(buffer, "%s/%s", options.extrafiles, + PROVIDED_RCFILE); + + if ((dflt = fopen(buffer, "r")) == NULL) { + /* Ok, fine, so we can't open the default one we provided + * with the distribution. We'll just give the user a really + * short and crappy one. + */ + fprintf(Q, "Couldn't open %s: %s.\n", buffer, + g_strerror(errno)); + fprintf(Q, + "Fine then! We'll try something else...\n"); + fflush(Q); + + fprintf(fp, "%s", DEFAULT_RCFILE); + fclose(fp); + fprintf(Q, + "Success writing default .gtkeyboardrc\n"); + fprintf(Q, + "You can edit it to make changes later by editing "); + fprintf(Q, "%s\n", file); + fflush(Q); + return (1); + } /* End if */ + else { + while (!feof(dflt)) { + FILE_readline(dflt, buffer2, 1024); + /* Add a newline because FILE_readline kills them off */ + fprintf(fp, "%s\n", buffer2); + } /* End while */ + + fflush(fp); + fclose(dflt); + fclose(fp); + + fprintf(Q, + "Successfully wrote .gtkeyboardrc from "); + fprintf(Q, + "default. (%s: Distribution provided)\n", + PROVIDED_RCFILE); + } /* End else */ + } /* End else */ + FLUSH_EVERYTHING; + return (1); +} /* End setup_default_rcfile */ + +static int file_exists(const char *filename) +{ + struct stat file_info; + int x; + + STAT_AND_RETURN_IF_BAD(filename, x, file_info); + + return (1); +} /* End file_exists */ + +/* seems that xfree86 computes the timestamps for events like this + * strange but it relies on the *1000-32bit-wrap-around + * if anybody knows exactly how to do it, please contact me + * returns: a timestamp for the + * constructed event + */ +static Time fake_timestamp() +{ + int tint; + struct timeval tv; + struct timezone tz; /* is not used since ages */ + gettimeofday(&tv, &tz); + tint = (int) tv.tv_sec * 1000; + tint = tint / 1000 * 1000; + tint = tint + tv.tv_usec / 1000; + return ((Time) tint); +} /* End fake_timestamp() */ + +/* in: id of the root window name of the target window + * returns: id of the target window + * called by: main + */ +static Window find_window(Window top, char *name) +{ + char *wname, *iname; + XClassHint xch; + Window *children, foo; + int revert_to_return; + unsigned int nc; + + if (!strcmp(active_window_name, name)) { + XGetInputFocus(GDK_DISPLAY(), &foo, &revert_to_return); + return (foo); + } + + /* End if */ + /* First the base case */ + if (XFetchName(GDK_DISPLAY(), top, &wname)) { + if (!strncmp(wname, name, strlen(name))) { + XFree(wname); + return (top); /* found it! */ + } + /* End if */ + XFree(wname); + } + /* End if */ + if (XGetIconName(GDK_DISPLAY(), top, &iname)) { + if (!strncmp(iname, name, strlen(name))) { + XFree(iname); + return (top); /* found it! */ + } /* End if */ + XFree(iname); + } + /* End if */ + if (XGetClassHint(GDK_DISPLAY(), top, &xch)) { + if (!strcmp(xch.res_class, name)) { + XFree(xch.res_name); + XFree(xch.res_class); + return (top); /* found it! */ + } /* End if */ + XFree(xch.res_name); + XFree(xch.res_class); + } + /* End if */ + if (!XQueryTree(GDK_DISPLAY(), top, &foo, &foo, &children, &nc) || + children == NULL) + return (0); /* no more windows here */ + + /* check all the sub windows */ + for (; nc > 0; nc--) { + top = find_window(children[nc - 1], name); + if (top) + break; /* we found it somewhere */ + } /* End for */ + + /* Free that mem! Yeehaw!!! */ + if (children) + XFree(children); + + return (top); +} /* End find_window() */ + +/* This just assigns a bunch of things to certain elements of the pointer + * that are shared no matter what type of signal GTKeyboard is sending. + * Prevents code duplication in ugly places + */ +static void gtkeyboard_XEvent_common_setup(XKeyEvent * xev) +{ + xev->type = KeyPress; + xev->display = GDK_DISPLAY(); + xev->root = root; + xev->subwindow = None; + xev->time = fake_timestamp(); + xev->same_screen = True; + xev->state = 0; + xev->x = xev->y = xev->x_root = xev->y_root = 1; +} /* End gtkeyboard_XEvent_common_setup */ + +static int assign_keycode_from_keysym(KeySym foo, XKeyEvent * xev) +{ + unsigned long mask = 0; + char *keyname = (char *) NULL; + + keyname = XKeysymToString(foo); + xev->keycode = XKeysymToKeycode(GDK_DISPLAY(), foo); + + /* Check and assign masks. */ + if (options.SHIFT) { /* Need ShiftMask? */ + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Shift_L)); + if (!mask) { + /* WTF? Shift_L isn't mapped? OK, try Shift_R */ + mask = + find_modifier_mask(XKeysymToKeycode + (GDK_DISPLAY(), + XK_Shift_R)); + } + /* End if */ + fprintf(Q, "Shift mask: 0x%lx normal mask 0x%lx\n", mask, + (unsigned long) ShiftMask); + + /* Even if mask is actually 0 because we couldn't find the shift + * key mapped, this just won't do anything at all. + * find_modifier_mask issued a warning about not finding it, too + */ + xev->state |= mask; + options.SHIFT = 0; + } + /* End if */ + if (options.CAPS_LOCK) { /* Need LockMask? */ + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Caps_Lock)); + fprintf(Q, "Capslock mask: 0x%lx normal mask 0x%lx\n", + mask, (unsigned long) LockMask); + xev->state |= mask; /* Normally LockMask */ + } + /* End if */ + if (options.CONTROL) { /* Need ControlMask? */ + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Control_L)); + if (!mask) { + mask = + find_modifier_mask(XKeysymToKeycode + (GDK_DISPLAY(), + XK_Control_R)); + } + /* End if */ + fprintf(Q, "Control mask: 0x%lx normal mask 0x%lx\n", + mask, (unsigned long) ControlMask); + xev->state |= mask; + } + /* End if */ + if (options.ALT) { /* Need Mod1Mask? */ + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Alt_L)); + if (!mask) { + mask = + find_modifier_mask(XKeysymToKeycode + (GDK_DISPLAY(), XK_Alt_R)); + } + /* End if */ + fprintf(Q, "Alt mask: 0x%lx normal mask 0x%lx\n", + mask, (unsigned long) Mod1Mask); + xev->state |= mask; + } + /* End if */ + if (options.NUMLOCK) { + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Num_Lock)); + fprintf(Q, "Numlock: Mask 0x%lx\n", mask); + xev->state |= mask; + } + /* End if */ + if (options.ALT_GR) { + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_Mode_switch)); + fprintf(Q, "Alt_GR: Mask 0x%lx\n", mask); + xev->state |= mask; + } + /* End if */ + if (strstr(keyname, "Cyrillic_")) { /* Cyrillic? */ + mask = find_modifier_mask(XKeysymToKeycode(GDK_DISPLAY(), + XK_ISO_Group_Shift)); + /* FIXME: How do we get this mask and what does it mean? + * Seems to be XKB_Group. Default 0x2000 + */ + + xev->state |= mask; + } + + + /* End if */ + /* xev->state = xev->state | ButtonMotionMask; */ +#if 0 + fprintf(Q, "Final mask on event: %ld 0x%lx\n", + (unsigned long) xev->state, (unsigned long) xev->state); +#endif + + if (xev->keycode != 0) + return 1; + + else + return 0; +} /* End assign_keycode_from_keysym() */ + +static void keysym_sendkey(KeySym somesym, Window w) +{ + gtkeyboard_XEvent_common_setup((XKeyEvent *) & xev); + + /* assign_keycode_from_keysym() will also add in the needed + * masks. WARNING: This may change options.SHIFT and other + * bitflags in options according to whether or not they should + * change. + */ + if (!assign_keycode_from_keysym(somesym, (XKeyEvent *) & xev)) { + return; + } + /* End if */ + xev.xkey.window = w; + + /* This may produce a BadWindow error with Xlib. Bummer. + * This happens most commonly when the window that was selected to + * redirect to doesn't exist on screen anymore. + */ + gdk_error_trap_push(); /* Catch errors, hopefully */ + + XSendEvent(GDK_DISPLAY(), w, True, KeyPressMask, &xev); + + XSync(GDK_DISPLAY(), False); + + xev.type = KeyRelease; /* Start the next Event */ + /* usleep(50000); */ +#if 0 + XFlush(GDK_DISPLAY()); +#endif + xev.xkey.time = fake_timestamp(); + XSendEvent(GDK_DISPLAY(), w, True, KeyReleaseMask, &xev); + XSync(GDK_DISPLAY(), False); + +#if 0 + gdk_flush(); +#endif + + if (gdk_error_trap_pop()) { + } + /* End if */ + return; +} /* End keysym_sendkey() */ + +/* Insert KeyCode code into slot slot in the table structure. + * Returns != 0 on success, 0 on failure. Failure means that + * the table is full, or that the code you're trying to insert is 0 + */ +static int ModmapTable_insert(ModmapTable * table, KeyCode code, int slot) +{ + int x = 0; + + if ((code == (KeyCode) 0) || (slot < 0) || (slot > 8)) + /* This operation makes no sense. Return failure. */ + return 0; + + for (x = 0; x < table->max_keypermod; x++) { + /* Insert in the first available open slot + * but not in taken slots. That would be a bad idea to + * silently overwrite some of the caller's data. :) + */ + if (table->modifiers[slot].codes[x] == 0) { + table->modifiers[slot].codes[x] = code; + return 1; + } /* End if */ + } /* End for */ + + /* Fail - can't find empty slot */ + return (0); +} /* End ModmapTable_insert() */ + +static ModmapTable *ModmapTable_new(void) +{ + XModifierKeymap *map = XGetModifierMapping(GDK_DISPLAY()); + ModmapTable *table; + int mkpm = map->max_keypermod; + int x = 0; + int y = 0; + + XFreeModifiermap(map); + table = g_new0_(ModmapTable, 1); + table->max_keypermod = mkpm; + + for (x = 0; x < 8; x++) { + for (y = 0; y < 4; y++) { + table->modifiers[x].codes[y] = (KeyCode) 0; + } /* End for */ + } /* End for */ + + return table; +} /* End ModmapTable_new() */ + +static void ModmapTable_destroy(ModmapTable * table) +{ + g_free_(table); +} /* End ModmapTable_destroy() */ + +/* Translates a string mask name into a slot number for access to numerous + * modmap data structures. + */ +static int mask_name_to_slot_number(char *maskname) +{ + char *masks[] = { "ShiftMask", "LockMask", + "ControlMask", "Mod1Mask", + "Mod2Mask", "Mod3Mask", + "Mod4Mask", "Mod5Mask" + }; + int maskcount = 8; + int y = 0; + + for (y = 0; y < maskcount; y++) { + if (g_strcasecmp(maskname, masks[y]) == 0) + return y; + } /* End for */ + + return (-1); +} /* End mask_name_to_slot_number() */ + +static unsigned long find_modifier_mask(KeyCode code) +{ + XModifierKeymap *map = XGetModifierMapping(GDK_DISPLAY()); + int x = 0, y = 0; + KeyCode c = (KeyCode) NULL; + unsigned long mask = 0; + + if (code == (KeyCode) 0) { + XFreeModifiermap(map); + fprintf(Q, + "Error finding modifier mask for 0 keycode: Have you\n"); + fprintf(Q, + "actually remapped your keyboard to this layout?\n"); + return 0; + } + /* End if */ + for (x = 0; x < 8; x++) { + for (y = 0; y < map->max_keypermod; y++) { + c = map->modifiermap[x * map->max_keypermod + y]; + if (c == code) { + XFreeModifiermap(map); + mask = slot_number_to_mask(x); + fprintf(Q, + "Found modifier %d in slot (%d,%d) mask %ld 0x%lx\n", + code, x, y, mask, mask); + return mask; + } /* End if */ + } /* End for */ + } /* End for */ + + XFreeModifiermap(map); + + /* Return nothing. This is bad, but better than doing the wrong thing. */ + fprintf(Q, + "***** WARNING: find_modifier_mask failed to locate code %d\n", + code); + fflush(Q); + return 0; +} /* End find_modifier_mask() */ + + +/* Makes a NULL-terminated string that gets passed as input nothing but + * upper case characters. + * + * THIS FUNCTION MODIFIES ITS ARGUMENT + */ +static void str_toupper(char *string) +{ + int x = 0; + + while (string[x]) { /* Stop on NULL */ + string[x] = toupper(string[x]); + x++; + } /* End while */ +} /* End str_toupper() */ + +/* Passed - the filename, the set of variables to look for, (see the header + * file for the definition of that structure) and an integer - if it's 0, + * then "syntax error" messages won't be printed. Otherwise, we'll complain. + */ +static int read_ConfigFile(char *filename, RCVARS * vars, int complain) +{ + gint n = 0; + gpointer N; + FILE *rcFile; + GHashTable *H; + gchar Line[BUFSIZ], varPrefix[BUFSIZ], varName[BUFSIZ], + varVal[BUFSIZ]; + + /* if the RC file doesn't exist, don't bother doing anything else */ + if ((rcFile = fopen(filename, "r")) == NULL) { + if (complain) { + fprintf(Q, "Couldn't open %s for reading: %s\n", + filename, g_strerror(errno)); + fflush(Q); + } /* End if */ + return 1; + } + + /* End if */ + /* Create a hash table of all the variable names and their arrayindex+1 */ + H = g_hash_table_new(g_str_hash, g_str_equal); + + n = 0; + /* Hash in all of the variable names. Later when we read them in, + * we'll hash in what we read to compare it against what was in the + * table passed to us. + */ + while (vars[n].Type != RC_NONE) { + g_hash_table_insert(H, vars[n].Name, + GINT_TO_POINTER(n + 1)); + n++; + } /* End while */ + + /* read each line of the RC file */ + while (fgets(Line, BUFSIZ, rcFile) != NULL) { + /* Strip leading and trailing whitespace from the string */ + strcpy(Line, g_strstrip(Line)); + + /* Skip comments and lines too short to have useful information + * in them. This will include "blank" lines that got g_strstrip'd + * down to 0 or 1 bytes + */ + if ((strlen(Line) < 2) || Line[0] == '#') + continue; + + /* Initialize values so in case of error they will be NULL, not + * the value of the last parse. + */ + varPrefix[0] = varName[0] = varVal[0] = '\0'; + + /* grab each variable and its value (maybe). + * If prefix is specified, it tries to read the + * given prefix. + */ + if (strstr(Line, "=")) + sscanf(Line, " %s = %s\n", varName, varVal); + else + sscanf(Line, " %s %s %s\n", varPrefix, varName, + varVal); + + /* Sometimes prefix *could* be null, but if name or value is + * null, there's really nothing we can do with that string. + */ + if (!varName[0] && !varVal[0]) { + if (complain) { + fprintf(stderr, + "Error parsing line \"%s\": ", + Line); + fprintf(stderr, + "I have no idea what that line means.\n"); + fflush(stderr); + } + /* End if */ + continue; + } + + /* End if */ + /* We want the rc file to be case insensitive, but we're looking for + * all upper-case varaible names, so convert the string to all + * upper-case so it will hash in correctly. + */ + str_toupper(varName); + + /* use the hash table to find the correct array entry */ + if ((N = g_hash_table_lookup(H, varName)) == NULL) { + continue; /* but skip to the next line if can't find it. */ + } + /* End if */ + n = GPOINTER_TO_INT(N) - 1; /* convert back into an array index */ + + /* We can't necessarily match the read prefix to the requested + * prefix since the prefixes may be different and may require + * processing through the function pointer associated with the + * record + */ + + /* + * Did we see a prefix when we didn't want one? + */ + if (!vars[n].Prefix && varPrefix[0]) { + fprintf(stderr, + "Error: Bad syntax. I wasn't expecting to see "); + fprintf(stderr, "a variable prefix on \"%s\".\n", + (varName ? varName : Line)); + fprintf(stderr, "Ignoring line \"%s\"\n", Line); + fflush(stderr); + continue; + } + + /* End if */ + /* Are we supposed to run this one through a function? */ + if (vars[n].Type == RC_PARSE_FUNC) { + /* Use the outside function specified in the structure + * to parse these line elements since their grammar is + * somewhat weird + */ + if (!vars[n]. + func(varPrefix, varName, varVal, + vars[n].Val)) { + fprintf(stderr, + "There was an error parsing \"%s\"\n", + Line); + fflush(stderr); + } + /* End if */ + continue; /* Done with this line */ + } + + /* End if */ + /* We're not supposed to run this through a function -- + * based on the variable's type, set the C variable to its saved + * value + */ + switch (vars[n].Type) { + case (RC_STR): + { + char *tok; + + /* varVal is not trustworthy, find the string + * within the quotes and use that instead. + */ + if (strstr(Line, "\"")) { + tok = strtok(Line, "\""); + if (!tok) { + /* This really shouldn't happen */ + if (complain) { + fprintf(stderr, + "Parse error within \"%s\"\n", + Line); + fflush(stderr); + } /* End if */ + break; + } /* End if */ + tok = strtok(NULL, "\""); + } /* End if */ + else + tok = &varVal[0]; + + /* free the current contents of the variable */ + if (*(gchar **) (vars[n].Val)) + g_free_(*(gchar **) vars[n].Val); + + /* set the variable to its new value. */ + if (tok) { + *(gchar **) (vars[n].Val) = + g_strdup_(tok); + } /* End if */ + else + *(gchar **) (vars[n].Val) = + (char *) NULL; + break; + } /* End block */ + } /* End switch */ + } /* End while */ + + /* clean up and exit */ + g_hash_table_destroy(H); + fclose(rcFile); + return 0; +} /* End read_ConfigFile() */ + +static KEY *gtkeyboard_key_copy(KEY * key) +{ + KEY *newkey; + + if (!key) + return (NO_KEY); + + newkey = gtkeyboard_new_key(key->lower_case, + key->upper_case, + key->alt_gr, key->aux_string); + newkey->code = key->code; + return (newkey); +} /* End gtkeyboard_key_copy() */ + +/* Returns the "keyno"th key in row "row" of keyb + * This is allocated memory which must be g_free()'d later. + * This will ALWAYS return allocated memory - it just might always be + * filled with NoSymbol + */ +static KEY *gtkeyboard_keyboard_get_key(KEYBOARD * keyb, int row, + int keyno) +{ + KEY *foobar; + int index; + int x, findex = 0; + + foobar = gtkeyboard_new_key(NoSymbol, NoSymbol, NoSymbol, NULL); + + if (row > MAXIMUM_ROWS) { + fprintf(stderr, + "gtkeyboard_keyboard_get_key: Row out of range.\n"); + fflush(stderr); + return (foobar); + } + /* End if */ + if (!keyb) { + fprintf(stderr, + "gtkeyboard_keyboard_get_key: Null keyb.\n"); + fflush(stderr); + return (foobar); + } + /* End if */ + x = findex = 0; + + while (x < row) { + /* Add up the number of keys on all lines preceeding the one we're + * looking for + */ + findex += keyb->row_values[x]; + x++; + } /* End while */ + + index = (findex * 3) + (keyno * 3); + + if (index > ((keyb->keycount * 3) - 3)) { + fprintf(stderr, "gtkeyboard_keyboard_get_key(): "); + fprintf(stderr, + "Illegal index %d of a total keycount of %d (%d).\n", + index, keyb->keycount, ((keyb->keycount * 3) - 3)); + fflush(stderr); + return (foobar); + } + + /* End if */ + /* Three consecutive KeySyms */ + foobar->lower_case = keyb->syms[index]; + foobar->upper_case = keyb->syms[(index + 1)]; + foobar->alt_gr = keyb->syms[(index + 2)]; + foobar->aux_string = (char *) NULL; /* No auxilliary */ + + if (keyb->codes) + foobar->code = keyb->codes[(findex + keyno)]; + else + foobar->code = 0; + + return (foobar); +} /* End gtkeyboard_keyboard_get_key() */ + +static KEY *gtkeyboard_new_key(const KeySym lower, const KeySym upper, + const KeySym altgr, const char *alt) +{ + KEY *somekey = g_new0_(KEY, 1); + somekey->lower_case = lower; + somekey->upper_case = upper; + somekey->alt_gr = altgr; + somekey->code = 0; + if (alt) { + somekey->aux_string = g_strdup_(alt); + } /* End if */ + else + somekey->aux_string = NULL; + + return (somekey); +} /* End gtkeyboard_new_key() */ + +static KEY *gtkeyboard_destroy_key(KEY * input) +{ + if (!input) { + fprintf(Q, + "Error: gtkeyboard_destroy_key: NULL argument.\n"); + fflush(Q); + return (NO_KEY); + } + /* End if */ + if (input->aux_string) { + g_free_(input->aux_string); + input->aux_string = (char *) NULL; + } + /* End if */ + g_free_(input); + input = NO_KEY; /* Null pointer so it won't be reused */ + + return (NO_KEY); +} /* End gtkeyboard_destroy_key() */ + +static KEYBOARD *gtkeyboard_destroy_keyboard(KEYBOARD * input) +{ + if (!input) { + fprintf(stderr, + "gtkeyboard_destroy_keyboard: Cannot destroy NULL ptr.\n"); + fflush(stderr); + return (NO_KEYBOARD); + } + /* End if */ + if (input->syms) { + g_free_(input->syms); + input->syms = NULL; + } + /* End if */ + if (input->name) { + g_free_(input->name); + input->name = NULL; + } + /* End if */ + if (input->codes) { + g_free_(input->codes); + input->codes = NULL; + } + /* End if */ + if (input->modmap) { + ModmapTable_destroy(input->modmap); + input->modmap = (ModmapTable *) NULL; + } + /* End if */ + if (input->trans) { + CONDFREE(input->trans->space); + CONDFREE(input->trans->tab); + CONDFREE(input->trans->alt_gr); + CONDFREE(input->trans->alt); + CONDFREE(input->trans->control); + CONDFREE(input->trans->shift); + CONDFREE(input->trans->backspace); + + /* Free the parent pointer */ + CONDFREE(input->trans); + } + /* End if */ + g_free_(input); + input = NO_KEYBOARD; + + return (NO_KEYBOARD); +} /* End gtkeyboard_destroy_keyboard() */ + +static int get_valid_line(FILE * fp, char *mem, const int maxlen) +{ + mem[0] = '\0'; + + while (!feof(fp) && mem[0] == '\0') { + FILE_readline(fp, mem, maxlen); + + if (mem[0] != '\0') { + strcpy(mem, g_strstrip(mem)); + + if ((mem[0] && mem[0] == '#') + || (mem[0] && mem[0] == '!')) + mem[0] = '\0'; + } /* End if */ + } /* End while */ + + if (mem[0] == '\0') + return (0); + + else + return (1); +} /* End get_valid_line() */ + +/* Parses the contents of a keyboard description file and returns + * a corresponding KEYBOARD structure. + */ +static KEYBOARD *read_keyboard_template(char *filename) +{ + KEYBOARD *keyb = NO_KEYBOARD; + FILE *fp; + register int x = 0, y = 0; + int line_size = 1024; + int index = 0; + char linedata[line_size]; + char **tokens; + char **tofree; + char *ptr; + + if (!filename || !file_exists(filename)) { + fprintf(stderr, "Error loading keyboard file \"%s\": ", + (filename ? filename : "NULL")); + fprintf(stderr, "File doesn't exist."); + fflush(stderr); + return (NO_KEYBOARD); + } + /* End if */ + fp = fopen(filename, "r"); + + if (!fp) { + return (NO_KEYBOARD); + } + /* End if */ + linedata[0] = '\0'; + + if (!get_valid_line(fp, linedata, line_size)) { + fclose(fp); + return (NO_KEYBOARD); + } + /* End if */ + keyb = g_new0_(KEYBOARD, 1); + keyb->modmap = ModmapTable_new(); + + tofree = g_strsplit(linedata, " ", -1); + tokens = tofree; + + keyb->keycount = 0; + keyb->trans = g_new_(KeyboardTranslation, 1); + + /* Initialize it's various elements */ + keyb->trans->shift = keyb->trans->backspace = keyb->trans->space = + keyb->trans->caps_lock = keyb->trans->control = + keyb->trans->tab = keyb->trans->alt = keyb->trans->alt_gr = + (char *) NULL; + + for (x = 0; x < MAXIMUM_ROWS; x++) { + if (*tokens) + ptr = *tokens++; + else + ptr = NULL; + + if (ptr) + keyb->row_values[x] = atoi(ptr); + else { + *tokens = NULL; + keyb->row_values[x] = 0; + } /* End else */ + + keyb->keycount += keyb->row_values[x]; + } /* End for */ + + g_strfreev(tofree); + tofree = tokens = NULL; + ptr = NULL; + + /* We now know how many keys we have to allocate, how many lines to read, + * and all that good stuff. + * + * Each key must have 3 syms, (lower case, upper case, and Alt Gr) + * So allocate 3*keyb->keycount items, and read keyb->keycount lines. + */ + keyb->syms = g_new0_(KeySym, (3 * keyb->keycount)); + keyb->codes = g_new0_(KeyCode, keyb->keycount); + keyb->name = g_strdup_(filename); /* Save the name of the keyboard */ + + for (x = 0; x < keyb->keycount; x++) { + keyb->codes[x] = 0; /* Initialize that keycode since we're already + * paying the price of the loop and it needs + * to be done. + */ + + if (!get_valid_line(fp, linedata, line_size)) { + fprintf(stderr, + "Error reading file %s: Bad line %d.\n", + filename, (x + 1)); + fflush(stderr); + fflush(stderr); + keyb = gtkeyboard_destroy_keyboard(keyb); + fclose(fp); + return (NO_KEYBOARD); + } + /* End if */ + tokens = tofree = g_strsplit(linedata, " ", -1); + + for (y = 0; y < 3; y++) { + if (*tokens) + ptr = *tokens++; + else + ptr = NULL; + + index = (x * 3) + y; + + if (ptr) { + /* Translate a string into a KeySym */ + keyb->syms[index] = XStringToKeysym(ptr); + + /* Error check that KeySym */ + if (!keyb->syms[index] + || keyb->syms[index] == NoSymbol) { + keyb->syms[index] = NoSymbol; + keyb = + gtkeyboard_destroy_keyboard + (keyb); + return (NO_KEYBOARD); + } /* End if */ + } /* End if */ + else { + /* This kinda sucks */ + keyb->syms[index] = NoSymbol; + } /* End else */ + } /* End for */ + + if (ptr) { + ptr = *tokens++; + } + + /* End if */ + /* Grab the KeyCode if it's there */ + keyb->codes[x] = atoi(ptr ? ptr : "0"); + + if (ptr) { + ptr = *tokens++; + } + /* End if */ + if (ptr && strcmp(ptr, "") != 0) { +#if 0 + fprintf(Q, "Reading proposed mask \"%s\"\n", ptr); + fflush(Q); +#endif + + if (!ModmapTable_insert + (keyb->modmap, keyb->codes[x], + mask_name_to_slot_number(ptr))) { + fprintf(Q, + "*** Warning: Failed to insert %d into %d\n", + keyb->codes[x], + mask_name_to_slot_number(ptr)); + } + /* End if */ +#if 0 + fprintf(Q, "Inserted code %d in slot %d\n", + keyb->codes[x], + mask_name_to_slot_number(ptr)); + fflush(Q); +#endif + } + /* End if */ + g_strfreev(tofree); + } /* End for */ + + fclose(fp); + + return (keyb); +} /* End read_keyboard_template() */ + +static void send_redirect_a_keysym(KeySym input) +{ + Window window; + int revert_to; + + if (!options.other || options.other == (Window) NULL) { + /* SEND_TO_BOTH_WINDOWS was probably set and there wasn't + * a redirect window to send to. Let's save the time involved + * with doing all this string crap and just jump out here. + */ + return; + } + /* End if */ + if (options.other) { + /* send to window user picked */ + keysym_sendkey(input, options.other); + } /* End if */ + else { + /* default to just send the event to whatever window has the input + * focus + */ + XGetInputFocus(GDK_DISPLAY(), &window, &revert_to); + keysym_sendkey(input, window); + } /* End else */ +} /* End send_redirect_a_keysym() */ + +gint track_focus(gpointer data) +{ + Window winFocus; + Window wfcopy; + int revert_to_return; + char *winName; + + + /* find out which window currently has focus */ + XGetInputFocus(GDK_DISPLAY(), &winFocus, &revert_to_return); + wfcopy = winFocus; + + /* Return if the window is the same or if it's the program + * window or if we can't redirect to that window. + * + * If there was a previous window that was any good, stick to + * that one. + */ + if (winFocus == options.redirect_window || + winFocus == GUI.xwindow || + winFocus == None || winFocus == PointerRoot) { + return TRUE; + } + + + + /* End if */ + /* At this point, we know the window is "good" and that we want + * it's name. We're going to use it as the redirect from now on. + */ + /* set up error trapping, in case we get a BadWindow error */ + gdk_error_trap_push(); + + /* this could generate the error */ + XFetchName(GDK_DISPLAY(), winFocus, &winName); + if (!winName) + winName = "Unknown"; + + gdk_flush(); + + if (gdk_error_trap_pop()) { + /* Oops...error. Probably BadWindow */ + CONDFREE(options.redirect_window_name); + + options.redirect_window = None; /* reset focus window */ + options.other = None; + + printf + ("There was an error finding a valid redirect window.\n"); + return TRUE; /* better luck next time */ + } + + /* End if */ + /* since we made it this far, update the window_name */ + if (winName) { + CONDFREE(options.redirect_window_name); + + /* Grab the window definition */ + options.redirect_window = wfcopy; + options.other = wfcopy; + + options.redirect_window_name = g_strdup_(winName); + } /* End if */ + return TRUE; +} /* End track_focus */ diff --git a/gui/gtk/gtkeyboard.h b/gui/gtk/gtkeyboard.h new file mode 100644 index 00000000..fef9fa7a --- /dev/null +++ b/gui/gtk/gtkeyboard.h @@ -0,0 +1,3 @@ +int init_keyboard_stuff(char *input); +GtkWidget *build_keyboard(GtkWidget * input, char *filename); +gint track_focus(gpointer data); diff --git a/gui/gtk/gui_gtk.h b/gui/gtk/gui_gtk.h new file mode 100644 index 00000000..f231c2fd --- /dev/null +++ b/gui/gtk/gui_gtk.h @@ -0,0 +1,4 @@ + +struct statusbar *gui_gtk_statusbar_new(GtkWidget **widget); +struct toolbar *gui_gtk_toolbar_new(struct container *co, GtkWidget **widget); +struct menu *gui_gtk_menu_new(struct container *co, GtkWidget **widget); diff --git a/gui/gtk/gui_gtk_menu.c b/gui/gtk/gui_gtk_menu.c new file mode 100644 index 00000000..8ddebf6c --- /dev/null +++ b/gui/gtk/gui_gtk_menu.c @@ -0,0 +1,430 @@ +#define GTK_ENABLE_BROKEN +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <time.h> +#include <gtk/gtk.h> +#include "coord.h" +#include "graphics.h" +#include "data_window.h" +#include "route.h" +#include "cursor.h" +#include "command.h" +#include "transform.h" +#include "block.h" +#include "street.h" +#include "statusbar.h" +#include "destination.h" +#include "main.h" +#include "container.h" + +struct menu_gui { + struct container *co; +}; + +#include "menu.h" + +extern struct coord current_pos; + +extern struct data_window *navigation_window; + +struct destination { + struct container *co; + char *text; + struct coord pos; +}; + +static void +menu_goto_abensberg(struct container *co) +{ + co->trans->center.x=1317000; + co->trans->center.y=6235000; + co->trans->scale=2*16; + graphics_redraw(co); +} + +static void +menu_goto_regensburg(struct container *co) +{ + co->trans->center.x=(1339653+1341853)/2; + co->trans->center.y=(6272179+6269979)/2; + co->trans->scale=4*16; + graphics_redraw(co); +} + +static void +menu_goto_problem(struct container *co) +{ +#if 0 /* Crailsheim */ + map->center_x=0x112e55; + map->center_y=0x60275a; + map->scale=4*16; + map_redraw(map); + route_click(map->route, map, 697, 31); + route_click(map->route, map, 71, 503); +#endif + +#if 1 /* Abensberg */ + co->trans->center.x=1317000; + co->trans->center.y=6235000; + co->trans->scale=2*16; + graphics_redraw(co); + route_click(co->route, co, 196, 449); +#endif + +#if 1 /* Neckarsulm */ + co->trans->center.x=0xfa3ac; + co->trans->center.y=0x60289a; + co->trans->scale=2*16; + graphics_redraw(co); + route_click(co->route, co, 454, 274); + + co->trans->center.x=0x1251ac; + co->trans->center.y=0x5f5eda; + co->trans->scale=512*16; + graphics_redraw(co); +#endif + + +} + +static void +menu_window_clone(struct container *co) +{ +#if 0 + void window(int x, int y, int scale); + window(co->trans->center.x, co->trans->center.y, co->trans->scale); +#endif +} + +gboolean +menu_window_command_key_press(GtkWidget *widget, GdkEventKey *event, + GtkWidget *win) +{ + GtkWidget *text; + unsigned const char *t; + struct container *co; + + if (! strcmp(event->string,"\r")) { + text=gtk_object_get_data(GTK_OBJECT(win), "Input"); + co=gtk_object_get_data(GTK_OBJECT(win), "Container"); + t=gtk_entry_get_text(GTK_ENTRY(text)); + if (!strncmp(t,"goto ",5)) { + command_goto(co, t+5); + } + } + return TRUE; +} + + +static void +menu_window_command(struct container *co) +{ + GtkWidget *win,*entry,*text,*box; + win=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(win), 320, 200); + gtk_window_set_title(GTK_WINDOW(win), "Command"); + entry=gtk_entry_new(); + text=gtk_text_new(NULL, NULL); + box=gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(box), entry, 1, 1, 0); + gtk_box_pack_start(GTK_BOX(box), text, 1, 1, 0); + gtk_container_add(GTK_CONTAINER(win), box); + gtk_object_set_data(GTK_OBJECT(win), "Container", co); + gtk_object_set_data(GTK_OBJECT(win), "Input", entry); + gtk_object_set_data(GTK_OBJECT(win), "Output", text); + gtk_signal_connect(GTK_OBJECT(win), "key-press-event", GTK_SIGNAL_FUNC(menu_window_command_key_press), win); + gtk_widget_show_all(win); +} + +static void +menu_window_visible_blocks(struct container *co) +{ + co->data_window[data_window_type_block]=data_window("Visible Blocks",co->win,NULL); + graphics_redraw(co); +} + +static void +menu_window_visible_towns(struct container *co) +{ + co->data_window[data_window_type_town]=data_window("Visible Towns",co->win,NULL); + graphics_redraw(co); +} + +static void +menu_window_visible_polys(struct container *co) +{ + co->data_window[data_window_type_street]=data_window("Visible Polys",co->win,NULL); + graphics_redraw(co); +} + +static void +menu_window_visible_streets(struct container *co) +{ + co->data_window[data_window_type_street]=data_window("Visible Streets",co->win,NULL); + graphics_redraw(co); +} + +static void +menu_window_visible_points(struct container *co) +{ + co->data_window[data_window_type_point]=data_window("Visible Points",co->win,NULL); + graphics_redraw(co); +} + +static void +menu_map_compare(struct container *co) +{ + char cmd[256]; + int x_min, x_max, y_min, y_max; + + x_min=co->trans->center.x-co->trans->scale/16*co->trans->width*4/10; + x_max=co->trans->center.x+co->trans->scale/16*co->trans->width*4/10; + y_min=co->trans->center.y-co->trans->scale/16*co->trans->height*4/10; + y_max=co->trans->center.y+co->trans->scale/16*co->trans->height*4/10; + sprintf(cmd, "./get_map %d %d %d %d %d %d ; xv map.xpm &", co->trans->width, co->trans->height, x_min, y_max, x_max, y_min); + system(cmd); +} + +static void +menu_map_distances(struct container *co) +{ + route_display_points(co->route, co); +} + +static void +menu_destination_selected(GtkMenuItem *item, struct destination *dest) +{ + struct container *co =dest->co; + + destination_set(co, destination_type_bookmark, dest->text, &dest->pos); +} + +static void +menu_item(struct menu *me, GtkWidget *menu, char *name, void (*func)(struct container *co)) +{ + GtkWidget *item; + item=gtk_menu_item_new_with_label(name); + gtk_menu_append (GTK_MENU(menu), item); + gtk_signal_connect_object(GTK_OBJECT(item), "activate", + GTK_SIGNAL_FUNC (func), me); +} + +int +menu_clock_update(void *data) +{ + char buffer[16]; + time_t now=time(NULL); + GtkWidget *widget=GTK_WIDGET(data); + struct tm *now_tm=localtime(&now); + + sprintf(buffer,"%02d:%02d", now_tm->tm_hour, now_tm->tm_min); + gtk_label_set_text(GTK_LABEL(widget), buffer); + gtk_timeout_add((60-now_tm->tm_sec)*1000,menu_clock_update,widget); + return FALSE; +} + +struct menu * +gui_gtk_menu_new(struct container *co, GtkWidget **widget) +{ + struct menu *this=g_new0(struct menu, 1); + + this->gui=g_new0(struct menu_gui,1); + this->gui->co=co; + + + GtkWidget *menu,*item,*menu2,*item2,*menu3,*clock; + + menu=gtk_menu_bar_new(); + item=gtk_menu_item_new_with_label("Goto"); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + { + menu2=gtk_menu_new(); + item2=gtk_menu_item_new_with_label("Abensberg"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_goto_abensberg), this); + + item2=gtk_menu_item_new_with_label("Regensburg"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_goto_regensburg), this); + item2=gtk_menu_item_new_with_label("Problem"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_goto_problem), this); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu2); + + item=gtk_menu_item_new_with_label("Window"); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + { + menu2=gtk_menu_new(); + + item2=gtk_menu_item_new_with_label("Clone"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_clone), this); + + item2=gtk_menu_item_new_with_label("Command"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_command), this); + + item2=gtk_menu_item_new_with_label("Visible Blocks"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_visible_blocks), co); + + item2=gtk_menu_item_new_with_label("Visible Towns"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_visible_towns), co); + + item2=gtk_menu_item_new_with_label("Visible Polys"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_visible_polys), co); + + + item2=gtk_menu_item_new_with_label("Visible Streets"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_window_visible_streets), co); + + menu_item(this, menu2, "Visible Points", menu_window_visible_points); + + item2=gtk_menu_item_new_with_label("Exit"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (exit), this); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu2); + + item=gtk_menu_item_new_with_label("Map"); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + { + menu2=gtk_menu_new(); + + item2=gtk_menu_item_new_with_label("Compare"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_map_compare), this); + + item2=gtk_menu_item_new_with_label("Distances"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_map_distances), this); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu2); + + item=gtk_menu_item_new_with_label("Route"); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + { + menu2=gtk_menu_new(); + + item2=gtk_menu_item_new_with_label("Start"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (route_start), co); + + item2=gtk_menu_item_new_with_label("Trace"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (route_trace), co); + + item2=gtk_menu_item_new_with_label("Update"); + gtk_menu_append (GTK_MENU(menu2), item2); + gtk_signal_connect_object(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_route_update), this); + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu2); + + item=gtk_menu_item_new_with_label("Destinations"); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + menu2=gtk_menu_new(); + + item2=gtk_menu_item_new_with_label("Last Destinations"); + gtk_menu_append (GTK_MENU(menu2), item2); + menu3=gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item2), menu3); + + item2=gtk_menu_item_new_with_label("Address"); + gtk_menu_append (GTK_MENU(menu2), item2); + + { + FILE *file; + char buffer[8192]; + double lat,lng,lat_deg,lng_deg; + char lat_c,lng_c; + struct destination *dest; + int pos,len; + char *utf8,*text,*tok,*label; + GList *list; + + file=fopen("locations.txt","r"); + while (fgets(buffer,8192,file)) { + dest=malloc(sizeof(*dest)); + dest->co=co; + len=strlen(buffer)-1; + while (len >= 0 && buffer[len] == '\n') { + buffer[len]='\0'; + } + sscanf(buffer,"%lf %c %lf %c %n",&lat, &lat_c, &lng, &lng_c, &pos); + + lat_deg=floor(lat/100); + lat-=lat_deg*100; + lat_deg+=lat/60; + + lng_deg=floor(lng/100); + lng-=lng_deg*100; + lng_deg+=lng/60; + + transform_mercator(&lng_deg, &lat_deg, &dest->pos); + + text=buffer+pos; + dest->text=strdup(text); + item2=NULL; + menu3=menu2; + while ((tok=strtok(text,"/"))) { + list=NULL; + if (item2) { + menu3=gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item2), menu3); + } + list=gtk_container_get_children(GTK_CONTAINER(menu3)); + while (list) { + item2=GTK_WIDGET(list->data); + gtk_label_get(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item2))),&label); + if (!strcmp(label, tok)) { + menu3=gtk_menu_item_get_submenu(GTK_MENU_ITEM(item2)); + break; + } + list=list->next; + } + item2=NULL; + if (! list) { + utf8=g_locale_to_utf8(tok,-1,NULL,NULL,NULL); + item2=gtk_menu_item_new_with_label(utf8); + gtk_menu_append (GTK_MENU(menu3), item2); + g_free(utf8); + } + text=NULL; + } + gtk_signal_connect(GTK_OBJECT(item2), "activate", + GTK_SIGNAL_FUNC (menu_destination_selected), dest); + } + } + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu2); + + item=gtk_menu_item_new(); + clock=gtk_label_new(NULL); + gtk_menu_item_right_justify(GTK_MENU_ITEM(item)); + gtk_container_add(GTK_CONTAINER(item), clock); + gtk_menu_bar_append(GTK_MENU_BAR(menu), item); + menu_clock_update(clock); + + *widget=menu; + return this; +} diff --git a/gui/gtk/gui_gtk_statusbar.c b/gui/gtk/gui_gtk_statusbar.c new file mode 100644 index 00000000..fa4edfa7 --- /dev/null +++ b/gui/gtk/gui_gtk_statusbar.c @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <math.h> +#include <gtk/gtk.h> +#include "coord.h" +#include "route.h" +#include "transform.h" +#include "gui_gtk.h" + +#include "statusbar.h" + +struct statusbar_gui { + GtkWidget *hbox; + char mouse_text[128]; + GtkWidget *mouse; + char gps_text[128]; + GtkWidget *gps; + char route_text[128]; + GtkWidget *route; +}; + + +void +statusbar_destroy(struct statusbar *this) +{ + g_free(this->gui); + g_free(this); +} + +void +statusbar_mouse_update(struct statusbar *this, struct transformation *tr, struct point *p) +{ + struct coord c; + struct coord_geo g; + char buffer[128]; + + transform_reverse(tr, p, &c); + transform_lng_lat(&c, &g); + transform_geo_text(&g, buffer); + sprintf(this->gui->mouse_text,"M: %s", buffer); + gtk_label_set_text(GTK_LABEL(this->gui->mouse), this->gui->mouse_text); +} + +void +statusbar_gps_update(struct statusbar *this, int sats, int qual, double lng, double lat, double height, double direction, double speed) +{ + char lat_c='N'; + char lng_c='E'; + char *dirs[]={"N","NO","O","SO","S","SW","W","NW","N"}; + char *dir; + char *utf8; + int dir_idx; + + if (lng < 0) { + lng=-lng; + lng_c='W'; + } + if (lat < 0) { + lat=-lat; + lat_c='S'; + } + dir_idx=(direction+22.5)/45; + dir=dirs[dir_idx]; + sprintf(this->gui->gps_text,"GPS %2d/%1d %02.0f%07.4f%c %03.0f%07.4f%c %4.0fm %3.0f°%-2s %3.0fkm/h", sats, qual, floor(lat), fmod(lat*60,60), lat_c, floor(lng), fmod(lng*60,60), lng_c, height, direction, dir, speed); + utf8=g_locale_to_utf8(this->gui->gps_text,-1,NULL,NULL,NULL); + gtk_label_set_text(GTK_LABEL(this->gui->gps), utf8); + g_free(utf8); + +} + +void +statusbar_route_update(struct statusbar *this, struct route *route) +{ + struct tm *eta_tm; + double route_len; + + eta_tm=route_get_eta(route); + route_len=route_get_len(route); + + sprintf(this->gui->route_text,"Route %4.0fkm %02d:%02d ETA",route_len/1000, eta_tm->tm_hour, eta_tm->tm_min); + gtk_label_set_text(GTK_LABEL(this->gui->route), this->gui->route_text); +} + +struct statusbar * +gui_gtk_statusbar_new(GtkWidget **widget) +{ + struct statusbar *this=g_new0(struct statusbar, 1); + char *utf8; + + this->gui=g_new0(struct statusbar_gui,1); + this->statusbar_destroy=statusbar_destroy; + this->statusbar_mouse_update=statusbar_mouse_update; + this->statusbar_route_update=statusbar_route_update; + this->statusbar_gps_update=statusbar_gps_update; + + this->gui->hbox=gtk_hbox_new(FALSE, 1); + this->gui->mouse=gtk_label_new("M: 0000.0000N 00000.0000E"); + gtk_label_set_justify(GTK_LABEL(this->gui->mouse), GTK_JUSTIFY_LEFT); + utf8=g_locale_to_utf8("GPS 00/0 0000.0000N 00000.0000E 0000m 000°NO 000km/h",-1,NULL,NULL,NULL); + this->gui->gps=gtk_label_new(utf8); + g_free(utf8); + gtk_label_set_justify(GTK_LABEL(this->gui->gps), GTK_JUSTIFY_LEFT); + this->gui->route=gtk_label_new("Route 0000km 0+00:00 ETA"); + gtk_label_set_justify(GTK_LABEL(this->gui->route), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(this->gui->hbox), this->gui->mouse, FALSE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(this->gui->hbox), gtk_vseparator_new(), TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(this->gui->hbox), this->gui->gps, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(this->gui->hbox), gtk_vseparator_new(), TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(this->gui->hbox), this->gui->route, TRUE, TRUE, 2); + + *widget=this->gui->hbox; + return this; +} + diff --git a/gui/gtk/gui_gtk_toolbar.c b/gui/gtk/gui_gtk_toolbar.c new file mode 100644 index 00000000..420c93ba --- /dev/null +++ b/gui/gtk/gui_gtk_toolbar.c @@ -0,0 +1,349 @@ +#include <gtk/gtk.h> +#include "graphics.h" +#include "gui_gtk.h" +#include "menu.h" +#include "coord.h" +#include "destination.h" +#include "container.h" + +struct toolbar_gui { + struct container *co; +}; + +#include "toolbar.h" + +static void +zoom_in(GtkWidget *w, struct toolbar *tb) +{ + unsigned long scale; + graphics_get_view(tb->gui->co, NULL, NULL, &scale); + scale/=2; + if (scale < 1) + scale=1; + graphics_set_view(tb->gui->co, NULL, NULL, &scale); +} + +static void +zoom_out(GtkWidget *w, struct toolbar *tb) +{ + unsigned long scale; + graphics_get_view(tb->gui->co, NULL, NULL, &scale); + scale*=2; + graphics_set_view(tb->gui->co, NULL, NULL, &scale); +} + +static void +refresh_route(GtkWidget *w, struct toolbar *tb) +{ + menu_route_update(tb->gui->co); +} + +static void +track(GtkWidget *w, struct toolbar *tb) +{ + if (tb->gui->co->flags->track) { + tb->gui->co->flags->track=0; + gtk_widget_set_state(w, GTK_STATE_ACTIVE); + } else { + tb->gui->co->flags->track=1; + gtk_widget_set_state(w, GTK_STATE_ACTIVE); + } +} + +static void +orient_north(GtkWidget *w, struct toolbar *tb) +{ + if (tb->gui->co->flags->orient_north) { + tb->gui->co->flags->orient_north=0; + gtk_widget_set_state(w, GTK_STATE_ACTIVE); + } else { + tb->gui->co->flags->orient_north=1; + gtk_widget_set_state(w, GTK_STATE_ACTIVE); + } +} + +static void +destination(GtkWidget *w, struct toolbar *tb) +{ + destination_address(tb->gui->co); +} + + +/* XPM */ +/* Drawn by Mark Donohoe for the K Desktop Environment */ +/* See http://www.kde.org */ +static char*viewmag_plus_xpm[]={ +"22 22 5 1", +"# c #000000", +"c c #a0a0a4", +"a c #dcdcdc", +"b c #ffffff", +". c None", +"......................", +"......................", +"......................", +"......................", +"......................", +".......####...........", +"......#abba#..........", +".....#abcbba#.........", +".....#bcbbbb#.........", +".....#bbbbbb#.........", +".....#abbbba#.........", +"......#abba##.........", +".......#######........", +"............###.......", +".....#.......###......", +".....#........###.....", +"...#####.......##.....", +".....#................", +".....#................", +"......................", +"......................", +"......................"}; + + +/* XPM */ +/* Drawn by Mark Donohoe for the K Desktop Environment */ +/* See http://www.kde.org */ +static char*viewmag_minus_xpm[]={ +"22 22 5 1", +"# c #000000", +"c c #a0a0a4", +"a c #dcdcdc", +"b c #ffffff", +". c None", +"......................", +"......................", +"......................", +"......................", +"......................", +".......####...........", +"......#abba#..........", +".....#abcbba#.........", +".....#bcbbbb#.........", +".....#bbbbbb#.........", +".....#abbbba#.........", +"......#abba##.........", +".......#######........", +"............###.......", +".............###......", +"..............###.....", +"...#####.......##.....", +"......................", +"......................", +"......................", +"......................", +"......................"}; + + +/* XPM */ +/* Drawn by Mark Donohoe for the K Desktop Environment */ +/* See http://www.kde.org */ +static char*reload_xpm[]={ +"22 22 3 1", +"# c #808080", +"a c #000000", +". c None", +"......................", +"......................", +"......................", +"......................", +"........##aaa#........", +".......#aaaaaaa.......", +"......#aa#....#a......", +"......aa#.............", +".....aaa.......a......", +"...aaaaaaa....aaa.....", +"....aaaaa....aaaaa....", +".....aaa....aaaaaaa...", +"......a.......aaa.....", +".............#aa......", +"......a#....#aa#......", +".......aaaaaaa#.......", +"........#aaa##........", +"......................", +"......................", +"......................", +"......................", +"......................"}; + + +/* XPM */ +static char * cursor_xpm[] = { +"22 22 2 1", +" c None", +". c #0000FF", +" ", +" ", +" ", +" .. ", +" .. .. ", +" .. .. ", +" . . ", +" . . ", +" . ... . ", +" . ... . . ", +" . ... . . ", +" . .. . . ", +" . . . ", +" . . . ", +" . . . ", +" . . . ", +" .. .. ", +" .. .. ", +" .. ", +" ", +" ", +" "}; + + +/* XPM */ +static char * north_xpm[] = { +"22 22 2 1", +" c None", +". c #000000", +" ", +" ", +" . ", +" ... ", +" . . . ", +" . . . ", +" . ", +" .... . .... ", +" .... . .... ", +" .... . .. ", +" .. .. .. ", +" .. .. .. ", +" .. .. .. ", +" .. .. .. ", +" .. . .... ", +" .... . .... ", +" .... . .... ", +" . ", +" . ", +" . ", +" ", +" "}; + + +/* XPM */ +static char * flag_xpm[] = { +"22 22 2 1", +" c None", +"+ c #000000", +"+++++++ ", +"+ +++++++++ ", +"+ +++ +++++++++ ", +"+ +++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ + ", +"+ ++++++ +++ + ", +"+ +++ ++++++ + ", +"+ +++ +++ +++ ", +"++++ +++ +++ ", +"++++ +++ +++ ", +"++++++++++ +++ + ", +"+ +++++++++ + ", +"+ ++++++ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ "}; + +static GtkWidget * +xpm_to_widget(GtkWidget *draw, gchar **xpm_data) +{ + /* GtkWidget is the storage type for widgets */ + GtkWidget *pixmapwid; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + + style = gtk_widget_get_style(draw); + + /* In order for this to not create a warning, window has to be a + * gtk_realize_widget (realized) widget + */ + pixmap = gdk_pixmap_create_from_xpm_d(draw->window, &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **)xpm_data ); + + /* a pixmap widget to contain the pixmap */ + pixmapwid = gtk_pixmap_new(pixmap, mask); + gtk_widget_show(pixmapwid); + + return(pixmapwid); +} + +static void +toolbar_button_leave (GtkButton *button, gpointer status) +{ + int *st=status,new_state=GTK_STATE_NORMAL; + g_return_if_fail (button != NULL); + g_return_if_fail (GTK_IS_BUTTON (button)); + + if (*st) + new_state=GTK_STATE_ACTIVE; + if (GTK_WIDGET_STATE (button) != new_state) + { + gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_widget_queue_draw (GTK_WIDGET (button)); + } +} + +int tst_stat=1; + +void +toolbar_button(GtkWidget *window, GtkWidget *toolbar, char **icon_data, char *text, void (*func)(GtkWidget *w, struct toolbar *tb), void *data) +{ + GtkWidget *icon; + icon=xpm_to_widget(window, icon_data); + gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL, text, NULL, icon, GTK_SIGNAL_FUNC(func), data); +} + +void +toolbar_button_toggle(GtkWidget *window, GtkWidget *toolbar, char **icon_data, char *text, void (*func)(GtkWidget *w, struct toolbar *tb), void *data, int *flag) +{ + GtkWidget *icon,*item; + icon=xpm_to_widget(window, icon_data); + item=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar), NULL, text, NULL, icon, GTK_SIGNAL_FUNC(func), data); + if (*flag) + gtk_widget_set_state(item, GTK_STATE_ACTIVE); + gtk_signal_connect(GTK_OBJECT(item), "leave", GTK_SIGNAL_FUNC(toolbar_button_leave), flag); +} + + +struct toolbar * +gui_gtk_toolbar_new(struct container *co, GtkWidget **widget) +{ + GtkWidget *toolbar,*window; + struct toolbar *this=g_new0(struct toolbar, 1); + + this->gui=g_new0(struct toolbar_gui, 1); + this->gui->co=co; + + toolbar=gtk_toolbar_new(); + gtk_toolbar_prepend_space(GTK_TOOLBAR(toolbar)); + gtk_toolbar_prepend_space(GTK_TOOLBAR(toolbar)); + + window=(GtkWidget *)(co->win); + + co->flags->track=1; + co->flags->orient_north=1; + + toolbar_button(window, toolbar, viewmag_plus_xpm, "Zoom In", zoom_in, this); + toolbar_button(window, toolbar, viewmag_minus_xpm, "Zoom Out", zoom_out, this); + toolbar_button(window, toolbar, reload_xpm, "Refresh Route", refresh_route, this); + toolbar_button_toggle(window, toolbar, cursor_xpm, "Cursor on/off", track, this, &co->flags->track); + toolbar_button_toggle(window, toolbar, north_xpm, "Orientate North on/off", orient_north, this, &co->flags->orient_north); + toolbar_button(window, toolbar, flag_xpm, "Destination", destination, this); + + *widget=toolbar; + + return this; +} diff --git a/gui/gtk/gui_gtk_window.c b/gui/gtk/gui_gtk_window.c new file mode 100644 index 00000000..40ddddb1 --- /dev/null +++ b/gui/gtk/gui_gtk_window.c @@ -0,0 +1,67 @@ +#include <stdio.h> +#include <gtk/gtk.h> +#include "coord.h" +#include "transform.h" +#include "container.h" +#include "gui_gtk.h" + + +extern void container_init_gra(struct container *co); + +struct container * +container_new(GtkWidget **widget) +{ + struct container *co=g_new0(struct container, 1); + extern struct map_data *map_data_default; + struct transformation *t=g_new0(struct transformation, 1); + struct map_flags *flags=g_new0(struct map_flags, 1); + struct graphics *gra; + + co->map_data=map_data_default; +#if 1 + extern struct graphics *graphics_gtk_drawing_area_new(struct container *co, GtkWidget **widget); + gra=graphics_gtk_drawing_area_new(co, widget); +#else + extern struct graphics *graphics_gtk_gl_area_new(struct container *co, GtkWidget **widget); + gra=graphics_gtk_gl_area_new(co, widget); +#endif + co->gra=gra; + co->trans=t; + co->flags=flags; + + return co; +} + +struct container * +gui_gtk_window(int x, int y, int scale) +{ + GtkWidget *window,*map_widget; + GtkWidget *vbox; + GtkWidget *statusbar,*toolbar,*menu; + struct container *co; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(window), 792, 547); + gtk_window_set_title(GTK_WINDOW(window), "Map"); + gtk_widget_realize(window); + vbox = gtk_vbox_new(FALSE, 0); + co=container_new(&map_widget); + + transform_setup(co->trans, x, y, scale, 0); + + co->win=(struct window *) window; + co->statusbar=gui_gtk_statusbar_new(&statusbar); + co->toolbar=gui_gtk_toolbar_new(co, &toolbar); + co->menu=gui_gtk_menu_new(co, &menu); + gtk_box_pack_start(GTK_BOX(vbox), menu, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); + gtk_box_pack_end(GTK_BOX(vbox), map_widget, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + + gtk_widget_show_all(window); + container_init_gra(co); + return co; +} + + diff --git a/locations.txt b/locations.txt new file mode 100644 index 00000000..739f93b2 --- /dev/null +++ b/locations.txt @@ -0,0 +1 @@ +5231.3734 N 01324.8633 E Berlin Alexanderplatz @@ -0,0 +1,88 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "file.h" +#include "map_data.h" +#include "log.h" + +void +log_write(char *message, struct file *file, void *data, int size) +{ + char log[4096]; + unsigned char *l,*p=data; + + int fd=open("log.txt",O_RDWR|O_CREAT|O_APPEND|O_SYNC, 0644); + sprintf(log,"# %s\n",message); + l=log+strlen(log); + sprintf(l, "%s 0x%x ", file->name, p-file->begin); + l=log+strlen(log); + while (size) { + sprintf(l,"%02x ", *p++); + l+=3; + size--; + } + *l++='\n'; + *l='\0'; + write(fd, log, strlen(log)); + close(fd); +} + +void +log_apply(struct map_data *map, int files) +{ + char buffer[4096],*p; + char *filename, *addr; + struct file *file; + unsigned char *data; + unsigned long dataval; + struct map_data *curr; + int j; + + FILE *f=fopen("log.txt","r"); + if (!f) + return; + while (fgets(buffer, 4096, f)) { + if (buffer[0] != '#') { + buffer[strlen(buffer)-1]='\0'; + filename=buffer; + p=buffer; + while (*p && *p != ' ') + p++; + if (! *p) + continue; + *p++=0; + file=NULL; + curr=map; + while (curr) { + for(j = 0 ; j < files ; j++) { + if (curr->file[j] && !strcmp(curr->file[j]->name, filename)) { + file=curr->file[j]; + break; + } + } + if (file) + break; + curr=curr->next; + } + if (file) { + addr=p; + while (*p && *p != ' ') + p++; + if (! *p) + continue; + *p++=0; + data=file->begin+strtoul(addr, NULL, 16); + while (*p) { + dataval=strtoul(p, NULL, 16); + *data++=dataval; + p+=2; + while (*p == ' ') + p++; + } + } + } + } + fclose(f); +} @@ -0,0 +1,2 @@ +void log_write(char *message, struct file *file, void *data, int size); +void log_apply(struct map_data *map, int files); @@ -0,0 +1,80 @@ +#include <locale.h> +#include <stdio.h> +#include "coord.h" +#include "vehicle.h" +#include "cursor.h" +#include "speech.h" +#include "route.h" +#include "map.h" +#include "map_data.h" +#if 0 +#include "map-share.h" +#endif +#include "transform.h" +#include "popup.h" +#include "plugin.h" +#include "compass.h" +#include "container.h" + + +void *speech_handle; + +struct container *co; + +struct map_data *map_data_default; + +struct container *gui_gtk_window(int x, int y, int scale); + +extern void test(struct map_data *mdat); + +int main(int argc, char **argv) +{ + CORBA_Environment ev; + CORBA_ORB orb; + Map map_client = CORBA_OBJECT_NIL; + char *retval; + FILE *ior; + + setenv("LC_NUMERIC","C",1); + setlocale(LC_ALL,""); + setlocale(LC_NUMERIC,"C"); + gtk_set_locale(); + setlocale(LC_NUMERIC,"C"); + gtk_init(&argc, &argv); + gdk_rgb_init(); + + map_data_default=load_maps(NULL); + plugin_load(); + co=gui_gtk_window(1300000,7000000,8192); + co->vehicle=vehicle_new("/tmp/gpsdata"); + co->cursor=cursor_new(co); + co->speech=speech_new(); + speech_handle=co->speech; + co->route=route_new(); + co->compass=compass_new(co); + route_mapdata_set(co->route, co->map_data); + + +#if 0 + CORBA_exception_init(&ev); + orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); + g_assert(ev._major == CORBA_NO_EXCEPTION); + + map_srv_start_poa(orb, &ev); + g_assert(ev._major == CORBA_NO_EXCEPTION); + map_client = map_srv_start_object(&ev, map); + retval = CORBA_ORB_object_to_string(orb, map_client, &ev); + g_assert(ev._major == CORBA_NO_EXCEPTION); + ior=fopen("map.ior","w"); + if (ior) { + fprintf(ior, "%s\n", retval); + fclose(ior); + } + CORBA_free(retval); +#endif + + gtk_main(); + return 0; +} + + @@ -0,0 +1 @@ +extern void *speech_handle; diff --git a/map-common.c b/map-common.c new file mode 100644 index 00000000..91d27199 --- /dev/null +++ b/map-common.c @@ -0,0 +1,442 @@ +/* + * This file was generated by orbit-idl-2 - DO NOT EDIT! + */ + +#include <string.h> +#define ORBIT2_STUBS_API +#define ORBIT_IDL_C_COMMON +#define map_COMMON +#include "map.h" + +static const CORBA_unsigned_long ORBit_zero_int = 0; + +#ifndef ORBIT_IDL_C_IMODULE_map +void +_ORBIT_skel_small_Mappel_Test(POA_Mappel * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_Test) (PortableServer_Servant + _servant, + CORBA_Environment * ev)) +{ + _impl_Test(_o_servant, _o_ev); +} + +void +_ORBIT_skel_small_Map_mapString(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + Map(*_impl_mapString) (PortableServer_Servant + _servant, + const CORBA_char * + astring, + CORBA_double * anum, + CORBA_Environment * + ev)) +{ + *(Map *) _o_retval = + _impl_mapString(_o_servant, *(const CORBA_char * *) _o_args[0], + *(CORBA_double * *)_o_args[1], _o_ev); +} + +void +_ORBIT_skel_small_Map_doNothing(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_doNothing) + (PortableServer_Servant _servant, + CORBA_Environment * ev)) +{ + _impl_doNothing(_o_servant, _o_ev); +} + +void +_ORBIT_skel_small_Map_doOneWay(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_doOneWay) (PortableServer_Servant + _servant, + const CORBA_char * + ignore, + CORBA_Environment * + ev)) +{ + _impl_doOneWay(_o_servant, *(const CORBA_char * *) _o_args[0], _o_ev); +} + +void +_ORBIT_skel_small_Map_PlaceFlag(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_PlaceFlag) + (PortableServer_Servant _servant, + CORBA_Environment * ev)) +{ + _impl_PlaceFlag(_o_servant, _o_ev); +} + +void +_ORBIT_skel_small_Map_PointFromCoord(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + PointObj(*_impl_PointFromCoord) + (PortableServer_Servant _servant, + const CORBA_char * coord, + CORBA_Environment * ev)) +{ + *(PointObj *) _o_retval = + _impl_PointFromCoord(_o_servant, *(const CORBA_char * *) _o_args[0], + _o_ev); +} + +void +_ORBIT_skel_small_Map_View(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_View) (PortableServer_Servant + _servant, + const PointObj * where, + CORBA_Environment * ev)) +{ + _impl_View(_o_servant, (const PointObj *) _o_args[0], _o_ev); +} + +void +_ORBIT_skel_small_Map_ViewAll(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_ViewAll) (PortableServer_Servant + _servant, + const PointObjSequence * + where, + CORBA_Environment * ev)) +{ + _impl_ViewAll(_o_servant, (const CORBA_sequence_PointObj *) _o_args[0], + _o_ev); +} + +void +_ORBIT_skel_small_Map_Route(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + void (*_impl_Route) (PortableServer_Servant + _servant, + const PointObj * src, + const PointObj * dst, + CORBA_Environment * ev)) +{ + _impl_Route(_o_servant, (const PointObj *) _o_args[0], + (const PointObj *) _o_args[1], _o_ev); +} + +void +_ORBIT_skel_small_Map_Get(POA_Map * _o_servant, gpointer _o_retval, + gpointer * _o_args, CORBA_Context _o_ctx, + CORBA_Environment * _o_ev, + Mappel(*_impl_Get) (PortableServer_Servant _servant, + CORBA_Environment * ev)) +{ + *(Mappel *) _o_retval = _impl_Get(_o_servant, _o_ev); +} + +#endif +#if ( (TC_IMPL_TC_PointObj_0 == 'm') \ +&& (TC_IMPL_TC_PointObj_1 == 'a') \ +&& (TC_IMPL_TC_PointObj_2 == 'p') \ +) && !defined(TC_DEF_TC_PointObj) +#define TC_DEF_TC_PointObj 1 +static const char *anon_subnames_array0[] = { "lng", "lat", "height" }; +static const CORBA_TypeCode anon_subtypes_array1[] = + { (CORBA_TypeCode) & TC_CORBA_float_struct, +(CORBA_TypeCode) & TC_CORBA_float_struct, (CORBA_TypeCode) & TC_CORBA_float_struct }; +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_PointObj_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_struct, + 0, + 0, + ORBIT_ALIGNOF_CORBA_FLOAT, + 0, + 3, + (CORBA_TypeCode *) anon_subtypes_array1, + CORBA_OBJECT_NIL, + "PointObj", + "IDL:PointObj:1.0", + (char **) anon_subnames_array0, + NULL, + -1, + 0, + 0, 0 +}; +#endif +#if ( (TC_IMPL_TC_CORBA_sequence_PointObj_0 == 'm') \ +&& (TC_IMPL_TC_CORBA_sequence_PointObj_1 == 'a') \ +&& (TC_IMPL_TC_CORBA_sequence_PointObj_2 == 'p') \ +) && !defined(TC_DEF_TC_CORBA_sequence_PointObj) +#define TC_DEF_TC_CORBA_sequence_PointObj 1 +static const CORBA_TypeCode anon_subtypes_array4[] = + { (CORBA_TypeCode) & TC_PointObj_struct }; +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_CORBA_sequence_PointObj_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_sequence, + 0, + 0, + MAX(ORBIT_ALIGNOF_CORBA_POINTER, + MAX(ORBIT_ALIGNOF_CORBA_LONG, MAX(ORBIT_ALIGNOF_CORBA_STRUCT, 1))), + 0, + 1, + (CORBA_TypeCode *) anon_subtypes_array4, + CORBA_OBJECT_NIL, + NULL, + NULL, + NULL, + NULL, + -1, + 0, + 0, 0 +}; +#endif +#if ( (TC_IMPL_TC_CORBA_sequence_PointObj_0 == 'm') \ +&& (TC_IMPL_TC_CORBA_sequence_PointObj_1 == 'a') \ +&& (TC_IMPL_TC_CORBA_sequence_PointObj_2 == 'p') \ +) && !defined(TC_DEF_TC_CORBA_sequence_PointObj) +#define TC_DEF_TC_CORBA_sequence_PointObj 1 +static const CORBA_TypeCode anon_subtypes_array11[] = + { (CORBA_TypeCode) & TC_PointObj_struct }; +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_CORBA_sequence_PointObj_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_sequence, + 0, + 0, + MAX(ORBIT_ALIGNOF_CORBA_POINTER, + MAX(ORBIT_ALIGNOF_CORBA_LONG, MAX(ORBIT_ALIGNOF_CORBA_STRUCT, 1))), + 0, + 1, + (CORBA_TypeCode *) anon_subtypes_array11, + CORBA_OBJECT_NIL, + NULL, + NULL, + NULL, + NULL, + -1, + 0, + 0, 0 +}; +#endif +#if ( (TC_IMPL_TC_PointObjSequence_0 == 'm') \ +&& (TC_IMPL_TC_PointObjSequence_1 == 'a') \ +&& (TC_IMPL_TC_PointObjSequence_2 == 'p') \ +) && !defined(TC_DEF_TC_PointObjSequence) +#define TC_DEF_TC_PointObjSequence 1 +static const CORBA_TypeCode anon_subtypes_array14[] = + { (CORBA_TypeCode) & TC_CORBA_sequence_PointObj_struct }; +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_PointObjSequence_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_alias, + 0, + 0, + MAX(ORBIT_ALIGNOF_CORBA_POINTER, + MAX(ORBIT_ALIGNOF_CORBA_LONG, MAX(ORBIT_ALIGNOF_CORBA_STRUCT, 1))), + 0, + 1, + (CORBA_TypeCode *) anon_subtypes_array14, + CORBA_OBJECT_NIL, + "PointObjSequence", + "IDL:PointObjSequence:1.0", + NULL, + NULL, + -1, + 0, + 0, 0 +}; +#endif +#if ( (TC_IMPL_TC_Mappel_0 == 'm') \ +&& (TC_IMPL_TC_Mappel_1 == 'a') \ +&& (TC_IMPL_TC_Mappel_2 == 'p') \ +) && !defined(TC_DEF_TC_Mappel) +#define TC_DEF_TC_Mappel 1 +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_Mappel_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_objref, + 0, + 0, + ORBIT_ALIGNOF_CORBA_POINTER, + 0, + 0, + NULL, + CORBA_OBJECT_NIL, + "Mappel", + "IDL:Mappel:1.0", + NULL, + NULL, + -1, + 0, + 0, 0 +}; +#endif +#if ( (TC_IMPL_TC_Map_0 == 'm') \ +&& (TC_IMPL_TC_Map_1 == 'a') \ +&& (TC_IMPL_TC_Map_2 == 'p') \ +) && !defined(TC_DEF_TC_Map) +#define TC_DEF_TC_Map 1 +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +const struct CORBA_TypeCode_struct TC_Map_struct = { + {&ORBit_TypeCode_epv, ORBIT_REFCOUNT_STATIC}, + CORBA_tk_objref, + 0, + 0, + ORBIT_ALIGNOF_CORBA_POINTER, + 0, + 0, + NULL, + CORBA_OBJECT_NIL, + "Map", + "IDL:Map:1.0", + NULL, + NULL, + -1, + 0, + 0, 0 +}; +#endif + +#ifndef ORBIT_IDL_C_IMODULE_map +CORBA_unsigned_long Mappel__classid = 0; +#endif + +#ifndef ORBIT_IDL_C_IMODULE_map +CORBA_unsigned_long Map__classid = 0; +#endif + +/* Interface type data */ + +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +ORBit_IMethod Mappel__imethods[] = { + { + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "Test", 4, + 0} +}; +static CORBA_string Mappel__base_itypes[] = { + "IDL:omg.org/CORBA/Object:1.0" +}; + +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +ORBit_IInterface Mappel__iinterface = { + TC_Mappel, {1, 1, Mappel__imethods, FALSE}, + {1, 1, Mappel__base_itypes, FALSE} +}; + +static ORBit_IArg Map_mapString__arginfo[] = { + {TC_CORBA_string, ORBit_I_ARG_IN, "astring"}, + {TC_CORBA_double, ORBit_I_ARG_OUT | ORBit_I_COMMON_FIXED_SIZE, "anum"} +}; +static ORBit_IArg Map_doOneWay__arginfo[] = { + {TC_CORBA_string, ORBit_I_ARG_IN, "ignore"} +}; +static ORBit_IArg Map_PointFromCoord__arginfo[] = { + {TC_CORBA_string, ORBit_I_ARG_IN, "coord"} +}; +static ORBit_IArg Map_View__arginfo[] = { + {TC_PointObj, ORBit_I_ARG_IN | ORBit_I_COMMON_FIXED_SIZE, "where"} +}; +static ORBit_IArg Map_ViewAll__arginfo[] = { + {TC_PointObjSequence, ORBit_I_ARG_IN, "where"} +}; +static ORBit_IArg Map_Route__arginfo[] = { + {TC_PointObj, ORBit_I_ARG_IN | ORBit_I_COMMON_FIXED_SIZE, "src"}, + {TC_PointObj, ORBit_I_ARG_IN | ORBit_I_COMMON_FIXED_SIZE, "dst"} +}; + +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +ORBit_IMethod Map__imethods[] = { + { + {2, 2, Map_mapString__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_Map, "mapString", 9, + 0} + , { + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "doNothing", 9, + 0} + , { + {1, 1, Map_doOneWay__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "doOneWay", 8, + 0 | ORBit_I_METHOD_1_WAY} + , { + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "PlaceFlag", 9, + 0} + , { + {1, 1, Map_PointFromCoord__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_PointObj, "PointFromCoord", 14, + 0 | ORBit_I_COMMON_FIXED_SIZE} + , { + {1, 1, Map_View__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "View", 4, + 0} + , { + {1, 1, Map_ViewAll__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "ViewAll", 7, + 0} + , { + {2, 2, Map_Route__arginfo, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_void, "Route", 5, + 0} + , { + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + {0, 0, NULL, FALSE}, + TC_Mappel, "Get", 3, + 0} +}; +static CORBA_string Map__base_itypes[] = { + "IDL:omg.org/CORBA/Object:1.0" +}; + +#ifdef ORBIT_IDL_C_IMODULE_map +static +#endif +ORBit_IInterface Map__iinterface = { + TC_Map, {9, 9, Map__imethods, FALSE}, + {1, 1, Map__base_itypes, FALSE} +}; diff --git a/map-share.h b/map-share.h new file mode 100644 index 00000000..c540f30e --- /dev/null +++ b/map-share.h @@ -0,0 +1,2 @@ +void map_srv_start_poa(CORBA_ORB orb, CORBA_Environment * ev); +CORBA_Object map_srv_start_object(CORBA_Environment * ev, struct container *co); diff --git a/map-skelimpl.c b/map-skelimpl.c new file mode 100644 index 00000000..890df21c --- /dev/null +++ b/map-skelimpl.c @@ -0,0 +1,286 @@ +/* This is a template file generated by command */ +/* orbit-idl-2 --skeleton-impl map.idl */ +/* User must edit this file, inserting servant */ +/* specific code between markers. */ + +#include "map.h" + +/*** App-specific servant structures ***/ + +typedef struct +{ + POA_Mappel servant; + PortableServer_POA poa; + + /* ------ add private attributes here ------ */ + /* ------ ---------- end ------------ ------ */ +} impl_POA_Mappel; + +typedef struct +{ + POA_Map servant; + PortableServer_POA poa; + + /* ------ add private attributes here ------ */ + /* ------ ---------- end ------------ ------ */ +} impl_POA_Map; + +/*** Implementation stub prototypes ***/ + +static void impl_Mappel__destroy(impl_POA_Mappel * servant, + CORBA_Environment * ev); +static void +impl_Mappel_Test(impl_POA_Mappel * servant, CORBA_Environment * ev); + +static void impl_Map__destroy(impl_POA_Map * servant, CORBA_Environment * ev); +static Map +impl_Map_mapString(impl_POA_Map * servant, + const CORBA_char * astring, + CORBA_double * anum, CORBA_Environment * ev); + +static void +impl_Map_doNothing(impl_POA_Map * servant, CORBA_Environment * ev); + +static void +impl_Map_doOneWay(impl_POA_Map * servant, + const CORBA_char * ignore, CORBA_Environment * ev); + +static void +impl_Map_PlaceFlag(impl_POA_Map * servant, CORBA_Environment * ev); + +static PointObj +impl_Map_PointFromCoord(impl_POA_Map * servant, + const CORBA_char * coord, CORBA_Environment * ev); + +static void +impl_Map_View(impl_POA_Map * servant, + const PointObj * where, CORBA_Environment * ev); + +static void +impl_Map_ViewAll(impl_POA_Map * servant, + const PointObjSequence * where, CORBA_Environment * ev); + +static void +impl_Map_Route(impl_POA_Map * servant, + const PointObj * src, + const PointObj * dst, CORBA_Environment * ev); + +static Mappel impl_Map_Get(impl_POA_Map * servant, CORBA_Environment * ev); + +/*** epv structures ***/ + +static PortableServer_ServantBase__epv impl_Mappel_base_epv = { + NULL, /* _private data */ + (gpointer) & impl_Mappel__destroy, /* finalize routine */ + NULL, /* default_POA routine */ +}; +static POA_Mappel__epv impl_Mappel_epv = { + NULL, /* _private */ + (gpointer) & impl_Mappel_Test, + +}; +static PortableServer_ServantBase__epv impl_Map_base_epv = { + NULL, /* _private data */ + (gpointer) & impl_Map__destroy, /* finalize routine */ + NULL, /* default_POA routine */ +}; +static POA_Map__epv impl_Map_epv = { + NULL, /* _private */ + (gpointer) & impl_Map_mapString, + + (gpointer) & impl_Map_doNothing, + + (gpointer) & impl_Map_doOneWay, + + (gpointer) & impl_Map_PlaceFlag, + + (gpointer) & impl_Map_PointFromCoord, + + (gpointer) & impl_Map_View, + + (gpointer) & impl_Map_ViewAll, + + (gpointer) & impl_Map_Route, + + (gpointer) & impl_Map_Get, + +}; + +/*** vepv structures ***/ + +static POA_Mappel__vepv impl_Mappel_vepv = { + &impl_Mappel_base_epv, + &impl_Mappel_epv, +}; +static POA_Map__vepv impl_Map_vepv = { + &impl_Map_base_epv, + &impl_Map_epv, +}; + +/*** Stub implementations ***/ + +static Mappel +impl_Mappel__create(PortableServer_POA poa, CORBA_Environment * ev) +{ + Mappel retval; + impl_POA_Mappel *newservant; + PortableServer_ObjectId *objid; + + newservant = g_new0(impl_POA_Mappel, 1); + newservant->servant.vepv = &impl_Mappel_vepv; + newservant->poa = + (PortableServer_POA) CORBA_Object_duplicate((CORBA_Object) poa, ev); + POA_Mappel__init((PortableServer_Servant) newservant, ev); + /* Before servant is going to be activated all + * private attributes must be initialized. */ + + /* ------ init private attributes here ------ */ + /* ------ ---------- end ------------- ------ */ + + objid = PortableServer_POA_activate_object(poa, newservant, ev); + CORBA_free(objid); + retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); + + return retval; +} + +static void +impl_Mappel__destroy(impl_POA_Mappel * servant, CORBA_Environment * ev) +{ + CORBA_Object_release((CORBA_Object) servant->poa, ev); + + /* No further remote method calls are delegated to + * servant and you may free your private attributes. */ + /* ------ free private attributes here ------ */ + /* ------ ---------- end ------------- ------ */ + + POA_Mappel__fini((PortableServer_Servant) servant, ev); +} + +static void +impl_Mappel_Test(impl_POA_Mappel * servant, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static Map +impl_Map__create(PortableServer_POA poa, CORBA_Environment * ev) +{ + Map retval; + impl_POA_Map *newservant; + PortableServer_ObjectId *objid; + + newservant = g_new0(impl_POA_Map, 1); + newservant->servant.vepv = &impl_Map_vepv; + newservant->poa = + (PortableServer_POA) CORBA_Object_duplicate((CORBA_Object) poa, ev); + POA_Map__init((PortableServer_Servant) newservant, ev); + /* Before servant is going to be activated all + * private attributes must be initialized. */ + + /* ------ init private attributes here ------ */ + /* ------ ---------- end ------------- ------ */ + + objid = PortableServer_POA_activate_object(poa, newservant, ev); + CORBA_free(objid); + retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); + + return retval; +} + +static void +impl_Map__destroy(impl_POA_Map * servant, CORBA_Environment * ev) +{ + CORBA_Object_release((CORBA_Object) servant->poa, ev); + + /* No further remote method calls are delegated to + * servant and you may free your private attributes. */ + /* ------ free private attributes here ------ */ + /* ------ ---------- end ------------- ------ */ + + POA_Map__fini((PortableServer_Servant) servant, ev); +} + +static Map +impl_Map_mapString(impl_POA_Map * servant, + const CORBA_char * astring, + CORBA_double * anum, CORBA_Environment * ev) +{ + Map retval; + + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ + + return retval; +} + +static void +impl_Map_doNothing(impl_POA_Map * servant, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static void +impl_Map_doOneWay(impl_POA_Map * servant, + const CORBA_char * ignore, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static void +impl_Map_PlaceFlag(impl_POA_Map * servant, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static PointObj +impl_Map_PointFromCoord(impl_POA_Map * servant, + const CORBA_char * coord, CORBA_Environment * ev) +{ + PointObj retval; + + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ + + return retval; +} + +static void +impl_Map_View(impl_POA_Map * servant, + const PointObj * where, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static void +impl_Map_ViewAll(impl_POA_Map * servant, + const PointObjSequence * where, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static void +impl_Map_Route(impl_POA_Map * servant, + const PointObj * src, + const PointObj * dst, CORBA_Environment * ev) +{ + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ +} + +static Mappel +impl_Map_Get(impl_POA_Map * servant, CORBA_Environment * ev) +{ + Mappel retval; + + /* ------ insert method code here ------ */ + /* ------ ---------- end ------------ ------ */ + + return retval; +} diff --git a/map-skels.c b/map-skels.c new file mode 100644 index 00000000..bcc99254 --- /dev/null +++ b/map-skels.c @@ -0,0 +1,184 @@ +/* + * This file was generated by orbit-idl-2 - DO NOT EDIT! + */ + +#include <string.h> +#define ORBIT2_STUBS_API +#include "map.h" + +static ORBitSmallSkeleton +get_skel_small_Mappel(POA_Mappel * servant, + const char *opname, gpointer * m_data, gpointer * impl) +{ + switch (opname[0]) { + case 'T': + if (strcmp((opname + 1), "est")) + break; + *impl = (gpointer) servant->vepv->Mappel_epv->Test; + *m_data = (gpointer) & Mappel__iinterface.methods._buffer[0]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Mappel_Test; + break; + default: + break; + } + return NULL; +} + +void +POA_Mappel__init(PortableServer_Servant servant, CORBA_Environment * env) +{ + static PortableServer_ClassInfo class_info = + { NULL, (ORBit_small_impl_finder) & get_skel_small_Mappel, +"IDL:Mappel:1.0", &Mappel__classid, NULL, &Mappel__iinterface }; + PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), + env); + ORBit_skel_class_register(&class_info, servant, POA_Mappel__fini, + ORBIT_VEPV_OFFSET(POA_Mappel__vepv, Mappel_epv), + (CORBA_unsigned_long) 0); +} + +void +POA_Mappel__fini(PortableServer_Servant servant, CORBA_Environment * env) +{ + PortableServer_ServantBase__fini(servant, env); +} + +static ORBitSmallSkeleton +get_skel_small_Map(POA_Map * servant, + const char *opname, gpointer * m_data, gpointer * impl) +{ + switch (opname[0]) { + case 'G': + if (strcmp((opname + 1), "et")) + break; + *impl = (gpointer) servant->vepv->Map_epv->Get; + *m_data = (gpointer) & Map__iinterface.methods._buffer[8]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_Get; + break; + case 'P': + switch (opname[1]) { + case 'l': + if (strcmp((opname + 2), "aceFlag")) + break; + *impl = (gpointer) servant->vepv->Map_epv->PlaceFlag; + *m_data = (gpointer) & Map__iinterface.methods._buffer[3]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_PlaceFlag; + break; + case 'o': + if (strcmp((opname + 2), "intFromCoord")) + break; + *impl = (gpointer) servant->vepv->Map_epv->PointFromCoord; + *m_data = (gpointer) & Map__iinterface.methods._buffer[4]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_PointFromCoord; + break; + default: + break; + } + break; + case 'R': + if (strcmp((opname + 1), "oute")) + break; + *impl = (gpointer) servant->vepv->Map_epv->Route; + *m_data = (gpointer) & Map__iinterface.methods._buffer[7]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_Route; + break; + case 'V': + switch (opname[1]) { + case 'i': + switch (opname[2]) { + case 'e': + switch (opname[3]) { + case 'w': + switch (opname[4]) { + case '\0': + *impl = (gpointer) servant->vepv->Map_epv->View; + *m_data = + (gpointer) & Map__iinterface.methods. + _buffer[5]; + return (ORBitSmallSkeleton) + _ORBIT_skel_small_Map_View; + break; + case 'A': + if (strcmp((opname + 5), "ll")) + break; + *impl = + (gpointer) servant->vepv->Map_epv->ViewAll; + *m_data = + (gpointer) & Map__iinterface.methods. + _buffer[6]; + return (ORBitSmallSkeleton) + _ORBIT_skel_small_Map_ViewAll; + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + break; + case 'd': + switch (opname[1]) { + case 'o': + switch (opname[2]) { + case 'N': + if (strcmp((opname + 3), "othing")) + break; + *impl = (gpointer) servant->vepv->Map_epv->doNothing; + *m_data = (gpointer) & Map__iinterface.methods._buffer[1]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_doNothing; + break; + case 'O': + if (strcmp((opname + 3), "neWay")) + break; + *impl = (gpointer) servant->vepv->Map_epv->doOneWay; + *m_data = (gpointer) & Map__iinterface.methods._buffer[2]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_doOneWay; + break; + default: + break; + } + break; + default: + break; + } + break; + case 'm': + if (strcmp((opname + 1), "apString")) + break; + *impl = (gpointer) servant->vepv->Map_epv->mapString; + *m_data = (gpointer) & Map__iinterface.methods._buffer[0]; + return (ORBitSmallSkeleton) _ORBIT_skel_small_Map_mapString; + break; + default: + break; + } + return NULL; +} + +void +POA_Map__init(PortableServer_Servant servant, CORBA_Environment * env) +{ + static PortableServer_ClassInfo class_info = + { NULL, (ORBit_small_impl_finder) & get_skel_small_Map, "IDL:Map:1.0", +&Map__classid, NULL, &Map__iinterface }; + PortableServer_ServantBase__init(((PortableServer_ServantBase *) servant), + env); + ORBit_skel_class_register(&class_info, servant, POA_Map__fini, + ORBIT_VEPV_OFFSET(POA_Map__vepv, Map_epv), + (CORBA_unsigned_long) 0); +} + +void +POA_Map__fini(PortableServer_Servant servant, CORBA_Environment * env) +{ + PortableServer_ServantBase__fini(servant, env); +} diff --git a/map-srv.c b/map-srv.c new file mode 100644 index 00000000..6d38db03 --- /dev/null +++ b/map-srv.c @@ -0,0 +1,262 @@ +/* + * CORBA map test + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Elliot Lee <sopwith@redhat.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "map.h" +#include "coord.h" +#include "route.h" +#include "transform.h" +#include "statusbar.h" +#include "map-share.h" +#include "main.h" +#include <math.h> + +/** + This is used by map-server.c and map-local.c + It uses map-skels.c +**/ + +static Map the_map_client; +static CORBA_ORB the_orb; +static PortableServer_POA the_poa; +static PortableServer_ObjectId *the_objid; + +#if 0 +static GtkMap *global_map; +#endif + +static CORBA_Object +do_mapString(PortableServer_Servant servant, + const CORBA_char * astring, + CORBA_double * outnum, CORBA_Environment * ev) +{ + + g_message("[server] %s", astring); + + *outnum = rand() % 100; + + return CORBA_Object_duplicate(the_map_client, ev); +} + +static void +do_PlaceFlag(PortableServer_Servant servant, CORBA_Environment * ev) +{ + + g_message("[server PlaceFlag]"); + +} + + +static void +do_doNothing(PortableServer_Servant servant, CORBA_Environment * ev) +{ +} + +PortableServer_ServantBase__epv base_epv = { + NULL, + NULL, + NULL +}; + +PointObj +do_PointFromCoord(PortableServer_Servant _servant, const CORBA_char * coord, CORBA_Environment * ev) +{ + PointObj ret; + double lat,lng,lat_deg,lng_deg; + char lat_c,lng_c; + + printf("String=%s\n", coord); + sscanf(coord,"%lf %c %lf %c",&lat, &lat_c, &lng, &lng_c); + + printf("lat=%f lng=%f\n", lat, lng); + + lat_deg=floor(lat/100); + lat-=lat_deg*100; + lat_deg+=lat/60; + + lng_deg=floor(lng/100); + lng-=lng_deg*100; + lng_deg+=lng/60; + + ret.lat=lat_deg; + ret.lng=lng_deg; + printf("lat_deg=%f lng_deg=%f\n", lat_deg, lng_deg); + + ret.height=0; + return ret; +} + +static void +PointObj_to_coor(const PointObj *pnt, struct coord *c) +{ + double lng, lat; + lng=pnt->lng; + lat=pnt->lat; + transform_mercator(&lng, &lat, c); +} + +void +do_View(PortableServer_Servant _servant, const PointObj *pnt, CORBA_Environment * ev) +{ + unsigned long scale; + struct coord c; +#if 0 + GtkMap *map=global_map; + + map_get_view(map, NULL, NULL, &scale); + PointObj_to_coor(pnt, &c); + map_set_view(map, c.x, c.y, scale); +#endif +} + + +void +do_Route(PortableServer_Servant _servant, const PointObj *src, const PointObj *dst, CORBA_Environment * ev) +{ +#if 0 + struct coord c_src,c_dst; + GtkMap *map=global_map; + unsigned long scale; + + PointObj_to_coor(src, &c_src); + PointObj_to_coor(dst, &c_dst); + route_set_position(map->container->route, &c_src); + route_set_destination(map->container->route, &c_dst); + + map_get_view(map, NULL, NULL, &scale); + map_set_view(map, c_src.x, c_src.y, scale); + + if (map->container->statusbar && map->container->statusbar->statusbar_route_update) + map->container->statusbar->statusbar_route_update(map->container->statusbar, map->container->route); +#endif +} + +POA_Mappel__epv mappel_epv = { +}; + +Mappel do_Get(PortableServer_Servant _servant, CORBA_Environment * ev) +{ + Mappel retval=NULL; +#if 0 + impl_POA_Mappel *newservant; + PortableServer_ObjectId *objid; + + printf("Do_Get\n"); + newservant = g_new0(impl_POA_Mappel, 1); + newservant->servant.vepv = &mappel_epv; + newservant->poa = poa; + POA_Mappel__init((PortableServer_Servant) newservant, ev); + objid = PortableServer_POA_activate_object(poa, newservant, ev); + CORBA_free(objid); + retval = PortableServer_POA_servant_to_reference(poa, newservant, ev); +#endif + + return retval; +} + +POA_Map__epv map_epv = { + mapString: do_mapString, + doNothing: do_doNothing, + PlaceFlag: do_PlaceFlag, + PointFromCoord: do_PointFromCoord, + View: do_View, + Route: do_Route, + Get: do_Get, + }; +POA_Map__vepv poa_map_vepv = { &base_epv, &map_epv }; +POA_Map poa_map_servant = { NULL, &poa_map_vepv }; + + +void map_srv_start_poa(CORBA_ORB orb, CORBA_Environment * ev) +{ + PortableServer_POAManager mgr; + + the_orb = orb; + the_poa = (PortableServer_POA) + CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev); + + mgr = PortableServer_POA__get_the_POAManager(the_poa, ev); + PortableServer_POAManager_activate(mgr, ev); + CORBA_Object_release((CORBA_Object) mgr, ev); +} + +CORBA_Object map_srv_start_object(CORBA_Environment * ev, struct container *co) +{ + POA_Map__init(&poa_map_servant, ev); + if (ev->_major) { + printf("object__init failed: %d\n", ev->_major); + exit(1); + } + the_objid = PortableServer_POA_activate_object(the_poa, + &poa_map_servant, + ev); + if (ev->_major) { + printf("activate_object failed: %d\n", ev->_major); + exit(1); + } + the_map_client = PortableServer_POA_servant_to_reference(the_poa, + &poa_map_servant, + ev); + if (ev->_major) { + printf("servant_to_reference failed: %d\n", ev->_major); + exit(1); + } +#if 0 + global_map=map; +#endif + return the_map_client; +} + +void map_srv_finish_object(CORBA_Environment * ev) +{ + CORBA_Object_release(the_map_client, ev); + if (ev->_major) { + printf("object_release failed: %d\n", ev->_major); + exit(1); + } + the_map_client = 0; + PortableServer_POA_deactivate_object(the_poa, the_objid, ev); + if (ev->_major) { + printf("deactivate_object failed: %d\n", ev->_major); + exit(1); + } + CORBA_free(the_objid); + the_objid = 0; + POA_Map__fini(&poa_map_servant, ev); + if (ev->_major) { + printf("object__fini failed: %d\n", ev->_major); + exit(1); + } +} + + +void map_srv_finish_poa(CORBA_Environment * ev) +{ + CORBA_Object_release((CORBA_Object) the_poa, ev); + if (ev->_major) { + printf("POA release failed: %d\n", ev->_major); + exit(1); + } + the_poa = 0; +} + diff --git a/map-stubs.c b/map-stubs.c new file mode 100644 index 00000000..fa7d0f34 --- /dev/null +++ b/map-stubs.c @@ -0,0 +1,135 @@ +/* + * This file was generated by orbit-idl-2 - DO NOT EDIT! + */ + +#include <string.h> +#define ORBIT2_STUBS_API +#include "map.h" + +void +Mappel_Test(Mappel _obj, CORBA_Environment * ev) +{ + ORBit_c_stub_invoke(_obj, &Mappel__iinterface.methods, 0, NULL, NULL, NULL, + ev, Mappel__classid, G_STRUCT_OFFSET(POA_Mappel__epv, + Test), + (ORBitSmallSkeleton) _ORBIT_skel_small_Mappel_Test); + +} + +Map +Map_mapString(Map _obj, const CORBA_char * astring, CORBA_double * anum, + CORBA_Environment * ev) +{ + Map _ORBIT_retval; + gpointer _args[2]; + + _args[0] = (gpointer) & astring; + _args[1] = &anum; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 0, &_ORBIT_retval, + _args, NULL, ev, Map__classid, + G_STRUCT_OFFSET(POA_Map__epv, mapString), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_mapString); + + return _ORBIT_retval; +} + +void +Map_doNothing(Map _obj, CORBA_Environment * ev) +{ + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 1, NULL, NULL, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, + doNothing), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_doNothing); + +} + +void +Map_doOneWay(Map _obj, const CORBA_char * ignore, CORBA_Environment * ev) +{ + gpointer _args[1]; + + _args[0] = (gpointer) & ignore; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 2, NULL, _args, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, + doOneWay), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_doOneWay); + +} + +void +Map_PlaceFlag(Map _obj, CORBA_Environment * ev) +{ + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 3, NULL, NULL, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, + PlaceFlag), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_PlaceFlag); + +} + +PointObj +Map_PointFromCoord(Map _obj, const CORBA_char * coord, CORBA_Environment * ev) +{ + PointObj _ORBIT_retval; + gpointer _args[1]; + + _args[0] = (gpointer) & coord; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 4, &_ORBIT_retval, + _args, NULL, ev, Map__classid, + G_STRUCT_OFFSET(POA_Map__epv, PointFromCoord), + (ORBitSmallSkeleton) + _ORBIT_skel_small_Map_PointFromCoord); + + return _ORBIT_retval; +} + +void +Map_View(Map _obj, const PointObj * where, CORBA_Environment * ev) +{ + gpointer _args[1]; + + _args[0] = (gpointer) where; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 5, NULL, _args, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, View), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_View); + +} + +void +Map_ViewAll(Map _obj, const PointObjSequence * where, CORBA_Environment * ev) +{ + gpointer _args[1]; + + _args[0] = (gpointer) where; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 6, NULL, _args, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, + ViewAll), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_ViewAll); + +} + +void +Map_Route(Map _obj, const PointObj * src, const PointObj * dst, + CORBA_Environment * ev) +{ + gpointer _args[2]; + + _args[0] = (gpointer) src; + _args[1] = (gpointer) dst; + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 7, NULL, _args, NULL, + ev, Map__classid, G_STRUCT_OFFSET(POA_Map__epv, Route), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_Route); + +} + +Mappel +Map_Get(Map _obj, CORBA_Environment * ev) +{ + Mappel _ORBIT_retval; + + ORBit_c_stub_invoke(_obj, &Map__iinterface.methods, 8, &_ORBIT_retval, + NULL, NULL, ev, Map__classid, + G_STRUCT_OFFSET(POA_Map__epv, Get), + (ORBitSmallSkeleton) _ORBIT_skel_small_Map_Get); + + return _ORBIT_retval; +} @@ -0,0 +1,341 @@ +/* + * This file was generated by orbit-idl-2 - DO NOT EDIT! + */ + +#ifndef map_H +#define map_H 1 +#include <glib.h> +#define ORBIT_IDL_SERIAL 20 +#include <orbit/orbit-types.h> + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/** typedefs **/ +#if !defined(_PointObj_defined) +#define _PointObj_defined 1 + typedef struct PointObj_type PointObj; + struct PointObj_type + { + CORBA_float lng; + CORBA_float lat; + CORBA_float height; + }; + +#if !defined(TC_IMPL_TC_PointObj_0) +#define TC_IMPL_TC_PointObj_0 'm' +#define TC_IMPL_TC_PointObj_1 'a' +#define TC_IMPL_TC_PointObj_2 'p' +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + const struct CORBA_TypeCode_struct TC_PointObj_struct; +#define TC_PointObj ((CORBA_TypeCode)&TC_PointObj_struct) +#endif +#define PointObj__alloc() ((PointObj *)ORBit_small_alloc (TC_PointObj)) +#define PointObj__freekids(m,d) ORBit_small_freekids (TC_PointObj,(m),(d)) +#endif +#if !defined(ORBIT_DECL_CORBA_sequence_PointObj) +#define ORBIT_DECL_CORBA_sequence_PointObj 1 +#define ORBIT_IMPL_CORBA_sequence_PointObj_0 'm' +#define ORBIT_IMPL_CORBA_sequence_PointObj_1 'a' +#define ORBIT_IMPL_CORBA_sequence_PointObj_2 'p' +#if !defined(_CORBA_sequence_PointObj_defined) +#define _CORBA_sequence_PointObj_defined 1 + typedef struct + { + CORBA_unsigned_long _maximum, + _length; + PointObj *_buffer; + CORBA_boolean _release; + } CORBA_sequence_PointObj; +#endif +#if !defined(TC_IMPL_TC_CORBA_sequence_PointObj_0) +#define TC_IMPL_TC_CORBA_sequence_PointObj_0 'm' +#define TC_IMPL_TC_CORBA_sequence_PointObj_1 'a' +#define TC_IMPL_TC_CORBA_sequence_PointObj_2 'p' +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + const struct CORBA_TypeCode_struct TC_CORBA_sequence_PointObj_struct; +#define TC_CORBA_sequence_PointObj ((CORBA_TypeCode)&TC_CORBA_sequence_PointObj_struct) +#endif +#define CORBA_sequence_PointObj__alloc() ((CORBA_sequence_PointObj *)ORBit_small_alloc (TC_CORBA_sequence_PointObj)) +#define CORBA_sequence_PointObj__freekids(m,d) ORBit_small_freekids (TC_CORBA_sequence_PointObj,(m),(d)) +#define CORBA_sequence_PointObj_allocbuf(l) ((PointObj*)ORBit_small_allocbuf (TC_CORBA_sequence_PointObj, (l))) +#define CORBA_sequence_PointObj_allocbuf(l) ((PointObj*)ORBit_small_allocbuf (TC_CORBA_sequence_PointObj, (l))) +#endif +#if !defined(_PointObjSequence_defined) +#define _PointObjSequence_defined 1 + typedef CORBA_sequence_PointObj PointObjSequence; +#define PointObjSequence_marshal(x,y,z) CORBA_sequence_PointObj_marshal((x),(y),(z)) +#define PointObjSequence_demarshal(x,y,z,i) CORBA_sequence_PointObj_demarshal((x),(y),(z),(i)) +#if !defined(TC_IMPL_TC_PointObjSequence_0) +#define TC_IMPL_TC_PointObjSequence_0 'm' +#define TC_IMPL_TC_PointObjSequence_1 'a' +#define TC_IMPL_TC_PointObjSequence_2 'p' +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + const struct CORBA_TypeCode_struct TC_PointObjSequence_struct; +#define TC_PointObjSequence ((CORBA_TypeCode)&TC_PointObjSequence_struct) +#endif +#define PointObjSequence__alloc() ((PointObjSequence *)ORBit_small_alloc (TC_CORBA_sequence_PointObj)) +#define PointObjSequence__freekids(m,d) ORBit_small_freekids (TC_CORBA_sequence_PointObj,(m),(d)) +#define PointObjSequence_allocbuf(l) ((PointObj*)ORBit_small_allocbuf (TC_CORBA_sequence_PointObj, (l))) +#endif +#if !defined(ORBIT_DECL_Mappel) && !defined(_Mappel_defined) +#define ORBIT_DECL_Mappel 1 +#define _Mappel_defined 1 +#define Mappel__freekids CORBA_Object__freekids + typedef CORBA_Object Mappel; + extern CORBA_unsigned_long Mappel__classid; +#if !defined(TC_IMPL_TC_Mappel_0) +#define TC_IMPL_TC_Mappel_0 'm' +#define TC_IMPL_TC_Mappel_1 'a' +#define TC_IMPL_TC_Mappel_2 'p' +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + const struct CORBA_TypeCode_struct TC_Mappel_struct; +#define TC_Mappel ((CORBA_TypeCode)&TC_Mappel_struct) +#endif +#endif +#if !defined(ORBIT_DECL_Map) && !defined(_Map_defined) +#define ORBIT_DECL_Map 1 +#define _Map_defined 1 +#define Map__freekids CORBA_Object__freekids + typedef CORBA_Object Map; + extern CORBA_unsigned_long Map__classid; +#if !defined(TC_IMPL_TC_Map_0) +#define TC_IMPL_TC_Map_0 'm' +#define TC_IMPL_TC_Map_1 'a' +#define TC_IMPL_TC_Map_2 'p' +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + const struct CORBA_TypeCode_struct TC_Map_struct; +#define TC_Map ((CORBA_TypeCode)&TC_Map_struct) +#endif +#endif + +/** POA structures **/ +#ifndef _defined_POA_Mappel +#define _defined_POA_Mappel 1 + typedef struct + { + void *_private; + void (*Test) (PortableServer_Servant _servant, CORBA_Environment * ev); + } POA_Mappel__epv; + typedef struct + { + PortableServer_ServantBase__epv *_base_epv; + POA_Mappel__epv *Mappel_epv; + } POA_Mappel__vepv; + typedef struct + { + void *_private; + POA_Mappel__vepv *vepv; + } POA_Mappel; + extern void POA_Mappel__init(PortableServer_Servant servant, + CORBA_Environment * ev); + extern void POA_Mappel__fini(PortableServer_Servant servant, + CORBA_Environment * ev); +#endif /* _defined_POA_Mappel */ +#ifndef _defined_POA_Map +#define _defined_POA_Map 1 + typedef struct + { + void *_private; + Map(*mapString) (PortableServer_Servant _servant, + const CORBA_char * astring, CORBA_double * anum, + CORBA_Environment * ev); + void (*doNothing) (PortableServer_Servant _servant, + CORBA_Environment * ev); + void (*doOneWay) (PortableServer_Servant _servant, + const CORBA_char * ignore, CORBA_Environment * ev); + void (*PlaceFlag) (PortableServer_Servant _servant, + CORBA_Environment * ev); + PointObj(*PointFromCoord) (PortableServer_Servant _servant, + const CORBA_char * coord, + CORBA_Environment * ev); + void (*View) (PortableServer_Servant _servant, const PointObj * where, + CORBA_Environment * ev); + void (*ViewAll) (PortableServer_Servant _servant, + const PointObjSequence * where, + CORBA_Environment * ev); + void (*Route) (PortableServer_Servant _servant, const PointObj * src, + const PointObj * dst, CORBA_Environment * ev); + Mappel(*Get) (PortableServer_Servant _servant, CORBA_Environment * ev); + } POA_Map__epv; + typedef struct + { + PortableServer_ServantBase__epv *_base_epv; + POA_Map__epv *Map_epv; + } POA_Map__vepv; + typedef struct + { + void *_private; + POA_Map__vepv *vepv; + } POA_Map; + extern void POA_Map__init(PortableServer_Servant servant, + CORBA_Environment * ev); + extern void POA_Map__fini(PortableServer_Servant servant, + CORBA_Environment * ev); +#endif /* _defined_POA_Map */ + +/** skel prototypes **/ + void _ORBIT_skel_small_Mappel_Test(POA_Mappel * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_Test) + (PortableServer_Servant _servant, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_mapString(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + Map(*_impl_mapString) + (PortableServer_Servant _servant, + const CORBA_char * astring, + CORBA_double * anum, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_doNothing(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_doNothing) + (PortableServer_Servant _servant, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_doOneWay(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_doOneWay) + (PortableServer_Servant _servant, + const CORBA_char * ignore, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_PlaceFlag(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_PlaceFlag) + (PortableServer_Servant _servant, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_PointFromCoord(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + PointObj(*_impl_PointFromCoord) + (PortableServer_Servant _servant, + const CORBA_char * coord, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_View(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_View) (PortableServer_Servant + _servant, + const PointObj * where, + CORBA_Environment * + ev)); + void _ORBIT_skel_small_Map_ViewAll(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, + CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_ViewAll) + (PortableServer_Servant _servant, + const PointObjSequence * where, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_Route(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, CORBA_Context ctx, + CORBA_Environment * ev, + void (*_impl_Route) + (PortableServer_Servant _servant, + const PointObj * src, + const PointObj * dst, + CORBA_Environment * ev)); + void _ORBIT_skel_small_Map_Get(POA_Map * _ORBIT_servant, + gpointer _ORBIT_retval, + gpointer * _ORBIT_args, CORBA_Context ctx, + CORBA_Environment * ev, + Mappel(*_impl_Get) (PortableServer_Servant + _servant, + CORBA_Environment * + ev)); + +/** stub prototypes **/ + void Mappel_Test(Mappel _obj, CORBA_Environment * ev); + Map Map_mapString(Map _obj, const CORBA_char * astring, + CORBA_double * anum, CORBA_Environment * ev); + void Map_doNothing(Map _obj, CORBA_Environment * ev); + void Map_doOneWay(Map _obj, const CORBA_char * ignore, + CORBA_Environment * ev); + void Map_PlaceFlag(Map _obj, CORBA_Environment * ev); + PointObj Map_PointFromCoord(Map _obj, const CORBA_char * coord, + CORBA_Environment * ev); + void Map_View(Map _obj, const PointObj * where, CORBA_Environment * ev); + void Map_ViewAll(Map _obj, const PointObjSequence * where, + CORBA_Environment * ev); + void Map_Route(Map _obj, const PointObj * src, const PointObj * dst, + CORBA_Environment * ev); + Mappel Map_Get(Map _obj, CORBA_Environment * ev); +#include <orbit/orb-core/orbit-interface.h> + +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + ORBit_IInterface Mappel__iinterface; +#define Mappel_IMETHODS_LEN 1 +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + ORBit_IMethod Mappel__imethods[Mappel_IMETHODS_LEN]; +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + ORBit_IInterface Map__iinterface; +#define Map_IMETHODS_LEN 9 +#ifdef ORBIT_IDL_C_IMODULE_map + static +#else + extern +#endif + ORBit_IMethod Map__imethods[Map_IMETHODS_LEN]; +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#ifndef EXCLUDE_ORBIT_H +#include <orbit/orbit.h> + +#endif /* EXCLUDE_ORBIT_H */ +#endif +#undef ORBIT_IDL_SERIAL diff --git a/map.idl b/map.idl new file mode 100644 index 00000000..a68c7d54 --- /dev/null +++ b/map.idl @@ -0,0 +1,25 @@ +struct PointObj { + float lng; /* degrees */ + float lat; /* degrees */ + float height; /* meters */ +}; + +typedef sequence<PointObj> PointObjSequence; + +interface Mappel { + void Test(); +}; + +interface Map { + Map mapString (in string astring, + out double anum); + void doNothing (); + oneway void doOneWay (in string ignore); + void PlaceFlag(); + PointObj PointFromCoord(in string coord); + void View(in PointObj where); + void ViewAll(in PointObjSequence where); + void Route(in PointObj src, in PointObj dst); + Mappel Get(); +}; + diff --git a/map.ior b/map.ior new file mode 100644 index 00000000..cb892efd --- /dev/null +++ b/map.ior @@ -0,0 +1 @@ +IOR:010f00000c00000049444c3a4d61703a312e3000030000000054424f540000000101020005000000554e495800736f630900000070636d617274696e00005f6d2c0000002f746d702f6f726269742d6d617274696e2f6c696e632d353830642d302d363264393631633861336164360000000000caaedfba58000000010102312c0000002f746d702f6f726269742d6d617274696e2f6c696e632d353830642d302d3632643936316338613361643600000000001c00000000000000ad20380865f02828dd29282828282828010000007c08e43c0100000048000000016c654202000000050000001c00000000000000ad20380865f02828dd29282828282828010000007c08e43c0100000014000000010f000001000105000000000901010000000000 diff --git a/map_data.c b/map_data.c new file mode 100644 index 00000000..cc384f03 --- /dev/null +++ b/map_data.c @@ -0,0 +1,112 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#include "file.h" +#include "block.h" +#include "map_data.h" +#include "log.h" + +static struct map_data *load_map(char *dirname) +{ + int i,len=strlen(dirname); + char *filename[file_end]; + char file[len+16]; + struct map_data *data=g_new0(struct map_data,1); + + memset(filename, 0, sizeof(*filename)); + + filename[file_border_ply]="border.ply"; + filename[file_bridge_ply]="bridge.ply"; + filename[file_height_ply]="height.ply"; + filename[file_other_ply]="other.ply"; + filename[file_rail_ply]="rail.ply"; + filename[file_sea_ply]="sea.ply"; + filename[file_street_bti]="street.bti"; + filename[file_street_str]="street.str"; + filename[file_strname_stn]="strname.stn"; + filename[file_town_twn]="town.twn"; + filename[file_tunnel_ply]="tunnel.ply"; + filename[file_water_ply]="water.ply"; + filename[file_woodland_ply]="woodland.ply"; + + strcpy(file, dirname); + file[len]='/'; + for (i = 0 ; i < file_end ; i++) { + if (filename[i]) { + strcpy(file+len+1, filename[i]); + data->file[i]=file_create_caseinsensitive(file); + if (! data->file[i]) { + g_warning("Failed to load %s", file); + } + } + } + return data; +} + +struct map_data *load_maps(char *map) +{ + char *name; + void *hnd; + struct map_data *last,*ret; + int i; + + if (! map) + map=getenv("MAP_DATA"); + if (! map) + map="/opt/reiseplaner/travel/DE.map"; + + ret=load_map(map); + last=ret; + hnd=file_opendir(map); + if (hnd) { + while ((name=file_readdir(hnd))) { + if (!strcasecmp(name+strlen(name)-4,".smp")) { + char next_name[strlen(map)+strlen(name)+2]; + strcpy(next_name, map); + strcat(next_name, "/"); + strcat(next_name, name); + last->next=load_map(next_name); + last=last->next; + } + } + file_closedir(hnd); + } else { + g_warning("Unable to open Map Directory '%s'\n", map); + } + log_apply(ret, file_end); + +#if 0 + last=ret; + while (last) { + for (i = 0 ; i < file_end ; i++) { + if (last->file[i]) { + file_set_readonly(last->file[i]); + } + } + last=last->next; + } + *((int *)0)=0; +#endif + + return ret; +} + + +void +map_data_foreach(struct map_data *mdata, int file, struct transformation *t, int limit, + void(*func)(struct block_info *, unsigned char *, unsigned char *, void *), void *data) +{ + struct block_info blk_inf; + + memset(&blk_inf, 0, sizeof(blk_inf)); + + while (mdata) { + if (mdata->file[file]) { + blk_inf.mdata=mdata; + blk_inf.file=mdata->file[file]; + block_foreach_visible(&blk_inf, t, limit, data, func); + } + mdata=mdata->next; + } +} diff --git a/map_data.h b/map_data.h new file mode 100644 index 00000000..a38bd085 --- /dev/null +++ b/map_data.h @@ -0,0 +1,30 @@ + +enum file_index { + file_border_ply=0, + file_bridge_ply, + file_height_ply, + file_other_ply, + file_rail_ply, + file_sea_ply, + file_street_bti, + file_street_str, + file_strname_stn, + file_town_twn, + file_tunnel_ply, + file_water_ply, + file_woodland_ply, + file_end +}; + +struct map_data { + struct file *file[file_end]; + struct map_data *next; +}; + +struct map_data *load_maps(char *map); + +struct transformation; +struct block_info; + +void map_data_foreach(struct map_data *mdata, int file, struct transformation *t, int limit, + void(*func)(struct block_info *, unsigned char *, unsigned char *, void *), void *data); diff --git a/mapclient.c b/mapclient.c new file mode 100644 index 00000000..056510fd --- /dev/null +++ b/mapclient.c @@ -0,0 +1,103 @@ +/* + * CORBA map test + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Elliot Lee <sopwith@redhat.com> + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "map.h" + + +#define ABORT_IF_EXCEPTION(_ev, _message) \ +if ((_ev)->_major != CORBA_NO_EXCEPTION) { \ + g_error("%s: %s", _message, CORBA_exception_id (_ev)); \ + CORBA_exception_free (_ev); \ + abort(); \ +} + +Map map_client, bec; +Mappel mappel; + +gboolean map_opt_quiet = FALSE; + +int main(int argc, char *argv[]) +{ + CORBA_Environment ev; + CORBA_ORB orb; + char buf[1024]; + FILE *ior; + PointObj pnt,src,dst; + + ior=fopen("map.ior","r"); + if (ior) { + fread(buf,1024,1,ior); + fclose(ior); + } + CORBA_exception_init(&ev); + orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev); + + + /* bind to object */ + map_client = CORBA_ORB_string_to_object(orb, buf, &ev); + ABORT_IF_EXCEPTION(&ev, "cannot bind to object"); + g_assert(map_client != NULL); + +#if 0 + /* Method call without any argument, usefull to tell + * lifeness */ + Map_doNothing(map_client, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + + Map_PlaceFlag(map_client, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); +#endif + + if (argc > 0) { + if (!strcmp(argv[1],"--view")) { + pnt=Map_PointFromCoord(map_client, argv[2], &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + Map_View(map_client, &pnt, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + } + if (!strcmp(argv[1],"--route")) { + src=Map_PointFromCoord(map_client, argv[2], &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + dst=Map_PointFromCoord(map_client, argv[3], &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + Map_Route(map_client, &src, &dst, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + } + mappel=Map_Get(map_client, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + } + + /* release initial object reference */ + CORBA_Object_release(map_client, &ev); + ABORT_IF_EXCEPTION(&ev, "service raised exception "); + + /* shutdown ORB, shutdown IO channels */ + CORBA_ORB_shutdown(orb, FALSE, &ev); + ABORT_IF_EXCEPTION(&ev, "ORB shutdown ..."); + + /* destroy local ORB */ + CORBA_ORB_destroy(orb, &ev); + ABORT_IF_EXCEPTION(&ev, "destroying local ORB raised exception"); + + return 0; +} @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> +#include <time.h> +#include "coord.h" +#include "data_window.h" +#include "route.h" +#include "cursor.h" +#include "menu.h" +#include "command.h" +#include "transform.h" +#include "street.h" +#include "statusbar.h" +#include "destination.h" +#include "main.h" +#include "container.h" + +void +menu_route_do_update(struct container *co) +{ + if (co->cursor) { + route_set_position(co->route, cursor_pos_get(co->cursor)); + graphics_redraw(co); + if (co->statusbar && co->statusbar->statusbar_route_update) + co->statusbar->statusbar_route_update(co->statusbar, co->route); + } +} + +void +menu_route_update(struct container *co) +{ + menu_route_do_update(co); + graphics_redraw(co); +} @@ -0,0 +1,8 @@ +struct menu { + struct menu_gui *gui; +}; + +struct container; + +void menu_route_do_update(struct container *co); +void menu_route_update(struct container *co); diff --git a/navigation.c b/navigation.c new file mode 100644 index 00000000..feb9e385 --- /dev/null +++ b/navigation.c @@ -0,0 +1,249 @@ +#include <math.h> +#include <stdlib.h> +#include "coord.h" +#include "param.h" +#include "block.h" +#include "route.h" +#include "street.h" +#include "street_name.h" +#include "speech.h" +#include "navigation.h" +#include "data_window.h" + +struct data_window *navigation_window; + +static int +road_angle(struct coord *c, int dir) +{ + double angle; + int dx=c[1].x-c[0].x; + int dy=c[1].y-c[0].y; + angle=atan2(dx,dy); + angle*=180/M_PI; + if (dir == -1) + angle=angle-180; + if (angle < 0) + angle+=360; + return angle; +} + +static void +expand_str(char *str) +{ + int len=strlen(str); + if (len > 4 && !strcmp(str+len-4,"str.")) + strcpy(str+len-4,"strasse"); + if (len > 4 && !strcmp(str+len-4,"Str.")) + strcpy(str+len-4,"Strasse"); +} + +struct navigation_item { + char name1[128]; + char name2[128]; + int length; + int time; + int crossings_start; + int crossings_end; + int angle_start; + int angle_end; + int points; + struct coord start; + struct coord end; +}; + +void +navigation_goto(struct data_window *navigation_window, char **cols) +{ + extern struct container *co; + unsigned long scale; + long x,y; + + printf("goto %s\n",cols[8]); + sscanf(cols[8],"%lx,%lx",&x,&y); + graphics_set_view(co, &x, &y, NULL); +} + +int +is_same_street(struct navigation_item *old, struct navigation_item *new) +{ + if (strlen(old->name2) && !strcmp(old->name2, new->name2)) { + strcpy(old->name1, new->name1); + return 1; + } + if (strlen(old->name1) && !strcmp(old->name1, new->name1)) { + strcpy(old->name2, new->name2); + return 1; + } + return 0; +} + +int +maneuver_required(struct navigation_item *old, struct navigation_item *new, int *delta) +{ + if (is_same_street(old, new)) + return 0; + if (old->crossings_end == 2) + return 0; + *delta=new->angle_start-old->angle_end; + if (*delta < -180) + *delta+=360; + if (*delta > 180) + *delta-=360; + if (*delta < 20 && *delta >-20) + return 0; + return 1; +} + +int flag; +extern void *speech_handle; + +void +make_maneuver(struct navigation_item *old, struct navigation_item *new) +{ + + int delta; + struct param_list param_list[20]; + + char angle_old[30],angle_new[30],angle_delta[30],cross_roads[30],position[30]; + char command[256],*p,*dir; + + param_list[0].name="Name1 Old"; + param_list[0].value=old->name1; + param_list[1].name="Name2 Old"; + param_list[1].value=old->name2; + param_list[2].name="Name1 New"; + param_list[2].value=new->name1; + param_list[3].name="Name2 New"; + param_list[3].value=new->name2; + param_list[4].name="Angle Old"; + param_list[5].name="Angle New"; + param_list[6].name="Delta"; + param_list[7].name="Cross-Roads"; + param_list[8].name="Position"; + param_list[9].name="Command"; + if (old->points) { + if (!maneuver_required(old, new, &delta)) { + old->length+=new->length; + old->time+=new->time; + old->crossings_end=new->crossings_end; + old->angle_end=new->angle_end; + old->points+=new->points; + } else { + sprintf(angle_old,"%d", old->angle_end); + param_list[4].value=angle_old; + sprintf(angle_new,"%d", new->angle_start); + param_list[5].value=angle_new; + sprintf(angle_delta,"%d", delta); + param_list[6].value=angle_delta; + sprintf(cross_roads,"%d", old->crossings_end); + param_list[7].value=cross_roads; + sprintf(position,"0x%lx,0x%lx", new->start.x, new->start.y); + param_list[8].value=position; + sprintf(command,"Dem Strassenverlauf %d Meter folgen, dann ", old->length); + p=command+strlen(command); + dir="rechts"; + if (delta < 0) { + dir="links"; + delta=-delta; + } + if (delta < 45) { + strcpy(p,"leicht "); + } else if (delta < 105) { + } else if (delta < 165) { + strcpy(p,"scharf "); + } + p+=strlen(p); + strcpy(p,dir); + p+=strlen(p); + strcpy(p," abbiegen"); + param_list[9].value=command; + if (flag) { + printf("command='%s'\n", command); +#if 0 + speech_say(speech_handle, command); +#endif + flag=0; + } + data_window_add(navigation_window, param_list, 10); + *old=*new; + } + } else { + *old=*new; + } +} + +void +navigation_path_description(void *route) +{ + int id; + struct route_path_segment *curr=route_path_get_all(route); + struct block_info blk_inf; + struct street_str *str; + struct street_name name; + struct street_coord *coord; + struct map_data *mdata=route_mapdata_get(route); + struct coord *start,*end,*tmp; + int angle_start, angle_end, angle_tmp; + struct route_crossings *crossings_start,*crossings_end; + struct navigation_item item_curr,item_last; + + memset(&item_last,0,sizeof(item_last)); + + if (!navigation_window) + navigation_window=data_window("Navigation",NULL,navigation_goto); + data_window_begin(navigation_window); + flag=1; + while (curr) { + str=NULL; + id=curr->segid; + if (id) { + if (id < 0) + id=-id; + street_get_by_id(mdata, id, &blk_inf, &str); + coord=street_coord_get(&blk_inf, str); + start=coord->c; + end=coord->c+coord->count-1; + angle_start=road_angle(coord->c, curr->dir); + if (coord->count > 2) + angle_end=road_angle(coord->c+coord->count-2,curr->dir); + else + angle_end=angle_start; + if (curr->dir < 0) { + tmp=start; + angle_tmp=angle_start; + start=end; + angle_start=angle_end; + end=tmp; + angle_end=angle_tmp; + } + crossings_start=route_crossings_get(route, start); + crossings_end=route_crossings_get(route, end); + if (str && str->nameid) { + street_name_get_by_id(&name, blk_inf.mdata, str->nameid); + strcpy(item_curr.name1,name.name1); + strcpy(item_curr.name2,name.name2); + expand_str(item_curr.name1); + expand_str(item_curr.name2); + } else { + item_curr.name1[0]='\0'; + item_curr.name2[0]='\0'; + } + item_curr.length=curr->length; + item_curr.time=curr->time; + item_curr.crossings_start=crossings_start->count; + item_curr.crossings_end=crossings_end->count; + item_curr.angle_start=angle_start; + item_curr.angle_end=angle_end; + item_curr.points=coord->count; + item_curr.start=*start; + item_curr.end=*end; + make_maneuver(&item_last,&item_curr); + free(coord); + free(crossings_start); + free(crossings_end); + } + curr=curr->next; + } + data_window_end(navigation_window); +} + diff --git a/navigation.h b/navigation.h new file mode 100644 index 00000000..ae39528f --- /dev/null +++ b/navigation.h @@ -0,0 +1 @@ +void navigation_path_description(void *route); diff --git a/param.c b/param.c new file mode 100644 index 00000000..0b3296e3 --- /dev/null +++ b/param.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include "param.h" + +void +param_add_string(char *name, char *value, struct param_list **param, int *count) +{ + if (*count > 0) { + (*param)->name=malloc(strlen(value)+strlen(name)+2); + (*param)->value=(*param)->name+strlen(name)+1; + strcpy((*param)->name, name); + strcpy((*param)->value, value); + (*count)--; + (*param)++; + } + +} + +void +param_add_dec(char *name, unsigned long value, struct param_list **param, int *count) +{ + char buffer[1024]; + sprintf(buffer, "%ld", value); + param_add_string(name, buffer, param, count); +} + + +void +param_add_hex(char *name, unsigned long value, struct param_list **param, int *count) +{ + char buffer[1024]; + sprintf(buffer, "0x%lx", value); + param_add_string(name, buffer, param, count); +} + +void +param_add_hex_sig(char *name, long value, struct param_list **param, int *count) +{ + char buffer[1024]; + if (value < 0) + sprintf(buffer, "-0x%lx", -value); + else + sprintf(buffer, "0x%lx", value); + param_add_string(name, buffer, param, count); +} diff --git a/param.h b/param.h new file mode 100644 index 00000000..496c0542 --- /dev/null +++ b/param.h @@ -0,0 +1,9 @@ +struct param_list { + char *name; + char *value; +}; + +void param_add_string(char *name, char *value, struct param_list **param, int *count); +void param_add_dec(char *name, unsigned long value, struct param_list **param, int *count); +void param_add_hex(char *name, unsigned long value, struct param_list **param, int *count); +void param_add_hex_sig(char *name, long value, struct param_list **param, int *count); diff --git a/phrase.c b/phrase.c new file mode 100644 index 00000000..92f6e7c3 --- /dev/null +++ b/phrase.c @@ -0,0 +1,25 @@ +#include <time.h> +#include "coord.h" +#include "route.h" +#include "speech.h" + +void +phrase_route_calc(void *speech) +{ + if (! speech) + return; + speech_say(speech,"Die Route wird berechnet\n"); +} + +void +phrase_route_calculated(void *speech, void *route) +{ + struct tm *eta; + if (! speech) + return; + + eta=route_get_eta(route); + + speech_sayf(speech,"Die Route wurde berechnet. Geschätzte Ankunftszeit %d Uhr %d Entfernung %4.0f Kilometer", eta->tm_hour,eta->tm_min,route_get_len(route)/1000); + +} diff --git a/phrase.h b/phrase.h new file mode 100644 index 00000000..9f357388 --- /dev/null +++ b/phrase.h @@ -0,0 +1,2 @@ +void phrase_route_calc(void *speech); +void phrase_route_calculated(void *speech, void *route); diff --git a/plugin.c b/plugin.c new file mode 100644 index 00000000..d5c182b5 --- /dev/null +++ b/plugin.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <dlfcn.h> +#include "plugin.h" +#define PLUGIN_C +#include "plugin.h" + +void +plugin_load(void) +{ + char *plugin="plugins/poi_geodownload/plugin_poi_geodownload.so"; + void *h=dlopen(plugin,RTLD_LAZY); + void (*init)(void); + + if (! h) + printf("can't load '%s', Error '%s'\n", plugin, dlerror()); + else { + init=dlsym(h,"plugin_init"); + (*init)(); + } + +} diff --git a/plugin.h b/plugin.h new file mode 100644 index 00000000..84e0845d --- /dev/null +++ b/plugin.h @@ -0,0 +1,56 @@ +void plugin_load(void); +int plugin_init(void); + +struct container; +struct popup; +struct popup_item; +#undef PLUGIN_FUNC1 +#undef PLUGIN_FUNC3 +#undef PLUGIN_FUNC4 +#define PLUGIN_PROTO(name,args...) void name(args) + +#ifdef PLUGIN_C +#define PLUGIN_REGISTER(name,args...) \ +void \ +plugin_register_##name(PLUGIN_PROTO((*func),args)) \ +{ \ + plugin_##name##_func=func; \ +} + +#define PLUGIN_CALL(name,args...) \ +{ \ + if (plugin_##name##_func) \ + (*plugin_##name##_func)(args); \ +} + +#define PLUGIN_FUNC1(name,t1,p1) \ +PLUGIN_PROTO((*plugin_##name##_func),t1 p1); \ +void plugin_call_##name(t1 p1) PLUGIN_CALL(name,p1) \ +PLUGIN_REGISTER(name,t1 p1) + +#define PLUGIN_FUNC3(name,t1,p1,t2,p2,t3,p3) \ +PLUGIN_PROTO((*plugin_##name##_func),t1 p1,t2 p2,t3 p3); \ +void plugin_call_##name(t1 p1,t2 p2, t3 p3) PLUGIN_CALL(name,p1,p2,p3) \ +PLUGIN_REGISTER(name,t1 p1,t2 p2,t3 p3) + +#define PLUGIN_FUNC4(name,t1,p1,t2,p2,t3,p3,t4,p4) \ +PLUGIN_PROTO((*plugin_##name##_func),t1 p1,t2 p2,t3 p3,t4 p4); \ +void plugin_call_##name(t1 p1,t2 p2, t3 p3, t4 p4) PLUGIN_CALL(name,p1,p2,p3,p4) \ +PLUGIN_REGISTER(name,t1 p1,t2 p2,t3 p3,t4 p4) + +#else +#define PLUGIN_FUNC1(name,t1,p1) \ +void plugin_register_##name(void(*func)(t1 p1)); \ +void plugin_call_##name(t1 p1); + +#define PLUGIN_FUNC3(name,t1,p1,t2,p2,t3,p3) \ +void plugin_register_##name(void(*func)(t1 p1,t2 p2,t3 p3)); \ +void plugin_call_##name(t1 p1,t2 p2,t3 p3); + +#define PLUGIN_FUNC4(name,t1,p1,t2,p2,t3,p3,t4,p4) \ +void plugin_register_##name(void(*func)(t1 p1,t2 p2,t3 p3,t4 p4)); \ +void plugin_call_##name(t1 p1,t2 p2,t3 p3,t4 p4); +#endif + +PLUGIN_FUNC1(draw, struct container *, co) +PLUGIN_FUNC3(popup, struct container *, map, struct popup *, p, struct popup_item **, list) diff --git a/plugins/poi_geodownload/libmdb/backend.c b/plugins/poi_geodownload/libmdb/backend.c new file mode 100644 index 00000000..e90f807b --- /dev/null +++ b/plugins/poi_geodownload/libmdb/backend.c @@ -0,0 +1,301 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* +** functions to deal with different backend database engines +*/ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +static int is_init; +static GHashTable *mdb_backends; + + /* Access data types */ +static MdbBackendType mdb_access_types[] = { + {"Unknown 0x00", 0,0,0 }, + {"Boolean", 0,0,0}, + {"Byte", 0,0,0}, + {"Integer", 0,0,0}, + {"Long Integer", 0,0,0}, + {"Currency", 0,0,0}, + {"Single", 0,0,0}, + {"Double", 0,0,0}, + {"DateTime (Short)", 0,0,1}, + {"Unknown 0x09", 0,0,0}, + {"Text", 1,0,1}, + {"OLE", 1,0,1}, + {"Memo/Hyperlink",1,0,1}, + {"Unknown 0x0d",0,0,0}, + {"Unknown 0x0e",0,0,0}, + {"Replication ID",0,0,0}, + {"Numeric",1,1,0} +}; + +/* Oracle data types */ +static MdbBackendType mdb_oracle_types[] = { + {"Oracle_Unknown 0x00",0,0,0}, + {"NUMBER",1,0,0}, + {"NUMBER",1,0,0}, + {"NUMBER",1,0,0}, + {"NUMBER",1,0,0}, + {"NUMBER",1,0,0}, + {"FLOAT",0,0,0}, + {"FLOAT",0,0,0}, + {"DATE",0,0,0}, + {"Oracle_Unknown 0x09",0,0,0}, + {"VARCHAR2",1,0,1}, + {"BLOB",1,0,1}, + {"CLOB",1,0,1}, + {"Oracle_Unknown 0x0d",0,0,0}, + {"Oracle_Unknown 0x0e",0,0,0}, + {"NUMBER",1,0,0}, + {"NUMBER",1,0,0}, +}; + +/* Sybase/MSSQL data types */ +static MdbBackendType mdb_sybase_types[] = { + {"Sybase_Unknown 0x00",0,0,0}, + {"bit",0,0,0}, + {"char",1,0,1}, + {"smallint",0,0,0}, + {"int",0,0,0}, + {"money",0,0,0}, + {"real",0,0,0}, + {"float",0,0,0}, + {"smalldatetime",0,0,0}, + {"Sybase_Unknown 0x09",0,0,0}, + {"varchar",1,0,1}, + {"varbinary",1,0,1}, + {"text",1,0,1}, + {"Sybase_Unknown 0x0d",0,0,0}, + {"Sybase_Unknown 0x0e",0,0,0}, + {"Sybase_Replication ID",0,0,0}, + {"numeric",1,1,0}, +}; + +/* Postgres data types */ +static MdbBackendType mdb_postgres_types[] = { + {"Postgres_Unknown 0x00",0,0,0}, + {"Bool",0,0,0}, + {"Int2",0,0,0}, + {"Int4",0,0,0}, + {"Int8",0,0,0}, + {"Money",0,0,0}, + {"Float4",0,0,0}, + {"Float8",0,0,0}, + {"Timestamp",0,0,0}, + {"Postgres_Unknown 0x09",0,0,0}, + {"Char",1,0,1}, + {"Postgres_Unknown 0x0b",0,0,0}, + {"Postgres_Unknown 0x0c",0,0,0}, + {"Postgres_Unknown 0x0d",0,0,0}, + {"Postgres_Unknown 0x0e",0,0,0}, + {"Serial",0,0,0}, + {"Postgres_Unknown 0x10",0,0,0}, +}; +/* MySQL data types */ +static MdbBackendType mdb_mysql_types[] = { + {"Text",1,0,1}, + {"char",0,0,0}, + {"int",0,0,0}, + {"int",0,0,0}, + {"int",0,0,0}, + {"float",0,0,0}, + {"float",0,0,0}, + {"float",0,0,0}, + {"date",0,0,1}, + {"varchar",1,0,1}, + {"varchar",1,0,1}, + {"varchar",1,0,1}, + {"text",1,0,1}, + {"blob",0,0,0}, + {"text",1,0,1}, + {"numeric",1,1,0}, + {"numeric",1,1,0}, +}; + +static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data); + +char *mdb_get_coltype_string(MdbBackend *backend, int col_type) +{ + static char buf[16]; + + if (col_type > 0x10 ) { + // return NULL; + snprintf(buf,sizeof(buf), "type %04x", col_type); + return buf; + } else { + return backend->types_table[col_type].name; + } +} + +int mdb_coltype_takes_length(MdbBackend *backend, int col_type) +{ + return backend->types_table[col_type].needs_length; +} + +/** + * mdb_init_backends + * + * Initializes the mdb_backends hash and loads the builtin backends. + * Use mdb_remove_backends() to destroy this hash when done. + */ +void mdb_init_backends() +{ + mdb_backends = g_hash_table_new(g_str_hash, g_str_equal); + + mdb_register_backend(mdb_access_types, "access"); + mdb_register_backend(mdb_sybase_types, "sybase"); + mdb_register_backend(mdb_oracle_types, "oracle"); + mdb_register_backend(mdb_postgres_types, "postgres"); + mdb_register_backend(mdb_mysql_types, "mysql"); +} +void mdb_register_backend(MdbBackendType *backend_type, char *backend_name) +{ + MdbBackend *backend = (MdbBackend *) g_malloc0(sizeof(MdbBackend)); + backend->types_table = backend_type; + g_hash_table_insert(mdb_backends, backend_name, backend); +} + +/** + * mdb_remove_backends + * + * Removes all entries from and destroys the mdb_backends hash. + */ +void mdb_remove_backends() +{ + g_hash_table_foreach_remove(mdb_backends, mdb_drop_backend, NULL); + g_hash_table_destroy(mdb_backends); +} +static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data) +{ + MdbBackend *backend = (MdbBackend *)value; + g_free (backend); + return TRUE; +} + +/** + * mdb_set_default_backend + * @mdb: Handle to open MDB database file + * @backend_name: Name of the backend to set as default + * + * Sets the default backend of the handle @mdb to @backend_name. + * + * Returns: 1 if successful, 0 if unsuccessful. + */ +int mdb_set_default_backend(MdbHandle *mdb, char *backend_name) +{ + MdbBackend *backend; + + backend = (MdbBackend *) g_hash_table_lookup(mdb_backends, backend_name); + if (backend) { + mdb->default_backend = backend; + mdb->backend_name = (char *) g_strdup(backend_name); + is_init = 0; + return 1; + } else { + return 0; + } +} + +/** + * mdb_get_relationships + * @mdb: Handle to open MDB database file + * + * Generates relationships by reading the MSysRelationships table. + * 'szColumn' contains the column name of the child table. + * 'szObject' contains the table name of the child table. + * 'szReferencedColumn' contains the column name of the parent table. + * 'szReferencedObject' contains the table name of the parent table. + * + * Returns: a string stating that relationships are not supported for the + * selected backend, or a string containing SQL commands for setting up + * the relationship, tailored for the selected backend. The caller is + * responsible for freeing this string. + */ +char *mdb_get_relationships(MdbHandle *mdb) +{ + unsigned int i; + gchar *text = NULL; /* String to be returned */ + static char *bound[4]; /* Bound values */ + static MdbTableDef *table; /* Relationships table */ + int backend = 0; /* Backends: 1=oracle */ + + if (strncmp(mdb->backend_name,"oracle",6) == 0) { + backend = 1; + } else { + if (is_init == 0) { /* the first time through */ + is_init = 1; + return (char *) g_strconcat( + "-- relationships are not supported for ", + mdb->backend_name, NULL); + } else { /* the second time through */ + is_init = 0; + return NULL; + } + } + + if (is_init == 0) { + table = mdb_read_table_by_name(mdb, "MSysRelationships", MDB_TABLE); + if ((!table) || (table->num_rows == 0)) { + return NULL; + } + + mdb_read_columns(table); + for (i=0;i<4;i++) { + bound[i] = (char *) g_malloc0(MDB_BIND_SIZE); + } + mdb_bind_column_by_name(table, "szColumn", bound[0]); + mdb_bind_column_by_name(table, "szObject", bound[1]); + mdb_bind_column_by_name(table, "szReferencedColumn", bound[2]); + mdb_bind_column_by_name(table, "szReferencedObject", bound[3]); + mdb_rewind_table(table); + + is_init = 1; + } + else if (table->cur_row >= table->num_rows) { /* past the last row */ + for (i=0;i<4;i++) + g_free(bound[i]); + is_init = 0; + return NULL; + } + + if (!mdb_fetch_row(table)) { + for (i=0;i<4;i++) + g_free(bound[i]); + is_init = 0; + return NULL; + } + + switch (backend) { + case 1: /* oracle */ + text = g_strconcat("alter table ", bound[1], + " add constraint ", bound[3], "_", bound[1], + " foreign key (", bound[0], ")" + " references ", bound[3], "(", bound[2], ")", NULL); + break; + } + + return (char *)text; +} + diff --git a/plugins/poi_geodownload/libmdb/catalog.c b/plugins/poi_geodownload/libmdb/catalog.c new file mode 100644 index 00000000..dc08abdd --- /dev/null +++ b/plugins/poi_geodownload/libmdb/catalog.c @@ -0,0 +1,138 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +char * +mdb_get_objtype_string(int obj_type) +{ +static char *type_name[] = {"Form", + "Table", + "Macro", + "System Table", + "Report", + "Query", + "Linked Table", + "Module", + "Relationship", + "Unknown 0x09", + "Unknown 0x0a", + "Database" + }; + + if (obj_type > 11) { + return NULL; + } else { + return type_name[obj_type]; + } +} + +void mdb_free_catalog(MdbHandle *mdb) +{ + unsigned int i; + + if (!mdb->catalog) return; + for (i=0; i<mdb->catalog->len; i++) + g_free (g_ptr_array_index(mdb->catalog, i)); + g_ptr_array_free(mdb->catalog, TRUE); + mdb->catalog = NULL; +} + +GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype) +{ + MdbCatalogEntry *entry, msysobj; + MdbTableDef *table; + char obj_id[256]; + char obj_name[256]; + char obj_type[256]; + char obj_flags[256]; + int type; + + if (mdb->catalog) mdb_free_catalog(mdb); + mdb->catalog = g_ptr_array_new(); + mdb->num_catalog = 0; + + /* dummy up a catalog entry so we may read the table def */ + memset(&msysobj, 0, sizeof(MdbCatalogEntry)); + msysobj.mdb = mdb; + msysobj.object_type = MDB_TABLE; + msysobj.table_pg = 2; + strcpy(msysobj.object_name, "MSysObjects"); + + /* mdb_table_dump(&msysobj); */ + + table = mdb_read_table(&msysobj); + if (!table) return NULL; + + mdb_read_columns(table); + + mdb_bind_column_by_name(table, "Id", obj_id); + mdb_bind_column_by_name(table, "Name", obj_name); + mdb_bind_column_by_name(table, "Type", obj_type); + mdb_bind_column_by_name(table, "Flags", obj_flags); + + mdb_rewind_table(table); + + while (mdb_fetch_row(table)) { + type = atoi(obj_type); + if (objtype==MDB_ANY || type == objtype) { + // fprintf(stdout, "obj_id: %10ld objtype: %-3d obj_name: %s\n", + // (atol(obj_id) & 0x00FFFFFF), type, obj_name); + entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry)); + entry->mdb = mdb; + strcpy(entry->object_name, obj_name); + entry->object_type = (type & 0x7F); + entry->table_pg = atol(obj_id) & 0x00FFFFFF; + entry->flags = atol(obj_flags); + mdb->num_catalog++; + g_ptr_array_add(mdb->catalog, entry); + } + } + //mdb_dump_catalog(mdb, MDB_TABLE); + + mdb_free_tabledef(table); + + return mdb->catalog; +} + +void +mdb_dump_catalog(MdbHandle *mdb, int obj_type) +{ + unsigned int i; + MdbCatalogEntry *entry; + + mdb_read_catalog(mdb, obj_type); + for (i=0;i<mdb->num_catalog;i++) { + entry = g_ptr_array_index(mdb->catalog,i); + if (obj_type==MDB_ANY || entry->object_type==obj_type) { + fprintf(stdout,"Type: %-10s Name: %-18s T pg: %04x KKD pg: %04x row: %2d\n", + mdb_get_objtype_string(entry->object_type), + entry->object_name, + (unsigned int) entry->table_pg, + (unsigned int) entry->kkd_pg, + entry->kkd_rowid); + } + } + return; +} + diff --git a/plugins/poi_geodownload/libmdb/data.c b/plugins/poi_geodownload/libmdb/data.c new file mode 100644 index 00000000..e50e57db --- /dev/null +++ b/plugins/poi_geodownload/libmdb/data.c @@ -0,0 +1,856 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" +#include "time.h" +#include "math.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#define OFFSET_MASK 0x1fff + +char *mdb_money_to_string(MdbHandle *mdb, int start, char *s); +static int _mdb_attempt_bind(MdbHandle *mdb, + MdbColumn *col, unsigned char isnull, int offset, int len); +static char *mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale); +int mdb_copy_ole(MdbHandle *mdb, char *dest, int start, int size); + +static char date_fmt[64] = "%x %X"; + +void mdb_set_date_fmt(const char *fmt) +{ + date_fmt[63] = 0; + strncpy(date_fmt, fmt, 63); +} + +void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr) +{ +MdbColumn *col; + + /* + ** the column arrary is 0 based, so decrement to get 1 based parameter + */ + col=g_ptr_array_index(table->columns, col_num - 1); + col->bind_ptr = bind_ptr; +} +int +mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr) +{ + unsigned int i; + int col_num = -1; + MdbColumn *col; + + for (i=0;i<table->num_cols;i++) { + col=g_ptr_array_index(table->columns,i); + if (!strcmp(col->name,col_name)) { + col_num = col->col_num + 1; + mdb_bind_column(table, col_num, bind_ptr); + break; + } + } + + return col_num; +} +void mdb_bind_len(MdbTableDef *table, int col_num, int *len_ptr) +{ +MdbColumn *col; + + col=g_ptr_array_index(table->columns, col_num - 1); + col->len_ptr = len_ptr; +} + +/** + * mdb_find_pg_row + * @mdb: Database file handle + * @pg_row: Lower byte contains the row number, the upper three contain page + * @buf: Pointer for returning a pointer to the page + * @off: Pointer for returning an offset to the row + * @len: Pointer for returning the length of the row + * + * Returns: 0 on success. 1 on failure. + */ +int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, int *len) +{ + unsigned int pg = pg_row >> 8; + unsigned int row = pg_row & 0xff; + + if (mdb_read_alt_pg(mdb, pg) != mdb->fmt->pg_size) + return 1; + mdb_swap_pgbuf(mdb); + *off = mdb_pg_get_int16(mdb, mdb->fmt->row_count_offset + 2 + (row*2)); + *len = mdb_find_end_of_row(mdb, row) - *off + 1; + mdb_swap_pgbuf(mdb); + *buf = mdb->alt_pg_buf; + return 0; +} + +int +mdb_find_end_of_row(MdbHandle *mdb, int row) +{ + MdbFormatConstants *fmt = mdb->fmt; + int row_end; + + /* Search the previous "row start" values for the first non-'lookupflag' one. + * If we don't find one, then the end of the page is the correct value. + */ +#if 1 + if (row==0) { + row_end = fmt->pg_size - 1; + } else { + row_end = (mdb_pg_get_int16(mdb, ((fmt->row_count_offset + 2) + (row - 1) * 2)) & OFFSET_MASK) - 1; + } + return row_end; +#else + int i, row_start; + + /* if lookupflag is not set, it's good (deleteflag is ok) */ + for (i = row - 1; i >= 0; i--) { + row_start = mdb_pg_get_int16(mdb, ((fmt->row_count_offset + 2) + i * 2)); + if (!(row_start & 0x8000)) { + break; + } + } + + if (i == -1) { + row_end = fmt->pg_size - 1; + } else { + row_end = (row_start & OFFSET_MASK) - 1; + } + return row_end; +#endif +} +int mdb_is_null(unsigned char *null_mask, int col_num) +{ +int byte_num = (col_num - 1) / 8; +int bit_num = (col_num - 1) % 8; + + if ((1 << bit_num) & null_mask[byte_num]) { + return 0; + } else { + return 1; + } +} +/* bool has to be handled specially because it uses the null bit to store its +** value*/ +static int +mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value) +{ + + col->cur_value_len = value; + if (col->bind_ptr) { + strcpy(col->bind_ptr, value ? "0" : "1"); + } + + return 0; +} +static int mdb_xfer_bound_ole(MdbHandle *mdb, int start, MdbColumn *col, int len) +{ + int ret = 0; + if (len) { + col->cur_value_start = start; + col->cur_value_len = len; + } else { + col->cur_value_start = 0; + col->cur_value_len = 0; + } + if (col->bind_ptr || col->len_ptr) { + //ret = mdb_copy_ole(mdb, col->bind_ptr, start, len); + memcpy(col->bind_ptr, &mdb->pg_buf[start], MDB_MEMO_OVERHEAD); + } + if (col->len_ptr) { + *col->len_ptr = MDB_MEMO_OVERHEAD; + } + return ret; +} +static int mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len) +{ +int ret; + //if (!strcmp("Name",col->name)) { + //printf("start %d %d\n",start, len); + //} + if (len) { + col->cur_value_start = start; + col->cur_value_len = len; + } else { + col->cur_value_start = 0; + col->cur_value_len = 0; + } + if (col->bind_ptr) { + if (!len) { + strcpy(col->bind_ptr, ""); + } else if (col->col_type == MDB_NUMERIC) { + //fprintf(stdout,"len %d size %d\n",len, col->col_size); + char *str = mdb_num_to_string(mdb, start, col->col_type, + col->col_prec, col->col_scale); + strcpy(col->bind_ptr, str); + g_free(str); + } else { + //fprintf(stdout,"len %d size %d\n",len, col->col_size); + char *str = mdb_col_to_string(mdb, mdb->pg_buf, start, + col->col_type, len); + strcpy(col->bind_ptr, str); + + } + ret = strlen(col->bind_ptr); + if (col->len_ptr) { + *col->len_ptr = ret; + } + return ret; + } + return 0; +} +int mdb_read_row(MdbTableDef *table, unsigned int row) +{ + MdbHandle *mdb = table->entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + MdbColumn *col; + unsigned int i; + int rc; + int row_start, row_end; + int delflag, lookupflag; + MdbField fields[256]; + int num_fields; + + if (table->num_rows <= row) + return 0; + + row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (row*2)); + row_end = mdb_find_end_of_row(mdb, row); + + delflag = lookupflag = 0; + if (row_start & 0x8000) lookupflag++; + if (row_start & 0x4000) delflag++; + row_start &= OFFSET_MASK; /* remove flags */ +#if MDB_DEBUG + fprintf(stdout,"Row %d bytes %d to %d %s %s\n", + row, row_start, row_end, + lookupflag ? "[lookup]" : "", + delflag ? "[delflag]" : ""); +#endif + + if (!table->noskip_del && delflag) { + row_end = row_start-1; + return 0; + } + + num_fields = mdb_crack_row(table, row_start, row_end, fields); + if (!mdb_test_sargs(table, fields, num_fields)) return 0; + +#if MDB_DEBUG + fprintf(stdout,"sarg test passed row %d \n", row); +#endif + +#if MDB_DEBUG + buffer_dump(mdb->pg_buf, row_start, row_end); +#endif + + /* take advantage of mdb_crack_row() to clean up binding */ + /* use num_cols instead of num_fields -- bsb 03/04/02 */ + for (i = 0; i < table->num_cols; i++) { + col = g_ptr_array_index(table->columns,fields[i].colnum); + rc = _mdb_attempt_bind(mdb, col, fields[i].is_null, + fields[i].start, fields[i].siz); + } + + return 1; +} +static int _mdb_attempt_bind(MdbHandle *mdb, + MdbColumn *col, + unsigned char isnull, + int offset, + int len) +{ + if (col->col_type == MDB_BOOL) { + mdb_xfer_bound_bool(mdb, col, isnull); + } else if (isnull) { + mdb_xfer_bound_data(mdb, 0, col, 0); + } else if (col->col_type == MDB_OLE) { + mdb_xfer_bound_ole(mdb, offset, col, len); + } else { + //if (!mdb_test_sargs(mdb, col, offset, len)) { + //return 0; + //} + mdb_xfer_bound_data(mdb, offset, col, len); + } + return 1; +} +int mdb_read_next_dpg(MdbTableDef *table) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + int next_pg; + +#ifndef SLOW_READ + next_pg = mdb_map_find_next(mdb, table->usage_map, + table->map_sz, table->cur_phys_pg); + + if (next_pg >= 0) { + if (mdb_read_pg(mdb, next_pg)) { + table->cur_phys_pg = next_pg; + return table->cur_phys_pg; + } else { + return 0; + } + } + fprintf(stderr, "Warning: defaulting to brute force read\n"); +#endif + /* can't do a fast read, go back to the old way */ + do { + if (!mdb_read_pg(mdb, table->cur_phys_pg++)) + return 0; + } while (mdb->pg_buf[0]!=0x01 || mdb_pg_get_int32(mdb, 4)!=entry->table_pg); + /* fprintf(stderr,"returning new page %ld\n", table->cur_phys_pg); */ + return table->cur_phys_pg; +} +int mdb_rewind_table(MdbTableDef *table) +{ + table->cur_pg_num=0; + table->cur_phys_pg=0; + table->cur_row=0; + + return 0; +} +int +mdb_fetch_row(MdbTableDef *table) +{ + MdbHandle *mdb = table->entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + unsigned int rows; + int rc; + guint32 pg; + + if (table->num_rows==0) + return 0; + + /* initialize */ + if (!table->cur_pg_num) { + table->cur_pg_num=1; + table->cur_row=0; + if ((!table->is_temp_table)&&(table->strategy!=MDB_INDEX_SCAN)) + if (!mdb_read_next_dpg(table)) return 0; + } + + do { + if (table->is_temp_table) { + GPtrArray *pages = table->temp_table_pages; + rows = mdb_get_int16( + g_ptr_array_index(pages, table->cur_pg_num-1), + fmt->row_count_offset); + if (table->cur_row >= rows) { + table->cur_row = 0; + table->cur_pg_num++; + if (table->cur_pg_num > pages->len) + return 0; + } + memcpy(mdb->pg_buf, + g_ptr_array_index(pages, table->cur_pg_num-1), + fmt->pg_size); + } else if (table->strategy==MDB_INDEX_SCAN) { + + if (!mdb_index_find_next(table->mdbidx, table->scan_idx, table->chain, &pg, (guint16 *) &(table->cur_row))) { + mdb_index_scan_free(table); + return 0; + } + mdb_read_pg(mdb, pg); + } else { + rows = mdb_pg_get_int16(mdb,fmt->row_count_offset); + + /* if at end of page, find a new page */ + if (table->cur_row >= rows) { + table->cur_row=0; + + if (!mdb_read_next_dpg(table)) { + return 0; + } + } + } + + /* printf("page %d row %d\n",table->cur_phys_pg, table->cur_row); */ + rc = mdb_read_row(table, table->cur_row); + table->cur_row++; + } while (!rc); + + return 1; +} +void mdb_data_dump(MdbTableDef *table) +{ + unsigned int i; + char *bound_values[MDB_MAX_COLS]; + + for (i=0;i<table->num_cols;i++) { + bound_values[i] = (char *) g_malloc(256); + mdb_bind_column(table, i+1, bound_values[i]); + } + mdb_rewind_table(table); + while (mdb_fetch_row(table)) { + for (i=0;i<table->num_cols;i++) { + fprintf(stdout, "column %d is %s\n", i+1, bound_values[i]); + } + } + for (i=0;i<table->num_cols;i++) { + g_free(bound_values[i]); + } +} + +int mdb_is_fixed_col(MdbColumn *col) +{ + return col->is_fixed; +} +#if 0 +static char *mdb_data_to_hex(MdbHandle *mdb, char *text, int start, int size) +{ +int i; + + for (i=start; i<start+size; i++) { + sprintf(&text[(i-start)*2],"%02x", mdb->pg_buf[i]); + } + text[(i-start)*2]='\0'; + + return text; +} +#endif +int +mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr) +{ + guint16 ole_len; + guint16 ole_flags; + char *buf; + int pg_row, row_start; + int len; + + ole_len = mdb_get_int16(ole_ptr, 0); + ole_flags = mdb_get_int16(ole_ptr, 2); + + if (ole_flags == 0x8000) { + /* inline fields don't have a next */ + return 0; + } else if (ole_flags == 0x4000) { + /* 0x4000 flagged ole's are contained on one page and thus + * should be handled entirely with mdb_ole_read() */ + return 0; + } else if (ole_flags == 0x0000) { + pg_row = (col->cur_blob_pg << 8) & col->cur_blob_row; + if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { + return 0; + } + if (col->bind_ptr) + memcpy(col->bind_ptr, buf + row_start, len); + pg_row = mdb_get_int32(buf, row_start); + col->cur_blob_pg = pg_row >> 8; + col->cur_blob_row = pg_row & 0xff; + + return len; + } + return 0; +} +int +mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size) +{ + guint16 ole_len; + guint16 ole_flags; + char *buf; + int pg_row, row_start; + int len; + + ole_len = mdb_get_int16(ole_ptr, 0); + ole_flags = mdb_get_int16(ole_ptr, 2); + mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %08x", + ole_len, ole_flags); + + col->chunk_size = chunk_size; + + if (ole_flags == 0x8000) { + /* inline ole field, if we can satisfy it, then do it */ + len = col->cur_value_len - MDB_MEMO_OVERHEAD; + if (chunk_size >= len) { + if (col->bind_ptr) + memcpy(col->bind_ptr, + &mdb->pg_buf[col->cur_value_start + + MDB_MEMO_OVERHEAD], + len); + return len; + } else { + return 0; + } + } else if (ole_flags == 0x4000) { + pg_row = mdb_get_int32(ole_ptr, 4); + col->cur_blob_pg = pg_row >> 8; + col->cur_blob_row = pg_row & 0xff; + mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", + col->cur_blob_row, col->cur_blob_pg); + + if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { + return 0; + } + mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); + + if (col->bind_ptr) { + memcpy(col->bind_ptr, buf + row_start, len); + if (mdb_get_option(MDB_DEBUG_OLE)) + buffer_dump(col->bind_ptr, 0, 16); + } + return len; + } else if (ole_flags == 0x0000) { + pg_row = mdb_get_int32(ole_ptr, 4); + col->cur_blob_pg = pg_row >> 8; + col->cur_blob_row = pg_row & 0xff; + + if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { + return 0; + } + + if (col->bind_ptr) + memcpy(col->bind_ptr, buf + row_start, len); + + pg_row = mdb_get_int32(buf, row_start); + col->cur_blob_pg = pg_row >> 8; + col->cur_blob_row = pg_row & 0xff; + + return len; + } else { + fprintf(stderr,"Unhandled ole field flags = %04x\n", ole_flags); + return 0; + } +} +int mdb_copy_ole(MdbHandle *mdb, char *dest, int start, int size) +{ + guint16 ole_len; + guint16 ole_flags; + guint32 row_start, pg_row; + guint32 len; + char *buf; + + if (size<MDB_MEMO_OVERHEAD) { + return 0; + } + + /* The 16 bit integer at offset 0 is the length of the memo field. + * The 32 bit integer at offset 4 contains page and row information. + */ + ole_len = mdb_pg_get_int16(mdb, start); + ole_flags = mdb_pg_get_int16(mdb, start+2); + + if (ole_flags == 0x8000) { + len = size - MDB_MEMO_OVERHEAD; + /* inline ole field */ + if (dest) memcpy(dest, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD], + size - MDB_MEMO_OVERHEAD); + return len; + } else if (ole_flags == 0x4000) { + pg_row = mdb_get_int32(mdb->pg_buf, start+4); + mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8); + + if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { + return 0; + } + mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", + pg_row & 0xff, row_start, len); + + if (dest) + memcpy(dest, buf + row_start, len); + return len; + } else if (ole_flags == 0x0000) { + int cur = 0; + pg_row = mdb_get_int32(mdb->pg_buf, start+4); + mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8); + do { + if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { + return 0; + } + + mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", + pg_row & 0xff, row_start, len); + + if (dest) + memcpy(dest+cur, buf + row_start + 4, len - 4); + cur += len - 4; + + /* find next lval page */ + pg_row = mdb_get_int32(buf, row_start); + } while ((pg_row >> 8)); + return cur; + } else { + fprintf(stderr,"Unhandled ole field flags = %04x\n", ole_flags); + return 0; + } +} +static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) +{ + guint16 memo_len; + static char text[MDB_BIND_SIZE]; + guint16 memo_flags; + guint32 row_start, pg_row; + guint32 len; + char *buf; + + if (size<MDB_MEMO_OVERHEAD) { + return ""; + } + +#if MDB_DEBUG + buffer_dump(mdb->pg_buf, start, start + 12); +#endif + + /* The 16 bit integer at offset 0 is the length of the memo field. + * The 32 bit integer at offset 4 contains page and row information. + */ + memo_len = mdb_pg_get_int16(mdb, start); + memo_flags = mdb_pg_get_int16(mdb, start+2); + + if (memo_flags & 0x8000) { + /* inline memo field */ + strncpy(text, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD], + size - MDB_MEMO_OVERHEAD); + text[size - MDB_MEMO_OVERHEAD]='\0'; + return text; + } else if (memo_flags & 0x4000) { + pg_row = mdb_get_int32(mdb->pg_buf, start+4); +#if MDB_DEBUG + printf("Reading LVAL page %06x\n", pg_row >> 8); +#endif + if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { + return ""; + } +#if MDB_DEBUG + printf("row num %d start %d len %d\n", + pg_row & 0xff, row_start, len); + buffer_dump(mdb->pg_buf, row_start, row_start + len); +#endif + if (IS_JET3(mdb)) { + strncpy(text, buf + row_start, len); + text[len]='\0'; + } else { + mdb_unicode2ascii(mdb, buf, row_start, len, text); + } + return text; + } else { /* if (memo_flags == 0x0000) { */ + pg_row = mdb_get_int32(mdb->pg_buf, start+4); +#if MDB_DEBUG + printf("Reading LVAL page %06x\n", pg_row >> 8); +#endif + text[0]='\0'; + do { + if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { + return ""; + } +#if MDB_DEBUG + printf("row num %d start %d len %d\n", + pg_row & 0xff, row_start, len); +#endif + strncat(text, buf + row_start + 4, + strlen(text) + len - 4 > MDB_BIND_SIZE ? + MDB_BIND_SIZE - strlen(text) : len - 4); + + /* find next lval page */ + pg_row = mdb_get_int32(mdb->pg_buf, row_start); + } while ((pg_row >> 8)); + return text; +/* + } else { + fprintf(stderr,"Unhandled memo field flags = %04x\n", memo_flags); + return ""; +*/ + } +} +static char * +mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale) +{ + char *text; + gint32 l; + + memcpy(&l, mdb->pg_buf+start+13, 4); + + text = (char *) g_malloc(prec+2); + sprintf(text, "%0*" G_GINT32_FORMAT, prec, GINT32_FROM_LE(l)); + if (scale) { + memmove(text+prec-scale, text+prec-scale+1, scale+1); + text[prec-scale] = '.'; + } + return text; +} + +static int trim_trailing_zeros(char * buff, int n) +{ + char * p = buff + n - 1; + + while (p >= buff && *p == '0') + *p-- = '\0'; + + if (*p == '.') + *p = '\0'; + + return 0; +} + +char *mdb_col_to_string(MdbHandle *mdb, unsigned char *buf, int start, int datatype, int size) +{ + /* FIX ME -- not thread safe */ + static char text[MDB_BIND_SIZE]; + time_t t; + int n; + float tf; + double td; + + switch (datatype) { + case MDB_BOOL: + /* shouldn't happen. bools are handled specially + ** by mdb_xfer_bound_bool() */ + break; + case MDB_BYTE: + sprintf(text,"%d",mdb_get_byte(buf, start)); + return text; + break; + case MDB_INT: + sprintf(text,"%ld",(long)mdb_get_int16(buf, start)); + return text; + break; + case MDB_LONGINT: + sprintf(text,"%ld",mdb_get_int32(buf, start)); + return text; + break; + case MDB_FLOAT: + tf = mdb_get_single(mdb->pg_buf, start); + n = sprintf(text,"%.*f",FLT_DIG - (int)ceil(log10(tf)), tf); + trim_trailing_zeros(text, n); + return text; + break; + case MDB_DOUBLE: + td = mdb_get_double(mdb->pg_buf, start); + n = sprintf(text,"%.*f",DBL_DIG - (int)ceil(log10(td)), td); + trim_trailing_zeros(text, n); + return text; + break; + case MDB_TEXT: + if (size<0) { + return ""; + } + if (IS_JET4(mdb)) { +/* + int i; + for (i=0;i<size;i++) { + fprintf(stdout, "%c %02x ", mdb->pg_buf[start+i], mdb->pg_buf[start+i]); + } + fprintf(stdout, "\n"); +*/ + mdb_unicode2ascii(mdb, mdb->pg_buf, start, size, text); + } else { + strncpy(text, &buf[start], size); + text[size]='\0'; + } + return text; + break; + case MDB_SDATETIME: + td = mdb_get_double(mdb->pg_buf, start); + if (td > 1) { + t = (long int)((td - 25569.0) * 86400.0); + } else { + t = (long int)(td * 86400.0); + } + strftime(text, MDB_BIND_SIZE, date_fmt, (struct tm*)gmtime(&t)); + return text; + + break; + case MDB_MEMO: + return mdb_memo_to_string(mdb, start, size); + break; + case MDB_MONEY: + mdb_money_to_string(mdb, start, text); + return text; + case MDB_NUMERIC: + break; + default: + return ""; + break; + } + return NULL; +} +int mdb_col_disp_size(MdbColumn *col) +{ + switch (col->col_type) { + case MDB_BOOL: + return 1; + break; + case MDB_BYTE: + return 4; + break; + case MDB_INT: + return 6; + break; + case MDB_LONGINT: + return 11; + break; + case MDB_FLOAT: + return 10; + break; + case MDB_DOUBLE: + return 10; + break; + case MDB_TEXT: + return col->col_size; + break; + case MDB_SDATETIME: + return 20; + break; + case MDB_MEMO: + return 255; + break; + case MDB_MONEY: + return 21; + break; + } + return 0; +} +int mdb_col_fixed_size(MdbColumn *col) +{ + switch (col->col_type) { + case MDB_BOOL: + return 1; + break; + case MDB_BYTE: + return -1; + break; + case MDB_INT: + return 2; + break; + case MDB_LONGINT: + return 4; + break; + case MDB_FLOAT: + return 4; + break; + case MDB_DOUBLE: + return 8; + break; + case MDB_TEXT: + return -1; + break; + case MDB_SDATETIME: + return 4; + break; + case MDB_MEMO: + return -1; + break; + case MDB_MONEY: + return 8; + break; + } + return 0; +} diff --git a/plugins/poi_geodownload/libmdb/dump.c b/plugins/poi_geodownload/libmdb/dump.c new file mode 100644 index 00000000..7ee17f9a --- /dev/null +++ b/plugins/poi_geodownload/libmdb/dump.c @@ -0,0 +1,39 @@ +#include <ctype.h> +#include <string.h> +#include <stdio.h> + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +void buffer_dump(const unsigned char* buf, int start, int end) +{ + char asc[20]; + int j, k; + + memset(asc, 0, sizeof(asc)); + k = 0; + for (j=start; j<=end; j++) { + if (k == 0) { + fprintf(stdout, "%04x ", j); + } + fprintf(stdout, "%02x ", buf[j]); + asc[k] = isprint(buf[j]) ? buf[j] : '.'; + k++; + if (k == 8) { + fprintf(stdout, " "); + } + if (k == 16) { + fprintf(stdout, " %s\n", asc); + memset(asc, 0, sizeof(asc)); + k = 0; + } + } + for (j=k; j<16; j++) { + fprintf(stdout, " "); + } + if (k < 8) { + fprintf(stdout, " "); + } + fprintf(stdout, " %s\n", asc); +} diff --git a/plugins/poi_geodownload/libmdb/file.c b/plugins/poi_geodownload/libmdb/file.c new file mode 100644 index 00000000..941830c5 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/file.c @@ -0,0 +1,376 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/* +typedef struct { + int pg_size; + guint16 row_count_offset; + guint16 tab_num_rows_offset; + guint16 tab_num_cols_offset; + guint16 tab_num_idxs_offset; + guint16 tab_num_ridxs_offset; + guint16 tab_usage_map_offset; + guint16 tab_first_dpg_offset; + guint16 tab_cols_start_offset; + guint16 tab_ridx_entry_size; + guint16 col_fixed_offset; + guint16 col_size_offset; + guint16 col_num_offset; + guint16 tab_col_entry_size; + guint16 tab_free_map_offset; + guint16 tab_col_offset_var; + guint16 tab_col_offset_fixed; + guint16 tab_row_col_num_offset; +} MdbFormatConstants; +*/ +MdbFormatConstants MdbJet4Constants = { + 4096, 0x0c, 16, 45, 47, 51, 55, 56, 63, 12, 15, 23, 5, 25, 59, 7, 21, 9 +}; +MdbFormatConstants MdbJet3Constants = { + 2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5 /* not sure on 5, need to check */ +}; + +static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg); + +/** + * mdb_find_file: + * @filename: path to MDB (database) file + * + * Finds and returns the absolute path to an MDB file. Function will first try + * to fstat file as passed, then search through the $MDBPATH if not found. + * + * Return value: gchar pointer to absolute path. Caller is responsible for + * freeing. + **/ + +static gchar *mdb_find_file(char *file_name) +{ + struct stat status; + gchar *mdbpath, **dir, *tmpfname; + unsigned int i = 0; + + /* try the provided file name first */ + if (!stat(file_name, &status)) { + return g_strdup(file_name); + } + + /* Now pull apart $MDBPATH and try those */ + mdbpath = (gchar *) getenv("MDBPATH"); + /* no path, can't find file */ + if (!mdbpath || !strlen(mdbpath)) return NULL; + + dir = g_strsplit(mdbpath, ":", 0); + while (dir[i]) { + if (!strlen(dir[i])) continue; + tmpfname = g_strconcat(dir[i++], "/", file_name, NULL); + if (!stat(tmpfname, &status)) { + g_strfreev(dir); + return tmpfname; + } + g_free(tmpfname); + } + g_strfreev(dir); + return NULL; +} +/** + * mdb_open: + * @filename: path to MDB (database) file + * @flags: MDB_NOFLAGS for read-only, MDB_WRITABLE for read/write + * + * Opens an MDB file and returns an MdbHandle to it. MDB File may be relative + * to the current directory, a full path to the file, or relative to a + * component of $MDBPATH. + * + * Return value: pointer to MdbHandle structure. + **/ +MdbHandle *mdb_open(char *filename, MdbFileFlags flags) +{ + MdbHandle *mdb; + + mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle)); + mdb_set_default_backend(mdb, "access"); + /* need something to bootstrap with, reassign after page 0 is read */ + mdb->fmt = &MdbJet3Constants; + mdb->f = (MdbFile *) g_malloc0(sizeof(MdbFile)); + mdb->f->refs = 1; + mdb->f->fd = -1; + mdb->f->filename = (char *) mdb_find_file(filename); + if (!mdb->f->filename) { + fprintf(stderr, "Can't alloc filename\n"); + mdb_close(mdb); + return NULL; + } + if (flags & MDB_WRITABLE) { + mdb->f->writable = TRUE; + mdb->f->fd = open(mdb->f->filename,O_RDWR); + } else { + mdb->f->fd = open(mdb->f->filename,O_RDONLY); + } + + if (mdb->f->fd==-1) { + fprintf(stderr,"Couldn't open file %s\n",mdb->f->filename); + mdb_close(mdb); + return NULL; + } + if (!mdb_read_pg(mdb, 0)) { + fprintf(stderr,"Couldn't read first page.\n"); + mdb_close(mdb); + return NULL; + } + if (mdb->pg_buf[0] != 0) { + mdb_close(mdb); + return NULL; + } + mdb->f->jet_version = mdb_pg_get_int32(mdb, 0x14); + if (IS_JET4(mdb)) { + mdb->fmt = &MdbJet4Constants; + } else if (IS_JET3(mdb)) { + mdb->fmt = &MdbJet3Constants; + } else { + fprintf(stderr,"Unknown Jet version.\n"); + mdb_close(mdb); + return NULL; + } + + return mdb; +} + +/** + * mdb_close: + * @mdb: Handle to open MDB database file + * + * Dereferences MDB file, closes if reference count is 0, and destroys handle. + * + **/ +void +mdb_close(MdbHandle *mdb) +{ + if (!mdb) return; + mdb_free_catalog(mdb); + g_free(mdb->stats); + g_free(mdb->backend_name); + + if (mdb->f) { + if (mdb->f->refs > 1) { + mdb->f->refs--; + } else { + if (mdb->f->fd != -1) close(mdb->f->fd); + g_free(mdb->f->filename); + g_free(mdb->f); + } + } + + g_free(mdb); +} +/** + * mdb_clone_handle: + * @mdb: Handle to open MDB database file + * + * Clones an existing database handle. Cloned handle shares the file descriptor + * but has its own page buffer, page position, and similar internal variables. + * + * Return value: new handle to the database. + */ +MdbHandle *mdb_clone_handle(MdbHandle *mdb) +{ + MdbHandle *newmdb; + MdbCatalogEntry *entry, *data; + unsigned int i; + + newmdb = (MdbHandle *) g_memdup(mdb, sizeof(MdbHandle)); + newmdb->stats = NULL; + newmdb->catalog = g_ptr_array_new(); + for (i=0;i<mdb->num_catalog;i++) { + entry = g_ptr_array_index(mdb->catalog,i); + data = g_memdup(entry,sizeof(MdbCatalogEntry)); + g_ptr_array_add(newmdb->catalog, data); + } + mdb->backend_name = NULL; + if (mdb->f) { + mdb->f->refs++; + } + return newmdb; +} + +/* +** mdb_read a wrapper for read that bails if anything is wrong +*/ +ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg) +{ + ssize_t len; + + if (pg && mdb->cur_pg == pg) return mdb->fmt->pg_size; + + len = _mdb_read_pg(mdb, mdb->pg_buf, pg); + //fprintf(stderr, "read page %d type %02x\n", pg, mdb->pg_buf[0]); + mdb->cur_pg = pg; + /* kan - reset the cur_pos on a new page read */ + mdb->cur_pos = 0; /* kan */ + return len; +} +ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg) +{ + ssize_t len; + + len = _mdb_read_pg(mdb, mdb->alt_pg_buf, pg); + return len; +} +static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg) +{ + ssize_t len; + struct stat status; + off_t offset = pg * mdb->fmt->pg_size; + + fstat(mdb->f->fd, &status); + if (status.st_size < offset) { + fprintf(stderr,"offset %lu is beyond EOF\n",offset); + return 0; + } + if (mdb->stats && mdb->stats->collect) + mdb->stats->pg_reads++; + + lseek(mdb->f->fd, offset, SEEK_SET); + len = read(mdb->f->fd,pg_buf,mdb->fmt->pg_size); + if (len==-1) { + perror("read"); + return 0; + } + else if (len<mdb->fmt->pg_size) { + /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */ + return 0; + } + return len; +} +void mdb_swap_pgbuf(MdbHandle *mdb) +{ +char tmpbuf[MDB_PGSIZE]; + + memcpy(tmpbuf,mdb->pg_buf, MDB_PGSIZE); + memcpy(mdb->pg_buf,mdb->alt_pg_buf, MDB_PGSIZE); + memcpy(mdb->alt_pg_buf,tmpbuf,MDB_PGSIZE); +} + + +/* really stupid, just here for consistancy */ +unsigned char mdb_get_byte(unsigned char *buf, int offset) +{ + return buf[offset]; +} +unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset) +{ + if (offset < 0 || offset+1 > mdb->fmt->pg_size) return -1; + mdb->cur_pos++; + return mdb->pg_buf[offset]; +} + +int mdb_get_int16(unsigned char *buf, int offset) +{ + return buf[offset+1]*256+buf[offset]; +} +int mdb_pg_get_int16(MdbHandle *mdb, int offset) +{ + if (offset < 0 || offset+2 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=2; + return mdb_get_int16(mdb->pg_buf, offset); +} + +gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset) +{ + gint32 l = 0; + if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=3; + memcpy((char *)&l+1, &(mdb->pg_buf[offset]), 3); +#if 0 + printf("l=0x%08x 0x%08x\n",l,GINT32_FROM_BE(l)); +#endif + return GINT32_FROM_BE(l); +} +gint32 mdb_get_int24(unsigned char *buf, int offset) +{ + gint32 l = 0; + memcpy(&l, &buf[offset], 3); + return GINT32_FROM_LE(l); +} +gint32 mdb_pg_get_int24(MdbHandle *mdb, int offset) +{ + if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=3; + return mdb_get_int24(mdb->pg_buf, offset); +} + +long mdb_get_int32(unsigned char *buf, int offset) +{ + guint32 l; + memcpy(&l, &buf[offset], 4); + return (long)GINT32_FROM_LE(l); +} +long mdb_pg_get_int32(MdbHandle *mdb, int offset) +{ + if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=4; + return mdb_get_int32(mdb->pg_buf, offset); +} + +float mdb_get_single(unsigned char *buf, int offset) +{ + union {guint32 g; float f;} f; + memcpy(&f, &buf[offset], 4); + f.g = GUINT32_FROM_LE(f.g); + return f.f; +} +float mdb_pg_get_single(MdbHandle *mdb, int offset) +{ + if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=4; + return mdb_get_single(mdb->pg_buf, offset); +} + +double mdb_get_double(unsigned char *buf, int offset) +{ + union {guint64 g; double d;} d; + memcpy(&d, &buf[offset], 8); + d.g = GUINT64_FROM_LE(d.g); + return d.d; +} +double mdb_pg_get_double(MdbHandle *mdb, int offset) +{ + if (offset <0 || offset+8 > mdb->fmt->pg_size) return -1; + mdb->cur_pos+=8; + return mdb_get_double(mdb->pg_buf, offset); +} + + +int +mdb_set_pos(MdbHandle *mdb, int pos) +{ + if (pos<0 || pos >= mdb->fmt->pg_size) return 0; + + mdb->cur_pos=pos; + return pos; +} +int mdb_get_pos(MdbHandle *mdb) +{ + return mdb->cur_pos; +} diff --git a/plugins/poi_geodownload/libmdb/iconv.c b/plugins/poi_geodownload/libmdb/iconv.c new file mode 100644 index 00000000..9f41afe3 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/iconv.c @@ -0,0 +1,63 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +int +mdb_unicode2ascii(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest) +{ + unsigned int i; + + if (buf[offset]==0xff && buf[offset+1]==0xfe) { + strncpy(dest, &buf[offset+2], len-2); + dest[len-2]='\0'; + } else { + /* convert unicode to ascii, rather sloppily */ + for (i=0;i<len;i+=2) + dest[i/2] = buf[offset + i]; + dest[len/2]='\0'; + } + return len; +} + +int +mdb_ascii2unicode(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest) +{ + unsigned int i = 0; + + if (!buf) return 0; + + if (IS_JET3(mdb)) { + strncpy(dest, &buf[offset], len); + dest[len]='\0'; + return strlen(dest); + } + + while (i<strlen(&buf[offset]) && (i*2+2)<len) { + dest[i*2] = buf[offset+i]; + dest[i*2+1] = 0; + i++; + } + + return (i*2); +} diff --git a/plugins/poi_geodownload/libmdb/include/mdbtools.h b/plugins/poi_geodownload/libmdb/include/mdbtools.h new file mode 100644 index 00000000..186851bc --- /dev/null +++ b/plugins/poi_geodownload/libmdb/include/mdbtools.h @@ -0,0 +1,536 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _mdbtools_h_ +#define _mdbtools_h_ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <glib.h> + +#ifdef HAVE_ICONV +#include <iconv.h> +#endif + +#define MDB_DEBUG 0 + +#define MDB_PGSIZE 4096 +#define MDB_MAX_OBJ_NAME 256 +#define MDB_MAX_COLS 256 +#define MDB_MAX_IDX_COLS 10 +#define MDB_CATALOG_PG 18 +#define MDB_MEMO_OVERHEAD 12 +#define MDB_BIND_SIZE 16384 + +enum { + MDB_PAGE_DB = 0, + MDB_PAGE_DATA, + MDB_PAGE_TABLE, + MDB_PAGE_INDEX, + MDB_PAGE_LEAF, + MDB_PAGE_MAP +}; +enum { + MDB_VER_JET3 = 0, + MDB_VER_JET4 = 1 +}; +enum { + MDB_FORM = 0, + MDB_TABLE, + MDB_MACRO, + MDB_SYSTEM_TABLE, + MDB_REPORT, + MDB_QUERY, + MDB_LINKED_TABLE, + MDB_MODULE, + MDB_RELATIONSHIP, + MDB_UNKNOWN_09, + MDB_UNKNOWN_0A, + MDB_DATABASE_PROPERTY, + MDB_ANY = -1 +}; +enum { + MDB_BOOL = 0x01, + MDB_BYTE = 0x02, + MDB_INT = 0x03, + MDB_LONGINT = 0x04, + MDB_MONEY = 0x05, + MDB_FLOAT = 0x06, + MDB_DOUBLE = 0x07, + MDB_SDATETIME = 0x08, + MDB_TEXT = 0x0a, + MDB_OLE = 0x0b, + MDB_MEMO = 0x0c, + MDB_REPID = 0x0f, + MDB_NUMERIC = 0x10 +}; + +/* SARG operators */ +enum { + MDB_OR = 1, + MDB_AND, + MDB_NOT, + MDB_EQUAL, + MDB_GT, + MDB_LT, + MDB_GTEQ, + MDB_LTEQ, + MDB_LIKE, + MDB_ISNULL, + MDB_NOTNULL +}; + +typedef enum { + MDB_TABLE_SCAN, + MDB_LEAF_SCAN, + MDB_INDEX_SCAN +} MdbStrategy; + +typedef enum { + MDB_NOFLAGS = 0x00, + MDB_WRITABLE = 0x01 +} MdbFileFlags; + +enum { + MDB_DEBUG_LIKE = 0x0001, + MDB_DEBUG_WRITE = 0x0002, + MDB_DEBUG_USAGE = 0x0004, + MDB_DEBUG_OLE = 0x0008, + MDB_DEBUG_ROW = 0x0010, + MDB_USE_INDEX = 0x0020 +}; + +#define mdb_is_logical_op(x) (x == MDB_OR || \ + x == MDB_AND || \ + x == MDB_NOT ) + +#define mdb_is_relational_op(x) (x == MDB_EQUAL || \ + x == MDB_GT || \ + x == MDB_LT || \ + x == MDB_GTEQ || \ + x == MDB_LTEQ || \ + x == MDB_LIKE || \ + x == MDB_ISNULL || \ + x == MDB_NOTNULL ) + +enum { + MDB_ASC, + MDB_DESC +}; + +enum { + MDB_IDX_UNIQUE = 0x01, + MDB_IDX_IGNORENULLS = 0x02, + MDB_IDX_REQUIRED = 0x08 +}; + +#define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) +#define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3) + +/* hash to store registered backends */ +extern GHashTable *mdb_backends; + +/* forward declarations */ +typedef struct mdbindex MdbIndex; +typedef struct mdbsargtree MdbSargNode; + +typedef struct { + char *name; + unsigned char needs_length; /* or precision */ + unsigned char needs_scale; + unsigned char needs_quotes; +} MdbBackendType; + +typedef struct { + MdbBackendType *types_table; +} MdbBackend; + +typedef struct { + gboolean collect; + unsigned long pg_reads; +} MdbStatistics; + +typedef struct { + int fd; + gboolean writable; + char *filename; + guint32 jet_version; + guint32 db_key; + char db_passwd[14]; + MdbBackend *default_backend; + char *backend_name; + MdbStatistics *stats; + /* free map */ + int map_sz; + unsigned char *free_map; + /* reference count */ + int refs; +} MdbFile; + +/* offset to row count on data pages...version dependant */ +typedef struct { + int pg_size; + guint16 row_count_offset; + guint16 tab_num_rows_offset; + guint16 tab_num_cols_offset; + guint16 tab_num_idxs_offset; + guint16 tab_num_ridxs_offset; + guint16 tab_usage_map_offset; + guint16 tab_first_dpg_offset; + guint16 tab_cols_start_offset; + guint16 tab_ridx_entry_size; + guint16 col_fixed_offset; + guint16 col_size_offset; + guint16 col_num_offset; + guint16 tab_col_entry_size; + guint16 tab_free_map_offset; + guint16 tab_col_offset_var; + guint16 tab_col_offset_fixed; + guint16 tab_row_col_num_offset; +} MdbFormatConstants; + +typedef struct { + MdbFile *f; + guint32 cur_pg; + guint16 row_num; + unsigned int cur_pos; + unsigned char pg_buf[MDB_PGSIZE]; + unsigned char alt_pg_buf[MDB_PGSIZE]; + unsigned int num_catalog; + GPtrArray *catalog; + MdbBackend *default_backend; + char *backend_name; + MdbFormatConstants *fmt; + MdbStatistics *stats; +#ifdef HAVE_ICONV + iconv_t iconv_out; +#endif +} MdbHandle; + +typedef struct { + MdbHandle *mdb; + char object_name[MDB_MAX_OBJ_NAME+1]; + int object_type; + unsigned long table_pg; /* misnomer since object may not be a table */ + unsigned long kkd_pg; + unsigned int kkd_rowid; + int num_props; + GArray *props; + GArray *columns; + int flags; +} MdbCatalogEntry; + +typedef struct { + gchar *name; + GHashTable *hash; +} MdbProperties; + +typedef union { + int i; + double d; + char s[256]; +} MdbAny; + +typedef struct { + char name[MDB_MAX_OBJ_NAME+1]; + int col_type; + int col_size; + void *bind_ptr; + int *len_ptr; + GHashTable *properties; + unsigned int num_sargs; + GPtrArray *sargs; + GPtrArray *idx_sarg_cache; + unsigned char is_fixed; + int query_order; + /* col_num is the current column order, + * does not include deletes */ + int col_num; + int cur_value_start; + int cur_value_len; + /* MEMO/OLE readers */ + guint32 cur_blob_pg; + int cur_blob_row; + int chunk_size; + /* numerics only */ + int col_prec; + int col_scale; + MdbProperties *props; + /* info needed for handling deleted/added columns */ + int fixed_offset; + int var_col_num; + /* row_col_num is the row column number order, + * including deleted columns */ + int row_col_num; +} MdbColumn; + +struct mdbsargtree { + int op; + MdbColumn *col; + MdbAny value; + void *parent; + MdbSargNode *left; + MdbSargNode *right; +}; + +typedef struct { + guint32 pg; + int start_pos; + int offset; + int len; + guint16 idx_starts[2000]; + unsigned char cache_value[256]; +} MdbIndexPage; + +typedef int (*MdbSargTreeFunc)(MdbSargNode *, gpointer *data); + +#define MDB_MAX_INDEX_DEPTH 10 + +typedef struct { + int cur_depth; + guint32 last_leaf_found; + int clean_up_mode; + MdbIndexPage pages[MDB_MAX_INDEX_DEPTH]; +} MdbIndexChain; + +typedef struct { + MdbCatalogEntry *entry; + char name[MDB_MAX_OBJ_NAME+1]; + unsigned int num_cols; + GPtrArray *columns; + unsigned int num_rows; + int index_start; + unsigned int num_real_idxs; + unsigned int num_idxs; + GPtrArray *indices; + guint32 first_data_pg; + guint32 cur_pg_num; + guint32 cur_phys_pg; + unsigned int cur_row; + int noskip_del; /* don't skip deleted rows */ + /* object allocation map */ + guint32 map_base_pg; + unsigned int map_sz; + unsigned char *usage_map; + /* pages with free space left */ + guint32 freemap_base_pg; + unsigned int freemap_sz; + unsigned char *free_usage_map; + /* query planner */ + MdbSargNode *sarg_tree; + MdbStrategy strategy; + MdbIndex *scan_idx; + MdbHandle *mdbidx; + MdbIndexChain *chain; + MdbProperties *props; + unsigned int num_var_cols; /* to know if row has variable columns */ + /* temp table */ + unsigned int is_temp_table; + GPtrArray *temp_table_pages; +} MdbTableDef; + +struct mdbindex { + int index_num; + char name[MDB_MAX_OBJ_NAME+1]; + unsigned char index_type; + guint32 first_pg; + int num_rows; /* number rows in index */ + unsigned int num_keys; + short key_col_num[MDB_MAX_IDX_COLS]; + unsigned char key_col_order[MDB_MAX_IDX_COLS]; + unsigned char flags; + MdbTableDef *table; +}; + +typedef struct { + char name[MDB_MAX_OBJ_NAME+1]; +} MdbColumnProp; + +typedef struct { + void *value; + int siz; + int start; + unsigned char is_null; + unsigned char is_fixed; + int colnum; + int offset; +} MdbField; + +typedef struct { + int op; + MdbAny value; +} MdbSarg; + +/* mem.c */ +extern void mdb_init(); +extern void mdb_exit(); + +/* file.c */ +extern ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg); +extern ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg); +extern unsigned char mdb_get_byte(unsigned char *buf, int offset); +extern int mdb_get_int16(unsigned char *buf, int offset); +extern gint32 mdb_get_int24(unsigned char *buf, int offset); +extern long mdb_get_int32(unsigned char *buf, int offset); +extern float mdb_get_single(unsigned char *buf, int offset); +extern double mdb_get_double(unsigned char *buf, int offset); +extern unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset); +extern int mdb_pg_get_int16(MdbHandle *mdb, int offset); +extern gint32 mdb_pg_get_int24(MdbHandle *mdb, int offset); +extern long mdb_pg_get_int32(MdbHandle *mdb, int offset); +extern float mdb_pg_get_single(MdbHandle *mdb, int offset); +extern double mdb_pg_get_double(MdbHandle *mdb, int offset); +extern gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset); +extern MdbHandle *mdb_open(char *filename, MdbFileFlags flags); +extern void mdb_close(MdbHandle *mdb); +extern MdbHandle *mdb_clone_handle(MdbHandle *mdb); +extern void mdb_swap_pgbuf(MdbHandle *mdb); +extern long _mdb_get_int32(unsigned char *buf, int offset); + +/* catalog.c */ +extern void mdb_free_catalog(MdbHandle *mdb); +extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type); +extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type); +extern char *mdb_get_objtype_string(int obj_type); + +/* table.c */ +extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry); +extern void mdb_free_tabledef(MdbTableDef *table); +extern MdbTableDef *mdb_read_table(MdbCatalogEntry *entry); +extern MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type); +extern void mdb_append_column(GPtrArray *columns, MdbColumn *in_col); +extern void mdb_free_columns(GPtrArray *columns); +extern GPtrArray *mdb_read_columns(MdbTableDef *table); +extern void mdb_table_dump(MdbCatalogEntry *entry); +extern guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos); +extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos); +extern int read_pg_if(MdbHandle *mdb, int *cur_pos, int offset); +extern guint16 read_pg_if_n(MdbHandle *mdb, unsigned char *buf, int *cur_pos, int len); +extern int mdb_is_user_table(MdbCatalogEntry *entry); +extern int mdb_is_system_table(MdbCatalogEntry *entry); + +/* data.c */ +extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr); +extern void mdb_data_dump(MdbTableDef *table); +extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr); +extern int mdb_rewind_table(MdbTableDef *table); +extern int mdb_fetch_row(MdbTableDef *table); +extern int mdb_is_fixed_col(MdbColumn *col); +extern char *mdb_col_to_string(MdbHandle *mdb, unsigned char *buf, int start, int datatype, int size); +extern int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, int *len); +extern int mdb_find_end_of_row(MdbHandle *mdb, int row); +extern int mdb_col_fixed_size(MdbColumn *col); +extern int mdb_col_disp_size(MdbColumn *col); +extern void mdb_bind_len(MdbTableDef *table, int col_num, int *len_ptr); +extern int mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr); +extern int mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size); +extern void mdb_set_date_fmt(const char *); +extern int mdb_read_row(MdbTableDef *table, unsigned int row); + +/* dump.c */ +extern void buffer_dump(const unsigned char* buf, int start, int end); + +/* backend.c */ +extern char *mdb_get_coltype_string(MdbBackend *backend, int col_type); +extern int mdb_coltype_takes_length(MdbBackend *backend, int col_type); +extern void mdb_init_backends(); +extern void mdb_register_backend(MdbBackendType *backend, char *backend_name); +extern void mdb_remove_backends(); +extern int mdb_set_default_backend(MdbHandle *mdb, char *backend_name); +extern char *mdb_get_relationships(MdbHandle *mdb); + +/* sargs.c */ +extern int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields); +extern int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field); +extern void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data); +extern int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data); +extern int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg); +extern int mdb_test_string(MdbSargNode *node, char *s); +extern int mdb_test_int(MdbSargNode *node, gint32 i); +extern int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg); + + + +/* index.c */ +extern GPtrArray *mdb_read_indices(MdbTableDef *table); +extern void mdb_index_dump(MdbTableDef *table, MdbIndex *idx); +extern void mdb_index_scan_free(MdbTableDef *table); +extern int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg); +extern int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row); +extern void mdb_index_hash_text(guchar *text, guchar *hash); +extern void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table); +extern int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row); +extern void mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest); +extern void mdb_free_indices(GPtrArray *indices); +void mdb_index_page_reset(MdbIndexPage *ipg); +extern MdbIndexPage *mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain); +extern MdbIndexPage *mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain); +extern void mdb_index_page_init(MdbIndexPage *ipg); + + +/* stats.c */ +extern void mdb_stats_on(MdbHandle *mdb); +extern void mdb_stats_off(MdbHandle *mdb); +extern void mdb_dump_stats(MdbHandle *mdb); + +/* like.c */ +extern int mdb_like_cmp(char *s, char *r); + +/* write.c */ +extern int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields); +extern guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size); +extern int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum); +extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields); +extern int mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size); +extern int mdb_pg_get_freespace(MdbHandle *mdb); +extern int mdb_update_row(MdbTableDef *table); +extern unsigned char *mdb_new_data_pg(MdbCatalogEntry *entry); + +/* map.c */ +extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size); +guint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg); + +/* props.c */ +extern GPtrArray *mdb_read_props_list(gchar *kkd, int len); +extern void mdb_free_props(MdbProperties *props); +extern MdbProperties *mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len); + +/* worktable.c */ +extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name); +extern void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col); +extern void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed); +extern void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int column); +extern void mdb_temp_columns_end(MdbTableDef *table); + +/* options.c */ +extern int mdb_get_option(unsigned long optnum); +extern void mdb_debug(int klass, char *fmt, ...); + +/* iconv.c */ +extern int mdb_unicode2ascii(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest); +extern int mdb_ascii2unicode(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest); + +#endif /* _mdbtools_h_ */ diff --git a/plugins/poi_geodownload/libmdb/index.c b/plugins/poi_geodownload/libmdb/index.c new file mode 100644 index 00000000..e840536e --- /dev/null +++ b/plugins/poi_geodownload/libmdb/index.c @@ -0,0 +1,905 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000-2004 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +MdbIndexPage *mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain); +MdbIndexPage *mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg); + +char idx_to_text[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0-7 0x00-0x07 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8-15 0x09-0x0f */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16-23 0x10-0x17 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24-31 0x19-0x1f */ +' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32-39 0x20-0x27 */ +0x00, 0x00, 0x00, 0x00, 0x00, ' ', ' ', 0x00, /* 40-47 0x29-0x2f */ +'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', /* 48-55 0x30-0x37 */ +'^', '_', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56-63 0x39-0x3f */ +0x00, '`', 'a', 'b', 'd', 'f', 'g', 'h', /* 64-71 0x40-0x47 */ +'i', 'j', 'k', 'l', 'm', 'o', 'p', 'r', /* 72-79 0x49-0x4f H */ +'s', 't', 'u', 'v', 'w', 'x', 'z', '{', /* 80-87 0x50-0x57 P */ +'|', '}', '~', '5', '6', '7', '8', '9', /* 88-95 0x59-0x5f */ +0x00, '`', 'a', 'b', 'd', 'f', 'g', 'h', /* 96-103 0x60-0x67 */ +'i', 'j', 'k', 'l', 'm', 'o', 'p', 'r', /* 014-111 0x69-0x6f h */ +'s', 't', 'u', 'v', 'w', 'x', 'z', '{', /* 112-119 0x70-0x77 p */ +'|', '}', '~', 0x00, 0x00, 0x00, 0x00, 0x00, /* 120-127 0x78-0x7f */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128-135 0x80-0x87 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ +0x00, 0x00, 0x00, 0x00, 0x00, '`', 0x00, 0x00, /* 0xc0-0xc7 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ +0x00, '`', 0x00, '`', '`', '`', 0x00, 0x00, /* 0xe0-0xe7 */ +'f', 'f', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ +0x00, 0x00, 0x00, 'r', 0x00, 0x00, 'r', 0x00, /* 0xf0-0xf7 */ +0x81, 0x00, 0x00, 0x00, 'x', 0x00, 0x00, 0x00, /* 0xf8-0xff */ +}; + + +GPtrArray * +mdb_read_indices(MdbTableDef *table) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + MdbIndex *pidx; + unsigned int i, j; + int idx_num, key_num, col_num; + int cur_pos, name_sz, idx2_sz, type_offset; + int index_start_pg = mdb->cur_pg; + gchar *tmpbuf; + + table->indices = g_ptr_array_new(); + + if (IS_JET4(mdb)) { + cur_pos = table->index_start + 52 * table->num_real_idxs; + idx2_sz = 28; + type_offset = 23; + } else { + cur_pos = table->index_start + 39 * table->num_real_idxs; + idx2_sz = 20; + type_offset = 19; + } + + tmpbuf = (gchar *) g_malloc(idx2_sz); + for (i=0;i<table->num_idxs;i++) { + read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); + cur_pos += idx2_sz; + pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex)); + pidx->table = table; + pidx->index_num = mdb_get_int16(tmpbuf, 4); + pidx->index_type = tmpbuf[type_offset]; + g_ptr_array_add(table->indices, pidx); + } + g_free(tmpbuf); + + for (i=0;i<table->num_idxs;i++) { + pidx = g_ptr_array_index (table->indices, i); + if (IS_JET4(mdb)) { + name_sz=read_pg_if_16(mdb, &cur_pos); + cur_pos += 2; + tmpbuf = g_malloc(name_sz); + read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz); + cur_pos += name_sz; + mdb_unicode2ascii(mdb, tmpbuf, 0, name_sz, pidx->name); + g_free(tmpbuf); + } else { + read_pg_if(mdb, &cur_pos, 0); + name_sz=mdb->pg_buf[cur_pos++]; + read_pg_if_n(mdb, pidx->name, &cur_pos, name_sz); + cur_pos += name_sz; + pidx->name[name_sz]='\0'; + } + //fprintf(stderr, "index name %s\n", pidx->name); + } + + mdb_read_alt_pg(mdb, entry->table_pg); + mdb_read_pg(mdb, index_start_pg); + cur_pos = table->index_start; + idx_num=0; + for (i=0;i<table->num_real_idxs;i++) { + if (IS_JET4(mdb)) cur_pos += 4; + do { + pidx = g_ptr_array_index (table->indices, idx_num++); + } while (pidx && pidx->index_type==2); + + /* if there are more real indexes than index entries left after + removing type 2's decrement real indexes and continue. Happens + on Northwind Orders table. + */ + if (!pidx) { + table->num_real_idxs--; + continue; + } + + pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf, + fmt->tab_cols_start_offset + + (i*fmt->tab_ridx_entry_size)); + + key_num=0; + for (j=0;j<MDB_MAX_IDX_COLS;j++) { + col_num=read_pg_if_16(mdb,&cur_pos); + cur_pos += 2; + read_pg_if(mdb, &cur_pos, 0); + cur_pos++; + if (col_num == 0xFFFF) + continue; + /* set column number to a 1 based column number and store */ + pidx->key_col_num[key_num] = col_num + 1; + pidx->key_col_order[key_num] = + (mdb->pg_buf[cur_pos-1]) ? MDB_ASC : MDB_DESC; + key_num++; + } + pidx->num_keys = key_num; + + cur_pos += 4; + pidx->first_pg = read_pg_if_32(mdb, &cur_pos); + cur_pos += 4; + read_pg_if(mdb, &cur_pos, 0); + pidx->flags = mdb->pg_buf[cur_pos++]; + if (IS_JET4(mdb)) cur_pos += 9; + } + return NULL; +} +void +mdb_index_hash_text(guchar *text, guchar *hash) +{ + unsigned int k; + + for (k=0;k<strlen(text);k++) { + hash[k] = idx_to_text[text[k]]; + if (!(hash[k])) fprintf(stderr, + "No translation available for %02x %d\n", + text[k],text[k]); + } + hash[strlen(text)]=0; +} +void +mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest) +{ + int i, j = 0; + + for (i = sz; i > 0; i--) { + dest[j++] = src[i]; + } +} +void +mdb_index_cache_sarg(MdbColumn *col, MdbSarg *sarg, MdbSarg *idx_sarg) +{ + //guint32 cache_int; + unsigned char *c; + + switch (col->col_type) { + case MDB_TEXT: + mdb_index_hash_text(sarg->value.s, idx_sarg->value.s); + break; + + case MDB_LONGINT: + idx_sarg->value.i = GUINT32_SWAP_LE_BE(sarg->value.i); + //cache_int = sarg->value.i * -1; + c = (unsigned char *) &(idx_sarg->value.i); + c[0] |= 0x80; + //printf("int %08x %02x %02x %02x %02x\n", sarg->value.i, c[0], c[1], c[2], c[3]); + break; + + case MDB_INT: + break; + + default: + break; + } +} +#if 0 +int +mdb_index_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSarg *sarg, int offset, int len) +{ +char tmpbuf[256]; +int lastchar; + + switch (col->col_type) { + case MDB_BYTE: + return mdb_test_int(sarg, mdb_pg_get_byte(mdb, offset)); + break; + case MDB_INT: + return mdb_test_int(sarg, mdb_pg_get_int16(mdb, offset)); + break; + case MDB_LONGINT: + return mdb_test_int(sarg, mdb_pg_get_int32(mdb, offset)); + break; + case MDB_TEXT: + strncpy(tmpbuf, &mdb->pg_buf[offset],255); + lastchar = len > 255 ? 255 : len; + tmpbuf[lastchar]='\0'; + return mdb_test_string(sarg, tmpbuf); + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown type. Add code to mdb_test_sarg() for type %d\n",col->col_type); + break; + } + return 1; +} +#endif +int +mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, unsigned char *buf, int len) +{ + unsigned int i, j; + MdbColumn *col; + MdbTableDef *table = idx->table; + MdbSarg *idx_sarg; + MdbSarg *sarg; + MdbField field; + MdbSargNode node; + //int c_offset = 0, + int c_len; + +#if 0 + fprintf(stderr,"mdb_index_test_sargs called on "); + for (i=0;i<len;i++) + fprintf(stderr,"%02x ",buf[i]); //mdb->pg_buf[offset+i]); + fprintf(stderr,"\n"); +#endif + for (i=0;i<idx->num_keys;i++) { + //c_offset++; /* the per column null indicator/flags */ + col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); + /* + * This will go away eventually + */ + if (col->col_type==MDB_TEXT) { + //c_len = strlen(&mdb->pg_buf[offset + c_offset]); + c_len = strlen(buf); + } else { + c_len = col->col_size; + //fprintf(stderr,"Only text types currently supported. How did we get here?\n"); + } + /* + * If we have no cached index values for this column, + * create them. + */ + if (col->num_sargs && !col->idx_sarg_cache) { + col->idx_sarg_cache = g_ptr_array_new(); + for (j=0;j<col->num_sargs;j++) { + sarg = g_ptr_array_index (col->sargs, j); + idx_sarg = g_memdup(sarg,sizeof(MdbSarg)); + //printf("calling mdb_index_cache_sarg\n"); + mdb_index_cache_sarg(col, sarg, idx_sarg); + g_ptr_array_add(col->idx_sarg_cache, idx_sarg); + } + } + + for (j=0;j<col->num_sargs;j++) { + sarg = g_ptr_array_index (col->idx_sarg_cache, j); + /* XXX - kludge */ + node.op = sarg->op; + node.value = sarg->value; + //field.value = &mdb->pg_buf[offset + c_offset]; + field.value = buf; + field.siz = c_len; + field.is_null = FALSE; + if (!mdb_test_sarg(mdb, col, &node, &field)) { + /* sarg didn't match, no sense going on */ + return 0; + } + } + } + return 1; +} +/* + * pack the pages bitmap + */ +int +mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg) +{ + int mask_bit = 0; + int mask_pos = 0x16; + int mask_byte = 0; + int elem = 0; + int len, start, i; + + start = ipg->idx_starts[elem++]; + + while (start) { + len = ipg->idx_starts[elem] - start; + fprintf(stdout, "len is %d\n", len); + for (i=0; i < len; i++) { + mask_bit++; + if (mask_bit==8) { + mask_bit=0; + mdb->pg_buf[mask_pos++] = mask_byte; + mask_byte = 0; + } + /* upon reaching the len, set the bit */ + } + mask_byte = (1 << mask_bit) | mask_byte; + fprintf(stdout, "mask byte is %02x at %d\n", mask_byte, mask_pos); + start = ipg->idx_starts[elem++]; + } + /* flush the last byte if any */ + mdb->pg_buf[mask_pos++] = mask_byte; + /* remember to zero the rest of the bitmap */ + for (i = mask_pos; i < 0xf8; i++) { + mdb->pg_buf[mask_pos++] = 0; + } + return 0; +} +/* + * unpack the pages bitmap + */ +int +mdb_index_unpack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg) +{ + int mask_bit = 0; + int mask_pos = 0x16; + int mask_byte; + int start = 0xf8; + int elem = 0; + int len = 0; + + ipg->idx_starts[elem++]=start; + +#if 0 + fprintf(stdout, "Unpacking index page %u\n", ipg->pg); +#endif + do { + len = 0; + do { + mask_bit++; + if (mask_bit==8) { + mask_bit=0; + mask_pos++; + } + mask_byte = mdb->pg_buf[mask_pos]; + len++; + } while (mask_pos <= 0xf8 && !((1 << mask_bit) & mask_byte)); + //fprintf(stdout, "%d %d %d %d\n", mask_pos, mask_bit, mask_byte, len); + + start += len; + if (mask_pos < 0xf8) ipg->idx_starts[elem++]=start; + + } while (mask_pos < 0xf8); + + /* if we zero the next element, so we don't pick up the last pages starts*/ + ipg->idx_starts[elem]=0; + + return elem; +} +/* + * find the next entry on a page (either index or leaf). Uses state information + * stored in the MdbIndexPage across calls. + */ +int +mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg) +{ + if (!ipg->pg) return 0; + + /* if this page has not been unpacked to it */ + if (!ipg->idx_starts[0]){ + //fprintf(stdout, "Unpacking page %d\n", ipg->pg); + mdb_index_unpack_bitmap(mdb, ipg); + } + + + if (ipg->idx_starts[ipg->start_pos + 1]==0) return 0; + ipg->len = ipg->idx_starts[ipg->start_pos+1] - ipg->idx_starts[ipg->start_pos]; + ipg->start_pos++; + //fprintf(stdout, "Start pos %d\n", ipg->start_pos); + + return ipg->len; +} +void mdb_index_page_reset(MdbIndexPage *ipg) +{ + ipg->offset = 0xf8; /* start byte of the index entries */ + ipg->start_pos=0; + ipg->len = 0; + ipg->idx_starts[0]=0; +} +void mdb_index_page_init(MdbIndexPage *ipg) +{ + memset(ipg, 0, sizeof(MdbIndexPage)); + mdb_index_page_reset(ipg); +} +/* + * find the next leaf page if any given a chain. Assumes any exhausted leaf + * pages at the end of the chain have been peeled off before the call. + */ +MdbIndexPage * +mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) +{ + MdbIndexPage *ipg, *newipg; + guint32 pg; + guint passed = 0; + + ipg = mdb_index_read_bottom_pg(mdb, idx, chain); + + /* + * If we are at the first page deep and it's not an index page then + * we are simply done. (there is no page to find + */ + + if (mdb->pg_buf[0]==MDB_PAGE_LEAF) { + /* Indexes can have leaves at the end that don't appear + * in the upper tree, stash the last index found so + * we can follow it at the end. */ + chain->last_leaf_found = ipg->pg; + return ipg; + } + + /* + * apply sargs here, currently we don't + */ + do { + ipg->len = 0; + //printf("finding next on pg %lu\n", ipg->pg); + if (!mdb_index_find_next_on_page(mdb, ipg)) { + //printf("find_next_on_page returned 0\n"); + return 0; + } + pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 3); + //printf("Looking at pg %lu at %lu %d\n", pg, ipg->offset, ipg->len); + ipg->offset += ipg->len; + + /* + * add to the chain and call this function + * recursively. + */ + newipg = mdb_chain_add_page(mdb, chain, pg); + newipg = mdb_find_next_leaf(mdb, idx, chain); + //printf("returning pg %lu\n",newipg->pg); + return newipg; + } while (!passed); + /* no more pages */ + return NULL; + +} +MdbIndexPage * +mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg) +{ + MdbIndexPage *ipg; + + chain->cur_depth++; + if (chain->cur_depth > MDB_MAX_INDEX_DEPTH) { + fprintf(stderr,"Error! maximum index depth of %d exceeded. This is probably due to a programming bug, If you are confident that your indexes really are this deep, adjust MDB_MAX_INDEX_DEPTH in mdbtools.h and recompile.\n", MDB_MAX_INDEX_DEPTH); + exit(1); + } + ipg = &(chain->pages[chain->cur_depth - 1]); + mdb_index_page_init(ipg); + ipg->pg = pg; + + return ipg; +} +/* + * returns the bottom page of the IndexChain, if IndexChain is empty it + * initializes it by reading idx->first_pg (the root page) + */ +MdbIndexPage * +mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) +{ + MdbIndexPage *ipg; + + /* + * if it's new use the root index page (idx->first_pg) + */ + if (!chain->cur_depth) { + ipg = &(chain->pages[0]); + mdb_index_page_init(ipg); + chain->cur_depth = 1; + ipg->pg = idx->first_pg; + if (!(ipg = mdb_find_next_leaf(mdb, idx, chain))) + return 0; + } else { + ipg = &(chain->pages[chain->cur_depth - 1]); + ipg->len = 0; + } + + mdb_read_pg(mdb, ipg->pg); + + return ipg; +} +/* + * unwind the stack and search for new leaf node + */ +MdbIndexPage * +mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) +{ + MdbIndexPage *ipg; + + //printf("page %lu finished\n",ipg->pg); + if (chain->cur_depth==1) { + //printf("cur_depth == 1 we're out\n"); + return NULL; + } + /* + * unwind the stack until we find something or reach + * the top. + */ + ipg = NULL; + while (chain->cur_depth>1 && ipg==NULL) { + //printf("chain depth %d\n", chain->cur_depth); + chain->cur_depth--; + ipg = mdb_find_next_leaf(mdb, idx, chain); + if (ipg) mdb_index_find_next_on_page(mdb, ipg); + } + if (chain->cur_depth==1) { + //printf("last leaf %lu\n", chain->last_leaf_found); + return NULL; + } + return ipg; +} +/* + * the main index function. + * caller provides an index chain which is the current traversal of index + * pages from the root page to the leaf. Initially passed as blank, + * mdb_index_find_next will store it's state information here. Each invocation + * then picks up where the last one left off, allowing us to scroll through + * the index one by one. + * + * Sargs are applied here but also need to be applied on the whole row b/c + * text columns may return false positives due to hashing and non-index + * columns with sarg values can't be tested here. + */ +int +mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row) +{ + MdbIndexPage *ipg; + int passed = 0; + int idx_sz; + int idx_start = 0; + MdbColumn *col; + + ipg = mdb_index_read_bottom_pg(mdb, idx, chain); + + /* + * loop while the sargs don't match + */ + do { + ipg->len = 0; + /* + * if no more rows on this leaf, try to find a new leaf + */ + if (!mdb_index_find_next_on_page(mdb, ipg)) { + if (!chain->clean_up_mode) { + if (!(ipg = mdb_index_unwind(mdb, idx, chain))) + chain->clean_up_mode = 1; + } + if (chain->clean_up_mode) { + //fprintf(stdout,"in cleanup mode\n"); + + if (!chain->last_leaf_found) return 0; + mdb_read_pg(mdb, chain->last_leaf_found); + chain->last_leaf_found = mdb_pg_get_int24(mdb, 0x0c); + //printf("next leaf %lu\n", chain->last_leaf_found); + mdb_read_pg(mdb, chain->last_leaf_found); + /* reuse the chain for cleanup mode */ + chain->cur_depth = 1; + ipg = &chain->pages[0]; + mdb_index_page_init(ipg); + ipg->pg = chain->last_leaf_found; + //printf("next on page %d\n", + if (!mdb_index_find_next_on_page(mdb, ipg)) + return 0; + } + } + *row = mdb->pg_buf[ipg->offset + ipg->len - 1]; +#if 0 + printf("page: "); + buffer_dump(mdb->pg_buf, ipg->offset+ipg->len-4, ipg->offset+ipg->len-2); +#endif + *pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); +#if 0 + printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, ipg->pg, ipg->offset, ipg->len); +#endif + col=g_ptr_array_index(idx->table->columns,idx->key_col_num[0]-1); + idx_sz = mdb_col_fixed_size(col); + /* handle compressed indexes, single key indexes only? */ + if (idx->num_keys==1 && idx_sz>0 && ipg->len - 4 < idx_sz) { +#if 0 + printf("short index found\n"); + buffer_dump(ipg->cache_value, 0, idx_sz); +#endif + memcpy(&ipg->cache_value[idx_sz - (ipg->len - 4)], &mdb->pg_buf[ipg->offset], ipg->len); +#if 0 + buffer_dump(ipg->cache_value, 0, idx_sz); +#endif + } else { + idx_start = ipg->offset + (ipg->len - 4 - idx_sz); + memcpy(ipg->cache_value, &mdb->pg_buf[idx_start], idx_sz); + } + + //idx_start = ipg->offset + (ipg->len - 4 - idx_sz); + passed = mdb_index_test_sargs(mdb, idx, ipg->cache_value, idx_sz); + +// printf("passed=%d\n", passed); + + buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1); + ipg->offset += ipg->len; + + } while (!passed); + +#if 0 + fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->len); + buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1); +#endif + + return ipg->len; +} +/* + * XXX - FIX ME + * This function is grossly inefficient. It scans the entire index building + * an IndexChain to a specific row. We should be checking the index pages + * for matches against the indexed fields to find the proper leaf page, but + * getting it working first and then make it fast! + */ +int +mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row) +{ + MdbIndexPage *ipg; + int passed = 0; + guint32 datapg; + guint16 datarow; + + ipg = mdb_index_read_bottom_pg(mdb, idx, chain); + + do { + ipg->len = 0; + /* + * if no more rows on this leaf, try to find a new leaf + */ + if (!mdb_index_find_next_on_page(mdb, ipg)) { + /* back to top? We're done */ + if (chain->cur_depth==1) + return 0; + + /* + * unwind the stack until we find something or reach + * the top. + */ + while (chain->cur_depth>1) { + chain->cur_depth--; + if (!(ipg = mdb_find_next_leaf(mdb, idx, chain))) + return 0; + mdb_index_find_next_on_page(mdb, ipg); + } + if (chain->cur_depth==1) + return 0; + } + /* test row and pg */ + datarow = mdb->pg_buf[ipg->offset + ipg->len - 1]; + datapg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); + + if (datapg == pg && datarow == row) { + passed = 1; + } + ipg->offset += ipg->len; + } while (!passed); + + /* index chain from root to leaf should now be in "chain" */ + return 1; +} + +void mdb_index_walk(MdbTableDef *table, MdbIndex *idx) +{ +MdbHandle *mdb = table->entry->mdb; +int cur_pos = 0; +unsigned char marker; +MdbColumn *col; +unsigned int i; + + if (idx->num_keys!=1) return; + + mdb_read_pg(mdb, idx->first_pg); + cur_pos = 0xf8; + + for (i=0;i<idx->num_keys;i++) { + marker = mdb->pg_buf[cur_pos++]; + col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); + //printf("column %d coltype %d col_size %d (%d)\n",i,col->col_type, mdb_col_fixed_size(col), col->col_size); + } +} +void +mdb_index_dump(MdbTableDef *table, MdbIndex *idx) +{ + unsigned int i; + MdbColumn *col; + + fprintf(stdout,"index number %d\n", idx->index_num); + fprintf(stdout,"index name %s\n", idx->name); + fprintf(stdout,"index first page %d\n", idx->first_pg); + fprintf(stdout,"index rows %d\n", idx->num_rows); + if (idx->index_type==1) fprintf(stdout,"index is a primary key\n"); + for (i=0;i<idx->num_keys;i++) { + col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); + fprintf(stdout,"Column %s(%d) Sorted %s Unique: %s\n", + col->name, + idx->key_col_num[i], + idx->key_col_order[i]==MDB_ASC ? "ascending" : "descending", + idx->flags & MDB_IDX_UNIQUE ? "Yes" : "No" + ); + } + mdb_index_walk(table, idx); +} +/* + * compute_cost tries to assign a cost to a given index using the sargs + * available in this query. + * + * Indexes with no matching sargs are assigned 0 + * Unique indexes are preferred over non-uniques + * Operator preference is equal, like, isnull, others + */ +int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx) +{ + unsigned int i; + MdbColumn *col; + MdbSarg *sarg = NULL; + int not_all_equal = 0; + + if (!idx->num_keys) return 0; + if (idx->num_keys > 1) { + for (i=0;i<idx->num_keys;i++) { + col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1); + if (col->sargs) sarg = g_ptr_array_index (col->sargs, 0); + if (!sarg || sarg->op != MDB_EQUAL) not_all_equal++; + } + } + + col=g_ptr_array_index(table->columns,idx->key_col_num[0]-1); + /* + * if this is the first key column and there are no sargs, + * then this index is useless. + */ + if (!col->num_sargs) return 0; + + sarg = g_ptr_array_index (col->sargs, 0); + + /* + * a like with a wild card first is useless as a sarg */ + if (sarg->op == MDB_LIKE && sarg->value.s[0]=='%') + return 0; + + /* + * this needs a lot of tweaking. + */ + if (idx->flags & MDB_IDX_UNIQUE) { + if (idx->num_keys == 1) { + //printf("op is %d\n", sarg->op); + switch (sarg->op) { + case MDB_EQUAL: + return 1; break; + case MDB_LIKE: + return 4; break; + case MDB_ISNULL: + return 12; break; + default: + return 8; break; + } + } else { + switch (sarg->op) { + case MDB_EQUAL: + if (not_all_equal) return 2; + else return 1; + break; + case MDB_LIKE: + return 6; break; + case MDB_ISNULL: + return 12; break; + default: + return 9; break; + } + } + } else { + if (idx->num_keys == 1) { + switch (sarg->op) { + case MDB_EQUAL: + return 2; break; + case MDB_LIKE: + return 5; break; + case MDB_ISNULL: + return 12; break; + default: + return 10; break; + } + } else { + switch (sarg->op) { + case MDB_EQUAL: + if (not_all_equal) return 3; + else return 2; + break; + case MDB_LIKE: + return 7; break; + case MDB_ISNULL: + return 12; break; + default: + return 11; break; + } + } + } + return 0; +} +/* + * choose_index runs mdb_index_compute_cost for each available index and picks + * the best. + * + * Returns strategy to use (table scan, or index scan) + */ +MdbStrategy +mdb_choose_index(MdbTableDef *table, int *choice) +{ + unsigned int i; + MdbIndex *idx; + int cost = 0; + int least = 99; + + *choice = -1; + for (i=0;i<table->num_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + cost = mdb_index_compute_cost(table, idx); + //printf("cost for %s is %d\n", idx->name, cost); + if (cost && cost < least) { + least = cost; + *choice = i; + } + } + /* and the winner is: *choice */ + if (least==99) return MDB_TABLE_SCAN; + return MDB_INDEX_SCAN; +} +void +mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table) +{ + int i; + + if (mdb_get_option(MDB_USE_INDEX) && mdb_choose_index(table, &i) == MDB_INDEX_SCAN) { + table->strategy = MDB_INDEX_SCAN; + table->scan_idx = g_ptr_array_index (table->indices, i); + table->chain = g_malloc0(sizeof(MdbIndexChain)); + table->mdbidx = mdb_clone_handle(mdb); + mdb_read_pg(table->mdbidx, table->scan_idx->first_pg); + //printf("best index is %s\n",table->scan_idx->name); + } + //printf("TABLE SCAN? %d\n", table->strategy); +} +void +mdb_index_scan_free(MdbTableDef *table) +{ + if (table->chain) { + g_free(table->chain); + table->chain = NULL; + } + if (table->mdbidx) { + mdb_close(table->mdbidx); + table->mdbidx = NULL; + } +} + +void mdb_free_indices(GPtrArray *indices) +{ + unsigned int i; + + if (!indices) return; + for (i=0; i<indices->len; i++) + g_free (g_ptr_array_index(indices, i)); + g_ptr_array_free(indices, TRUE); +} diff --git a/plugins/poi_geodownload/libmdb/kkd.c b/plugins/poi_geodownload/libmdb/kkd.c new file mode 100644 index 00000000..ea72887c --- /dev/null +++ b/plugins/poi_geodownload/libmdb/kkd.c @@ -0,0 +1,149 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + + +/* +** Note: This code is mostly garbage right now...just a test to parse out the +** KKD structures. +*/ + +GArray *mdb_get_column_props(MdbCatalogEntry *entry, int start) +{ +int pos, cnt=0; +int len, tmp, cplen; +MdbColumnProp prop; +MdbHandle *mdb = entry->mdb; + + entry->props = g_array_new(FALSE,FALSE,sizeof(MdbColumnProp)); + len = mdb_pg_get_int16(mdb,start); + pos = start + 6; + while (pos < start+len) { + tmp = mdb_pg_get_int16(mdb,pos); /* length of string */ + pos += 2; + cplen = tmp > MDB_MAX_OBJ_NAME ? MDB_MAX_OBJ_NAME : tmp; + g_memmove(prop.name,&mdb->pg_buf[pos],cplen); + prop.name[cplen]='\0'; + pos += tmp; + g_array_append_val(entry->props, prop.name); + cnt++; + } + entry->num_props = cnt; + return entry->props; +} + +GHashTable *mdb_get_column_def(MdbCatalogEntry *entry, int start) +{ +GHashTable *hash = NULL; +MdbHandle *mdb = entry->mdb; +MdbColumnProp prop; +int tmp, pos, col_num, val_len, i; +int len, col_type; +unsigned char c; +int end; + + fprintf(stdout,"\n data\n"); + fprintf(stdout,"-------\n"); + len = mdb_pg_get_int16(mdb,start); + fprintf(stdout,"length = %3d\n",len); + pos = start + 6; + end = start + len; + while (pos < end) { + fprintf(stdout,"pos = %3d\n",pos); + start = pos; + tmp = mdb_pg_get_int16(mdb,pos); /* length of field */ + pos += 2; + col_type = mdb_pg_get_int16(mdb,pos); /* ??? */ + pos += 2; + col_num = 0; + if (col_type) { + col_num = mdb_pg_get_int16(mdb,pos); + pos += 2; + } + val_len = mdb_pg_get_int16(mdb,pos); + pos += 2; + fprintf(stdout,"length = %3d %04x %2d %2d ",tmp, col_type, col_num, val_len); + for (i=0;i<val_len;i++) { + c = mdb->pg_buf[pos+i]; + if (isprint(c)) + fprintf(stdout," %c",c); + else + fprintf(stdout," %02x",c); + + } + pos = start + tmp; + prop = g_array_index(entry->props,MdbColumnProp,col_num); + fprintf(stdout," Property %s",prop.name); + fprintf(stdout,"\n"); + } + return hash; +} +void mdb_kkd_dump(MdbCatalogEntry *entry) +{ +int rows; +int kkd_start, kkd_end; +int i, tmp, pos, row_type, datapos=0; +MdbColumnProp prop; +MdbHandle *mdb = entry->mdb; +int rowid = entry->kkd_rowid; + + + mdb_read_pg(mdb, entry->kkd_pg); + rows = mdb_pg_get_int16(mdb,8); + fprintf(stdout,"number of rows = %d\n",rows); + kkd_start = mdb_pg_get_int16(mdb,10+rowid*2); + fprintf(stdout,"kkd start = %d %04x\n",kkd_start,kkd_start); + kkd_end = mdb->fmt->pg_size; + for (i=0;i<rows;i++) { + tmp = mdb_pg_get_int16(mdb, 10+i*2); + if (tmp < mdb->fmt->pg_size && + tmp > kkd_start && + tmp < kkd_end) { + kkd_end = tmp; + } + } + fprintf(stdout,"kkd end = %d %04x\n",kkd_end,kkd_end); + pos = kkd_start + 4; /* 4 = K K D \0 */ + while (pos < kkd_end) { + tmp = mdb_pg_get_int16(mdb,pos); + row_type = mdb_pg_get_int16(mdb,pos+4); + fprintf(stdout,"row size = %3d type = 0x%02x\n",tmp,row_type); + if (row_type==0x80) { + fprintf(stdout,"\nColumn Properties\n"); + fprintf(stdout,"-----------------\n"); + mdb_get_column_props(entry,pos); + for (i=0;i<entry->num_props;i++) { + prop = g_array_index(entry->props,MdbColumnProp,i); + fprintf(stdout,"%3d %s\n",i,prop.name); + } + } + if (row_type==0x01) datapos = pos; + pos += tmp; + } + + if (datapos) { + mdb_get_column_def(entry, datapos); + } +} + diff --git a/plugins/poi_geodownload/libmdb/like.c b/plugins/poi_geodownload/libmdb/like.c new file mode 100644 index 00000000..0a23d45c --- /dev/null +++ b/plugins/poi_geodownload/libmdb/like.c @@ -0,0 +1,78 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <mdbtools.h> + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/** + * mdb_like_cmp + * @s: String to search within. + * @r: Search pattern. + * + * Tests the string @s to see if it matches the search pattern @r. In the + * search pattern, a percent sign indicates matching on any number of + * characters, and an underscore indicates matching any single character. + * + * Returns: 1 if the string matches, 0 if the string does not match. + */ +int mdb_like_cmp(char *s, char *r) +{ + unsigned int i; + int ret; + + mdb_debug(MDB_DEBUG_LIKE, "comparing %s and %s", s, r); + switch (r[0]) { + case '\0': + if (s[0]=='\0') { + return 1; + } else { + return 0; + } + case '_': + /* skip one character */ + return mdb_like_cmp(&s[1],&r[1]); + case '%': + /* skip any number of characters */ + /* the strlen(s)+1 is important so the next call can */ + /* if there are trailing characters */ + for(i=0;i<strlen(s)+1;i++) { + if (mdb_like_cmp(&s[i],&r[1])) { + return 1; + } + } + return 0; + default: + for(i=0;i<strlen(r);i++) { + if (r[i]=='_' || r[i]=='%') break; + } + if (strncmp(s,r,i)) { + return 0; + } else { + mdb_debug(MDB_DEBUG_LIKE, "at pos %d comparing %s and %s", i, &s[i], &r[i]); + ret = mdb_like_cmp(&s[i],&r[i]); + mdb_debug(MDB_DEBUG_LIKE, "returning %d (%s and %s)", ret, &s[i], &r[i]); + return ret; + } + } +} diff --git a/plugins/poi_geodownload/libmdb/map.c b/plugins/poi_geodownload/libmdb/map.c new file mode 100644 index 00000000..1164b7be --- /dev/null +++ b/plugins/poi_geodownload/libmdb/map.c @@ -0,0 +1,133 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +static guint32 +mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg) +{ + guint32 pgnum, i, usage_bitlen; + unsigned char *usage_bitmap; + + pgnum = mdb_get_int32(map, 1); + usage_bitmap = map + 5; + usage_bitlen = (map_sz - 5) * 8; + + i = (start_pg >= pgnum) ? start_pg-pgnum+1 : 0; + for (; i<usage_bitlen; i++) { + if (usage_bitmap[i/8] & (1 << (i%8))) { + return pgnum + i; + } + } + /* didn't find anything */ + return 0; +} +static int +mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg) +{ + guint32 map_ind, max_map_pgs, offset, usage_bitlen; + + /* + * start_pg will tell us where to (re)start the scan + * for the next data page. each usage_map entry points to a + * 0x05 page which bitmaps (mdb->fmt->pg_size - 4) * 8 pages. + * + * map_ind gives us the starting usage_map entry + * offset gives us a page offset into the bitmap + */ + usage_bitlen = (mdb->fmt->pg_size - 4) * 8; + max_map_pgs = (map_sz - 1) / 4; + map_ind = (start_pg + 1) / usage_bitlen; + offset = (start_pg + 1) % usage_bitlen; + + for (; map_ind<max_map_pgs; map_ind++) { + unsigned char *usage_bitmap; + guint32 i, map_pg; + + if (!(map_pg = mdb_get_int32(map, (map_ind*4)+1))) { + continue; + } + if(mdb_read_alt_pg(mdb, map_pg) != mdb->fmt->pg_size) { + fprintf(stderr, "Oops! didn't get a full page at %d\n", map_pg); + exit(1); + } + + usage_bitmap = mdb->alt_pg_buf + 4; + for (i=offset; i<usage_bitlen; i++) { + if (usage_bitmap[i/8] & (1 << (i%8))) { + return map_ind*usage_bitlen + i; + } + } + offset = 0; + } + /* didn't find anything */ + return 0; +} +guint32 +mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg) +{ + if (map[0] == 0) { + return mdb_map_find_next0(mdb, map, map_sz, start_pg); + } else if (map[0] == 1) { + return mdb_map_find_next1(mdb, map, map_sz, start_pg); + } + + fprintf(stderr, "Warning: unrecognized usage map type: %d\n", map[0]); + return -1; +} +guint32 +mdb_alloc_page(MdbTableDef *table) +{ + printf("Allocating new page\n"); + return 0; +} +guint32 +mdb_map_find_next_freepage(MdbTableDef *table, int row_size) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + guint32 pgnum; + guint32 cur_pg = 0; + int free_space; + + do { + pgnum = mdb_map_find_next(mdb, + table->free_usage_map, + table->freemap_sz, cur_pg); + printf("looking at page %d\n", pgnum); + if (!pgnum) { + /* allocate new page */ + pgnum = mdb_alloc_page(table); + return pgnum; + } + cur_pg = pgnum; + + mdb_read_pg(mdb, pgnum); + free_space = mdb_pg_get_freespace(mdb); + + } while (free_space < row_size); + + printf("page %d has %d bytes left\n", pgnum, free_space); + + return pgnum; +} diff --git a/plugins/poi_geodownload/libmdb/mem.c b/plugins/poi_geodownload/libmdb/mem.c new file mode 100644 index 00000000..9c518321 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/mem.c @@ -0,0 +1,50 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" +#include <locale.h> + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/** + * mdb_init: + * + * Initializes the LibMDB library. This function should be called exactly once + * by calling program and prior to any other function. + * + **/ +void mdb_init() +{ + mdb_init_backends(); +} + +/** + * mdb_exit: + * + * Cleans up the LibMDB library. This function should be called exactly once + * by the calling program prior to exiting (or prior to final use of LibMDB + * functions). + * + **/ +void mdb_exit() +{ + mdb_remove_backends(); +} diff --git a/plugins/poi_geodownload/libmdb/money.c b/plugins/poi_geodownload/libmdb/money.c new file mode 100644 index 00000000..7f2cf657 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/money.c @@ -0,0 +1,139 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 1998-1999 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#define MAXPRECISION 20 +/* +** these routines are copied from the freetds project which does something +** very similiar +*/ + +static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier); +static int do_carry(unsigned char *product); +static char *array_to_string(unsigned char *array, int unsigned scale, char *s); + +/** + * mdb_money_to_string + * @mdb: Handle to open MDB database file + * @start: Offset of the field within the current page + * @s: String that will receieve the value + * + * Returns: the string that has received the value. + */ +char *mdb_money_to_string(MdbHandle *mdb, int start, char *s) +{ + int num_bytes = 8; + int i; + int neg=0; + unsigned char multiplier[MAXPRECISION], temp[MAXPRECISION]; + unsigned char product[MAXPRECISION]; + unsigned char money[num_bytes]; + + memset(multiplier,0,MAXPRECISION); + memset(product,0,MAXPRECISION); + multiplier[0]=1; + memcpy(money, mdb->pg_buf + start, num_bytes); + + /* Perform two's complement for negative numbers */ + if (money[7] & 0x80) { + neg = 1; + for (i=0;i<num_bytes;i++) { + money[i] = ~money[i]; + } + for (i=0; i<num_bytes; i++) { + money[i] ++; + if (money[i]!=0) break; + } + } + + for (i=0;i<num_bytes;i++) { + /* product += multiplier * current byte */ + multiply_byte(product, money[i], multiplier); + + /* multiplier = multiplier * 256 */ + memcpy(temp, multiplier, MAXPRECISION); + memset(multiplier,0,MAXPRECISION); + multiply_byte(multiplier, 256, temp); + } + if (neg) { + s[0]='-'; + array_to_string(product, 4, &s[1]); + } else { + array_to_string(product, 4, s); + } + return s; +} +static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier) +{ + unsigned char number[3]; + unsigned int i, j; + + number[0]=num%10; + number[1]=(num/10)%10; + number[2]=(num/100)%10; + + for (i=0;i<MAXPRECISION;i++) { + if (multiplier[i] == 0) continue; + for (j=0;j<3;j++) { + if (number[j] == 0) continue; + product[i+j] += multiplier[i]*number[j]; + } + do_carry(product); + } + return 0; +} +static int do_carry(unsigned char *product) +{ + unsigned int j; + + for (j=0;j<MAXPRECISION-1;j++) { + if (product[j]>9) { + product[j+1]+=product[j]/10; + product[j]=product[j]%10; + } + } + if (product[j]>9) { + product[j]=product[j]%10; + } + return 0; +} +static char *array_to_string(unsigned char *array, unsigned int scale, char *s) +{ + unsigned int top, i, j=0; + + for (top=MAXPRECISION;(top>0) && (top-1>scale) && !array[top-1];top--); + + if (top == 0) { + s[j++] = '0'; + } else { + for (i=top; i>0; i--) { + if (j == top-scale) s[j++]='.'; + s[j++]=array[i-1]+'0'; + } + } + s[j]='\0'; + + return s; +} diff --git a/plugins/poi_geodownload/libmdb/options.c b/plugins/poi_geodownload/libmdb/options.c new file mode 100644 index 00000000..cdbbc662 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/options.c @@ -0,0 +1,86 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2004 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +#include <mdbtools.h> + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#define DEBUG 1 + +static unsigned long opts; +static int optset; + +static void load_options(); + +void +mdb_debug(int klass, char *fmt, ...) +{ +#ifdef DEBUG + va_list ap; + + if (!optset) load_options(); + if (klass & opts) { + va_start(ap, fmt); + vfprintf (stdout,fmt, ap); + va_end(ap); + fprintf(stdout,"\n"); + } +#endif +} + +static void +load_options() +{ + char *opt; + char *s; + + if (!optset && (s=getenv("MDBOPTS"))) { + opt = strtok(s, ":"); + do { + if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX; + if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE; + if (!strcmp(opt, "debug_write")) opts |= MDB_DEBUG_WRITE; + if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE; + if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE; + if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW; + if (!strcmp(opt, "debug_all")) { + opts |= MDB_DEBUG_LIKE; + opts |= MDB_DEBUG_WRITE; + opts |= MDB_DEBUG_USAGE; + opts |= MDB_DEBUG_OLE; + opts |= MDB_DEBUG_ROW; + } + opt = strtok(NULL,":"); + } while (opt); + } + optset = 1; +} +int +mdb_get_option(unsigned long optnum) +{ + if (!optset) load_options(); + return ((opts & optnum) > 0); +} diff --git a/plugins/poi_geodownload/libmdb/props.c b/plugins/poi_geodownload/libmdb/props.c new file mode 100644 index 00000000..61db9f54 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/props.c @@ -0,0 +1,127 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +GPtrArray * +mdb_read_props_list(gchar *kkd, int len) +{ + guint32 record_len; + int pos = 0; + gchar *name; + GPtrArray *names = NULL; + int i = 0; + + names = g_ptr_array_new(); +#ifdef MDB_DEBUG + buffer_dump(kkd, 0, len - 1); +#endif + pos = 0; + while (pos < len) { + record_len = mdb_get_int16(kkd, pos); + pos += 2; +#ifdef MDB_DEBUG + printf("%02d ",i++); + buffer_dump(kkd, pos - 2, pos + record_len - 1); +#endif + name = g_malloc(record_len + 1); + strncpy(name, &kkd[pos], record_len); + name[record_len] = '\0'; + pos += record_len; + g_ptr_array_add(names, name); +#ifdef MDB_DEBUG + printf("new len = %d\n", names->len); +#endif + } + return names; +} +void +mdb_free_props(MdbProperties *props) +{ + if (!props) return; + + if (props->name) g_free(props->name); + g_free(props); +} +MdbProperties * +mdb_alloc_props() +{ + MdbProperties *props; + + props = g_malloc0(sizeof(MdbProperties)); + + return props; +} +MdbProperties * +mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) +{ + guint32 record_len, name_len; + int pos = 0; + int elem, dtype, dsize; + gchar *name, *value; + MdbProperties *props; + int i = 0; + +#ifdef MDB_DEBUG + buffer_dump(kkd, 0, len - 1); +#endif + pos = 0; + + /* skip the name record */ + record_len = mdb_get_int16(kkd, pos); + pos += 4; + name_len = mdb_get_int16(kkd, pos); + pos += 2; + props = mdb_alloc_props(); + if (name_len) { + props->name = g_malloc(name_len + 1); + strncpy(props->name, &kkd[pos], name_len); + props->name[name_len]='\0'; + } + pos += name_len; + + props->hash = g_hash_table_new(g_str_hash, g_str_equal); + + while (pos < len) { + record_len = mdb_get_int16(kkd, pos); + elem = mdb_get_int16(kkd, pos + 4); + dtype = kkd[pos + 3]; + dsize = mdb_get_int16(kkd, pos + 6); + value = g_malloc(dsize + 1); + strncpy(value, &kkd[pos + 8], dsize); + value[dsize] = '\0'; + name = g_ptr_array_index(names,elem); +#ifdef MDB_DEBUG + printf("%02d ",i++); + buffer_dump(kkd, pos, pos + record_len - 1); + printf("elem %d dsize %d dtype %d\n", elem, dsize, dtype); +#endif + if (dtype == MDB_MEMO) dtype = MDB_TEXT; + if (dtype == MDB_BOOL) { + g_hash_table_insert(props->hash, g_strdup(name), g_strdup(kkd[pos + 8] ? "yes" : "no")); + } else { + g_hash_table_insert(props->hash, g_strdup(name), g_strdup(mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize))); + } + g_free(value); + pos += record_len; + } + return props; + +} diff --git a/plugins/poi_geodownload/libmdb/sargs.c b/plugins/poi_geodownload/libmdb/sargs.c new file mode 100644 index 00000000..b14aaa94 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/sargs.c @@ -0,0 +1,273 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * code for handling searchable arguments (sargs) used primary by the sql + * engine to support where clause handling. The sargs are configured in + * a tree with AND/OR operators connecting the child nodes. NOT operations + * have only one child on the left side. Logical operators (=,<,>,etc..) + * have no children. + * + * datatype support is a bit weak at this point. To add more types create + * a mdb_test_[type]() function and invoke it from mdb_test_sarg() + */ +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +void +mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data) +{ + if (func(node, data)) + return; + if (node->left) mdb_sql_walk_tree(node->left, func, data); + if (node->right) mdb_sql_walk_tree(node->right, func, data); +} +int +mdb_test_string(MdbSargNode *node, char *s) +{ +int rc; + + if (node->op == MDB_LIKE) { + return mdb_like_cmp(s,node->value.s); + } + rc = strncmp(node->value.s, s, 255); + switch (node->op) { + case MDB_EQUAL: + if (rc==0) return 1; + break; + case MDB_GT: + if (rc<0) return 1; + break; + case MDB_LT: + if (rc>0) return 1; + break; + case MDB_GTEQ: + if (rc<=0) return 1; + break; + case MDB_LTEQ: + if (rc>=0) return 1; + break; + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_string() for operator %d\n",node->op); + break; + } + return 0; +} +int mdb_test_int(MdbSargNode *node, gint32 i) +{ + switch (node->op) { + case MDB_EQUAL: + printf("comparing %x and %x %d\n", i, node->value.i, node->value.i == i); + if (node->value.i == i) return 1; + break; + case MDB_GT: + if (node->value.i < i) return 1; + break; + case MDB_LT: + if (node->value.i > i) return 1; + break; + case MDB_GTEQ: + if (node->value.i <= i) return 1; + break; + case MDB_LTEQ: + if (node->value.i >= i) return 1; + break; + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_int() for operator %d\n",node->op); + break; + } + return 0; +} +#if 0 +#endif +int +mdb_find_indexable_sargs(MdbSargNode *node, gpointer data) +{ + MdbSarg sarg; + + if (node->op == MDB_OR || node->op == MDB_NOT) return 1; + + /* + * right now all we do is look for sargs that are anded together from + * the root. Later we may put together OR ops into a range, and then + * range scan the leaf pages. That is col1 = 2 or col1 = 4 becomes + * col1 >= 2 and col1 <= 4 for the purpose of index scans, and then + * extra rows are thrown out when the row is tested against the main + * sarg tree. range scans are generally only a bit better than table + * scanning anyway. + * + * also, later we should support the NOT operator, but it's generally + * a pretty worthless test for indexes, ie NOT col1 = 3, we are + * probably better off table scanning. + */ + if (mdb_is_relational_op(node->op) && node->col) { + //printf("op = %d value = %s\n", node->op, node->value.s); + sarg.op = node->op; + sarg.value = node->value; + mdb_add_sarg(node->col, &sarg); + } + return 0; +} +int +mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field) +{ +char tmpbuf[256]; +int lastchar; + + if (node->op == MDB_ISNULL) { + if (field->is_null) return 0; + else return 1; + } else if (node->op == MDB_NOTNULL) { + if (field->is_null) return 1; + else return 0; + } + switch (col->col_type) { + case MDB_BOOL: + return mdb_test_int(node, !field->is_null); + break; + case MDB_BYTE: + return mdb_test_int(node, (gint32)((char *)field->value)[0]); + break; + case MDB_INT: + return mdb_test_int(node, (gint32)mdb_get_int16(field->value, 0)); + break; + case MDB_LONGINT: + return mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0)); + break; + case MDB_TEXT: + if (IS_JET4(mdb)) { + mdb_unicode2ascii(mdb, field->value, 0, field->siz, tmpbuf); + } else { + strncpy(tmpbuf, field->value, 255); + lastchar = field->siz > 255 ? 255 : field->siz; + tmpbuf[lastchar]='\0'; + } + return mdb_test_string(node, tmpbuf); + default: + fprintf(stderr, "Calling mdb_test_sarg on unknown type. Add code to mdb_test_sarg() for type %d\n",col->col_type); + break; + } + return 1; +} +int +mdb_find_field(int col_num, MdbField *fields, int num_fields) +{ + int i; + + for (i=0;i<num_fields;i++) { + if (fields[i].colnum == col_num) return i; + } + return -1; +} +int +mdb_test_sarg_node(MdbHandle *mdb, MdbSargNode *node, MdbField *fields, int num_fields) +{ + int elem; + MdbColumn *col; + int rc; + + if (mdb_is_relational_op(node->op)) { + col = node->col; + /* for const = const expressions */ + if (!col) { + return (node->value.i); + } + elem = mdb_find_field(col->col_num, fields, num_fields); + if (!mdb_test_sarg(mdb, col, node, &fields[elem])) + return 0; + } else { /* logical op */ + switch (node->op) { + case MDB_NOT: + rc = mdb_test_sarg_node(mdb, node->left, fields, num_fields); + return !rc; + break; + case MDB_AND: + if (!mdb_test_sarg_node(mdb, node->left, fields, num_fields)) + return 0; + return mdb_test_sarg_node(mdb, node->right, fields, num_fields); + break; + case MDB_OR: + if (mdb_test_sarg_node(mdb, node->left, fields, num_fields)) + return 1; + return mdb_test_sarg_node(mdb, node->right, fields, num_fields); + break; + } + } + return 1; +} +int +mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields) +{ + MdbSargNode *node; + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + + node = table->sarg_tree; + + /* there may not be a sarg tree */ + if (!node) return 1; + + return mdb_test_sarg_node(mdb, node, fields, num_fields); +} +#if 0 +int mdb_test_sargs(MdbHandle *mdb, MdbColumn *col, int offset, int len) +{ +MdbSarg *sarg; +int i; + + for (i=0;i<col->num_sargs;i++) { + sarg = g_ptr_array_index (col->sargs, i); + if (!mdb_test_sarg(mdb, col, sarg, offset, len)) { + /* sarg didn't match, no sense going on */ + return 0; + } + } + + return 1; +} +#endif +int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg) +{ +MdbSarg *sarg; + if (!col->sargs) { + col->sargs = g_ptr_array_new(); + } + sarg = g_memdup(in_sarg,sizeof(MdbSarg)); + g_ptr_array_add(col->sargs, sarg); + col->num_sargs++; + + return 1; +} +int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg) +{ + MdbColumn *col; + unsigned int i; + + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index (table->columns, i); + if (!strcasecmp(col->name,colname)) { + return mdb_add_sarg(col, in_sarg); + } + } + /* else didn't find the column return 0! */ + return 0; +} diff --git a/plugins/poi_geodownload/libmdb/stats.c b/plugins/poi_geodownload/libmdb/stats.c new file mode 100644 index 00000000..1abf2857 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/stats.c @@ -0,0 +1,74 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/** + * mdb_stats_on: + * @mdb: Handle to the (open) MDB file to collect stats on. + * + * Begins collection of statistics on an MDBHandle. + * + * Statistics in LibMDB will track the number of reads from the MDB file. The + * collection of statistics is started and stopped with the mdb_stats_on and + * mdb_stats_off functions. Collected statistics are accessed by reading the + * MdbStatistics structure or calling mdb_dump_stats. + * + */ +void +mdb_stats_on(MdbHandle *mdb) +{ + if (!mdb->stats) + mdb->stats = g_malloc0(sizeof(MdbStatistics)); + + mdb->stats->collect = TRUE; +} +/** + * mdb_stats_off: + * @mdb: pointer to handle of MDB file with active stats collection. + * + * Turns off statistics collection. + * + * If mdb_stats_off is not called, statistics will be turned off when handle + * is freed using mdb_close. + **/ +void +mdb_stats_off(MdbHandle *mdb) +{ + if (!mdb->stats) return; + + mdb->stats->collect = FALSE; +} +/** + * mdb_dump_stats: + * @mdb: pointer to handle of MDB file with active stats collection. + * + * Dumps current statistics to stdout. + **/ +void +mdb_dump_stats(MdbHandle *mdb) +{ + if (!mdb->stats) return; + + fprintf(stdout, "Physical Page Reads: %lu\n", mdb->stats->pg_reads); +} diff --git a/plugins/poi_geodownload/libmdb/table.c b/plugins/poi_geodownload/libmdb/table.c new file mode 100644 index 00000000..d3afca8c --- /dev/null +++ b/plugins/poi_geodownload/libmdb/table.c @@ -0,0 +1,368 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + + +static gint mdb_col_comparer(MdbColumn **a, MdbColumn **b) +{ + if ((*a)->col_num > (*b)->col_num) + return 1; + else if ((*a)->col_num < (*b)->col_num) + return -1; + else + return 0; +} + +unsigned char mdb_col_needs_size(int col_type) +{ + if (col_type == MDB_TEXT) { + return TRUE; + } else { + return FALSE; + } +} + +MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry) +{ + MdbTableDef *table; + + table = (MdbTableDef *) g_malloc0(sizeof(MdbTableDef)); + table->entry=entry; + strcpy(table->name, entry->object_name); + + return table; +} +void mdb_free_tabledef(MdbTableDef *table) +{ + if (!table) return; + if (table->is_temp_table) { + unsigned int i; + for (i=0; i<table->temp_table_pages->len; i++) + g_free(g_ptr_array_index(table->temp_table_pages,i)); + g_ptr_array_free(table->temp_table_pages, TRUE); + } + mdb_free_columns(table->columns); + mdb_free_indices(table->indices); + g_free(table->usage_map); + g_free(table->free_usage_map); + g_free(table); +} +MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) +{ + MdbTableDef *table; + MdbHandle *mdb = entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + int len, row_start, pg_row; + char *buf; + + table = mdb_alloc_tabledef(entry); + + mdb_read_pg(mdb, entry->table_pg); + if (mdb->pg_buf[0] != 0x02) return NULL; /* not a valid table def page */ + + len = mdb_pg_get_int16(mdb,8); + + table->num_rows = mdb_pg_get_int32(mdb, fmt->tab_num_rows_offset); + table->num_var_cols = mdb_pg_get_int16(mdb, fmt->tab_num_cols_offset-2); + table->num_cols = mdb_pg_get_int16(mdb, fmt->tab_num_cols_offset); + table->num_idxs = mdb_pg_get_int32(mdb, fmt->tab_num_idxs_offset); + table->num_real_idxs = mdb_pg_get_int32(mdb, fmt->tab_num_ridxs_offset); + /* grab a copy of the usage map */ + pg_row = mdb_pg_get_int32(mdb, fmt->tab_usage_map_offset); + mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->map_sz)); + table->usage_map = g_memdup(buf + row_start, table->map_sz); + if (mdb_get_option(MDB_DEBUG_USAGE)) + buffer_dump(buf, row_start, row_start+table->map_sz-1); + mdb_debug(MDB_DEBUG_USAGE,"usage map found on page %ld row %d start %d len %d", + pg_row >> 8, pg_row & 0xff, row_start, table->map_sz); + + /* grab a copy of the free space page map */ + pg_row = mdb_pg_get_int32(mdb, fmt->tab_free_map_offset); + mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->freemap_sz)); + table->free_usage_map = g_memdup(buf + row_start, table->freemap_sz); + mdb_debug(MDB_DEBUG_USAGE,"free map found on page %ld row %d start %d len %d\n", + pg_row >> 8, pg_row & 0xff, row_start, table->freemap_sz); + + table->first_data_pg = mdb_pg_get_int16(mdb, fmt->tab_first_dpg_offset); + + return table; +} +MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type) +{ + unsigned int i; + MdbCatalogEntry *entry; + + mdb_read_catalog(mdb, obj_type); + + for (i=0; i<mdb->num_catalog; i++) { + entry = g_ptr_array_index(mdb->catalog, i); + if (!strcasecmp(entry->object_name, table_name)) + return mdb_read_table(entry); + } + + return NULL; +} + +/* +** read the next page if offset is > pg_size +** return true if page was read +*/ +int +read_pg_if(MdbHandle *mdb, int *cur_pos, int offset) +{ + if (*cur_pos + offset >= mdb->fmt->pg_size) { + mdb_read_pg(mdb, mdb_pg_get_int32(mdb,4)); + *cur_pos = 8 - (mdb->fmt->pg_size - (*cur_pos)); + return 1; + } + return 0; +} +guint32 +read_pg_if_32(MdbHandle *mdb, int *cur_pos) +{ + unsigned char c[4]; + int i, rc = 0; + + for (i=0;i<4;i++) { + rc += read_pg_if(mdb, cur_pos, i); + c[i] = mdb->pg_buf[(*cur_pos) + i]; + } + return mdb_get_int32(c, 0); +} +guint16 +read_pg_if_16(MdbHandle *mdb, int *cur_pos) +{ + unsigned char low_byte, high_byte; + int rc = 0; + + rc += read_pg_if(mdb, cur_pos, 0); + low_byte = mdb->pg_buf[*cur_pos]; + rc += read_pg_if(mdb, cur_pos, 1); + high_byte = mdb->pg_buf[(*cur_pos) + 1]; + + return (high_byte * 256 + low_byte); +} +guint16 +read_pg_if_n(MdbHandle *mdb, unsigned char *buf, int *cur_pos, int len) +{ + if (*cur_pos + len < mdb->fmt->pg_size) { + memcpy(buf, &mdb->pg_buf[*cur_pos], len); + return 0; + } else { + int half = mdb->fmt->pg_size - *cur_pos; + memcpy(buf, &mdb->pg_buf[*cur_pos], half); + mdb_read_pg(mdb, mdb_pg_get_int32(mdb,4)); + memcpy(buf + half, &mdb->pg_buf[8], len - half); + *cur_pos = 8 - half; + return 1; + } +} + +void mdb_append_column(GPtrArray *columns, MdbColumn *in_col) +{ + g_ptr_array_add(columns, g_memdup(in_col,sizeof(MdbColumn))); +} +void mdb_free_columns(GPtrArray *columns) +{ + unsigned int i; + + if (!columns) return; + for (i=0; i<columns->len; i++) + g_free (g_ptr_array_index(columns, i)); + g_ptr_array_free(columns, TRUE); +} +GPtrArray *mdb_read_columns(MdbTableDef *table) +{ + MdbHandle *mdb = table->entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + MdbColumn *pcol; + unsigned char *col; + unsigned int i; + int cur_pos, name_sz; + + table->columns = g_ptr_array_new(); + + col = (unsigned char *) g_malloc(fmt->tab_col_entry_size); + + cur_pos = fmt->tab_cols_start_offset + + (table->num_real_idxs * fmt->tab_ridx_entry_size); + + /* new code based on patch submitted by Tim Nelson 2000.09.27 */ + + /* + ** column attributes + */ + for (i=0;i<table->num_cols;i++) { +#ifdef MDB_DEBUG + /* printf("column %d\n", i); + buffer_dump(mdb->pg_buf, cur_pos ,cur_pos + 18); */ +#endif + read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size); + cur_pos += fmt->tab_col_entry_size; + pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn)); + + pcol->col_type = col[0]; + + // col_num_offset == 1 or 5 + pcol->col_num = col[fmt->col_num_offset]; + + //fprintf(stdout,"----- column %d -----\n",pcol->col_num); + // col_var == 3 or 7 + pcol->var_col_num = mdb_get_int16(col, fmt->tab_col_offset_var); + //fprintf(stdout,"var column pos %d\n",pcol->var_col_num); + + // col_var == 5 or 9 + pcol->row_col_num = mdb_get_int16(col, fmt->tab_row_col_num_offset); + //fprintf(stdout,"row column num %d\n",pcol->row_col_num); + + /* FIXME: can this be right in Jet3 and Jet4? */ + if (pcol->col_type == MDB_NUMERIC) { + pcol->col_prec = col[11]; + pcol->col_scale = col[12]; + } + + // col_fixed_offset == 13 or 15 + pcol->is_fixed = col[fmt->col_fixed_offset] & 0x01 ? 1 : 0; + + // col_fixed_offset == 13 or 15 + pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed); + //fprintf(stdout,"fixed column offset %d\n",pcol->fixed_offset); + //fprintf(stdout,"col type %s\n",pcol->is_fixed ? "fixed" : "variable"); + + if (pcol->col_type != MDB_BOOL) { + // col_size_offset == 16 or 23 + pcol->col_size = mdb_get_int16(col, fmt->col_size_offset); + } else { + pcol->col_size=0; + } + + g_ptr_array_add(table->columns, pcol); + } + + g_free (col); + + /* + ** column names - ordered the same as the column attributes table + */ + for (i=0;i<table->num_cols;i++) { + pcol = g_ptr_array_index(table->columns, i); + + if (IS_JET4(mdb)) { + char *tmp_buf; + name_sz = read_pg_if_16(mdb, &cur_pos); + cur_pos += 2; + tmp_buf = (char *) g_malloc(name_sz); + read_pg_if_n(mdb, tmp_buf, &cur_pos, name_sz); + mdb_unicode2ascii(mdb, tmp_buf, 0, name_sz, pcol->name); + g_free(tmp_buf); + cur_pos += name_sz; + } else if (IS_JET3(mdb)) { + read_pg_if(mdb, &cur_pos, 0); + name_sz = mdb->pg_buf[cur_pos]; + cur_pos++; + read_pg_if_n(mdb, pcol->name, &cur_pos, name_sz); + pcol->name[name_sz]='\0'; + cur_pos += name_sz; + } else { + fprintf(stderr,"Unknown MDB version\n"); + } + } + + /* Sort the columns by col_num */ + g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer); + + table->index_start = cur_pos; + return table->columns; +} + +void mdb_table_dump(MdbCatalogEntry *entry) +{ +MdbTableDef *table; +MdbColumn *col; +int coln; +MdbIndex *idx; +MdbHandle *mdb = entry->mdb; +unsigned int i, bitn; +guint32 pgnum; + + table = mdb_read_table(entry); + fprintf(stdout,"definition page = %lu\n",entry->table_pg); + fprintf(stdout,"number of datarows = %d\n",table->num_rows); + fprintf(stdout,"number of columns = %d\n",table->num_cols); + fprintf(stdout,"number of indices = %d\n",table->num_real_idxs); + + mdb_read_columns(table); + mdb_read_indices(table); + + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index(table->columns,i); + + fprintf(stdout,"column %d Name: %-20s Type: %s(%d)\n", + i, col->name, + mdb_get_coltype_string(mdb->default_backend, col->col_type), + col->col_size); + } + + for (i=0;i<table->num_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + mdb_index_dump(table, idx); + } + if (table->usage_map) { + printf("pages reserved by this object\n"); + printf("usage map pg %" G_GUINT32_FORMAT "\n", + table->map_base_pg); + printf("free map pg %" G_GUINT32_FORMAT "\n", + table->freemap_base_pg); + pgnum = mdb_get_int32(table->usage_map,1); + /* the first 5 bytes of the usage map mean something */ + coln = 0; + for (i=5;i<table->map_sz;i++) { + for (bitn=0;bitn<8;bitn++) { + if (table->usage_map[i] & 1 << bitn) { + coln++; + printf("%6" G_GUINT32_FORMAT, pgnum); + if (coln==10) { + printf("\n"); + coln = 0; + } else { + printf(" "); + } + } + pgnum++; + } + } + printf("\n"); + } +} + +int mdb_is_user_table(MdbCatalogEntry *entry) +{ + return ((entry->object_type == MDB_TABLE) + && !(entry->flags & 0x80000002)) ? 1 : 0; +} +int mdb_is_system_table(MdbCatalogEntry *entry) +{ + return ((entry->object_type == MDB_TABLE) + && (entry->flags & 0x80000002)) ? 1 : 0; +} diff --git a/plugins/poi_geodownload/libmdb/worktable.c b/plugins/poi_geodownload/libmdb/worktable.c new file mode 100644 index 00000000..6f893dcf --- /dev/null +++ b/plugins/poi_geodownload/libmdb/worktable.c @@ -0,0 +1,99 @@ +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2004 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +/* + * Temp table routines. These are currently used to generate mock results for + * commands like "list tables" and "describe table" + */ + +void +mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed) +{ + memset(tcol,0,sizeof(MdbColumn)); + strcpy(tcol->name, col_name); + tcol->col_type = col_type; + if ((col_type == MDB_TEXT) || (col_type == MDB_MEMO)) { + tcol->col_size = col_size; + } else { + tcol->col_size = mdb_col_fixed_size(tcol); + } + tcol->is_fixed = is_fixed; +} +void +mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int colnum) +{ + field->value = value; + field->siz = siz; + field->is_fixed = is_fixed; + field->is_null = is_null; + field->start = start; + field->colnum = colnum; +} +MdbTableDef * +mdb_create_temp_table(MdbHandle *mdb, char *name) +{ + MdbCatalogEntry *entry; + MdbTableDef *table; + + /* dummy up a catalog entry */ + entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry)); + entry->mdb = mdb; + entry->object_type = MDB_TABLE; + entry->table_pg = 0; + strcpy(entry->object_name, name); + + table = mdb_alloc_tabledef(entry); + table->columns = g_ptr_array_new(); + table->is_temp_table = 1; + table->temp_table_pages = g_ptr_array_new(); + + return table; +} +void +mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col) +{ + col->col_num = table->num_cols; + if (!col->is_fixed) + col->var_col_num = table->num_var_cols++; + g_ptr_array_add(table->columns, g_memdup(col, sizeof(MdbColumn))); + table->num_cols++; +} +/* + * Should be called after setting up all temp table columns + */ +void mdb_temp_columns_end(MdbTableDef *table) +{ + MdbColumn *col; + unsigned int i; + unsigned int start = 0; + + for (i=0; i<table->num_cols; i++) { + col = g_ptr_array_index(table->columns, i); + if (col->is_fixed) { + col->fixed_offset = start; + start += col->col_size; + } + } +} diff --git a/plugins/poi_geodownload/libmdb/write.c b/plugins/poi_geodownload/libmdb/write.c new file mode 100644 index 00000000..1cff96a4 --- /dev/null +++ b/plugins/poi_geodownload/libmdb/write.c @@ -0,0 +1,878 @@ +/* MDB Tools - A library for reading MS Access database file + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mdbtools.h" +#include "time.h" +#include "math.h" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + + +//static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg); +static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields); + +void +_mdb_put_int16(unsigned char *buf, guint32 offset, guint32 value) +{ + buf[offset] = value % 256; + value /= 256; + buf[offset+1] = value % 256; +} +void +_mdb_put_int32(unsigned char *buf, guint32 offset, guint32 value) +{ + buf[offset] = value % 256; + value /= 256; + buf[offset+1] = value % 256; + value /= 256; + buf[offset+2] = value % 256; + value /= 256; + buf[offset+3] = value % 256; +} +ssize_t +mdb_write_pg(MdbHandle *mdb, unsigned long pg) +{ + ssize_t len; + struct stat status; + off_t offset = pg * mdb->fmt->pg_size; + + fstat(mdb->f->fd, &status); + /* is page beyond current size + 1 ? */ + if (status.st_size < offset + mdb->fmt->pg_size) { + fprintf(stderr,"offset %lu is beyond EOF\n",offset); + return 0; + } + lseek(mdb->f->fd, offset, SEEK_SET); + len = write(mdb->f->fd,mdb->pg_buf,mdb->fmt->pg_size); + if (len==-1) { + perror("write"); + return 0; + } else if (len<mdb->fmt->pg_size) { + /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->pg_size); */ + return 0; + } + mdb->cur_pos = 0; + return len; +} + +static int +mdb_is_col_indexed(MdbTableDef *table, int colnum) +{ + unsigned int i, j; + MdbIndex *idx; + + for (i=0;i<table->num_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + for (j=0;j<idx->num_keys;j++) { + if (idx->key_col_num[j]==colnum) return 1; + } + } + return 0; +} +static int +mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + unsigned char *pg_buf = mdb->pg_buf; + unsigned int i; + unsigned int row_var_cols=0, row_fixed_cols, row_cols; + unsigned int fixed_cols_found; + unsigned int col_start; + unsigned char *nullmask; + unsigned int bitmask_sz; + unsigned int byte_num, bit_num; + unsigned int *var_col_offsets = NULL; + + if (mdb_get_option(MDB_DEBUG_ROW)) { + buffer_dump(pg_buf, row_start, row_end); + } + + row_cols = mdb_pg_get_int16(mdb, row_start); + + bitmask_sz = (row_cols + 7) / 8; + nullmask = &pg_buf[row_end - bitmask_sz + 1]; + + /* read table of variable column locations */ + if (table->num_var_cols > 0) { + row_var_cols = mdb_pg_get_int16(mdb, row_end - bitmask_sz - 1); + var_col_offsets = (int *)g_malloc((row_var_cols+1)*sizeof(int)); + for (i=0; i<row_var_cols+1; i++) { + var_col_offsets[i] = mdb_pg_get_int16(mdb, + row_end - bitmask_sz - 3 - (i*2)); + } + } + fixed_cols_found = 0; + row_fixed_cols = row_cols - row_var_cols; + + /* read information into fields[] */ + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index(table->columns,i); + fields[i].colnum = i; + fields[i].is_fixed = (mdb_is_fixed_col(col)) ? 1 : 0; + byte_num = col->col_num / 8; + bit_num = col->col_num % 8; + /* logic on nulls is reverse, 1 is not null, 0 is null */ + fields[i].is_null = nullmask[byte_num] & (1 << bit_num) ? 0 : 1; + + if ((fields[i].is_fixed) + && (fixed_cols_found < row_fixed_cols)) { + col_start = col->fixed_offset + 2; + fields[i].start = row_start + col_start; + fields[i].value = &pg_buf[row_start + col_start]; + fields[i].siz = col->col_size; + fixed_cols_found++; + /* Use col->var_col_num because a deleted column is still + * present in the variable column offsets table for the row */ + } else if ((!fields[i].is_fixed) + && (col->var_col_num < row_var_cols)) { + col_start = var_col_offsets[col->var_col_num]; + fields[i].start = row_start + col_start; + fields[i].value = &pg_buf[row_start + col_start]; + fields[i].siz = var_col_offsets[(col->var_col_num)+1] - + col_start; + } else { + fields[i].start = 0; + fields[i].value = NULL; + fields[i].siz = 0; + fields[i].is_null = 1; + } + } + g_free(var_col_offsets); + + return row_cols; +} +static int +mdb_crack_row3(MdbTableDef *table, int row_start, int row_end, MdbField *fields) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + unsigned char *pg_buf = mdb->pg_buf; + unsigned int i; + unsigned int row_var_cols = 0, row_fixed_cols, row_cols; + unsigned int fixed_cols_found, var_cols_found; + unsigned int col_start; + unsigned char *nullmask; + unsigned int bitmask_sz; + unsigned int byte_num, bit_num; + unsigned int *var_col_offsets = NULL; + unsigned int num_jumps = 0, jumps_used = 0; + unsigned int col_ptr, row_len; + + if (mdb_get_option(MDB_DEBUG_ROW)) { + buffer_dump(pg_buf, row_start, row_end); + } + + row_cols = pg_buf[row_start]; + + bitmask_sz = (row_cols + 7) / 8; + nullmask = &pg_buf[row_end - bitmask_sz + 1]; + + /* read table of variable column locations */ + if (table->num_var_cols > 0) { + row_var_cols = pg_buf[row_end - bitmask_sz]; + row_len = row_end - row_start + 1; + num_jumps = (row_len - 1) / 256; + col_ptr = row_end - bitmask_sz - num_jumps - 1; + /* If last jump is a dummy value, ignore it */ + if ((col_ptr-row_start-row_var_cols)/256 < num_jumps) + num_jumps--; + + var_col_offsets = (int *)g_malloc((row_var_cols+1)*sizeof(int)); + jumps_used = 0; + for (i=0; i<row_var_cols+1; i++) { + if ((jumps_used < num_jumps) + && (i == pg_buf[row_end-bitmask_sz-jumps_used-1])) { + jumps_used++; + } + var_col_offsets[i] = pg_buf[col_ptr-i]+(jumps_used*256); + } + } + fixed_cols_found = 0; + var_cols_found = 0; + row_fixed_cols = row_cols - row_var_cols; + + if (mdb_get_option(MDB_DEBUG_ROW)) { + fprintf(stdout,"bitmask_sz %d num_jumps %d\n",bitmask_sz, num_jumps); + fprintf(stdout,"row_var_cols %d\n", row_var_cols); + fprintf(stdout,"row_fixed_cols %d\n", row_fixed_cols); + } + + /* read information into fields[] */ + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index (table->columns, i); + fields[i].colnum = i; + fields[i].is_fixed = (mdb_is_fixed_col(col)) ? 1 : 0; + byte_num = col->col_num / 8; + bit_num = col->col_num % 8; + /* logic on nulls is reverse, 1 is not null, 0 is null */ + fields[i].is_null = nullmask[byte_num] & (1 << bit_num) ? 0 : 1; + + if ((fields[i].is_fixed) + && (fixed_cols_found < row_fixed_cols)) { + col_start = col->fixed_offset + 1; + fields[i].start = row_start + col_start; + fields[i].value = &pg_buf[row_start + col_start]; + fields[i].siz = col->col_size; + fixed_cols_found++; + } else if ((!fields[i].is_fixed) + && (var_cols_found < row_var_cols)) { + col_start = var_col_offsets[var_cols_found]; + fields[i].start = row_start + col_start; + fields[i].value = &pg_buf[row_start + col_start]; + fields[i].siz = var_col_offsets[var_cols_found+1] - + col_start; + var_cols_found++; + } else { + fields[i].start = 0; + fields[i].value = NULL; + fields[i].siz = 0; + fields[i].is_null = 1; + } + } + g_free(var_col_offsets); + + return row_cols; +} +/** + * mdb_crack_row: + * @table: Table that the row belongs to + * @row_start: offset to start of row on current page + * @row_end: offset to end of row on current page + * @fields: pointer to MdbField array to be popluated by mdb_crack_row + * + * Cracks a row buffer apart into its component fields. + * + * A row buffer is that portion of a data page which contains the values for + * that row. Its beginning and end can be found in the row offset table. + * + * The resulting MdbField array contains pointers into the row for each field + * present. Be aware that by modifying field[]->value, you would be modifying + * the row buffer itself, not a copy. + * + * This routine is mostly used internally by mdb_fetch_row() but may have some + * applicability for advanced application programs. + * + * Return value: number of fields present. + */ +int +mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields) +{ +MdbCatalogEntry *entry = table->entry; +MdbHandle *mdb = entry->mdb; + + if (IS_JET4(mdb)) { + return mdb_crack_row4(table, row_start, row_end, fields); + } else { + return mdb_crack_row3(table, row_start, row_end, fields); + } +} + +static int +mdb_pack_null_mask(unsigned char *buffer, int num_fields, MdbField *fields) +{ + int pos = 0, bit = 0, byte = 0; + int i; + + /* 'Not null' bitmap */ + for (i=0; i<num_fields; i++) { + /* column is null if bit is clear (0) */ + if (!fields[i].is_null) { + byte |= 1 << bit; + //printf("%d %d %d %d\n", i, bit, 1 << bit, byte); + } + bit++; + if (bit==8) { + buffer[pos++] = byte; + bit = byte = 0; + } + } + /* if we've written any bits to the current byte, flush it */ + if (bit) + buffer[pos++] = byte; + + return pos; +} +/* fields must be ordered with fixed columns first, then vars, subsorted by + * column number */ +static int +mdb_pack_row4(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields) +{ + unsigned int pos = 0; + unsigned int var_cols = 0; + unsigned int i; + + row_buffer[pos++] = num_fields & 0xff; + row_buffer[pos++] = (num_fields >> 8) & 0xff; + + /* Fixed length columns */ + for (i=0;i<num_fields;i++) { + if (fields[i].is_fixed) { + fields[i].offset = pos; + if (!fields[i].is_null) { + memcpy(&row_buffer[pos], fields[i].value, fields[i].siz); + } + pos += fields[i].siz; + } + } + /* For tables without variable-length columns */ + if (table->num_var_cols == 0) { + pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); + return pos; + } + /* Variable length columns */ + for (i=0;i<num_fields;i++) { + if (!fields[i].is_fixed) { + var_cols++; + fields[i].offset = pos; + if (! fields[i].is_null) { + memcpy(&row_buffer[pos], fields[i].value, fields[i].siz); + pos += fields[i].siz; + } + } + } + /* EOD */ + row_buffer[pos] = pos & 0xff; + row_buffer[pos+1] = (pos >> 8) & 0xff; + pos += 2; + + /* Offsets of the variable-length columns */ + for (i=num_fields; i>0; i--) { + if (!fields[i-1].is_fixed) { + row_buffer[pos++] = fields[i-1].offset & 0xff; + row_buffer[pos++] = (fields[i-1].offset >> 8) & 0xff; + } + } + /* Number of variable-length columns */ + row_buffer[pos++] = var_cols & 0xff; + row_buffer[pos++] = (var_cols >> 8) & 0xff; + + pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); + return pos; +} + +static int +mdb_pack_row3(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields) +{ + unsigned int pos = 0; + unsigned int var_cols = 0; + unsigned int i, j; + unsigned char *offset_high; + + row_buffer[pos++] = num_fields; + + /* Fixed length columns */ + for (i=0;i<num_fields;i++) { + if (fields[i].is_fixed) { + fields[i].offset = pos; + if (!fields[i].is_null) { + memcpy(&row_buffer[pos], fields[i].value, fields[i].siz); + } + pos += fields[i].siz; + } + } + /* For tables without variable-length columns */ + if (table->num_var_cols == 0) { + pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); + return pos; + } + /* Variable length columns */ + for (i=0;i<num_fields;i++) { + if (!fields[i].is_fixed) { + var_cols++; + fields[i].offset = pos; + if (! fields[i].is_null) { + memcpy(&row_buffer[pos], fields[i].value, fields[i].siz); + pos += fields[i].siz; + } + } + } + + offset_high = (unsigned char *) g_malloc(var_cols+1); + offset_high[0] = (pos << 8) & 0xff; + j = 1; + + /* EOD */ + row_buffer[pos] = pos & 0xff; + pos++; + + /* Variable length column offsets */ + for (i=num_fields; i>0; i--) { + if (!fields[i-1].is_fixed) { + row_buffer[pos++] = fields[i-1].offset & 0xff; + offset_high[j++] = (fields[i-1].offset << 8) & 0xff; + } + } + + /* Dummy jump table entry */ + if (offset_high[0] < (pos+(num_fields+7)/8-1)/255) { + row_buffer[pos++] = 0xff; + } + /* Jump table */ + for (i=0; i<var_cols; i++) { + if (offset_high[i] > offset_high[i+1]) { + row_buffer[pos++] = var_cols-i; + } + } + g_free(offset_high); + + row_buffer[pos++] = var_cols; + + pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); + return pos; +} +int +mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, int unsigned num_fields, MdbField *fields) +{ + if (table->is_temp_table) { + unsigned int i; + for (i=0; i<num_fields; i++) { + MdbColumn *c = g_ptr_array_index(table->columns, i); + fields[i].is_null = (fields[i].value) ? 0 : 1; + fields[i].colnum = i; + fields[i].is_fixed = c->is_fixed; + if ((c->col_type != MDB_TEXT) + && (c->col_type != MDB_MEMO)) { + fields[i].siz = c->col_size; + } + } + } + if (IS_JET4(table->entry->mdb)) { + return mdb_pack_row4(table, row_buffer, num_fields, fields); + } else { + return mdb_pack_row3(table, row_buffer, num_fields, fields); + } +} +int +mdb_pg_get_freespace(MdbHandle *mdb) +{ + int rows, free_start, free_end; + int row_count_offset = mdb->fmt->row_count_offset; + + rows = mdb_pg_get_int16(mdb, row_count_offset); + free_start = row_count_offset + 2 + (rows * 2); + free_end = mdb_pg_get_int16(mdb, row_count_offset + (rows * 2)); + mdb_debug(MDB_DEBUG_WRITE,"free space left on page = %d", free_end - free_start); + return (free_end - free_start); +} +unsigned char * +mdb_new_leaf_pg(MdbCatalogEntry *entry) +{ + MdbHandle *mdb = entry->mdb; + unsigned char *new_pg; + + new_pg = (unsigned char *) g_malloc0(mdb->fmt->pg_size); + + new_pg[0]=0x04; + new_pg[1]=0x01; + _mdb_put_int32(new_pg, 4, entry->table_pg); + + return new_pg; +} +unsigned char * +mdb_new_data_pg(MdbCatalogEntry *entry) +{ + MdbFormatConstants *fmt = entry->mdb->fmt; + unsigned char *new_pg; + + new_pg = (unsigned char *) g_malloc0(fmt->pg_size); + + new_pg[0]=0x01; + new_pg[1]=0x01; + _mdb_put_int16(new_pg, 2, fmt->pg_size - fmt->row_count_offset - 2); + _mdb_put_int32(new_pg, 4, entry->table_pg); + + return new_pg; +} + +int +mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) +{ + unsigned int i; + MdbIndex *idx; + + for (i=0;i<table->num_idxs;i++) { + idx = g_ptr_array_index (table->indices, i); + mdb_debug(MDB_DEBUG_WRITE,"Updating %s (%d).", idx->name, idx->index_type); + if (idx->index_type==1) { + mdb_update_index(table, idx, num_fields, fields, pgnum, rownum); + } + } + return 1; +} + +int +mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + + table->scan_idx = idx; + table->chain = g_malloc0(sizeof(MdbIndexChain)); + table->mdbidx = mdb_clone_handle(mdb); + mdb_read_pg(table->mdbidx, table->scan_idx->first_pg); + + return 1; +} + +int +mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + int idx_xref[16]; + unsigned int i, j; + MdbIndexChain *chain; + MdbField idx_fields[10]; + + for (i = 0; i < idx->num_keys; i++) { + for (j = 0; j < num_fields; j++) { + // key_col_num is 1 based, can't remember why though + if (fields[j].colnum == idx->key_col_num[i]-1) { + idx_xref[i] = j; + idx_fields[i] = fields[j]; + } + } + } + for (i = 0; i < idx->num_keys; i++) { + fprintf(stdout, "key col %d (%d) is mapped to field %d (%d %d)\n", + i, idx->key_col_num[i], idx_xref[i], fields[idx_xref[i]].colnum, + fields[idx_xref[i]].siz); + } + for (i = 0; i < num_fields; i++) { + fprintf(stdout, "%d (%d %d)\n", + i, fields[i].colnum, + fields[i].siz); + } + + chain = g_malloc0(sizeof(MdbIndexChain)); + + mdb_index_find_row(mdb, idx, chain, pgnum, rownum); + printf("chain depth = %d\n", chain->cur_depth); + printf("pg = %" G_GUINT32_FORMAT "\n", + chain->pages[chain->cur_depth-1].pg); + //mdb_copy_index_pg(table, idx, &chain->pages[chain->cur_depth-1]); + mdb_add_row_to_leaf_pg(table, idx, &chain->pages[chain->cur_depth-1], idx_fields); + + return 1; +} + +int +mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields) +{ + int new_row_size; + unsigned char row_buffer[4096]; + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + guint32 pgnum; + guint16 rownum; + + if (!mdb->f->writable) { + fprintf(stderr, "File is not open for writing\n"); + return 0; + } + new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields); + if (mdb_get_option(MDB_DEBUG_WRITE)) { + buffer_dump(row_buffer, 0, new_row_size-1); + } + pgnum = mdb_map_find_next_freepage(table, new_row_size); + if (!pgnum) { + fprintf(stderr, "Unable to allocate new page.\n"); + return 0; + } + + rownum = mdb_add_row_to_pg(table, row_buffer, new_row_size); + + if (mdb_get_option(MDB_DEBUG_WRITE)) { + buffer_dump(mdb->pg_buf, 0, 39); + buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1); + } + mdb_debug(MDB_DEBUG_WRITE, "writing page %d", pgnum); + if (!mdb_write_pg(mdb, pgnum)) { + fprintf(stderr, "write failed! exiting...\n"); + exit(1); + } + + mdb_update_indexes(table, num_fields, fields, pgnum, rownum); + + return 1; +} +/* + * Assumes caller has verfied space is available on page and adds the new + * row to the current pg_buf. + */ +guint16 +mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size) +{ + unsigned char *new_pg; + int num_rows, i, pos, row_start, row_end, row_size; + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbFormatConstants *fmt = mdb->fmt; + + if (table->is_temp_table) { + GPtrArray *pages = table->temp_table_pages; + if (pages->len == 0) { + new_pg = mdb_new_data_pg(entry); + g_ptr_array_add(pages, new_pg); + } else { + new_pg = g_ptr_array_index(pages, pages->len - 1); + if (mdb_get_int16(new_pg, 2) < new_row_size + 2) { + new_pg = mdb_new_data_pg(entry); + g_ptr_array_add(pages, new_pg); + } + } + + num_rows = mdb_get_int16(new_pg, fmt->row_count_offset); + pos = (num_rows == 0) ? fmt->pg_size : + mdb_get_int16(new_pg, fmt->row_count_offset + (num_rows*2)); + } else { /* is not a temp table */ + new_pg = mdb_new_data_pg(entry); + + num_rows = mdb_pg_get_int16(mdb, fmt->row_count_offset); + pos = fmt->pg_size; + + /* copy existing rows */ + for (i=0;i<num_rows;i++) { + row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2)); + row_end = mdb_find_end_of_row(mdb, i); + row_size = row_end - row_start + 1; + pos -= row_size; + memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size); + _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos); + } + } + + /* add our new row */ + pos -= new_row_size; + memcpy(&new_pg[pos], row_buffer, new_row_size); + /* add row to the row offset table */ + _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (num_rows*2), pos); + + /* update number rows on this page */ + num_rows++; + _mdb_put_int16(new_pg, fmt->row_count_offset, num_rows); + + /* update the freespace */ + _mdb_put_int16(new_pg,2,pos - fmt->row_count_offset - 2 - (num_rows*2)); + + /* copy new page over old */ + if (!table->is_temp_table) { + memcpy(mdb->pg_buf, new_pg, fmt->pg_size); + g_free(new_pg); + } + + return num_rows; +} +int +mdb_update_row(MdbTableDef *table) +{ +int row_start, row_end; +unsigned int i; +MdbColumn *col; +MdbCatalogEntry *entry = table->entry; +MdbHandle *mdb = entry->mdb; +MdbFormatConstants *fmt = mdb->fmt; +MdbField fields[256]; +unsigned char row_buffer[4096]; +int old_row_size, new_row_size, delta; +unsigned int num_fields; + + if (!mdb->f->writable) { + fprintf(stderr, "File is not open for writing\n"); + return 0; + } + row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + ((table->cur_row-1)*2)); + row_end = mdb_find_end_of_row(mdb, table->cur_row-1); + old_row_size = row_end - row_start; + + row_start &= 0x0FFF; /* remove flags */ + + mdb_debug(MDB_DEBUG_WRITE,"page %lu row %d start %d end %d", (unsigned long) table->cur_phys_pg, table->cur_row-1, row_start, row_end); + if (mdb_get_option(MDB_DEBUG_LIKE)) + buffer_dump(mdb->pg_buf, row_start, row_end); + + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index(table->columns,i); + if (col->bind_ptr && mdb_is_col_indexed(table,i)) { + fprintf(stderr, "Attempting to update column that is part of an index\n"); + return 0; + } + } + num_fields = mdb_crack_row(table, row_start, row_end, fields); + + if (mdb_get_option(MDB_DEBUG_WRITE)) { + for (i=0;i<num_fields;i++) { + printf("col %d %d start %d siz %d\n", i, fields[i].colnum, fields[i].start, fields[i].siz); + } + } + for (i=0;i<table->num_cols;i++) { + col = g_ptr_array_index(table->columns,i); + if (col->bind_ptr) { + printf("yes\n"); + fields[i].value = col->bind_ptr; + fields[i].siz = *(col->len_ptr); + } + } + + new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields); + if (mdb_get_option(MDB_DEBUG_WRITE)) + buffer_dump(row_buffer, 0, new_row_size-1); + delta = new_row_size - old_row_size; + if ((mdb_pg_get_freespace(mdb) - delta) < 0) { + fprintf(stderr, "No space left on this page, update will not occur\n"); + return 0; + } + /* do it! */ + mdb_replace_row(table, table->cur_row-1, row_buffer, new_row_size); + return 0; +} +int +mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size) +{ +MdbCatalogEntry *entry = table->entry; +MdbHandle *mdb = entry->mdb; +MdbFormatConstants *fmt = mdb->fmt; +unsigned char *new_pg; +guint16 num_rows; +int row_start, row_end, row_size; +int i, pos; + + if (mdb_get_option(MDB_DEBUG_WRITE)) { + buffer_dump(mdb->pg_buf, 0, 39); + buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1); + } + mdb_debug(MDB_DEBUG_WRITE,"updating row %d on page %lu", row, (unsigned long) table->cur_phys_pg); + new_pg = mdb_new_data_pg(entry); + + num_rows = mdb_pg_get_int16(mdb, fmt->row_count_offset); + _mdb_put_int16(new_pg, fmt->row_count_offset, num_rows); + + pos = mdb->fmt->pg_size; + + /* rows before */ + for (i=0;i<row;i++) { + row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2)); + row_end = mdb_find_end_of_row(mdb, i); + row_size = row_end - row_start + 1; + pos -= row_size; + memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size); + _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos); + } + + /* our row */ + pos -= new_row_size; + memcpy(&new_pg[pos], new_row, new_row_size); + _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (row*2), pos); + + /* rows after */ + for (i=row+1;i<num_rows;i++) { + row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2)); + row_end = mdb_find_end_of_row(mdb, i); + row_size = row_end - row_start + 1; + pos -= row_size; + memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size); + _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos); + } + + /* almost done, copy page over current */ + memcpy(mdb->pg_buf, new_pg, fmt->pg_size); + + g_free(new_pg); + + _mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb)); + if (mdb_get_option(MDB_DEBUG_WRITE)) { + buffer_dump(mdb->pg_buf, 0, 39); + buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1); + } + /* drum roll, please */ + if (!mdb_write_pg(mdb, table->cur_phys_pg)) { + fprintf(stderr, "write failed! exiting...\n"); + exit(1); + } + return 0; +} +static int +mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields) +/*, guint32 pgnum, guint16 rownum) +static int +mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg) +*/ +{ + MdbCatalogEntry *entry = table->entry; + MdbHandle *mdb = entry->mdb; + MdbColumn *col; + guint32 pg; + guint16 row; + unsigned char *new_pg; + unsigned char key_hash[256]; + unsigned char iflag; + int keycol; + + new_pg = mdb_new_leaf_pg(entry); + + mdb_index_page_reset(ipg); + mdb_read_pg(mdb, ipg->pg); + + /* do we support this index type yet? */ + if (idx->num_keys > 1) { + fprintf(stderr,"multikey indexes not yet supported, aborting\n"); + return 0; + } + keycol = idx->key_col_num[0]; + col = g_ptr_array_index (table->columns, keycol - 1); + printf("keycol = %d (%s)\n", keycol, col->name); + if (!mdb_is_fixed_col(col)) { + fprintf(stderr,"variable length key columns not yet supported, aborting\n"); + return 0; + } + printf("col size = %d\n", col->col_size); + + while (mdb_index_find_next_on_page(mdb, ipg)) { + + /* check for compressed indexes. */ + if (ipg->len < col->col_size + 1) { + fprintf(stderr,"compressed indexes not yet supported, aborting\n"); + return 0; + } + + pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4); + row = mdb->pg_buf[ipg->offset + ipg->len - 1]; + iflag = mdb->pg_buf[ipg->offset]; + mdb_index_swap_n(&mdb->pg_buf[ipg->offset + 1], col->col_size, key_hash); + key_hash[col->col_size - 1] &= 0x7f; + printf("length = %d\n", ipg->len); + printf("iflag = %d pg = %" G_GUINT32_FORMAT + " row = %" G_GUINT16_FORMAT "\n", iflag, pg, row); + buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset + ipg->len - 1); + buffer_dump(mdb->pg_buf, ipg->offset + 1, ipg->offset + col->col_size); + buffer_dump(key_hash, 0, col->col_size - 1); + ipg->offset += ipg->len; + ipg->len = 0; + row++; + } + g_free(new_pg); + + return ipg->len; +} diff --git a/plugins/poi_geodownload/poi.c b/plugins/poi_geodownload/poi.c new file mode 100644 index 00000000..9b6ef93e --- /dev/null +++ b/plugins/poi_geodownload/poi.c @@ -0,0 +1,474 @@ +#include <mdbtools.h> +#include "display.h" +#include "container.h" +#include "coord.h" +#include "transform.h" +#include "popup.h" +#include "plugin.h" + + +struct index_data { + unsigned char data[15]; +}; +struct poi { + char *filename; + char *icon; + MdbHandle *h; + MdbHandle *h_idx; + MdbTableDef *table; + GPtrArray *table_col; + MdbColumn **cols; + MdbIndex *idx; + int idx_size; + struct index_data index_data; + MdbIndexChain chain; + struct poi *next; +} *poi_list; + +struct poi_data { + struct poi *poi; + int page; + int row; +}; + + +static void +print_col(MdbHandle *h, MdbColumn *col, char *buffer, int hex) +{ + switch (col->col_type) { + case MDB_BOOL: + strcpy(buffer, mdb_pg_get_byte(h, col->cur_value_start) ? "True" : "False"); + break; + case MDB_BYTE: + sprintf(buffer, "%d", mdb_pg_get_byte(h, col->cur_value_start)); + break; + case MDB_LONGINT: + if (hex) + sprintf(buffer, "0x%lx", mdb_pg_get_int32(h, col->cur_value_start)); + else + sprintf(buffer, "%ld", mdb_pg_get_int32(h, col->cur_value_start)); + break; + case MDB_DOUBLE: + sprintf(buffer, "%f", mdb_pg_get_double(h, col->cur_value_start)); + break; + case MDB_TEXT: + sprintf(buffer, "%s", mdb_col_to_string (h, h->pg_buf, col-> cur_value_start, + col->col_type, col->cur_value_len)); + break; + default: + sprintf(buffer, "unknown (%d)", col->col_type); + } +} + +static void +setup_idx_data(struct index_data *idx, struct coord *c, unsigned int geoflags, int size) +{ + /* 7f 80 1c 91 0a 7f 80 5c f5 41 7f 80 00 00 05 */ + idx->data[0]=0x7f; + idx->data[1]=(c->x >> 24) ^ 0x80; + idx->data[2]=c->x >> 16; + idx->data[3]=c->x >> 8; + idx->data[4]=c->x; + idx->data[5]=0x7f; + idx->data[6]=(c->y >> 24) ^ 0x80; + idx->data[7]=c->y >> 16; + idx->data[8]=c->y >> 8; + idx->data[9]=c->y; + idx->data[10]=0x7f; + if (size > 12) { + idx->data[11]=0x80 | (geoflags >> 24); + idx->data[12]=geoflags >> 16; + idx->data[13]=geoflags >> 8; + idx->data[14]=geoflags; + } else { + idx->data[11]=geoflags; + } +} + +static void +setup_idx_rect(struct coord *rect, struct index_data *idx, int size) +{ + struct coord r[2]; + r[0].x=rect[0].x; + r[0].y=rect[1].y; + r[1].x=rect[1].x; + r[1].y=rect[0].y; +#if 0 + printf("low 0x%x 0%x\n", r[0].x, r[0].y); + printf("high 0x%x 0%x\n", r[1].x, r[1].y); +#endif + setup_idx_data(idx, r, 0, size); + setup_idx_data(idx+1, r+1, 0xffffffff, size); +} + +static int +load_row(struct poi *poi, int pg, int row) +{ + int row_start, row_end, offset; + unsigned int num_fields, i; + MdbField fields[256]; + MdbFormatConstants *fmt; + int debug=0; + + fmt=poi->h->fmt; + mdb_read_pg(poi->h, pg); + if (debug) + printf("Page Type %d row_count_offset %d\n",poi->h->pg_buf[0], fmt->row_count_offset); + if (debug > 1) { + for (i = 0; i <= row; i++) { + offset=(fmt->row_count_offset + 2) + i * 2; + printf("row %d %d 0x%x\n", i, offset, mdb_pg_get_int16(poi->h, offset)); + } + } + row_start = mdb_pg_get_int16(poi->h, (fmt->row_count_offset + 2) + row * 2); + if (row_start & 0x4000) + return 1; + row_end = mdb_find_end_of_row(poi->h, row); + if (debug) { + printf("start=0x%x end=0x%x\n", row_start, row_end); + buffer_dump(poi->h->pg_buf, row_start, row_end); + } + + poi->h->cur_pos=row_start & 0x1fff; + poi->table->cur_row=row+1; + num_fields = mdb_crack_row(poi->table, row_start & 0x1fff, row_end, fields); + if (debug) + printf("num_fields=%d\n", num_fields); + for (i = 0; i < num_fields; i++) { + poi->cols[i]->cur_value_start=fields[i].start; + poi->cols[i]->cur_value_len=fields[i].siz; + } + return 0; +} + +static MdbIndexPage * +index_next_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain) +{ + MdbIndexPage *ipg; + + ipg = mdb_index_read_bottom_pg(mdb, idx, chain); + if (!mdb_index_find_next_on_page(mdb, ipg)) { +#if 0 + printf("no next\n"); +#endif + if (!chain->clean_up_mode) { +#if 0 + printf("no cleanup\n"); +#endif + if (!(ipg = mdb_index_unwind(mdb, idx, chain))) + chain->clean_up_mode = 1; + } + if (chain->clean_up_mode) { +#if 0 + printf("cleanup\n"); +#endif + //fprintf(stdout,"in cleanup mode\n"); + + if (!chain->last_leaf_found) { + printf("no last_leaf_found\n"); + return NULL; + } + mdb_read_pg(mdb, chain->last_leaf_found); + chain->last_leaf_found = + mdb_pg_get_int24(mdb, 0x0c); + //printf("next leaf %lu\n", chain->last_leaf_found); + mdb_read_pg(mdb, chain->last_leaf_found); + /* reuse the chain for cleanup mode */ + chain->cur_depth = 1; + ipg = &chain->pages[0]; + mdb_index_page_init(ipg); + ipg->pg = chain->last_leaf_found; + //printf("next on page %d\n", + if (!mdb_index_find_next_on_page(mdb, ipg)) { +#if 0 + printf("no find_next_on_page\n"); +#endif + return NULL; + } + } + } + return ipg; +} + +static int +index_next(struct poi *poi, struct index_data *idx) +{ + MdbIndexPage *ipg; + MdbIndexChain *chain = &poi->chain; + int row; + int pg; + int offset; + char *cmp, *low, *high; + int debug=0; + + + for(;;) { + for(;;) { + ipg=index_next_row(poi->h_idx, poi->idx, chain); + if (! ipg) + return 0; + row = poi->h_idx->pg_buf[ipg->offset + ipg->len - 1]; + pg = mdb_pg_get_int24_msb(poi->h_idx, ipg->offset + ipg->len - 4); + + offset=poi->idx_size+4-ipg->len; + memcpy(poi->index_data.data+offset, poi->h_idx->pg_buf+ipg->offset, ipg->len - 4); + cmp=poi->index_data.data; + low=idx[0].data; + high=idx[1].data; + if (debug > 1) { + buffer_dump(low, 0, poi->idx_size-1); + buffer_dump(cmp, 0, poi->idx_size-1); + buffer_dump(high, 0, poi->idx_size-1); + printf("%d %d %d\n", memcmp(cmp, low, poi->idx_size), memcmp(cmp, high, poi->idx_size), offset); + } +#if 0 + buffer_dump(poi->h_idx->pg_buf, ipg->offset, ipg->offset+ipg->len-1); +#endif + ipg->offset += ipg->len; + if (memcmp(cmp, low, poi->idx_size) >= 0) { + if (memcmp(cmp, high, poi->idx_size) <=0 ) { + if (debug) { + printf("match\n"); + buffer_dump(low, 0, poi->idx_size-1); + buffer_dump(cmp, 0, poi->idx_size-1); + buffer_dump(high, 0, poi->idx_size-1); + printf("%d %d %d\n", memcmp(cmp, low, poi->idx_size), memcmp(cmp, high, poi->idx_size), offset); + } + break; + } else { + return 0; + } + } + if (debug > 1) + printf("row=0x%x pg=0x%x len=%d\n", row, pg, ipg->len); + } + if (debug) + printf("match: row=0x%x pg=0x%x len=%d\n", row, pg, ipg->len); + if (!load_row(poi, pg, row)) + break; + } + return 1; +} + + +static int +load_poi_table(struct poi *poi, MdbCatalogEntry *entry) +{ + int j; + MdbIndex *idx; + + poi->h_idx=NULL; + poi->table = mdb_read_table(entry); + poi->table_col = mdb_read_columns(poi->table); + mdb_read_indices(poi->table); + poi->cols = (MdbColumn **) (poi->table_col->pdata); + if (poi->table_col->len < 4 || strcasecmp(poi->cols[0]->name, "X") || + strcasecmp(poi->cols[1]->name, "Y") || strcasecmp(poi->cols[3]->name, "GEOFLAGS")) + return 1; + for (j = 0; j < poi->table->num_idxs; j++) { + idx = poi->table->indices->pdata[j]; + if (idx->num_keys == 3 && idx->key_col_num[0] == 1 && + idx->key_col_num[1] == 2 && idx->key_col_num[2] == 4) { + poi->idx = idx; + poi->idx_size=3+poi->cols[0]->col_size+poi->cols[1]->col_size+poi->cols[3]->col_size; + poi->h_idx=mdb_clone_handle(poi->h); + } + } + return 0; +} + +static void +load_poi(char *filename, char *icon) +{ + int i; + MdbCatalogEntry *entry; + GPtrArray *catalog; + struct poi *new = g_new(struct poi, 1); + + new->filename = filename; + new->icon = icon; + + new->h = mdb_open(filename, MDB_NOFLAGS); + catalog = mdb_read_catalog(new->h, MDB_TABLE); + for (i = 0; i < catalog->len; i++) { + entry = catalog->pdata[i]; + if (!strcasecmp(entry->object_name, "_INDEXDATA")) { + if (load_poi_table(new, entry)) { + printf("%s invalid\n", filename); + free(new); + new=NULL; + } + } + } + g_ptr_array_free(catalog, 1); + if (new) { + new->next = poi_list; + poi_list = new; + } +} + +static void +get_coord(struct poi *p, struct coord *c) +{ + c->x=mdb_pg_get_int32(p->h, p->cols[0]->cur_value_start); + c->y=mdb_pg_get_int32(p->h, p->cols[1]->cur_value_start); +} + +static void +poi_info(struct display_list *list, struct popup_item **popup) +{ + struct poi_data *data=list->data; + struct poi *poi=data->poi; + struct popup_item *popup_last, *popup_val_last; + char *text,buffer[4096]; + int j; + MdbColumn *col; + char *v; + + popup_last = *popup; + printf("poi_info pg=%d row=%d\n", data->page, data->row); + load_row(poi, data->page, data->row); + + popup_val_last = NULL; + sprintf(buffer,"File:%s", poi->filename); + popup_item_new_text(&popup_val_last, buffer, 1); + sprintf(buffer,"Icon:%s", poi->icon); + popup_item_new_text(&popup_val_last, buffer, 2); + sprintf(buffer,"Page:%d", data->page); + popup_item_new_text(&popup_val_last, buffer, 3); + sprintf(buffer,"Row:%d", data->row); + popup_item_new_text(&popup_val_last, buffer, 4); + for (j = 0; j < poi->table_col->len; j++) { + col = poi->table_col->pdata[j]; +#if 0 + printf("start: %d type:%d\n", col->cur_value_start, col->col_type); +#endif + sprintf(buffer, "%s:", col->name); + v = buffer + strlen(buffer); + if (!strcasecmp(col->name,"X") || !strcasecmp(col->name,"Y")) + print_col(poi->h, col, v, 1); + else + print_col(poi->h, col, v, 0); +#if 0 + printf("%s\n", buffer); +#endif + text=g_convert(buffer,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + popup_item_new_text(&popup_val_last, buffer, j+10); + g_free(text); + + } + popup_item_new_text(&popup_last, "POI", 20)->submenu = popup_val_last; + *popup=popup_last; +} + +static void +draw_poi(struct poi *p, struct container *co, struct point *pnt) +{ + struct poi_data data; + data.poi=p; + data.page=p->h->cur_pg; + data.row=p->table->cur_row-1; + display_add(&co->disp[display_poi], 5, 0, p->icon, 1, pnt, poi_info, &data, sizeof(data)); +} + +static void +plugin_draw(struct container *co) +{ + struct coord c; + struct point pnt; + struct poi *p; + struct index_data idx[2]; + int use_index=1; + int debug=0; + + p = poi_list; + + if (co->trans->scale > 256) + return; + if (debug) { + printf("scale=%ld\n", co->trans->scale); + printf("rect 0x%lx,0%lx-0x%lx,0x%lx\n", co->trans->rect[0].x, co->trans->rect[0].y, co->trans->rect[1].x, co->trans->rect[1].y); + } + while (p) { + if (use_index) + setup_idx_rect(co->trans->rect, idx, p->idx_size); + if (! use_index) { + printf("rewind %s %p\n", p->filename, p->table); + mdb_rewind_table(p->table); + while (mdb_fetch_row(p->table)) { + get_coord(p, &c); + if (transform(co->trans, &c, &pnt)) { + if (debug) + printf("coord 0x%lx,0x%lx pg %d row %d\n", c.x, c.y, p->h->cur_pg, p->table->cur_row); + draw_poi(p, co, &pnt); + } + } + } else { + memset(&p->chain, 0, sizeof(p->chain)); + while (index_next(p, idx)) { + get_coord(p, &c); + if (transform(co->trans, &c, &pnt)) { + if (debug) + printf("coord 0x%lx,0x%lx pg %d row %d\n", c.x, c.y, p->h->cur_pg, p->table->cur_row); + draw_poi(p, co, &pnt); + } + } + } + p = p->next; + } + +} + + +int plugin_init(void) +{ + plugin_register_draw(plugin_draw); + mdb_init(); + load_poi("/home/martin/map/work/data/1/GEO00001.MDB", + "/home/martin/map/work/data/1/_MCDNLDS.BMP"); + load_poi("/home/martin/map/work/data/2/GEO00001.MDB", + "/home/martin/map/work/data/2/_BURKING.BMP"); + load_poi("/home/martin/map/work/data/3/GEO00001.MDB", + "/home/martin/map/work/data/3/_PIZZHUT.BMP"); + load_poi("/home/martin/map/work/data/4/GEO00001.MDB", + "/home/martin/map/work/data/4/_CHICKEN.BMP"); + load_poi("/home/martin/map/work/data/5/GEO00001.MDB", + "/home/martin/map/work/data/5/_WIENERW.BMP"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/bahn.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/bahn.adr/BAHN.BMP"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/cinmus.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/cinmus.adr/_Kinocen.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/fsight.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/fsight.adr/_sehensw.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/erlbns.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/erlbns.adr/_Freizei.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/faehre.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/faehre.adr/_Faehren.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/fenter.adr/GEO00001.MDB", + "/opt/reiseplaner/travel/prog.mov/fenter.adr/_casino.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/vhotel.adr/Geo00001.mdb", + "/opt/reiseplaner/travel/prog.mov/vhotel.adr/Vhotel.bmp"); + load_poi + ("/opt/reiseplaner/travel/prog.mov/vgast.adr/Geo00001.mdb", + "/opt/reiseplaner/travel/prog.mov/vgast.adr/Vgast.BMP"); + load_poi + ("/opt/reiseplaner/travel/address/p_ceu.adr/p_ceu.mdb", + "/opt/reiseplaner/travel/address/p_ceu.adr/p_ceu.bmp"); + load_poi + ("/opt/reiseplaner/travel/address/p_eeu.adr/p_eeu.mdb", + "/opt/reiseplaner/travel/address/p_eeu.adr/P_eeu.bmp"); + load_poi + ("/opt/reiseplaner/travel/address/p_heu.adr/p_heu.mdb", + "/opt/reiseplaner/travel/address/p_heu.adr/P_heu.bmp"); + load_poi + ("/opt/reiseplaner/travel/address/p_ieu.adr/p_ieu.mdb", + "/opt/reiseplaner/travel/address/p_ieu.adr/P_ieu.bmp"); + return 0; +} diff --git a/point.h b/point.h new file mode 100644 index 00000000..6672f3d5 --- /dev/null +++ b/point.h @@ -0,0 +1,9 @@ +#ifndef POINT_H +#define POINT_H + +struct point { + int x; + int y; +}; + +#endif @@ -0,0 +1,109 @@ +#include <stdlib.h> +#include <assert.h> +#include "coord.h" +#include "map_data.h" +#include "file.h" +#include "block.h" +#include "poly.h" +#include "display.h" +#include "draw_info.h" +#include "data_window.h" +#include "container.h" + +extern struct data_window poly_window; + +int +poly_get_hdr(unsigned char **p,struct poly_hdr *poly_hdr) +{ + poly_hdr->addr=*p; + poly_hdr->c=(struct coord *) (*p); + *p+=3*sizeof(struct coord); + poly_hdr->name=*p; + while (**p) { + (*p)++; + } + (*p)++; + poly_hdr->order=*(*p)++; + poly_hdr->type=*(*p)++; + poly_hdr->polys=*(unsigned long *)(*p); (*p)+=sizeof(unsigned long); + poly_hdr->count=(unsigned long *)(*p); (*p)+=poly_hdr->polys*sizeof(unsigned long); + poly_hdr->count_sum=*(unsigned long *)(*p); (*p)+=sizeof(unsigned long); + return 0; +} + +void +poly_draw_segment(struct container *co, struct segment *seg, int disp, unsigned char **p, int limit) +{ + struct poly_hdr poly_hdr; + struct coord *coord; + unsigned int j,k,o; + struct point pnt; + struct param_list param[100]; + int max=20000; + struct point xpoints[max]; + + seg->data[0]=*p; + poly_get_hdr(p, &poly_hdr); + if (poly_hdr.order < limit && is_visible(co->trans, poly_hdr.c)) { + transform(co->trans,&poly_hdr.c[2],&pnt); + for (k = 0 ; k < poly_hdr.polys ; k++) { + assert(poly_hdr.count[k] < max); + for (j = 0 ; j < poly_hdr.count[k] ; j++) { + transform(co->trans, coord_get(p), &xpoints[j]); + } + if (poly_hdr.type < 0x80) { + o=0; + if (poly_hdr.type == 0x1e) + o=1; + else if (poly_hdr.type == 0x2d) + o=2; + else if (poly_hdr.type == 0x32) + o=3; + display_add(&co->disp[disp+o], 0, 0, poly_hdr.name, poly_hdr.count[k], xpoints, NULL, seg, sizeof(*seg)); + + } else { + display_add(&co->disp[disp], 1, 0, poly_hdr.name, poly_hdr.count[k], xpoints, NULL, seg, sizeof(*seg)); + } + if (co->data_window[data_window_type_poly]) + data_window_add(co->data_window[data_window_type_poly], param, poly_get_param(seg, param, 100)); + } + } else + (*p)+=poly_hdr.count_sum*sizeof(*coord); +} + +void +poly_draw_block(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data) +{ + struct draw_info *drw_inf=data; + struct segment seg; + int i; + + seg.blk_inf=*blk_inf; + + for (i = 0 ; i < blk_inf->block->count ; i++) + poly_draw_segment(drw_inf->co, &seg, drw_inf->display, &p, drw_inf->limit); +} + + +int +poly_get_param(struct segment *seg, struct param_list *param, int count) +{ + int i=count; + unsigned char *p=seg->data[0]; + struct poly_hdr poly_hdr; + + + param_add_hex("Addr", p-seg->blk_inf.file->begin, ¶m, &count); + poly_get_hdr(&p, &poly_hdr); + param_add_string("Name", poly_hdr.name, ¶m, &count); + param_add_hex("L", poly_hdr.c[0].x, ¶m, &count); + param_add_hex("T", poly_hdr.c[0].y, ¶m, &count); + param_add_hex("R", poly_hdr.c[1].x, ¶m, &count); + param_add_hex("B", poly_hdr.c[1].y, ¶m, &count); + param_add_hex("X", poly_hdr.c[2].x, ¶m, &count); + param_add_hex("Y", poly_hdr.c[2].y, ¶m, &count); + param_add_hex("Order", poly_hdr.order, ¶m, &count); + param_add_hex("Type", poly_hdr.type, ¶m, &count); + param_add_hex("Polys", poly_hdr.polys, ¶m, &count); + return i-count; +} @@ -0,0 +1,13 @@ +struct poly_hdr { + unsigned char *addr; + struct coord *c; + char *name; + unsigned char order; + unsigned char type; + unsigned long polys; + unsigned long *count; + unsigned long count_sum; +}; + +void poly_draw_block(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data); +int poly_get_param(struct segment *seg, struct param_list *param, int count); diff --git a/popup.c b/popup.c new file mode 100644 index 00000000..f0fc5883 --- /dev/null +++ b/popup.c @@ -0,0 +1,306 @@ +#include <malloc.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <gtk/gtk.h> +#include "coord.h" +#include "param.h" +#include "map_data.h" +#include "block.h" +#include "display.h" +#include "town.h" +#include "street.h" +#include "poly.h" +#include "log.h" +#include "popup.h" +#include "plugin.h" +#include "vehicle.h" +#include "route.h" +#include "cursor.h" +#include "statusbar.h" +#include "container.h" + +void +popup_item_destroy_text(struct popup_item *item) +{ + g_free(item->text); + g_free(item); +} + +struct popup_item * +popup_item_new_text(struct popup_item **last, char *text, int priority) +{ + struct popup_item *curr; + curr=g_new(struct popup_item,1); + memset(curr, 0, sizeof(*curr)); + curr->text=g_strdup(text); + curr->priority=priority; + curr->destroy=popup_item_destroy_text; + if (last) { + curr->next=*last; + *last=curr; + } + return curr; +} + +struct popup_item * +popup_item_new_func(struct popup_item **last, char *text, int priority, void (*func)(struct popup_item *, void *), void *param) +{ + struct popup_item *curr=popup_item_new_text(last, text, priority); + curr->func=func; + curr->param=param; + return curr; +} + +struct popup_item * +param_to_menu_new(char *name,struct param_list *plist, int c, int iso) +{ + struct popup_item *last, *curr, *ret; + int i; + + ret=popup_item_new_text(NULL,name,1); + last=NULL; + for (i = 0 ; i < c ; i++) { + char name_buffer[strlen(plist[i].name)+strlen(plist[i].value)+2]; + char *text=name_buffer; + + sprintf(name_buffer,"%s:%s", plist[i].name, plist[i].value); + if (iso) { + text=g_convert(name_buffer,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + if (! text) { + printf("problem converting '%s'\n", name_buffer); + } + } + curr=popup_item_new_text(&last, text, i); + if (iso) + free(text); + } + ret->submenu=last; + return ret; +} + +void +popup_set_no_passing(struct popup_item *item, void *param) +{ + struct display_list *l=param; + struct segment *seg=(struct segment *)(l->data); + struct street_str *str=(struct street_str *)(seg->data[0]); + char log[256]; + int segid=str->segid; + if (segid < 0) + segid=-segid; + + sprintf(log,"Attributes Street 0x%x updated: limit=0x%x(0x%x)", segid, 0x33, str->limit); + str->limit=0x33; + log_write(log, seg->blk_inf.file, str, sizeof(*str)); +} + +void +popup_set_destination(struct popup_item *item, void *param) +{ + struct popup_item *ref=param; + struct popup *popup=ref->param; + struct container *co=popup->co; + printf("Destination %s\n", ref->text); + route_set_position(co->route, cursor_pos_get(co->cursor)); + route_set_destination(co->route, &popup->c); + graphics_redraw(popup->co); + if (co->statusbar && co->statusbar->statusbar_route_update) + co->statusbar->statusbar_route_update(co->statusbar, co->route); +} + +extern void *vehicle; + +void +popup_set_position(struct popup_item *item, void *param) +{ + struct popup_item *ref=param; + struct popup *popup=ref->param; + printf("Position %s\n", ref->text); + vehicle_set_position(popup->co->vehicle, &popup->c); +} + +void +popup_break_crossing(struct display_list *l) +{ + struct segment *seg=(struct segment *)(l->data); + struct street_str *str=(struct street_str *)(seg->data[0]); + char log[256]; + int segid=str->segid; + if (segid < 0) + segid=-segid; + + sprintf(log,"Coordinates Street 0x%x updated: limit=0x%x(0x%x)", segid, 0x33, str->limit); + str->limit=0x33; + log_write(log, seg->blk_inf.file, str, sizeof(*str)); +} + +void +popup_call_func(GtkObject *obj, void *parm) +{ + struct popup_item *curr=parm; + curr->func(curr, curr->param); +} + +GtkWidget * +popup_menu(struct popup_item *list) +{ + int min_prio,curr_prio; + struct popup_item *curr; + GtkWidget *item,*menu,*submenu; + + curr_prio=0; + menu=gtk_menu_new(); + do { + min_prio=INT_MAX; + curr=list; + while (curr) { + if (curr->priority == curr_prio) { + item=gtk_menu_item_new_with_label(curr->text); + gtk_menu_append(GTK_MENU(menu), item); + if (curr->submenu) { + submenu=popup_menu(curr->submenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu); + } else if (curr->func) { + gtk_signal_connect(GTK_OBJECT(item), "activate", + GTK_SIGNAL_FUNC (popup_call_func), curr); + } + } + if (curr->priority > curr_prio && curr->priority < min_prio) + min_prio=curr->priority; + curr=curr->next; + } + curr_prio=min_prio; + } while (min_prio != INT_MAX); + return menu; +} + +void +popup_display_list_default(struct display_list *d, struct popup_item **popup_list) +{ + struct segment *seg; + char *desc,*text,*item_text; + struct popup_item *curr_item,*submenu; + struct param_list plist[100]; + + desc=NULL; + if (d->type == 0) desc="Polygon"; + if (d->type == 1) desc="Polyline"; + if (d->type == 2) desc="Street"; + if (d->type == 3) desc="Label"; + if (d->type == 4) desc="Point"; + seg=(struct segment *)(d->data); + if (seg) { + if (d->label && strlen(d->label)) { + item_text=malloc(strlen(desc)+strlen(d->label)+2); + strcpy(item_text, desc); + strcat(item_text," "); + strcat(item_text, d->label); + } else { + item_text=desc; + } + text=g_convert(item_text,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + curr_item=popup_item_new_text(popup_list,text,1); + g_free(text); + + curr_item->submenu=param_to_menu_new("File", plist, file_get_param(seg->blk_inf.file, plist, 100), 1); + submenu=curr_item->submenu; + submenu->next=param_to_menu_new("Block", plist, block_get_param(&seg->blk_inf, plist, 100), 1); + submenu=submenu->next; + + if (d->type == 0 || d->type == 1) { + submenu->next=param_to_menu_new(desc, plist, poly_get_param(seg, plist, 100), 1); + } + if (d->type == 2) { + submenu->next=param_to_menu_new(desc, plist, street_get_param(seg, plist, 100, 1), 1); + popup_item_new_func(&submenu->next,"Set no passing", 1000, popup_set_no_passing, d); + } + if (d->type == 3) { + submenu->next=param_to_menu_new(desc, plist, town_get_param(seg, plist, 100), 1); + } + if (d->type == 4) { + submenu->next=param_to_menu_new(desc, plist, street_bti_get_param(seg, plist, 100), 1); + } + } +} + +void +popup_display_list(struct container *co, struct popup *popup, struct popup_item **popup_list) +{ + GtkWidget *menu, *item; + struct display_list *list[100],**p=list; + + menu=gtk_menu_new(); + item=gtk_menu_item_new_with_label("Selection"); + gtk_menu_append (GTK_MENU(menu), item); + display_find(&popup->pnt, co->disp, display_end, 3, list, 100); + while (*p) { + if (! (*p)->info) + popup_display_list_default(*p, popup_list); + else + (*(*p)->info)(*p, popup_list); + p++; + } +} + +void +popup_destroy_items(struct popup_item *item) +{ + struct popup_item *next; + while (item) { + if (item->active && item->func) + item->func(item, item->param); + if (item->submenu) + popup_destroy_items(item->submenu); + next=item->next; + assert(item->destroy != NULL); + item->destroy(item); + item=next; + } +} + +void +popup_destroy(GtkObject *obj, void *parm) +{ + struct popup *popup=parm; + + popup_destroy_items(popup->items); + g_free(popup); +} + +void +popup(struct container *co, int x, int y, int button) +{ + GtkWidget *menu; + struct popup *popup=g_new(struct popup,1); + struct popup_item *list=NULL; + struct popup_item *descr; + struct coord_geo g; + char buffer[256]; + + popup->co=co; + popup->pnt.x=x; + popup->pnt.y=y; + transform_reverse(co->trans, &popup->pnt, &popup->c); + popup_display_list(co, popup, &list); + plugin_call_popup(co, popup, &list); + transform_lng_lat(&popup->c, &g); + strcpy(buffer,"Map Point "); + transform_geo_text(&g, buffer+strlen(buffer)); + descr=popup_item_new_text(&list,buffer, 0); + descr->param=popup; + + popup_item_new_func(&list,"Set as Position", 1000, popup_set_position, descr); + popup_item_new_func(&list,"Set as Destination", 1001, popup_set_destination, descr); + + popup->items=list; + menu=popup_menu(list); + gtk_widget_show_all(menu); + popup->gui_data=menu; + + + gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, button, gtk_get_current_event_time()); + gtk_signal_connect(GTK_OBJECT(menu), "selection-done", GTK_SIGNAL_FUNC (popup_destroy), popup); +} + + diff --git a/popup.h b/popup.h new file mode 100644 index 00000000..989d5155 --- /dev/null +++ b/popup.h @@ -0,0 +1,22 @@ +void popup(struct container *co, int x, int y, int button); +struct popup_item *popup_item_new_text(struct popup_item **last, char *text, int priority); + +struct popup { + struct container *co; + struct point pnt; + struct coord c; + void *gui_data; + struct popup_item *items; + struct popup_item *active; +}; + +struct popup_item { + char *text; + int priority; + void (*func)(struct popup_item *, void *); + void *param; + struct popup_item *submenu; + struct popup_item *next; + void (*destroy)(struct popup_item *); + int active; +}; diff --git a/profile.c b/profile.c new file mode 100644 index 00000000..35a41447 --- /dev/null +++ b/profile.c @@ -0,0 +1,18 @@ +#include <stdlib.h> +#include <sys/time.h> + +void +profile_timer(char *where) +{ + static struct timeval last; + struct timeval curr; + int msec; + + if (where) { + gettimeofday(&curr, NULL); + msec=(curr.tv_usec-last.tv_usec)/1000+ + (curr.tv_sec-last.tv_sec)*1000; + printf("%s:%d msec\n", where, msec); + } + gettimeofday(&last, NULL); +} diff --git a/route.c b/route.c new file mode 100644 index 00000000..75de703a --- /dev/null +++ b/route.c @@ -0,0 +1,1053 @@ +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <unistd.h> +#include <sys/time.h> +#include <glib.h> +#include "coord.h" +#include "param.h" +#include "map_data.h" +#include "block.h" +#include "street.h" +#include "street_data.h" +#include "display.h" +#include "transform.h" +#include "route.h" +#include "phrase.h" +#include "navigation.h" +#include "fib-1.0/fib.h" +#include "time.h" + +/* Node1: 4 */ +/* Node2: 4 */ +/* Segid: 4 */ +/* len: 4 */ +/* type: 1 */ +/* limit/order: 1 */ +/* 18 Bytes */ + +extern void *speech_handle; +static int speed_list[16]={120,120,80,110,90,80,60,90,80,70,60,50,30,10,0,60}; + +int debug_route=0; + +#define GC_TEXT_FG 7 +#define GC_TEXT_BG 8 +#define GC_BLACK 9 +#define GC_RED 21 + +int hx=0x1416bc; /* 447C9E dx=3E18, dxmg=5E09*/ +int hy=0x5f224c; /* 5282B5 dy=5E07, dymg=8F1C*/ +int segid_h=0x20461961; + +int hkx=0x1474c5; /* 44BAB6 */ +int hky=0x5fb168; /* 52E0BC */ + +int lx=0x141ac3; +int ly=0x5f2d7a; + +int trace; +/* 0x141b53, 0x5f2065 */ + +struct coord3d { + struct coord xy; + int h; +}; + + +struct route_point { + struct route_point *next; + struct route_point *hash_next; + struct route_segment *start; + struct route_segment *end; + struct route_segment *seg; +#if 0 + int conn; + int id; +#endif + struct fibheap_el *el; + int value; + struct coord3d c; +}; + + +struct route_segment { + struct route_segment *next; + struct route_segment *start_next; + struct route_segment *end_next; + struct route_point *start; + struct route_point *end; + struct street_str *str; + int limit; + int len; + int offset; +}; + +struct street_info { + struct street_header *hdr; + struct street_type *typ; + struct street_str *str; + unsigned char *p; + int bytes; + int include; +}; + +struct route_info { + int mode; + struct coord3d seg1,seg2,line1,line2,pos,click; + int seg1_len,seg2_len; + int offset; + int dist; + struct block_info blk_inf; + struct street_info str_inf; +}; + +struct route { + struct map_data *map_data; + double route_time_val; + double route_len_val; + struct route_path_segment *path; + struct route_path_segment *path_last; + struct route_info *pos; + struct route_info *dst; + struct route_segment *route_segments; + struct route_point *route_points; + struct block_list *blk_lst; +#define HASH_SIZE 8192 + struct route_point *hash[HASH_SIZE]; +}; + +struct route * +route_new(void) +{ + struct route *this=g_new0(struct route, 1); + return this; +} + +void +route_path_free(struct route *this) +{ + struct route_path_segment *curr, *next; + curr=this->path; + + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } + this->path=NULL; + this->path_last=NULL; +} + +void +route_mapdata_set(struct route *this, struct map_data *mdata) +{ + this->map_data=mdata; +} + +struct map_data * +route_mapdata_get(struct route *this) +{ + return this->map_data; +} + +static void +route_add_path_segment(struct route *this, int segid, int offset, struct coord *start, struct coord *end, int dir, int len, int time) +{ + struct route_path_segment *segment=g_new0(struct route_path_segment,1); + segment->next=NULL; + segment->segid=segid; + segment->offset=offset; + segment->dir=dir; + segment->length=len; + segment->time=time; + if (start) + segment->c[0]=*start; + if (end) + segment->c[1]=*end; + if (!this->path) + this->path=segment; + if (this->path_last) + this->path_last->next=segment; + this->path_last=segment; +} + +void +route_set_position(struct route *this, struct coord *pos) +{ + struct route_info *rt; + + route_path_free(this); + rt=route_find_nearest_street(this->map_data, pos); + route_find_point_on_street(rt); + if (this->pos) + g_free(this->pos); + this->pos=rt; + if (this->dst) { + route_find(this, this->pos, this->dst); + } +} + +struct route_path_segment * +route_path_get_all(struct route *this) +{ + return this->path; +} + +struct route_path_segment * +route_path_get(struct route *this, int segid) +{ + struct route_path_segment *curr=this->path; + + while (curr) { + if (curr->segid == segid) + return curr; + curr=curr->next; + } + return NULL; + +} + +void +route_set_destination(struct route *this, struct coord *dest) +{ + struct route_info *rt; + + rt=route_find_nearest_street(this->map_data, dest); + route_find_point_on_street(rt); + if (this->dst) + g_free(this->dst); + this->dst=rt; + route_do_start(this, this->pos, this->dst); +} + +struct coord * +route_get_destination(struct route *this) +{ + if (! this->dst) + return NULL; + return &this->dst->click.xy; +} + +void +route_street_foreach(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data, + void(*func)(struct block_info *, struct street_info *, unsigned char **, unsigned char *, void *)) +{ + struct street_info str_inf; + struct street_str *str,*str_tmp; + + if (blk_inf->block_number == 0x10c6) { + printf("route_street_foreach p=%p\n", p); + } + str_inf.hdr=(struct street_header *)p; + p+=sizeof(struct street_header); + assert(str_inf.hdr->count == blk_inf->block->count); + + str_inf.bytes=street_get_bytes(blk_inf->block); + + str_inf.typ=(struct street_type *)p; + p+=blk_inf->block->count*sizeof(struct street_type); + + str=(struct street_str *)p; + str_tmp=str; + while (str_tmp->segid) + str_tmp++; + + p=(unsigned char *)str_tmp; + p+=4; + + while (str->segid) { + str_inf.include=(str[1].segid > 0); + str_inf.str=str; + str_inf.p=p; + func(blk_inf, &str_inf, &p, end-4, data); + if (str_inf.include) + str_inf.typ++; + str++; + } +} + + +static struct route_point * +route_get_point(struct route *this, struct coord3d *c) +{ + struct route_point *p=this->route_points; + int hashval=(c->xy.x + c->xy.y + c->h) & (HASH_SIZE-1); + p=this->hash[hashval]; + while (p) { + if (p->c.xy.x == c->xy.x && p->c.xy.y == c->xy.y && p->c.h == c->h) + return p; + p=p->hash_next; + } + return NULL; +} + + +struct route_point * +route_point_add(struct route *this, struct coord3d *f, int conn) +{ + int hashval; + struct route_point *p; + + p=route_get_point(this,f); + if (p) { +#if 0 + p->conn+=conn; +#endif + } else { + hashval=(f->xy.x + f->xy.y + f->h) & (HASH_SIZE-1); + if (debug_route) + printf("p (0x%lx,0x%lx,0x%x)\n", f->xy.x, f->xy.y, f->h); + p=g_new(struct route_point,1); + p->hash_next=this->hash[hashval]; + this->hash[hashval]=p; + p->next=this->route_points; +#if 0 + p->conn=conn; + p->id=++id; +#endif + p->el=NULL; + p->start=NULL; + p->end=NULL; + p->seg=NULL; + p->value=INT_MAX; + p->c=*f; + this->route_points=p; + } + return p; +} + +static void +route_points_free(struct route *this) +{ + struct route_point *curr,*next; + curr=this->route_points; + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } + this->route_points=NULL; + memset(this->hash, 0, sizeof(this->hash)); +} + +void +route_segment_add(struct route *this, struct route_point *start, struct route_point *end, int len, struct street_str *str, int offset, int limit) +{ + struct route_segment *s; + s=g_new(struct route_segment,1); + s->start=start; + s->start_next=start->start; + start->start=s; + s->end=end; + s->end_next=end->end; + end->end=s; + s->len=len; + s->str=str; + s->offset=offset; + s->limit=limit; + s->next=this->route_segments; + this->route_segments=s; + if (debug_route) + printf("l (0x%lx,0x%lx0x%x)-(0x%lx,0x%lx,0x%x)\n", start->c.xy.x, start->c.xy.y, start->c.h, end->c.xy.x, end->c.xy.y, end->c.h); + +} + +void +route_segments_free(struct route *this) +{ + struct route_segment *curr,*next; + curr=this->route_segments; + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } + this->route_segments=NULL; +} + +void +route_display_points(struct route *this, struct container *co) +{ +#if 0 + GtkMap *map=co->map; + struct route_point *p=this->route_points; + int r=5; + struct point pnt; + char text[256]; + + while (p) { + if (transform(co->trans, &p->c.xy, &pnt)) { + gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], FALSE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); + if (p->value != -1) { + sprintf(text,"%d", p->value); +#if 0 + display_text(GTK_WIDGET(map)->window, map->gc[GC_TEXT_FG], map->gc[GC_TEXT_BG], map->face[0], text, pnt.x+6, pnt.y+4, 0x10000, 0); +#endif + } + } + p=p->next; + } +#endif +} + +int +route_time(int type, int len) +{ + return len*36/speed_list[type & 0x3f]; +} + +int +route_value(int type, int len) +{ + return route_time(type, len); +} + +int +route_get_height(int segid, struct coord *c) +{ + if (c->x == 0x141b53 && c->y == 0x5f2065 && (segid == 0x4fad2fa || segid == 0x4fad155)) + return 1; + if (c->x == 0x1477a7 && c->y == 0x5fac38 && (segid == 0x32adac2 || segid == 0x40725c6)) + return 1; + if (c->x == 0x147a4c && c->y == 0x5fb194 && (segid == 0x32adb17 || segid == 0x32adb16)) + return 1; + return 0; +} + +void +route_process_street_graph(struct block_info *blk_inf, struct street_info *str_inf, unsigned char **p, unsigned char *end, void *data) +{ + struct route *this=data; + int limit,flags=0; + double len=0; + struct coord3d f,o,l; + struct route_point *s_pnt,*e_pnt; + + street_get_coord(p, str_inf->bytes, blk_inf->block->c, &f.xy); + f.h=route_get_height(str_inf->str->segid, &f.xy); + s_pnt=route_point_add(this,&f, 1); + + l=f; + o=f; + while (*p < end) { + flags=street_get_coord(p, str_inf->bytes, blk_inf->block->c, &f.xy); + if (flags && !str_inf->include) + break; + len+=transform_distance(&l.xy, &o.xy); + l=o; + o=f; + if (flags) + break; + } + len+=transform_distance(&l.xy, &o.xy); + o.h=route_get_height(str_inf->str->segid, &o.xy); + e_pnt=route_point_add(this,&o, 1); + + limit=str_inf->str->limit; + if (str_inf->str->limit == 0x30 && (str_inf->str->type & 0x40)) + limit=0x03; + if (str_inf->str->limit == 0x03 && (str_inf->str->type & 0x40)) + limit=0x30; + + if (str_inf->str->limit != 0x33) + route_segment_add(this, s_pnt, e_pnt, len, str_inf->str, 0, limit); + debug_route=0; + *p-=2*str_inf->bytes; +} + +static int +compare(void *v1, void *v2) +{ + struct route_point *p1=v1; + struct route_point *p2=v2; + return p1->value-p2->value; +} + +static void +route_flood(struct route *this, struct route_info *rt_end) +{ + struct route_point *end; + struct route_point *p_min; + struct route_segment *s; + int min,new,old,val; + struct fibheap *heap; + + heap = fh_makeheap(); + + fh_setcmp(heap, compare); + + end=route_get_point(this, &rt_end->pos); + assert(end != 0); + end->value=0; + end->el=fh_insert(heap, end); + for (;;) { + p_min=fh_extractmin(heap); + if (! p_min) + break; + min=p_min->value; + if (debug_route) + printf("min=%d, 0x%lx, 0x%lx\n", min, p_min->c.xy.x, p_min->c.xy.y); + s=p_min->start; + while (s) { + val=route_value(s->str->type, s->len); +#if 0 + val+=val*2*street_route_contained(s->str->segid); +#endif + new=min+val; + if (debug_route) + printf("begin %d (0x%lx,0x%lx) ",new,s->end->c.xy.x, s->end->c.xy.y); + if (new < s->end->value && !(s->limit & 0x30)) { + s->end->value=new; + s->end->seg=s; + if (! s->end->el) { + if (debug_route) + printf("insert"); + s->end->el=fh_insert(heap, s->end); + } + else { + if (debug_route) + printf("replace"); + fh_replacedata(heap, s->end->el, s->end); + } + } + if (debug_route) + printf("\n"); + s=s->start_next; + } + s=p_min->end; + while (s) { + new=min+route_value(s->str->type, s->len); + if (debug_route) + printf("end %d vs %d (0x%lx,0x%lx) ",new,s->start->value,s->start->c.xy.x, s->start->c.xy.y); + if (new < s->start->value && !(s->limit & 0x03)) { + old=s->start->value; + s->start->value=new; + s->start->seg=s; + if (! s->start->el) { + if (debug_route) + printf("insert"); + s->start->el=fh_insert(heap, s->start); + } + else { + if (debug_route) + printf("replace"); + fh_replacedata(heap, s->start->el, s->start); + } + } + if (debug_route) + printf("\n"); + s=s->end_next; + } + } +} + +int +route_find(struct route *this, struct route_info *rt_start, struct route_info *rt_end) +{ + struct route_point *start,*start1,*start2; + struct route_segment *s=NULL; + double len=0,slen; + int ret,hr,min,time=0,seg_time,dir,type; + unsigned int val1=0xffffffff,val2=0xffffffff; + + start1=route_get_point(this, &rt_start->seg1); + start2=route_get_point(this, &rt_start->seg2); + assert(start1 != 0); + assert(start2 != 0); + if (start1->value != -1) + val1=start1->value+route_value(rt_start->str_inf.str->type, rt_start->seg1_len); + if (start2->value != -1) + val2=start2->value+route_value(rt_start->str_inf.str->type, rt_start->seg2_len); + + route_add_path_segment(this, 0, 0, &rt_start->click.xy, &rt_start->pos.xy, 1, 0, 0); + type=rt_start->str_inf.str->type; + if (val1 < val2) { + ret=1; + start=start1; + slen=transform_distance(&rt_start->pos.xy, &rt_start->line1.xy); + route_add_path_segment(this, 0, 0, &rt_start->pos.xy, &rt_start->line1.xy, 1, slen, route_time(type, slen)); + route_add_path_segment(this, rt_start->str_inf.str->segid, rt_start->offset, NULL, NULL, -1, rt_start->seg1_len, route_time(type, rt_start->seg1_len)); + } + else { + ret=2; + start=start2; + slen=transform_distance(&rt_start->pos.xy, &rt_start->line2.xy); + route_add_path_segment(this, 0, 0, &rt_start->pos.xy, &rt_start->line2.xy, 1, slen, route_time(type, slen)); + route_add_path_segment(this, rt_start->str_inf.str->segid, -rt_start->offset, NULL, NULL, 1, rt_start->seg2_len, route_time(type, rt_start->seg2_len)); + } + + while (start->value) { + s=start->seg; + if (! s) { + printf("No Route found\n"); + break; + } + if (s->start == start) { + start=s->end; + dir=1; + } + else { + start=s->start; + dir=-1; + } + len+=s->len; + seg_time=route_time(s->str->type, s->len); + time+=seg_time; + route_add_path_segment(this, s->str->segid, s->offset, NULL, NULL, dir, s->len, seg_time); + } + if (s) { + if (s->start->c.xy.x == rt_end->seg1.xy.x && s->start->c.xy.y == rt_end->seg1.xy.y) + route_add_path_segment(this, 0, 0, &rt_end->pos.xy, &rt_end->line1.xy, -1, 0, 0); + else + route_add_path_segment(this, 0, 0, &rt_end->pos.xy, &rt_end->line2.xy, -1, 0, 0); + route_add_path_segment(this, 0, 0, &rt_end->click.xy, &rt_end->pos.xy, -1, 0, 0); + printf("len %5.3f\n", len/1000); + this->route_time_val=time/10; + time/=10; + this->route_len_val=len; + min=time/60; + time-=min*60; + hr=min/60; + min-=hr*60; + printf("time %02d:%02d:%02d\n", hr, min, time); +#if 1 + navigation_path_description(this); +#endif + } + return ret; +} + +struct block_list { + struct block_info blk_inf; + unsigned char *p; + unsigned char *end; + struct block_list *next; +}; + +void +route_process_street_block_graph(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data) +{ + struct route *this=data; + struct block_list *blk_lst=this->blk_lst; + + while (blk_lst) { + if (blk_lst->blk_inf.block_number == blk_inf->block_number && blk_lst->blk_inf.file == blk_inf->file) + return; + blk_lst=blk_lst->next; + } + blk_lst=g_new(struct block_list,1); + blk_lst->blk_inf=*blk_inf; + blk_lst->p=p; + blk_lst->end=end; + blk_lst->next=this->blk_lst; + this->blk_lst=blk_lst; +#if 0 + route_street_foreach(blk_inf, p, end, data, route_process_street_graph); +#endif +} + +void +route_blocklist_free(struct route *this) +{ + struct block_list *curr,*next; + curr=this->blk_lst; + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } +} + +void +route_build_graph(struct route *this, struct map_data *mdata, struct coord *c, int coord_count) +{ + struct coord rect[2]; + struct transformation t; + + int i,j,max_dist,max_coord_dist; + int ranges[7]={0,1024000,512000,256000,128000,64000,32000}; + this->blk_lst=NULL; + struct block_list *blk_lst_curr; + + rect[0]=c[0]; + rect[1]=c[0]; + for (i = 1 ; i < coord_count ; i++) { + if (c[i].x < rect[0].x) + rect[0].x=c[i].x; + if (c[i].x > rect[1].x) + rect[1].x=c[i].x; + if (c[i].y > rect[0].y) + rect[0].y=c[i].y; + if (c[i].y < rect[1].y) + rect[1].y=c[i].y; + } + max_coord_dist=rect[1].x-rect[0].x; + if (max_coord_dist < rect[0].y-rect[1].y) + max_coord_dist=rect[0].y-rect[1].y; + max_coord_dist+=10000+max_coord_dist/2; + + printf("Collecting Blocks\n"); + for (i = 0 ; i < coord_count ; i++) { + for (j = 0 ; j < 7 ; j++) { + printf("range %d,%d\n", i, j); + max_dist=ranges[j]; + if (max_dist == 0 || max_dist > max_coord_dist) + max_dist=max_coord_dist; + + transform_setup_source_rect_limit(&t,&c[i],max_dist); + + map_data_foreach(mdata, file_street_str, &t, j+1, route_process_street_block_graph, this); + } + } + blk_lst_curr=this->blk_lst; + i=0; + while (blk_lst_curr) { + i++; + blk_lst_curr=blk_lst_curr->next; + } + printf("Block Count %d\n", i); + blk_lst_curr=this->blk_lst; + + j=0; + while (blk_lst_curr) { + j++; + printf("%d/%d\n", j, i); + route_street_foreach(&blk_lst_curr->blk_inf, blk_lst_curr->p, blk_lst_curr->end, this, route_process_street_graph); + blk_lst_curr=blk_lst_curr->next; + } +} + +void +route_process_street3(struct block_info *blk_inf, struct street_info *str_inf, unsigned char **p, unsigned char *end, void *data) +{ + int flags=0; + int i,ldist; + struct coord3d first,f,o,l; + struct coord3d cret; + int match=0; + double len=0,len_p=0; + struct route_info *rt_inf=(struct route_info *)data; + + street_get_coord(p, str_inf->bytes, blk_inf->block->c, &f.xy); + f.h=route_get_height(str_inf->str->segid, &f.xy); + + l=f; + o=f; + first=f; + i=0; + + while (*p < end) { + flags=street_get_coord(p, str_inf->bytes, blk_inf->block->c, &f.xy); + f.h=route_get_height(str_inf->str->segid, &f.xy); + if (flags && !str_inf->include) + break; + + if (i++) { + ldist=transform_distance_line_sq(&l.xy, &o.xy, &rt_inf->click.xy, &cret.xy); + if (ldist < rt_inf->dist) { + rt_inf->dist=ldist; + rt_inf->seg1=first; + rt_inf->line1=l; + rt_inf->pos=cret; + rt_inf->blk_inf=*blk_inf; + rt_inf->str_inf=*str_inf; + rt_inf->line2=o; + rt_inf->offset=i-1; + len_p=len; + match=1; + } + if (rt_inf->mode == 1) + len+=transform_distance(&l.xy, &o.xy); + } + l=o; + o=f; + if (flags) + break; + } + ldist=transform_distance_line_sq(&l.xy, &o.xy, &rt_inf->click.xy, &cret.xy); + if (ldist < rt_inf->dist) { + rt_inf->dist=ldist; + rt_inf->seg1=first; + rt_inf->line1=l; + rt_inf->pos=cret; + rt_inf->blk_inf=*blk_inf; + rt_inf->str_inf=*str_inf; + rt_inf->line2=o; + rt_inf->offset=i; + len_p=len; + match=1; + } + if (match) { + rt_inf->seg2=o; + if (rt_inf->mode == 1) { + len+=transform_distance(&l.xy, &o.xy); + len_p+=transform_distance(&rt_inf->pos.xy, &rt_inf->line1.xy); + rt_inf->seg1_len=len_p; + rt_inf->seg2_len=len-len_p; + } + } + *p-=2*str_inf->bytes; +} + + +void +route_process_street_block(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data) +{ + route_street_foreach(blk_inf, p, end, data, route_process_street3); +} + +struct street_str * +route_info_get_street(struct route_info *rt) +{ + return rt->str_inf.str; +} + +struct block_info * +route_info_get_block(struct route_info *rt) +{ + return &rt->blk_inf; +} + +struct route_info * +route_find_nearest_street(struct map_data *mdata, struct coord *c) +{ + struct route_info *ret=g_new0(struct route_info,1); + struct transformation t; + int max_dist=1000; + + transform_setup_source_rect_limit(&t,c,max_dist); + + ret->click.xy=*c; + ret->dist=INT_MAX; + ret->mode=0; + + map_data_foreach(mdata, file_street_str, &t, 48, route_process_street_block, ret); + + return ret; +} + +void +route_find_point_on_street(struct route_info *rt_inf) +{ + unsigned char *p,*end; + + rt_inf->dist=INT_MAX; + rt_inf->mode=1; + + p=rt_inf->str_inf.p; + end=(unsigned char *)rt_inf->blk_inf.block; + end+=rt_inf->blk_inf.block->size; + + route_process_street3(&rt_inf->blk_inf, &rt_inf->str_inf, &p, end, rt_inf); +} + + +struct route_info *start,*end; +int count; + +/* XPM */ +static char * flag_xpm[] = { +"16 16 3 1", +" c None", +"+ c #000000", +"@ c #FFFF00", +"+++ ", +"+@@++ ", +"+@@@@+++ ", +"+@@@@@@@++ ", +"+@@@@@@@@@++ ", +"+@@@@@@@@@@@++ ", +"+@@@@@@@@@++ ", +"+@@@@@@@++ ", +"+@@@@+++ ", +"+@@++ ", +"+++ ", +"+ ", +"+ ", +"+ ", +"+ ", +"+ "}; + +void +route_click(struct route *this, struct container *co, int x, int y) +{ +#if 0 + GtkMap *map=co->map; + struct point pnt; + GdkBitmap *flag_mask; + GdkPixmap *flag; + struct coord c; + struct route_info *rt_inf; + GdkGC *gc; + + + pnt.x=x; + pnt.y=y; + transform_reverse(co->trans, &pnt, &c); + transform(co->trans, &c, &pnt); + rt_inf=route_find_nearest_street(co->map_data, &c); + + + route_find_point_on_street(rt_inf); + + flag=gdk_pixmap_create_from_xpm_d(GTK_WIDGET(map)->window, &flag_mask, NULL, flag_xpm); + gc=gdk_gc_new(map->DrawingBuffer); + + gdk_gc_set_clip_origin(gc,pnt.x, pnt.y-15); + gdk_gc_set_clip_mask(gc,flag_mask); + gdk_draw_pixmap(GTK_WIDGET(map)->window, + gc, + flag, + 0, 0, pnt.x, pnt.y-15, 16, 16); + printf("Segment ID 0x%lx\n", rt_inf->str_inf.str->segid); +#if 0 + printf("Segment Begin 0x%lx, 0x%lx, 0x%x\n", route_info.seg1.xy.x, route_info.seg1.xy.y, route_info.seg1.h); + printf("Segment End 0x%lx, 0x%lx, 0x%x\n", route_info.seg2.xy.x, route_info.seg2.xy.y, route_info.seg2.h); +#endif + +#if 0 + transform(map, &route_info.seg1.xy, &pnt); gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], TRUE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); + transform(map, &route_info.line1.xy, &pnt); gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], TRUE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); + transform(map, &route_info.seg2.xy, &pnt); gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], TRUE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); + transform(map, &route_info.line2.xy, &pnt); gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], TRUE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); + transform(map, &route_info.pos.xy, &pnt); gdk_draw_arc(GTK_WIDGET(map)->window, map->gc[GC_BLACK], TRUE, pnt.x-r/2, pnt.y-r/2, r, r, 0, 64*360); +#endif + printf("offset=%d\n", rt_inf->offset); + printf("seg1_len=%d\n", rt_inf->seg1_len); + printf("seg2_len=%d\n", rt_inf->seg2_len); + + if (trace) { + start=rt_inf; + count=0; + route_path_free(this); + route_find(this, start, end); + map_redraw(map); + } else { + if (! count) { + start=rt_inf; + count=1; + } + else { + end=rt_inf; + count=0; + } + } +#endif +} + +void +route_start(struct route *this, struct container *co) +{ + route_do_start(this, end, start); +} + +void +route_trace(struct container *co) +{ + trace=1-trace; +} + +void +route_data_free(void *t) +{ + route_blocklist_free(t); + route_path_free(t); + route_points_free(t); + route_segments_free(t); +} + +void +route_do_start(struct route *this, struct route_info *rt_start, struct route_info *rt_end) +{ + int res; + struct route_point *seg1,*seg2,*pos; + struct coord c[2]; + struct timeval tv[4]; + + phrase_route_calc(speech_handle); + route_data_free(this); + gettimeofday(&tv[0], NULL); + c[0]=rt_start->pos.xy; + c[1]=rt_end->pos.xy; + route_build_graph(this,this->map_data,c,2); + gettimeofday(&tv[1], NULL); + seg1=route_point_add(this, &rt_end->seg1, 1); + pos=route_point_add(this, &rt_end->pos, 2); + seg2=route_point_add(this ,&rt_end->seg2, 1); + route_segment_add(this, seg1, pos, rt_end->seg1_len, rt_end->str_inf.str, rt_end->offset, 0); + route_segment_add(this, seg2, pos, rt_end->seg2_len, rt_end->str_inf.str, -rt_end->offset, 0); + + printf("flood\n"); + route_flood(this, rt_end); + gettimeofday(&tv[2], NULL); + printf("find\n"); + res=route_find(this, rt_start, rt_end); + printf("ok\n"); + gettimeofday(&tv[3], NULL); + + printf("graph time %ld\n", (tv[1].tv_sec-tv[0].tv_sec)*1000+(tv[1].tv_usec-tv[0].tv_usec)/1000); + printf("flood time %ld\n", (tv[2].tv_sec-tv[1].tv_sec)*1000+(tv[2].tv_usec-tv[1].tv_usec)/1000); + printf("find time %ld\n", (tv[3].tv_sec-tv[2].tv_sec)*1000+(tv[3].tv_usec-tv[2].tv_usec)/1000); + phrase_route_calculated(speech_handle, this); + +} + + +int +route_destroy(void *t) +{ + struct route *this=t; + + route_data_free(t); + if (this->pos) + g_free(this->pos); + if (this->dst) + g_free(this->dst); + g_free(this); + return 0; +} + + +struct tm * +route_get_eta(struct route *this) +{ + time_t eta; + + eta=time(NULL)+this->route_time_val; + + return localtime(&eta); +} + +double +route_get_len(struct route *this) +{ + return this->route_len_val; +} + +struct route_crossings * +route_crossings_get(struct route *this, struct coord *c) +{ + struct coord3d c3; + struct route_point *pnt; + struct route_segment *seg; + int crossings=0; + struct route_crossings *ret; + + c3.xy=*c; + c3.h=0; + pnt=route_get_point(this, &c3); + seg=pnt->start; + while (seg) { + crossings++; + seg=seg->start_next; + } + seg=pnt->end; + while (seg) { + crossings++; + seg=seg->end_next; + } + ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing)); + ret->count=crossings; + return ret; +} diff --git a/route.h b/route.h new file mode 100644 index 00000000..0b249129 --- /dev/null +++ b/route.h @@ -0,0 +1,48 @@ +struct route_path_segment { + struct route_path_segment *next; + long segid; + int offset; + int dir; + int time; + int length; + struct coord c[2]; +}; + +struct route_crossing { + long segid; + int dir; +}; + +struct route_crossings { + int count; + struct route_crossing crossing[0]; +}; + +struct route; +struct map_data; +struct container; +struct route_info; + +struct route *route_new(void); +int route_destroy(); +void route_mapdata_set(struct route *this, struct map_data *mdata); +struct map_data* route_mapdata_get(struct route *this); +void route_display_points(struct route *this, struct container *co); +void route_click(struct route *this, struct container *co, int x, int y); +void route_start(struct route *this, struct container *co); +void route_set_position(struct route *this, struct coord *pos); +void route_set_destination(struct route *this, struct coord *dst); +struct coord *route_get_destination(struct route *this); +struct route_path_segment *route_path_get(struct route *, int segid); +struct route_path_segment *route_path_get_all(struct route *this); +void route_trace(struct container *co); +struct street_str *route_info_get_street(struct route_info *rt); +struct block_info *route_info_get_block(struct route_info *rt); +struct route_info *route_find_nearest_street(struct map_data *mdata, struct coord *c); +void route_find_point_on_street(struct route_info *rt_inf); +void route_do_start(struct route *this, struct route_info *rt_start, struct route_info *rt_end); +int route_find(struct route *this, struct route_info *rt_start, struct route_info *rt_end); +struct tm *route_get_eta(struct route *this); +double route_get_len(struct route *this); +struct route_crossings *route_crossings_get(struct route *this, struct coord *c); + diff --git a/script/get_map b/script/get_map new file mode 100755 index 00000000..20de37d3 --- /dev/null +++ b/script/get_map @@ -0,0 +1,5 @@ +#! /bin/bash +echo "/* XPM */" >map.xpm +req="<MapRequest reqVer='100' format='jpeg' visibleRoutes='111111111' colorDepth='4'><Rect l='0' t='0' r='$1' b='$2'></Rect><Rect l='$3' t='$4' r='$5' b='$6'></Rect></MapRequest>" +perl -e 'print (pack("a20",length($ARGV[0]))) ; print $ARGV[0]' "$req" | netcat localhost 10371 | dd bs=20 skip=1 2>/dev/null | tail +2 >>map.xpm + diff --git a/script/gps_emu b/script/gps_emu new file mode 100755 index 00000000..f2eef3e5 --- /dev/null +++ b/script/gps_emu @@ -0,0 +1,19 @@ +#! /bin/bash +function send_data +{ + trap send_data SIGPIPE + while read line + do + case $line in + \$GPVTG*) + echo "$line" + sleep 1 + ;; + *) + echo "$line" + ;; + esac + done <track/all.txt >/tmp/gpsdata +} + +send_data diff --git a/script/gps_emu2 b/script/gps_emu2 new file mode 100755 index 00000000..8f5d9a61 --- /dev/null +++ b/script/gps_emu2 @@ -0,0 +1,40 @@ +#! /usr/bin/perl + +open(FILE,"<$ARGV[0]"); +read(FILE,$header,64); + +($magic,$version)=unpack("a8l",$header); + +#print "magic=$magic version=$version\n"; + +select STDOUT; $| = 1; + +while (read(FILE,$record,64)) +{ + ($flags,$status,$mode,$hdop,$vdop,$pdop,$sats,$timestampl,$timestamph,$latitude,$longitude,$altitude,$speed,$direction)=unpack("SCCCCCCLLddddd",$record); + + + if ($mode == 3) { + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($timestampl); + $datestring=sprintf("%02d.%02d.%d %02d:%02d:%02d",$mday,$mon+1,$year+1900,$hour,$min,$sec); + $long_dir="E"; + $lat_dir="N"; + if ($longitude < 0) { + $long_dir="W"; + $logitude=-$longitude; + } + if ($latitude < 0) { + $lat_dir="S"; + $latitude=-$latitude; + } + $long_deg=int($longitude); + $lat_deg=int($latitude); + $long_gps=$long_deg*100+($longitude-$long_deg)*60; + $lat_gps=$lat_deg*100+($latitude-$lat_deg)*60; + $lastpos="$lat_gps $lat_dir $long_gps $long_dir"; + printf("\$GPGGA,%02d%02d%02d,%s,%s,%s,%s,1,%d,%s,%s,M,,,,0000*0C\n",$hour,$min,$sec,$lat_gps,$lat_dir,$long_gps,$long_dir,$sats,$hdop,$altitude); + printf("\$GPVTG,%s,T,,M,,N,%s,K,*6A\n",$direction,$speed*1.852); + printf(STDERR "\$GPGGA,%02d%02d%02d,%s,%s,%s,%s,1,%d,%s,%s,M,,,,0000*0C\n",$hour,$min,$sec,$lat_gps,$lat_dir,$long_gps,$long_dir,$sats,$hdop,$altitude); + sleep(1); + } +} diff --git a/script/gps_emu3 b/script/gps_emu3 new file mode 100755 index 00000000..5c0ecf25 --- /dev/null +++ b/script/gps_emu3 @@ -0,0 +1,12 @@ +#! /bin/bash +while read line +do + if [ -n "$line" ] + then + echo $line + fi + if [ "${line#\$GPVTG}" != "$line" ] + then + sleep 1 + fi +done <$1 diff --git a/search.c b/search.c new file mode 100644 index 00000000..165282ce --- /dev/null +++ b/search.c @@ -0,0 +1,442 @@ +#include <glib.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "search.h" +#include "coord.h" +#include "country.h" +#include "town.h" +#include "street.h" +#include "street_name.h" + + +struct search { + struct map_data *map_data; + char *country; + GHashTable *country_hash; + char *postal; + char *town; + GHashTable *town_hash; + char *district; + GHashTable *district_hash; + char *street; + GHashTable *street_hash; + char *number; + int number_low, number_high; + int (*func)(struct search_destination *dest, void *user_data); + void *user_data; +}; + +struct dest_town { + int country; + int assoc; + char *name; + char postal_code[16]; + struct town town; +}; + +static GHashTable * +search_country_new(void) +{ + return g_hash_table_new_full(NULL, NULL, NULL, g_free); +} + +static int +search_country_add(struct country *cou, void *data) +{ + struct search *search=data; + struct country *cou2; + + void *first; + first=g_hash_table_lookup(search->country_hash, (void *)(cou->id)); + if (! first) { + cou2=g_new(struct country, 1); + *cou2=*cou; + g_hash_table_insert(search->country_hash, (void *)(cou->id), cou2); + } + return 0; +} + +static void +search_country_show(gpointer key, gpointer value, gpointer user_data) +{ + struct country *cou=value; + struct search *search=(struct search *)user_data; + struct search_destination dest; + + memset(&dest, 0, sizeof(dest)); + dest.country=cou; + dest.country_name=cou->name; + dest.country_car=cou->car; + dest.country_iso2=cou->iso2; + dest.country_iso3=cou->iso3; + (*search->func)(&dest, search->user_data); +} + +static guint +search_town_hash(gconstpointer key) +{ + const struct dest_town *hash=key; + gconstpointer hashkey=(gconstpointer)(hash->country^hash->assoc); + return g_direct_hash(hashkey); +} + +static gboolean +search_town_equal(gconstpointer a, gconstpointer b) +{ + const struct dest_town *t_a=a; + const struct dest_town *t_b=b; + if (t_a->assoc == t_b->assoc && t_a->country == t_b->country) { + if (t_a->name && t_b->name && strcmp(t_a->name, t_b->name)) + return FALSE; + return TRUE; + } + return FALSE; +} + + +static GHashTable * +search_town_new(void) +{ + return g_hash_table_new_full(search_town_hash, search_town_equal, NULL, g_free); +} + + +static int +search_town_add(struct town *town, void *data) +{ + struct search *search=data; + struct dest_town *first; + + struct dest_town cmp; + char *zip1, *zip2; + + if (town->id == 0x1d546b7e) { + printf("found\n"); + } + cmp.country=town->country; + cmp.assoc=town->street_assoc; + cmp.name=town->name; + first=g_hash_table_lookup(search->town_hash, &cmp); + if (! first) { + first=g_new(struct dest_town, 1); + first->country=cmp.country; + first->assoc=cmp.assoc; + strcpy(first->postal_code, town->postal_code2); + first->name=town->name; + first->town=*town; + g_hash_table_insert(search->town_hash, first, first); + } else { + zip1=town->postal_code2; + zip2=first->postal_code; + while (*zip1 && *zip2) { + if (*zip1 != *zip2) { + while (*zip2) { + *zip2++='.'; + } + break; + } + zip1++; + zip2++; + } + } + cmp.name=NULL; + cmp.assoc=town->id; + first=g_hash_table_lookup(search->district_hash, &cmp); + if (! first) { + first=g_new(struct dest_town, 1); + first->country=cmp.country; + first->assoc=cmp.assoc; + first->name=NULL; + first->town=*town; + g_hash_table_insert(search->district_hash, first, first); + } + return 0; +} + +static void +search_town_search(gpointer key, gpointer value, gpointer user_data) +{ + struct country *cou=value; + struct search *search=user_data; + + town_search_by_name(search->map_data, cou->id, search->town, 1, search_town_add, search); +} + +static void +search_town_set(const struct dest_town *town, struct search_destination *dest, int full) +{ + char country[32]; + struct country *cou; + if ((cou=country_get_by_id(town->country))) { + dest->country=cou; + dest->country_name=cou->name; + dest->country_car=cou->car; + dest->country_iso2=cou->iso2; + dest->country_iso3=cou->iso3; + } else { + sprintf(country,"(%d)", town->country); + dest->country=NULL; + dest->country_car=country; + } + if (full) { + dest->town_postal=(char *)(town->town.postal_code2); + dest->town_name=g_convert(town->town.name,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + if (town->town.district[0]) + dest->district=g_convert(town->town.district,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + else + dest->district=NULL; + } else { + dest->town_postal=(char *)(town->postal_code); + dest->town_name=g_convert(town->name,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + } +} + + +static void +search_town_show(gpointer key, gpointer value, gpointer user_data) +{ + struct dest_town *town=value; + struct search *search=user_data; + struct search_destination dest; + + memset(&dest, 0, sizeof(dest)); + dest.town=&town->town; + dest.street_name=NULL; + dest.c=town->town.c; + search_town_set(town, &dest, 0); + + (*search->func)(&dest, search->user_data); +} + + +GHashTable * +search_street_new(void) +{ + return g_hash_table_new_full(NULL, NULL, NULL, g_free); +} + + +static int +search_street_add(struct street_name *name, void *data) +{ + struct search *search=data; + struct street_name *name2; + + name2=g_new(struct street_name, 1); + *name2=*name; + g_hash_table_insert(search->street_hash, name2, name2); + return 0; +} + +static int +number_partial(int search, int ref, int ext) +{ + int max=1; + + printf("number_partial(%d,%d,%d)", search, ref, ext); + if (ref >= 10) + max=10; + if (ref >= 100) + max=100; + if (ref >= 1000) + max=1000; + while (search < max) { + search*=10; + search+=ext; + } + printf("max=%d result=%d\n", max, search); + return search; +} + +static int +check_number(int low, int high, int s_low, int s_high) +{ + int debug=0; + + if (debug) + printf("check_number(%d,%d,%d,%d)\n", low, high, s_low, s_high); + if (low <= s_high && high >= s_low) + return 1; + if (s_low == s_high) { + if (low <= number_partial(s_high, high, 9) && high >= number_partial(s_low, low, 0)) + return 1; + } + if (debug) + printf("return 0\n"); + return 0; +} + +static void +search_street_show_common(gpointer key, gpointer value, gpointer user_data, int number) +{ + struct street_name *name=value; + struct search *search=user_data; + char *utf8; + struct dest_town cmp; + struct dest_town *town; + char buffer[32]; + struct street_name_info info; + struct street_name_number_info num_info; + struct search_destination dest; + int debug=0; + + memset(&dest, 0, sizeof(dest)); + name->tmp_len=name->aux_len; + name->tmp_data=name->aux_data; + while (street_name_get_info(&info, name)) { + cmp.country=info.country; + cmp.assoc=info.dist; + cmp.name=NULL; + town=g_hash_table_lookup(search->district_hash, &cmp); + if (debug) + printf("town=%p\n", town); + if (town) { + search_town_set(town, &dest, 1); + utf8=g_convert(name->name2,-1,"utf-8","iso8859-1",NULL,NULL,NULL); + dest.street_name=utf8; + if (number) { + info.tmp_len=info.aux_len; + info.tmp_data=info.aux_data; + while (street_name_get_number_info(&num_info, &info)) { + dest.town=&town->town; + dest.street=name; + dest.c=num_info.c; + if (check_number(num_info.first, num_info.last, search->number_low, search->number_high)) { + if (num_info.first == num_info.last) + sprintf(buffer,"%d",num_info.first); + else + sprintf(buffer,"%d-%d",num_info.first,num_info.last); + dest.street_number=buffer; + (*search->func)(&dest, search->user_data); + } + } + } else { + dest.town=&town->town; + dest.street=name; + dest.c=info.c; + (*search->func)(&dest, search->user_data); + } + g_free(utf8); + } else { + printf("Town for '%s' not found\n", name->name2); + } + } +} + +static void +search_street_show(gpointer key, gpointer value, gpointer user_data) +{ + search_street_show_common(key, value, user_data, 0); +} + +static void +search_street_show_number(gpointer key, gpointer value, gpointer user_data) +{ + search_street_show_common(key, value, user_data, 1); +} + +static void +search_street_search(gpointer key, gpointer value, gpointer user_data) +{ + const struct dest_town *town=value; + struct search *search=user_data; + street_name_search(search->map_data, town->country, town->assoc, search->street, 1, search_street_add, search); +} + + + +void search_update(struct search *search, enum search_param what, char *val) +{ + char *dash; + + if (what == search_country) { + if (search->country_hash) g_hash_table_destroy(search->country_hash); + search->country_hash=NULL; + } + if (what == search_country || what == search_town) { + if (search->town_hash) g_hash_table_destroy(search->town_hash); + if (search->district_hash) g_hash_table_destroy(search->district_hash); + search->town_hash=NULL; + search->district_hash=NULL; + } + + if (what == search_country || what == search_town || what == search_street) { + if (search->street_hash) g_hash_table_destroy(search->street_hash); + search->street_hash=NULL; + } + + if (what == search_country) { + g_free(search->country); + search->country=g_strdup(val); + if (val) { + search->country_hash=search_country_new(); + country_search_by_name(val, 1, search_country_add, search); + country_search_by_car(val, 1, search_country_add, search); + country_search_by_iso2(val, 1, search_country_add, search); + country_search_by_iso3(val, 1, search_country_add, search); + g_hash_table_foreach(search->country_hash, search_country_show, search); + } + } + if (what == search_town) { + g_free(search->town); + search->town=g_strdup(val); + if (val) { + search->town_hash=search_town_new(); + search->district_hash=search_town_new(); + g_hash_table_foreach(search->country_hash, search_town_search, search); + g_hash_table_foreach(search->town_hash, search_town_show, search); + } + } + if (what == search_street) { + g_free(search->street); + search->street=g_strdup(val); + if (val) { + search->street_hash=search_street_new(); + g_hash_table_foreach(search->town_hash, search_street_search, search); + g_hash_table_foreach(search->street_hash, search_street_show, search); + } + } + if (what == search_number) { + g_free(search->number); + search->number=g_strdup(val); + if (val) { + char buffer[strlen(val)+1]; + strcpy(buffer, val); + dash=index(buffer,'-'); + if (dash) { + *dash++=0; + search->number_low=atoi(buffer); + if (strlen(val)) + search->number_high=atoi(dash); + else + search->number_high=10000; + } else { + if (!strlen(val)) { + search->number_low=0; + search->number_high=10000; + } else { + search->number_low=atoi(val); + search->number_high=atoi(val); + } + } + g_hash_table_foreach(search->street_hash, search_street_show_number, search); + } + } +} + +struct search * +search_new(struct map_data *mdat, char *country, char *postal, char *town, char *district, char *street, char *number, int (*func)(struct search_destination *dest, void *user_data), void *user_data) +{ + struct search *this=g_new0(struct search,1); + this->map_data=mdat; + this->country=g_strdup(country); + this->postal=g_strdup(postal); + this->town=g_strdup(town); + this->district=g_strdup(district); + this->street=g_strdup(street); + this->number=g_strdup(number); + this->func=func; + this->user_data=user_data; + return this; +} diff --git a/search.h b/search.h new file mode 100644 index 00000000..88f38826 --- /dev/null +++ b/search.h @@ -0,0 +1,30 @@ +enum search_param { + search_country, + search_postal, + search_town, + search_district, + search_street, + search_number +}; + +struct search_destination { + char *country_name; + char *country_car; + char *country_iso2; + char *country_iso3; + char *town_postal; + char *town_name; + char *district; + char *street_name; + char *street_number; + struct country *country; + struct town *town; + struct street_name *street; + struct coord *c; +}; + +struct search; +struct map_data; + +void search_update(struct search *search, enum search_param what, char *val); +struct search *search_new(struct map_data *mdat, char *country, char *postal, char *town, char *district, char *street, char *number, int (*func)(struct search_destination *dest, void *user_data), void *user_data); diff --git a/speech.c b/speech.c new file mode 100644 index 00000000..c913629c --- /dev/null +++ b/speech.c @@ -0,0 +1,61 @@ +/* speechd simple client program + * CVS revision: $Id: speech.c,v 1.1 2005-12-02 10:41:56 martin-s Exp $ + * Author: Tomas Cerha <cerha@brailcom.cz> */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <glib.h> +#include <stdarg.h> + +#include <libspeechd.h> +#include "speech.h" + +struct speech { + int sockfd; +}; + +struct speech * +speech_new(void) { + struct speech *this; + int sockfd; + + sockfd = spd_init("map","main"); + if (sockfd == 0) + return NULL; + this=g_new(struct speech,1); + if (this) { + this->sockfd=sockfd; + } + return this; +} + +int +speech_say(struct speech *this, char *text) { + int err; + + err = spd_sayf(this->sockfd, 2, text); + if (err != 1) + return 1; + return 0; +} + +int +speech_sayf(struct speech *this, char *format, ...) { + char buffer[8192]; + va_list ap; + va_start(ap,format); + vsnprintf(buffer, 8192, format, ap); + return speech_say(this, buffer); +} + +int +speech_destroy(struct speech *this) { + spd_close(this->sockfd); + g_free(this); + return 0; +} diff --git a/speech.h b/speech.h new file mode 100644 index 00000000..a4038e06 --- /dev/null +++ b/speech.h @@ -0,0 +1,5 @@ +struct speech; +struct speech *speech_new(void); +int speech_say(struct speech *this, char *text); +int speech_sayf(struct speech *this, char *format, ...); +int speech_destroy(struct speech *this); diff --git a/statusbar.h b/statusbar.h new file mode 100644 index 00000000..1b9092c9 --- /dev/null +++ b/statusbar.h @@ -0,0 +1,10 @@ +struct route; +struct statusbar_gui; + +struct statusbar { + void (*statusbar_destroy)(struct statusbar *this); + void (*statusbar_mouse_update)(struct statusbar *this, struct transformation *tr, struct point *p); + void (*statusbar_route_update)(struct statusbar *this, struct route *route); + void (*statusbar_gps_update)(struct statusbar *this, int sats, int qual, double lng, double lat, double height, double direction, double speed); + struct statusbar_gui *gui; +}; diff --git a/street.c b/street.c new file mode 100644 index 00000000..f449f1e1 --- /dev/null +++ b/street.c @@ -0,0 +1,455 @@ +#include <assert.h> +#include <stdio.h> +#include <malloc.h> +#include <unistd.h> +#include <glib.h> +#include "container.h" +#include "coord.h" +#include "map_data.h" +#include "file.h" +#include "block.h" +#include "route.h" +#include "street.h" +#include "street_data.h" +#include "street_name.h" +#include "display.h" +#include "draw_info.h" +#include "data_window.h" +#include "data.h" +#include "tree.h" + + +static void +street_draw_segment(struct container *co, struct segment *seg, unsigned char **pos, unsigned char *end, struct coord *ref, int bytes, int include, int disp) +{ + int j,flags,limit; + struct coord f; + struct coord l[2]; + struct street_str *str=seg->data[0]; + char *label; + struct street_name name; + struct param_list param[100]; + struct route_path_segment *route; + struct display_list **displ=co->disp; + int max=10000; + struct point xpoints[max]; + + flags=0; + j=0; + while (! flags && *pos < end) { + flags=street_get_coord(pos, bytes, ref, &f); + if (! j) { + l[0]=f; + l[1]=f; + } else { + if (include || !flags) { + if (f.x < l[0].x) l[0].x=f.x; + if (f.x > l[1].x) l[1].x=f.x; + if (f.y > l[0].y) l[0].y=f.y; + if (f.y < l[1].y) l[1].y=f.y; + } + } + transform(co->trans, &f, &xpoints[j]); + if (! j) + flags=0; + j++; + assert(j < max); + } + if (! include) + j--; + if (is_visible(co->trans, l) && str->type) { + label=NULL; + if (str->nameid) { + street_name_get_by_id(&name, seg->blk_inf.mdata, str->nameid); + if (name.name2[0]) + label=name.name2; + else + label=name.name1; + } + if (str->nameid && name.townassoc < 0 ) { + char buffer[128]; + sprintf(buffer,"-0x%x", -name.townassoc); + label=g_strdup(buffer); + } + limit=0; + if (str->limit == 0x30) + limit=1; + if (str->limit == 0x03) + limit=-1; + if (str->type & 0x40) + limit=-limit; + display_add(&displ[disp], 2, limit, label, j, xpoints, NULL, seg, sizeof(*seg)); + if (co->route && (route=route_path_get(co->route, str->segid))) { + if (! route->offset) + display_add(&displ[display_street_route], 2, 0, label, j, xpoints, NULL, NULL, 0); + else if (route->offset > 0) + display_add(&displ[display_street_route], 2, 0, label, route->offset, xpoints, NULL, NULL, 0); + else + display_add(&displ[display_street_route], 2, 0, label, j+route->offset, xpoints-route->offset, NULL, NULL, 0); + } + if (co->data_window[data_window_type_street]) + data_window_add(co->data_window[data_window_type_street], param, street_get_param(seg, param, 100, 0)); + } + *pos-=2*bytes; +} + +void +street_safety_check(struct street_str *str) +{ +#if 0 + if (!((str->type & 0xf0) == 0x0 || (str->type & 0xf0) == 0x40)) { + printf("str->type=0x%x\n", str->type); + } + assert((str->type & 0xf0) == 0x0 || (str->type & 0xf0) == 0x40); +#endif + assert(str->type != 0xe && str->type != 0x4e && str->type != 0x40); + assert(str->unknown2 == str->unknown3); + assert(str->unknown2 == 0x40 || str->unknown2 == 0x44); +} + +struct street_header_type { + struct street_header *header; + int type_count; + struct street_type *type; +}; + +static void +street_header_type_get(struct block *blk, unsigned char **p_p, struct street_header_type *ret) +{ + unsigned char *p=*p_p; + ret->header=(struct street_header *)p; + p+=sizeof(struct street_header); + ret->type_count=blk->count; + ret->type=(struct street_type *)p; + p+=ret->type_count*sizeof(struct street_type); + assert(ret->header->count == blk->count); + *p_p=p; +} + +static void +street_coord_get_begin(unsigned char **p_p) +{ + unsigned char *p=*p_p; + struct street_str *str; + + str=(struct street_str *)p; + while (str->segid) { + str++; + } + p=(unsigned char *)str; + p+=4; + *p_p=p; +} + +void +street_draw_block(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data) +{ + struct street_str *str; + struct street_header_type header_type; + struct street_type *str_type; + int include,count,ncount,bytes,offset; + struct draw_info *drw_inf=data; + struct segment seg; + + seg.blk_inf=*blk_inf; + + street_header_type_get(blk_inf->block, &p, &header_type); + if (header_type.header->order >= drw_inf->limit) + return; + + str_type=header_type.type; + bytes=street_get_bytes(blk_inf->block); + str=(struct street_str *)p; + count=0; + ncount=0; + street_coord_get_begin(&p); + str_type--; + while (str->segid) { + include=1; + if (str[1].segid < 0) { + include=0; + str_type++; + } + seg.data[0]=str; + seg.data[1]=str_type; + seg.data[2]=p; + seg.data[3]=header_type.header; + street_safety_check(str); + offset=0; + if (header_type.header->order < 0x2) + offset=3; + else if (header_type.header->order < 0x4 && str->type != 0x6 && str->type != 0x46) + offset=2; + else if (header_type.header->order < 0x6) + offset=1; + if (str->limit == 0x33) + offset=4; + street_draw_segment(drw_inf->co, &seg, &p, end-4, blk_inf->block->c, bytes, include, drw_inf->display+offset); + str++; + } +} + +void +street_bti_draw_block(struct block_info *blk_inf, unsigned char *p, unsigned char *end, void *data) +{ + struct draw_info *drw_inf=data; + struct street_bti *str; + struct point pnt; + struct param_list param[100]; + struct segment seg; + + while (p < end) { + str=(struct street_bti *)p; + seg.data[0]=str; + p+=sizeof(*str); + if (transform(drw_inf->co->trans, &str->c, &pnt)) { + display_add(&drw_inf->co->disp[display_bti], 4, 0, NULL, 1, &pnt, NULL, &seg, sizeof(seg)); + if (drw_inf->co->data_window[data_window_type_point]) + data_window_add(drw_inf->co->data_window[data_window_type_point], param, street_bti_get_param(&seg, param, 100)); + } + } +} + +void +street_route_draw(struct container *co) +{ + struct route_path_segment *route=NULL; + struct point xpoints[2]; + + if (co->route) + route=route_path_get_all(co->route); + while (route) { + if (!route->segid) { + transform(co->trans, &route->c[0], &xpoints[0]); + transform(co->trans, &route->c[1], &xpoints[1]); + display_add(&co->disp[display_street_route], 2, 0, NULL, 2, xpoints, NULL, NULL, 0); + } + route=route->next; + } +} + +struct street_coord * +street_coord_get(struct block_info *blk_inf, struct street_str *str) +{ + struct block *blk; + unsigned char *p=(unsigned char *)(blk_inf->block),*end,*p_sav; + struct street_header_type hdr_type; + struct street_str *str_curr; + struct coord f,*c; + struct street_coord *ret; + int bytes,num,points,include; + int debug=0; + + end=p; + blk=block_get(&p); + end+=blk->size; + + street_header_type_get(blk, &p, &hdr_type); + str_curr=(struct street_str *)p; + num=str-str_curr; + street_coord_get_begin(&p); + bytes=street_get_bytes(blk); + if (debug) { + printf("num=%d\n", num); + } + street_get_coord(&p, bytes, blk->c, &f); + while (num && str_curr->segid) { + while (! street_get_coord(&p, bytes, blk->c, &f) && p < end); + str_curr++; + num--; + } + include=(str[1].segid > 0); + p_sav=p-2*bytes; + points=1+include; + while (! street_get_coord(&p, bytes, blk->c, &f) && p < end) + points++; + + if (debug) + printf("p=%p points=%d\n",p_sav, points); + p=p_sav; + ret=malloc(sizeof(struct street_coord)+points*sizeof(struct coord)); + ret->count=points; + c=ret->c; + while (points) { + street_get_coord(&p, bytes, blk->c, c); + c++; + points--; + } + return ret; +} + +#if 0 +struct street_nearest * +street_find_nearest(struct map_data *mdata, struct coord *c) +{ + struct street_nearest *ret=g_new0(struct street_nearest,1); + struct transformation t; + int max_dist=1000; + + transform_setup_source_rect_limit(&t,c,max_dist); + + ret->click.xy=*c; + ret->dist=INT_MAX; + ret->mode=0; + + map_data_foreach(mdata, file_street_str, &t, 48, route_process_street_block, ret); + + ret->mode=1; + ret->dist=INT_MAX; + + return ret; +} + +#endif + +int +street_get_by_id(struct map_data *mdat, int id, struct block_info *res_blk_inf, struct street_str **res_str) +{ + int debug=0; + int res,block,num; + struct map_data *mdat_res; + struct block *blk; + unsigned char *p; + struct street_header_type hdr_type; + struct street_str *str; + + if (tree_search_hv_map(mdat, file_street_str, (id >> 8) | 0x31000000, id & 0xff, &res, &mdat_res)) { + return 1; + } + + block=res >> 12; + num=res & 0xfff; + if (debug) { + printf("block=0x%x\n", block); + printf("num=0x%x\n", num); + } + blk=block_get_byindex(mdat_res->file[file_street_str], block, &p); + res_blk_inf->mdata=mdat_res; + res_blk_inf->file=mdat_res->file[file_street_str]; + res_blk_inf->block=blk; + if (debug) { + printf("blk->count=0x%x\n", blk->count); + } + street_header_type_get(blk, &p, &hdr_type); + str=(struct street_str *)p; + str+=num; + *res_str=str; + return 0; +} + +int +street_get_param(struct segment *seg, struct param_list *param, int count, int verbose) +{ + char buffer[1024]; + int i=count,j; + struct street_str *str=seg->data[0]; + struct street_type *type=seg->data[1]; + struct street_name name; + struct street_name_info name_info; +#if 0 + struct street_name_number_info name_number_info; +#endif + + param_add_hex("Type-Addr", (unsigned char *)type-seg->blk_inf.file->begin, ¶m, &count); + param_add_hex("Order", type->order, ¶m, &count); + param_add_hex("Country", type->country, ¶m, &count); + + param_add_hex("Addr", (unsigned char *)str-seg->blk_inf.file->begin, ¶m, &count); + param_add_hex_sig("Seg-Id", str->segid, ¶m, &count); + param_add_hex("Limit", str->limit, ¶m, &count); + param_add_hex("Unknown2", str->unknown2, ¶m, &count); + param_add_hex("Unknown3", str->unknown3, ¶m, &count); + param_add_hex("Type", str->type, ¶m, &count); + param_add_hex("Name-Id", str->nameid, ¶m, &count); + if (str->segid) { + street_name_get_by_id(&name, seg->blk_inf.mdata, str->nameid); + + param_add_hex("Len", name.len, ¶m, &count); + param_add_hex("Country", name.country, ¶m, &count); + param_add_hex_sig("TownAssoc", name.townassoc, ¶m, &count); + printf("TownAssoc 0x%lx\n", name.townassoc+str->segid); + param_add_string("Name1", name.name1, ¶m, &count); + param_add_string("Name2", name.name2, ¶m, &count); + param_add_hex("Segments", name.segment_count, ¶m, &count); + if (verbose) { + for (j = 0 ; j < name.segment_count ; j++) { + sprintf(buffer,"0x%x 0x%x", name.segments[j].country, name.segments[j].segid); + param_add_string("Segment", buffer, ¶m, &count); + } + param_add_hex("Len", name.aux_len, ¶m, &count); + while (street_name_get_info(&name_info, &name)) { + param_add_hex("Len", name_info.len, ¶m, &count); + param_add_hex("Tag", name_info.tag, ¶m, &count); + param_add_hex("Dist", name_info.dist, ¶m, &count); + param_add_hex("Country", name_info.country, ¶m, &count); + param_add_hex("X", name_info.c->x, ¶m, &count); + param_add_hex("Y", name_info.c->y, ¶m, &count); + param_add_dec("First", name_info.first, ¶m, &count); + param_add_dec("Last", name_info.last, ¶m, &count); + param_add_hex("Segments", name_info.segment_count, ¶m, &count); + } +#if 0 + int tag; + int k, segs; + printf("\n"); + printf("Len 0x%x\n",get_short(&stn)); + tag=*stn++; + printf("Tag 0x%x\n",tag); + if (tag == 0xc0 || tag == 0xd0 || tag == 0xe0) { + printf("DistAssoc 0x%lx\n",get_long(&stn)); + printf("Country 0x%lx\n",get_long(&stn)); + printf("X 0x%lx\n",get_long(&stn)); + printf("Y 0x%lx\n",get_long(&stn)); + printf("First %ld\n",get_triple(&stn)); + printf("Last %ld\n",get_triple(&stn)); + segs=get_long(&stn); + printf("Segs 0x%x\n",segs); + for (k = 0 ; k < 0 ; k++) { + printf("SegId 0x%lx\n", get_long(&stn)); + printf("Country 0x%lx\n",get_long(&stn)); + } + } else if (tag == 0x8f || tag == 0xaa || tag == 0xab || tag == 0xae || tag == 0xaf || tag == 0x9a || tag == 0x9e || tag == 0x9f) { + printf("X 0x%lx\n",get_long(&stn)); + printf("Y 0x%lx\n",get_long(&stn)); + printf("First %ld\n",get_triple(&stn)); + printf("Last %ld\n",get_triple(&stn)); + printf("SegId 0x%lx\n",get_long(&stn)); + printf("Country 0x%lx\n",get_long(&stn)); + } else { + printf("Unknown tag 0x%x\n", tag); + break; + } + } +#endif + } + } else { + if (!verbose) { + param_add_string("Len", "", ¶m, &count); + param_add_string("Country", "", ¶m, &count); + param_add_string("TownAssoc", "", ¶m, &count); + param_add_string("Name1", "", ¶m, &count); + param_add_string("Name2", "", ¶m, &count); + param_add_string("Segments", "", ¶m, &count); + } + } + return i-count; +} + +int +street_bti_get_param(struct segment *seg, struct param_list *param, int count) +{ + int i=count; + struct street_bti *str=seg->data[0]; + + param_add_hex("Addr", (unsigned char *)str-seg->blk_inf.file->begin, ¶m, &count); + param_add_hex("Unknown1", str->unknown1, ¶m, &count); + param_add_hex("Segid1", str->segid1, ¶m, &count); + param_add_hex("Country1", str->country1, ¶m, &count); + param_add_hex("Segid2", str->segid2, ¶m, &count); + param_add_hex("Country2", str->country2, ¶m, &count); + param_add_hex("Unknown5", str->unknown5, ¶m, &count); + param_add_hex("X", str->c.x, ¶m, &count); + param_add_hex("Y", str->c.y, ¶m, &count); + + return i-count; +} diff --git a/street.h b/street.h new file mode 100644 index 00000000..65d024f1 --- /dev/null +++ b/street.h @@ -0,0 +1,53 @@ +struct container; +struct block_info; +struct segment; + +struct street_header { + unsigned char order; + int count; +} __attribute__((packed)); + +struct street_type { + unsigned char order; + unsigned short country; +} __attribute__((packed)); + +struct street_str { + long segid; + unsigned char limit; /* 0x03,0x30=One Way,0x33=No Passing */ + unsigned char unknown2; + unsigned char unknown3; + unsigned char type; + unsigned long nameid; +}; + +struct street_bti { + unsigned char unknown1; + unsigned long segid1; + unsigned long country1; + unsigned long segid2; + unsigned long country2; + unsigned char unknown5; + struct coord c; +} __attribute__((packed)); + +struct street_route { + struct street_route *next; + long segid; + int offset; + struct coord c[2]; +}; + +struct street_coord { + int count; + struct coord c[0]; +}; + + +void street_draw_block(struct block_info *blk_inf, unsigned char *start, unsigned char *end, void *data); +struct street_coord *street_coord_get(struct block_info *blk_inf, struct street_str *str); +int street_get_by_id(struct map_data *mdat, int id, struct block_info *res_blk_inf, struct street_str **res_str); +void street_bti_draw_block(struct block_info *blk_inf, unsigned char *start, unsigned char *end, void *data); +int street_get_param(struct segment *seg, struct param_list *param, int count, int verbose); +int street_bti_get_param(struct segment *seg, struct param_list *param, int count); +void street_route_draw(struct container *co); diff --git a/street_data.h b/street_data.h new file mode 100644 index 00000000..a7701430 --- /dev/null +++ b/street_data.h @@ -0,0 +1,60 @@ +static inline int street_get_bytes(struct block *blk) +{ + int bytes,dx,dy; + bytes=2; + dx=blk->c[1].x-blk->c[0].x; + dy=blk->c[0].y-blk->c[1].y; + + if (dx > 32767 || dy > 32767) + bytes=3; + if (dx > 8388608 || dy > 8388608) + bytes=4; + + return bytes; +} + +static inline int street_get_coord(unsigned char **pos, int bytes, struct coord *ref, struct coord *f) +{ + unsigned char *p; + int x,y,flags=0; + + p=*pos; + x=*p++; + x|=(*p++) << 8; + if (bytes == 2) { + if ( x > 0x7fff) { + x=0x10000-x; + flags=1; + } + } + else if (bytes == 3) { + x|=(*p++) << 16; + if ( x > 0x7fffff) { + x=0x1000000-x; + flags=1; + } + } else { + x|=(*p++) << 16; + x|=(*p++) << 24; + if (x < 0) { + x=-x; + flags=1; + } + } + y=*p++; + y|=(*p++) << 8; + if (bytes == 3) { + y|=(*p++) << 16; + } else if (bytes == 4) { + y|=(*p++) << 16; + y|=(*p++) << 24; + } + f->x=ref[0].x+x; + f->y=ref[1].y+y; +#if 0 + printf("0x%x,0x%x + 0x%x,0x%x = 0x%x,0x%x", x, y, ref[0].x, ref[1].y, f->x, f->y); +#endif + *pos=p; + return flags; +} + diff --git a/street_name.c b/street_name.c new file mode 100644 index 00000000..202c8ae5 --- /dev/null +++ b/street_name.c @@ -0,0 +1,260 @@ +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "map_data.h" +#include "street_name.h" +#include "file.h" +#include "block.h" +#include "data.h" +#include "tree.h" + +void +street_name_get_by_id(struct street_name *name, struct map_data *mdat, unsigned long id) +{ + unsigned char *p; + if (id) { + p=mdat->file[file_strname_stn]->begin+id+0x2000; + street_name_get(name, &p); + } +} + +void +street_name_get(struct street_name *name, unsigned char **p) +{ + unsigned char *start=*p; + name->len=get_short(p); + name->country=get_short(p); + name->townassoc=get_long(p); + name->name1=get_string(p); + name->name2=get_string(p); + name->segment_count=get_long(p); + name->segments=(struct street_name_segment *)(*p); + (*p)+=(sizeof (struct street_name_segment))*name->segment_count; + name->aux_len=name->len-(*p-start); + name->aux_data=*p; + name->tmp_len=name->aux_len; + name->tmp_data=name->aux_data; + (*p)+=name->aux_len; +} + + +struct street_name_index { + unsigned short country; + long town_assoc; + char name[0]; +} __attribute__((packed)); + +struct street_search_priv { + struct street_name_index *search; + int partial; + struct block_offset last_leaf; + struct map_data *last_mdat; + int last_res; +}; + +int street_name_compare(struct street_name_index *i1, struct street_name_index *i2, int partial) +{ + char c1_u,c2_u; + int ret=0; + int debug=0; + + if (i1->country > i2->country) + ret=2; + if (i1->country < i2->country) + ret=-2; + if (! ret) { + if (debug) + printf("town: %ld vs %ld\n", i1->town_assoc,i2->town_assoc); + if (i1->town_assoc > i2->town_assoc) + ret=2; + if (i1->town_assoc < i2->town_assoc) + ret=-2; + if (! ret) { + char *c1=i1->name; + char *c2=i2->name; + if (debug) + printf("name: '%s' vs '%s'\n", c1, c2); + for (;;) { + c1_u=toupper(*c1); + c2_u=toupper(*c2); + if (c1_u == c2_u && c1) { + c1++; + c2++; + } else { + if (! c1_u && ! c2_u) { + if (debug) + printf("return 0: end of strings\n"); + ret=0; + break; + } + if (c1_u == '\0' && c2_u == '\t') { + if (debug) + printf("return 0: delimiter found\n"); + ret=0; + break; + } + if (c1_u == '\0' && partial) { + ret=-1; + break; + } + if (c1_u > c2_u) { + ret=2; + break; + } + if (c1_u < c2_u) { + ret=-2; + break; + } + } + } + } + } + return ret; +} + +static int +street_name_tree_process(int version, int leaf, unsigned char **s2, struct map_data *mdat, void *data) +{ + int ret; + struct street_search_priv *priv_data=data; + struct block_offset *blk_off; + int debug=0; + + blk_off=(struct block_offset *)(*s2); + if (debug) + printf("0x%lx\n", get_long(s2)); + else + get_long(s2); + struct street_name_index *i1=priv_data->search; + struct street_name_index *i2=(struct street_name_index *)(*s2); + + if (debug) { + printf("Country %d %d\n",i1->country, i2->country); + printf("Town_Assoc 0x%lx 0x%lx\n",i1->town_assoc, i2->town_assoc); + printf("Name '%s' '%s'\n",i1->name, i2->name); + printf("Leaf Data 0x%x 0x%x %d\n", blk_off->offset, blk_off->block, sizeof(*blk_off)); + } + *s2+=sizeof(*i2)+strlen(i2->name)+1; + ret=street_name_compare(i1, i2, priv_data->partial); + if (ret <= 0 && leaf == 1 && i1->country == i2->country && priv_data->last_res > 0) { + if (debug) + printf("street_tree_process: file='%s'\n", mdat->file[file_strname_stn]->name); + priv_data->last_leaf=*blk_off; + priv_data->last_mdat=mdat; + priv_data->last_res=ret; + } + if (debug) + printf("ret=%d\n", ret); + return ret; +} + +int +street_name_search(struct map_data *mdat, int country, int town_assoc, const char *name, int partial, int (*func)(struct street_name *name, void *data), void *data) +{ + struct street_search_priv priv; + unsigned char idx_buffer[strlen(name)+1+sizeof(struct street_name_index)]; + struct street_name_index *idx=(struct street_name_index *)idx_buffer; + struct block *blk; + unsigned char *p,*end; + int blk_num,res; + struct street_name str_name; + char buffer2[4096]; + struct street_name_index *idx2=(struct street_name_index *)buffer2; + int ret,debug=0; + + priv.partial=partial; + idx->country=country; + idx->town_assoc=town_assoc; + strcpy(idx->name, name); + priv.search=idx; + priv.last_res=1; + priv.last_mdat=NULL; + + tree_search_map(mdat, file_strname_stn, "b1", street_name_tree_process, &priv); + +#if 0 + if (debug) + printf("street_search_by_name: name='%s' leaf_data=0x%x priv=%p\n",name,priv.last_leaf.data,&priv); +#endif + if (!priv.last_mdat) + return 0; + blk_num=priv.last_leaf.offset; + if (debug) { + printf("block_num 0x%x\n", blk_num); + printf("file %p\n", priv.last_mdat->file[file_strname_stn]); + } + blk=block_get_byindex(priv.last_mdat->file[file_strname_stn], blk_num, &p); + end=(unsigned char *)blk; + end+=blk->size; + + p=(unsigned char *)blk; + p+=12; + if (debug) + printf("p=%p\n",p); + while (p < end) { + street_name_get(&str_name, &p); + idx2->country=str_name.country; + idx2->town_assoc=str_name.townassoc; + strcpy(idx2->name, str_name.name2); + res=street_name_compare(idx,idx2,partial); + if (res == 0 || res == -1) { + if (debug) + printf("Add res=%d '%s' '%s'\n",res,str_name.name1,str_name.name2); + ret=(*func)(&str_name, data); + if (ret) + return 1; + } + if (res < -1) + break; + } + if (debug) + printf("street_search_by_name: %p vs %p\n", p, end); + return 0; +} + + +int +street_name_get_info(struct street_name_info *inf, struct street_name *name) +{ + unsigned char *p=name->tmp_data; + + if (name->tmp_len <= 0) + return 0; + inf->len=get_short(&p); + inf->tag=*p++; + inf->dist=get_long(&p); + inf->country=get_long(&p); + inf->c=coord_get(&p); + inf->first=get_triple(&p); + inf->last=get_triple(&p); + inf->segment_count=get_long(&p); + inf->segments=(struct street_segment *)p; + p+=sizeof(struct street_name_segment)*inf->segment_count; + inf->aux_len=name->tmp_data+name->tmp_len-p; + inf->aux_data=p; + inf->tmp_len=inf->aux_len; + inf->tmp_data=inf->aux_data; + name->tmp_data+=inf->len; + name->tmp_len-=inf->len; + + return 1; +} + +int +street_name_get_number_info(struct street_name_number_info *num, struct street_name_info *inf) +{ + unsigned char *p=inf->tmp_data; + + if (inf->tmp_len <= 0) + return 0; + num->len=get_short(&p); + num->tag=*p++; + num->c=coord_get(&p); + num->first=get_triple(&p); + num->last=get_triple(&p); + num->segment=(struct street_name_segment *)p; + inf->tmp_data+=num->len; + inf->tmp_len-=num->len; + + return 1; +} diff --git a/street_name.h b/street_name.h new file mode 100644 index 00000000..b6c178b1 --- /dev/null +++ b/street_name.h @@ -0,0 +1,51 @@ +struct street_name_segment { + int segid; + int country; +}; + +struct street_name { + int len; + int country; + int townassoc; + char *name1; + char *name2; + int segment_count; + struct street_name_segment *segments; + int aux_len; + unsigned char *aux_data; + int tmp_len; + unsigned char *tmp_data; +}; + + +struct street_name_info { + int len; + int tag; + int dist; + int country; + struct coord *c; + int first; + int last; + int segment_count; + struct street_segment *segments; + int aux_len; + unsigned char *aux_data; + int tmp_len; + unsigned char *tmp_data; +}; + +struct street_name_number_info { + int len; + int tag; + struct coord *c; + int first; + int last; + struct street_name_segment *segment; +}; + +void street_name_get_by_id(struct street_name *name, struct map_data *mdat, unsigned long id); +void street_name_get(struct street_name *name, unsigned char **p); +int street_name_search(struct map_data *mdat, int country, int town_assoc, const char *name, int partial, int (*func)(struct street_name *name, void *data), void *data); +int street_name_get_info(struct street_name_info *inf, struct street_name *name); +int street_name_get_number_info(struct street_name_number_info *num, struct street_name_info *inf); + diff --git a/toolbar.h b/toolbar.h new file mode 100644 index 00000000..ce2f18d6 --- /dev/null +++ b/toolbar.h @@ -0,0 +1,3 @@ +struct toolbar { + struct toolbar_gui *gui; +}; @@ -0,0 +1,260 @@ +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include "display.h" +#include "coord.h" +#include "data_window.h" +#include "map_data.h" +#include "town.h" +#include "data.h" +#include "tree.h" +#include "block.h" +#include "file.h" +#include "draw_info.h" +#include "container.h" +#include "util.h" + +void +town_get(struct town *town, unsigned char **p) +{ + town->id=get_long(p); + town->c=coord_get(p); + town->name=get_string(p); + town->district=get_string(p); + town->postal_code1=get_string(p); + town->order=get_char(p); + town->country=get_short(p); + town->type=get_char(p); + town->unknown2=get_long(p); + town->size=get_char(p); + town->street_assoc=get_long(p); + town->unknown3=get_char(p); + town->postal_code2=get_string(p); + town->unknown4=get_long(p); +} + +void +town_draw_block(struct block_info *blk_inf, unsigned char *start, unsigned char *end, void *data) +{ + unsigned char *p=start; + struct town town; + char *s; + struct point pnt; + struct param_list param[100]; + struct segment seg; + struct draw_info *drw_inf=data; + struct data_window *win=drw_inf->co->data_window[data_window_type_town]; + + seg.blk_inf=*blk_inf; + + p+=4; + while (p < end) { + seg.data[0]=p; + town_get(&town, &p); + if (town.order < drw_inf->limit && transform(drw_inf->co->trans, town.c, &pnt)) { + s=town.name; + if (*town.district) + s=town.district; + display_add(&drw_inf->co->disp[drw_inf->display+town.order], 3, 0, s, 1, &pnt, NULL, &seg, sizeof(seg)); + if (win) + data_window_add(win, param, town_get_param(&seg, param, 100)); + } + } +} + +struct town_search_priv { + int country; + const char *name; + int name_len; + int partial; + int leaf; + int (*func)(struct town *, void *data); + void *data; +}; + +static int +town_tree_process(int version, int leaf, unsigned char **s2, struct map_data *mdat, void *data) +{ + int len, cmp, country; + struct block *blk; + struct town_search_priv *priv_data=data; + struct file *f=mdat->file[file_town_twn]; + struct block_offset *blk_off; + struct town town; + unsigned char *p,*name; + int ret,i,debug=0; + + country=get_short(s2); + name=get_string(s2); + if (debug) { + printf("Country: 0x%x ", country); + printf("Town: '%s' ", name); + } + len=get_long(s2); + + blk_off=(struct block_offset *)(*s2); + *s2+=len*4; + + cmp=priv_data->country-country; + if (! cmp) { + if (leaf == -1) + priv_data->leaf=0; + if (leaf == 1) + priv_data->leaf=1; + + if (debug) { + printf("'%s' vs '%s' version=%d\n", priv_data->name, name, version); + } + if (priv_data->leaf && priv_data->partial) + cmp=strncmp(priv_data->name,name,priv_data->name_len); + else + cmp=strcmp(priv_data->name,name); + } else { + if (debug) { + printf("country mismatch\n"); + } + } + + if (cmp > 0) + return 2; + if (cmp < 0) + return -2; + if (debug) + printf("%s\n", name); + for (i = 0 ; i < len ; i++) { + blk=block_get_byindex(f, blk_off->block, &p); + p=(unsigned char *)blk+blk_off->offset; + town_get(&town, &p); + ret=(*priv_data->func)(&town, priv_data->data); + if (ret) + return 1; + blk_off++; + } + return 0; +} + +int +town_search_by(struct map_data *mdat, char *ext, int country, const char *search, int partial, int (*func)(struct town *, void *data), void *data) +{ + struct town_search_priv priv_data; + priv_data.country=country; + priv_data.name=search; + priv_data.name_len=strlen(search); + priv_data.partial=partial; + priv_data.leaf=0; + priv_data.func=func; + priv_data.data=data; + + tree_search_map(mdat, file_town_twn, ext, town_tree_process, &priv_data); + + return 0; +} + +int +town_search_by_postal_code(struct map_data *mdat, int country, unsigned char *name, int partial, int (*func)(struct town *, void *data), void *data) +{ + unsigned char uname[strlen(name)+1]; + + strtoupper(uname, name); + return town_search_by(mdat, "b1", country, uname, partial, func, data); +} + + +int +town_search_by_name(struct map_data *mdat, int country, const char *name, int partial, int (*func)(struct town *, void *data), void *data) +{ + unsigned char uname[strlen(name)+1]; + + strtolower(uname, (char *)name); + return town_search_by(mdat, "b2", country, uname, partial, func, data); +} + +int +town_search_by_district(struct map_data *mdat, int country, unsigned char *name, int partial, int (*func)(struct town *, void *data), void *data) +{ + unsigned char uname[strlen(name)+1]; + + strtoupper(uname, name); + return town_search_by(mdat, "b3", country, uname, partial, func, data); +} + +int +town_search_by_name_phon(struct map_data *mdat, int country, unsigned char *name, int partial, int (*func)(struct town *, void *data), void *data) +{ + unsigned char uname[strlen(name)+1]; + + strtoupper(uname, name); + return town_search_by(mdat, "b4", country, uname, partial, func, data); +} + +int +town_search_by_district_phon(struct map_data *mdat, int country, unsigned char *name, int partial, int (*func)(struct town *, void *data), void *data) +{ + unsigned char uname[strlen(name)+1]; + + strtoupper(uname, name); + return town_search_by(mdat, "b5", country, uname, partial, func, data); +} + + +void +town_get_by_id(struct town *town, struct map_data *mdat, int country, int id) +{ + struct map_data *mdat_res; + struct file *f; + int res,block,offset; + struct block *blk; + unsigned char *p; + int search1,search2; + unsigned long id2=id; + + if (id < 0) + id=-id; + search2 = id2 & 0xff; + search1 = (id2 >> 8) | (country << 24); + printf("country=0x%x id=0x%lx -id=0x%lx search1=0x%x search2=0x%x\n", country, id2, -id2, search1, search2); + return; + tree_search_hv_map(mdat, file_town_twn, search1, search2, &res, &mdat_res); + printf("res=0x%x\n",res); + block=res >> 16; + offset=res & 0xffff; + f=mdat_res->file[file_town_twn]; + printf("file %s block 0x%x offset 0x%x\n", f->name, block, offset); + blk=block_get_byindex(f, block, &p); + p=(unsigned char *)blk+offset; + printf("addr 0x%x\n", p-f->begin); + town_get(town, &p); +} + +int +town_get_param(struct segment *seg, struct param_list *param, int count) +{ + int i=count; + unsigned char *p; + struct town town; + + p=(unsigned char *)(seg->blk_inf.block); + p+=sizeof(*seg->blk_inf.block); + + param_add_hex("Block Unknown", get_long(&p), ¶m, &count); + p=seg->data[0]; + param_add_hex("Address", p-seg->blk_inf.file->begin, ¶m, &count); + town_get(&town, &p); + param_add_hex("ID", town.id, ¶m, &count); + param_add_hex_sig("X", town.c->x, ¶m, &count); + param_add_hex_sig("Y", town.c->y, ¶m, &count); + param_add_string("Name", town.name, ¶m, &count); + param_add_string("District", town.district, ¶m, &count); + param_add_string("PostalCode1", town.postal_code1, ¶m, &count); + param_add_hex("Order", town.order, ¶m, &count); + param_add_hex("Country", town.country, ¶m, &count); + param_add_hex("Type", town.type, ¶m, &count); + param_add_hex("Unknown2", town.unknown2, ¶m, &count); + param_add_hex("Size", town.size, ¶m, &count); + param_add_hex("StreetAssoc", town.street_assoc, ¶m, &count); + param_add_hex("Unknown3", town.unknown3, ¶m, &count); + param_add_string("PostalCode2", town.postal_code2, ¶m, &count); + param_add_hex("Unknown4", town.unknown4, ¶m, &count); + + return i-count; +} @@ -0,0 +1,27 @@ +struct town { + unsigned long id; + struct coord *c; + char *name; + char *district; + char *postal_code1; + unsigned char order; + unsigned char type; + unsigned short country; + unsigned long unknown2; + unsigned char size; + unsigned long street_assoc; + unsigned char unknown3; + char *postal_code2; + unsigned long unknown4; +}; + +struct block_info; +struct segment; +struct container; +struct param_list; +struct map_data; + +void town_draw_block(struct block_info *blk_inf, unsigned char *start, unsigned char *end, void *data); +int town_get_param(struct segment *seg, struct param_list *param, int count); +int town_search_by_name(struct map_data *mdat, int country, const char *name, int partial, int (*func)(struct town *t, void *data), void *data); +void town_get_by_id(struct town *town, struct map_data *mdat, int country, int id); diff --git a/transform.c b/transform.c new file mode 100644 index 00000000..a0f6fe6a --- /dev/null +++ b/transform.c @@ -0,0 +1,363 @@ +#include <assert.h> +#include <stdio.h> +#include <math.h> +#include <limits.h> +#include "coord.h" +#include "transform.h" + +int +transform(struct transformation *t, struct coord *c, struct point *p) +{ + double xc,yc; + int ret=0; + xc=c->x; + yc=c->y; + if (xc >= t->rect[0].x && xc <= t->rect[1].x && yc >= t->rect[1].y && yc <= t->rect[0].y) + ret=1; + xc-=t->center.x; + yc-=t->center.y; + yc=-yc; + if (t->angle) { + int xcn, ycn; + xcn=xc*t->cos_val+yc*t->sin_val; + ycn=-xc*t->sin_val+yc*t->cos_val; + xc=xcn; + yc=ycn; + } + xc=xc*16.0/(double)(t->scale); + yc=yc*16.0/(double)(t->scale); +#if 0 + { + double zc=yc; + if (zc < 10 && zc > 10) + zc=10; + return 0; + yc=300; + xc/=(-zc+1000.0)/1000.0; + yc/=(-zc+1000.0)/1000.0; + xc+=t->width/2; + } +#else + yc+=t->height/2; + xc+=t->width/2; +#endif + if (xc < -0x8000) + xc=-0x8000; + if (xc > 0x7fff) { + xc=0x7fff; + } + if (yc < -0x8000) + yc=-0x8000; + if (yc > 0x7fff) + yc=0x7fff; + p->x=xc; + p->y=yc; + return ret; +} + +void +transform_reverse(struct transformation *t, struct point *p, struct coord *c) +{ + int xc,yc; + xc=p->x; + yc=p->y; + xc-=t->width/2; + yc-=t->height/2; + xc=xc*t->scale/16; + yc=-yc*t->scale/16; + if (t->angle) { + int xcn, ycn; + xcn=xc*t->cos_val+yc*t->sin_val; + ycn=-xc*t->sin_val+yc*t->cos_val; + xc=xcn; + yc=ycn; + } + c->x=t->center.x+xc; + c->y=t->center.y+yc; +} + + +static int +min4(int v1,int v2, int v3, int v4) +{ + int res=v1; + if (v2 < res) + res=v2; + if (v3 < res) + res=v3; + if (v4 < res) + res=v4; + return res; +} + +static int +max4(int v1,int v2, int v3, int v4) +{ + int res=v1; + if (v2 > res) + res=v2; + if (v3 > res) + res=v3; + if (v4 > res) + res=v4; + return res; +} + +void +transform_set_angle(struct transformation *t,int angle) +{ + t->angle=angle; + t->cos_val=cos(M_PI*t->angle/180); + t->sin_val=sin(M_PI*t->angle/180); +} + +void +transform_setup(struct transformation *t, int x, int y, int scale, int angle) +{ + t->center.x=x; + t->center.y=y; + t->scale=scale; + transform_set_angle(t, angle); +} + +void +transform_setup_source_rect_limit(struct transformation *t, struct coord *center, int limit) +{ + t->center=*center; + t->scale=1; + t->angle=0; + t->rect[0].x=center->x-limit; + t->rect[1].x=center->x+limit; + t->rect[1].y=center->y-limit; + t->rect[0].y=center->y+limit; +} + +void +transform_setup_source_rect(struct transformation *t) +{ + int i; + struct coord screen[4]; + struct point screen_pnt[4]; + + screen_pnt[0].x=0; + screen_pnt[0].y=0; + screen_pnt[1].x=t->width; + screen_pnt[1].y=0; + screen_pnt[2].x=0; + screen_pnt[2].y=t->height; + screen_pnt[3].x=t->width; + screen_pnt[3].y=t->height; + for (i = 0 ; i < 4 ; i++) { + transform_reverse(t, &screen_pnt[i], &screen[i]); + } + t->rect[0].x=min4(screen[0].x,screen[1].x,screen[2].x,screen[3].x); + t->rect[1].x=max4(screen[0].x,screen[1].x,screen[2].x,screen[3].x); + t->rect[1].y=min4(screen[0].y,screen[1].y,screen[2].y,screen[3].y); + t->rect[0].y=max4(screen[0].y,screen[1].y,screen[2].y,screen[3].y); +} + +int +transform_get_scale(struct transformation *t) +{ + return t->scale/16; +} + +void +transform_lng_lat(struct coord *c, struct coord_geo *g) +{ + g->lng=c->x/6371000.0/M_PI*180; + g->lat=atan(exp(c->y/6371000.0))/M_PI*360-90; +#if 0 + printf("y=%d vs %f\n", c->y, log(tan(M_PI_4+*lat*M_PI/360))*6371020.0); +#endif +} + +void +transform_geo_text(struct coord_geo *g, char *buffer) +{ + double lng=g->lng; + double lat=g->lat; + char lng_c='E'; + char lat_c='N'; + + if (lng < 0) { + lng=-lng; + lng_c='W'; + } + if (lat < 0) { + lat=-lat; + lat_c='S'; + } + + sprintf(buffer,"%02.0f%07.4f%c %03.0f%07.4f%c", floor(lat), fmod(lat*60,60), lat_c, floor(lng), fmod(lng*60,60), lng_c); + +} + +void +transform_mercator(double *lng, double *lat, struct coord *c) +{ + c->x=*lng*6371000.0*M_PI/180; + c->y=log(tan(M_PI_4+*lat*M_PI/360))*6371000.0; +} + +double +transform_scale(int y) +{ + struct coord c; + struct coord_geo g; + c.x=0; + c.y=y; + transform_lng_lat(&c, &g); + return 1/cos(g.lat/180*M_PI); +} + +double +transform_distance(struct coord *c1, struct coord *c2) +{ + double dx,dy,scale=transform_scale((c1->y+c2->y)/2); + dx=c1->x-c2->x; + dy=c1->y-c2->y; + return sqrt(dx*dx+dy*dy)/scale; +} + +int +transform_distance_sq(struct coord *c1, struct coord *c2) +{ + int dx=c1->x-c2->x; + int dy=c1->y-c2->y; + + if (dx > 32767 || dy > 32767 || dx < -32767 || dy < -32767) + return INT_MAX; + else + return dx*dx+dy*dy; +} + +int +transform_distance_line_sq(struct coord *l0, struct coord *l1, struct coord *ref, struct coord *lpnt) +{ + int vx,vy,wx,wy; + int c1,c2; + struct coord l; + + vx=l1->x-l0->x; + vy=l1->y-l0->y; + wx=ref->x-l0->x; + wy=ref->y-l0->y; + + c1=vx*wx+vy*wy; + if ( c1 <= 0 ) { + if (lpnt) + *lpnt=*l0; + return transform_distance_sq(l0, ref); + } + c2=vx*vx+vy*vy; + if ( c2 <= c1 ) { + if (lpnt) + *lpnt=*l1; + return transform_distance_sq(l1, ref); + } + + l.x=l0->x+vx*c1/c2; + l.y=l0->y+vy*c1/c2; + if (lpnt) + *lpnt=l; + return transform_distance_sq(&l, ref); +} + + +void +transform_print_deg(double deg) +{ + printf("%2.0f:%2.0f:%2.4f", floor(deg), fmod(deg*60,60), fmod(deg*3600,60)); +} + +int +is_visible(struct transformation *t, struct coord *c) +{ + struct coord *r=t->rect; + + assert(c[0].x <= c[1].x); + assert(c[0].y >= c[1].y); + assert(r[0].x <= r[1].x); + assert(r[0].y >= r[1].y); + if (c[0].x > r[1].x) + return 0; + if (c[1].x < r[0].x) + return 0; + if (c[0].y < r[1].y) + return 0; + if (c[1].y > r[0].y) + return 0; + return 1; +} + +int +is_point_visible(struct transformation *t, struct coord *c) +{ + struct coord *r=t->rect; + + assert(r[0].x <= r[1].x); + assert(r[0].y >= r[1].y); + if (c->x > r[1].x) + return 0; + if (c->x < r[0].x) + return 0; + if (c->y < r[1].y) + return 0; + if (c->y > r[0].y) + return 0; + return 1; +} + + +int +is_too_small(struct transformation *t, struct coord *c, int limit) +{ + return 0; + if ((c[1].x-c[0].x) < limit*t->scale/16) { + return 1; + } + if ((c[0].y-c[1].y) < limit*t->scale/16) { + return 1; + } + return 0; +} + +/* +Note: there are many mathematically equivalent ways to express these formulas. As usual, not all of them are computationally equivalent. + +L = latitude in radians (positive north) +Lo = longitude in radians (positive east) +E = easting (meters) +N = northing (meters) + +For the sphere + +E = r Lo +N = r ln [ tan (pi/4 + L/2) ] + +where + +r = radius of the sphere (meters) +ln() is the natural logarithm + +For the ellipsoid + +E = a Lo +N = a * ln ( tan (pi/4 + L/2) * ( (1 - e * sin (L)) / (1 + e * sin (L))) ** (e/2) ) + + + e + - + pi L 1 - e sin(L) 2 + = a ln( tan( ---- + ---) (--------------) ) + 4 2 1 + e sin(L) + + +where + +a = the length of the semi-major axis of the ellipsoid (meters) +e = the first eccentricity of the ellipsoid + + +*/ diff --git a/transform.h b/transform.h new file mode 100644 index 00000000..fe0a0f23 --- /dev/null +++ b/transform.h @@ -0,0 +1,37 @@ +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include "point.h" + +struct transformation { + int width; /* Height of destination rectangle */ + int height; /* Width of destination rectangle */ + long scale; /* Scale factor */ + int angle; /* Rotation angle */ + double cos_val,sin_val; /* cos and sin of rotation angle */ + struct coord rect[2]; /* Source rectangle */ + struct coord center; /* Center of source rectangle */ +}; + +int transform(struct transformation *t, struct coord *c, struct point *p); +int is_visible(struct transformation *t, struct coord *c); +int is_too_small(struct transformation *t, struct coord *c, int limit); +void transform_lng_lat(struct coord *c, struct coord_geo *g); +void transform_reverse(struct transformation *t, struct point *p, struct coord *c); +void transform_print_deg(double deg); +double transform_scale(int y); +double transform_distance(struct coord *c1, struct coord *c2); +int transform_distance_sq(struct coord *c1, struct coord *c2); +int transform_distance_line_sq(struct coord *l0, struct coord *l1, struct coord *ref, struct coord *lpnt); + +void transform_mercator(double *lng, double *lat, struct coord *c); +int is_point_visible(struct transformation *t, struct coord *c); +int transform_get_scale(struct transformation *t); +void transform_setup_source_rect(struct transformation *t); +void transform_set_angle(struct transformation *t,int angle); +void transform_setup(struct transformation *t, int x, int y, int scale, int angle); +void transform_setup_source_rect_limit(struct transformation *t, struct coord *center, int limit); +void transform_geo_text(struct coord_geo *g, char *buffer); + + +#endif @@ -0,0 +1,320 @@ +#include <stdio.h> +#include <string.h> +#include "file.h" +#include "map_data.h" +#include "data.h" +#include "tree.h" + +struct tree_hdr { + unsigned int addr; + unsigned int size; + unsigned int low; +}; + +struct tree_hdr_h { + unsigned int addr; + unsigned int size; +}; + +struct tree_leaf_h { + unsigned int lower; + unsigned int higher; + unsigned int match; + unsigned int value; +}; + +struct tree_hdr_v { + unsigned int count; + unsigned int next; + unsigned int unknown; +}; + +struct tree_leaf_v { + unsigned char key; + int value; +} __attribute__((packed)); + +int +tree_compare_string(unsigned char *s1, unsigned char **s2_ptr) +{ + unsigned char *s2=*s2_ptr; + char s1_exp, s2_exp; + *s2_ptr+=strlen(s2)+1; + for (;;) { + s1_exp=*s1++; + s2_exp=*s2++; + if (! s1_exp && ! s2_exp) + return 0; + if (s1_exp == 'A' && *s1 == 'E') { s1_exp='Ä'; s1++; } + if (s1_exp == 'O' && *s1 == 'E') { s1_exp='Ö'; s1++; } + if (s1_exp == 'U' && *s1 == 'E') { s1_exp='Ü'; s1++; } + if (s2_exp == 'A' && *s2 == 'E') { s2_exp='Ä'; s2++; } + if (s2_exp == 'O' && *s2 == 'E') { s2_exp='Ö'; s2++; } + if (s2_exp == 'U' && *s2 == 'E') { s2_exp='Ü'; s2++; } + if (s1_exp > s2_exp) + return 2; + if (s1_exp < s2_exp) + return -2; + } +} + +int +tree_compare_string_partial(unsigned char *s1, unsigned char **s2_ptr) +{ + unsigned char *s2=*s2_ptr; + char s1_exp, s2_exp; + *s2_ptr+=strlen(s2)+1; + for (;;) { + s1_exp=*s1++; + s2_exp=*s2++; + if (! s1_exp && ! s2_exp) + return 0; + if (s1_exp == 'A' && *s1 == 'E') { s1_exp='Ä'; s1++; } + if (s1_exp == 'O' && *s1 == 'E') { s1_exp='Ö'; s1++; } + if (s1_exp == 'U' && *s1 == 'E') { s1_exp='Ü'; s1++; } + if (s2_exp == 'A' && *s2 == 'E') { s2_exp='Ä'; s2++; } + if (s2_exp == 'O' && *s2 == 'E') { s2_exp='Ö'; s2++; } + if (s2_exp == 'U' && *s2 == 'E') { s2_exp='Ü'; s2++; } + if (! s1_exp) + return -1; + if (s1_exp > s2_exp) + return 2; + if (s1_exp < s2_exp) + return -2; + } +} + + +int +tree_search_h(struct file *file, unsigned int search) +{ + unsigned char *p=file->begin,*end; + int last,i=0,debug=0; + struct tree_hdr_h *thdr; + struct tree_leaf_h *tleaf; + + if (debug) { + printf("tree_search_h\n"); + } + while (i++ < 1000) { + thdr=(struct tree_hdr_h *)p; + p+=sizeof(*thdr); + end=p+thdr->size; + if (debug) { + printf("@0x%x\n", p-file->begin); + } + last=0; + while (p < end) { + tleaf=(struct tree_leaf_h *)p; + p+=sizeof(*tleaf); + if (debug) { + printf("low:0x%x high:0x%x match:0x%x val:0x%x search:0x%x\n", tleaf->lower, tleaf->higher, tleaf->match, tleaf->value, search); + } + if (tleaf->value == search) + return tleaf->match; + if (tleaf->value > search) { + if (tleaf->lower) + last=tleaf->lower; + break; + } + last=tleaf->higher; + } + if (! last || last == -1) + return 0; + p=file->begin+last; + } + return 0; +} + +int +tree_search_v(struct file *file, int offset, int search) +{ + unsigned char *p=file->begin+offset; + int i=0,count,debug=0; + struct tree_hdr_v *thdr; + struct tree_leaf_v *tleaf; + while (i++ < 1000) { + thdr=(struct tree_hdr_v *)p; + p+=sizeof(*thdr); + count=thdr->count; + while (count--) { + tleaf=(struct tree_leaf_v *)p; + p+=sizeof(*tleaf); + if (debug) + printf("tree_search_v: 0x%x 0x%x\n", tleaf->key, search); + if (tleaf->key == search) + return tleaf->value; + } + if (! thdr->next) + break; + p=file->begin+thdr->next; + } + return 0; + +} + +/* return values */ +/* 0=Next */ +/* -2=Too low */ +/* 1=Abort */ +/* 2=Too high */ + +int +tree_search(int version, struct file *file, unsigned char *p, int (*tree_func)(int version, int leaf, unsigned char **, struct map_data *mdat, void *), struct map_data *mdat, void *data, int higher) +{ + unsigned char *end,*psav; + struct tree_hdr *thdr; + int res=1,low; + int high; + int debug=0; + int leaf=0; + int retry=0; + + if (debug) + printf("version %d\n", version); + + thdr=(struct tree_hdr *)p; + p+=sizeof(*thdr); + low=thdr->low; + end=p+thdr->size; + if (debug) + printf("Header: offset 0x%x size %d low 0x%x\n", thdr->addr, thdr->size, thdr->low); + if (higher == -1) + leaf=-1; + if (higher == 1 && low != -1) { + if (debug) + printf("calling first higher tree 0x%x\n",low); + res=tree_search(version,file,low+file->begin,tree_func,mdat,data,1); + if (debug) + printf("returning from first higher tree res=%d\n", res); + } + while (p < end) { + psav=p; + high=get_long(&p); + if (high == -1) + leaf=1; + res=tree_func(version, leaf, &p, mdat, data); + leaf=0; + if (debug) + printf("result: %d high 0x%x\n", res, high); + if (res == 1) + return res; + if (res < 0) { + if (debug) + printf("calling lower tree 0x%x\n",low); + if (low != -1) { + res=tree_search(version,file,low+file->begin,tree_func,mdat,data,0); + if (debug) + printf("returning from lower tree res=%d\n", res); + if (! res && !retry++ ) { + if (debug) + printf("retrying current leaf\n"); + p=psav; + continue; + } + low=-1; + if (res < 0) + break; + } + else + break; + } + retry=0; + if (! res && high != -1) { + if (debug) + printf("high=0x%x\n", high); + if (debug) + printf("calling higher tree 0x%x\n",high); + res=tree_search(version,file,high+file->begin,tree_func,mdat,data,1); + if (debug) + printf("returning from higer tree res=%d\n", res); + low=-1; + } else { + low=high; + } + } + if (low != -1) + res=tree_search(version,file,low+file->begin,tree_func,mdat,data,0); + + return res; +} + +int +tree_search_map(struct map_data *mdat, int map, char *ext, + int (*tree_func)(int, int, unsigned char **, struct map_data *mdat, void *), void *data) + +{ + struct file *f_dat,*f_idx; + char filename[4096]; + int len, version, ret; + unsigned char *p; + int debug=0; + + while (mdat) { + f_dat=mdat->file[map]; + strcpy(filename, f_dat->name); + len=strlen(filename); + strcpy(filename+len-3,ext); + if (debug) + printf("tree_search_map: filename='%s'\n", filename); + f_idx=file_create(filename); + version=1; + p=f_idx->begin; + if (!strncmp(p+4,"RootBlock",9)) { + p+=0x1000; + version=2; + } + ret=tree_search(version, f_idx, p, tree_func, mdat, data, -1); + if (debug) + printf("tree_search_map: ret=%d\n", ret); + file_destroy(f_idx); + if (ret == 1) + return 1; + mdat=mdat->next; + } + return 0; +} + +struct tree_search_hv { + struct map_data *mdat; + struct file *f_idx_h; + struct file *f_idx_v; + struct tree_search_hv *next; +}; + +int +tree_search_hv_map(struct map_data *mdat, int map, unsigned int search1, unsigned int search2, int *result, struct map_data **mdat_result) + +{ + struct file *f_dat,*f_idx_h, *f_idx_v; + char filename[4096]; + int h,len,ret=0; + int debug=0; + + while (mdat && !ret) { + f_dat=mdat->file[map]; + strcpy(filename, f_dat->name); + len=strlen(filename); + strcpy(filename+len-3,"h1"); + f_idx_h=file_create(filename); + strcpy(filename+len-3,"v1"); + f_idx_v=file_create(filename); + h=tree_search_h(f_idx_h, search1); + if (h) { + ret=tree_search_v(f_idx_v, h, search2); + if (ret) { + if (debug) + printf("result 0x%x\n", ret); + *result=ret; + *mdat_result=mdat; + file_destroy(f_idx_v); + file_destroy(f_idx_h); + return 0; + } + } + file_destroy(f_idx_v); + file_destroy(f_idx_h); + mdat=mdat->next; + } + return 1; +} @@ -0,0 +1,13 @@ +struct block_offset { + unsigned short offset; + unsigned short block; +}; + + +int tree_compare_string(unsigned char *s1, unsigned char **s2); +int tree_compare_string_partial(unsigned char *s1, unsigned char **s2); +#if 0 +int tree_search(struct file *file, unsigned char *search, int (*tree_func)(int, unsigned char *, unsigned char **, struct map_data *, void *), struct map_data *mdat, void *data2); +#endif +int tree_search_map(struct map_data *mdat, int map, char *ext, int (*tree_func)(int, int, unsigned char **, struct map_data *, void *), void *data); +int tree_search_hv_map(struct map_data *mdat, int map, unsigned int search1, unsigned int search2, int *result, struct map_data **mdat_result); @@ -0,0 +1,15 @@ +#include <glib/gmacros.h> +#include <glib/gtypes.h> +#include <glib.h> + +int tst(void) +{ + unsigned short t1=20; + unsigned short t2=10; + return t2-t1; +} + +int main(int argc, char **argv) +{ + printf("res=%d\n", tst()); +} @@ -0,0 +1,18 @@ +#include <ctype.h> + +void +strtoupper(unsigned char *dest, unsigned char *src) +{ + while (*src) + *dest++=toupper(*src++); + *dest='\0'; +} + +void +strtolower(unsigned char *dest, unsigned char *src) +{ + while (*src) + *dest++=tolower(*src++); + *dest='\0'; +} + @@ -0,0 +1,4 @@ +#include <ctype.h> + +void strtoupper(unsigned char *dest, unsigned char *src); +void strtolower(unsigned char *dest, unsigned char *src); diff --git a/vehicle.c b/vehicle.c new file mode 100644 index 00000000..80eda88c --- /dev/null +++ b/vehicle.c @@ -0,0 +1,216 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <math.h> +#include <glib.h> +#include "coord.h" +#include "transform.h" +#include "statusbar.h" +#include "vehicle.h" + +struct vehicle { + GIOChannel *iochan; + int timer_count; + int qual; + int sats; + double lat,lng; + double height; + double dir,speed; + struct coord current_pos; + struct coord_d curr; + struct coord_d delta; + + double speed_last; +}; + +void (*callback_func)(); +void *callback_data; + +int +vehicle_timer(gpointer t) +{ + struct vehicle *this=t; + if (this->timer_count++ < 10) { + this->curr.x+=this->delta.x; + this->curr.y+=this->delta.y; + this->current_pos.x=this->curr.x; + this->current_pos.y=this->curr.y; + if (callback_func) + (*callback_func)(callback_data); + } + return TRUE; +} + +struct coord * +vehicle_pos_get(void *t) +{ + struct vehicle *this=t; + + return &this->current_pos; +} + +double * +vehicle_speed_get(void *t) +{ + struct vehicle *this=t; + + return &this->speed; +} + +double * +vehicle_dir_get(void *t) +{ + struct vehicle *this=t; + + return &this->dir; +} + +void +vehicle_set_position(void *t, struct coord *pos) +{ + struct vehicle *this=t; + + this->current_pos=*pos; + this->curr.x=this->current_pos.x; + this->curr.y=this->current_pos.y; + this->delta.x=0; + this->delta.y=0; + if (callback_func) + (*callback_func)(callback_data); +} + +void +vehicle_parse_gps(struct vehicle *this, char *buffer) +{ + char *p,*item[16]; + double lat,lng,scale,speed; + int i,debug=0; + + if (debug) { + printf("GPS %s\n", buffer); + } + if (!strncmp(buffer,"$GPGGA",6)) { + /* $GPGGA,184424.505,4924.2811,N,01107.8846,E,1,05,2.5,408.6,M,,,,0000*0C + UTC of Fix,Latitude,N/S,Longitude,E/W,Quality,Satelites,HDOP,Altitude,"M" + */ + i=0; + p=buffer; + while (i < 16) { + item[i++]=p; + while (*p && *p != ',') + p++; + if (! *p) break; + *p++='\0'; + } + + sscanf(item[2],"%lf",&lat); + this->lat=floor(lat/100); + lat-=this->lat*100; + this->lat+=lat/60; + + sscanf(item[4],"%lf",&lng); + this->lng=floor(lng/100); + lng-=this->lng*100; + this->lng+=lng/60; + + sscanf(item[6],"%d",&this->qual); + sscanf(item[7],"%d",&this->sats); + sscanf(item[9],"%lf",&this->height); + + transform_mercator(&this->lng, &this->lat, &this->current_pos); + + this->curr.x=this->current_pos.x; + this->curr.y=this->current_pos.y; + this->timer_count=0; + if (callback_func) + (*callback_func)(callback_data); + } + if (!strncmp(buffer,"$GPVTG",6)) { + /* $GPVTG,143.58,T,,M,0.26,N,0.5,K*6A + Course Over Ground Degrees True,"T",Course Over Ground Degrees Magnetic,"M", + Speed in Knots,"N","Speed in KM/H","K",*CHECKSUM */ + + i=0; + p=buffer; + while (i < 16) { + item[i++]=p; + while (*p && *p != ',') + p++; + if (! *p) break; + *p++='\0'; + } + sscanf(item[1],"%lf",&this->dir); + sscanf(item[7],"%lf",&this->speed); + + scale=transform_scale(this->current_pos.y); + speed=this->speed+(this->speed-this->speed_last)/2; + this->delta.x=sin(M_PI*this->dir/180)*speed*scale/36; + this->delta.y=cos(M_PI*this->dir/180)*speed*scale/36; + this->speed_last=this->speed; + } +} + +gboolean +vehicle_track(GIOChannel *iochan, GIOCondition condition, gpointer t) +{ + struct vehicle *this=t; + GError *error=NULL; + char buffer[4096]; + char *str,*tok; + int size; + + if (condition == G_IO_IN) { + g_io_channel_read_chars(iochan, buffer, 4096, &size, &error); + buffer[size]='\0'; + str=buffer; + while ((tok=strtok(str, "\n"))) { + str=NULL; + vehicle_parse_gps(this, tok); + } + return TRUE; + } + return FALSE; +} + +void * +vehicle_new(char *file) +{ + struct vehicle *this; + GError *error=NULL; + int fd; + + this=g_new(struct vehicle,1); + fd=open(file,O_RDONLY|O_NDELAY); + this->iochan=g_io_channel_unix_new(fd); + g_io_channel_set_encoding(this->iochan, NULL, &error); + g_io_add_watch(this->iochan, G_IO_IN|G_IO_ERR|G_IO_HUP, vehicle_track, this); +#if 0 + g_timeout_add(100, vehicle_timer, this); +#endif + this->current_pos.x=0x130000; + this->current_pos.y=0x600000; + + return this; +} + +void +vehicle_callback(void (*func)(), void *data) +{ + callback_func=func; + callback_data=data; +} + +int +vehicle_destroy(void *t) +{ + struct vehicle *this=t; + GError *error=NULL; + + + g_io_channel_shutdown(this->iochan,0,&error); + g_free(this); + + return 0; +} diff --git a/vehicle.h b/vehicle.h new file mode 100644 index 00000000..10101c24 --- /dev/null +++ b/vehicle.h @@ -0,0 +1,6 @@ +struct coord *vehicle_pos_get(void *); +double *vehicle_dir_get(void *); +double *vehicle_speed_get(void *); +void vehicle_callback(void (*func)(),void *data); +void vehicle_set_position(void *, struct coord *); +void *vehicle_new(char *file); |