/[zanavi_public1]/navit/navit/bookmarks.c
ZANavi

Contents of /navit/navit/bookmarks.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (11 years, 3 months ago) by zoff99
File MIME type: text/plain
File size: 19737 byte(s)
import files
1 zoff99 2 /**
2     * Navit, a modular navigation system.
3     * Copyright (C) 2005-2010 Navit Team
4     *
5     * This program is free software; you can redistribute it and/or
6     * modify it under the terms of the GNU General Public License
7     * version 2 as published by the Free Software Foundation.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with this program; if not, write to the
16     * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     * Boston, MA 02110-1301, USA.
18     */
19    
20     #include <stdlib.h>
21     #include <glib.h>
22     #include <stdio.h>
23     #include "config.h"
24     #ifdef HAVE_UNISTD_H
25     #include <unistd.h>
26     #endif
27     #include "file.h"
28     #include "debug.h"
29     #include "projection.h"
30     #include "coord.h"
31     #include "transform.h"
32     #include "callback.h"
33     #include "map.h"
34     #include "command.h"
35     #include "bookmarks.h"
36     #include "navit.h"
37     #include "navit_nls.h"
38     #include "util.h"
39    
40     /* FIXME: Move this to support directory */
41     #ifdef _MSC_VER
42     #include <windows.h>
43     static int ftruncate(int fd, __int64 length)
44     {
45     HANDLE fh = (HANDLE)_get_osfhandle(fd);
46     if (!fh || _lseeki64(fd, length, SEEK_SET)) {
47     return -1;
48     }
49     return SetEndOfFile(fh) ? 0 : -1;
50     }
51     #endif /* _MSC_VER */
52    
53     struct bookmarks {
54     //data storage
55     struct map *bookmark;
56     struct map_rect *mr;
57     GHashTable *bookmarks_hash;
58     GList *bookmarks_list;
59     char* bookmark_file;
60     char *working_file;
61     struct bookmark_item_priv* clipboard;
62     struct bookmark_item_priv* root;
63     struct bookmark_item_priv* current;
64    
65     //Refs to other objects
66     struct transformation *trans;
67     struct attr **attrs;
68     struct callback_list *attr_cbl;
69     struct attr *parent;
70     };
71    
72     struct bookmark_item_priv {
73     char *label;
74     enum item_type type;
75     struct pcoord c;
76     GList *children;
77     GList *iter;
78     struct bookmark_item_priv *parent;
79     struct item item;
80     };
81    
82     void bookmarks_move_root(struct bookmarks *this_) {
83     this_->current=this_->root;
84     this_->current->iter=g_list_first(this_->current->children);
85     dbg(2,"Root list have %u entries\n",g_list_length(this_->current->children));
86     return;
87     }
88     void bookmarks_move_up(struct bookmarks *this_) {
89     if (this_->current->parent) {
90     this_->current=this_->current->parent;
91     this_->current->iter=this_->current->children;
92     }
93     return;
94     }
95     int bookmarks_move_down(struct bookmarks *this_,const char* name) {
96     bookmarks_item_rewind(this_);
97     if (this_->current->children==NULL) {
98     return 0;
99     }
100     while (this_->current->iter!=NULL) {
101     struct bookmark_item_priv* data=(struct bookmark_item_priv*)this_->current->iter->data;
102     if (!strcmp(data->label,name)) {
103     this_->current=(struct bookmark_item_priv*)this_->current->iter->data;
104     this_->current->iter=g_list_first(this_->current->children);
105     dbg(2,"%s list have %u entries\n",this_->current->label,g_list_length(this_->current->children));
106     return 1;
107     }
108     this_->current->iter=g_list_next(this_->current->iter);
109     }
110     return 0;
111     }
112    
113     void bookmarks_item_rewind(struct bookmarks* this_) {
114     this_->current->children=g_list_first(this_->current->children);
115     this_->current->iter=this_->current->children;
116     this_->current->iter=this_->current->children;
117     }
118     struct item* bookmarks_get_item(struct bookmarks* this_) {
119     struct item item,*ret;
120     if (this_->current->iter==NULL) {
121     return NULL;
122     }
123    
124     item=((struct bookmark_item_priv*)this_->current->iter->data)->item;
125     this_->current->iter=g_list_next(this_->current->iter);
126    
127     ret = map_rect_get_item_byid(this_->mr, item.id_hi, item.id_lo);
128    
129     return ret;
130     }
131    
132     const char* bookmarks_item_cwd(struct bookmarks* this_) {
133     return this_->current->label;
134     }
135    
136     static void bookmarks_clear_item(struct bookmark_item_priv *b_item) {
137     b_item->children=g_list_first(b_item->children);
138     while(b_item->children) {
139     bookmarks_clear_item((struct bookmark_item_priv*)b_item->children->data);
140     b_item->children=g_list_next(b_item->children);
141     }
142     g_free(b_item->label);
143     g_free(b_item);
144     }
145    
146     static void
147     bookmarks_clear_hash(struct bookmarks *this_) {
148     bookmarks_clear_item(this_->root);
149     g_hash_table_destroy(this_->bookmarks_hash);
150     g_list_free(this_->bookmarks_list);
151     }
152    
153     static void
154     bookmarks_load_hash(struct bookmarks *this_) {
155     struct bookmark_item_priv *b_item;
156     struct item *item;
157     struct attr attr;
158     struct coord c;
159     char *pos,*finder;
160     char *copy_helper;
161    
162     if (this_->mr) {
163     map_rect_destroy(this_->mr);
164     }
165     this_->mr=map_rect_new(this_->bookmark, NULL);
166    
167     this_->bookmarks_hash=g_hash_table_new(g_str_hash, g_str_equal);
168     this_->root=g_new0(struct bookmark_item_priv,1);
169     this_->root->type=type_none;
170     this_->root->parent=NULL;
171     this_->root->children=NULL;
172     bookmarks_move_root(this_);
173    
174     while ((item=map_rect_get_item(this_->mr))) {
175     if (item->type != type_bookmark && item->type != type_bookmark_folder ) continue;
176     if (!item_attr_get(item, attr_path, &attr)) {
177     item_attr_get(item, attr_label, &attr);
178     }
179     item_coord_get(item, &c, 1);
180    
181     b_item=g_new0(struct bookmark_item_priv,1);
182     b_item->c.x=c.x;
183     b_item->c.y=c.y;
184     b_item->label=g_strdup(attr.u.str);
185     b_item->type=item->type;
186     b_item->item=*item;
187    
188     //Prepare position
189     bookmarks_move_root(this_);
190     finder=b_item->label;
191     while ((pos=strchr(finder,'/'))) {
192     *pos=0x00;
193     dbg(1,"Found path entry: %s\n",finder);
194     if (!bookmarks_move_down(this_,finder)) {
195     struct bookmark_item_priv *path_item=g_new0(struct bookmark_item_priv,1);
196     path_item->type=type_bookmark_folder;
197     path_item->parent=this_->current;
198     path_item->children=NULL;
199     path_item->label=g_strdup(finder);
200    
201     this_->current->children=g_list_append(this_->current->children,path_item);
202     this_->current=path_item;
203     g_hash_table_insert(this_->bookmarks_hash,b_item->label,path_item);
204     this_->bookmarks_list=g_list_append(this_->bookmarks_list,path_item);
205     }
206     finder+=strlen(finder)+1;
207     }
208     copy_helper=g_strdup(finder);
209     free(b_item->label);
210     b_item->label=copy_helper;
211     b_item->parent=this_->current;
212    
213     g_hash_table_insert(this_->bookmarks_hash,b_item->label,b_item);
214     this_->bookmarks_list=g_list_append(this_->bookmarks_list,b_item);
215     this_->current->children=g_list_append(this_->current->children,b_item);
216     this_->current->children=g_list_first(this_->current->children);
217     dbg(1,"Added %s to %s and current list now %u long\n",b_item->label,this_->current->label,g_list_length(this_->current->children));
218     }
219     bookmarks_move_root(this_);
220     }
221    
222     struct bookmarks *
223     bookmarks_new(struct attr *parent, struct attr **attrs, struct transformation *trans) {
224     struct bookmarks *this_;
225    
226     if (parent->type!=attr_navit) {
227     return NULL;
228     }
229    
230     this_ = g_new0(struct bookmarks,1);
231     this_->attr_cbl=callback_list_new();
232     this_->parent=parent;
233     //this_->attrs=attr_list_dup(attrs);
234     this_->trans=trans;
235    
236     this_->bookmark_file=g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/bookmark.txt", NULL);
237     this_->working_file=g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/bookmark.txt.tmp", NULL);
238    
239     this_->clipboard=g_new0(struct bookmark_item_priv,1);
240    
241     {
242     //Load map now
243     struct attr type={attr_type, {"textfile"}}, data={attr_data, {this_->bookmark_file}};
244     struct attr *attrs[]={&type, &data, NULL};
245     this_->bookmark=map_new(this_->parent, attrs);
246     if (!this_->bookmark)
247     return NULL;
248     bookmarks_load_hash(this_);
249     }
250    
251     return this_;
252     }
253    
254     void
255     bookmarks_destroy(struct bookmarks *this_) {
256    
257     bookmarks_clear_hash(this_);
258    
259     map_destroy(this_->bookmark);
260     callback_list_destroy(this_->attr_cbl);
261    
262     g_free(this_->bookmark_file);
263     g_free(this_->working_file);
264    
265     g_free(this_->clipboard);
266     g_free(this_);
267     }
268    
269     struct map*
270     bookmarks_get_map(struct bookmarks *this_) {
271     return this_->bookmark;
272     }
273    
274     enum projection bookmarks_get_projection(struct bookmarks *this_){
275     return map_projection(this_->bookmark);
276     }
277     void
278     bookmarks_add_callback(struct bookmarks *this_, struct callback *cb)
279     {
280     callback_list_add(this_->attr_cbl, cb);
281     }
282    
283     static int
284     bookmarks_store_bookmarks_to_file(struct bookmarks *this_, int limit,int replace) {
285     FILE *f;
286     struct bookmark_item_priv *item,*parent_item;
287     char *fullname;
288     const char *prostr;
289     int result;
290     GHashTable *dedup=g_hash_table_new_full(g_str_hash,g_str_equal,g_free,NULL);
291    
292     f=fopen(this_->working_file, replace ? "w+" : "a+");
293     if (f==NULL) {
294     navit_add_message(this_->parent->u.navit,_("Failed to write bookmarks file"));
295     return FALSE;
296     }
297    
298     this_->bookmarks_list=g_list_first(this_->bookmarks_list);
299     while (this_->bookmarks_list) {
300     item=(struct bookmark_item_priv*)this_->bookmarks_list->data;
301    
302     parent_item=item;
303     fullname=g_strdup(item->label);
304     while ((parent_item=parent_item->parent)) {
305     char *pathHelper;
306     if (parent_item->label) {
307     pathHelper=g_strconcat(parent_item->label,"/",fullname,NULL);
308     g_free(fullname);
309     fullname=g_strdup(pathHelper);
310     g_free(pathHelper);
311     dbg(1,"full name: %s\n",fullname);
312     }
313     }
314    
315     if (!g_hash_table_lookup(dedup,fullname)) {
316     g_hash_table_insert(dedup,fullname,fullname);
317     if (item->type == type_bookmark) {
318     prostr = projection_to_name(projection_mg,NULL);
319     if (fprintf(f,"%s%s%s0x%x %s0x%x type=%s label=\"%s\" path=\"%s\"\n",
320     prostr, *prostr ? ":" : "",
321     item->c.x >= 0 ? "":"-", item->c.x >= 0 ? item->c.x : -item->c.x,
322     item->c.y >= 0 ? "":"-", item->c.y >= 0 ? item->c.y : -item->c.y,
323     "bookmark", item->label,fullname)<1) {
324     g_free(fullname);
325     break;
326     }
327     }
328     if (item->type == type_bookmark_folder) {
329     prostr = projection_to_name(projection_mg,NULL);
330     if (fprintf(f,"%s%s%s0x%x %s0x%x type=%s label=\"%s\" path=\"%s\"\n",
331     prostr, *prostr ? ":" : "",
332     "", 0,
333     "", 0,
334     "bookmark_folder", item->label,fullname)<1) {
335     g_free(fullname);
336     break;
337     }
338     }
339     }
340    
341     /* Limit could be zero, so we start decrementing it from zero and never reach 1
342     or it was bigger and we decreased it earlier. So when this counter becomes 1, we know
343     that we have enough entries in bookmarks file */
344     if (limit==1) {
345     break;
346     }
347     limit--;
348    
349     this_->bookmarks_list=g_list_next(this_->bookmarks_list);
350     }
351    
352     fclose(f);
353    
354     g_hash_table_destroy(dedup);
355    
356     if (this_->mr) {
357     map_rect_destroy(this_->mr);
358     this_->mr = 0;
359     }
360    
361     unlink(this_->bookmark_file);
362     result=(rename(this_->working_file,this_->bookmark_file)==0);
363     if (!result)
364     {
365     navit_add_message(this_->parent->u.navit,_("Failed to write bookmarks file"));
366     }
367     return result;
368     }
369    
370     /*
371     * bookmarks_get_destination_file
372     *
373     * returns the name of the file used to store destinations with its
374     * full path
375     *
376     * arg: gboolean create: create the directory where the file is stored
377     * if it does not exist
378     */
379     char*
380     bookmarks_get_destination_file(gboolean create)
381     {
382     return g_strjoin(NULL, navit_get_user_data_directory(create), "/destination.txt", NULL);
383     }
384    
385     /*
386     * bookmarks_get_center_file
387     *
388     * returns the name of the file used to store the center file with its
389     * full path
390     *
391     * arg: gboolean create: create the directory where the file is stored
392     * if it does not exist
393     */
394     char*
395     bookmarks_get_center_file(gboolean create)
396     {
397     return g_strjoin(NULL, navit_get_user_data_directory(create), "/center.txt", NULL);
398     }
399    
400     void
401     bookmarks_set_center_from_file(struct bookmarks *this_, char *file)
402     {
403     FILE *f;
404     char *line = NULL;
405    
406     dbg(0,"enter\n");
407    
408     size_t line_size = 0;
409     enum projection pro;
410     struct coord *center;
411    
412     f = fopen(file, "r");
413     if (! f)
414     return;
415     getline(&line, &line_size, f);
416     fclose(f);
417     if (line) {
418     center = transform_center(this_->trans);
419     pro = transform_get_projection(this_->trans);
420     coord_parse(g_strchomp(line), pro, center);
421     dbg(0,"******** load center from file *********");
422     free(line);
423     }
424     return;
425     }
426    
427     void
428     bookmarks_write_center_to_file(struct bookmarks *this_, char *file)
429     {
430     FILE *f;
431     enum projection pro;
432     struct coord *center;
433    
434     f = fopen(file, "w+");
435     if (f)
436     {
437     // save (pixel-on-screen width/2 height/2) screen center
438     struct coord_geo g22;
439     struct coord c22;
440     struct point p;
441    
442     int width, height;
443     transform_get_size(this_->trans, &width, &height);
444     p.x=width/2;
445     p.y=height/2;
446    
447     transform_reverse(this_->trans, &p, &c22);
448     //dbg(0,"%f, %f\n",a, b);
449     //dbg(0,"%d, %d\n",p.x, p.y);
450     // * transform_to_geo(projection_mg, &c22, &g22);
451     //dbg(0,"%d, %d, %f, %f\n",c22.x, c22.y, g22.lat, g22.lng);
452     // * result=g_strdup_printf("%f:%f",g22.lat,g22.lng);
453    
454     // + center = transform_center(this_->trans);
455     pro = transform_get_projection(this_->trans);
456     // + coord_print(pro, center, f);
457     coord_print(pro, &c22, f);
458     dbg(0,"******** write center to file *********");
459     fclose(f);
460     }
461     else
462     {
463     perror(file);
464     }
465     return;
466     }
467    
468     static void
469     bookmarks_emit_dbus_signal(struct bookmarks *this_, struct pcoord *c, const char *description,int create)
470     {
471     struct attr attr1,attr2,attr3,attr4,cb,*attr_list[5];
472     int valid=0;
473     attr1.type=attr_type;
474     attr1.u.str="bookmark";
475     attr2.type=attr_data;
476     attr2.u.str=create ? "create" : "delete";
477     attr3.type=attr_data;
478     attr3.u.str=(char *)description;
479     attr4.type=attr_coord;
480     attr4.u.pcoord=c;
481     attr_list[0]=&attr1;
482     attr_list[1]=&attr2;
483     attr_list[2]=&attr3;
484     attr_list[3]=&attr4;
485     attr_list[4]=NULL;
486     if (navit_get_attr(this_->parent->u.navit, attr_callback_list, &cb, NULL))
487     callback_list_call_attr_4(cb.u.callback_list, attr_command, "dbus_send_signal", attr_list, NULL, &valid);
488     }
489    
490     /**
491     * Record the given set of coordinates as a bookmark
492     *
493     * @param navit The navit instance
494     * @param c The coordinate to store
495     * @param description A label which allows the user to later identify this bookmark
496     * @returns nothing
497     */
498     int
499     bookmarks_add_bookmark(struct bookmarks *this_, struct pcoord *pc, const char *description)
500     {
501     struct bookmark_item_priv *b_item=g_new0(struct bookmark_item_priv,1);
502     int result;
503    
504     if (pc) {
505     b_item->c.x=pc->x;
506     b_item->c.y=pc->y;
507     b_item->type=type_bookmark;
508     } else {
509     b_item->type=type_bookmark_folder;
510     }
511     b_item->label=g_strdup(description);
512     b_item->parent=this_->current;
513     b_item->children=NULL;
514    
515     this_->current->children=g_list_first(this_->current->children);
516     this_->current->children=g_list_append(this_->current->children,b_item);
517     this_->bookmarks_list=g_list_first(this_->bookmarks_list);
518     this_->bookmarks_list=g_list_append(this_->bookmarks_list,b_item);
519    
520     result=bookmarks_store_bookmarks_to_file(this_,0,0);
521    
522     callback_list_call_attr_0(this_->attr_cbl, attr_bookmark_map);
523     bookmarks_clear_hash(this_);
524     bookmarks_load_hash(this_);
525    
526     bookmarks_emit_dbus_signal(this_,&(b_item->c),description,TRUE);
527    
528     return result;
529     }
530    
531     int
532     bookmarks_cut_bookmark(struct bookmarks *this_, const char *label) {
533     if (bookmarks_copy_bookmark(this_,label)) {
534     return bookmarks_delete_bookmark(this_,label);
535     }
536    
537     return FALSE;
538     }
539     int
540     bookmarks_copy_bookmark(struct bookmarks *this_, const char *label) {
541     bookmarks_item_rewind(this_);
542     if (this_->current->children==NULL) {
543     return 0;
544     }
545     while (this_->current->iter!=NULL) {
546     struct bookmark_item_priv* data=(struct bookmark_item_priv*)this_->current->iter->data;
547     if (!strcmp(data->label,label)) {
548     this_->clipboard->c=data->c;
549     this_->clipboard->type=data->type;
550     this_->clipboard->item=data->item;
551     this_->clipboard->children=data->children;
552     if (!this_->clipboard->label) {
553     g_free(this_->clipboard->label);
554     }
555     this_->clipboard->label=g_strdup(data->label);
556     return TRUE;
557     }
558     this_->current->iter=g_list_next(this_->current->iter);
559     }
560     return FALSE;
561     }
562     int
563     bookmarks_paste_bookmark(struct bookmarks *this_) {
564     int result;
565     struct bookmark_item_priv* b_item;
566    
567     if (!this_->clipboard->label) {
568     return FALSE;
569     }
570    
571     b_item=g_new0(struct bookmark_item_priv,1);
572     b_item->c.x=this_->clipboard->c.x;
573     b_item->c.y=this_->clipboard->c.y;
574     b_item->label=g_strdup(this_->clipboard->label);
575     b_item->type=this_->clipboard->type;
576     b_item->item=this_->clipboard->item;
577     b_item->parent=this_->current;
578     b_item->children=this_->clipboard->children;
579    
580     g_hash_table_insert(this_->bookmarks_hash,b_item->label,b_item);
581     this_->bookmarks_list=g_list_append(this_->bookmarks_list,b_item);
582     this_->current->children=g_list_append(this_->current->children,b_item);
583     this_->current->children=g_list_first(this_->current->children);
584    
585     result=bookmarks_store_bookmarks_to_file(this_,0,0);
586    
587     callback_list_call_attr_0(this_->attr_cbl, attr_bookmark_map);
588     bookmarks_clear_hash(this_);
589     bookmarks_load_hash(this_);
590    
591     return result;
592     }
593    
594    
595     int
596     bookmarks_delete_bookmark(struct bookmarks *this_, const char *label) {
597     int result;
598    
599     bookmarks_item_rewind(this_);
600     if (this_->current->children==NULL) {
601     return 0;
602     }
603     while (this_->current->iter!=NULL) {
604     struct bookmark_item_priv* data=(struct bookmark_item_priv*)this_->current->iter->data;
605     if (!strcmp(data->label,label)) {
606     this_->bookmarks_list=g_list_first(this_->bookmarks_list);
607     this_->bookmarks_list=g_list_remove(this_->bookmarks_list,data);
608    
609     result=bookmarks_store_bookmarks_to_file(this_,0,0);
610    
611     callback_list_call_attr_0(this_->attr_cbl, attr_bookmark_map);
612     bookmarks_clear_hash(this_);
613     bookmarks_load_hash(this_);
614    
615     bookmarks_emit_dbus_signal(this_,&(data->c),label,FALSE);
616    
617     return result;
618     }
619     this_->current->iter=g_list_next(this_->current->iter);
620     }
621    
622     return FALSE;
623     }
624    
625     int
626     bookmarks_rename_bookmark(struct bookmarks *this_, const char *oldName, const char* newName) {
627     int result;
628    
629     bookmarks_item_rewind(this_);
630     if (this_->current->children==NULL) {
631     return 0;
632     }
633     while (this_->current->iter!=NULL) {
634     struct bookmark_item_priv* data=(struct bookmark_item_priv*)this_->current->iter->data;
635     if (!strcmp(data->label,oldName)) {
636     g_free(data->label);
637     data->label=g_strdup(newName);
638    
639     result=bookmarks_store_bookmarks_to_file(this_,0,0);
640    
641     callback_list_call_attr_0(this_->attr_cbl, attr_bookmark_map);
642     bookmarks_clear_hash(this_);
643     bookmarks_load_hash(this_);
644    
645     return result;
646     }
647     this_->current->iter=g_list_next(this_->current->iter);
648     }
649    
650     return FALSE;
651     }
652    
653     static int
654     bookmarks_shrink(char *bookmarks, int offset)
655     {
656     char buffer[4096];
657     int count,ioffset=offset,ooffset=0;
658     FILE *f;
659     if (!offset)
660     return 1;
661     f = fopen(bookmarks, "r+");
662     if (!f)
663     return 0;
664     for (;;) {
665     fseek(f, ioffset, SEEK_SET);
666     count=fread(buffer, 1, sizeof(buffer), f);
667     if (!count)
668     break;
669     fseek(f, ooffset, SEEK_SET);
670     if (fwrite(buffer, count, 1, f) != 1)
671     return 0;
672     ioffset+=count;
673     ooffset+=count;
674     }
675     fflush(f);
676     ftruncate(fileno(f),ooffset);
677     #ifdef HAVE_FSYNC
678     fsync(fileno(f));
679     #endif
680     fclose(f);
681     return 1;
682     }
683    
684     /**
685     * @param limit Limits the number of entries in the "backlog". Set to 0 for "infinite"
686     */
687     void
688     bookmarks_append_coord(struct bookmarks *this_, char *file, struct pcoord *c, int count, const char *type, const char *description, GHashTable *h, int limit)
689     {
690     FILE *f;
691     const char *prostr;
692    
693     if (limit != 0 && (f=fopen(file, "r"))) {
694     int *offsets=g_alloca(sizeof(int)*limit);
695     int offset_pos=0;
696     int offset;
697     char buffer[4096];
698     memset(offsets, 0, sizeof(int)*limit);
699     for (;;) {
700     offset=ftell(f);
701     if (!fgets(buffer, sizeof(buffer), f))
702     break;
703     if (strstr(buffer,"type=")) {
704     offsets[offset_pos]=offset;
705     offset_pos=(offset_pos+1)%limit;
706     }
707     }
708     fclose(f);
709     bookmarks_shrink(file, offsets[offset_pos]);
710     }
711     f=fopen(file, "a");
712     if (f) {
713     if (c) {
714     int i;
715     if (description)
716     fprintf(f,"type=%s label=\"%s\"\n", type, description);
717     else
718     fprintf(f,"type=%s\n", type);
719     for (i = 0 ; i < count ; i++) {
720     prostr = projection_to_name(c[i].pro,NULL);
721     fprintf(f,"%s%s%s0x%x %s0x%x\n",
722     prostr, *prostr ? ":" : "",
723     c[i].x >= 0 ? "":"-", c[i].x >= 0 ? c[i].x : -c[i].x,
724     c[i].y >= 0 ? "":"-", c[i].y >= 0 ? c[i].y : -c[i].y);
725     }
726     } else
727     fprintf(f,"\n");
728     }
729     fclose(f);
730     }
731    

   
Visit the ZANavi Wiki