fix use of setlocale all over the place ...
[rrdtool.git] / src / rrd_graph.c
index ef51b7c..898b6ff 100644 (file)
@@ -337,6 +337,12 @@ int im_free(
         free(im->gdes[i].rpnp);
     }
     free(im->gdes);
+
+    for (i = 0; i < DIM(text_prop);i++){
+        pango_font_description_free(im->text_prop[i].font_desc);
+        im->text_prop[i].font_desc = NULL;
+    }
+
     if (im->font_options)
         cairo_font_options_destroy(im->font_options);
 
@@ -344,6 +350,8 @@ int im_free(
         status = cairo_status(im->cr);
         cairo_destroy(im->cr);
     }
+
+
     if (im->rendered_image) {
         free(im->rendered_image);
     }
@@ -2293,7 +2301,7 @@ int horizontal_log_grid(
                         }
                 }
                 else {
-                      sprintf(graph_label_right,im->second_axis_format,sval);
+                      sprintf(graph_label_right,im->second_axis_format,sval,"");
                 }
 
                 gfx_text ( im,
@@ -3983,15 +3991,18 @@ rrd_info_t *rrd_graph_v(
     char *old_locale;
     rrd_graph_init(&im);
     /* a dummy surface so that we can measure text sizes for placements */
-    old_locale = setlocale(LC_NUMERIC, "C");
+    old_locale = setlocale(LC_NUMERIC, NULL);
+    setlocale(LC_NUMERIC, "C");
     rrd_graph_options(argc, argv, &im);
     if (rrd_test_error()) {
+        setlocale(LC_NUMERIC, old_locale); /* reenable locale */
         rrd_info_free(im.grinfo);
         im_free(&im);
         return NULL;
     }
 
     if (optind >= argc) {
+        setlocale(LC_NUMERIC, old_locale); /* reenable locale */
         rrd_info_free(im.grinfo);
         im_free(&im);
         rrd_set_error("missing filename");
@@ -3999,6 +4010,7 @@ rrd_info_t *rrd_graph_v(
     }
 
     if (strlen(argv[optind]) >= MAXPATH) {
+        setlocale(LC_NUMERIC, old_locale); /* reenable locale */
         rrd_set_error("filename (including path) too long");
         rrd_info_free(im.grinfo);
         im_free(&im);
@@ -4068,6 +4080,8 @@ rrd_set_font_desc (
     if (font){
         strncpy(im->text_prop[prop].font, font, sizeof(text_prop[prop].font) - 1);
         im->text_prop[prop].font[sizeof(text_prop[prop].font) - 1] = '\0';
+        /* if we already got one, drop it first */
+        pango_font_description_free(im->text_prop[prop].font_desc);
         im->text_prop[prop].font_desc = pango_font_description_from_string( font );
     };
     if (size > 0){
@@ -4161,6 +4175,7 @@ void rrd_graph_init(
 
     for (i = 0; i < DIM(text_prop); i++) {
         im->text_prop[i].size = -1;
+        im->text_prop[i].font_desc = NULL;
         rrd_set_font_desc(im,i, deffont ? deffont : text_prop[i].font,text_prop[i].size);
     }
 
@@ -4175,6 +4190,7 @@ void rrd_graph_init(
     pango_cairo_update_context(im->cr,context);
 
     im->layout = pango_layout_new(context);
+    g_object_unref (context);
 
 //  im->layout = pango_cairo_create_layout(im->cr);
 
@@ -5232,44 +5248,119 @@ void grinfo_push(
     }
 }
 
+
 void time_clean(
     char *result,
     char *format)
 {
     int       j, jj;
     
+/*     Handling based on
+       - ANSI C99 Specifications                         http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
+       - Single UNIX Specification version 2             http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html 
+       - POSIX:2001/Single UNIX Specification version 3  http://www.opengroup.org/onlinepubs/009695399/functions/strftime.html
+       - POSIX:2008 Specifications                       http://www.opengroup.org/onlinepubs/9699919799/functions/strftime.html
+       Specifications tells 
+       "If a conversion specifier is not one of the above, the behavior is undefined."
+
+      C99 tells
+       "A conversion specifier consists of a % character, possibly followed by an E or O modifier character (described below), followed by a character that determines the behavior of the conversion specifier.
+
+      POSIX:2001 tells
+      "A conversion specification consists of a '%' character, possibly followed by an E or O modifier, and a terminating conversion specifier character that determines the conversion specification's behavior."
+
+      POSIX:2008 introduce more complexe behavior that are not handled here.
+
+      According to this, this code will replace:
+      - % followed by @ by a %@
+      - % followed by   by a %SPACE
+      - % followed by . by a %.
+      - % followed by % by a %
+      - % followed by t by a TAB
+      - % followed by E then anything by '-'
+      - % followed by O then anything by '-'
+      - % followed by anything else by at least one '-'. More characters may be added to better fit expected output length
+*/
+
     jj = 0;
-    for(j = 0; j < FMT_LEG_LEN - 1; j++) { /* we don't need to parse the last char */
+    for(j = 0; (j < FMT_LEG_LEN - 1) && (jj < FMT_LEG_LEN); j++) { /* we don't need to parse the last char */
         if (format[j] == '%') {
-            if ((format[j+1] == 'A') || (format[j+1] == 'a') ||
-                (format[j+1] == 'B') || (format[j+1] == 'b') ||
-                (format[j+1] == 'C') || (format[j+1] == 'c') ||
-                (format[j+1] == 'D') || (format[j+1] == 'd') ||
-                (format[j+1] == 'E') || (format[j+1] == 'e') ||
-                (format[j+1] == 'F') ||
-                (format[j+1] == 'G') || (format[j+1] == 'g') ||
-                (format[j+1] == 'H') || (format[j+1] == 'h') ||
-                (format[j+1] == 'I') ||
-                                        (format[j+1] == 'j') ||
-                                        (format[j+1] == 'k') ||
-                                        (format[j+1] == 'l') ||
-                (format[j+1] == 'M') || (format[j+1] == 'm') ||
-                (format[j+1] == 'O') ||
-                (format[j+1] == 'P') || (format[j+1] == 'p') ||
-                (format[j+1] == 'R') || (format[j+1] == 'r') ||
-                (format[j+1] == 'S') || (format[j+1] == 's') ||
-                (format[j+1] == 'T') ||
-                (format[j+1] == 'U') || (format[j+1] == 'u') ||
-                (format[j+1] == 'V') || (format[j+1] == 'v') ||
-                (format[j+1] == 'W') || (format[j+1] == 'w') ||
-                (format[j+1] == 'X') || (format[j+1] == 'x') ||
-                (format[j+1] == 'Y') || (format[j+1] == 'y') ||
-                (format[j+1] == 'Z') || (format[j+1] == 'z') ||
-                (format[j+1] == '+')) {
+            if ((format[j+1] == 'E') || (format[j+1] == 'O')) {
+                result[jj++] = '-';
+                j+=2; /* We skip next 2 following char */
+            } else if ((format[j+1] == 'C') || (format[j+1] == 'd') ||
+                       (format[j+1] == 'g') || (format[j+1] == 'H') ||
+                       (format[j+1] == 'I') || (format[j+1] == 'm') ||
+                       (format[j+1] == 'M') || (format[j+1] == 'S') ||
+                       (format[j+1] == 'U') || (format[j+1] == 'V') ||
+                       (format[j+1] == 'W') || (format[j+1] == 'y')) {
                 result[jj++] = '-';
+                if (jj < FMT_LEG_LEN) {
+                    result[jj++] = '-';
+                }
                 j++; /* We skip the following char */
-            } else if (format[j+1] == '%') {
-                result[jj++] = '%';
+            } else if (format[j+1] == 'j') {
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 1) {
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+               }
+                j++; /* We skip the following char */
+            } else if ((format[j+1] == 'G') || (format[j+1] == 'Y')) {
+                /* Assuming Year on 4 digit */
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 2) {
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == 'R') {
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 3) {
+                    result[jj++] = '-';
+                    result[jj++] = ':';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == 'T') {
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 6) {
+                    result[jj++] = '-';
+                    result[jj++] = ':';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = ':';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == 'F') {
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 8) {
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == 'D') {
+                result[jj++] = '-';
+                if (jj < FMT_LEG_LEN - 6) {
+                    result[jj++] = '-';
+                    result[jj++] = '/';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                    result[jj++] = '/';
+                    result[jj++] = '-';
+                    result[jj++] = '-';
+                }
                 j++; /* We skip the following char */
             } else if (format[j+1] == 'n') {
                 result[jj++] = '\r';
@@ -5278,11 +5369,33 @@ void time_clean(
             } else if (format[j+1] == 't') {
                 result[jj++] = '\t';
                 j++; /* We skip the following char */
+            } else if (format[j+1] == '%') {
+                result[jj++] = '%';
+                j++; /* We skip the following char */
+            } else if (format[j+1] == ' ') {
+                if (jj < FMT_LEG_LEN - 1) {
+                    result[jj++] = '%';
+                    result[jj++] = ' ';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == '.') {
+                if (jj < FMT_LEG_LEN - 1) {
+                    result[jj++] = '%';
+                    result[jj++] = '.';
+                }
+                j++; /* We skip the following char */
+            } else if (format[j+1] == '@') {
+                if (jj < FMT_LEG_LEN - 1) {
+                    result[jj++] = '%';
+                    result[jj++] = '@';
+                }
+                j++; /* We skip the following char */
             } else {
-                result[jj++] = format[j];
+                result[jj++] = '-';
+                j++; /* We skip the following char */
             }
         } else {
-            result[jj++] = format[j];
+                result[jj++] = format[j];
         }
     }
     result[jj] = '\0'; /* We must force the end of the string */