Allow method to pass execgraph arguments containing spaces.
[monky] / src / timeinfo.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  * vim: ts=4 sw=4 noet ai cindent syntax=c
3  *
4  * Conky, a system monitor, based on torsmo
5  *
6  * Any original torsmo code is licensed under the BSD license
7  *
8  * All code written since the fork of torsmo is licensed under the GPL
9  *
10  * Please see COPYING for details
11  *
12  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
13  * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
14  *      (see AUTHORS)
15  * All rights reserved.
16  *
17  * This program is free software: you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation, either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * You should have received a copy of the GNU General Public License
27  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28  *
29  */
30
31 #include "conky.h"
32 #include "text_object.h"
33 #include <locale.h>
34 #include <string.h>
35 #include <time.h>
36 #include <errno.h>
37 #include <logging.h>
38
39 char print_times_in_seconds = 0;
40
41 struct tztime_s {
42         char *tz;       /* timezone variable */
43         char *fmt;      /* time display formatting */
44 };
45
46 void set_times_in_seconds(char val)
47 {
48         print_times_in_seconds = val;
49 }
50
51 char times_in_seconds(void)
52 {
53         return print_times_in_seconds;
54 }
55
56 void scan_time(struct text_object *obj, const char *arg)
57 {
58         obj->data.opaque = strndup(arg ? arg : "%F %T", text_buffer_size);
59 }
60
61 void scan_tztime(struct text_object *obj, const char *arg)
62 {
63         char buf1[256], buf2[256], *fmt, *tz;
64         struct tztime_s *ts;
65
66         fmt = tz = NULL;
67         if (arg) {
68                 int nArgs = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
69
70                 switch (nArgs) {
71                         case 2:
72                                 fmt = buf2;
73                         case 1:
74                                 tz = buf1;
75                 }
76         }
77
78         ts = malloc(sizeof(struct tztime_s));
79         memset(ts, 0, sizeof(struct tztime_s));
80         ts->fmt = strndup(fmt ? fmt : "%F %T", text_buffer_size);
81         ts->tz = tz ? strndup(tz, text_buffer_size) : NULL;
82         obj->data.opaque = ts;
83 }
84
85 void print_time(struct text_object *obj, char *p, int p_max_size)
86 {
87         time_t t = time(NULL);
88         struct tm *tm = localtime(&t);
89
90         setlocale(LC_TIME, "");
91         strftime(p, p_max_size, (char *)obj->data.opaque, tm);
92 }
93
94 void print_utime(struct text_object *obj, char *p, int p_max_size)
95 {
96         time_t t = time(NULL);
97         struct tm *tm = gmtime(&t);
98
99         setlocale(LC_TIME, "");
100         strftime(p, p_max_size, (char *)obj->data.opaque, tm);
101 }
102
103 void print_tztime(struct text_object *obj, char *p, int p_max_size)
104 {
105         char *oldTZ = NULL;
106         time_t t;
107         struct tm *tm;
108         struct tztime_s *ts = obj->data.opaque;
109
110         if (!ts)
111                 return;
112
113         if (ts->tz) {
114                 oldTZ = getenv("TZ");
115                 setenv("TZ", ts->tz, 1);
116                 tzset();
117         }
118         t = time(NULL);
119         tm = localtime(&t);
120
121         setlocale(LC_TIME, "");
122         strftime(p, p_max_size, ts->fmt, tm);
123         if (oldTZ) {
124                 setenv("TZ", oldTZ, 1);
125                 tzset();
126         } else {
127                 unsetenv("TZ");
128         }
129         // Needless to free oldTZ since getenv gives ptr to static data
130 }
131
132 void free_time(struct text_object *obj)
133 {
134         if (!obj->data.opaque)
135                 return;
136         free(obj->data.opaque);
137         obj->data.opaque = NULL;
138 }
139
140 void free_tztime(struct text_object *obj)
141 {
142         struct tztime_s *ts = obj->data.opaque;
143
144         if (!ts)
145                 return;
146
147         if (ts->tz)
148                 free(ts->tz);
149         if (ts->fmt)
150                 free(ts->fmt);
151
152         free(obj->data.opaque);
153         obj->data.opaque = NULL;
154 }
155
156 //all chars after the ending " and between the seconds and the starting " are silently
157 //ignored, this is wanted behavior, not a bug, so don't "fix" this.
158 void print_format_time(struct text_object *obj, char *p, unsigned int p_max_size) {
159         double seconds;
160         char *currentchar, *temp;
161         unsigned int output_length = 0;
162         int minutes, hours, days, weeks;
163         char show_minutes = 0, show_hours = 0, show_days = 0, show_weeks = 0, hidestring;
164
165         if (!times_in_seconds()) {
166                 NORM_ERR("Enable \"times_in_seconds\" to use $format_time");
167                 return;
168         }
169
170         errno = 0;
171         seconds = strtod(obj->data.s, &currentchar);
172         if(errno == 0 && obj->data.s != currentchar) {
173                 while(*currentchar != 0 && *currentchar != '"') {
174                         currentchar++;
175                 }
176                 if(*currentchar != 0) {
177                         currentchar++;
178                         minutes = seconds / 60;
179                         seconds -= minutes * 60;
180                         hours = minutes / 60;
181                         minutes %= 60;
182                         days = hours / 24;
183                         hours %= 24;
184                         weeks = days / 7;
185                         days %= 7;
186                         for(temp = currentchar; *temp != 0 && *temp != '"'; temp++) {
187                                 if(*temp=='\\') {
188                                         switch(*(temp+1)) {
189                                         case '\\':
190                                                 temp++;
191                                                 break;
192                                         case 'w':
193                                                 show_weeks = 1;
194                                                 break;
195                                         case 'd':
196                                                 show_days = 1;
197                                                 break;
198                                         case 'h':
199                                                 show_hours = 1;
200                                                 break;
201                                         case 'm':
202                                                 show_minutes = 1;
203                                                 break;
204                                         }
205                                 }
206                         }
207                         if(show_weeks == 0) days += weeks * 7;
208                         if(show_days == 0) hours += days * 24;
209                         if(show_hours == 0) minutes += hours * 60;
210                         if(show_minutes == 0) seconds += minutes * 60;
211                         hidestring = 0;
212                         while(output_length < p_max_size - 1) {
213                                 if(*currentchar != 0 && *currentchar != '"') {
214                                         temp = NULL;
215                                         if(*currentchar == '\\' && hidestring == 0) {
216                                                 currentchar++;
217                                                 switch(*currentchar){
218                                                 case 'w':
219                                                         asprintf(&temp, "%d", weeks);
220                                                         break;
221                                                 case 'd':
222                                                         asprintf(&temp, "%d", days);
223                                                         break;
224                                                 case 'h':
225                                                         asprintf(&temp, "%d", hours);
226                                                         break;
227                                                 case 'm':
228                                                         asprintf(&temp, "%d", minutes);
229                                                         break;
230                                                 case 's':
231                                                         asprintf(&temp, "%d", (int) seconds);
232                                                         break;
233                                                 case 'S':
234                                                         currentchar++;
235                                                         if(*currentchar >= '0' && *currentchar <= '9') {
236                                                                 asprintf(&temp, "%.*f", (*currentchar) - '0', seconds);
237                                                         } else if(*currentchar == 'x') {
238                                                                 if(seconds == (int) seconds ) {
239                                                                         asprintf(&temp, "%d", (int) seconds);
240                                                                 } else {
241                                                                         asprintf(&temp, "%.9f", seconds);
242                                                                         while(*(temp + strlen(temp) - 1) == '0' || *(temp + strlen(temp) - 1) == '.') {
243                                                                                 *(temp + strlen(temp) - 1) = 0;
244                                                                         }
245                                                                 }
246                                                         }else{
247                                                                 currentchar--;
248                                                                 NORM_ERR("$format_time needs a digit behind 'S' to specify precision")
249                                                         }
250                                                         break;
251                                                 case '\\':
252                                                 case '(':
253                                                 case ')':
254                                                         p[output_length] = *currentchar;
255                                                         output_length++;
256                                                         break;
257                                                 default:
258                                                         NORM_ERR("$format_time doesn't have a special char '%c'", *currentchar)
259                                                 }
260                                         } else if(*currentchar == '(') {
261                                                 for(temp = currentchar + 1; *temp != 0 && *temp != ')'; temp++) {
262                                                         if(*(temp-1) == '\\') {
263                                                                 switch(*temp) {
264                                                                 case 'w':
265                                                                         if(weeks == 0) hidestring = 1;
266                                                                         break;
267                                                                 case 'd':
268                                                                         if(days == 0) hidestring = 1;
269                                                                         break;
270                                                                 case 'h':
271                                                                         if(hours == 0) hidestring = 1;
272                                                                         break;
273                                                                 case 'm':
274                                                                         if(minutes == 0) hidestring = 1;
275                                                                         break;
276                                                                 case 's':
277                                                                 case 'S':
278                                                                         if(seconds == 0) hidestring = 1;
279                                                                         break;
280                                                                 }
281                                                         }
282                                                 }
283                                                 temp = NULL;
284                                         } else if(*currentchar == ')') {
285                                                 hidestring = 0;
286                                         } else if(hidestring == 0) {
287                                                 p[output_length] = *currentchar;
288                                                 output_length++;
289                                         }
290                                         if(temp) {
291                                                 if(output_length + strlen(temp) < p_max_size - 1) {
292                                                         strcpy(p + output_length, temp);
293                                                         output_length += strlen(temp);
294                                                 } else NORM_ERR("The format string for $format_time is too long")
295                                                 free(temp);
296                                         }
297                                         currentchar++;
298                                 } else break;
299                         }
300                         p[output_length] = 0;
301                 } else {
302                         NORM_ERR("$format_time needs a output-format starting with a \"-char as 2nd argument")
303                 }
304         } else {
305                 NORM_ERR("$format_time didn't receive a time in seconds as first argument")
306         }
307 }