Fix:map_csv:Disable default notification of each deleted item.
[profile/ivi/navit.git] / navit / navit / log.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 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 "config.h"
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #ifdef HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27 #include <fcntl.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <time.h>
33 #include <glib.h>
34 #include "file.h"
35 #include "item.h"
36 #include "event.h"
37 #include "callback.h"
38 #include "debug.h"
39 #include "log.h"
40
41 struct log_data {
42         int len;
43         int max_len;
44         char *data;
45 };
46
47 struct log {
48         FILE *f;
49         int overwrite;
50         int empty;
51         int lazy;
52         int mkdir;
53         int flush_size;
54         int flush_time;
55         struct event_timeout *timer;
56         struct callback *timer_callback;
57 #ifdef HAVE_SYS_TIME_H
58         struct timeval last_flush;
59 #endif
60         char *filename;
61         char *filename_ex1;
62         char *filename_ex2;
63         struct log_data header;
64         struct log_data data;
65         struct log_data trailer;
66         struct attr **attrs;
67 };
68
69 static void
70 strftime_localtime(char *buffer, int size, char *fmt)
71 {
72         time_t t;
73         struct tm *tm;
74
75         t=time(NULL);
76         tm=localtime(&t);
77         strftime(buffer, 4096, fmt, tm);
78 }
79
80 static void
81 expand_filenames(struct log *this_)
82 {
83         char *pos,buffer[4096];
84         int i;
85
86         strftime_localtime(buffer, 4096, this_->filename);
87         this_->filename_ex1=g_strdup(buffer);
88         if ((pos=strstr(this_->filename_ex1,"%i"))) {
89 #ifdef HAVE_API_ANDROID
90                 pos[1]='d';
91 #endif
92                 i=0;
93                 do {
94                         g_free(this_->filename_ex2);
95                         this_->filename_ex2=g_strdup_printf(this_->filename_ex1,i++);
96                 } while (file_exists(this_->filename_ex2));
97 #ifdef HAVE_API_ANDROID
98                 pos[1]='i';
99 #endif
100         } else 
101                 this_->filename_ex2=g_strdup(this_->filename_ex1);
102 }
103
104 static void
105 log_set_last_flush(struct log *this_)
106 {
107 #ifdef HAVE_SYS_TIME_H
108         gettimeofday(&this_->last_flush, NULL);
109 #endif
110 }
111
112 static void
113 log_open(struct log *this_)
114 {
115         char *mode;
116         if (this_->overwrite)
117                 mode="w";
118         else
119                 mode="r+";
120         if (this_->mkdir)
121                 file_mkdir(this_->filename_ex2, 2);
122         this_->f=fopen(this_->filename_ex2, mode);
123         if (! this_->f)
124                 this_->f=fopen(this_->filename_ex2, "w");
125         if (! this_->f)
126                 return;
127         if (!this_->overwrite) 
128                 fseek(this_->f, 0, SEEK_END);
129         this_->empty = !ftell(this_->f);
130         log_set_last_flush(this_);
131 }
132
133 static void
134 log_close(struct log *this_)
135 {
136         if (! this_->f)
137                 return;
138         if (this_->trailer.len) 
139                 fwrite(this_->trailer.data, 1, this_->trailer.len, this_->f);
140         fflush(this_->f);
141         fclose(this_->f);
142         this_->f=NULL;
143 }
144
145 static void
146 log_flush(struct log *this_, enum log_flags flags)
147 {
148         long pos;
149         if (this_->lazy && !this_->f) {
150                 if (!this_->data.len)
151                         return;
152                 log_open(this_);
153         }
154         if (! this_->f)
155                 return;
156         if (this_->empty) {
157                 if (this_->header.len) 
158                         fwrite(this_->header.data, 1, this_->header.len, this_->f);
159                 if (this_->header.len || this_->data.len)
160                         this_->empty=0;
161         }
162         fwrite(this_->data.data, 1, this_->data.len, this_->f);
163 #ifndef HAVE_API_WIN32_BASE
164         if (flags & log_flag_truncate) {
165                 pos=ftell(this_->f);
166                 ftruncate(fileno(this_->f), pos);
167         }
168 #endif
169         if (this_->trailer.len) {
170                 pos=ftell(this_->f);
171                 if (pos > 0) {
172                         fwrite(this_->trailer.data, 1, this_->trailer.len, this_->f);
173                         fseek(this_->f, pos, SEEK_SET); 
174                 }
175         }
176         if (flags & log_flag_keep_pointer)
177                 fseek(this_->f, -this_->data.len, SEEK_CUR);
178         fflush(this_->f);
179         if (!(flags & log_flag_keep_buffer)) {
180                 g_free(this_->data.data);
181                 this_->data.data=NULL;
182                 this_->data.max_len=this_->data.len=0;
183         }
184         log_set_last_flush(this_);
185 }
186
187 static int
188 log_flush_required(struct log *this_)
189 {
190         return this_->data.len > this_->flush_size;
191 }
192
193
194 static void
195 log_change(struct log *this_)
196 {
197         log_flush(this_,0);
198         log_close(this_);
199         expand_filenames(this_);
200         if (! this_->lazy)
201                 log_open(this_);
202 }
203
204 static int
205 log_change_required(struct log *this_)
206 {
207         char buffer[4096];
208
209         strftime_localtime(buffer, 4096, this_->filename);
210         return (strcmp(this_->filename_ex1, buffer) != 0);
211 }
212
213 static void
214 log_timer(struct log *this_)
215 {
216 #ifdef HAVE_SYS_TIME_H
217         struct timeval tv;
218         int delta;
219         gettimeofday(&tv, NULL);
220         delta=(tv.tv_sec-this_->last_flush.tv_sec)*1000+(tv.tv_usec-this_->last_flush.tv_usec)/1000;
221         dbg(1,"delta=%d flush_time=%d\n", delta, this_->flush_time);
222         if (this_->flush_time && delta >= this_->flush_time*1000)
223                 log_flush(this_,0);
224 #endif
225 }
226
227 int
228 log_get_attr(struct log *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
229 {
230         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
231 }
232
233
234 struct log *
235 log_new(struct attr * parent,struct attr **attrs)
236 {
237         struct log *ret=g_new0(struct log, 1);
238         struct attr *data,*overwrite,*lazy,*mkdir,*flush_size,*flush_time;
239         struct file_wordexp *wexp;
240         char *filename, **wexp_data;
241
242         dbg(1,"enter\n");
243         data=attr_search(attrs, NULL, attr_data);
244         if (! data)
245                 return NULL;
246         filename=data->u.str;
247         wexp=file_wordexp_new(filename);
248         if (wexp && file_wordexp_get_count(wexp) > 0) {
249                 wexp_data=file_wordexp_get_array(wexp);
250                 filename=wexp_data[0];
251         }
252         if (filename)
253                 ret->filename=g_strdup(filename);
254         if (wexp)
255                 file_wordexp_destroy(wexp);
256         overwrite=attr_search(attrs, NULL, attr_overwrite);
257         if (overwrite)
258                 ret->overwrite=overwrite->u.num;
259         lazy=attr_search(attrs, NULL, attr_lazy);
260         if (lazy)
261                 ret->lazy=lazy->u.num;
262         mkdir=attr_search(attrs, NULL, attr_mkdir);
263         if (mkdir)
264                 ret->mkdir=mkdir->u.num;
265         flush_size=attr_search(attrs, NULL, attr_flush_size);
266         if (flush_size)
267                 ret->flush_size=flush_size->u.num;
268         flush_time=attr_search(attrs, NULL, attr_flush_time);
269         if (flush_time)
270                 ret->flush_time=flush_time->u.num;
271         if (ret->flush_time) {
272                 dbg(1,"interval %d\n", ret->flush_time*1000);
273                 ret->timer_callback=callback_new_1(callback_cast(log_timer), ret);
274                 ret->timer=event_add_timeout(ret->flush_time*1000, 1, ret->timer_callback);
275         }
276         expand_filenames(ret);
277         if (ret->lazy)
278                 log_set_last_flush(ret);
279         else
280                 log_open(ret);
281         ret->attrs=attr_list_dup(attrs);
282         return ret;
283 }
284
285 void
286 log_set_header(struct log *this_, char *data, int len)
287 {
288         this_->header.data=g_malloc(len);
289         this_->header.max_len=this_->header.len=len;
290         memcpy(this_->header.data, data, len);
291 }
292
293 void
294 log_set_trailer(struct log *this_, char *data, int len)
295 {
296         this_->trailer.data=g_malloc(len);
297         this_->trailer.max_len=this_->trailer.len=len;
298         memcpy(this_->trailer.data, data, len);
299 }
300
301 void
302 log_write(struct log *this_, char *data, int len, enum log_flags flags)
303 {
304         dbg(1,"enter\n");
305         if (log_change_required(this_)) {
306                 dbg(1,"log_change");
307                 log_change(this_);
308         }
309         if (flags & log_flag_replace_buffer)
310                 this_->data.len=0;
311         if (this_->data.len + len > this_->data.max_len) {
312                 dbg(2,"overflow\n");
313                 this_->data.max_len+=16384;
314                 this_->data.data=g_realloc(this_->data.data,this_->data.max_len);
315         }
316         memcpy(this_->data.data+this_->data.len, data, len);
317         this_->data.len+=len;
318         if (log_flush_required(this_) || (flags & log_flag_force_flush))
319                 log_flush(this_, flags);
320 }
321
322 void *
323 log_get_buffer(struct log *this_, int *len)
324 {
325         if (len)
326                 *len=this_->data.len;
327         return this_->data.data;
328 }
329
330
331 void
332 log_printf(struct log *this_, char *fmt, ...)
333 {
334         char buffer[LOG_BUFFER_SIZE];
335         int size;
336         va_list ap;
337
338         va_start(ap, fmt);
339
340         // Format the string and write it to the log
341         size = g_vsnprintf(buffer, LOG_BUFFER_SIZE, fmt, ap);
342         log_write(this_, buffer, size, 0);
343
344         va_end(ap);
345 }
346
347 void
348 log_destroy(struct log *this_)
349 {
350         attr_list_free(this_->attrs);
351         callback_destroy(this_->timer_callback);
352         event_remove_timeout(this_->timer);
353         log_flush(this_,0);
354         log_close(this_);
355         g_free(this_);
356 }