c5af148563fe749123df176c40515dbdec9b4856
[mdictionary] / src / bookmarks / bdb / src / engine_bookmark.c
1 /******************************************************************************
2 This file is part of WhiteStork.
3
4 WhiteStork is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 WhiteStork 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 WhiteStork; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
18 Copyright 2006 ComArch S.A.
19 ******************************************************************************/
20
21 // header with data structure and function definition for XDXF engine.
22 // Also Engine API. 
23 #include "engine_bookmark.h"
24 //------------------------------------------------------------------------------
25
26 #ifndef NOLOGS
27         #include <glib/gstdio.h>
28         #define LOGS g_debug
29 #else
30         #define LOGS(frm,...) while(FALSE)
31 #endif
32
33
34 //------------------------------------------------------------------------------
35 static gint bm_compare_key_trans(const DBT *a, const DBT *b) {
36         guint tmpa;// = (guint*)(a->data);
37         guint tmpb;// = (guint*)(b->data);
38         memcpy(&tmpa, a->data, sizeof(guint));
39         memcpy(&tmpb, b->data, sizeof(guint));
40
41         if(tmpa == tmpb) return 0;
42         if(tmpa  > tmpb) return 1;
43         else return -1;
44 }
45 //------------------------------------------------------------------------------
46 static gint bm_compare_key_words(const DBT *a, const DBT *b) {
47         gchar* tmpa = g_utf8_casefold((gchar*)(a->data),-1);
48         gchar* tmpb = g_utf8_casefold((gchar*)(b->data),-1);
49         gint result = g_utf8_collate(tmpa,tmpb);
50         eg_free(tmpa);
51         eg_free(tmpb);
52         return result;
53 }
54 //------------------------------------------------------------------------------
55 static void bm_save_freeID(BookData* data) {
56         LOGS("Saveing new freeID=%u...\n",data->freeID);
57         guint temp = 0;
58         DBT key = {     &temp       , sizeof(guint)};
59         DBT val = { &(data->freeID) , sizeof(guint) };
60
61         gint res = data->db_trans->del(data->db_trans, &key, 0);
62         if(-1 == res)
63         {
64                 data->last_error = ENGINE_INTERNAL_ERROR;
65                 LOGS("Error while trying to delete old freeID!\n");
66                 return;
67         }
68         else {
69                 LOGS("Old freeID=%u deleted successfully!\n",data->freeID-1);
70         }
71
72         res = data->db_trans->put(data->db_trans, &key, &val, R_NOOVERWRITE);
73         if(-1 == res || 1 == res)
74         {
75                 data->last_error = ENGINE_INTERNAL_ERROR;
76                 LOGS("Error while trying to write new value for freeID!\n");
77         }
78         else {
79                 LOGS("New freeID=%u written successfully!\n",data->freeID);
80         }
81
82         res = data->db_trans->sync(data->db_trans, 0);
83         if(-1 == res || 1 == res)
84         {
85                 data->last_error = ENGINE_INTERNAL_ERROR;
86                 LOGS("Error while trying to write data to fuile!\n");
87         }
88         else {
89                 LOGS("New data saved successfully to file!\n");
90         }       
91 }
92 //------------------------------------------------------------------------------
93 static void bm_load_freeID(BookData* data) {
94         guint temp = 0;
95         DBT key = { &temp , sizeof(guint) };
96         DBT val = { NULL  , 0 };
97
98         gint res = data->db_trans->get(data->db_trans, &key, &val, 0);
99         if(-1 == res)
100         {
101                 data->last_error = ENGINE_INTERNAL_ERROR;
102                 LOGS("Bookmark/%s->%s() Error while getting access to trans "
103                      "database!",
104                      (gchar*)__FILE__,
105                      (gchar*)__FUNCTION__
106                     );
107         }
108         else if( 1 != res)
109         {
110                 memcpy(&(data->freeID), val.data, sizeof(guint));
111                 //data->freeID = *((guint*)(val.data));
112                 LOGS("Bookmark/%s->%s() Available next free ID is equal = %d",
113                      (gchar*)__FILE__,
114                      (gchar*)__FUNCTION__,
115                      data->freeID
116                     );
117         }
118         else
119         {
120                 LOGS("Bookmark/%s->%s() Could not load the minimal, available"
121                      " ID for next record - translation!",
122                      (gchar*)__FILE__,
123                      (gchar*)__FUNCTION__
124                     );
125                 data->freeID = 1;
126                 data->last_error = ENGINE_INTERNAL_ERROR;
127         }
128 }
129
130
131
132 //==============================================================================
133 //==============================================================================
134 //==============================================================================
135 //-------------------------------------- FUNCTION FROM API 0.2 !!!
136 //==============================================================================
137
138 gboolean bm_engine_add_word(Engine* engine,
139                          gchar*  word,
140                          gchar*  translation) {
141         LOGS("Bookmark/%s->%s() called. Param\nEngine at address: %p\n"
142              "word: %s\ntranslation address: %p\n",
143              (gchar*)__FILE__,
144              (gchar*)__FUNCTION__,
145              engine,
146              word,
147              translation
148             );
149         g_assert(engine != NULL);
150         g_assert(word != NULL);
151         g_assert(translation != NULL);
152
153         // start bm_timer for this function
154         bm_timer(TIMER_START, (gchar*)(gchar*)__FUNCTION__);
155
156         gboolean result = TRUE;
157         BookData* data = (BookData*)(engine->engine_data);
158         guint length = strlen(word) + 1;
159         DBT key = { word , length };
160         DBT val = { NULL , 0 };
161                 
162
163         gint db_res = data->db_words->get(data->db_words, &key, &val, 0);
164         if ( 0 == db_res )
165         {
166         // there is already entry for this key - check if this translation is in
167         // database - check string hash equality
168                 LOGS("Bookmark/%s->%s() updating entry for key: %s",
169                         (gchar*)__FILE__,
170                         (gchar*)__FUNCTION__,
171                         (gchar*)(key.data)
172                         );
173
174                 guint hash = g_str_hash(translation);
175                 guint* values = (guint*)(val.data);
176                 guint  N = values[0];
177                 memcpy(&N, values, sizeof(guint));
178                 guint  i = N;
179                 guint  tmp_hash = 0;
180                 gboolean exist = FALSE;
181                 ++values;
182                 while(i--)
183                 {
184                         memcpy(&tmp_hash, values + (i*2+1), sizeof(guint));
185                         if( tmp_hash == hash)
186                         {
187                                 exist = TRUE;
188                                 break;
189                         }
190                 }
191                 if(!exist)
192                 {
193                         LOGS("Bookmark/%s->%s() Adding new translation to "
194                                 "already exist word in dictionary.\n",
195                                 (gchar*)__FILE__,
196                                 (gchar*)__FUNCTION__
197                                 );
198                         values = (guint*)(val.data);
199                         guint* tmp = eg_malloc(val.size + sizeof(guint)*2);
200                         g_memmove(tmp, values, val.size);
201                         tmp[0]++;
202                         tmp[N*2+1] = data->freeID;
203                         tmp[N*2+2] = hash;
204                         val.data = tmp;
205                         val.size += 2*sizeof(guint);
206                         gint o = data->db_words->del(data->db_words,&key,0);
207                         if(0 != o)
208                         {
209                                 LOGS("Bookmark/%s->%s() Error while removing!",
210                                      (gchar*)__FILE__,
211                                      (gchar*)__FUNCTION__
212                                     );                          
213                         }
214                         o = data->db_words->sync(data->db_words, 0);
215                         if(0 != o) {
216                                 LOGS("Error while 1st synchronizing file with data!\n");
217                         }
218                         
219                         o = data->db_words->put(data->db_words,
220                                             &key,
221                                             &val,
222                                             R_NOOVERWRITE);
223                         if(0 != o) {
224                                 LOGS("Error while putting new info about word!\n");
225                         }
226                         o = data->db_words->sync(data->db_words, 0);
227                         if(0 != o) {
228                                 LOGS("Error while 2nd synchronizing file with data!\n");
229                         }
230                         bm_add_only_translation(data,translation,data->freeID);
231                         (data->freeID)++;
232                         bm_save_freeID(data);
233                         eg_free(tmp);
234                 }
235                 else
236                 {
237                         LOGS("Bookmark/%s->%s() This translation already exist!",
238                                 (gchar*)__FILE__,
239                                 (gchar*)__FUNCTION__
240                                 );
241                 }
242         }
243         else if ( 1 == db_res )
244         {
245         // there is no such a key - word in database - create new entry
246                 LOGS("Bookmark/%s->%s() adding new entry for key: %s",
247                         (gchar*)__FILE__,
248                         (gchar*)__FUNCTION__,
249                         (gchar*)(key.data)
250                         );
251                 result = bm_add_new_entry(word,translation,data);
252         }
253         else {
254         // there was an error, while accessing to the database
255                 LOGS("Bookmark/%s->%s() Error while trying to add new word: %s",
256                         (gchar*)__FILE__,
257                         (gchar*)__FUNCTION__,
258                         (gchar*)(key.data)
259                         );
260                 data->last_error = ENGINE_COULDNT_READ;
261                 result = FALSE;
262         }
263
264         bm_timer(TIMER_STOP, (gchar*)(gchar*)__FUNCTION__);
265         return result;
266 }
267 //------------------------------------------------------------------------------
268 static gboolean bm_add_only_translation(BookData* data,
269                                         gchar* translation,
270                                         guint id)
271 {
272         DBT key = { &id , sizeof(id) };
273         DBT val = { translation , strlen(translation) + 1 };
274         gint res = data->db_trans->put(data->db_trans,
275                                         &key,
276                                         &val,
277                                         R_NOOVERWRITE);
278         if(-1 == res) {
279                 LOGS("Error while adding only translation!\n");
280                 return FALSE;
281         }
282         res = data->db_trans->sync(data->db_trans, 0);
283         if(-1 == res) {
284                 LOGS("Error while synchronizing file with data\n");
285                 return FALSE;
286         }
287         return TRUE;
288 }
289 //------------------------------------------------------------------------------
290 static gboolean bm_add_new_entry(gchar* word,gchar* translation,BookData* data)
291 {
292         guint hash = g_str_hash(translation);
293         gboolean result = TRUE;
294
295         DBT new_key = { &(data->freeID) , sizeof(guint) };
296         DBT new_val = { translation , strlen(translation) + 1};
297         gint db_res = data->db_trans->put(data->db_trans,
298                                           &new_key,
299                                           &new_val,
300                                           R_NOOVERWRITE
301                                          );
302         if(-1 == db_res)
303         {
304                 data->last_error = ENGINE_COULDNT_WRITE;
305                 result = FALSE;
306         }
307         else
308         {
309                 new_key.data = word;
310                 new_key.size = strlen(word) + 1;
311
312                 // { number of entries , id of the first entry , hash #1 }
313                 guint temp[3] = { 1 , data->freeID, hash };
314                 new_val.data = temp;
315                 new_val.size = sizeof(guint) * 3;
316
317                 db_res = data->db_words->put(data->db_words,
318                                              &new_key,
319                                              &new_val,
320                                              R_NOOVERWRITE
321                                             );
322                 if(-1 == db_res)
323                 {
324                         new_key.data = &(data->freeID);
325                         new_key.size =  sizeof(guint);
326                         data->db_trans->del(data->db_trans, &new_key, 0);
327                         result = FALSE;
328                         data->last_error = ENGINE_INTERNAL_ERROR;
329                 }
330                 else
331                 {
332                         result = TRUE;
333                         (data->freeID)++;
334                         bm_save_freeID(data);
335                 }
336         }
337         db_res = data->db_words->sync(data->db_words,0);
338         db_res |= data->db_trans->sync(data->db_trans,0);
339         if(0 == db_res)
340         {
341                 LOGS("Bookmark/%s->%s() adding new bookmark successful.\n",
342                       (gchar*)__FILE__,(gchar*)__FUNCTION__);
343         }
344         else
345         {
346                 LOGS("Bookmark/%s->%s() adding new bookmark failed.\n",
347                       (gchar*)__FILE__,(gchar*)__FUNCTION__);
348         }
349         return result;  
350 }
351 //------------------------------------------------------------------------------
352 gboolean bm_engine_remove_word(Engine* engine,
353                              gchar*  word) {
354         gboolean result = TRUE;
355
356         LOGS("Bookmark/%s->%s() called. Param\nEngine at address: %p\n"
357              "word: %s\n",(gchar*)__FILE__,(gchar*)__FUNCTION__,engine,word);
358         g_assert(engine != NULL);
359         g_assert(word != NULL);
360         bm_timer(TIMER_START, (gchar*)(gchar*)__FUNCTION__);
361
362         BookData* data = (BookData*)(engine->engine_data);
363
364         DBT key = { word , strlen(word) + 1 };
365         DBT val = { NULL , 0 };
366                 
367         gint db_res = data->db_words->get(data->db_words, &key, &val, 0);
368         if ( 0 == db_res )
369         {
370                 guint* t = (guint*)(val.data);
371                 guint  N = t[0];
372                 guint  id = 0;
373                 memcpy(&N, t, sizeof(guint));
374                 ++t;
375                 guint  i = 0;
376                 key.size = sizeof(guint);
377                 key.data = &id;
378                 while( i < N ) {
379                         memcpy(&id, t + i*2, sizeof(guint));
380                         db_res = data->db_trans->del(data->db_trans, &key, 0);
381                         if(0 != db_res) {
382                                 LOGS("Error while removing translation # %u for word: %s",i+1,word);
383                         }
384                         ++i;
385                 }
386         }
387         else if( -1 == db_res) {
388                 LOGS("Bookmark/%s->%s() Error while removing word: %s!",
389                         (gchar*)__FILE__,
390                         (gchar*)__FUNCTION__,
391                         word
392                         );
393                 return FALSE;
394         }
395         else {
396                 LOGS("Bookmark/%s->%s() Ther is no such a word!",
397                         (gchar*)__FILE__,
398                         (gchar*)__FUNCTION__
399                         );
400                 return TRUE;
401         };
402
403         // all data from trnaslation database has been deleted - now delete
404         // record in words database.
405
406         DBT key_del = { word , strlen(word) + 1 };
407         db_res = data->db_words->del(data->db_words,&key_del,0);
408         if(-1 == db_res)
409         {
410                 LOGS("Bookmark/%s->%s() Error while removing!\n",
411                         (gchar*)__FILE__,
412                         (gchar*)__FUNCTION__
413                         );                              
414         }
415         else if(1 == db_res)
416         {
417                 LOGS("Bookmark/%s->%s() There is no such a word!\n",
418                         (gchar*)__FILE__,
419                         (gchar*)__FUNCTION__
420                         );
421         }
422         else if(0 == db_res)
423         {
424                 LOGS("Bookmark/%s->%s() word deleted successfully!\n",
425                         (gchar*)__FILE__,
426                         (gchar*)__FUNCTION__
427                         );
428         }
429         db_res = data->db_words->sync(data->db_words, 0);
430
431         if((0 != db_res) || (NULL == data->db_words) || (NULL == data->db_trans)) {
432                 LOGS("Error while 2nd synchronizing file with data!\n");
433         }
434
435
436         bm_timer(TIMER_STOP, (gchar*)(gchar*)__FUNCTION__);
437         LOGS("Bookmark/%s->%s() finished work.\n",
438                 (gchar*)__FILE__,
439                 (gchar*)__FUNCTION__
440                );
441         return result;
442 }
443 //------------------------------------------------------------------------------      
444 gchar* bm_engine_get_lang_from(Engine* engine) {
445         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
446         gchar* result = g_strdup("any");
447         LOGS("Bookmark/%s->%s() return string=%s\n",
448                 (gchar*)__FILE__,
449                 (gchar*)__FUNCTION__,
450                 result
451                );
452         return result;
453 }
454 //------------------------------------------------------------------------------
455 gchar* bm_engine_get_lang_to(Engine* engine) {
456         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
457         gchar* result = g_strdup("any");
458         LOGS("Bookmark/%s->%s() return string=%s\n",
459                 (gchar*)__FILE__,
460                 (gchar*)__FUNCTION__,
461                 result
462                );
463         return result;
464 }
465 //------------------------------------------------------------------------------
466 gchar* bm_engine_get_title(Engine* engine) {
467         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
468         gchar* result = g_strconcat(g_get_user_name(),"s' bookmarks",NULL);
469         LOGS("Bookmark/%s->%s() return string=%s\n",
470                 (gchar*)__FILE__,
471                 (gchar*)__FUNCTION__,
472                 result
473                );
474         return result;
475 }
476 //------------------------------------------------------------------------------
477 gchar* bm_engine_get_icon_path(Engine* engine) {
478         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
479         gchar* result = g_strdup("/usr/share/pixmaps/ws_eng_bookmark_icon.png");
480         LOGS("Bookmark/%s->%s() return string=%s\n",
481                 (gchar*)__FILE__,
482                 (gchar*)__FUNCTION__,
483                 result
484                );
485         return result;
486 }
487
488 //==============================================================================
489 //==============================================================================
490 //==============================================================================
491 //-------------------------------------- FUNCTION TO WRITE (NOT IMPLEMENTED YET)
492 //==============================================================================
493
494 //------------------------------------------------------------------------------
495 // searching word by concrete engine
496 void bm_engine_search_word_translation(Engine* engine,
497                                        gchar* word,
498                                        gpointer cb_data)
499 {
500         LOGS("Bookmark/%s->%s() called.\n-->PARAM:engine at adress=%p\n"
501              "-->PARAM:word=\'%s\'\n",
502              (gchar*)__FILE__,
503              (gchar*)__FUNCTION__,
504              engine,
505              word
506             );
507         g_assert(engine != NULL);
508         g_assert(word != NULL);
509         // start bm_timer for this function
510         bm_timer(TIMER_START, (gchar*)(gchar*)__FUNCTION__);
511         BookData* data = (BookData*)(engine->engine_data);
512
513         gchar* down_word = g_utf8_strdown(word,-1);
514         DBT search = { down_word , strlen(down_word) + 1 };
515         DBT info   = {    NULL   ,        0              };
516         DBT trans  = {    NULL   ,        0              };
517         gchar* tran = NULL;
518         gchar* tran_ = NULL;
519
520         gint tmp = data->db_words->get(data->db_words, &search, &info, 0);
521         if(0 == tmp)
522         {
523                 // plugin found some information about this word
524                 
525                 guint* records = (guint*)(info.data);
526                 guint count = records[0];
527                 memcpy(&count, records, sizeof(guint));
528                 //printf("Buffer (memcpy): %#x-%#x-%#x\n",count,records[1],records[2]);
529                 ++records;
530                 guint id = 0;
531                 search.data = &id;
532                 search.size = sizeof(guint);
533                 
534                 while(count-- > 0 && count < 100)
535                 {
536                         //printf("--> LOOP:count = %#x\n",count);
537                         memcpy(search.data, records, sizeof(guint));
538                         records += 2;
539                         tmp = data->db_trans->get(data->db_trans, &search, &trans, 0);
540                         if(0 == tmp)
541                         {
542                                 if(NULL == tran)
543                                 {
544                                         tran = g_strdup(trans.data);
545                                 }
546                                 else
547                                 {
548                                         tran_ = 
549                                         g_strconcat(tran,"<br />",trans.data,NULL);
550                                         g_free(tran);
551                                         tran = tran_;
552                                         tran_ = NULL;
553                                 }
554                         }
555                 }
556         };
557         g_free(down_word);
558         bm_timer(TIMER_STOP,(gchar*)(gchar*)__FUNCTION__);
559         bm_timer(TIMER_START,"callback for returning word's translation START");
560         // calling callback for word translation
561
562         if ( NULL == cb_data )
563         {
564                 cb_data = data->cb_search_word_trans_data;
565         }
566         data->cb_search_word_trans(tran, word, cb_data, ENGINE_NO_ERROR);
567                 
568         bm_timer(TIMER_STOP,"callback for returning word's translation END");
569 //         if(data->auto_free) {
570 //                 LOGS("Bookmark/%s->%s() deleting all dynamic data because "
571 //                      "AUTO_FREE=TRUE\n",
572 //                      (gchar*)__FILE__,
573 //                      (gchar*)__FUNCTION__
574 //                     );
575 //                 g_free(tran);
576 //         }
577         g_free(tran);
578         tran = NULL;
579 }
580
581 //------------------------------------------------------------------------------
582 void bm_engine_close(Engine* engine)
583 {
584         LOGS("Bookmark/%s->%s() called.\n-->PARAM: engine adress=%p\n",
585                 (gchar*)__FILE__,
586                 (gchar*)__FUNCTION__,
587                 engine);
588         g_assert(engine != NULL);
589         
590         BookData* data = (BookData*)(engine->engine_data);
591         data->db_words->close(data->db_words);
592         data->db_trans->close(data->db_trans);
593         
594         LOGS("Bookmark/%s->%s() engine at adress=%p is deleted.\n",
595                 (gchar*)__FILE__,
596                 (gchar*)__FUNCTION__,
597                 engine);
598         g_free(data->dict_path); 
599         g_free(data);
600         data = NULL;
601         g_free(engine);
602         engine = NULL;
603 }
604 //------------------------------------------------------------------------------
605
606 Engine* bm_engine_create(gchar* location,
607                       EngineOptimizationFlag auto_cache,
608                       cb_progress progress_handler,
609                       gpointer progress_data,
610                       gdouble seed)
611 {
612         LOGS("Bookmark/%s->%s() called.\n"
613              "-->PARAM:location=\'%s\'\n"
614              "-->PARAM:auto_cache=%d\n",
615              (gchar*)__FILE__,
616              (gchar*)__FUNCTION__,
617              location,
618              (guint)auto_cache
619             );
620         bm_timer(TIMER_START,(gchar*)(gchar*)__FUNCTION__);        
621
622         gchar* tmp = g_strdup(location);
623         string_to_path(&tmp);
624
625         Engine* result = (Engine*)g_try_malloc(sizeof(Engine));
626         result->engine_location = bm_engine_location;
627         result->engine_is_optimized = bm_engine_is_optimized;
628         result->engine_optimize = bm_engine_optimize;
629         result->engine_search_word_list = bm_engine_search_word_list;
630         result->engine_search_word_translation = 
631                         bm_engine_search_word_translation;        
632         result->engine_close = bm_engine_close;
633         result->engine_status = bm_engine_status;
634         result->engine_error_message = bm_engine_status_message;
635         result->engine_set_callback = bm_engine_set_callback;
636         result->engine_set_progress_seed = bm_engine_set_progress_seed;
637         result->engine_set_auto_free = bm_engine_set_auto_free;
638         // 0.2 API:
639         result->engine_add_word = bm_engine_add_word;
640         result->engine_remove_word = bm_engine_remove_word;
641         result->engine_get_lang_from = bm_engine_get_lang_from;
642         result->engine_get_lang_to = bm_engine_get_lang_to;
643         result->engine_get_title = bm_engine_get_title;
644         result->engine_get_icon_path = bm_engine_get_icon_path;
645
646
647         BookData* data = (BookData*)g_try_malloc(sizeof(BookData));
648         result->engine_data = (gpointer)data;
649
650         LOGS("Bookmark/%s->%s() opening file...\'%s\'.\n",
651              (gchar*)__FILE__,
652              (gchar*)__FUNCTION__,
653              location
654             );
655
656         u_int32_t flags = O_CREAT | O_RDWR;
657         gchar* tmp_w = g_strconcat(tmp,"/bm_words.db",NULL);
658         gchar* tmp_t = g_strconcat(tmp,"/bm_trans.db",NULL);
659
660         BTREEINFO inf = {
661           0,            /* permit duplicate keys? */
662           0,                    /* cache size; 0 - default size */
663           0,                    /* page size; 0 - default */
664           0,                    /* byte order; 0 - use host order */
665           0,                    /* min page number per page; 0 - default=2 */
666           bm_compare_key_words, /* comparision function */
667           NULL                  /* prefix comparision function */
668         };
669         data->info_words = inf;
670         inf.compare = bm_compare_key_trans;
671         data->info_trans = inf;
672
673         data->db_words = 
674                 dbopen(tmp_w,       /* On-disk file that holds the database. */
675                        flags,       /* flags, like O_CREAT etc. */
676                        0755,        /* mode same as flags <hmmm> ? */
677                        DB_BTREE,    /* type */
678                        &(data->info_words)
679                       );
680         if(data->db_words == NULL)
681         {
682                 g_free(data);
683                 g_free(result);
684                 result = NULL;
685         }
686         else {
687                 data->db_trans = 
688                         dbopen(tmp_t,
689                         flags,
690                         0755,
691                         DB_BTREE,
692                         &(data->info_trans)
693                         );
694
695                 if(data->db_trans == NULL)
696                 {
697                         data->db_words->close(data->db_words);
698                         g_free(data);
699                         g_free(result);
700                         result = NULL;
701                 }
702
703         }
704         g_free(tmp_w); tmp_w = NULL;
705         g_free(tmp_t); tmp_t = NULL;
706         if(result == NULL) {
707                 LOGS("Bookmark/%s->%s() opening bookmark file failed.\n",
708                      (gchar*)__FILE__,
709                      (gchar*)__FUNCTION__
710                     );
711         }
712         else {
713                 LOGS("Bookmark/%s->%s()opening dictionary file successed.\n",
714                         (gchar*)__FILE__,
715                         (gchar*)__FUNCTION__
716                        );
717                 data->dict_path = g_strdup(tmp);
718                 data->cb_progress_caching = progress_handler;
719                 data->cb_progress_caching_data = progress_data;        
720                 data->cb_progress_caching_seed = seed;        
721                 data->cb_progress_word_list = NULL;
722                 data->cb_progress_word_list_data = NULL;
723                 data->cb_progress_word_list_seed = 0.01;
724                 data->cb_progress_word_trans = NULL;
725                 data->cb_progress_word_trans_data = NULL;
726                 data->cb_progress_word_trans_seed = 0.01;
727
728                 data->cb_search_word_list = NULL;
729                 data->cb_search_word_list_data = NULL;
730
731                 data->cb_search_word_trans = NULL;
732                 data->cb_search_word_trans_data = NULL;
733
734                 data->auto_free = FALSE;
735
736                 bm_load_freeID(data);
737
738         }
739         g_free(tmp); tmp = NULL;
740         
741         bm_timer(TIMER_STOP,(gchar*)(gchar*)__FUNCTION__);
742         LOGS("Bookmark/%s->%s() returned Engine at adress=%p\n",
743              (gchar*)__FILE__,
744              (gchar*)__FUNCTION__,
745              result
746             );
747         return result;
748 }
749 //------------------------------------------------------------------------------
750
751
752
753 static gboolean is_Bookmark_db_file(gchar* file) {
754         LOGS("Bookmark/%s->%s() called.\n\
755                  -->PARAM:file=\'%s\'\n",
756                  (gchar*)__FILE__,
757                  (gchar*)__FUNCTION__,
758                  file
759                );
760
761         u_int32_t flags = O_RDWR;
762         DB* dbp = dbopen(file,flags,0755,DB_BTREE,NULL);
763
764         if(NULL == dbp) 
765         {
766                 LOGS("Could no open! Wrong database! Not a bookmark.\n");
767                 return FALSE;
768         };
769         
770         DBT search = {"four",sizeof("four")};
771         DBT result = {NULL, 0};
772
773         int errCode = dbp->get(dbp,&search,&result,0);
774         dbp->close(dbp);
775         g_free(result.data);
776
777         if(-1 == errCode)
778         {
779                 LOGS("Could not read! Wrong database! Not a bookmark.\n");
780                 return FALSE;
781         };
782         return TRUE;
783 }
784 //------------------------------------------------------------------------------
785
786
787 void bm_engine_optimize(Engine* engine)
788 {
789         LOGS("Bookmark/%s->%s() called for engine at adress=%p\n",
790              (gchar*)__FILE__,
791              (gchar*)__FUNCTION__,
792              engine
793             );
794         LOGS("Unsupported optimization mechanizm for this engine!\n");
795         LOGS("Bookmark/%s->%s()'s work finished.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
796 }
797 //------------------------------------------------------------------------------
798 gboolean bm_engine_check(gchar* location) 
799 {        
800         LOGS("Bookmark/%s->%s() called.\n-->PARAM:location=\'%s\'\n",
801              (gchar*)__FILE__,
802              (gchar*)__FUNCTION__,
803              location
804             );
805         bm_timer(TIMER_START,(gchar*)(gchar*)__FUNCTION__);
806         gboolean result = TRUE;
807         gchar* filepath = g_strdup(location);
808         gchar* tmp = NULL;
809         gchar* tmp2 = NULL;
810         
811         string_to_path(&filepath);
812         if (filepath == NULL) {
813                 result = FALSE;
814                 LOGS("Bookmark/%s->%s() location \'%s\' is not a proper "
815                      "path!\n",
816                      (gchar*)__FILE__,
817                      (gchar*)__FUNCTION__,
818                      location
819                     );
820         }
821         else {
822                 tmp = g_strconcat(filepath,"/bm_words.db",NULL);
823                 tmp2 = g_strconcat(filepath,"/bm_trans.db",NULL);
824                 g_free(filepath);
825                 filepath = tmp;
826                 tmp = NULL;
827
828                 LOGS("Bookmark/%s->%s() finnal file to check is: %s\n",
829                      (gchar*)__FILE__,
830                      (gchar*)__FUNCTION__,
831                      filepath
832                     );
833                 if (!g_file_test(filepath, G_FILE_TEST_IS_REGULAR) || 
834                     !g_file_test(tmp2, G_FILE_TEST_IS_REGULAR) 
835                    ) {
836                         LOGS("Bookmark/%s->%s() file \'%s\' does not exists!\n",
837                              (gchar*)__FILE__,
838                              (gchar*)__FUNCTION__,
839                              filepath
840                             );
841                         result = FALSE;
842                 };
843         };
844         if (result != FALSE) {
845                 result = is_Bookmark_db_file(filepath) & 
846                          is_Bookmark_db_file(tmp2);
847         };
848
849         g_free(filepath);  filepath = NULL;
850         g_free(tmp2);      tmp2 = NULL;
851         bm_timer(TIMER_STOP,(gchar*)(gchar*)__FUNCTION__);
852         LOGS("Bookmark/%s->%s() returned bool statement=%s.\n",
853              (gchar*)__FILE__,
854              (gchar*)__FUNCTION__,
855              PRINT_STATE(result)
856             );
857         return result;
858 }
859
860 //------------------------------------------------------------------------------
861 gboolean bm_engine_is_optimized(Engine* engine) 
862 {
863         LOGS("Bookmark/%s->%s() called.\n-->PARAM: engine adress=%p\n",
864              (gchar*)__FILE__,
865              (gchar*)__FUNCTION__,
866              engine
867             );
868         g_assert(engine != NULL);                
869         gboolean result = FALSE;
870         LOGS("Bookmark/%s->%s() returned bool statement=%s.\n",
871              (gchar*)__FILE__,
872              (gchar*)__FUNCTION__,
873              PRINT_STATE(result)
874             );
875         return result;
876 }
877 //------------------------------------------------------------------------------
878
879 void bm_engine_search_word_list(Engine* engine,
880                                 gchar* pattern,
881                                 gpointer cb_data)
882 {
883         LOGS("Bookmark/%s->%s() called. Searching words list\n"
884              "-->PARAM:engine at adress=%p\n"
885              "-->PARAM:pattern=\"%s\"\n",
886              (gchar*)__FILE__,
887              (gchar*)__FUNCTION__,
888              engine,
889              pattern
890             );
891         g_assert(engine != NULL);
892         g_assert(pattern != NULL);
893
894         bm_timer(TIMER_START,(gchar*)(gchar*)__FUNCTION__);
895         BookData* data = (BookData*)(engine->engine_data);
896         if(data->cb_search_word_list == NULL) {
897                 LOGS("Bookmark/%s->%s() callback for Word List not set. "
898                      "Searching aborted.\n",
899                      (gchar*)__FILE__,
900                      (gchar*)__FUNCTION__
901                     );
902                 bm_timer(TIMER_STOP,(gchar*)(gchar*)__FUNCTION__);
903                 return;
904         };
905
906         GArray* result = g_array_new(TRUE, TRUE, sizeof(gchar*) );
907         guint a = G_MAXUINT32;
908         DBT search = { &a , sizeof(a) };
909         DBT reply  = { NULL , 0 };
910         gchar* down_word = NULL;
911         gchar *tmp;
912         
913         GPatternSpec* regex;
914         regex = g_pattern_spec_new (g_utf8_casefold(pattern,-1));
915
916         gint code = data->db_words->sync(data->db_words, 0);
917         code = data->db_words->seq(data->db_words, &search, &reply, R_FIRST);
918         
919 /*
920         if((('*' == pattern[0]) && ('\0' == pattern[1])) || ('\0' == pattern[0]))
921         {
922                 // especiall treat if user give only '*'
923                 while(0 == code) {
924                         gchar* cos = g_strdup(search.data);
925                         g_array_append_val(result,cos);
926                         code = data->db_words->seq(data->db_words, &search, &reply, R_NEXT);
927                         // we are giving to the user all words from dictionary
928                 }
929         }
930         else
931         {*/
932         while(0 == code) {
933                 tmp = g_strconcat ((gchar*)(search.data), " ", NULL);
934                 down_word = g_utf8_casefold(tmp,-1);
935                 g_free (tmp);
936                 tmp = g_utf8_casefold ((gchar*)(search.data),-1);
937                 
938                 if(( g_pattern_match_string( regex, down_word ) == TRUE ) ||
939                         ( g_pattern_match_string( regex, tmp ) == TRUE ))
940                 {
941                         tmp = g_strdup(search.data);
942                         g_array_append_val(result, tmp );
943                 };
944
945                 //eg_free(reply.data);
946                 eg_free(down_word);
947                 code = data->db_words->seq(data->db_words, &search, &reply, R_NEXT);
948                 g_free (tmp);
949         }
950         
951         bm_timer(TIMER_STOP,(gchar*)(gchar*)__FUNCTION__);
952         g_pattern_spec_free (regex);
953
954
955         bm_timer(TIMER_START,"callback for returning words LIST START");
956         // calling callback for word translation
957
958         if ( NULL == cb_data )
959         {
960                 cb_data = data->cb_search_word_list_data;
961         }
962         data->cb_search_word_list(result, pattern, cb_data, ENGINE_NO_ERROR);
963
964
965        /* if(data->auto_free) {
966                 LOGS("Bookmark/%s->%s() deleting all dynamic data because "
967                      "AUTO_FREE=TRUE\n",
968                      (gchar*)__FILE__,
969                      (gchar*)__FUNCTION__
970                     );
971                 len = 0;
972                 while(NULL != (tmp = g_array_index(result,gchar*,len++)))
973                 {
974                         g_free(tmp); tmp = NULL;
975                 }
976                 g_array_free(result, TRUE);
977         }*/
978         guint len = 0;
979         
980         while(NULL != (tmp = g_array_index(result,gchar*,len++)))
981         {
982                 g_free(tmp); tmp = NULL;
983         }
984         g_array_free(result, TRUE);
985         bm_timer(TIMER_STOP,"callback for returning word LIST END");
986 }
987
988 //==============================================================================
989 //==============================================================================
990 //==============================================================================
991 //---------------------------------------------------------- COMPLETED FUNCTIONS
992 //==============================================================================
993 // global functions
994 EngineModule engine_global_functions()
995 {
996         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
997         EngineModule result;        
998         result.engine_check             = bm_engine_check;
999         result.engine_description       = bm_engine_description;
1000         result.engine_format            = bm_engine_format;
1001         result.engine_version           = bm_engine_version;
1002         result.engine_create            = bm_engine_create;
1003         LOGS("Bookmark/%s->%s()returned EngineModule at adress=%p.\n",
1004              (gchar*)__FILE__,
1005              (gchar*)__FUNCTION__,
1006              &result
1007             );
1008         return result;
1009 }
1010 //------------------------------------------------------------------------------
1011 // for macro: dict_eng_status_message(error)
1012 gchar* bm_engine_status_message(EngineStatus error) 
1013 {
1014         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1015         switch (error) {
1016                 case ENGINE_NO_ERROR:
1017                         return "No error.";
1018                 case ENGINE_WRONG_FILE:
1019                         return "File which You are trying to use is wrong type.";
1020                 case ENGINE_COULDNT_READ:
1021                         return "Could not read from file.";
1022                 case ENGINE_NO_FILE:
1023                         return "There is no such a file.";
1024                 case ENGINE_OUT_OF_MEMORY:
1025                         return "There were no enough memory for this action.";
1026                 default:
1027                         return "Wrong engine's status identifier!";
1028         }
1029 }
1030 //------------------------------------------------------------------------------
1031 // for macro: dict_eng_module_get_version(module)
1032 gchar* bm_engine_version() 
1033 {
1034         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1035         gchar* result = g_strdup(DIC_ENG_VERSION);
1036         LOGS("Bookmark/%s->%s() return string=%s\n",
1037                 (gchar*)__FILE__,
1038                 (gchar*)__FUNCTION__,
1039                 result
1040                );
1041         return result;
1042 }
1043 //------------------------------------------------------------------------------
1044 // for macro: dict_eng_module_get_format(module)
1045 gchar* bm_engine_format() 
1046 {
1047         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1048         gchar* result = g_strdup(DIC_ENG_FORMAT);
1049         LOGS("Bookmark/%s->%s() return string=%s\n",
1050              (gchar*)__FILE__,
1051              (gchar*)__FUNCTION__,
1052              result
1053             );
1054         return result;
1055 }
1056 //------------------------------------------------------------------------------
1057 // for macro: dict_eng_module_get_description(module)
1058 gchar* bm_engine_description() 
1059 {
1060         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1061         gchar* result = g_strdup(DIC_ENG_DESCRIPTION);
1062         LOGS("Bookmark/%s->%s() return string=%s\n",
1063              (gchar*)__FILE__,
1064              (gchar*)__FUNCTION__,
1065              result
1066             );
1067         return result;
1068 }
1069 //------------------------------------------------------------------------------
1070 // for macro: dict_eng_get_location(engine)
1071 gchar* bm_engine_location(Engine* engine)
1072 {
1073         LOGS("Bookmark/%s->%s() called.\n-->PARAM: engine adress=%p\n",
1074              (gchar*)__FILE__,
1075              (gchar*)__FUNCTION__,
1076              engine
1077             );
1078         g_assert(engine != NULL);
1079         BookData* data = (BookData*)(engine->engine_data);
1080  
1081         gchar* result;
1082         if(data->auto_free) {
1083                 result = data->dict_path;
1084         }
1085         else {
1086                 result = g_strdup(data->dict_path);
1087         }
1088
1089         LOGS("Bookmark/%s->%s() returned string=%s\n",
1090              (gchar*)__FILE__,
1091              (gchar*)__FUNCTION__,
1092              result
1093             );
1094         return result;
1095 }
1096 //------------------------------------------------------------------------------
1097 // for macro: dict_eng_set_auto_free(engine, state)
1098 void bm_engine_set_auto_free(Engine* engine, gboolean state) 
1099 {
1100         LOGS("Bookmark/%s->%s() called.\n"
1101              "-->PARAM:engine at adress=%p\n"
1102              "-->PARAM:state=%s\n",
1103              (gchar*)__FILE__,
1104              (gchar*)__FUNCTION__,
1105              engine,
1106              PRINT_STATE(state)
1107             );
1108         g_assert(engine != NULL);
1109         BookData* data = (BookData*)(engine->engine_data);
1110         
1111         data->auto_free = state;
1112         LOGS("Bookmark/%s->%s() Current auto_free is %s\n",
1113              (gchar*)__FILE__,
1114              (gchar*)__FUNCTION__,
1115              PRINT_STATE(data->auto_free)
1116             );
1117 }
1118 //------------------------------------------------------------------------------
1119 // for macro: dict_eng_get_last_status(engine)
1120 EngineStatus bm_engine_status(Engine* engine) 
1121 {
1122         LOGS("Bookmark/%s->%s() called.\n"
1123                 "-->PARAM:engine at adress=%p\n",
1124                 (gchar*)__FILE__,
1125                 (gchar*)__FUNCTION__,
1126                engine
1127                );
1128         BookData* data = (BookData*)(engine->engine_data);
1129         LOGS("Bookmark/%s->%s() returned error code: %d\n",
1130              (gchar*)__FILE__,
1131              (gchar*)__FUNCTION__,
1132              (gint)(data->last_error)
1133             );
1134         return data->last_error;
1135 }
1136 //------------------------------------------------------------------------------
1137 // for macro: dict_eng_set_progress_seed(engine, signal, val)
1138 void bm_engine_set_progress_seed(Engine* engine, gchar* signal, gdouble seed) {
1139         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1140         BookData* data = (BookData*)(engine->engine_data);
1141         if(g_ascii_strcasecmp(signal,ENGINE_PROGRESS_OPTIMIZING_SIGNAL) == 0)  {
1142                 data->cb_progress_caching_seed = seed;
1143                 LOGS("Bookmark/%s->%s() sets new seed=%0.2f for for signal "
1144                      "\"%s\".\n",
1145                      (gchar*)__FILE__,
1146                      (gchar*)__FUNCTION__,
1147                      seed,
1148                      signal
1149                     );        
1150         } 
1151         else {
1152                 LOGS("Bookmark/%s->%s() unsupported signalfor progress: %s.\n",
1153                      (gchar*)__FILE__,
1154                      (gchar*)__FUNCTION__,
1155                      signal
1156                     );
1157         };
1158 }
1159 //------------------------------------------------------------------------------
1160 // for macro: dict_eng_set_callback(engine,signal,c_handler,data)
1161 gpointer bm_engine_set_callback(Engine* engine,
1162                              gchar* signal,
1163                              gpointer c_handler,
1164                              gpointer user_data)
1165 {
1166         LOGS("Bookmark/%s->%s() called.\n",(gchar*)__FILE__,(gchar*)__FUNCTION__);
1167         g_assert(engine != NULL);
1168         g_assert(signal != NULL);
1169         g_assert(c_handler != NULL);
1170         BookData* data = (BookData*)(engine->engine_data);
1171         if(g_ascii_strcasecmp(signal,ENGINE_PROGRESS_OPTIMIZING_SIGNAL) == 0)  {
1172                 gpointer result = data->cb_progress_caching;
1173                 data->cb_progress_caching = c_handler;
1174                 data->cb_progress_caching_data = user_data;
1175                 LOGS("Bookmark/%s->%s() sets handler for signal \"%s\".\n",
1176                         (gchar*)__FILE__,
1177                         (gchar*)__FUNCTION__,
1178                         signal
1179                        );
1180                 LOGS("Bookmark/%s->%s() Function at adress =  %d.\n",
1181                         (gchar*)__FILE__,
1182                         (gchar*)__FUNCTION__,
1183                         (guint)c_handler
1184                        );
1185                 LOGS("Bookmark/%s->%s()     Data at adress =  %d.\n",
1186                         (gchar*)__FILE__,
1187                         (gchar*)__FUNCTION__,
1188                         (guint)user_data
1189                        );
1190                 return result;                
1191         }
1192         else if(g_ascii_strcasecmp(signal, ENGINE_WORD_LIST_SIGNAL) == 0) {
1193                 gpointer result = data->cb_search_word_list;
1194                 data->cb_search_word_list = c_handler;
1195                 data->cb_search_word_list_data = user_data;
1196                 LOGS("Bookmark/%s->%s() sets handler for signal \"%s\".\n",
1197                         (gchar*)__FILE__,
1198                         (gchar*)__FUNCTION__,
1199                         signal
1200                        );
1201                 LOGS("Bookmark/%s->%s() Function at adress =  %d.\n",
1202                         (gchar*)__FILE__,
1203                         (gchar*)__FUNCTION__,
1204                         (guint)c_handler
1205                        );
1206                 LOGS("Bookmark/%s->%s()     Data at adress =  %d.\n",
1207                         (gchar*)__FILE__,
1208                         (gchar*)__FUNCTION__,
1209                         (guint)user_data
1210                        );
1211                 return result;                        
1212         }
1213         else if(g_ascii_strcasecmp(signal,
1214                 ENGINE_WORD_TRANSLATION_SIGNAL) == 0)  {
1215                         gpointer result = data->cb_search_word_trans;
1216                         data->cb_search_word_trans = c_handler;
1217                         data->cb_search_word_trans_data = user_data;
1218                         LOGS("Bookmark/%s->%s() sets handler for signal \"%s\".\n",
1219                                 (gchar*)__FILE__,
1220                                 (gchar*)__FUNCTION__,
1221                                 signal
1222                                );
1223                         LOGS("Bookmark/%s->%s() Function at adress =  %d.\n",
1224                                 (gchar*)__FILE__,
1225                                 (gchar*)__FUNCTION__,
1226                                 (guint)c_handler
1227                                );
1228                         LOGS("Bookmark/%s->%s()     Data at adress =  %d.\n",
1229                                 (gchar*)__FILE__,
1230                                 (gchar*)__FUNCTION__,
1231                                 (guint)user_data
1232                                );
1233                         return result;                        
1234                 }
1235                 else {
1236                         g_warning("Bookmark/%s->%s() unsupported signal: %s.\n",
1237                                   (gchar*)__FILE__,
1238                                   (gchar*)__FUNCTION__,
1239                                   signal
1240                                  );
1241                         return NULL;
1242                 }
1243 }
1244
1245
1246 //==============================================================================
1247 //==============================================================================
1248 //==============================================================================
1249 //---------------------------------------------------------- HELPFULLY FUNCTIONS
1250 //==============================================================================
1251
1252 //------------------------------------------------------------------------------
1253 static gchar* string_to_path(gchar** string) {
1254         LOGS("Bookmark/%s->%s() called.\n\
1255                  -->PARAM:string=\'%s\'\n",
1256                  (gchar*)__FILE__,
1257                  (gchar*)__FUNCTION__,
1258                  string[0]
1259                );
1260         gchar* arg = string[0];
1261         gchar* new = NULL;
1262         // cleaning from leading and trailing whitespaces
1263         g_strstrip(arg);        
1264          // add current directory if this is not absolute directory
1265         if (!g_path_is_absolute(arg)) {
1266                 gchar* tmp = g_get_current_dir();
1267                 new = g_strconcat(tmp,"/",arg,NULL);
1268                 g_free(arg); arg = new; new = NULL;
1269         };
1270         // this is not a directory
1271         if (!g_file_test(arg, G_FILE_TEST_IS_DIR)) {        
1272                 // if this is wrong filepath, string was wrong
1273                 if (!g_file_test(arg, G_FILE_TEST_IS_REGULAR)) {        
1274                         g_free(arg);
1275                         new = NULL;
1276                 }
1277                 //if this is a file, remove filename
1278                 else
1279                 {   
1280                         new = g_path_get_dirname (arg);
1281                         g_free(arg);
1282                 }
1283         }
1284         // this is a directory
1285         else {   
1286                 // remove suffix "/" if neded...     
1287                 if (g_str_has_suffix(arg,"/") ) {        
1288                         new = g_path_get_dirname (arg);
1289                         g_free(arg);
1290                 }
1291                 else {
1292                         new = arg;
1293                 }
1294         };
1295         // now in new should be proper filepath, if not, string was wrong
1296         if (!g_file_test(new, G_FILE_TEST_IS_DIR))  {        
1297                 // if that directory does not exist, passed string wasn't proper       
1298                 g_free(new);
1299                 new = NULL;
1300         };
1301         // replace string under passed address
1302         string[0] = new;
1303         LOGS("Bookmark/%s->%s() returned string=\'%s\'\n",
1304                 (gchar*)__FILE__,
1305                 (gchar*)__FUNCTION__,
1306                 string[0]
1307                );
1308         return new;
1309 }
1310 //------------------------------------------------------------------------------
1311 static double bm_timer(gboolean start, gchar* message)
1312 {
1313         static GArray* stack = NULL;
1314         static gboolean first_run = TRUE;
1315         static struct timeval actual_time;
1316         static struct timeval last_time;
1317         static struct timeval result;
1318         static double seconds = 0.0;
1319         if(first_run) {
1320                 first_run = FALSE;
1321                 stack = g_array_new(TRUE, TRUE, sizeof(struct timeval));
1322         };        
1323
1324         if (start) {
1325                 LOGS("Bookmark->%s() start bm_timer for function '%s()'.\n",
1326                         (gchar*)__FUNCTION__,
1327                         message
1328                        );
1329                 g_array_prepend_val(stack, actual_time);
1330                 gettimeofday(&g_array_index(stack, struct timeval, 0),NULL);
1331                 return -1.0;
1332         }
1333         // we just want to end some bm_timer - print some information about 
1334         // working time;
1335         else {          
1336                 gettimeofday(&actual_time,NULL);
1337                 last_time = g_array_index(stack, struct timeval, 0);
1338                 g_array_remove_index(stack, 0);
1339
1340                 if (actual_time.tv_usec < last_time.tv_usec) {
1341                         int nsec = (last_time.tv_usec - actual_time.tv_usec) / 
1342                                         (1000000 + 1);
1343                         last_time.tv_usec -= 1000000 * nsec;
1344                         last_time.tv_sec += nsec;
1345                 }
1346                 if (actual_time.tv_usec - last_time.tv_usec > 1000000) {
1347                         int nsec = (last_time.tv_usec - actual_time.tv_usec) / 
1348                                         1000000;
1349                         last_time.tv_usec += 1000000 * nsec;
1350                         last_time.tv_sec -= nsec;
1351                 }
1352                 result.tv_sec = actual_time.tv_sec - last_time.tv_sec;
1353                 result.tv_usec = actual_time.tv_usec - last_time.tv_usec;
1354                 seconds = (((double)(result.tv_usec)) / 1e6) +
1355                                 ((double)(result.tv_sec));
1356
1357                 LOGS("Bookmark->%s() function \'%s()\' was working for: %g "
1358                                 "[s] or %ld [us].\n",
1359                 (gchar*)__FUNCTION__,
1360                 message,
1361                 seconds,
1362                 ((long)(result.tv_sec*1e6)+(result.tv_usec))
1363                        );
1364                 // stack is empty so we delete everything
1365                 if(stack->len == 0)   
1366                 {
1367                         g_array_free(stack, TRUE);
1368                         first_run = TRUE;
1369                 }
1370         }
1371         return seconds;
1372 }
1373 //------------------------------------------------------------------------------