Replaces commit 44e3708cdb204782d728ddd6a40dec230bb9299c
[monky] / src / timeinfo.c
index 0a88fe8..0513e9b 100644 (file)
@@ -10,7 +10,7 @@
  * Please see COPYING for details
  *
  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
- * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
+ * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al.
  *     (see AUTHORS)
  * All rights reserved.
  *
  *
  */
 
+#include "conky.h"
 #include "text_object.h"
 #include <locale.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <logging.h>
+
+char print_times_in_seconds = 0;
+
+struct tztime_s {
+       char *tz;       /* timezone variable */
+       char *fmt;      /* time display formatting */
+};
+
+void set_times_in_seconds(char val)
+{
+       print_times_in_seconds = val;
+}
+
+char times_in_seconds(void)
+{
+       return print_times_in_seconds;
+}
 
 void scan_time(struct text_object *obj, const char *arg)
 {
-       obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
+       obj->data.opaque = strndup(arg ? arg : "%F %T", text_buffer_size);
 }
 
 void scan_tztime(struct text_object *obj, const char *arg)
 {
        char buf1[256], buf2[256], *fmt, *tz;
+       struct tztime_s *ts;
 
        fmt = tz = NULL;
        if (arg) {
@@ -46,14 +69,17 @@ void scan_tztime(struct text_object *obj, const char *arg)
 
                switch (nArgs) {
                        case 2:
-                               tz = buf1;
-                       case 1:
                                fmt = buf2;
+                       case 1:
+                               tz = buf1;
                }
        }
 
-       obj->data.tztime.fmt = strndup(fmt ? fmt : "%F %T", text_buffer_size);
-       obj->data.tztime.tz = tz ? strndup(tz, text_buffer_size) : NULL;
+       ts = malloc(sizeof(struct tztime_s));
+       memset(ts, 0, sizeof(struct tztime_s));
+       ts->fmt = strndup(fmt ? fmt : "%F %T", text_buffer_size);
+       ts->tz = tz ? strndup(tz, text_buffer_size) : NULL;
+       obj->data.opaque = ts;
 }
 
 void print_time(struct text_object *obj, char *p, int p_max_size)
@@ -62,7 +88,7 @@ void print_time(struct text_object *obj, char *p, int p_max_size)
        struct tm *tm = localtime(&t);
 
        setlocale(LC_TIME, "");
-       strftime(p, p_max_size, obj->data.s, tm);
+       strftime(p, p_max_size, (char *)obj->data.opaque, tm);
 }
 
 void print_utime(struct text_object *obj, char *p, int p_max_size)
@@ -71,7 +97,7 @@ void print_utime(struct text_object *obj, char *p, int p_max_size)
        struct tm *tm = gmtime(&t);
 
        setlocale(LC_TIME, "");
-       strftime(p, p_max_size, obj->data.s, tm);
+       strftime(p, p_max_size, (char *)obj->data.opaque, tm);
 }
 
 void print_tztime(struct text_object *obj, char *p, int p_max_size)
@@ -79,17 +105,21 @@ void print_tztime(struct text_object *obj, char *p, int p_max_size)
        char *oldTZ = NULL;
        time_t t;
        struct tm *tm;
+       struct tztime_s *ts = obj->data.opaque;
+
+       if (!ts)
+               return;
 
