Updated Turkish translation
[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 buffer[4096];
77         int i;
78
79         strftime_localtime(buffer, 4096, this_->filename);
80         this_->filename_ex1=g_strdup(buffer);
81         if (strstr(this_->filename_ex1,"%i")) {
82                 i=0;
83                 do {
84                         g_free(this_->filename_ex2);
85                         this_->filename_ex2=g_strdup_printf(this_->filename_ex1,i++);
86                 } while (file_exists(this_->filename_ex2));
87         } else 
88                 this_->filename_ex2=g_strdup(this_->filename_ex1);
89 }
90
91 static void
92 log_set_last_flush(struct log *this_)
93 {
94         gettimeofday(&this_->last_flush, NULL);
95 }
96
97 static void
98 log_open(struct log *this_)
99 {
100         char *mode;
101         if (this_->overwrite)
102                 mode="w";
103         else
104                 mode="r+";
105         if (this_->mkdir)
106                 file_mkdir(this_->filename_ex2, 2);
107         this_->f=fopen(this_->filename_ex2, mode);
108         if (! this_->f)
109                 this_->f=fopen(this_->filename_ex2, "w");
110         if (! this_->f)
111                 return;
112         if (!this_->overwrite) 
113                 fseek(this_->f, 0, SEEK_END);
114         this_->empty = !ftell(this_->f);
115         log_set_last_flush(this_);
116 }
117
118 static void
119 log_close(struct log *this_)
120 {
121         if (! this_->f)
122                 return;
123         if (this_->trailer.len) 
124                 fwrite(this_->trailer.data, 1, this_->trailer.len, this_->f);
125         fflush(this_->f);
126         fclose(this_->f);
127         this_->f=NULL;
128 }
129
130 static void
131 log_flush(struct log *this_)
132 {
133         long pos;
134         if (this_->lazy && !this_->f) {
135                 if (!this_->data.len)
136                         return;
137                 log_open(this_);
138         }
139         if (! this_->f)
140                 return;
141         if (this_->empty) {
142                 if (this_->header.len) 
143                         fwrite(this_->header.data, 1, this_->header.len, this_->f);
144                 if (this_->header.len || this_->data.len)
145                         this_->empty=0;
146         }
147         fwrite(this_->data.data, 1, this_->data.len, this_->f);
148         if (this_->trailer.len) {
149                 pos=ftell(this_->f);
150                 if (pos > 0) {
151                         fwrite(this_->trailer.data, 1, this_->trailer.len, this_->f);
152                         fseek(this_->f, pos, SEEK_SET); 
153                 }
154         }
155         
156         fflush(this_->f);
157         g_free(this_->data.data);
158         this_->data.data=NULL;
159         this_->data.max_len=this_->data.len=0;
160         log_set_last_flush(this_);
161 }
162
163 static int
164 log_flush_required(struct log *this_)
165 {
166         return this_->data.len > this_->flush_size;
167 }
168
169
170 static void
171 log_change(struct log *this_)
172 {
173         log_flush(this_);
174         log_close(this_);
175         expand_filenames(this_);
176         if (! this_->lazy)
177                 log_open(this_);
178 }
179
180 static int
181 log_change_required(struct log *this_)
182 {
183         char buffer[4096];
184
185         strftime_localtime(buffer, 4096, this_->filename);
186         return (strcmp(this_->filename_ex1, buffer) != 0);
187 }
188
189 static void
190 log_timer(struct log *this_)
191 {
192         struct timeval tv;
193         int delta;
194         gettimeofday(&tv, NULL);
195         delta=(tv.tv_sec-this_->last_flush.tv_sec)*1000+(tv.tv_usec-this_->last_flush.tv_usec)/1000;
196         dbg(1,"delta=%d flush_time=%d\n", delta, this_->flush_time);
197         if (this_->flush_time && delta >= this_->flush_time*1000)
198                 log_flush(this_);
199 }
200
201 int
202 log_get_attr(struct log *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
203 {
204         return attr_generic_get_attr(this_->attrs, NULL, type, attr, iter);
205 }
206
207
208 struct log *
209 log_new(struct attr * parent,struct attr **attrs)
210 {
211         struct log *ret=g_new0(struct log, 1);
212         struct attr *data,*overwrite,*lazy,*mkdir,*flush_size,*flush_time;
213         struct file_wordexp *wexp;
214         char *filename, **wexp_data;
215
216         dbg(1,"enter\n");
217         data=attr_search(attrs, NULL, attr_data);
218         if (! data)
219                 return NULL;
220         filename=data->u.str;
221         wexp=file_wordexp_new(filename);
222         if (wexp && file_wordexp_get_count(wexp) > 0) {
223                 wexp_data=file_wordexp_get_array(wexp);
224                 filename=wexp_data[0];
225         }
226         if (filename)
227                 ret->filename=g_strdup(filename);
228         if (wexp)
229                 file_wordexp_destroy(wexp);
230         overwrite=attr_search(attrs, NULL, attr_overwrite);
231         if (overwrite)
232                 ret->overwrite=overwrite->u.num;
233         lazy=attr_search(attrs, NULL, attr_lazy);
234         if (lazy)
235                 ret->lazy=lazy->u.num;
236         mkdir=attr_search(attrs, NULL, attr_mkdir);
237         if (mkdir)
238                 ret->mkdir=mkdir->u.num;
239         flush_size=attr_search(attrs, NULL, attr_flush_size);
240         if (flush_size)
241                 ret->flush_size=flush_size->u.num;
242         flush_time=attr_search(attrs, NULL, attr_flush_time);
243         if (flush_time)
244                 ret->flush_time=flush_time->u.num;
245         if (ret->flush_time) {
246                 dbg(1,"interval %d\n", ret->flush_time*1000);
247                 ret->timer_callback=callback_new_1(callback_cast(log_timer), ret);
248                 ret->timer=event_add_timeout(ret->flush_time*1000, 1, ret->timer_callback);
249         }
250         expand_filenames(ret);
251         if (ret->lazy)
252                 log_set_last_flush(ret);
253         else
254                 log_open(ret);
255         ret->attrs=attr_list_dup(attrs);
256         return ret;
257 }
258
259 void
260 log_set_header(struct log *this_, char *data, int len)
261 {
262         this_->header.data=g_malloc(len);
263         this_->header.max_len=this_->header.len=len;
264         memcpy(this_->header.data, data, len);
265 }
266
267 void
268 log_set_trailer(struct log *this_, char *data, int len)
269 {
270         this_->trailer.data=g_malloc(len);
271         this_->trailer.max_len=this_->trailer.len=len;
272         memcpy(this_->trailer.data, data, len);
273 }
274
275 void
276 log_write(struct log *this_, char *data, int len)
277 {
278         dbg(1,"enter\n");
279         if (log_change_required(this_)) {
280                 dbg(1,"log_change");
281                 log_change(this_);
282         }
283         if (this_->data.len + len > this_->data.max_len) {
284                 dbg(2,"overflow\n");
285                 this_->data.max_len+=16384;
286                 this_->data.data=g_realloc(this_->data.data,this_->data.max_len);
287         }
288         memcpy(this_->data.data+this_->data.len, data, len);
289         this_->data.len+=len;
290         if (log_flush_required(this_))
291                 log_flush(this_);
292 }
293
294 void
295 log_printf(struct log *this_, char *fmt, ...)
296 {
297         char buffer[LOG_BUFFER_SIZE];
298         int size;
299         va_list ap;
300
301         va_start(ap, fmt);
302
303         // Format the string and write it to the log
304         size = vsnprintf(buffer, LOG_BUFFER_SIZE, fmt, ap);
305         log_write(this_, buffer, size);
306
307         va_end(ap);
308 }
309
310 void
311 log_destroy(struct log *this_)
312 {
313         callback_destroy(this_->timer_callback);
314         event_remove_timeout(this_->timer);
315         log_flush(this_);
316         log_close(this_);
317         g_free(this_);
318 }