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