-       if (obj->data.tztime.tz) {
+       if (ts->tz) {
                oldTZ = getenv("TZ");
-               setenv("TZ", obj->data.tztime.tz, 1);
+               setenv("TZ", ts->tz, 1);
                tzset();
        }
        t = time(NULL);
        tm = localtime(&t);
 
        setlocale(LC_TIME, "");
-       strftime(p, p_max_size, obj->data.tztime.fmt, tm);
+       strftime(p, p_max_size, ts->fmt, tm);
        if (oldTZ) {
                setenv("TZ", oldTZ, 1);
                tzset();
@@ -101,20 +131,177 @@ void print_tztime(struct text_object *obj, char *p, int p_max_size)
 
 void free_time(struct text_object *obj)
 {
-       if (!obj->data.s)
+       if (!obj->data.opaque)
                return;
-       free(obj->data.s);
-       obj->data.s = NULL;
+       free(obj->data.opaque);
+       obj->data.opaque = NULL;
 }
 
 void free_tztime(struct text_object *obj)
 {
-       if (obj->data.tztime.tz) {
-               free(obj->data.tztime.tz);
-               obj->data.tztime.tz = NULL;
+       struct tztime_s *ts = obj->data.opaque;
+
+       if (!ts)
+               return;
+
+       if (ts->tz)
+               free(ts->tz);
+       if (ts->fmt)
+               free(ts->fmt);
+
+       free(obj->data.opaque);
+       obj->data.opaque = NULL;
+}
+
+//all chars after the ending " and between the seconds and the starting " are silently
+//ignored, this is wanted behavior, not a bug, so don't "fix" this.
+void print_format_time(struct text_object *obj, char *p, unsigned int p_max_size) {
+       double seconds;
+       char *currentchar, *temp;
+       unsigned int output_length = 0;
+       int minutes, hours, days, weeks;
+       char show_minutes = 0, show_hours = 0, show_days = 0, show_weeks = 0, hidestring;
+
+       if (!times_in_seconds()) {
+               NORM_ERR("Enable \"times_in_seconds\" to use $format_time");
+               return;
        }
-       if (obj->data.tztime.fmt) {
-               free(obj->data.tztime.fmt);
-               obj->data.tztime.fmt = NULL;
+
+       errno = 0;
+       seconds = strtod(obj->data.s, &currentchar);
+       if(errno == 0 && obj->data.s != currentchar) {
+               while(*currentchar != 0 && *currentchar != '"') {
+                       currentchar++;
+               }
+               if(*currentchar != 0) {
+                       currentchar++;
+                       minutes = seconds / 60;
+                       seconds -= minutes * 60;
+                       hours = minutes / 60;
+                       minutes %= 60;
+                       days = hours / 24;
+                       hours %= 24;
+                       weeks = days / 7;
+                       days %= 7;
+                       for(temp = currentchar; *temp != 0 && *temp != '"'; temp++) {
+                               if(*temp=='\\') {
+                                       switch(*(temp+1)) {
+                                       case '\\':
+                                               temp++;
+                                               break;
+                                       case 'w':
+                                               show_weeks = 1;
+                                               break;
+                                       case 'd':
+                                               show_days = 1;
+                                               break;
+                                       case 'h':
+                                               show_hours = 1;
+                                               break;
+                                       case 'm':
+                                               show_minutes = 1;
+                                               break;
+                                       }
+                               }
+                       }
+                       if(show_weeks == 0) days += weeks * 7;
+                       if(show_days == 0) hours += days * 24;
+                       if(show_hours == 0) minutes += hours * 60;
+                       if(show_minutes == 0) seconds += minutes * 60;
+                       hidestring = 0;
+                       while(output_length < p_max_size - 1) {
+                               if(*currentchar != 0 && *currentchar != '"') {
+                                       temp = NULL;
+                                       if(*currentchar == '\\' && hidestring == 0) {
+                                               currentchar++;
+                                               switch(*currentchar){
+                                               case 'w':
+                                                       asprintf(&temp, "%d", weeks);
+                                                       break;
+                                               case 'd':
+                                                       asprintf(&temp, "%d", days);
+                                                       break;
+                                               case 'h':
+                                                       asprintf(&temp, "%d", hours);
+                                                       break;
+                                               case 'm':
+                                                       asprintf(&temp, "%d", minutes);
+                                                       break;
+                                               case 's':
+                                                       asprintf(&temp, "%d", (int) seconds);
+                                                       break;
+                                               case 'S':
+                                                       currentchar++;
+                                                       if(*currentchar >= '0' && *currentchar <= '9') {
+                                                               asprintf(&temp, "%.*f", (*currentchar) - '0', seconds);
+                                                       } else if(*currentchar == 'x') {
+                                                               if(seconds == (int) seconds ) {
+                                                                       asprintf(&temp, "%d", (int) seconds);
+                                                               } else {
+                                                                       asprintf(&temp, "%.9f", seconds);
+                                                                       while(*(temp + strlen(temp) - 1) == '0' || *(temp + strlen(temp) - 1) == '.') {
+                                                                               *(temp + strlen(temp) - 1) = 0;
+                                                                       }
+                                                               }
+                                                       }else{
+                                                               currentchar--;
+                                                               NORM_ERR("$format_time needs a digit behind 'S' to specify precision")
+                                                       }
+                                                       break;
+                                               case '\\':
+                                               case '(':
+                                               case ')':
+                                                       p[output_length] = *currentchar;
+                                                       output_length++;
+                                                       break;
+                                               default:
+                                                       NORM_ERR("$format_time doesn't have a special char '%c'", *currentchar)
+                                               }
+                                       } else if(*currentchar == '(') {
+                                               for(temp = currentchar + 1; *temp != 0 && *temp != ')'; temp++) {
+                                                       if(*(temp-1) == '\\') {
+                                                               switch(*temp) {
+                                                               case 'w':
+                                                                       if(weeks == 0) hidestring = 1;
+                                                                       break;
+                                                               case 'd':
+                                                                       if(days == 0) hidestring = 1;
+                                                                       break;
+                                                               case 'h':
+                                                                       if(hours == 0) hidestring = 1;
+                                                                       break;
+                                                               case 'm':
+                                                                       if(minutes == 0) hidestring = 1;
+                                                                       break;
+                                                               case 's':
+                                                               case 'S':
+                                                                       if(seconds == 0) hidestring = 1;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               temp = NULL;
+                                       } else if(*currentchar == ')') {
+                                               hidestring = 0;
+                                       } else if(hidestring == 0) {
+                                               p[output_length] = *currentchar;
+                                               output_length++;
+                                       }
+                                       if(temp) {
+                                               if(output_length + strlen(temp) < p_max_size - 1) {
+                                                       strcpy(p + output_length, temp);
+                                                       output_length += strlen(temp);
+                                               } else NORM_ERR("The format string for $format_time is too long")
+                                               free(temp);
+                                       }
+                                       currentchar++;
+                               } else break;
+                       }
+                       p[output_length] = 0;
+               } else {
+                       NORM_ERR("$format_time needs a output-format starting with a \"-char as 2nd argument")
+               }
+       } else {
+               NORM_ERR("$format_time didn't receive a time in seconds as first argument")
        }
 }