summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>2005-12-02 10:41:56 +0000
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>2005-12-02 10:41:56 +0000
commitba8c7a19f05f6491eb7f191d44a5af8506f619cf (patch)
tree84264aa047b56e5db281be72b470c133b6f4f6f9
downloadnavit-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
-rw-r--r--block.c209
-rw-r--r--block.h30
-rw-r--r--command.c143
-rw-r--r--command.h1
-rw-r--r--compass.c122
-rw-r--r--compass.h2
-rw-r--r--container.h69
-rw-r--r--coord.c9
-rw-r--r--coord.h21
-rw-r--r--country.c94
-rw-r--r--country.h12
-rw-r--r--cursor.c196
-rw-r--r--cursor.h5
-rw-r--r--data.h39
-rw-r--r--data_window.c104
-rw-r--r--data_window.h8
-rw-r--r--data_window_int.h7
-rw-r--r--destination.c622
-rw-r--r--destination.h11
-rw-r--r--display.c266
-rw-r--r--display.h24
-rw-r--r--draw_info.h5
-rw-r--r--fib-1.1/Makefile.in116
-rw-r--r--fib-1.1/README26
-rwxr-xr-xfib-1.1/configure1045
-rw-r--r--fib-1.1/configure.in17
-rw-r--r--fib-1.1/fh_extractmin.397
-rw-r--r--fib-1.1/fh_makeheap.317
-rw-r--r--fib-1.1/fh_makekeyheap.384
-rw-r--r--fib-1.1/fib.c696
-rw-r--r--fib-1.1/fib.h64
-rw-r--r--fib-1.1/fibpriv.h98
-rw-r--r--fib-1.1/fibtest.c80
-rw-r--r--fib-1.1/fibtest.out37
-rw-r--r--fib-1.1/fibtest2.c69
-rw-r--r--fib-1.1/fibtest2.out37
-rw-r--r--fib-1.1/tt.c64
-rw-r--r--fib-1.1/tt.out29
-rw-r--r--fib-1.1/use.c126
-rw-r--r--file.c124
-rw-r--r--file.h18
-rw-r--r--graphics.c401
-rw-r--r--graphics.h48
-rw-r--r--graphics/gtk_drawing_area/graphics_gtk_drawing_area.c607
-rw-r--r--graphics/gtk_gl_ext/graphics_gtk_gl_ext.c333
-rw-r--r--gtkext.h1
-rw-r--r--gui/gtk/gtkeyboard.c2353
-rw-r--r--gui/gtk/gtkeyboard.h3
-rw-r--r--gui/gtk/gui_gtk.h4
-rw-r--r--gui/gtk/gui_gtk_menu.c430
-rw-r--r--gui/gtk/gui_gtk_statusbar.c115
-rw-r--r--gui/gtk/gui_gtk_toolbar.c349
-rw-r--r--gui/gtk/gui_gtk_window.c67
-rw-r--r--locations.txt1
-rw-r--r--log.c88
-rw-r--r--log.h2
-rw-r--r--main.c80
-rw-r--r--main.h1
-rw-r--r--map-common.c442
-rw-r--r--map-share.h2
-rw-r--r--map-skelimpl.c286
-rw-r--r--map-skels.c184
-rw-r--r--map-srv.c262
-rw-r--r--map-stubs.c135
-rw-r--r--map.h341
-rw-r--r--map.idl25
-rw-r--r--map.ior1
-rw-r--r--map_data.c112
-rw-r--r--map_data.h30
-rw-r--r--mapclient.c103
-rw-r--r--menu.c35
-rw-r--r--menu.h8
-rw-r--r--navigation.c249
-rw-r--r--navigation.h1
-rw-r--r--param.c46
-rw-r--r--param.h9
-rw-r--r--phrase.c25
-rw-r--r--phrase.h2
-rw-r--r--plugin.c21
-rw-r--r--plugin.h56
-rw-r--r--plugins/poi_geodownload/libmdb/backend.c301
-rw-r--r--plugins/poi_geodownload/libmdb/catalog.c138
-rw-r--r--plugins/poi_geodownload/libmdb/data.c856
-rw-r--r--plugins/poi_geodownload/libmdb/dump.c39
-rw-r--r--plugins/poi_geodownload/libmdb/file.c376
-rw-r--r--plugins/poi_geodownload/libmdb/iconv.c63
-rw-r--r--plugins/poi_geodownload/libmdb/include/mdbtools.h536
-rw-r--r--plugins/poi_geodownload/libmdb/index.c905
-rw-r--r--plugins/poi_geodownload/libmdb/kkd.c149
-rw-r--r--plugins/poi_geodownload/libmdb/like.c78
-rw-r--r--plugins/poi_geodownload/libmdb/map.c133
-rw-r--r--plugins/poi_geodownload/libmdb/mem.c50
-rw-r--r--plugins/poi_geodownload/libmdb/money.c139
-rw-r--r--plugins/poi_geodownload/libmdb/options.c86
-rw-r--r--plugins/poi_geodownload/libmdb/props.c127
-rw-r--r--plugins/poi_geodownload/libmdb/sargs.c273
-rw-r--r--plugins/poi_geodownload/libmdb/stats.c74
-rw-r--r--plugins/poi_geodownload/libmdb/table.c368
-rw-r--r--plugins/poi_geodownload/libmdb/worktable.c99
-rw-r--r--plugins/poi_geodownload/libmdb/write.c878
-rw-r--r--plugins/poi_geodownload/poi.c474
-rw-r--r--point.h9
-rw-r--r--poly.c109
-rw-r--r--poly.h13
-rw-r--r--popup.c306
-rw-r--r--popup.h22
-rw-r--r--profile.c18
-rw-r--r--route.c1053
-rw-r--r--route.h48
-rwxr-xr-xscript/get_map5
-rwxr-xr-xscript/gps_emu19
-rwxr-xr-xscript/gps_emu240
-rwxr-xr-xscript/gps_emu312
-rw-r--r--search.c442
-rw-r--r--search.h30
-rw-r--r--speech.c61
-rw-r--r--speech.h5
-rw-r--r--statusbar.h10
-rw-r--r--street.c455
-rw-r--r--street.h53
-rw-r--r--street_data.h60
-rw-r--r--street_name.c260
-rw-r--r--street_name.h51
-rw-r--r--toolbar.h3
-rw-r--r--town.c260
-rw-r--r--town.h27
-rw-r--r--transform.c363
-rw-r--r--transform.h37
-rw-r--r--tree.c320
-rw-r--r--tree.h13
-rw-r--r--tst.c15
-rw-r--r--util.c18
-rw-r--r--util.h4
-rw-r--r--vehicle.c216
-rw-r--r--vehicle.h6
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, &param, &count);
+ param_add_hex("Addr", (unsigned char *)blk_inf->block-blk_inf->file->begin, &param, &count);
+ param_add_hex("Blocks", blk_inf->block->blocks, &param, &count);
+ param_add_hex("Size", blk_inf->block->size, &param, &count);
+ param_add_hex("Next", blk_inf->block->next, &param, &count);
+ param_add_hex_sig("L", blk_inf->block->c[0].x, &param, &count);
+ param_add_hex_sig("T", blk_inf->block->c[0].y, &param, &count);
+ param_add_hex_sig("R", blk_inf->block->c[1].x, &param, &count);
+ param_add_hex_sig("B", blk_inf->block->c[1].y, &param, &count);
+ param_add_hex("W", blk_inf->block->c[1].x-blk_inf->block->c[0].x, &param, &count);
+ param_add_hex("H", blk_inf->block->c[0].y-blk_inf->block->c[1].y, &param, &count);
+ param_add_hex("Count", blk_inf->block->count, &param, &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);
diff --git a/data.h b/data.h
new file mode 100644
index 00000000..1f054333
--- /dev/null
+++ b/data.h
@@ -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;
+}
diff --git a/file.c b/file.c
new file mode 100644
index 00000000..2389d8a7
--- /dev/null
+++ b/file.c
@@ -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, &param, &count);
+ param_add_hex("Size", file->size, &param, &count);
+ return i-count;
+}
diff --git a/file.h b/file.h
new file mode 100644
index 00000000..4dedb894
--- /dev/null
+++ b/file.h
@@ -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
diff --git a/log.c b/log.c
new file mode 100644
index 00000000..c6995361
--- /dev/null
+++ b/log.c
@@ -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);
+}
diff --git a/log.h b/log.h
new file mode 100644
index 00000000..2bf04429
--- /dev/null
+++ b/log.h
@@ -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);
diff --git a/main.c b/main.c
new file mode 100644
index 00000000..e2d23554
--- /dev/null
+++ b/main.c
@@ -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;
+}
+
+
diff --git a/main.h b/main.h
new file mode 100644
index 00000000..fbf9d73d
--- /dev/null
+++ b/main.h
@@ -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;
+}
diff --git a/map.h b/map.h
new file mode 100644
index 00000000..2ffa914b
--- /dev/null
+++ b/map.h
@@ -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;
+}
diff --git a/menu.c b/menu.c
new file mode 100644
index 00000000..e694f82a
--- /dev/null
+++ b/menu.c
@@ -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);
+}
diff --git a/menu.h b/menu.h
new file mode 100644
index 00000000..51b24729
--- /dev/null
+++ b/menu.h
@@ -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
diff --git a/poly.c b/poly.c
new file mode 100644
index 00000000..954e7fb2
--- /dev/null
+++ b/poly.c
@@ -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, &param, &count);
+ poly_get_hdr(&p, &poly_hdr);
+ param_add_string("Name", poly_hdr.name, &param, &count);
+ param_add_hex("L", poly_hdr.c[0].x, &param, &count);
+ param_add_hex("T", poly_hdr.c[0].y, &param, &count);
+ param_add_hex("R", poly_hdr.c[1].x, &param, &count);
+ param_add_hex("B", poly_hdr.c[1].y, &param, &count);
+ param_add_hex("X", poly_hdr.c[2].x, &param, &count);
+ param_add_hex("Y", poly_hdr.c[2].y, &param, &count);
+ param_add_hex("Order", poly_hdr.order, &param, &count);
+ param_add_hex("Type", poly_hdr.type, &param, &count);
+ param_add_hex("Polys", poly_hdr.polys, &param, &count);
+ return i-count;
+}
diff --git a/poly.h b/poly.h
new file mode 100644
index 00000000..8d735f5b
--- /dev/null
+++ b/poly.h
@@ -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, &param, &count);
+ param_add_hex("Order", type->order, &param, &count);
+ param_add_hex("Country", type->country, &param, &count);
+
+ param_add_hex("Addr", (unsigned char *)str-seg->blk_inf.file->begin, &param, &count);
+ param_add_hex_sig("Seg-Id", str->segid, &param, &count);
+ param_add_hex("Limit", str->limit, &param, &count);
+ param_add_hex("Unknown2", str->unknown2, &param, &count);
+ param_add_hex("Unknown3", str->unknown3, &param, &count);
+ param_add_hex("Type", str->type, &param, &count);
+ param_add_hex("Name-Id", str->nameid, &param, &count);
+ if (str->segid) {
+ street_name_get_by_id(&name, seg->blk_inf.mdata, str->nameid);
+
+ param_add_hex("Len", name.len, &param, &count);
+ param_add_hex("Country", name.country, &param, &count);
+ param_add_hex_sig("TownAssoc", name.townassoc, &param, &count);
+ printf("TownAssoc 0x%lx\n", name.townassoc+str->segid);
+ param_add_string("Name1", name.name1, &param, &count);
+ param_add_string("Name2", name.name2, &param, &count);
+ param_add_hex("Segments", name.segment_count, &param, &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, &param, &count);
+ }
+ param_add_hex("Len", name.aux_len, &param, &count);
+ while (street_name_get_info(&name_info, &name)) {
+ param_add_hex("Len", name_info.len, &param, &count);
+ param_add_hex("Tag", name_info.tag, &param, &count);
+ param_add_hex("Dist", name_info.dist, &param, &count);
+ param_add_hex("Country", name_info.country, &param, &count);
+ param_add_hex("X", name_info.c->x, &param, &count);
+ param_add_hex("Y", name_info.c->y, &param, &count);
+ param_add_dec("First", name_info.first, &param, &count);
+ param_add_dec("Last", name_info.last, &param, &count);
+ param_add_hex("Segments", name_info.segment_count, &param, &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", "", &param, &count);
+ param_add_string("Country", "", &param, &count);
+ param_add_string("TownAssoc", "", &param, &count);
+ param_add_string("Name1", "", &param, &count);
+ param_add_string("Name2", "", &param, &count);
+ param_add_string("Segments", "", &param, &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, &param, &count);
+ param_add_hex("Unknown1", str->unknown1, &param, &count);
+ param_add_hex("Segid1", str->segid1, &param, &count);
+ param_add_hex("Country1", str->country1, &param, &count);
+ param_add_hex("Segid2", str->segid2, &param, &count);
+ param_add_hex("Country2", str->country2, &param, &count);
+ param_add_hex("Unknown5", str->unknown5, &param, &count);
+ param_add_hex("X", str->c.x, &param, &count);
+ param_add_hex("Y", str->c.y, &param, &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;
+};
diff --git a/town.c b/town.c
new file mode 100644
index 00000000..2d08427b
--- /dev/null
+++ b/town.c
@@ -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), &param, &count);
+ p=seg->data[0];
+ param_add_hex("Address", p-seg->blk_inf.file->begin, &param, &count);
+ town_get(&town, &p);
+ param_add_hex("ID", town.id, &param, &count);
+ param_add_hex_sig("X", town.c->x, &param, &count);
+ param_add_hex_sig("Y", town.c->y, &param, &count);
+ param_add_string("Name", town.name, &param, &count);
+ param_add_string("District", town.district, &param, &count);
+ param_add_string("PostalCode1", town.postal_code1, &param, &count);
+ param_add_hex("Order", town.order, &param, &count);
+ param_add_hex("Country", town.country, &param, &count);
+ param_add_hex("Type", town.type, &param, &count);
+ param_add_hex("Unknown2", town.unknown2, &param, &count);
+ param_add_hex("Size", town.size, &param, &count);
+ param_add_hex("StreetAssoc", town.street_assoc, &param, &count);
+ param_add_hex("Unknown3", town.unknown3, &param, &count);
+ param_add_string("PostalCode2", town.postal_code2, &param, &count);
+ param_add_hex("Unknown4", town.unknown4, &param, &count);
+
+ return i-count;
+}
diff --git a/town.h b/town.h
new file mode 100644
index 00000000..fce4b6b5
--- /dev/null
+++ b/town.h
@@ -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
diff --git a/tree.c b/tree.c
new file mode 100644
index 00000000..9aacfacc
--- /dev/null
+++ b/tree.c
@@ -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;
+}
diff --git a/tree.h b/tree.h
new file mode 100644
index 00000000..58ff0448
--- /dev/null
+++ b/tree.h
@@ -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);
diff --git a/tst.c b/tst.c
new file mode 100644
index 00000000..16cd8834
--- /dev/null
+++ b/tst.c
@@ -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());
+}
diff --git a/util.c b/util.c
new file mode 100644
index 00000000..b99dfcbd
--- /dev/null
+++ b/util.c
@@ -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';
+}
+
diff --git a/util.h b/util.h
new file mode 100644
index 00000000..5f89adb9
--- /dev/null
+++ b/util.h
@@ -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);