Add:Core:Support for position_coord_geo parsing
[navit-package] / src / log.c
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <time.h>
7 #include <sys/time.h>
8 #include <glib.h>
9 #include "file.h"
10 #include "item.h"
11 #include "debug.h"
12 #include "log.h"
13
14 struct log_data {
15         int len;
16         int max_len;
17         char *data;
18 };
19
20 struct log {
21         FILE *f;
22         int overwrite;
23         int empty;
24         int flush_size;
25         int flush_time;
26         guint timer;
27         struct timeval last_flush;
28         char *filename;
29         char *filename_ex1;
30         char *filename_ex2;
31         struct log_data header;
32         struct log_data data;
33         struct log_data trailer;
34 };
35
36 static void
37 strftime_localtime(char *buffer, int size, char *fmt)
38 {
39         time_t t;
40         struct tm *tm;
41
42         t=time(NULL);
43         tm=localtime(&t);
44         strftime(buffer, 4096, fmt, tm);
45 }
46
47 static void
48 expand_filenames(struct log *this_)
49 {
50         char buffer[4096];
51         int i;
52
53         strftime_localtime(buffer, 4096, this_->filename);
54         this_->filename_ex1=g_strdup(buffer);
55         if (strstr(this_->filename_ex1,"%i")) {
56                 i=0;
57                 do {
58                         g_free(this_->filename_ex2);
59                         this_->filename_ex2=g_strdup_printf(this_->filename_ex1,i++);
60                 } while (file_exists(this_->filename_ex2));
61         } else 
62                 this_->filename_ex2=g_strdup(this_->filename_ex1);
63 }
64
65 static void
66 log_open(struct log *this_)
67 {
68         char *mode;
69         if (this_->overwrite)
70                 mode="w";
71         else
72                 mode="a";
73         this_->f=fopen(this_->filename_ex2, mode);
74         this_->empty = !ftell(this_->f);
75 }
76
77 static void
78 log_close(struct log *this_)
79 {
80         if (this_->trailer.len) 
81                 fwrite(this_->header.data, 1, this_->trailer.len, this_->f);
82         fflush(this_->f);
83         fclose(this_->f);
84         this_->f=NULL;
85 }
86
87 static void
88 log_flush(struct log *this_)
89 {
90         if (this_->empty) {
91                 if (this_->header.len) 
92                         fwrite(this_->header.data, 1, this_->header.len, this_->f);
93                 if (this_->header.len || this_->data.len)
94                         this_->empty=0;
95         }
96         fwrite(this_->data.data, 1, this_->data.len, this_->f);
97         fflush(this_->f);
98         g_free(this_->data.data);
99         this_->data.data=NULL;
100         this_->data.max_len=this_->data.len=0;
101         gettimeofday(&this_->last_flush, NULL);
102 }
103
104 static int
105 log_flush_required(struct log *this_)
106 {
107         return this_->data.len > this_->flush_size;
108 }
109
110
111 static void
112 log_change(struct log *this_)
113 {
114         log_flush(this_);
115         log_close(this_);
116         log_open(this_);
117 }
118
119 static int
120 log_change_required(struct log *this_)
121 {
122         char buffer[4096];
123
124         strftime_localtime(buffer, 4096, this_->filename);
125         return (strcmp(this_->filename_ex1, buffer) != 0);
126 }
127
128 static gboolean
129 log_timer(gpointer data)
130 {
131         struct log *this_=data;
132         struct timeval tv;
133         int delta;
134         gettimeofday(&tv, NULL);
135         delta=(tv.tv_sec-this_->last_flush.tv_sec)*1000+(tv.tv_usec-this_->last_flush.tv_usec)/1000;
136         if (this_->flush_time && delta > this_->flush_time*1000)
137                 log_flush(this_);
138         
139         return TRUE;
140 }
141
142 struct log *
143 log_new(struct attr **attrs)
144 {
145         struct log *ret=g_new0(struct log, 1);
146         struct attr *data,*overwrite,*flush_size,*flush_time;
147
148         dbg(1,"enter\n");
149         data=attr_search(attrs, NULL, attr_data);
150         if (! data)
151                 return NULL;
152         ret->filename=g_strdup(data->u.str);
153         overwrite=attr_search(attrs, NULL, attr_overwrite);
154         if (overwrite)
155                 ret->overwrite=overwrite->u.num;
156         flush_size=attr_search(attrs, NULL, attr_flush_size);
157         if (flush_size)
158                 ret->flush_size=flush_size->u.num;
159         flush_time=attr_search(attrs, NULL, attr_flush_time);
160         if (flush_time)
161                 ret->flush_time=flush_time->u.num;
162         if (ret->flush_time) 
163                 ret->timer=g_timeout_add(ret->flush_time*1000, log_timer, ret);
164         expand_filenames(ret);
165         log_open(ret);
166         return ret;
167 }
168
169 void
170 log_set_header(struct log *this_, char *data, int len)
171 {
172         this_->header.data=g_malloc(len);
173         this_->header.max_len=this_->header.len=len;
174         memcpy(this_->header.data, data, len);
175 }
176
177 void
178 log_set_trailer(struct log *this_, char *data, int len)
179 {
180         this_->trailer.data=g_malloc(len);
181         this_->trailer.max_len=this_->trailer.len=len;
182         memcpy(this_->trailer.data, data, len);
183 }
184
185 void
186 log_write(struct log *this_, char *data, int len)
187 {
188         dbg(1,"enter\n");
189         if (log_change_required(this_)) 
190                 log_change(this_);
191         if (this_->data.len + len > this_->data.max_len) {
192                 dbg(2,"overflow\n");
193                 this_->data.max_len+=16384;
194                 this_->data.data=g_realloc(this_->data.data,this_->data.max_len);
195         }
196         memcpy(this_->data.data+this_->data.len, data, len);
197         this_->data.len+=len;
198         if (log_flush_required(this_))
199                 log_flush(this_);
200 }
201
202 void
203 log_destroy(struct log *this_)
204 {
205         if (this_->timer)
206                 g_source_remove(this_->timer);
207         log_flush(this_);
208         log_close(this_);
209         g_free(this_);
210 }