Revert "Uhh..ansohus"
[monky] / src / conky.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  * vim: ts=4 sw=4 noet ai cindent syntax=c
29  *
30  */
31
32 #include "config.h"
33 #include "text_object.h"
34 #include "conky.h"
35 #include "common.h"
36 #include <stdarg.h>
37 #include <math.h>
38 #include <time.h>
39 #include <locale.h>
40 #include <signal.h>
41 #include <errno.h>
42 #include <limits.h>
43 #if HAVE_DIRENT_H
44 #include <dirent.h>
45 #endif
46 #include <sys/time.h>
47 #include <sys/param.h>
48 #ifdef HAVE_SYS_INOTIFY_H
49 #include <sys/inotify.h>
50 #endif /* HAVE_SYS_INOTIFY_H */
51 #ifdef X11
52 #include "x11.h"
53 #include <X11/Xutil.h>
54 #ifdef HAVE_XDAMAGE
55 #include <X11/extensions/Xdamage.h>
56 #endif
57 #ifdef IMLIB2
58 #include "imlib2.h"
59 #endif /* IMLIB2 */
60 #endif /* X11 */
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <netinet/in.h>
64 #include <netdb.h>
65 #include <fcntl.h>
66 #include <getopt.h>
67 #ifdef NCURSES
68 #include <ncurses.h>
69 #endif
70 #ifdef XOAP
71 #include <libxml/parser.h>
72 #endif /* XOAP */
73
74 /* local headers */
75 #include "core.h"
76 #include "algebra.h"
77 #include "build.h"
78 #include "colours.h"
79 #include "diskio.h"
80 #ifdef X11
81 #include "fonts.h"
82 #endif
83 #include "fs.h"
84 #include "logging.h"
85 #include "mixer.h"
86 #include "mail.h"
87 #include "mboxscan.h"
88 #include "specials.h"
89 #include "temphelper.h"
90 #include "tailhead.h"
91 #include "top.h"
92
93 /* check for OS and include appropriate headers */
94 #if defined(__linux__)
95 #include "linux.h"
96 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
97 #include "freebsd.h"
98 #elif defined(__OpenBSD__)
99 #include "openbsd.h"
100 #endif
101
102 #if defined(__FreeBSD_kernel__)
103 #include <bsd/bsd.h>
104 #endif
105
106 /* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
107 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
108                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
109 int apm_getinfo(int fd, apm_info_t aip);
110 char *get_apm_adapter(void);
111 char *get_apm_battery_life(void);
112 char *get_apm_battery_time(void);
113 #endif
114
115 #ifdef CONFIG_OUTPUT
116 #include "defconfig.h"
117 #include "conf_cookie.h"
118 #endif
119
120 #ifndef S_ISSOCK
121 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
122 #endif
123
124 #define MAIL_FILE "$MAIL"
125 #define MAX_IF_BLOCK_DEPTH 5
126
127 //#define SIGNAL_BLOCKING
128 #undef SIGNAL_BLOCKING
129
130 /* debugging level, used by logging.h */
131 int global_debug_level = 0;
132
133 /* two strings for internal use */
134 static char *tmpstring1, *tmpstring2;
135
136 /* variables holding various config settings */
137 int short_units;
138 int format_human_readable;
139 int cpu_separate;
140 enum {
141         NO_SPACER = 0,
142         LEFT_SPACER,
143         RIGHT_SPACER
144 } use_spacer;
145 int top_cpu, top_mem, top_time;
146 #ifdef IOSTATS
147 int top_io;
148 #endif
149 static unsigned int top_name_width = 15;
150 int output_methods;
151 static int extra_newline;
152 enum x_initialiser_state x_initialised = NO;
153 static volatile int g_signal_pending;
154 /* Update interval */
155 double update_interval;
156 double update_interval_old;
157 double update_interval_bat;
158 void *global_cpu = NULL;
159 pid_t childpid = 0;
160
161 int argc_copy;
162 char** argv_copy;
163
164 /* prototypes for internally used functions */
165 static void signal_handler(int);
166 static void print_version(void) __attribute__((noreturn));
167 static void reload_config(void);
168 static void generate_text_internal(char *, int, struct text_object,
169                                    struct information *);
170
171 static void print_version(void)
172 {
173         printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
174
175         printf("\nCompiled in features:\n\n"
176                    "System config file: "SYSTEM_CONFIG_FILE"\n"
177                    "Package library path: "PACKAGE_LIBDIR"\n\n"
178 #ifdef X11
179                    " X11:\n"
180 # ifdef HAVE_XDAMAGE
181                    "  * Xdamage extension\n"
182 # endif /* HAVE_XDAMAGE */
183 # ifdef HAVE_XDBE
184                    "  * XDBE (double buffer extension)\n"
185 # endif /* HAVE_XDBE */
186 # ifdef XFT
187                    "  * Xft\n"
188 # endif /* XFT */
189 #endif /* X11 */
190                    "\n Music detection:\n"
191 #ifdef AUDACIOUS
192                    "  * Audacious\n"
193 #endif /* AUDACIOUS */
194 #ifdef BMPX
195                    "  * BMPx\n"
196 #endif /* BMPX */
197 #ifdef MPD
198                    "  * MPD\n"
199 #endif /* MPD */
200 #ifdef MOC
201                    "  * MOC\n"
202 #endif /* MOC */
203 #ifdef XMMS2
204                    "  * XMMS2\n"
205 #endif /* XMMS2 */
206                    "\n General:\n"
207 #ifdef HAVE_OPENMP
208                    "  * OpenMP\n"
209 #endif /* HAVE_OPENMP */
210 #ifdef MATH
211                    "  * math\n"
212 #endif /* Math */
213 #ifdef HDDTEMP
214                    "  * hddtemp\n"
215 #endif /* HDDTEMP */
216 #ifdef TCP_PORT_MONITOR
217                    "  * portmon\n"
218 #endif /* TCP_PORT_MONITOR */
219 #ifdef HAVE_CURL
220                    "  * Curl\n"
221 #endif /* HAVE_CURL */
222 #ifdef RSS
223                    "  * RSS\n"
224 #endif /* RSS */
225 #ifdef WEATHER
226                    "  * Weather (METAR)\n"
227 #ifdef XOAP
228                    "  * Weather (XOAP)\n"
229 #endif /* XOAP */
230 #endif /* WEATHER */
231 #ifdef HAVE_IWLIB
232                    "  * wireless\n"
233 #endif /* HAVE_IWLIB */
234 #ifdef IBM
235                    "  * support for IBM/Lenovo notebooks\n"
236 #endif /* IBM */
237 #ifdef NVIDIA
238                    "  * nvidia\n"
239 #endif /* NVIDIA */
240 #ifdef EVE
241                    "  * eve-online\n"
242 #endif /* EVE */
243 #ifdef CONFIG_OUTPUT
244                    "  * config-output\n"
245 #endif /* CONFIG_OUTPUT */
246 #ifdef IMLIB2
247                    "  * Imlib2\n"
248 #endif /* IMLIB2 */
249 #ifdef MIXER_IS_ALSA
250                    "  * ALSA mixer support\n"
251 #endif /* MIXER_IS_ALSA */
252 #ifdef APCUPSD
253                    "  * apcupsd\n"
254 #endif /* APCUPSD */
255 #ifdef IOSTATS
256                    "  * iostats\n"
257 #endif /* IOSTATS */
258 #ifdef HAVE_LUA
259                    "  * Lua\n"
260                    "\n  Lua bindings:\n"
261 #ifdef HAVE_LUA_CAIRO
262                    "   * Cairo\n"
263 #endif /* HAVE_LUA_CAIRO */
264 #ifdef HAVE_LUA_IMLIB2
265                    "   * Imlib2\n"
266 #endif /* IMLIB2 */
267 #endif /* HAVE_LUA */
268         );
269
270         exit(EXIT_SUCCESS);
271 }
272
273 static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
274
275
276 #ifdef X11
277
278 static void X11_create_window(void);
279 static void X11_initialisation(void);
280
281 struct _x11_stuff_s {
282         Region region;
283 #ifdef HAVE_XDAMAGE
284         Damage damage;
285         XserverRegion region2, part;
286         int event_base, error_base;
287 #endif
288 } x11_stuff;
289
290 /* text size */
291
292 static int text_start_x, text_start_y;  /* text start position in window */
293 static int text_width, text_height;
294
295 /* alignments */
296 enum alignment {
297         TOP_LEFT = 1,
298         TOP_RIGHT,
299         TOP_MIDDLE,
300         BOTTOM_LEFT,
301         BOTTOM_RIGHT,
302         BOTTOM_MIDDLE,
303         MIDDLE_LEFT,
304         MIDDLE_RIGHT,
305         NONE
306 };
307
308 /* display to connect to */
309 static char *disp = NULL;
310
311 #endif /* X11 */
312
313 /* struct that has all info to be shared between
314  * instances of the same text object */
315 struct information info;
316
317 /* path to config file */
318 char *current_config;
319
320 /* set to 1 if you want all text to be in uppercase */
321 static unsigned int stuff_in_uppercase;
322
323 /* Run how many times? */
324 static unsigned long total_run_times;
325
326 /* fork? */
327 static int fork_to_background;
328
329 static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
330
331 /* filenames for output */
332 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
333 char *append_file = NULL; FILE *append_fpointer = NULL;
334
335 #ifdef X11
336
337 static int show_graph_scale;
338 static int show_graph_range;
339
340 /* Position on the screen */
341 static int text_alignment;
342 static int gap_x, gap_y;
343
344 /* border */
345 static int draw_borders;
346 static int draw_graph_borders;
347 static int stippled_borders;
348
349 int get_stippled_borders(void)
350 {
351         return stippled_borders;
352 }
353
354 static int draw_shades, draw_outline;
355
356 long default_fg_color, default_bg_color, default_out_color;
357
358 /* create own window or draw stuff to root? */
359 static int set_transparent = 0;
360
361 #ifdef OWN_WINDOW
362 static int own_window = 0;
363 static int background_colour = 0;
364
365 /* fixed size/pos is set if wm/user changes them */
366 static int fixed_size = 0, fixed_pos = 0;
367 #endif
368
369 static int minimum_width, minimum_height;
370 static int maximum_width;
371
372 #endif /* X11 */
373
374 #ifdef __OpenBSD__
375 static int sensor_device;
376 #endif
377
378 long color0, color1, color2, color3, color4, color5, color6, color7, color8,
379          color9;
380
381 static char *template[MAX_TEMPLATES];
382
383 char **get_templates(void)
384 {
385         return template;
386 }
387
388 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
389 unsigned int max_user_text;
390
391 /* maximum size of individual text buffers, ie $exec buffer size */
392 unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
393
394 /* UTF-8 */
395 int utf8_mode = 0;
396
397 /* no buffers in used memory? */
398 int no_buffers;
399
400 /* pad percentages to decimals? */
401 static int pad_percents = 0;
402
403 static char *global_text = 0;
404
405 char *get_global_text(void)
406 {
407         return global_text;
408 }
409
410 long global_text_lines;
411
412 static int total_updates;
413 static int updatereset;
414
415 void set_updatereset(int i)
416 {
417         updatereset = i;
418 }
419
420 int get_updatereset(void)
421 {
422         return updatereset;
423 }
424
425 int check_contains(char *f, char *s)
426 {
427         int ret = 0;
428         FILE *where = open_file(f, 0);
429
430         if (where) {
431                 char buf1[256];
432
433                 while (fgets(buf1, 256, where)) {
434                         if (strstr(buf1, s)) {
435                                 ret = 1;
436                                 break;
437                         }
438                 }
439                 fclose(where);
440         } else {
441                 NORM_ERR("Could not open the file");
442         }
443         return ret;
444 }
445
446 #define SECRIT_MULTILINE_CHAR '\x02'
447
448 #ifdef X11
449
450 static inline int calc_text_width(const char *s, int l)
451 {
452         if ((output_methods & TO_X) == 0) {
453                 return 0;
454         }
455 #ifdef XFT
456         if (use_xft) {
457                 XGlyphInfo gi;
458
459                 if (utf8_mode) {
460                         XftTextExtentsUtf8(display, fonts[selected_font].xftfont,
461                                 (const FcChar8 *) s, l, &gi);
462                 } else {
463                         XftTextExtents8(display, fonts[selected_font].xftfont,
464                                 (const FcChar8 *) s, l, &gi);
465                 }
466                 return gi.xOff;
467         } else
468 #endif
469         {
470                 return XTextWidth(fonts[selected_font].font, s, l);
471         }
472 }
473 #endif /* X11 */
474
475 /* formatted text to render on screen, generated in generate_text(),
476  * drawn in draw_stuff() */
477
478 static char *text_buffer;
479
480 /* quite boring functions */
481
482 static inline void for_each_line(char *b, int f(char *, int))
483 {
484         char *ps, *pe;
485         int special_index = 0; /* specials index */
486
487         for (ps = b, pe = b; *pe; pe++) {
488                 if (*pe == '\n') {
489                         *pe = '\0';
490                         special_index = f(ps, special_index);
491                         *pe = '\n';
492                         ps = pe + 1;
493                 }
494         }
495
496         if (ps < pe) {
497                 f(ps, special_index);
498         }
499 }
500
501 static void convert_escapes(char *buf)
502 {
503         char *p = buf, *s = buf;
504
505         while (*s) {
506                 if (*s == '\\') {
507                         s++;
508                         if (*s == 'n') {
509                                 *p++ = '\n';
510                         } else if (*s == '\\') {
511                                 *p++ = '\\';
512                         }
513                         s++;
514                 } else {
515                         *p++ = *s++;
516                 }
517         }
518         *p = '\0';
519 }
520
521 /* Prints anything normally printed with snprintf according to the current value
522  * of use_spacer.  Actually slightly more flexible than snprintf, as you can
523  * safely specify the destination buffer as one of your inputs.  */
524 int spaced_print(char *buf, int size, const char *format, int width, ...)
525 {
526         int len = 0;
527         va_list argp;
528         char *tempbuf;
529
530         if (size < 1) {
531                 return 0;
532         }
533         tempbuf = malloc(size * sizeof(char));
534
535         // Passes the varargs along to vsnprintf
536         va_start(argp, width);
537         vsnprintf(tempbuf, size, format, argp);
538         va_end(argp);
539
540         switch (use_spacer) {
541                 case NO_SPACER:
542                         len = snprintf(buf, size, "%s", tempbuf);
543                         break;
544                 case LEFT_SPACER:
545                         len = snprintf(buf, size, "%*s", width, tempbuf);
546                         break;
547                 case RIGHT_SPACER:
548                         len = snprintf(buf, size, "%-*s", width, tempbuf);
549                         break;
550         }
551         free(tempbuf);
552         return len;
553 }
554
555 /* print percentage values
556  *
557  * - i.e., unsigned values between 0 and 100
558  * - respect the value of pad_percents */
559 static int percent_print(char *buf, int size, unsigned value)
560 {
561         return spaced_print(buf, size, "%u", pad_percents, value);
562 }
563
564 /* converts from bytes to human readable format (K, M, G, T)
565  *
566  * The algorithm always divides by 1024, as unit-conversion of byte
567  * counts suggests. But for output length determination we need to
568  * compare with 1000 here, as we print in decimal form. */
569 static void human_readable(long long num, char *buf, int size)
570 {
571         const char **suffix = suffixes;
572         float fnum;
573         int precision;
574         int width;
575         const char *format;
576
577         /* Possibly just output as usual, for example for stdout usage */
578         if (!format_human_readable) {
579                 spaced_print(buf, size, "%d", 6, round_to_int(num));
580                 return;
581         }
582         if (short_units) {
583                 width = 5;
584                 format = "%.*f%.1s";
585         } else {
586                 width = 7;
587                 format = "%.*f%-3s";
588         }
589
590         if (llabs(num) < 1000LL) {
591                 spaced_print(buf, size, format, width, 0, (float)num, *suffix);
592                 return;
593         }
594
595         while (llabs(num / 1024) >= 1000LL && **(suffix + 2)) {
596                 num /= 1024;
597                 suffix++;
598         }
599
600         suffix++;
601         fnum = num / 1024.0;
602
603         /* fnum should now be < 1000, so looks like 'AAA.BBBBB'
604          *
605          * The goal is to always have a significance of 3, by
606          * adjusting the decimal part of the number. Sample output:
607          *  123MiB
608          * 23.4GiB
609          * 5.12B   
610          * so the point of alignment resides between number and unit. The
611          * upside of this is that there is minimal padding necessary, though
612          * there should be a way to make alignment take place at the decimal
613          * dot (then with fixed width decimal part). 
614          *
615          * Note the repdigits below: when given a precision value, printf()
616          * rounds the float to it, not just cuts off the remaining digits. So
617          * e.g. 99.95 with a precision of 1 gets 100.0, which again should be
618          * printed with a precision of 0. Yay. */
619
620         precision = 0;          /* print 100-999 without decimal part */
621         if (fnum < 99.95)
622                 precision = 1;  /* print 10-99 with one decimal place */
623         if (fnum < 9.995)
624                 precision = 2;  /* print 0-9 with two decimal places */
625
626         spaced_print(buf, size, format, width, precision, fnum, *suffix);
627 }
628
629 /* global object list root element */
630 static struct text_object global_root_object;
631
632 //our own implementation of popen, the difference : the value of 'childpid' will be filled with
633 //the pid of the running 'command'. This is useful if want to kill it when it hangs while reading
634 //or writing to it. We have to kill it because pclose will wait until the process dies by itself
635 FILE* pid_popen(const char *command, const char *mode, pid_t *child) {
636         int ends[2];
637         int parentend, childend;
638
639         //by running pipe after the strcmp's we make sure that we don't have to create a pipe
640         //and close the ends if mode is something illegal
641         if(strcmp(mode, "r") == 0) {
642                 if(pipe(ends) != 0) {
643                         return NULL;
644                 }
645                 parentend = ends[0];
646                 childend = ends[1];
647         } else if(strcmp(mode, "w") == 0) {
648                 if(pipe(ends) != 0) {
649                         return NULL;
650                 }
651                 parentend = ends[1];
652                 childend = ends[0];
653         } else {
654                 return NULL;
655         }
656         *child = fork();
657         if(*child == -1) {
658                 close(parentend);
659                 close(childend);
660                 return NULL;
661         } else if(*child > 0) {
662                 close(childend);
663                 waitpid(*child, NULL, 0);
664         } else {
665                 //don't read from both stdin and pipe or write to both stdout and pipe
666                 if(childend == ends[0]) {
667                         close(0);
668                 } else {
669                         close(1);
670                 }
671                 dup(childend);  //by dupping childend, the returned fd will have close-on-exec turned off
672                 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
673                 _exit(EXIT_FAILURE); //child should die here, (normally execl will take care of this but it can fail) 
674         }
675         return fdopen(parentend, mode);
676 }
677
678 static inline void read_exec(const char *data, char *buf, const int size)
679 {
680         FILE *fp;
681
682         alarm(update_interval);
683         fp = pid_popen(data, "r", &childpid);
684         if(fp) {
685                 int length;
686
687                 length = fread(buf, 1, size, fp);
688                 pclose(fp);
689                 buf[length] = '\0';
690                 if (length > 0 && buf[length - 1] == '\n') {
691                         buf[length - 1] = '\0';
692                 }
693         } else {
694                 buf[0] = '\0';
695         }
696         alarm(0);
697 }
698
699 void do_read_exec(const char *data, char *buf, const int size)
700 {
701         read_exec(data, buf, size);
702 }
703
704 void *threaded_exec(void *) __attribute__((noreturn));
705
706 void *threaded_exec(void *arg)
707 {
708         char *buff, *p2;
709         struct text_object *obj = (struct text_object *)arg;
710
711         while (1) {
712                 buff = malloc(text_buffer_size);
713                 read_exec(obj->data.texeci.cmd, buff,
714                         text_buffer_size);
715                 p2 = buff;
716                 while (*p2) {
717                         if (*p2 == '\001') {
718                                 *p2 = ' ';
719                         }
720                         p2++;
721                 }
722                 timed_thread_lock(obj->data.texeci.p_timed_thread);
723                 strncpy(obj->data.texeci.buffer, buff, text_buffer_size);
724                 timed_thread_unlock(obj->data.texeci.p_timed_thread);
725                 free(buff);
726                 if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) {
727                         timed_thread_exit(obj->data.texeci.p_timed_thread);
728                 }
729         }
730         /* never reached */
731 }
732
733 static long current_text_color;
734
735 void set_current_text_color(long colour)
736 {
737         current_text_color = colour;
738 }
739
740 long get_current_text_color(void)
741 {
742         return current_text_color;
743 }
744
745 //adds newstring to to the tree unless you can already see it when travelling back.
746 //if it's possible to attach it then it returns a pointer to the leaf, else it returns NULL
747 struct conftree* conftree_add(struct conftree* previous, const char* newstring) {
748         struct conftree* node;
749         struct conftree* node2;
750
751         for(node = previous; node != NULL; node = node->back) {
752                 if(strcmp(node->string, newstring) == 0) {
753                         return NULL;
754                 }
755         }
756         node = malloc(sizeof(struct conftree));
757         if (previous != NULL) {
758                 if(previous->vert_next == NULL) {
759                         previous->vert_next = node;
760                 } else {
761                         for(node2 = previous->vert_next; node2->horz_next != NULL; node2 = node2->horz_next ) { }
762                         node2->horz_next = node;
763                 }
764         }
765         node->string = strdup(newstring);
766         node->horz_next = NULL;
767         node->vert_next = NULL;
768         node->back = previous;
769         return node;
770 }
771
772 void conftree_empty(struct conftree* tree) {
773         if(tree) {
774                 conftree_empty(tree->horz_next);
775                 conftree_empty(tree->vert_next);
776                 free(tree->string);
777                 free(tree);
778         }
779 }
780
781 struct conftree *currentconffile;
782
783 static void extract_variable_text(const char *p)
784 {
785         free_text_objects(&global_root_object, 0);
786         if (tmpstring1) {
787                 free(tmpstring1);
788                 tmpstring1 = 0;
789         }
790         if (tmpstring2) {
791                 free(tmpstring2);
792                 tmpstring2 = 0;
793         }
794         if (text_buffer) {
795                 free(text_buffer);
796                 text_buffer = 0;
797         }
798
799         extract_variable_text_internal(&global_root_object, p);
800 }
801
802 void parse_conky_vars(struct text_object *root, const char *txt, char *p, struct information *cur)
803 {
804         extract_variable_text_internal(root, txt);
805         generate_text_internal(p, max_user_text, *root, cur);
806 }
807
808 static inline struct mail_s *ensure_mail_thread(struct text_object *obj,
809                 void *thread(void *), const char *text)
810 {
811         if (obj->char_b && info.mail) {
812                 // this means we use info
813                 if (!info.mail->p_timed_thread) {
814                         info.mail->p_timed_thread =
815                                 timed_thread_create(thread,
816                                                 (void *) info.mail, info.mail->interval * 1000000);
817                         if (!info.mail->p_timed_thread) {
818                                 NORM_ERR("Error creating %s timed thread", text);
819                         }
820                         timed_thread_register(info.mail->p_timed_thread,
821                                         &info.mail->p_timed_thread);
822                         if (timed_thread_run(info.mail->p_timed_thread)) {
823                                 NORM_ERR("Error running %s timed thread", text);
824                         }
825                 }
826                 return info.mail;
827         } else if (obj->data.mail) {
828                 // this means we use obj
829                 if (!obj->data.mail->p_timed_thread) {
830                         obj->data.mail->p_timed_thread =
831                                 timed_thread_create(thread,
832                                                 (void *) obj->data.mail,
833                                                 obj->data.mail->interval * 1000000);
834                         if (!obj->data.mail->p_timed_thread) {
835                                 NORM_ERR("Error creating %s timed thread", text);
836                         }
837                         timed_thread_register(obj->data.mail->p_timed_thread,
838                                         &obj->data.mail->p_timed_thread);
839                         if (timed_thread_run(obj->data.mail->p_timed_thread)) {
840                                 NORM_ERR("Error running %s timed thread", text);
841                         }
842                 }
843                 return obj->data.mail;
844         } else if (!obj->a) {
845                 // something is wrong, warn once then stop
846                 NORM_ERR("There's a problem with your mail settings.  "
847                                 "Check that the global mail settings are properly defined"
848                                 " (line %li).", obj->line);
849                 obj->a++;
850         }
851         return NULL;
852 }
853
854 char *format_time(unsigned long timeval, const int width)
855 {
856         char buf[10];
857         unsigned long nt;       // narrow time, for speed on 32-bit
858         unsigned cc;            // centiseconds
859         unsigned nn;            // multi-purpose whatever
860
861         nt = timeval;
862         cc = nt % 100;          // centiseconds past second
863         nt /= 100;                      // total seconds
864         nn = nt % 60;           // seconds past the minute
865         nt /= 60;                       // total minutes
866         if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
867                                 nt, nn, cc)) {
868                 return strndup(buf, text_buffer_size);
869         }
870         if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
871                 return strndup(buf, text_buffer_size);
872         }
873         nn = nt % 60;           // minutes past the hour
874         nt /= 60;                       // total hours
875         if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
876                 return strndup(buf, text_buffer_size);
877         }
878         nn = nt;                        // now also hours
879         if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
880                 return strndup(buf, text_buffer_size);
881         }
882         nn /= 24;                       // now days
883         if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
884                 return strndup(buf, text_buffer_size);
885         }
886         nn /= 7;                        // now weeks
887         if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
888                 return strndup(buf, text_buffer_size);
889         }
890         // well shoot, this outta' fit...
891         return strndup("<inf>", text_buffer_size);
892 }
893
894 //remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat"
895 //string has to end with \0 and it's length should fit in a int
896 #define BACKSPACE 8
897 void remove_deleted_chars(char *string){
898         int i = 0;
899         while(string[i] != 0){
900                 if(string[i] == BACKSPACE){
901                         if(i != 0){
902                                 strcpy( &(string[i-1]), &(string[i+1]) );
903                                 i--;
904                         }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string
905                 }else i++;
906         }
907 }
908
909 static inline void format_media_player_time(char *buf, const int size,
910                 int seconds)
911 {
912         int days, hours, minutes;
913
914         days = seconds / (24 * 60 * 60);
915         seconds %= (24 * 60 * 60);
916         hours = seconds / (60 * 60);
917         seconds %= (60 * 60);
918         minutes = seconds / 60;
919         seconds %= 60;
920
921         if (days > 0) {
922                 snprintf(buf, size, "%i days %i:%02i:%02i", days,
923                                 hours, minutes, seconds);
924         } else if (hours > 0) {
925                 snprintf(buf, size, "%i:%02i:%02i", hours, minutes,
926                                 seconds);
927         } else {
928                 snprintf(buf, size, "%i:%02i", minutes, seconds);
929         }
930 }
931
932 static inline double get_barnum(char *buf)
933 {
934         char *c = buf;
935         double barnum;
936
937         while (*c) {
938                 if (*c == '\001') {
939                         *c = ' ';
940                 }
941                 c++;
942         }
943
944         if (sscanf(buf, "%lf", &barnum) == 0) {
945                 NORM_ERR("reading exec value failed (perhaps it's not the "
946                                 "correct format?)");
947                 return -1;
948         }
949         if (barnum > 100.0 || barnum < 0.0) {
950                 NORM_ERR("your exec value is not between 0 and 100, "
951                                 "therefore it will be ignored");
952                 return -1;
953         }
954         return barnum;
955 }
956
957 /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
958  * multiline objects like $exec work with $align[rc] and friends
959  */
960 void substitute_newlines(char *p, long l)
961 {
962         char *s = p;
963         if (l < 0) return;
964         while (p && *p && p < s + l) {
965                 if (*p == '\n') {
966                         /* only substitute if it's not the last newline */
967                         *p = SECRIT_MULTILINE_CHAR;
968                 }
969                 p++;
970         }
971 }
972
973 static void generate_text_internal(char *p, int p_max_size,
974                 struct text_object root, struct information *cur)
975 {
976         struct text_object *obj;
977 #ifdef X11
978         int need_to_load_fonts = 0;
979 #endif /* X11 */
980
981         /* for the OBJ_top* handler */
982         struct process **needed = 0;
983
984 #ifdef HAVE_ICONV
985         char buff_in[p_max_size];
986         buff_in[0] = 0;
987         set_iconv_converting(0);
988 #endif /* HAVE_ICONV */
989
990         p[0] = 0;
991         obj = root.next;
992         while (obj && p_max_size > 0) {
993                 needed = 0; /* reset for top stuff */
994
995 /* IFBLOCK jumping algorithm
996  *
997  * This is easier as it looks like:
998  * - each IF checks it's condition
999  *   - on FALSE: call DO_JUMP
1000  *   - on TRUE: don't care
1001  * - each ELSE calls DO_JUMP unconditionally
1002  * - each ENDIF is silently being ignored
1003  *
1004  * Why this works:
1005  * DO_JUMP overwrites the "obj" variable of the loop and sets it to the target
1006  * (i.e. the corresponding ELSE or ENDIF). After that, processing for the given
1007  * object can continue, free()ing stuff e.g., then the for-loop does the rest: as
1008  * regularly, "obj" is being updated to point to obj->next, so object parsing
1009  * continues right after the corresponding ELSE or ENDIF. This means that if we
1010  * find an ELSE, it's corresponding IF must not have jumped, so we need to jump
1011  * always. If we encounter an ENDIF, it's corresponding IF or ELSE has not
1012  * jumped, and there is nothing to do.
1013  */
1014 #define DO_JUMP { \
1015         DBGP2("jumping"); \
1016         obj = obj->data.ifblock.next; \
1017 }
1018
1019 #define OBJ(a) break; case OBJ_##a:
1020
1021                 switch (obj->type) {
1022                         default:
1023                                 NORM_ERR("not implemented obj type %d", obj->type);
1024                         OBJ(read_tcp) {
1025                                 int sock, received;
1026                                 struct sockaddr_in addr;
1027                                 struct hostent* he = gethostbyname(obj->data.read_tcp.host);
1028                                 if(he != NULL) {
1029                                         sock = socket(he->h_addrtype, SOCK_STREAM, 0);
1030                                         if(sock != -1) {
1031                                                 memset(&addr, 0, sizeof(addr));
1032                                                 addr.sin_family = AF_INET;
1033                                                 addr.sin_port = obj->data.read_tcp.port;
1034                                                 memcpy(&addr.sin_addr, he->h_addr, he->h_length);
1035                                                 if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == 0) {
1036                                                         fd_set readfds;
1037                                                         struct timeval tv;
1038                                                         FD_ZERO(&readfds);
1039                                                         FD_SET(sock, &readfds);
1040                                                         tv.tv_sec = 1;
1041                                                         tv.tv_usec = 0;
1042                                                         if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
1043                                                                 received = recv(sock, p, p_max_size, 0);
1044                                                                 p[received] = 0;
1045                                                         }
1046                                                         close(sock);
1047                                                 } else {
1048                                                         NORM_ERR("read_tcp: Couldn't create a connection");
1049                                                 }
1050                                         }else{
1051                                                 NORM_ERR("read_tcp: Couldn't create a socket");
1052                                         }
1053                                 }else{
1054                                         NORM_ERR("read_tcp: Problem with resolving the hostname");
1055                                 }
1056                         }
1057 #ifndef __OpenBSD__
1058                         OBJ(acpitemp) {
1059                                 temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
1060                         }
1061 #endif /* !__OpenBSD__ */
1062                         OBJ(freq) {
1063                                 if (obj->a) {
1064                                         obj->a = get_freq(p, p_max_size, "%.0f", 1,
1065                                                         obj->data.cpu_index);
1066                                 }
1067                         }
1068                         OBJ(freq_g) {
1069                                 if (obj->a) {
1070 #ifndef __OpenBSD__
1071                                         obj->a = get_freq(p, p_max_size, "%'.2f", 1000,
1072                                                         obj->data.cpu_index);
1073 #else
1074                                         /* OpenBSD has no such flag (SUSv2) */
1075                                         obj->a = get_freq(p, p_max_size, "%.2f", 1000,
1076                                                         obj->data.cpu_index);
1077 #endif /* __OpenBSD */
1078                                 }
1079                         }
1080 #if defined(__linux__)
1081                         OBJ(voltage_mv) {
1082                                 if (obj->a) {
1083                                         obj->a = get_voltage(p, p_max_size, "%.0f", 1,
1084                                                         obj->data.cpu_index);
1085                                 }
1086                         }
1087                         OBJ(voltage_v) {
1088                                 if (obj->a) {
1089                                         obj->a = get_voltage(p, p_max_size, "%'.3f", 1000,
1090                                                         obj->data.cpu_index);
1091                                 }
1092                         }
1093
1094 #ifdef HAVE_IWLIB
1095                         OBJ(wireless_essid) {
1096                                 snprintf(p, p_max_size, "%s", obj->data.net->essid);
1097                         }
1098                         OBJ(wireless_mode) {
1099                                 snprintf(p, p_max_size, "%s", obj->data.net->mode);
1100                         }
1101                         OBJ(wireless_bitrate) {
1102                                 snprintf(p, p_max_size, "%s", obj->data.net->bitrate);
1103                         }
1104                         OBJ(wireless_ap) {
1105                                 snprintf(p, p_max_size, "%s", obj->data.net->ap);
1106                         }
1107                         OBJ(wireless_link_qual) {
1108                                 spaced_print(p, p_max_size, "%d", 4,
1109                                                 obj->data.net->link_qual);
1110                         }
1111                         OBJ(wireless_link_qual_max) {
1112                                 spaced_print(p, p_max_size, "%d", 4,
1113                                                 obj->data.net->link_qual_max);
1114                         }
1115                         OBJ(wireless_link_qual_perc) {
1116                                 if (obj->data.net->link_qual_max > 0) {
1117                                         spaced_print(p, p_max_size, "%.0f", 5,
1118                                                         (double) obj->data.net->link_qual /
1119                                                         obj->data.net->link_qual_max * 100);
1120                                 } else {
1121                                         spaced_print(p, p_max_size, "unk", 5);
1122                                 }
1123                         }
1124                         OBJ(wireless_link_bar) {
1125 #ifdef X11
1126                                 if(output_methods & TO_X) {
1127                                         new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
1128                                                 obj->data.net->link_qual_max) * 255.0);
1129                                 }else{
1130 #endif /* X11 */
1131                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1132                                         new_bar_in_shell(p, p_max_size, ((double) obj->data.net->link_qual /
1133                                                 obj->data.net->link_qual_max) * 100.0, obj->a);
1134 #ifdef X11
1135                                 }
1136 #endif /* X11 */
1137                         }
1138 #endif /* HAVE_IWLIB */
1139
1140 #endif /* __linux__ */
1141
1142 #ifndef __OpenBSD__
1143                         OBJ(adt746xcpu) {
1144                                 get_adt746x_cpu(p, p_max_size);
1145                         }
1146                         OBJ(adt746xfan) {
1147                                 get_adt746x_fan(p, p_max_size);
1148                         }
1149                         OBJ(acpifan) {
1150                                 get_acpi_fan(p, p_max_size);
1151                         }
1152                         OBJ(acpiacadapter) {
1153                                 get_acpi_ac_adapter(p, p_max_size);
1154                         }
1155                         OBJ(battery) {
1156                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
1157                         }
1158                         OBJ(battery_time) {
1159                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
1160                         }
1161                         OBJ(battery_percent) {
1162                                 percent_print(p, p_max_size, get_battery_perct(obj->data.s));
1163                         }
1164                         OBJ(battery_bar) {
1165 #ifdef X11
1166                                 if(output_methods & TO_X) {
1167                                         new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
1168                                 }else{
1169 #endif /* X11 */
1170                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1171                                         new_bar_in_shell(p, p_max_size, get_battery_perct_bar(obj->data.s) / 2.55, obj->a);
1172 #ifdef X11
1173                                 }
1174 #endif /* X11 */
1175                         }
1176                         OBJ(battery_short) {
1177                                 get_battery_short_status(p, p_max_size, obj->data.s);
1178                         }
1179 #endif /* __OpenBSD__ */
1180
1181                         OBJ(buffers) {
1182                                 human_readable(cur->buffers * 1024, p, 255);
1183                         }
1184                         OBJ(cached) {
1185                                 human_readable(cur->cached * 1024, p, 255);
1186                         }
1187                         OBJ(cpu) {
1188                                 if (obj->data.cpu_index > info.cpu_count) {
1189                                         NORM_ERR("obj->data.cpu_index %i info.cpu_count %i",
1190                                                         obj->data.cpu_index, info.cpu_count);
1191                                         CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
1192                                 }
1193                                 percent_print(p, p_max_size,
1194                                               round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
1195                         }
1196 #ifdef X11
1197                         OBJ(cpugauge)
1198                                 new_gauge(p, obj->a, obj->b,
1199                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
1200 #endif /* X11 */
1201                         OBJ(cpubar) {
1202 #ifdef X11
1203                                 if(output_methods & TO_X) {
1204                                         new_bar(p, obj->a, obj->b,
1205                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
1206                                 }else{
1207 #endif /* X11 */
1208                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1209                                         new_bar_in_shell(p, p_max_size, round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100), obj->a);
1210 #ifdef X11
1211                                 }
1212 #endif /* X11 */
1213                         }
1214 #ifdef X11
1215                         OBJ(cpugraph) {
1216                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1217                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100),
1218                                                 100, 1, obj->char_a, obj->char_b);
1219                         }
1220                         OBJ(loadgraph) {
1221                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, cur->loadavg[0],
1222                                                 obj->e, 1, obj->char_a, obj->char_b);
1223                         }
1224 #endif /* X11 */
1225                         OBJ(color) {
1226                                 new_fg(p, obj->data.l);
1227                         }
1228 #ifdef X11
1229                         OBJ(color0) {
1230                                 new_fg(p, color0);
1231                         }
1232                         OBJ(color1) {
1233                                 new_fg(p, color1);
1234                         }
1235                         OBJ(color2) {
1236                                 new_fg(p, color2);
1237                         }
1238                         OBJ(color3) {
1239                                 new_fg(p, color3);
1240                         }
1241                         OBJ(color4) {
1242                                 new_fg(p, color4);
1243                         }
1244                         OBJ(color5) {
1245                                 new_fg(p, color5);
1246                         }
1247                         OBJ(color6) {
1248                                 new_fg(p, color6);
1249                         }
1250                         OBJ(color7) {
1251                                 new_fg(p, color7);
1252                         }
1253                         OBJ(color8) {
1254                                 new_fg(p, color8);
1255                         }
1256                         OBJ(color9) {
1257                                 new_fg(p, color9);
1258                         }
1259 #endif /* X11 */
1260                         OBJ(conky_version) {
1261                                 snprintf(p, p_max_size, "%s", VERSION);
1262                         }
1263                         OBJ(conky_build_date) {
1264                                 snprintf(p, p_max_size, "%s", BUILD_DATE);
1265                         }
1266                         OBJ(conky_build_arch) {
1267                                 snprintf(p, p_max_size, "%s", BUILD_ARCH);
1268                         }
1269 #if defined(__linux__)
1270                         OBJ(disk_protect) {
1271                                 snprintf(p, p_max_size, "%s",
1272                                                 get_disk_protect_queue(obj->data.s));
1273                         }
1274                         OBJ(i8k_version) {
1275                                 snprintf(p, p_max_size, "%s", i8k.version);
1276                         }
1277                         OBJ(i8k_bios) {
1278                                 snprintf(p, p_max_size, "%s", i8k.bios);
1279                         }
1280                         OBJ(i8k_serial) {
1281                                 snprintf(p, p_max_size, "%s", i8k.serial);
1282                         }
1283                         OBJ(i8k_cpu_temp) {
1284                                 int cpu_temp;
1285
1286                                 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
1287                                 temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
1288                         }
1289                         OBJ(i8k_left_fan_status) {
1290                                 int left_fan_status;
1291
1292                                 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
1293                                 if (left_fan_status == 0) {
1294                                         snprintf(p, p_max_size, "off");
1295                                 }
1296                                 if (left_fan_status == 1) {
1297                                         snprintf(p, p_max_size, "low");
1298                                 }
1299                                 if (left_fan_status == 2) {
1300                                         snprintf(p, p_max_size, "high");
1301                                 }
1302                         }
1303                         OBJ(i8k_right_fan_status) {
1304                                 int right_fan_status;
1305
1306                                 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
1307                                 if (right_fan_status == 0) {
1308                                         snprintf(p, p_max_size, "off");
1309                                 }
1310                                 if (right_fan_status == 1) {
1311                                         snprintf(p, p_max_size, "low");
1312                                 }
1313                                 if (right_fan_status == 2) {
1314                                         snprintf(p, p_max_size, "high");
1315                                 }
1316                         }
1317                         OBJ(i8k_left_fan_rpm) {
1318                                 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
1319                         }
1320                         OBJ(i8k_right_fan_rpm) {
1321                                 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
1322                         }
1323                         OBJ(i8k_ac_status) {
1324                                 int ac_status;
1325
1326                                 sscanf(i8k.ac_status, "%d", &ac_status);
1327                                 if (ac_status == -1) {
1328                                         snprintf(p, p_max_size, "disabled (read i8k docs)");
1329                                 }
1330                                 if (ac_status == 0) {
1331                                         snprintf(p, p_max_size, "off");
1332                                 }
1333                                 if (ac_status == 1) {
1334                                         snprintf(p, p_max_size, "on");
1335                                 }
1336                         }
1337                         OBJ(i8k_buttons_status) {
1338                                 snprintf(p, p_max_size, "%s", i8k.buttons_status);
1339                         }
1340 #if defined(IBM)
1341                         OBJ(ibm_fan) {
1342                                 get_ibm_acpi_fan(p, p_max_size);
1343                         }
1344                         OBJ(ibm_temps) {
1345                                 get_ibm_acpi_temps();
1346                                 temp_print(p, p_max_size,
1347                                            ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
1348                         }
1349                         OBJ(ibm_volume) {
1350                                 get_ibm_acpi_volume(p, p_max_size);
1351                         }
1352                         OBJ(ibm_brightness) {
1353                                 get_ibm_acpi_brightness(p, p_max_size);
1354                         }
1355 #endif /* IBM */
1356                         /* information from sony_laptop kernel module
1357                          * /sys/devices/platform/sony-laptop */
1358                         OBJ(sony_fanspeed) {
1359                                 get_sony_fanspeed(p, p_max_size);
1360                         }
1361                         OBJ(if_gw) {
1362                                 if (!cur->gw_info.count) {
1363                                         DO_JUMP;
1364                                 }
1365                         }
1366                         OBJ(gw_iface) {
1367                                 snprintf(p, p_max_size, "%s", cur->gw_info.iface);
1368                         }
1369                         OBJ(gw_ip) {
1370                                 snprintf(p, p_max_size, "%s", cur->gw_info.ip);
1371                         }
1372                         OBJ(laptop_mode) {
1373                                 snprintf(p, p_max_size, "%d", get_laptop_mode());
1374                         }
1375                         OBJ(pb_battery) {
1376                                 get_powerbook_batt_info(p, p_max_size, obj->data.i);
1377                         }
1378 #endif /* __linux__ */
1379 #if (defined(__FreeBSD__) || defined(__linux__))
1380                         OBJ(if_up) {
1381                                 if ((obj->data.ifblock.s)
1382                                                 && (!interface_up(obj->data.ifblock.s))) {
1383                                         DO_JUMP;
1384                                 }
1385                         }
1386 #endif
1387 #ifdef __OpenBSD__
1388                         OBJ(obsd_sensors_temp) {
1389                                 obsd_sensors.device = sensor_device;
1390                                 update_obsd_sensors();
1391                                 temp_print(p, p_max_size,
1392                                            obsd_sensors.temp[obsd_sensors.device][obj->data.sensor],
1393                                            TEMP_CELSIUS);
1394                         }
1395                         OBJ(obsd_sensors_fan) {
1396                                 obsd_sensors.device = sensor_device;
1397                                 update_obsd_sensors();
1398                                 snprintf(p, p_max_size, "%d",
1399                                                 obsd_sensors.fan[obsd_sensors.device][obj->data.sensor]);
1400                         }
1401                         OBJ(obsd_sensors_volt) {
1402                                 obsd_sensors.device = sensor_device;
1403                                 update_obsd_sensors();
1404                                 snprintf(p, p_max_size, "%.2f",
1405                                                 obsd_sensors.volt[obsd_sensors.device][obj->data.sensor]);
1406                         }
1407                         OBJ(obsd_vendor) {
1408                                 get_obsd_vendor(p, p_max_size);
1409                         }
1410                         OBJ(obsd_product) {
1411                                 get_obsd_product(p, p_max_size);
1412                         }
1413 #endif /* __OpenBSD__ */
1414 #ifdef X11
1415                         OBJ(font) {
1416                                 new_font(p, obj->data.s);
1417                                 need_to_load_fonts = 1;
1418                         }
1419 #endif /* X11 */
1420                         /* TODO: move this correction from kB to kB/s elsewhere
1421                          * (or get rid of it??) */
1422                         OBJ(diskio) {
1423                                 human_readable((obj->data.diskio->current / update_interval) * 1024LL,
1424                                                 p, p_max_size);
1425                         }
1426                         OBJ(diskio_write) {
1427                                 human_readable((obj->data.diskio->current_write / update_interval) * 1024LL,
1428                                                 p, p_max_size);
1429                         }
1430                         OBJ(diskio_read) {
1431                                 human_readable((obj->data.diskio->current_read / update_interval) * 1024LL,
1432                                                 p, p_max_size);
1433                         }
1434 #ifdef X11
1435                         OBJ(diskiograph) {
1436                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1437                                           obj->data.diskio->current, obj->e, 1, obj->char_a, obj->char_b);
1438                         }
1439                         OBJ(diskiograph_read) {
1440                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1441                                           obj->data.diskio->current_read, obj->e, 1, obj->char_a, obj->char_b);
1442                         }
1443                         OBJ(diskiograph_write) {
1444                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1445                                           obj->data.diskio->current_write, obj->e, 1, obj->char_a, obj->char_b);
1446                         }
1447 #endif /* X11 */
1448                         OBJ(downspeed) {
1449                                 human_readable(obj->data.net->recv_speed, p, 255);
1450                         }
1451                         OBJ(downspeedf) {
1452                                 spaced_print(p, p_max_size, "%.1f", 8,
1453                                                 obj->data.net->recv_speed / 1024.0);
1454                         }
1455 #ifdef X11
1456                         OBJ(downspeedgraph) {
1457                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1458                                         obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
1459                         }
1460 #endif /* X11 */
1461                         OBJ(else) {
1462                                 /* Since we see you, you're if has not jumped.
1463                                  * Do Ninja jump here: without leaving traces.
1464                                  * This is to prevent us from stale jumped flags.
1465                                  */
1466                                 obj = obj->data.ifblock.next;
1467                                 continue;
1468                         }
1469                         OBJ(endif) {
1470                                 /* harmless object, just ignore */
1471                         }
1472                         OBJ(addr) {
1473                                 if ((obj->data.net->addr.sa_data[2] & 255) == 0
1474                                                 && (obj->data.net->addr.sa_data[3] & 255) == 0
1475                                                 && (obj->data.net->addr.sa_data[4] & 255) == 0
1476                                                 && (obj->data.net->addr.sa_data[5] & 255) == 0) {
1477                                         snprintf(p, p_max_size, "No Address");
1478                                 } else {
1479                                         snprintf(p, p_max_size, "%u.%u.%u.%u",
1480                                                 obj->data.net->addr.sa_data[2] & 255,
1481                                                 obj->data.net->addr.sa_data[3] & 255,
1482                                                 obj->data.net->addr.sa_data[4] & 255,
1483                                                 obj->data.net->addr.sa_data[5] & 255);
1484                                 }
1485                         }
1486 #if defined(__linux__)
1487                         OBJ(addrs) {
1488                                 if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
1489                                         obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
1490                                         strcpy(p, obj->data.net->addrs);
1491                                 } else {
1492                                         strcpy(p, "0.0.0.0");
1493                                 }
1494                         }
1495 #endif /* __linux__ */
1496 #if defined(IMLIB2) && defined(X11)
1497                         OBJ(image) {
1498                                 /* doesn't actually draw anything, just queues it omp.  the
1499                                  * image will get drawn after the X event loop */
1500                                 cimlib_add_image(obj->data.s);
1501                         }
1502 #endif /* IMLIB2 */
1503                         OBJ(eval) {
1504                                 evaluate(obj->data.s, p);
1505                         }
1506                         OBJ(exec) {
1507                                 read_exec(obj->data.s, p, text_buffer_size);
1508                                 remove_deleted_chars(p);
1509                         }
1510                         OBJ(execp) {
1511                                 struct information *tmp_info;
1512                                 struct text_object subroot;
1513
1514                                 read_exec(obj->data.s, p, text_buffer_size);
1515
1516                                 tmp_info = malloc(sizeof(struct information));
1517                                 memcpy(tmp_info, cur, sizeof(struct information));
1518                                 parse_conky_vars(&subroot, p, p, tmp_info);
1519
1520                                 free_text_objects(&subroot, 1);
1521                                 free(tmp_info);
1522                         }
1523 #ifdef X11
1524                         OBJ(execgauge) {
1525                                 double barnum;
1526
1527                                 read_exec(obj->data.s, p, text_buffer_size);
1528                                 barnum = get_barnum(p); /*using the same function*/
1529
1530                                 if (barnum >= 0.0) {
1531                                         barnum /= 100;
1532                                         new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
1533                                 }
1534                         }
1535 #endif /* X11 */
1536                         OBJ(execbar) {
1537                                 double barnum;
1538
1539                                 read_exec(obj->data.s, p, text_buffer_size);
1540                                 barnum = get_barnum(p);
1541
1542                                 if (barnum >= 0.0) {
1543 #ifdef X11
1544                                         if(output_methods & TO_X) {
1545                                                 barnum /= 100;
1546                                                 new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
1547                                         }else{
1548 #endif /* X11 */
1549                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1550                                                 new_bar_in_shell(p, p_max_size, barnum, obj->a);
1551 #ifdef X11
1552                                         }
1553 #endif /* X11 */
1554                                 }
1555                         }
1556 #ifdef X11
1557                         OBJ(execgraph) {
1558                                 char showaslog = FALSE;
1559                                 char tempgrad = FALSE;
1560                                 double barnum;
1561                                 char *cmd = obj->data.s;
1562
1563                                 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
1564                                         tempgrad = TRUE;
1565                                         cmd += strlen(" "TEMPGRAD);
1566                                 }
1567                                 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
1568                                         showaslog = TRUE;
1569                                         cmd += strlen(" "LOGGRAPH);
1570                                 }
1571                                 read_exec(cmd, p, text_buffer_size);
1572                                 barnum = get_barnum(p);
1573
1574                                 if (barnum > 0) {
1575                                         new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
1576                                                         100, 1, showaslog, tempgrad);
1577                                 }
1578                         }
1579 #endif /* X11 */
1580                         OBJ(execibar) {
1581                                 if (current_update_time - obj->data.execi.last_update
1582                                                 >= obj->data.execi.interval) {
1583                                         double barnum;
1584
1585                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
1586                                         barnum = get_barnum(p);
1587
1588                                         if (barnum >= 0.0) {
1589                                                 obj->f = barnum;
1590                                         }
1591                                         obj->data.execi.last_update = current_update_time;
1592                                 }
1593 #ifdef X11
1594                                 if(output_methods & TO_X) {
1595                                         new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
1596                                 } else {
1597 #endif /* X11 */
1598                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1599                                         new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a);
1600 #ifdef X11
1601                                 }
1602 #endif /* X11 */
1603                         }
1604 #ifdef X11
1605                         OBJ(execigraph) {
1606                                 if (current_update_time - obj->data.execi.last_update
1607                                                 >= obj->data.execi.interval) {
1608                                         double barnum;
1609                                         char showaslog = FALSE;
1610                                         char tempgrad = FALSE;
1611                                         char *cmd = obj->data.execi.cmd;
1612
1613                                         if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
1614                                                 tempgrad = TRUE;
1615                                                 cmd += strlen(" "TEMPGRAD);
1616                                         }
1617                                         if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
1618                                                 showaslog = TRUE;
1619                                                 cmd += strlen(" "LOGGRAPH);
1620                                         }
1621                                         obj->char_a = showaslog;
1622                                         obj->char_b = tempgrad;
1623                                         read_exec(cmd, p, text_buffer_size);
1624                                         barnum = get_barnum(p);
1625
1626                                         if (barnum >= 0.0) {
1627                                                 obj->f = barnum;
1628                                         }
1629                                         obj->data.execi.last_update = current_update_time;
1630                                 }
1631                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b);
1632                         }
1633                         OBJ(execigauge) {
1634                                 if (current_update_time - obj->data.execi.last_update
1635                                                 >= obj->data.execi.interval) {
1636                                         double barnum;
1637
1638                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
1639                                         barnum = get_barnum(p);
1640
1641                                         if (barnum >= 0.0) {
1642                                                 obj->f = 255 * barnum / 100.0;
1643                                         }
1644                                         obj->data.execi.last_update = current_update_time;
1645                                 }
1646                                 new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
1647                         }
1648 #endif /* X11 */
1649                         OBJ(execi) {
1650                                 if (current_update_time - obj->data.execi.last_update
1651                                                 >= obj->data.execi.interval
1652                                                 && obj->data.execi.interval != 0) {
1653                                         read_exec(obj->data.execi.cmd, obj->data.execi.buffer,
1654                                                 text_buffer_size);
1655                                         obj->data.execi.last_update = current_update_time;
1656                                 }
1657                                 snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
1658                         }
1659                         OBJ(execpi) {
1660                                 struct text_object subroot;
1661                                 struct information *tmp_info =
1662                                         malloc(sizeof(struct information));
1663                                 memcpy(tmp_info, cur, sizeof(struct information));
1664
1665                                 if (current_update_time - obj->data.execi.last_update
1666                                                 < obj->data.execi.interval
1667                                                 || obj->data.execi.interval == 0) {
1668                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
1669                                 } else {
1670                                         char *output = obj->data.execi.buffer;
1671                                         FILE *fp = pid_popen(obj->data.execi.cmd, "r", &childpid);
1672                                         int length = fread(output, 1, text_buffer_size, fp);
1673
1674                                         pclose(fp);
1675
1676                                         output[length] = '\0';
1677                                         if (length > 0 && output[length - 1] == '\n') {
1678                                                 output[length - 1] = '\0';
1679                                         }
1680
1681                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
1682                                         obj->data.execi.last_update = current_update_time;
1683                                 }
1684                                 free_text_objects(&subroot, 1);
1685                                 free(tmp_info);
1686                         }
1687                         OBJ(texeci) {
1688                                 if (!obj->data.texeci.p_timed_thread) {
1689                                         obj->data.texeci.p_timed_thread =
1690                                                 timed_thread_create(&threaded_exec,
1691                                                 (void *) obj, obj->data.texeci.interval * 1000000);
1692                                         if (!obj->data.texeci.p_timed_thread) {
1693                                                 NORM_ERR("Error creating texeci timed thread");
1694                                         }
1695                                         /*
1696                                          * note that we don't register this thread with the
1697                                          * timed_thread list, because we destroy it manually
1698                                          */
1699                                         if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
1700                                                 NORM_ERR("Error running texeci timed thread");
1701                                         }
1702                                 } else {
1703                                         timed_thread_lock(obj->data.texeci.p_timed_thread);
1704                                         snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer);
1705                                         timed_thread_unlock(obj->data.texeci.p_timed_thread);
1706                                 }
1707                         }
1708                         OBJ(imap_unseen) {
1709                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1710
1711                                 if (mail && mail->p_timed_thread) {
1712                                         timed_thread_lock(mail->p_timed_thread);
1713                                         snprintf(p, p_max_size, "%lu", mail->unseen);
1714                                         timed_thread_unlock(mail->p_timed_thread);
1715                                 }
1716                         }
1717                         OBJ(imap_messages) {
1718                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1719
1720                                 if (mail && mail->p_timed_thread) {
1721                                         timed_thread_lock(mail->p_timed_thread);
1722                                         snprintf(p, p_max_size, "%lu", mail->messages);
1723                                         timed_thread_unlock(mail->p_timed_thread);
1724                                 }
1725                         }
1726                         OBJ(pop3_unseen) {
1727                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1728
1729                                 if (mail && mail->p_timed_thread) {
1730                                         timed_thread_lock(mail->p_timed_thread);
1731                                         snprintf(p, p_max_size, "%lu", mail->unseen);
1732                                         timed_thread_unlock(mail->p_timed_thread);
1733                                 }
1734                         }
1735                         OBJ(pop3_used) {
1736                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1737
1738                                 if (mail && mail->p_timed_thread) {
1739                                         timed_thread_lock(mail->p_timed_thread);
1740                                         snprintf(p, p_max_size, "%.1f",
1741                                                 mail->used / 1024.0 / 1024.0);
1742                                         timed_thread_unlock(mail->p_timed_thread);
1743                                 }
1744                         }
1745                         OBJ(fs_bar) {
1746                                 if (obj->data.fs != NULL) {
1747                                         if (obj->data.fs->size == 0) {
1748 #ifdef X11
1749                                                 if(output_methods & TO_X) {
1750                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1751                                                 }else{
1752 #endif /* X11 */
1753                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1754                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1755 #ifdef X11
1756                                                 }
1757 #endif /* X11 */
1758                                         } else {
1759 #ifdef X11
1760                                                 if(output_methods & TO_X) {
1761                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1762                                                                 (int) (255 - obj->data.fsbar.fs->avail * 255 /
1763                                                                 obj->data.fs->size));
1764                                                 }else{
1765 #endif /* X11 */
1766                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1767                                                         new_bar_in_shell(p, p_max_size,
1768                                                                 (int) (100 - obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1769 #ifdef X11
1770                                                 }
1771 #endif /* X11 */
1772                                         }
1773                                 }
1774                         }
1775                         OBJ(fs_free) {
1776                                 if (obj->data.fs != NULL) {
1777                                         human_readable(obj->data.fs->avail, p, 255);
1778                                 }
1779                         }
1780                         OBJ(fs_free_perc) {
1781                                 if (obj->data.fs != NULL) {
1782                                         int val = 0;
1783
1784                                         if (obj->data.fs->size) {
1785                                                 val = obj->data.fs->avail * 100 / obj->data.fs->size;
1786                                         }
1787
1788                                         percent_print(p, p_max_size, val);
1789                                 }
1790                         }
1791                         OBJ(fs_size) {
1792                                 if (obj->data.fs != NULL) {
1793                                         human_readable(obj->data.fs->size, p, 255);
1794                                 }
1795                         }
1796                         OBJ(fs_type) {
1797                                 if (obj->data.fs != NULL)
1798                                         snprintf(p, p_max_size, "%s", obj->data.fs->type);
1799                         }
1800                         OBJ(fs_used) {
1801                                 if (obj->data.fs != NULL) {
1802                                         human_readable(obj->data.fs->size - obj->data.fs->free, p,
1803                                                         255);
1804                                 }
1805                         }
1806                         OBJ(fs_bar_free) {
1807                                 if (obj->data.fs != NULL) {
1808                                         if (obj->data.fs->size == 0) {
1809 #ifdef X11
1810                                                 if(output_methods & TO_X) {
1811                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1812                                                 }else{
1813 #endif /* X11 */
1814                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1815                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1816 #ifdef X11
1817                                                 }
1818 #endif /* X11 */
1819                                         } else {
1820 #ifdef X11
1821                                                 if(output_methods & TO_X) {
1822                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1823                                                                 (int) (obj->data.fsbar.fs->avail * 255 /
1824                                                                 obj->data.fs->size));
1825                                                 }else{
1826 #endif /* X11 */
1827                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1828                                                         new_bar_in_shell(p, p_max_size,
1829                                                                 (int) (obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1830 #ifdef X11
1831                                                 }
1832 #endif /* X11 */
1833                                         }
1834                                 }
1835                         }
1836                         OBJ(fs_used_perc) {
1837                                 if (obj->data.fs != NULL) {
1838                                         int val = 0;
1839
1840                                         if (obj->data.fs->size) {
1841                                                 val = obj->data.fs->free
1842                                                                 * 100 /
1843                                                         obj->data.fs->size;
1844                                         }
1845
1846                                         percent_print(p, p_max_size, 100 - val);
1847                                 }
1848                         }
1849                         OBJ(loadavg) {
1850                                 float *v = info.loadavg;
1851
1852                                 if (obj->data.loadavg[2]) {
1853                                         snprintf(p, p_max_size, "%.2f %.2f %.2f",
1854                                                 v[obj->data.loadavg[0] - 1],
1855                                                 v[obj->data.loadavg[1] - 1],
1856                                                 v[obj->data.loadavg[2] - 1]);
1857                                 } else if (obj->data.loadavg[1]) {
1858                                         snprintf(p, p_max_size, "%.2f %.2f",
1859                                                 v[obj->data.loadavg[0] - 1],
1860                                                 v[obj->data.loadavg[1] - 1]);
1861                                 } else if (obj->data.loadavg[0]) {
1862                                         snprintf(p, p_max_size, "%.2f",
1863                                                 v[obj->data.loadavg[0] - 1]);
1864                                 }
1865                         }
1866                         OBJ(goto) {
1867                                 new_goto(p, obj->data.i);
1868                         }
1869                         OBJ(tab) {
1870                                 new_tab(p, obj->data.pair.a, obj->data.pair.b);
1871                         }
1872 #ifdef X11
1873                         OBJ(hr) {
1874                                 new_hr(p, obj->data.i);
1875                         }
1876 #endif
1877                         OBJ(nameserver) {
1878                                 if (cur->nameserver_info.nscount > obj->data.i)
1879                                         snprintf(p, p_max_size, "%s",
1880                                                         cur->nameserver_info.ns_list[obj->data.i]);
1881                         }
1882 #ifdef EVE
1883                         OBJ(eve) {
1884                                 char *skill = eve(obj->data.eve.userid, obj->data.eve.apikey, obj->data.eve.charid);
1885                                 snprintf(p, p_max_size, "%s", skill);
1886                         }
1887 #endif
1888 #ifdef HAVE_CURL
1889                         OBJ(curl) {
1890                                 if (obj->data.curl.uri != NULL) {
1891                                         ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval);
1892                                 } else {
1893                                         NORM_ERR("error processing Curl data");
1894                                 }
1895                         }
1896 #endif
1897 #ifdef RSS
1898                         OBJ(rss) {
1899                                 if (obj->data.rss.uri != NULL) {
1900                                         rss_process_info(p, p_max_size, obj->data.rss.uri, obj->data.rss.action, obj->data.rss.act_par, obj->data.rss.interval, obj->data.rss.nrspaces);
1901                                 } else {
1902                                         NORM_ERR("error processing RSS data");
1903                                 }
1904                         }
1905 #endif
1906 #ifdef WEATHER
1907                         OBJ(weather) {
1908                                 if (obj->data.weather.uri != NULL) {
1909                                         weather_process_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
1910                                 } else {
1911                                         NORM_ERR("error processing weather data, check that you have a valid XOAP key if using XOAP.");
1912                                 }
1913                         }
1914 #endif
1915 #ifdef XOAP
1916                         OBJ(weather_forecast) {
1917                                 if (obj->data.weather_forecast.uri != NULL) {
1918                                         weather_forecast_process_info(p, p_max_size, obj->data.weather_forecast.uri, obj->data.weather_forecast.day, obj->data.weather_forecast.data_type, obj->data.weather_forecast.interval);
1919                                 } else {
1920                                         NORM_ERR("error processing weather forecast data, check that you have a valid XOAP key if using XOAP.");
1921                                 }
1922                         }
1923 #endif
1924 #ifdef HAVE_LUA
1925                         OBJ(lua) {
1926                                 char *str = llua_getstring(obj->data.s);
1927                                 if (str) {
1928                                         snprintf(p, p_max_size, "%s", str);
1929                                         free(str);
1930                                 }
1931                         }
1932                         OBJ(lua_parse) {
1933                                 char *str = llua_getstring(obj->data.s);
1934                                 if (str) {
1935                                         evaluate(str, p);
1936                                         free(str);
1937                                 }
1938                         }
1939                         OBJ(lua_bar) {
1940                                 double per;
1941                                 if (llua_getnumber(obj->data.s, &per)) {
1942 #ifdef X11
1943                                         if(output_methods & TO_X) {
1944                                                 new_bar(p, obj->a, obj->b, (per/100.0 * 255));
1945                                         } else {
1946 #endif /* X11 */
1947                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1948                                                 new_bar_in_shell(p, p_max_size, per, obj->a);
1949 #ifdef X11
1950                                         }
1951 #endif /* X11 */
1952                                 }
1953                         }
1954 #ifdef X11
1955                         OBJ(lua_graph) {
1956                                 double per;
1957                                 if (llua_getnumber(obj->data.s, &per)) {
1958                                         new_graph(p, obj->a, obj->b, obj->c, obj->d,
1959                                                         per, obj->e, 1, obj->char_a, obj->char_b);
1960                                 }
1961                         }
1962                         OBJ(lua_gauge) {
1963                                 double per;
1964                                 if (llua_getnumber(obj->data.s, &per)) {
1965                                         new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
1966                                 }
1967                         }
1968 #endif /* X11 */
1969 #endif /* HAVE_LUA */
1970 #ifdef HDDTEMP
1971                         OBJ(hddtemp) {
1972                                 char *endptr, unit;
1973                                 long val;
1974                                 if (obj->data.hddtemp.update_time < current_update_time - 30) {
1975                                         if (obj->data.hddtemp.temp)
1976                                                 free(obj->data.hddtemp.temp);
1977                                         obj->data.hddtemp.temp = get_hddtemp_info(obj->data.hddtemp.dev,
1978                                                         obj->data.hddtemp.addr, obj->data.hddtemp.port);
1979                                         obj->data.hddtemp.update_time = current_update_time;
1980                                 }
1981                                 if (!obj->data.hddtemp.temp) {
1982                                         snprintf(p, p_max_size, "N/A");
1983                                 } else {
1984                                         val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
1985                                         unit = obj->data.hddtemp.temp[0];
1986
1987                                         if (*endptr != '\0')
1988                                                 snprintf(p, p_max_size, "N/A");
1989                                         else if (unit == 'C')
1990                                                 temp_print(p, p_max_size, (double)val, TEMP_CELSIUS);
1991                                         else if (unit == 'F')
1992                                                 temp_print(p, p_max_size, (double)val, TEMP_FAHRENHEIT);
1993                                         else
1994                                                 snprintf(p, p_max_size, "N/A");
1995                                 }
1996                         }
1997 #endif
1998                         OBJ(offset) {
1999                                 new_offset(p, obj->data.i);
2000                         }
2001                         OBJ(voffset) {
2002                                 new_voffset(p, obj->data.i);
2003                         }
2004 #ifdef __linux__
2005                         OBJ(i2c) {
2006                                 double r;
2007
2008                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
2009                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
2010
2011                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
2012
2013                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
2014                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
2015                                 } else if (r >= 100.0 || r == 0) {
2016                                         snprintf(p, p_max_size, "%d", (int) r);
2017                                 } else {
2018                                         snprintf(p, p_max_size, "%.1f", r);
2019                                 }
2020                         }
2021                         OBJ(platform) {
2022                                 double r;
2023
2024                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
2025                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
2026
2027                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
2028
2029                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
2030                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
2031                                 } else if (r >= 100.0 || r == 0) {
2032                                         snprintf(p, p_max_size, "%d", (int) r);
2033                                 } else {
2034                                         snprintf(p, p_max_size, "%.1f", r);
2035                                 }
2036                         }
2037                         OBJ(hwmon) {
2038                                 double r;
2039
2040                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
2041                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
2042
2043                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
2044
2045                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
2046                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
2047                                 } else if (r >= 100.0 || r == 0) {
2048                                         snprintf(p, p_max_size, "%d", (int) r);
2049                                 } else {
2050                                         snprintf(p, p_max_size, "%.1f", r);
2051                                 }
2052                         }
2053 #endif /* __linux__ */
2054                         OBJ(alignr) {
2055                                 new_alignr(p, obj->data.i);
2056                         }
2057                         OBJ(alignc) {
2058                                 new_alignc(p, obj->data.i);
2059                         }
2060                         OBJ(if_empty) {
2061                                 char buf[max_user_text];
2062                                 struct information *tmp_info =
2063                                         malloc(sizeof(struct information));
2064                                 memcpy(tmp_info, cur, sizeof(struct information));
2065                                 generate_text_internal(buf, max_user_text,
2066                                                        *obj->sub, tmp_info);
2067
2068                                 if (strlen(buf) != 0) {
2069                                         DO_JUMP;
2070                                 }
2071                                 free(tmp_info);
2072                         }
2073                         OBJ(if_match) {
2074                                 char expression[max_user_text];
2075                                 int val;
2076                                 struct information *tmp_info;
2077
2078                                 tmp_info = malloc(sizeof(struct information));
2079                                 memcpy(tmp_info, cur, sizeof(struct information));
2080                                 generate_text_internal(expression, max_user_text,
2081                                                        *obj->sub, tmp_info);
2082                                 DBGP("parsed arg into '%s'", expression);
2083
2084                                 val = compare(expression);
2085                                 if (val == -2) {
2086                                         NORM_ERR("compare failed for expression '%s'",
2087                                                         expression);
2088                                 } else if (!val) {
2089                                         DO_JUMP;
2090                                 }
2091                                 free(tmp_info);
2092                         }
2093                         OBJ(if_existing) {
2094                                 if (obj->data.ifblock.str
2095                                     && !check_contains(obj->data.ifblock.s,
2096                                                        obj->data.ifblock.str)) {
2097                                         DO_JUMP;
2098                                 } else if (obj->data.ifblock.s
2099                                            && access(obj->data.ifblock.s, F_OK)) {
2100                                         DO_JUMP;
2101                                 }
2102                         }
2103                         OBJ(if_mounted) {
2104                                 if ((obj->data.ifblock.s)
2105                                                 && (!check_mount(obj->data.ifblock.s))) {
2106                                         DO_JUMP;
2107                                 }
2108                         }
2109                         OBJ(if_running) {
2110 #ifdef __linux__
2111                                 if (!get_process_by_name(obj->data.ifblock.s)) {
2112 #else
2113                                 if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
2114 #endif
2115                                         DO_JUMP;
2116                                 }
2117                         }
2118 #if defined(__linux__)
2119                         OBJ(ioscheduler) {
2120                                 snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
2121                         }
2122 #endif
2123                         OBJ(kernel) {
2124                                 snprintf(p, p_max_size, "%s", cur->uname_s.release);
2125                         }
2126                         OBJ(machine) {
2127                                 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
2128                         }
2129
2130                         /* memory stuff */
2131                         OBJ(mem) {
2132                                 human_readable(cur->mem * 1024, p, 255);
2133                         }
2134                         OBJ(memeasyfree) {
2135                                 human_readable(cur->memeasyfree * 1024, p, 255);
2136                         }
2137                         OBJ(memfree) {
2138                                 human_readable(cur->memfree * 1024, p, 255);
2139                         }
2140                         OBJ(memmax) {
2141                                 human_readable(cur->memmax * 1024, p, 255);
2142                         }
2143                         OBJ(memperc) {
2144                                 if (cur->memmax)
2145                                         percent_print(p, p_max_size, cur->mem * 100 / cur->memmax);
2146                         }
2147 #ifdef X11
2148                         OBJ(memgauge){
2149                                 new_gauge(p, obj->data.pair.a, obj->data.pair.b,
2150                                         cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
2151                         }
2152 #endif /* X11 */
2153                         OBJ(membar) {
2154 #ifdef X11
2155                                 if(output_methods & TO_X) {
2156                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
2157                                                 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
2158                                 }else{
2159 #endif /* X11 */
2160                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
2161                                         new_bar_in_shell(p, p_max_size, cur->memmax ? (cur->mem * 100) / (cur->memmax) : 0, obj->data.pair.a);
2162 #ifdef X11
2163                                 }
2164 #endif /* X11 */
2165                         }
2166 #ifdef X11
2167                         OBJ(memgraph) {
2168                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2169                                         cur->memmax ? (cur->mem * 100.0) / (cur->memmax) : 0.0,
2170                                         100, 1, obj->char_a, obj->char_b);
2171                         }
2172 #endif /* X11 */
2173                         /* mixer stuff */
2174                         OBJ(mixer) {
2175                                 percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
2176                         }
2177                         OBJ(mixerl) {
2178                                 percent_print(p, p_max_size, mixer_get_left(obj->data.l));
2179                         }
2180                         OBJ(mixerr) {
2181                                 percent_print(p, p_max_size, mixer_get_right(obj->data.l));
2182                         }
2183 #ifdef X11
2184                         OBJ(mixerbar) {
2185                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
2186                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_avg(obj->data.mixerbar.l)));
2187                         }
2188                         OBJ(mixerlbar) {
2189                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
2190                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_left(obj->data.mixerbar.l)));
2191                         }
2192                         OBJ(mixerrbar) {
2193                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
2194                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_right(obj->data.mixerbar.l)));
2195                         }
2196 #endif /* X11 */
2197                         OBJ(if_mixer_mute) {
2198                                 if (!mixer_is_mute(obj->data.ifblock.i)) {
2199                                         DO_JUMP;
2200                                 }
2201                         }
2202 #ifdef X11
2203 #define NOT_IN_X "Not running in X"
2204                         OBJ(monitor) {
2205                                 if(x_initialised != YES) {
2206                                         strncpy(p, NOT_IN_X, p_max_size);
2207                                 }else{
2208                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
2209                                 }
2210                         }
2211                         OBJ(monitor_number) {
2212                                 if(x_initialised != YES) {
2213                                         strncpy(p, NOT_IN_X, p_max_size);
2214                                 }else{
2215                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
2216                                 }
2217                         }
2218                         OBJ(desktop) {
2219                                 if(x_initialised != YES) {
2220                                         strncpy(p, NOT_IN_X, p_max_size);
2221                                 }else{
2222                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
2223                                 }
2224                         }
2225                         OBJ(desktop_number) {
2226                                 if(x_initialised != YES) {
2227                                         strncpy(p, NOT_IN_X, p_max_size);
2228                                 }else{
2229                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
2230                                 }
2231                         }
2232                         OBJ(desktop_name) {
2233                                 if(x_initialised != YES) {
2234                                         strncpy(p, NOT_IN_X, p_max_size);
2235                                 }else if(cur->x11.desktop.name != NULL) {
2236                                         strncpy(p, cur->x11.desktop.name, p_max_size);
2237                                 }
2238                         }
2239 #endif /* X11 */
2240
2241                         /* mail stuff */
2242                         OBJ(mails) {
2243                                 update_mail_count(&obj->data.local_mail);
2244                                 snprintf(p, p_max_size, "%d", obj->data.local_mail.mail_count);
2245                         }
2246                         OBJ(new_mails) {
2247                                 update_mail_count(&obj->data.local_mail);
2248                                 snprintf(p, p_max_size, "%d",
2249                                         obj->data.local_mail.new_mail_count);
2250                         }
2251                         OBJ(seen_mails) {
2252                                 update_mail_count(&obj->data.local_mail);
2253                                 snprintf(p, p_max_size, "%d",
2254                                         obj->data.local_mail.seen_mail_count);
2255                         }
2256                         OBJ(unseen_mails) {
2257                                 update_mail_count(&obj->data.local_mail);
2258                                 snprintf(p, p_max_size, "%d",
2259                                         obj->data.local_mail.unseen_mail_count);
2260                         }
2261                         OBJ(flagged_mails) {
2262                                 update_mail_count(&obj->data.local_mail);
2263                                 snprintf(p, p_max_size, "%d",
2264                                         obj->data.local_mail.flagged_mail_count);
2265                         }
2266                         OBJ(unflagged_mails) {
2267                                 update_mail_count(&obj->data.local_mail);
2268                                 snprintf(p, p_max_size, "%d",
2269                                         obj->data.local_mail.unflagged_mail_count);
2270                         }
2271                         OBJ(forwarded_mails) {
2272                                 update_mail_count(&obj->data.local_mail);
2273                                 snprintf(p, p_max_size, "%d",
2274                                         obj->data.local_mail.forwarded_mail_count);
2275                         }
2276                         OBJ(unforwarded_mails) {
2277                                 update_mail_count(&obj->data.local_mail);
2278                                 snprintf(p, p_max_size, "%d",
2279                                         obj->data.local_mail.unforwarded_mail_count);
2280                         }
2281                         OBJ(replied_mails) {
2282                                 update_mail_count(&obj->data.local_mail);
2283                                 snprintf(p, p_max_size, "%d",
2284                                         obj->data.local_mail.replied_mail_count);
2285                         }
2286                         OBJ(unreplied_mails) {
2287                                 update_mail_count(&obj->data.local_mail);
2288                                 snprintf(p, p_max_size, "%d",
2289                                         obj->data.local_mail.unreplied_mail_count);
2290                         }
2291                         OBJ(draft_mails) {
2292                                 update_mail_count(&obj->data.local_mail);
2293                                 snprintf(p, p_max_size, "%d",
2294                                         obj->data.local_mail.draft_mail_count);
2295                         }
2296                         OBJ(trashed_mails) {
2297                                 update_mail_count(&obj->data.local_mail);
2298                                 snprintf(p, p_max_size, "%d",
2299                                         obj->data.local_mail.trashed_mail_count);
2300                         }
2301                         OBJ(mboxscan) {
2302                                 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
2303                                         text_buffer_size);
2304                                 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
2305                         }
2306                         OBJ(nodename) {
2307                                 snprintf(p, p_max_size, "%s", cur->uname_s.nodename);
2308                         }
2309                         OBJ(outlinecolor) {
2310                                 new_outline(p, obj->data.l);
2311                         }
2312                         OBJ(processes) {
2313                                 spaced_print(p, p_max_size, "%hu", 4, cur->procs);
2314                         }
2315                         OBJ(running_processes) {
2316                                 spaced_print(p, p_max_size, "%hu", 4, cur->run_procs);
2317                         }
2318                         OBJ(text) {
2319                                 snprintf(p, p_max_size, "%s", obj->data.s);
2320                         }
2321 #ifdef X11
2322                         OBJ(shadecolor) {
2323                                 new_bg(p, obj->data.l);
2324                         }
2325                         OBJ(stippled_hr) {
2326                                 new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
2327                         }
2328 #endif /* X11 */
2329                         OBJ(swap) {
2330                                 human_readable(cur->swap * 1024, p, 255);
2331                         }
2332                         OBJ(swapfree) {
2333                                 human_readable(cur->swapfree * 1024, p, 255);
2334                         }
2335                         OBJ(swapmax) {
2336                                 human_readable(cur->swapmax * 1024, p, 255);
2337                         }
2338                         OBJ(swapperc) {
2339                                 if (cur->swapmax == 0) {
2340                                         strncpy(p, "No swap", p_max_size);
2341                                 } else {
2342                                         percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
2343                                 }
2344                         }
2345                         OBJ(swapbar) {
2346 #ifdef X11
2347                                 if(output_methods & TO_X) {
2348                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
2349                                                 cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
2350                                 }else{
2351 #endif /* X11 */
2352                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
2353                                         new_bar_in_shell(p, p_max_size, cur->swapmax ? (cur->swap * 100) / (cur->swapmax) : 0, obj->data.pair.a);
2354 #ifdef X11
2355                                 }
2356 #endif /* X11 */
2357                         }
2358                         OBJ(sysname) {
2359                                 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
2360                         }
2361                         OBJ(time) {
2362                                 time_t t = time(NULL);
2363                                 struct tm *tm = localtime(&t);
2364
2365                                 setlocale(LC_TIME, "");
2366                                 strftime(p, p_max_size, obj->data.s, tm);
2367                         }
2368                         OBJ(utime) {
2369                                 time_t t = time(NULL);
2370                                 struct tm *tm = gmtime(&t);
2371
2372                                 strftime(p, p_max_size, obj->data.s, tm);
2373                         }
2374                         OBJ(tztime) {
2375                                 char *oldTZ = NULL;
2376                                 time_t t;
2377                                 struct tm *tm;
2378
2379                                 if (obj->data.tztime.tz) {
2380                                         oldTZ = getenv("TZ");
2381                                         setenv("TZ", obj->data.tztime.tz, 1);
2382                                         tzset();
2383                                 }
2384                                 t = time(NULL);
2385                                 tm = localtime(&t);
2386
2387                                 setlocale(LC_TIME, "");
2388                                 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
2389                                 if (oldTZ) {
2390                                         setenv("TZ", oldTZ, 1);
2391                                         tzset();
2392                                 } else {
2393                                         unsetenv("TZ");
2394                                 }
2395                                 // Needless to free oldTZ since getenv gives ptr to static data
2396                         }
2397                         OBJ(totaldown) {
2398                                 human_readable(obj->data.net->recv, p, 255);
2399                         }
2400                         OBJ(totalup) {
2401                                 human_readable(obj->data.net->trans, p, 255);
2402                         }
2403                         OBJ(updates) {
2404                                 snprintf(p, p_max_size, "%d", total_updates);
2405                         }
2406                         OBJ(if_updatenr) {
2407                                 if(total_updates % updatereset != obj->data.ifblock.i - 1) {
2408                                         DO_JUMP;
2409                                 }
2410                         }
2411                         OBJ(upspeed) {
2412                                 human_readable(obj->data.net->trans_speed, p, 255);
2413                         }
2414                         OBJ(upspeedf) {
2415                                 spaced_print(p, p_max_size, "%.1f", 8,
2416                                         obj->data.net->trans_speed / 1024.0);
2417                         }
2418 #ifdef X11
2419                         OBJ(upspeedgraph) {
2420                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2421                                         obj->data.net->trans_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
2422                         }
2423 #endif /* X11 */
2424                         OBJ(uptime_short) {
2425                                 format_seconds_short(p, p_max_size, (int) cur->uptime);
2426                         }
2427                         OBJ(uptime) {
2428                                 format_seconds(p, p_max_size, (int) cur->uptime);
2429                         }
2430                         OBJ(user_names) {
2431                                 snprintf(p, p_max_size, "%s", cur->users.names);
2432                         }
2433                         OBJ(user_terms) {
2434                                 snprintf(p, p_max_size, "%s", cur->users.terms);
2435                         }
2436                         OBJ(user_times) {
2437                                 snprintf(p, p_max_size, "%s", cur->users.times);
2438                         }
2439                         OBJ(user_number) {
2440                                 snprintf(p, p_max_size, "%d", cur->users.number);
2441                         }
2442 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
2443                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
2444                         OBJ(apm_adapter) {
2445                                 char *msg;
2446
2447                                 msg = get_apm_adapter();
2448                                 snprintf(p, p_max_size, "%s", msg);
2449                                 free(msg);
2450                         }
2451                         OBJ(apm_battery_life) {
2452                                 char *msg;
2453
2454                                 msg = get_apm_battery_life();
2455                                 snprintf(p, p_max_size, "%s", msg);
2456                                 free(msg);
2457                         }
2458                         OBJ(apm_battery_time) {
2459                                 char *msg;
2460
2461                                 msg = get_apm_battery_time();
2462                                 snprintf(p, p_max_size, "%s", msg);
2463                                 free(msg);
2464                         }
2465 #endif /* __FreeBSD__ __OpenBSD__ */
2466
2467 #ifdef MPD
2468 #define mpd_printf(fmt, val) \
2469         snprintf(p, p_max_size, fmt, mpd_get_info()->val)
2470 #define mpd_sprintf(val) { \
2471         if (!obj->data.i || obj->data.i > p_max_size) \
2472                 mpd_printf("%s", val); \
2473         else \
2474                 snprintf(p, obj->data.i, "%s", mpd_get_info()->val); \
2475 }
2476                         OBJ(mpd_title)
2477                                 mpd_sprintf(title);
2478                         OBJ(mpd_artist)
2479                                 mpd_sprintf(artist);
2480                         OBJ(mpd_album)
2481                                 mpd_sprintf(album);
2482                         OBJ(mpd_random)
2483                                 mpd_printf("%s", random);
2484                         OBJ(mpd_repeat)
2485                                 mpd_printf("%s", repeat);
2486                         OBJ(mpd_track)
2487                                 mpd_sprintf(track);
2488                         OBJ(mpd_name)
2489                                 mpd_sprintf(name);
2490                         OBJ(mpd_file)
2491                                 mpd_sprintf(file);
2492                         OBJ(mpd_vol)
2493                                 mpd_printf("%d", volume);
2494                         OBJ(mpd_bitrate)
2495                                 mpd_printf("%d", bitrate);
2496                         OBJ(mpd_status)
2497                                 mpd_printf("%s", status);
2498                         OBJ(mpd_elapsed) {
2499                                 format_media_player_time(p, p_max_size, mpd_get_info()->elapsed);
2500                         }
2501                         OBJ(mpd_length) {
2502                                 format_media_player_time(p, p_max_size, mpd_get_info()->length);
2503                         }
2504                         OBJ(mpd_percent) {
2505                                 percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
2506                         }
2507                         OBJ(mpd_bar) {
2508 #ifdef X11
2509                                 if(output_methods & TO_X) {
2510                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
2511                                                 (int) (mpd_get_info()->progress * 255.0f));
2512                                 } else {
2513 #endif /* X11 */
2514                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
2515                                         new_bar_in_shell(p, p_max_size, (int) (mpd_get_info()->progress * 100.0f), obj->data.pair.a);
2516 #ifdef X11
2517                                 }
2518 #endif /* X11 */
2519                         }
2520                         OBJ(mpd_smart) {
2521                                 struct mpd_s *mpd = mpd_get_info();
2522                                 int len = obj->data.i;
2523                                 if (len == 0 || len > p_max_size)
2524                                         len = p_max_size;
2525
2526                                 memset(p, 0, p_max_size);
2527                                 if (mpd->artist && *mpd->artist &&
2528                                     mpd->title && *mpd->title) {
2529                                         snprintf(p, len, "%s - %s", mpd->artist,
2530                                                 mpd->title);
2531                                 } else if (mpd->title && *mpd->title) {
2532                                         snprintf(p, len, "%s", mpd->title);
2533                                 } else if (mpd->artist && *mpd->artist) {
2534                                         snprintf(p, len, "%s", mpd->artist);
2535                                 } else if (mpd->file && *mpd->file) {
2536                                         snprintf(p, len, "%s", mpd->file);
2537                                 } else {
2538                                         *p = 0;
2539                                 }
2540                         }
2541                         OBJ(if_mpd_playing) {
2542                                 if (!mpd_get_info()->is_playing) {
2543                                         DO_JUMP;
2544                                 }
2545                         }
2546 #undef mpd_sprintf
2547 #undef mpd_printf
2548 #endif
2549
2550 #ifdef MOC
2551 #define MOC_PRINT(t, a) \
2552         snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
2553                         OBJ(moc_state) {
2554                                 MOC_PRINT(state, "??");
2555                         }
2556                         OBJ(moc_file) {
2557                                 MOC_PRINT(file, "no file");
2558                         }
2559                         OBJ(moc_title) {
2560                                 MOC_PRINT(title, "no title");
2561                         }
2562                         OBJ(moc_artist) {
2563                                 MOC_PRINT(artist, "no artist");
2564                         }
2565                         OBJ(moc_song) {
2566                                 MOC_PRINT(song, "no song");
2567                         }
2568                         OBJ(moc_album) {
2569                                 MOC_PRINT(album, "no album");
2570                         }
2571                         OBJ(moc_totaltime) {
2572                                 MOC_PRINT(totaltime, "0:00");
2573                         }
2574                         OBJ(moc_timeleft) {
2575                                 MOC_PRINT(timeleft, "0:00");
2576                         }
2577                         OBJ(moc_curtime) {
2578                                 MOC_PRINT(curtime, "0:00");
2579                         }
2580                         OBJ(moc_bitrate) {
2581                                 MOC_PRINT(bitrate, "0Kbps");
2582                         }
2583                         OBJ(moc_rate) {
2584                                 MOC_PRINT(rate, "0KHz");
2585                         }
2586 #undef MOC_PRINT
2587 #endif /* MOC */
2588 #ifdef XMMS2
2589                         OBJ(xmms2_artist) {
2590                                 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
2591                         }
2592                         OBJ(xmms2_album) {
2593                                 snprintf(p, p_max_size, "%s", cur->xmms2.album);
2594                         }
2595                         OBJ(xmms2_title) {
2596                                 snprintf(p, p_max_size, "%s", cur->xmms2.title);
2597                         }
2598                         OBJ(xmms2_genre) {
2599                                 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
2600                         }
2601                         OBJ(xmms2_comment) {
2602                                 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
2603                         }
2604                         OBJ(xmms2_url) {
2605                                 snprintf(p, p_max_size, "%s", cur->xmms2.url);
2606                         }
2607                         OBJ(xmms2_status) {
2608                                 snprintf(p, p_max_size, "%s", cur->xmms2.status);
2609                         }
2610                         OBJ(xmms2_date) {
2611                                 snprintf(p, p_max_size, "%s", cur->xmms2.date);
2612                         }
2613                         OBJ(xmms2_tracknr) {
2614                                 if (cur->xmms2.tracknr != -1) {
2615                                         snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
2616                                 }
2617                         }
2618                         OBJ(xmms2_bitrate) {
2619                                 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
2620                         }
2621                         OBJ(xmms2_id) {
2622                                 snprintf(p, p_max_size, "%u", cur->xmms2.id);
2623                         }
2624                         OBJ(xmms2_size) {
2625                                 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
2626                         }
2627                         OBJ(xmms2_elapsed) {
2628                                 snprintf(p, p_max_size, "%02d:%02d", cur->xmms2.elapsed / 60000,
2629                                         (cur->xmms2.elapsed / 1000) % 60);
2630                         }
2631                         OBJ(xmms2_duration) {
2632                                 snprintf(p, p_max_size, "%02d:%02d",
2633                                         cur->xmms2.duration / 60000,
2634                                         (cur->xmms2.duration / 1000) % 60);
2635                         }
2636                         OBJ(xmms2_percent) {
2637                                 snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
2638                         }
2639 #ifdef X11
2640                         OBJ(xmms2_bar) {
2641                                 new_bar(p, obj->data.pair.a, obj->data.pair.b,
2642                                         (int) (cur->xmms2.progress * 255.0f));
2643                         }
2644 #endif /* X11 */
2645                         OBJ(xmms2_playlist) {
2646                                 snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
2647                         }
2648                         OBJ(xmms2_timesplayed) {
2649                                 snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
2650                         }
2651                         OBJ(xmms2_smart) {
2652                                 if (strlen(cur->xmms2.title) < 2
2653                                                 && strlen(cur->xmms2.title) < 2) {
2654                                         snprintf(p, p_max_size, "%s", cur->xmms2.url);
2655                                 } else {
2656                                         snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist,
2657                                                 cur->xmms2.title);
2658                                 }
2659                         }
2660                         OBJ(if_xmms2_connected) {
2661                                 if (cur->xmms2.conn_state != 1) {
2662                                         DO_JUMP;
2663                                 }
2664                         }
2665 #endif /* XMMS */
2666 #ifdef AUDACIOUS
2667                         OBJ(audacious_status) {
2668                                 snprintf(p, p_max_size, "%s",
2669                                         cur->audacious.items[AUDACIOUS_STATUS]);
2670                         }
2671                         OBJ(audacious_title) {
2672                                 snprintf(p, cur->audacious.max_title_len > 0
2673                                         ? cur->audacious.max_title_len : p_max_size, "%s",
2674                                         cur->audacious.items[AUDACIOUS_TITLE]);
2675                         }
2676                         OBJ(audacious_length) {
2677                                 snprintf(p, p_max_size, "%s",
2678                                         cur->audacious.items[AUDACIOUS_LENGTH]);
2679                         }
2680                         OBJ(audacious_length_seconds) {
2681                                 snprintf(p, p_max_size, "%s",
2682                                         cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
2683                         }
2684                         OBJ(audacious_position) {
2685                                 snprintf(p, p_max_size, "%s",
2686                                         cur->audacious.items[AUDACIOUS_POSITION]);
2687                         }
2688                         OBJ(audacious_position_seconds) {
2689                                 snprintf(p, p_max_size, "%s",
2690                                         cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
2691                         }
2692                         OBJ(audacious_bitrate) {
2693                                 snprintf(p, p_max_size, "%s",
2694                                         cur->audacious.items[AUDACIOUS_BITRATE]);
2695                         }
2696                         OBJ(audacious_frequency) {
2697                                 snprintf(p, p_max_size, "%s",
2698                                         cur->audacious.items[AUDACIOUS_FREQUENCY]);
2699                         }
2700                         OBJ(audacious_channels) {
2701                                 snprintf(p, p_max_size, "%s",
2702                                         cur->audacious.items[AUDACIOUS_CHANNELS]);
2703                         }
2704                         OBJ(audacious_filename) {
2705                                 snprintf(p, p_max_size, "%s",
2706                                         cur->audacious.items[AUDACIOUS_FILENAME]);
2707                         }
2708                         OBJ(audacious_playlist_length) {
2709                                 snprintf(p, p_max_size, "%s",
2710                                         cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
2711                         }
2712                         OBJ(audacious_playlist_position) {
2713                                 snprintf(p, p_max_size, "%s",
2714                                         cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
2715                         }
2716                         OBJ(audacious_main_volume) {
2717                                 snprintf(p, p_max_size, "%s",
2718                                         cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
2719                         }
2720 #ifdef X11
2721                         OBJ(audacious_bar) {
2722                                 double progress;
2723
2724                                 progress =
2725                                         atof(cur->audacious.items[AUDACIOUS_POSITION_SECONDS]) /
2726                                         atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
2727                                 new_bar(p, obj->a, obj->b, (int) (progress * 255.0f));
2728                         }
2729 #endif /* X11 */
2730 #endif /* AUDACIOUS */
2731
2732 #ifdef BMPX
2733                         OBJ(bmpx_title) {
2734                                 snprintf(p, p_max_size, "%s", cur->bmpx.title);
2735                         }
2736                         OBJ(bmpx_artist) {
2737                                 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
2738                         }
2739                         OBJ(bmpx_album) {
2740                                 snprintf(p, p_max_size, "%s", cur->bmpx.album);
2741                         }
2742                         OBJ(bmpx_uri) {
2743                                 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
2744                         }
2745                         OBJ(bmpx_track) {
2746                                 snprintf(p, p_max_size, "%i", cur->bmpx.track);
2747                         }
2748                         OBJ(bmpx_bitrate) {
2749                                 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
2750                         }
2751 #endif /* BMPX */
2752                         /* we have four different types of top (top, top_mem,
2753                          * top_time and top_io). To avoid having almost-same code four
2754                          * times, we have this special handler. */
2755                         break;
2756                         case OBJ_top:
2757                                 parse_top_args("top", obj->data.top.s, obj);
2758                                 if (!needed) needed = cur->cpu;
2759                         case OBJ_top_mem:
2760                                 parse_top_args("top_mem", obj->data.top.s, obj);
2761                                 if (!needed) needed = cur->memu;
2762                         case OBJ_top_time:
2763                                 parse_top_args("top_time", obj->data.top.s, obj);
2764                                 if (!needed) needed = cur->time;
2765 #ifdef IOSTATS
2766                         case OBJ_top_io:
2767                                 parse_top_args("top_io", obj->data.top.s, obj);
2768                                 if (!needed) needed = cur->io;
2769 #endif
2770
2771                                 if (needed[obj->data.top.num]) {
2772                                         char *timeval;
2773
2774                                         switch (obj->data.top.type) {
2775                                                 case TOP_NAME:
2776                                                         snprintf(p, top_name_width + 1, "%-*s", top_name_width,
2777                                                                         needed[obj->data.top.num]->name);
2778                                                         break;
2779                                                 case TOP_CPU:
2780                                                         snprintf(p, 7, "%6.2f",
2781                                                                         needed[obj->data.top.num]->amount);
2782                                                         break;
2783                                                 case TOP_PID:
2784                                                         snprintf(p, 6, "%5i",
2785                                                                         needed[obj->data.top.num]->pid);
2786                                                         break;
2787                                                 case TOP_MEM:
2788                                                         snprintf(p, 7, "%6.2f",
2789                                                                         needed[obj->data.top.num]->totalmem);
2790                                                         break;
2791                                                 case TOP_TIME:
2792                                                         timeval = format_time(
2793                                                                         needed[obj->data.top.num]->total_cpu_time, 9);
2794                                                         snprintf(p, 10, "%9s", timeval);
2795                                                         free(timeval);
2796                                                         break;
2797                                                 case TOP_MEM_RES:
2798                                                         human_readable(needed[obj->data.top.num]->rss,
2799                                                                         p, 255);
2800                                                         break;
2801                                                 case TOP_MEM_VSIZE:
2802                                                         human_readable(needed[obj->data.top.num]->vsize,
2803                                                                         p, 255);
2804                                                         break;
2805 #ifdef IOSTATS
2806                                                 case TOP_READ_BYTES:
2807                                                         human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
2808                                                                         p, 255);
2809                                                         break;
2810                                                 case TOP_WRITE_BYTES:
2811                                                         human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
2812                                                                         p, 255);
2813                                                         break;
2814                                                 case TOP_IO_PERC:
2815                                                         snprintf(p, 7, "%6.2f",
2816                                                                         needed[obj->data.top.num]->io_perc);
2817                                                         break;
2818 #endif
2819                                         }
2820                                 }
2821                         OBJ(tail) {
2822                                 print_tailhead("tail", obj, p, p_max_size);
2823                         }
2824                         OBJ(head) {
2825                                 print_tailhead("head", obj, p, p_max_size);
2826                         }
2827                         OBJ(lines) {
2828                                 FILE *fp = open_file(obj->data.s, &obj->a);
2829
2830                                 if(fp != NULL) {
2831 /* FIXME: use something more general (see also tail.c, head.c */
2832 #define BUFSZ 0x1000
2833                                         char buf[BUFSZ];
2834                                         int j, lines;
2835
2836                                         lines = 0;
2837                                         while(fgets(buf, BUFSZ, fp) != NULL){
2838                                                 for(j = 0; buf[j] != 0; j++) {
2839                                                         if(buf[j] == '\n') {
2840                                                                 lines++;
2841                                                         }
2842                                                 }
2843                                         }
2844                                         sprintf(p, "%d", lines);
2845                                         fclose(fp);
2846                                 } else {
2847                                         sprintf(p, "File Unreadable");
2848                                 }
2849                         }
2850
2851                         OBJ(words) {
2852                                 FILE *fp = open_file(obj->data.s, &obj->a);
2853
2854                                 if(fp != NULL) {
2855                                         char buf[BUFSZ];
2856                                         int j, words;
2857                                         char inword = FALSE;
2858
2859                                         words = 0;
2860                                         while(fgets(buf, BUFSZ, fp) != NULL){
2861                                                 for(j = 0; buf[j] != 0; j++) {
2862                                                         if(!isspace(buf[j])) {
2863                                                                 if(inword == FALSE) {
2864                                                                         words++;
2865                                                                         inword = TRUE;
2866                                                                 }
2867                                                         } else {
2868                                                                 inword = FALSE;
2869                                                         }
2870                                                 }
2871                                         }
2872                                         sprintf(p, "%d", words);
2873                                         fclose(fp);
2874                                 } else {
2875                                         sprintf(p, "File Unreadable");
2876                                 }
2877                         }
2878 #ifdef TCP_PORT_MONITOR
2879                         OBJ(tcp_portmon) {
2880                                 tcp_portmon_action(p, p_max_size,
2881                                                    &obj->data.tcp_port_monitor);
2882                         }
2883 #endif /* TCP_PORT_MONITOR */
2884
2885 #ifdef HAVE_ICONV
2886                         OBJ(iconv_start) {
2887                                 set_iconv_converting(1);
2888                                 set_iconv_selected(obj->a);
2889                         }
2890                         OBJ(iconv_stop) {
2891                                 set_iconv_converting(0);
2892                                 set_iconv_selected(0);
2893                         }
2894 #endif /* HAVE_ICONV */
2895
2896                         OBJ(entropy_avail) {
2897                                 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
2898                         }
2899                         OBJ(entropy_perc) {
2900                                 percent_print(p, p_max_size,
2901                                               cur->entropy.entropy_avail *
2902                                               100 / cur->entropy.poolsize);
2903                         }
2904                         OBJ(entropy_poolsize) {
2905                                 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
2906                         }
2907                         OBJ(entropy_bar) {
2908                                 double entropy_perc;
2909
2910                                 entropy_perc = (double) cur->entropy.entropy_avail /
2911                                         (double) cur->entropy.poolsize;
2912 #ifdef X11
2913                                 if(output_methods & TO_X) {
2914                                         new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
2915                                 } else {
2916 #endif /* X11 */
2917                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
2918                                         new_bar_in_shell(p, p_max_size, (int) (entropy_perc * 100.0f), obj->a);
2919 #ifdef X11
2920                                 }
2921 #endif /* X11 */
2922                         }
2923 #ifdef IBM
2924                         OBJ(smapi) {
2925                                 char *s;
2926                                 if(obj->data.s) {
2927                                         s = smapi_get_val(obj->data.s);
2928                                         snprintf(p, p_max_size, "%s", s);
2929                                         free(s);
2930                                 }
2931                         }
2932                         OBJ(if_smapi_bat_installed) {
2933                                 int idx;
2934                                 if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
2935                                         if(!smapi_bat_installed(idx)) {
2936                                                 DO_JUMP;
2937                                         }
2938                                 } else
2939                                         NORM_ERR("argument to if_smapi_bat_installed must be an integer");
2940                         }
2941                         OBJ(smapi_bat_perc) {
2942                                 int idx, val;
2943                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2944                                         val = smapi_bat_installed(idx) ?
2945                                                 smapi_get_bat_int(idx, "remaining_percent") : 0;
2946                                         percent_print(p, p_max_size, val);
2947                                 } else
2948                                         NORM_ERR("argument to smapi_bat_perc must be an integer");
2949                         }
2950                         OBJ(smapi_bat_temp) {
2951                                 int idx, val;
2952                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2953                                         val = smapi_bat_installed(idx) ?
2954                                                 smapi_get_bat_int(idx, "temperature") : 0;
2955                                         /* temperature is in milli degree celsius */
2956                                         temp_print(p, p_max_size, val / 1000, TEMP_CELSIUS);
2957                                 } else
2958                                         NORM_ERR("argument to smapi_bat_temp must be an integer");
2959                         }
2960                         OBJ(smapi_bat_power) {
2961                                 int idx, val;
2962                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2963                                         val = smapi_bat_installed(idx) ?
2964                                                 smapi_get_bat_int(idx, "power_now") : 0;
2965                                         /* power_now is in mW, set to W with one digit precision */
2966                                         snprintf(p, p_max_size, "%.1f", ((double)val / 1000));
2967                                 } else
2968                                         NORM_ERR("argument to smapi_bat_power must be an integer");
2969                         }
2970 #ifdef X11
2971                         OBJ(smapi_bat_bar) {
2972                                 if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
2973                                         new_bar(p, obj->a, obj->b, (int)
2974                                                         (255 * smapi_get_bat_int(obj->data.i, "remaining_percent") / 100));
2975                                 else
2976                                         new_bar(p, obj->a, obj->b, 0);
2977                         }
2978 #endif /* X11 */
2979 #endif /* IBM */
2980                         OBJ(include) {
2981                                 if(obj->sub) {
2982                                         char buf[max_user_text];
2983
2984                                         generate_text_internal(buf, max_user_text, *obj->sub, cur);
2985                                         snprintf(p, p_max_size, "%s", buf);
2986                                 } else {
2987                                         p[0] = 0;
2988                                 }
2989                         }
2990                         OBJ(blink) {
2991                                 //blinking like this can look a bit ugly if the chars in the font don't have the same width
2992                                 char buf[max_user_text];
2993                                 unsigned int j;
2994
2995                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2996                                 snprintf(p, p_max_size, "%s", buf);
2997                                 if(total_updates % 2) {
2998                                         for(j=0; p[j] != 0; j++) {
2999                                                 p[j] = ' ';
3000                                         }
3001                                 }
3002                         }
3003                         OBJ(to_bytes) {
3004                                 char buf[max_user_text];
3005                                 long long bytes;
3006                                 char unit[16];  // 16 because we can also have long names (like mega-bytes)
3007
3008                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
3009                                 if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
3010                                         if(strncasecmp("b", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes);
3011                                         else if(strncasecmp("k", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024);
3012                                         else if(strncasecmp("m", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024);
3013                                         else if(strncasecmp("g", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024);
3014                                         else if(strncasecmp("t", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024 * 1024);
3015                                 }
3016                                 snprintf(p, p_max_size, "%s", buf);
3017                         }
3018                         OBJ(scroll) {
3019                                 unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
3020                                 char *pwithcolors;
3021                                 char buf[max_user_text];
3022                                 generate_text_internal(buf, max_user_text,
3023                                                        *obj->sub, cur);
3024                                 for(j = 0; buf[j] != 0; j++) {
3025                                         switch(buf[j]) {
3026                                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
3027 #define LINESEPARATOR '|'
3028                                                 buf[j]=LINESEPARATOR;
3029                                                 break;
3030                                         case SPECIAL_CHAR:
3031                                                 colorchanges++;
3032                                                 break;
3033                                         }
3034                                 }
3035                                 //no scrolling necessary if the length of the text to scroll is too short
3036                                 if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
3037                                         snprintf(p, p_max_size, "%s", buf);
3038                                         break;
3039                                 }
3040                                 //make sure a colorchange at the front is not part of the string we are going to show
3041                                 while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
3042                                         obj->data.scroll.start++;
3043                                 }
3044                                 //place all chars that should be visible in p, including colorchanges
3045                                 for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
3046                                         p[j] = *(buf + obj->data.scroll.start + j);
3047                                         if(p[j] == SPECIAL_CHAR) {
3048                                                 visibcolorchanges++;
3049                                         }
3050                                         //if there is still room fill it with spaces
3051                                         if( ! p[j]) break;
3052                                 }
3053                                 for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
3054                                         p[j] = ' ';
3055                                 }
3056                                 p[j] = 0;
3057                                 //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
3058                                 for(j = 0; j < obj->data.scroll.start; j++) {
3059                                         if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
3060                                 }
3061                                 pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
3062                                 for(j = 0; j < frontcolorchanges; j++) {
3063                                         pwithcolors[j] = SPECIAL_CHAR;
3064                                 }
3065                                 pwithcolors[j] = 0;
3066                                 strcat(pwithcolors,p);
3067                                 strend = strlen(pwithcolors);
3068                                 //and place the colorchanges not in front or in the visible part behind the visible part
3069                                 for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
3070                                         pwithcolors[strend + j] = SPECIAL_CHAR;
3071                                 }
3072                                 pwithcolors[strend + j] = 0;
3073                                 strcpy(p, pwithcolors);
3074                                 free(pwithcolors);
3075                                 //scroll
3076                                 obj->data.scroll.start += obj->data.scroll.step;
3077                                 if(buf[obj->data.scroll.start] == 0){
3078                                          obj->data.scroll.start = 0;
3079                                 }
3080 #ifdef X11
3081                                 //reset color when scroll is finished
3082                                 new_fg(p + strlen(p), obj->data.scroll.resetcolor);
3083 #endif
3084                         }
3085                         OBJ(combine) {
3086                                 char buf[2][max_user_text];
3087                                 int i, j;
3088                                 long longest=0;
3089                                 int nextstart;
3090                                 int nr_rows[2];
3091                                 struct llrows {
3092                                         char* row;
3093                                         struct llrows* next;
3094                                 };
3095                                 struct llrows *ll_rows[2], *current[2];
3096                                 struct text_object * objsub = obj->sub;
3097
3098                                 p[0]=0;
3099                                 for(i=0; i<2; i++) {
3100                                         nr_rows[i] = 1;
3101                                         nextstart = 0;
3102                                         ll_rows[i] = malloc(sizeof(struct llrows));
3103                                         current[i] = ll_rows[i];
3104                                         for(j=0; j<i; j++) objsub = objsub->sub;
3105                                         generate_text_internal(buf[i], max_user_text, *objsub, cur);
3106                                         for(j=0; buf[i][j] != 0; j++) {
3107                                                 if(buf[i][j] == '\t') buf[i][j] = ' ';
3108                                                 if(buf[i][j] == '\n') {
3109                                                         buf[i][j] = 0;
3110                                                         current[i]->row = strdup(buf[i]+nextstart);
3111                                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
3112                                                         current[i]->next = malloc(sizeof(struct llrows));
3113                                                         current[i] = current[i]->next;
3114                                                         nextstart = j + 1;
3115                                                         nr_rows[i]++;
3116                                                 }
3117                                         }
3118                                         current[i]->row = strdup(buf[i]+nextstart);
3119                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
3120                                         current[i]->next = NULL;
3121                                         current[i] = ll_rows[i];
3122                                 }
3123                                 for(j=0; j < (nr_rows[0] > nr_rows[1] ? nr_rows[0] : nr_rows[1] ); j++) {
3124                                         if(current[0]) {
3125                                                 strcat(p, current[0]->row);
3126                                                 i=strlen(current[0]->row);
3127                                         }else i = 0;
3128                                         while(i < longest) {
3129                                                 strcat(p, " ");
3130                                                 i++;
3131                                         }
3132                                         if(current[1]) {
3133                                                 strcat(p, obj->data.combine.seperation);
3134                                                 strcat(p, current[1]->row);
3135                                         }
3136                                         strcat(p, "\n");
3137                                         #ifdef HAVE_OPENMP
3138                                         #pragma omp parallel for schedule(dynamic,10)
3139                                         #endif /* HAVE_OPENMP */
3140                                         for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
3141                                 }
3142                                 #ifdef HAVE_OPENMP
3143                                 #pragma omp parallel for schedule(dynamic,10)
3144                                 #endif /* HAVE_OPENMP */
3145                                 for(i=0; i<2; i++) {
3146                                         while(ll_rows[i] != NULL) {
3147                                                 current[i]=ll_rows[i];
3148                                                 free(current[i]->row);
3149                                                 ll_rows[i]=current[i]->next;
3150                                                 free(current[i]);
3151                                         }
3152                                 }
3153                         }
3154 #ifdef NVIDIA
3155                         OBJ(nvidia) {
3156                                 int value = get_nvidia_value(obj->data.nvidia.type, display);
3157                                 if(value == -1)
3158                                         snprintf(p, p_max_size, "N/A");
3159                                 else if (obj->data.nvidia.type == NV_TEMP)
3160                                         temp_print(p, p_max_size, (double)value, TEMP_CELSIUS);
3161                                 else if (obj->data.nvidia.print_as_float &&
3162                                                 value > 0 && value < 100)
3163                                         snprintf(p, p_max_size, "%.1f", (float)value);
3164                                 else
3165                                         snprintf(p, p_max_size, "%d", value);
3166                         }
3167 #endif /* NVIDIA */
3168 #ifdef APCUPSD
3169                         OBJ(apcupsd) {
3170                                 /* This is just a meta-object to set host:port */
3171                         }
3172                         OBJ(apcupsd_name) {
3173                                 snprintf(p, p_max_size, "%s",
3174                                                  cur->apcupsd.items[APCUPSD_NAME]);
3175                         }
3176                         OBJ(apcupsd_model) {
3177                                 snprintf(p, p_max_size, "%s",
3178                                                  cur->apcupsd.items[APCUPSD_MODEL]);
3179                         }
3180                         OBJ(apcupsd_upsmode) {
3181                                 snprintf(p, p_max_size, "%s",
3182                                                  cur->apcupsd.items[APCUPSD_UPSMODE]);
3183                         }
3184                         OBJ(apcupsd_cable) {
3185                                 snprintf(p, p_max_size, "%s",
3186                                                  cur->apcupsd.items[APCUPSD_CABLE]);
3187                         }
3188                         OBJ(apcupsd_status) {
3189                                 snprintf(p, p_max_size, "%s",
3190                                                  cur->apcupsd.items[APCUPSD_STATUS]);
3191                         }
3192                         OBJ(apcupsd_linev) {
3193                                 snprintf(p, p_max_size, "%s",
3194                                                  cur->apcupsd.items[APCUPSD_LINEV]);
3195                         }
3196                         OBJ(apcupsd_load) {
3197                                 snprintf(p, p_max_size, "%s",
3198                                                  cur->apcupsd.items[APCUPSD_LOAD]);
3199                         }
3200                         OBJ(apcupsd_loadbar) {
3201                                 double progress;
3202 #ifdef X11
3203                                 if(output_methods & TO_X) {
3204                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
3205                                         new_bar(p, obj->a, obj->b, (int) progress);
3206                                 } else {
3207 #endif /* X11 */
3208                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
3209                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
3210                                         new_bar_in_shell(p, p_max_size, (int) progress, obj->a);
3211 #ifdef X11
3212                                 }
3213 #endif /* X11 */
3214                         }
3215 #ifdef X11
3216                         OBJ(apcupsd_loadgraph) {
3217                                 double progress;
3218                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]);
3219                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
3220                                                   (int)progress, 100, 1, obj->char_a, obj->char_b);
3221                         }
3222                         OBJ(apcupsd_loadgauge) {
3223                                 double progress;
3224                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
3225                                 new_gauge(p, obj->a, obj->b,
3226                                                   (int)progress);
3227                         }
3228 #endif /* X11 */
3229                         OBJ(apcupsd_charge) {
3230                                 snprintf(p, p_max_size, "%s",
3231                                                  cur->apcupsd.items[APCUPSD_CHARGE]);
3232                         }
3233                         OBJ(apcupsd_timeleft) {
3234                                 snprintf(p, p_max_size, "%s",
3235                                                  cur->apcupsd.items[APCUPSD_TIMELEFT]);
3236                         }
3237                         OBJ(apcupsd_temp) {
3238                                 snprintf(p, p_max_size, "%s",
3239                                                  cur->apcupsd.items[APCUPSD_TEMP]);
3240                         }
3241                         OBJ(apcupsd_lastxfer) {
3242                                 snprintf(p, p_max_size, "%s",
3243                                                  cur->apcupsd.items[APCUPSD_LASTXFER]);
3244                         }
3245 #endif /* APCUPSD */
3246                         break;
3247                 }
3248 #undef DO_JUMP
3249
3250
3251                 {
3252                         size_t a = strlen(p);
3253
3254 #ifdef HAVE_ICONV
3255                         iconv_convert(a, buff_in, p, p_max_size);
3256 #endif /* HAVE_ICONV */
3257                         if (obj->type != OBJ_text && obj->type != OBJ_execp && obj->type != OBJ_execpi) {
3258                                 substitute_newlines(p, a - 2);
3259                         }
3260                         p += a;
3261                         p_max_size -= a;
3262                 }
3263                 obj = obj->next;
3264         }
3265 #ifdef X11
3266         /* load any new fonts we may have had */
3267         if (need_to_load_fonts) {
3268                 load_fonts();
3269         }
3270 #endif /* X11 */
3271 }
3272
3273 void evaluate(const char *text, char *buffer)
3274 {
3275         struct information *tmp_info;
3276         struct text_object subroot;
3277
3278         tmp_info = malloc(sizeof(struct information));
3279         memcpy(tmp_info, &info, sizeof(struct information));
3280         parse_conky_vars(&subroot, text, buffer, tmp_info);
3281         DBGP("evaluated '%s' to '%s'", text, buffer);
3282
3283         free_text_objects(&subroot, 1);
3284         free(tmp_info);
3285 }
3286
3287 double current_update_time, next_update_time, last_update_time;
3288
3289 static void generate_text(void)
3290 {
3291         struct information *cur = &info;
3292         char *p;
3293
3294         special_count = 0;
3295
3296         /* update info */
3297
3298         current_update_time = get_time();
3299
3300         update_stuff();
3301
3302         /* add things to the buffer */
3303
3304         /* generate text */
3305
3306         p = text_buffer;
3307
3308         generate_text_internal(p, max_user_text, global_root_object, cur);
3309
3310         if (stuff_in_uppercase) {
3311                 char *tmp_p;
3312
3313                 tmp_p = text_buffer;
3314                 while (*tmp_p) {
3315                         *tmp_p = toupper(*tmp_p);
3316                         tmp_p++;
3317                 }
3318         }
3319
3320         next_update_time += update_interval;
3321         if (next_update_time < get_time()) {
3322                 next_update_time = get_time() + update_interval;
3323         } else if (next_update_time > get_time() + update_interval) {
3324                 next_update_time = get_time() + update_interval;
3325         }
3326         last_update_time = current_update_time;
3327         total_updates++;
3328 }
3329
3330 void set_update_interval(double interval)
3331 {
3332         update_interval = interval;
3333         update_interval_old = interval;
3334 }
3335
3336 static inline int get_string_width(const char *s)
3337 {
3338 #ifdef X11
3339         if (output_methods & TO_X) {
3340                 return *s ? calc_text_width(s, strlen(s)) : 0;
3341         }
3342 #endif /* X11 */
3343         return strlen(s);
3344 }
3345
3346 #ifdef X11
3347 static int get_string_width_special(char *s, int special_index)
3348 {
3349         char *p, *final;
3350         int idx = 1;
3351         int width = 0;
3352         long i;
3353
3354         if ((output_methods & TO_X) == 0) {
3355                 return (s) ? strlen(s) : 0;
3356         }
3357
3358         if (!s) {
3359                 return 0;
3360         }
3361
3362         p = strndup(s, text_buffer_size);
3363         final = p;
3364
3365         while (*p) {
3366                 if (*p == SPECIAL_CHAR) {
3367                         /* shift everything over by 1 so that the special char
3368                          * doesn't mess up the size calculation */
3369                         for (i = 0; i < (long)strlen(p); i++) {
3370                                 *(p + i) = *(p + i + 1);
3371                         }
3372                         if (specials[special_index + idx].type == GRAPH
3373                                         || specials[special_index + idx].type == GAUGE
3374                                         || specials[special_index + idx].type == BAR) {
3375                                 width += specials[special_index + idx].width;
3376                         }
3377                         idx++;
3378                 } else if (*p == SECRIT_MULTILINE_CHAR) {
3379                         *p = 0;
3380                         break;
3381                 } else {
3382                         p++;
3383                 }
3384         }
3385         if (strlen(final) > 1) {
3386                 width += calc_text_width(final, strlen(final));
3387         }
3388         free(final);
3389         return width;
3390 }
3391
3392 static int text_size_updater(char *s, int special_index);
3393
3394 int last_font_height;
3395 static void update_text_area(void)
3396 {
3397         int x = 0, y = 0;
3398
3399         if ((output_methods & TO_X) == 0)
3400                 return;
3401         /* update text size if it isn't fixed */
3402 #ifdef OWN_WINDOW
3403         if (!fixed_size)
3404 #endif
3405         {
3406                 text_width = minimum_width;
3407                 text_height = 0;
3408                 last_font_height = font_height();
3409                 for_each_line(text_buffer, text_size_updater);
3410                 text_width += 1;
3411                 if (text_height < minimum_height) {
3412                         text_height = minimum_height;
3413                 }
3414                 if (text_width > maximum_width && maximum_width > 0) {
3415                         text_width = maximum_width;
3416                 }
3417         }
3418
3419         /* get text position on workarea */
3420         switch (text_alignment) {
3421                 case TOP_LEFT:
3422                         x = gap_x;
3423                         y = gap_y;
3424                         break;
3425
3426                 case TOP_RIGHT:
3427                         x = workarea[2] - text_width - gap_x;
3428                         y = gap_y;
3429                         break;
3430
3431                 case TOP_MIDDLE:
3432                         x = workarea[2] / 2 - text_width / 2 - gap_x;
3433                         y = gap_y;
3434                         break;
3435
3436                 default:
3437                 case BOTTOM_LEFT:
3438                         x = gap_x;
3439                         y = workarea[3] - text_height - gap_y;
3440                         break;
3441
3442                 case BOTTOM_RIGHT:
3443                         x = workarea[2] - text_width - gap_x;
3444                         y = workarea[3] - text_height - gap_y;
3445                         break;
3446
3447                 case BOTTOM_MIDDLE:
3448                         x = workarea[2] / 2 - text_width / 2 - gap_x;
3449                         y = workarea[3] - text_height - gap_y;
3450                         break;
3451
3452                 case MIDDLE_LEFT:
3453                         x = gap_x;
3454                         y = workarea[3] / 2 - text_height / 2 - gap_y;
3455                         break;
3456
3457                 case MIDDLE_RIGHT:
3458                         x = workarea[2] - text_width - gap_x;
3459                         y = workarea[3] / 2 - text_height / 2 - gap_y;
3460                         break;
3461
3462 #ifdef OWN_WINDOW
3463                 case NONE:      // Let the WM manage the window
3464                         x = window.x;
3465                         y = window.y;
3466
3467                         fixed_pos = 1;
3468                         fixed_size = 1;
3469                         break;
3470 #endif
3471         }
3472 #ifdef OWN_WINDOW
3473
3474         if (own_window && !fixed_pos) {
3475                 x += workarea[0];
3476                 y += workarea[1];
3477                 text_start_x = window.border_inner_margin + window.border_outer_margin + window.border_width;
3478                 text_start_y = window.border_inner_margin + window.border_outer_margin + window.border_width;
3479                 window.x = x - window.border_inner_margin - window.border_outer_margin - window.border_width;
3480                 window.y = y - window.border_inner_margin - window.border_outer_margin - window.border_width;
3481         } else
3482 #endif
3483         {
3484                 /* If window size doesn't match to workarea's size,
3485                  * then window probably includes panels (gnome).
3486                  * Blah, doesn't work on KDE. */
3487                 if (workarea[2] != window.width || workarea[3] != window.height) {
3488                         y += workarea[1];
3489                         x += workarea[0];
3490                 }
3491
3492                 text_start_x = x;
3493                 text_start_y = y;
3494         }
3495 #ifdef HAVE_LUA
3496         /* update lua window globals */
3497         llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
3498 #endif /* HAVE_LUA */
3499 }
3500
3501 /* drawing stuff */
3502
3503 static int cur_x, cur_y;        /* current x and y for drawing */
3504 #endif
3505 //draw_mode also without X11 because we only need to print to stdout with FG
3506 static int draw_mode;           /* FG, BG or OUTLINE */
3507 #ifdef X11
3508 static long current_color;
3509
3510 static int text_size_updater(char *s, int special_index)
3511 {
3512         int w = 0;
3513         char *p;
3514
3515         if ((output_methods & TO_X) == 0)
3516                 return 0;
3517         /* get string widths and skip specials */
3518         p = s;
3519         while (*p) {
3520                 if (*p == SPECIAL_CHAR) {
3521                         *p = '\0';
3522                         w += get_string_width(s);
3523                         *p = SPECIAL_CHAR;
3524
3525                         if (specials[special_index].type == BAR
3526                                         || specials[special_index].type == GAUGE
3527                                         || specials[special_index].type == GRAPH) {
3528                                 w += specials[special_index].width;
3529                                 if (specials[special_index].height > last_font_height) {
3530                                         last_font_height = specials[special_index].height;
3531                                         last_font_height += font_height();
3532                                 }
3533                         } else if (specials[special_index].type == OFFSET) {
3534                                 if (specials[special_index].arg > 0) {
3535                                         w += specials[special_index].arg;
3536                                 }
3537                         } else if (specials[special_index].type == VOFFSET) {
3538                                 last_font_height += specials[special_index].arg;
3539                         } else if (specials[special_index].type == GOTO) {
3540                                 if (specials[special_index].arg > cur_x) {
3541                                         w = (int) specials[special_index].arg;
3542                                 }
3543                         } else if (specials[special_index].type == TAB) {
3544                                 int start = specials[special_index].arg;
3545                                 int step = specials[special_index].width;
3546
3547                                 if (!step || step < 0) {
3548                                         step = 10;
3549                                 }
3550                                 w += step - (cur_x - text_start_x - start) % step;
3551                         } else if (specials[special_index].type == FONT) {
3552                                 selected_font = specials[special_index].font_added;
3553                                 if (font_height() > last_font_height) {
3554                                         last_font_height = font_height();
3555                                 }
3556                         }
3557
3558                         special_index++;
3559                         s = p + 1;
3560                 } else if (*p == SECRIT_MULTILINE_CHAR) {
3561                         int lw;
3562                         *p = '\0';
3563                         lw = get_string_width(s);
3564                         *p = SECRIT_MULTILINE_CHAR;
3565                         s = p + 1;
3566                         w = lw > w ? lw : w;
3567                         text_height += last_font_height;
3568                 }
3569                 p++;
3570         }
3571         w += get_string_width(s);
3572         if (w > text_width) {
3573                 text_width = w;
3574         }
3575         if (text_width > maximum_width && maximum_width) {
3576                 text_width = maximum_width;
3577         }
3578
3579         text_height += last_font_height;
3580         last_font_height = font_height();
3581         return special_index;
3582 }
3583 #endif /* X11 */
3584
3585 static inline void set_foreground_color(long c)
3586 {
3587 #ifdef X11
3588         if (output_methods & TO_X) {
3589                 current_color = c;
3590                 XSetForeground(display, window.gc, c);
3591         }
3592 #endif /* X11 */
3593 #ifdef NCURSES
3594         if (output_methods & TO_NCURSES) {
3595                 attron(COLOR_PAIR(c));
3596         }
3597 #endif /* NCURSES */
3598         UNUSED(c);
3599         return;
3600 }
3601
3602 static void draw_string(const char *s)
3603 {
3604         int i, i2, pos, width_of_s;
3605         int max = 0;
3606         int added;
3607         char *s_with_newlines;
3608
3609         if (s[0] == '\0') {
3610                 return;
3611         }
3612
3613         width_of_s = get_string_width(s);
3614         s_with_newlines = strdup(s);
3615         for(i = 0; i < (int) strlen(s_with_newlines); i++) {
3616                 if(s_with_newlines[i] == SECRIT_MULTILINE_CHAR) {
3617                         s_with_newlines[i] = '\n';
3618                 }
3619         }
3620         if ((output_methods & TO_STDOUT) && draw_mode == FG) {
3621                 printf("%s\n", s_with_newlines);
3622                 if (extra_newline) fputc('\n', stdout);
3623                 fflush(stdout); /* output immediately, don't buffer */
3624         }
3625         if ((output_methods & TO_STDERR) && draw_mode == FG) {
3626                 fprintf(stderr, "%s\n", s_with_newlines);
3627                 fflush(stderr); /* output immediately, don't buffer */
3628         }
3629         if ((output_methods & OVERWRITE_FILE) && draw_mode == FG && overwrite_fpointer) {
3630                 fprintf(overwrite_fpointer, "%s\n", s_with_newlines);
3631         }
3632         if ((output_methods & APPEND_FILE) && draw_mode == FG && append_fpointer) {
3633                 fprintf(append_fpointer, "%s\n", s_with_newlines);
3634         }
3635 #ifdef NCURSES
3636         if ((output_methods & TO_NCURSES) && draw_mode == FG) {
3637                 printw("%s", s_with_newlines);
3638         }
3639 #endif
3640         free(s_with_newlines);
3641         memset(tmpstring1, 0, text_buffer_size);
3642         memset(tmpstring2, 0, text_buffer_size);
3643         strncpy(tmpstring1, s, text_buffer_size - 1);
3644         pos = 0;
3645         added = 0;
3646
3647 #ifdef X11
3648         if (output_methods & TO_X) {
3649                 max = ((text_width - width_of_s) / get_string_width(" "));
3650         }
3651 #endif /* X11 */
3652         /* This code looks for tabs in the text and coverts them to spaces.
3653          * The trick is getting the correct number of spaces, and not going
3654          * over the window's size without forcing the window larger. */
3655         for (i = 0; i < (int) text_buffer_size; i++) {
3656                 if (tmpstring1[i] == '\t') {
3657                         i2 = 0;
3658                         for (i2 = 0; i2 < (8 - (1 + pos) % 8) && added <= max; i2++) {
3659                                 /* guard against overrun */
3660                                 tmpstring2[MIN(pos + i2, (int)text_buffer_size - 1)] = ' ';
3661                                 added++;
3662                         }
3663                         pos += i2;
3664                 } else {
3665                         /* guard against overrun */
3666                         tmpstring2[MIN(pos, (int) text_buffer_size - 1)] = tmpstring1[i];
3667                         pos++;
3668                 }
3669         }
3670 #ifdef X11
3671         if (output_methods & TO_X) {
3672                 if (text_width == maximum_width) {
3673                         /* this means the text is probably pushing the limit,
3674                          * so we'll chop it */
3675                         while (cur_x + get_string_width(tmpstring2) - text_start_x
3676                                         > maximum_width && strlen(tmpstring2) > 0) {
3677                                 tmpstring2[strlen(tmpstring2) - 1] = '\0';
3678                         }
3679                 }
3680         }
3681 #endif /* X11 */
3682         s = tmpstring2;
3683 #ifdef X11
3684         if (output_methods & TO_X) {
3685 #ifdef XFT
3686                 if (use_xft) {
3687                         XColor c;
3688                         XftColor c2;
3689
3690                         c.pixel = current_color;
3691                         XQueryColor(display, DefaultColormap(display, screen), &c);
3692
3693                         c2.pixel = c.pixel;
3694                         c2.color.red = c.red;
3695                         c2.color.green = c.green;
3696                         c2.color.blue = c.blue;
3697                         c2.color.alpha = fonts[selected_font].font_alpha;
3698                         if (utf8_mode) {
3699                                 XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3700                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
3701                         } else {
3702                                 XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
3703                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
3704                         }
3705                 } else
3706 #endif
3707                 {
3708                         XDrawString(display, window.drawable, window.gc, cur_x, cur_y, s,
3709                                 strlen(s));
3710                 }
3711                 cur_x += width_of_s;
3712         }
3713 #endif /* X11 */
3714         memcpy(tmpstring1, s, text_buffer_size);
3715 }
3716
3717 int draw_each_line_inner(char *s, int special_index, int last_special_applied)
3718 {
3719 #ifdef X11
3720         int font_h = font_height();
3721         int cur_y_add = 0;
3722 #endif /* X11 */
3723         char *recurse = 0;
3724         char *p = s;
3725         int last_special_needed = -1;
3726         int orig_special_index = special_index;
3727
3728 #ifdef X11
3729         cur_x = text_start_x;
3730         cur_y += font_ascent();
3731 #endif /* X11 */
3732
3733         while (*p) {
3734                 if (*p == SECRIT_MULTILINE_CHAR) {
3735                         /* special newline marker for multiline objects */
3736                         recurse = p + 1;
3737                         *p = '\0';
3738                         break;
3739                 }
3740                 if (*p == SPECIAL_CHAR || last_special_applied > -1) {
3741 #ifdef X11
3742                         int w = 0;
3743 #endif /* X11 */
3744
3745                         /* draw string before special, unless we're dealing multiline
3746                          * specials */
3747                         if (last_special_applied > -1) {
3748                                 special_index = last_special_applied;
3749                         } else {
3750                                 *p = '\0';
3751                                 draw_string(s);
3752                                 *p = SPECIAL_CHAR;
3753                                 s = p + 1;
3754                         }
3755                         /* draw special */
3756                         switch (specials[special_index].type) {
3757 #ifdef X11
3758                                 case HORIZONTAL_LINE:
3759                                 {
3760                                         int h = specials[special_index].height;
3761                                         int mid = font_ascent() / 2;
3762
3763                                         w = text_start_x + text_width - cur_x;
3764
3765                                         XSetLineAttributes(display, window.gc, h, LineSolid,
3766                                                 CapButt, JoinMiter);
3767                                         XDrawLine(display, window.drawable, window.gc, cur_x,
3768                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
3769                                         break;
3770                                 }
3771
3772                                 case STIPPLED_HR:
3773                                 {
3774                                         int h = specials[special_index].height;
3775                                         int tmp_s = specials[special_index].arg;
3776                                         int mid = font_ascent() / 2;
3777                                         char ss[2] = { tmp_s, tmp_s };
3778
3779                                         w = text_start_x + text_width - cur_x - 1;
3780                                         XSetLineAttributes(display, window.gc, h, LineOnOffDash,
3781                                                 CapButt, JoinMiter);
3782                                         XSetDashes(display, window.gc, 0, ss, 2);
3783                                         XDrawLine(display, window.drawable, window.gc, cur_x,
3784                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
3785                                         break;
3786                                 }
3787
3788                                 case BAR:
3789                                 {
3790                                         int h, bar_usage, by;
3791                                         if (cur_x - text_start_x > maximum_width
3792                                                         && maximum_width > 0) {
3793                                                 break;
3794                                         }
3795                                         h = specials[special_index].height;
3796                                         bar_usage = specials[special_index].arg;
3797                                         by = cur_y - (font_ascent() / 2) - 1;
3798
3799                                         if (h < font_h) {
3800                                                 by -= h / 2 - 1;
3801                                         }
3802                                         w = specials[special_index].width;
3803                                         if (w == 0) {
3804                                                 w = text_start_x + text_width - cur_x - 1;
3805                                         }
3806                                         if (w < 0) {
3807                                                 w = 0;
3808                                         }
3809
3810                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
3811                                                 CapButt, JoinMiter);
3812
3813                                         XDrawRectangle(display, window.drawable, window.gc, cur_x,
3814                                                 by, w, h);
3815                                         XFillRectangle(display, window.drawable, window.gc, cur_x,
3816                                                 by, w * bar_usage / 255, h);
3817                                         if (h > cur_y_add
3818                                                         && h > font_h) {
3819                                                 cur_y_add = h;
3820                                         }
3821                                         break;
3822                                 }
3823
3824                                 case GAUGE: /* new GAUGE  */
3825                                 {
3826                                         int h, by = 0;
3827                                         unsigned long last_colour = current_color;
3828 #ifdef MATH
3829                                         float angle, px, py;
3830                                         int usage;
3831 #endif /* MATH */
3832
3833                                         if (cur_x - text_start_x > maximum_width
3834                                                         && maximum_width > 0) {
3835                                                 break;
3836                                         }
3837
3838                                         h = specials[special_index].height;
3839                                         by = cur_y - (font_ascent() / 2) - 1;
3840
3841                                         if (h < font_h) {
3842                                                 by -= h / 2 - 1;
3843                                         }
3844                                         w = specials[special_index].width;
3845                                         if (w == 0) {
3846                                                 w = text_start_x + text_width - cur_x - 1;
3847                                         }
3848                                         if (w < 0) {
3849                                                 w = 0;
3850                                         }
3851
3852                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
3853                                                         CapButt, JoinMiter);
3854
3855                                         XDrawArc(display, window.drawable, window.gc,
3856                                                         cur_x, by, w, h * 2, 0, 180*64);
3857
3858 #ifdef MATH
3859                                         usage = specials[special_index].arg;
3860                                         angle = (M_PI)*(float)(usage)/255.;
3861                                         px = (float)(cur_x+(w/2.))-(float)(w/2.)*cos(angle);
3862                                         py = (float)(by+(h))-(float)(h)*sin(angle);
3863
3864                                         XDrawLine(display, window.drawable, window.gc,
3865                                                         cur_x + (w/2.), by+(h), (int)(px), (int)(py));
3866 #endif /* MATH */
3867
3868                                         if (h > cur_y_add
3869                                                         && h > font_h) {
3870                                                 cur_y_add = h;
3871                                         }
3872
3873                                         set_foreground_color(last_colour);
3874
3875                                         break;
3876
3877                                 }
3878
3879                                 case GRAPH:
3880                                 {
3881                                         int h, by, i = 0, j = 0;
3882                                         int colour_idx = 0;
3883                                         unsigned long last_colour = current_color;
3884                                         unsigned long *tmpcolour = 0;
3885                                         if (cur_x - text_start_x > maximum_width
3886                                                         && maximum_width > 0) {
3887                                                 break;
3888                                         }
3889                                         h = specials[special_index].height;
3890                                         by = cur_y - (font_ascent() / 2) - 1;
3891
3892                                         if (h < font_h) {
3893                                                 by -= h / 2 - 1;
3894                                         }
3895                                         w = specials[special_index].width;
3896                                         if (w == 0) {
3897                                                 w = text_start_x + text_width - cur_x - 1;
3898                                         }
3899                                         if (w < 0) {
3900                                                 w = 0;
3901                                         }
3902                                         if (draw_graph_borders) {
3903                                                 XSetLineAttributes(display, window.gc, 1, LineSolid,
3904                                                         CapButt, JoinMiter);
3905                                                 XDrawRectangle(display, window.drawable, window.gc,
3906                                                         cur_x, by, w, h);
3907                                         }
3908                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
3909                                                 CapButt, JoinMiter);
3910
3911                                         if (specials[special_index].last_colour != 0
3912                                                         || specials[special_index].first_colour != 0) {
3913                                                 tmpcolour = do_gradient(w - 1, specials[special_index].last_colour, specials[special_index].first_colour);
3914                                         }
3915                                         colour_idx = 0;
3916                                         for (i = w - 2; i > -1; i--) {
3917                                                 if (specials[special_index].last_colour != 0
3918                                                                 || specials[special_index].first_colour != 0) {
3919                                                         if (specials[special_index].tempgrad) {
3920 #ifdef DEBUG_lol
3921                                                                 assert(
3922                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
3923                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
3924                                                                                 < w - 1
3925                                                                           );
3926                                                                 assert(
3927                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
3928                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
3929                                                                                 > -1
3930                                                                           );
3931                                                                 if (specials[special_index].graph[j] == specials[special_index].graph_scale) {
3932                                                                         assert(
3933                                                                                         (int)((float)(w - 2) - specials[special_index].graph[j] *
3934                                                                                                 (w - 2) / (float)specials[special_index].graph_scale)
3935                                                                                         == 0
3936                                                                                   );
3937                                                                 }
3938 #endif /* DEBUG_lol */
3939                                                                 XSetForeground(display, window.gc, tmpcolour[
3940                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
3941                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
3942                                                                                 ]);
3943                                                         } else {
3944                                                                 XSetForeground(display, window.gc, tmpcolour[colour_idx++]);
3945                                                         }
3946                                                 }
3947                                                 /* this is mugfugly, but it works */
3948                                                 XDrawLine(display, window.drawable, window.gc,
3949                                                                 cur_x + i + 1, by + h, cur_x + i + 1,
3950                                                                 round_to_int((double)by + h - specials[special_index].graph[j] *
3951                                                                         (h - 1) / specials[special_index].graph_scale));
3952                                                 if ((w - i) / ((float) (w - 2) /
3953                                                                         (specials[special_index].graph_width)) > j
3954                                                                 && j < MAX_GRAPH_DEPTH - 3) {
3955                                                         j++;
3956                                                 }
3957                                         }
3958                                         if (tmpcolour) free(tmpcolour);
3959                                         if (h > cur_y_add
3960                                                         && h > font_h) {
3961                                                 cur_y_add = h;
3962                                         }
3963                                         /* if (draw_mode == BG) {
3964                                                 set_foreground_color(default_bg_color);
3965                                         } else if (draw_mode == OUTLINE) {
3966                                                 set_foreground_color(default_out_color);
3967                                         } else {
3968                                                 set_foreground_color(default_fg_color);
3969                                         } */
3970                                         if (show_graph_range) {
3971                                                 int tmp_x = cur_x;
3972                                                 int tmp_y = cur_y;
3973                                                 unsigned short int seconds = update_interval * w;
3974                                                 char *tmp_day_str;
3975                                                 char *tmp_hour_str;
3976                                                 char *tmp_min_str;
3977                                                 char *tmp_sec_str;
3978                                                 char *tmp_str;
3979                                                 unsigned short int timeunits;
3980                                                 if (seconds != 0) {
3981                                                         timeunits = seconds / 86400; seconds %= 86400;
3982                                                         if (timeunits > 0) {
3983                                                                 asprintf(&tmp_day_str, "%dd", timeunits);
3984                                                         } else {
3985                                                                 tmp_day_str = strdup("");
3986                                                         }
3987                                                         timeunits = seconds / 3600; seconds %= 3600;
3988                                                         if (timeunits > 0) {
3989                                                                 asprintf(&tmp_hour_str, "%dh", timeunits);
3990                                                         } else {
3991                                                                 tmp_hour_str = strdup("");
3992                                                         }
3993                                                         timeunits = seconds / 60; seconds %= 60;
3994                                                         if (timeunits > 0) {
3995                                                                 asprintf(&tmp_min_str, "%dm", timeunits);
3996                                                         } else {
3997                                                                 tmp_min_str = strdup("");
3998                                                         }
3999                                                         if (seconds > 0) {
4000                                                                 asprintf(&tmp_sec_str, "%ds", seconds);
4001                                                         } else {
4002                                                                 tmp_sec_str = strdup("");
4003                                                         }
4004                                                         asprintf(&tmp_str, "%s%s%s%s", tmp_day_str, tmp_hour_str, tmp_min_str, tmp_sec_str);
4005                                                         free(tmp_day_str); free(tmp_hour_str); free(tmp_min_str); free(tmp_sec_str);
4006                                                 } else {
4007                                                         asprintf(&tmp_str, "Range not possible"); // should never happen, but better safe then sorry
4008                                                 }
4009                                                 cur_x += (w / 2) - (font_ascent() * (strlen(tmp_str) / 2));
4010                                                 cur_y += font_h / 2;
4011                                                 draw_string(tmp_str);
4012                                                 free(tmp_str);
4013                                                 cur_x = tmp_x;
4014                                                 cur_y = tmp_y;
4015                                         }
4016 #ifdef MATH
4017                                         if (show_graph_scale && (specials[special_index].show_scale == 1)) {
4018                                                 int tmp_x = cur_x;
4019                                                 int tmp_y = cur_y;
4020                                                 char *tmp_str;
4021                                                 cur_x += font_ascent() / 2;
4022                                                 cur_y += font_h / 2;
4023                                                 tmp_str = (char *)
4024                                                         calloc(log10(floor(specials[special_index].graph_scale)) + 4,
4025                                                                         sizeof(char));
4026                                                 sprintf(tmp_str, "%.1f", specials[special_index].graph_scale);
4027                                                 draw_string(tmp_str);
4028                                                 free(tmp_str);
4029                                                 cur_x = tmp_x;
4030                                                 cur_y = tmp_y;
4031                                         }
4032 #endif
4033                                         set_foreground_color(last_colour);
4034                                         break;
4035                                 }
4036
4037                                 case FONT:
4038                                 {
4039                                         int old = font_ascent();
4040
4041                                         cur_y -= font_ascent();
4042                                         selected_font = specials[special_index].font_added;
4043                                         set_font();
4044                                         if (cur_y + font_ascent() < cur_y + old) {
4045                                                 cur_y += old;
4046                                         } else {
4047                                                 cur_y += font_ascent();
4048                                         }
4049                                         font_h = font_height();
4050                                         break;
4051                                 }
4052 #endif /* X11 */
4053                                 case FG:
4054                                         if (draw_mode == FG) {
4055                                                 set_foreground_color(specials[special_index].arg);
4056                                         }
4057                                         break;
4058
4059 #ifdef X11
4060                                 case BG:
4061                                         if (draw_mode == BG) {
4062                                                 set_foreground_color(specials[special_index].arg);
4063                                         }
4064                                         break;
4065
4066                                 case OUTLINE:
4067                                         if (draw_mode == OUTLINE) {
4068                                                 set_foreground_color(specials[special_index].arg);
4069                                         }
4070                                         break;
4071
4072                                 case OFFSET:
4073                                         w += specials[special_index].arg;
4074                                         last_special_needed = special_index;
4075                                         break;
4076
4077                                 case VOFFSET:
4078                                         cur_y += specials[special_index].arg;
4079                                         break;
4080
4081                                 case GOTO:
4082                                         if (specials[special_index].arg >= 0) {
4083                                                 cur_x = (int) specials[special_index].arg;
4084                                         }
4085                                         last_special_needed = special_index;
4086                                         break;
4087
4088                                 case TAB:
4089                                 {
4090                                         int start = specials[special_index].arg;
4091                                         int step = specials[special_index].width;
4092
4093                                         if (!step || step < 0) {
4094                                                 step = 10;
4095                                         }
4096                                         w = step - (cur_x - text_start_x - start) % step;
4097                                         last_special_needed = special_index;
4098                                         break;
4099                                 }
4100
4101                                 case ALIGNR:
4102                                 {
4103                                         /* TODO: add back in "+ window.border_inner_margin" to the end of
4104                                          * this line? */
4105                                         int pos_x = text_start_x + text_width -
4106                                                 get_string_width_special(s, special_index);
4107
4108                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
4109                                                 "get_string_width(p) %i gap_x %i "
4110                                                 "specials[special_index].arg %i window.border_inner_margin %i "
4111                                                 "window.border_width %i\n", pos_x, text_start_x, text_width,
4112                                                 cur_x, get_string_width_special(s), gap_x,
4113                                                 specials[special_index].arg, window.border_inner_margin,
4114                                                 window.border_width); */
4115                                         if (pos_x > specials[special_index].arg && pos_x > cur_x) {
4116                                                 cur_x = pos_x - specials[special_index].arg;
4117                                         }
4118                                         last_special_needed = special_index;
4119                                         break;
4120                                 }
4121
4122                                 case ALIGNC:
4123                                 {
4124                                         int pos_x = (text_width) / 2 - get_string_width_special(s,
4125                                                         special_index) / 2 - (cur_x -
4126                                                                 text_start_x);
4127                                         /* int pos_x = text_start_x + text_width / 2 -
4128                                                 get_string_width_special(s) / 2; */
4129
4130                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
4131                                                 "get_string_width(p) %i gap_x %i "
4132                                                 "specials[special_index].arg %i\n", pos_x, text_start_x,
4133                                                 text_width, cur_x, get_string_width(s), gap_x,
4134                                                 specials[special_index].arg); */
4135                                         if (pos_x > specials[special_index].arg) {
4136                                                 w = pos_x - specials[special_index].arg;
4137                                         }
4138                                         last_special_needed = special_index;
4139                                         break;
4140                                 }
4141 #endif /* X11 */
4142                         }
4143
4144 #ifdef X11
4145                         cur_x += w;
4146 #endif /* X11 */
4147
4148                         if (special_index != last_special_applied) {
4149                                 special_index++;
4150                         } else {
4151                                 special_index = orig_special_index;
4152                                 last_special_applied = -1;
4153                         }
4154                 }
4155                 p++;
4156         }
4157
4158 #ifdef X11
4159         cur_y += cur_y_add;
4160 #endif /* X11 */
4161         draw_string(s);
4162 #ifdef NCURSES
4163         if (output_methods & TO_NCURSES) {
4164                 printw("\n");
4165         }
4166 #endif /* NCURSES */
4167 #ifdef X11
4168         cur_y += font_descent();
4169 #endif /* X11 */
4170         if (recurse && *recurse) {
4171                 special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
4172                 *(recurse - 1) = SECRIT_MULTILINE_CHAR;
4173         }
4174         return special_index;
4175 }
4176
4177 static int draw_line(char *s, int special_index)
4178 {
4179 #ifdef X11
4180         if (output_methods & TO_X) {
4181                 return draw_each_line_inner(s, special_index, -1);
4182         }
4183 #endif /* X11 */
4184 #ifdef NCURSES
4185         if (output_methods & TO_NCURSES) {
4186                 return draw_each_line_inner(s, special_index, -1);
4187         }
4188 #endif /* NCURSES */
4189         draw_string(s);
4190         UNUSED(special_index);
4191         return 0;
4192 }
4193
4194 static void draw_text(void)
4195 {
4196 #ifdef X11
4197 #ifdef HAVE_LUA
4198         llua_draw_pre_hook();
4199 #endif /* HAVE_LUA */
4200         if (output_methods & TO_X) {
4201                 cur_y = text_start_y;
4202
4203                 /* draw borders */
4204                 if (draw_borders && window.border_width > 0) {
4205                         if (stippled_borders) {
4206                                 char ss[2] = { stippled_borders, stippled_borders };
4207                                 XSetLineAttributes(display, window.gc, window.border_width, LineOnOffDash,
4208                                         CapButt, JoinMiter);
4209                                 XSetDashes(display, window.gc, 0, ss, 2);
4210                         } else {
4211                                 XSetLineAttributes(display, window.gc, window.border_width, LineSolid,
4212                                         CapButt, JoinMiter);
4213                         }
4214
4215                         XDrawRectangle(display, window.drawable, window.gc,
4216                                 text_start_x - window.border_inner_margin - window.border_width,
4217                                 text_start_y - window.border_inner_margin - window.border_width,
4218                                 text_width + window.border_inner_margin * 2 + window.border_width * 2,
4219                                 text_height + window.border_inner_margin * 2 + window.border_width * 2);
4220                 }
4221
4222                 /* draw text */
4223         }
4224         setup_fonts();
4225 #endif /* X11 */
4226 #ifdef NCURSES
4227         init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
4228         attron(COLOR_PAIR(COLOR_WHITE));
4229 #endif /* NCURSES */
4230         for_each_line(text_buffer, draw_line);
4231 #if defined(HAVE_LUA) && defined(X11)
4232         llua_draw_post_hook();
4233 #endif /* HAVE_LUA */
4234 }
4235
4236 static void draw_stuff(void)
4237 {
4238 #ifdef IMLIB2
4239         cimlib_render(text_start_x, text_start_y, window.width, window.height);
4240 #endif /* IMLIB2 */
4241         if (overwrite_file) {
4242                 overwrite_fpointer = fopen(overwrite_file, "w");
4243                 if(!overwrite_fpointer)
4244                         NORM_ERR("Can't overwrite '%s' anymore", overwrite_file);
4245         }
4246         if (append_file) {
4247                 append_fpointer = fopen(append_file, "a");
4248                 if(!append_fpointer)
4249                         NORM_ERR("Can't append '%s' anymore", append_file);
4250         }
4251 #ifdef X11
4252         if (output_methods & TO_X) {
4253                 selected_font = 0;
4254                 if (draw_shades && !draw_outline) {
4255                         text_start_x++;
4256                         text_start_y++;
4257                         set_foreground_color(default_bg_color);
4258                         draw_mode = BG;
4259                         draw_text();
4260                         text_start_x--;
4261                         text_start_y--;
4262                 }
4263
4264                 if (draw_outline) {
4265                         int i, j;
4266                         selected_font = 0;
4267
4268                         for (i = -1; i < 2; i++) {
4269                                 for (j = -1; j < 2; j++) {
4270                                         if (i == 0 && j == 0) {
4271                                                 continue;
4272                                         }
4273                                         text_start_x += i;
4274                                         text_start_y += j;
4275                                         set_foreground_color(default_out_color);
4276                                         draw_mode = OUTLINE;
4277                                         draw_text();
4278                                         text_start_x -= i;
4279                                         text_start_y -= j;
4280                                 }
4281                         }
4282                 }
4283
4284                 set_foreground_color(default_fg_color);
4285         }
4286 #endif /* X11 */
4287         draw_mode = FG;
4288         draw_text();
4289 #ifdef X11
4290         xdbe_swap_buffers();
4291         if (output_methods & TO_X) {
4292 #ifdef HAVE_XDBE
4293 #endif
4294         }
4295 #endif /* X11 */
4296         if(overwrite_fpointer) {
4297                 fclose(overwrite_fpointer);
4298                 overwrite_fpointer = 0;
4299         }
4300         if(append_fpointer) {
4301                 fclose(append_fpointer);
4302                 append_fpointer = 0;
4303         }
4304 }
4305
4306 #ifdef X11
4307 static void clear_text(int exposures)
4308 {
4309 #ifdef HAVE_XDBE
4310         if (use_xdbe) {
4311                 /* The swap action is XdbeBackground, which clears */
4312                 return;
4313         } else
4314 #endif
4315         if (display && window.window) { // make sure these are !null
4316                 /* there is some extra space for borders and outlines */
4317                 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
4318                         text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
4319                         text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
4320                         text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, exposures ? True : 0);
4321         }
4322 }
4323 #endif /* X11 */
4324
4325 static int need_to_update;
4326
4327 /* update_text() generates new text and clears old text area */
4328 static void update_text(void)
4329 {
4330 #ifdef IMLIB2
4331         cimlib_cleanup();
4332 #endif /* IMLIB2 */
4333         generate_text();
4334 #ifdef X11
4335         if (output_methods & TO_X)
4336                 clear_text(1);
4337 #endif /* X11 */
4338         need_to_update = 1;
4339 #ifdef HAVE_LUA
4340         llua_update_info(&info, update_interval);
4341 #endif /* HAVE_LUA */
4342 }
4343
4344 #ifdef HAVE_SYS_INOTIFY_H
4345 int inotify_fd;
4346 #endif
4347
4348 static void main_loop(void)
4349 {
4350         int terminate = 0;
4351 #ifdef SIGNAL_BLOCKING
4352         sigset_t newmask, oldmask;
4353 #endif
4354         double t;
4355 #ifdef HAVE_SYS_INOTIFY_H
4356         int inotify_config_wd = -1;
4357 #define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
4358 #define INOTIFY_BUF_LEN     (20 * (INOTIFY_EVENT_SIZE + 16))
4359         char inotify_buff[INOTIFY_BUF_LEN];
4360 #endif /* HAVE_SYS_INOTIFY_H */
4361
4362
4363 #ifdef SIGNAL_BLOCKING
4364         sigemptyset(&newmask);
4365         sigaddset(&newmask, SIGINT);
4366         sigaddset(&newmask, SIGTERM);
4367         sigaddset(&newmask, SIGUSR1);
4368 #endif
4369
4370         last_update_time = 0.0;
4371         next_update_time = get_time();
4372         info.looped = 0;
4373         while (terminate == 0 && (total_run_times == 0 || info.looped < total_run_times)) {
4374                 if(update_interval_bat != NOBATTERY && update_interval_bat != update_interval_old) {
4375                         char buf[max_user_text];
4376
4377                         get_battery_short_status(buf, max_user_text, "BAT0");
4378                         if(buf[0] == 'D') {
4379                                 update_interval = update_interval_bat;
4380                         } else {
4381                                 update_interval = update_interval_old;
4382                         }
4383                 }
4384                 info.looped++;
4385
4386 #ifdef SIGNAL_BLOCKING
4387                 /* block signals.  we will inspect for pending signals later */
4388                 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
4389                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
4390                 }
4391 #endif
4392
4393 #ifdef X11
4394                 if (output_methods & TO_X) {
4395                         XFlush(display);
4396
4397                         /* wait for X event or timeout */
4398
4399                         if (!XPending(display)) {
4400                                 fd_set fdsr;
4401                                 struct timeval tv;
4402                                 int s;
4403                                 t = next_update_time - get_time();
4404
4405                                 if (t < 0) {
4406                                         t = 0;
4407                                 } else if (t > update_interval) {
4408                                         t = update_interval;
4409                                 }
4410
4411                                 tv.tv_sec = (long) t;
4412                                 tv.tv_usec = (long) (t * 1000000) % 1000000;
4413                                 FD_ZERO(&fdsr);
4414                                 FD_SET(ConnectionNumber(display), &fdsr);
4415
4416                                 s = select(ConnectionNumber(display) + 1, &fdsr, 0, 0, &tv);
4417                                 if (s == -1) {
4418                                         if (errno != EINTR) {
4419                                                 NORM_ERR("can't select(): %s", strerror(errno));
4420                                         }
4421                                 } else {
4422                                         /* timeout */
4423                                         if (s == 0) {
4424                                                 update_text();
4425                                         }
4426                                 }
4427                         }
4428
4429                         if (need_to_update) {
4430 #ifdef OWN_WINDOW
4431                                 int wx = window.x, wy = window.y;
4432 #endif
4433
4434                                 need_to_update = 0;
4435                                 selected_font = 0;
4436                                 update_text_area();
4437 #ifdef OWN_WINDOW
4438                                 if (own_window) {
4439                                         int changed = 0;
4440
4441                                         /* resize window if it isn't right size */
4442                                         if (!fixed_size
4443                                                         && (text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.width
4444                                                                 || text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.height)) {
4445                                                 window.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4446                                                 window.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4447                                                 draw_stuff(); /* redraw everything in our newly sized window */
4448                                                 XResizeWindow(display, window.window, window.width,
4449                                                                 window.height); /* resize window */
4450                                                 set_transparent_background(window.window);
4451 #ifdef HAVE_XDBE
4452                                                 /* swap buffers */
4453                                                 xdbe_swap_buffers();
4454 #endif
4455
4456                                                 changed++;
4457 #ifdef HAVE_LUA
4458                                                 /* update lua window globals */
4459                                                 llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
4460 #endif /* HAVE_LUA */
4461                                         }
4462
4463                                         /* move window if it isn't in right position */
4464                                         if (!fixed_pos && (window.x != wx || window.y != wy)) {
4465                                                 XMoveWindow(display, window.window, window.x, window.y);
4466                                                 changed++;
4467                                         }
4468
4469                                         /* update struts */
4470                                         if (changed && window.type == TYPE_PANEL) {
4471                                                 int sidenum = -1;
4472
4473                                                 fprintf(stderr, PACKAGE_NAME": defining struts\n");
4474                                                 fflush(stderr);
4475
4476                                                 switch (text_alignment) {
4477                                                         case TOP_LEFT:
4478                                                         case TOP_RIGHT:
4479                                                         case TOP_MIDDLE:
4480                                                                 {
4481                                                                         sidenum = 2;
4482                                                                         break;
4483                                                                 }
4484                                                         case BOTTOM_LEFT:
4485                                                         case BOTTOM_RIGHT:
4486                                                         case BOTTOM_MIDDLE:
4487                                                                 {
4488                                                                         sidenum = 3;
4489                                                                         break;
4490                                                                 }
4491                                                         case MIDDLE_LEFT:
4492                                                                 {
4493                                                                         sidenum = 0;
4494                                                                         break;
4495                                                                 }
4496                                                         case MIDDLE_RIGHT:
4497                                                                 {
4498                                                                         sidenum = 1;
4499                                                                         break;
4500                                                                 }
4501                                                 }
4502
4503                                                 set_struts(sidenum);
4504                                         }
4505                                 }
4506 #endif
4507
4508                                 clear_text(1);
4509
4510 #ifdef HAVE_XDBE
4511                                 if (use_xdbe) {
4512                                         XRectangle r;
4513
4514                                         r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
4515                                         r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
4516                                         r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4517                                         r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4518                                         XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
4519                                 }
4520 #endif
4521                         }
4522
4523                         /* handle X events */
4524                         while (XPending(display)) {
4525                                 XEvent ev;
4526
4527                                 XNextEvent(display, &ev);
4528                                 switch (ev.type) {
4529                                         case Expose:
4530                                         {
4531                                                 XRectangle r;
4532                                                 r.x = ev.xexpose.x;
4533                                                 r.y = ev.xexpose.y;
4534                                                 r.width = ev.xexpose.width;
4535                                                 r.height = ev.xexpose.height;
4536                                                 XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
4537                                                 break;
4538                                         }
4539
4540                                         case PropertyNotify:
4541                                         {
4542                                                 if ( ev.xproperty.state == PropertyNewValue ) {
4543                                                         get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
4544                                                 }
4545                                                 break;
4546                                         }
4547
4548 #ifdef OWN_WINDOW
4549                                         case ReparentNotify:
4550                                                 /* set background to ParentRelative for all parents */
4551                                                 if (own_window) {
4552                                                         set_transparent_background(window.window);
4553                                                 }
4554                                                 break;
4555
4556                                         case ConfigureNotify:
4557                                                 if (own_window) {
4558                                                         /* if window size isn't what expected, set fixed size */
4559                                                         if (ev.xconfigure.width != window.width
4560                                                                         || ev.xconfigure.height != window.height) {
4561                                                                 if (window.width != 0 && window.height != 0) {
4562                                                                         fixed_size = 1;
4563                                                                 }
4564
4565                                                                 /* clear old stuff before screwing up
4566                                                                  * size and pos */
4567                                                                 clear_text(1);
4568
4569                                                                 {
4570                                                                         XWindowAttributes attrs;
4571                                                                         if (XGetWindowAttributes(display,
4572                                                                                         window.window, &attrs)) {
4573                                                                                 window.width = attrs.width;
4574                                                                                 window.height = attrs.height;
4575                                                                         }
4576                                                                 }
4577
4578                                                                 text_width = window.width - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
4579                                                                 text_height = window.height - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
4580                                                                 if (text_width > maximum_width
4581                                                                                 && maximum_width > 0) {
4582                                                                         text_width = maximum_width;
4583                                                                 }
4584                                                         }
4585
4586                                                         /* if position isn't what expected, set fixed pos
4587                                                          * total_updates avoids setting fixed_pos when window
4588                                                          * is set to weird locations when started */
4589                                                         /* // this is broken
4590                                                         if (total_updates >= 2 && !fixed_pos
4591                                                                         && (window.x != ev.xconfigure.x
4592                                                                         || window.y != ev.xconfigure.y)
4593                                                                         && (ev.xconfigure.x != 0
4594                                                                         || ev.xconfigure.y != 0)) {
4595                                                                 fixed_pos = 1;
4596                                                         } */
4597                                                 }
4598                                                 break;
4599
4600                                         case ButtonPress:
4601                                                 if (own_window) {
4602                                                         /* if an ordinary window with decorations */
4603                                                         if ((window.type == TYPE_NORMAL &&
4604                                                                                 (!TEST_HINT(window.hints,
4605                                                                                                         HINT_UNDECORATED))) ||
4606                                                                         window.type == TYPE_DESKTOP) {
4607                                                                 /* allow conky to hold input focus. */
4608                                                                 break;
4609                                                         } else {
4610                                                                 /* forward the click to the desktop window */
4611                                                                 XUngrabPointer(display, ev.xbutton.time);
4612                                                                 ev.xbutton.window = window.desktop;
4613                                                                 ev.xbutton.x = ev.xbutton.x_root;
4614                                                                 ev.xbutton.y = ev.xbutton.y_root;
4615                                                                 XSendEvent(display, ev.xbutton.window, False,
4616                                                                         ButtonPressMask, &ev);
4617                                                                 XSetInputFocus(display, ev.xbutton.window,
4618                                                                         RevertToParent, ev.xbutton.time);
4619                                                         }
4620                                                 }
4621                                                 break;
4622
4623                                         case ButtonRelease:
4624                                                 if (own_window) {
4625                                                         /* if an ordinary window with decorations */
4626                                                         if ((window.type == TYPE_NORMAL)
4627                                                                         && (!TEST_HINT(window.hints,
4628                                                                         HINT_UNDECORATED))) {
4629                                                                 /* allow conky to hold input focus. */
4630                                                                 break;
4631                                                         } else {
4632                                                                 /* forward the release to the desktop window */
4633                                                                 ev.xbutton.window = window.desktop;
4634                                                                 ev.xbutton.x = ev.xbutton.x_root;
4635                                                                 ev.xbutton.y = ev.xbutton.y_root;
4636                                                                 XSendEvent(display, ev.xbutton.window, False,
4637                                                                         ButtonReleaseMask, &ev);
4638                                                         }
4639                                                 }
4640                                                 break;
4641
4642 #endif
4643
4644                                         default:
4645 #ifdef HAVE_XDAMAGE
4646                                                 if (ev.type == x11_stuff.event_base + XDamageNotify) {
4647                                                         XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &ev;
4648
4649                                                         XFixesSetRegion(display, x11_stuff.part, &dev->area, 1);
4650                                                         XFixesUnionRegion(display, x11_stuff.region2, x11_stuff.region2, x11_stuff.part);
4651                                                 }
4652 #endif /* HAVE_XDAMAGE */
4653                                                 break;
4654                                 }
4655                         }
4656
4657 #ifdef HAVE_XDAMAGE
4658                         XDamageSubtract(display, x11_stuff.damage, x11_stuff.region2, None);
4659                         XFixesSetRegion(display, x11_stuff.region2, 0, 0);
4660 #endif /* HAVE_XDAMAGE */
4661
4662                         /* XDBE doesn't seem to provide a way to clear the back buffer
4663                          * without interfering with the front buffer, other than passing
4664                          * XdbeBackground to XdbeSwapBuffers. That means that if we're
4665                          * using XDBE, we need to redraw the text even if it wasn't part of
4666                          * the exposed area. OTOH, if we're not going to call draw_stuff at
4667                          * all, then no swap happens and we can safely do nothing. */
4668
4669                         if (!XEmptyRegion(x11_stuff.region)) {
4670 #ifdef HAVE_XDBE
4671                                 if (use_xdbe) {
4672                                         XRectangle r;
4673
4674                                         r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
4675                                         r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
4676                                         r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4677                                         r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
4678                                         XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
4679                                 }
4680 #endif
4681                                 XSetRegion(display, window.gc, x11_stuff.region);
4682 #ifdef XFT
4683                                 if (use_xft) {
4684                                         XftDrawSetClip(window.xftdraw, x11_stuff.region);
4685                                 }
4686 #endif
4687                                 draw_stuff();
4688                                 XDestroyRegion(x11_stuff.region);
4689                                 x11_stuff.region = XCreateRegion();
4690                         }
4691                 } else {
4692 #endif /* X11 */
4693                         t = (next_update_time - get_time()) * 1000000;
4694                         if(t > 0) usleep((useconds_t)t);
4695                         update_text();
4696                         draw_stuff();
4697 #ifdef NCURSES
4698                         if(output_methods & TO_NCURSES) {
4699                                 refresh();
4700                                 clear();
4701                         }
4702 #endif
4703 #ifdef X11
4704                 }
4705 #endif /* X11 */
4706
4707 #ifdef SIGNAL_BLOCKING
4708                 /* unblock signals of interest and let handler fly */
4709                 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
4710                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
4711                 }
4712 #endif
4713
4714                 switch (g_signal_pending) {
4715                         case SIGHUP:
4716                         case SIGUSR1:
4717                                 NORM_ERR("received SIGHUP or SIGUSR1. reloading the config file.");
4718                                 reload_config();
4719                                 break;
4720                         case SIGINT:
4721                         case SIGTERM:
4722                                 NORM_ERR("received SIGINT or SIGTERM to terminate. bye!");
4723                                 terminate = 1;
4724 #ifdef X11
4725                                 if (output_methods & TO_X) {
4726                                         XDestroyRegion(x11_stuff.region);
4727                                         x11_stuff.region = NULL;
4728 #ifdef HAVE_XDAMAGE
4729                                         XDamageDestroy(display, x11_stuff.damage);
4730                                         XFixesDestroyRegion(display, x11_stuff.region2);
4731                                         XFixesDestroyRegion(display, x11_stuff.part);
4732 #endif /* HAVE_XDAMAGE */
4733                                         if (disp) {
4734                                                 free(disp);
4735                                         }
4736                                 }
4737 #endif /* X11 */
4738                                 if(overwrite_file) {
4739                                         free(overwrite_file);
4740                                         overwrite_file = 0;
4741                                 }
4742                                 if(append_file) {
4743                                         free(append_file);
4744                                         append_file = 0;
4745                                 }
4746                                 break;
4747                         default:
4748                                 /* Reaching here means someone set a signal
4749                                  * (SIGXXXX, signal_handler), but didn't write any code
4750                                  * to deal with it.
4751                                  * If you don't want to handle a signal, don't set a handler on
4752                                  * it in the first place. */
4753                                 if (g_signal_pending) {
4754                                         NORM_ERR("ignoring signal (%d)", g_signal_pending);
4755                                 }
4756                                 break;
4757                 }
4758 #ifdef HAVE_SYS_INOTIFY_H
4759                 if (inotify_fd != -1 && inotify_config_wd == -1 && current_config != 0) {
4760                         inotify_config_wd = inotify_add_watch(inotify_fd,
4761                                         current_config,
4762                                         IN_MODIFY);
4763                 }
4764                 if (inotify_fd != -1 && inotify_config_wd != -1 && current_config != 0) {
4765                         int len = 0, idx = 0;
4766                         fd_set descriptors;
4767                         struct timeval time_to_wait;
4768
4769                         FD_ZERO(&descriptors);
4770                         FD_SET(inotify_fd, &descriptors);
4771
4772                         time_to_wait.tv_sec = time_to_wait.tv_usec = 0;
4773
4774                         select(inotify_fd + 1, &descriptors, NULL, NULL, &time_to_wait);
4775                         if (FD_ISSET(inotify_fd, &descriptors)) {
4776                                 /* process inotify events */
4777                                 len = read(inotify_fd, inotify_buff, INOTIFY_BUF_LEN);
4778                                 while (len > 0 && idx < len) {
4779                                         struct inotify_event *ev = (struct inotify_event *) &inotify_buff[idx];
4780                                         if (ev->wd == inotify_config_wd && (ev->mask & IN_MODIFY || ev->mask & IN_IGNORED)) {
4781                                                 /* current_config should be reloaded */
4782                                                 NORM_ERR("'%s' modified, reloading...", current_config);
4783                                                 reload_config();
4784                                                 if (ev->mask & IN_IGNORED) {
4785                                                         /* for some reason we get IN_IGNORED here
4786                                                          * sometimes, so we need to re-add the watch */
4787                                                         inotify_config_wd = inotify_add_watch(inotify_fd,
4788                                                                         current_config,
4789                                                                         IN_MODIFY);
4790                                                 }
4791                                         }
4792 #ifdef HAVE_LUA
4793                                         else {
4794                                                 llua_inotify_query(ev->wd, ev->mask);
4795                                         }
4796 #endif /* HAVE_LUA */
4797                                         idx += INOTIFY_EVENT_SIZE + ev->len;
4798                                 }
4799                         }
4800                 }
4801 #endif /* HAVE_SYS_INOTIFY_H */
4802
4803 #ifdef HAVE_LUA
4804         llua_update_info(&info, update_interval);
4805 #endif /* HAVE_LUA */
4806                 g_signal_pending = 0;
4807         }
4808         clean_up(NULL, NULL);
4809
4810 #ifdef HAVE_SYS_INOTIFY_H
4811         if (inotify_fd != -1) {
4812                 inotify_rm_watch(inotify_fd, inotify_config_wd);
4813                 close(inotify_fd);
4814                 inotify_fd = inotify_config_wd = 0;
4815         }
4816 #endif /* HAVE_SYS_INOTIFY_H */
4817 }
4818
4819 #ifdef X11
4820 static void load_config_file_x11(const char *);
4821 #endif /* X11 */
4822 void initialisation(int argc, char** argv);
4823
4824         /* reload the config file */
4825 static void reload_config(void)
4826 {
4827         char *current_config_copy = strdup(current_config);
4828         clean_up(NULL, NULL);
4829         current_config = current_config_copy;
4830         initialisation(argc_copy, argv_copy);
4831 }
4832
4833 void clean_up(void *memtofree1, void* memtofree2)
4834 {
4835         int i;
4836
4837 #ifdef NCURSES
4838         if(output_methods & TO_NCURSES) {
4839                 endwin();
4840         }
4841 #endif
4842         conftree_empty(currentconffile);
4843         currentconffile = NULL;
4844         if(memtofree1) {
4845                 free(memtofree1);
4846         }
4847         if(memtofree2) {
4848                 free(memtofree2);
4849         }
4850         timed_thread_destroy_registered_threads();
4851
4852         if (info.cpu_usage) {
4853                 free(info.cpu_usage);
4854                 info.cpu_usage = NULL;
4855         }
4856 #ifdef X11
4857         if (x_initialised == YES) {
4858                 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
4859                         text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
4860                         text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
4861                         text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, 0);
4862                 destroy_window();
4863                 free_fonts();
4864                 if(x11_stuff.region) {
4865                         XDestroyRegion(x11_stuff.region);
4866                         x11_stuff.region = NULL;
4867                 }
4868                 XCloseDisplay(display);
4869                 display = NULL;
4870                 if(info.x11.desktop.all_names) {
4871                         free(info.x11.desktop.all_names);
4872                         info.x11.desktop.all_names = NULL;
4873                 }
4874                 if (info.x11.desktop.name) {
4875                         free(info.x11.desktop.name);
4876                         info.x11.desktop.name = NULL;
4877                 }
4878                 x_initialised = NO;
4879         }else{
4880                 free(fonts);    //in set_default_configurations a font is set but not loaded
4881                 font_count = -1;
4882         }
4883
4884 #endif /* X11 */
4885
4886         for (i = 0; i < MAX_TEMPLATES; i++) {
4887                 if (template[i]) {
4888                         free(template[i]);
4889                         template[i] = NULL;
4890                 }
4891         }
4892
4893         free_text_objects(&global_root_object, 0);
4894         if (tmpstring1) {
4895                 free(tmpstring1);
4896                 tmpstring1 = 0;
4897         }
4898         if (tmpstring2) {
4899                 free(tmpstring2);
4900                 tmpstring2 = 0;
4901         }
4902         if (text_buffer) {
4903                 free(text_buffer);
4904                 text_buffer = 0;
4905         }
4906
4907         if (global_text) {
4908                 free(global_text);
4909                 global_text = 0;
4910         }
4911
4912         free(current_config);
4913         current_config = 0;
4914
4915 #ifdef TCP_PORT_MONITOR
4916         tcp_portmon_clear();
4917 #endif
4918 #ifdef HAVE_CURL
4919         ccurl_free_info();
4920 #endif
4921 #ifdef RSS
4922         rss_free_info();
4923 #endif
4924 #ifdef WEATHER
4925         weather_free_info();
4926 #endif
4927 #ifdef HAVE_LUA
4928         llua_shutdown_hook();
4929         llua_close();
4930 #endif /* HAVE_LUA */
4931 #ifdef IMLIB2
4932         cimlib_deinit();
4933 #endif /* IMLIB2 */
4934 #ifdef XOAP
4935         xmlCleanupParser();
4936 #endif /* XOAP */
4937
4938         if (specials) {
4939                 for (i = 0; i < special_count; i++) {
4940                         if (specials[i].type == GRAPH) {
4941                                 free(specials[i].graph);
4942                         }
4943                 }
4944                 free(specials);
4945                 specials = NULL;
4946         }
4947
4948         clear_net_stats();
4949         clear_diskio_stats();
4950         if(global_cpu != NULL) {
4951                 free(global_cpu);
4952                 global_cpu = NULL;
4953         }
4954 }
4955
4956 static int string_to_bool(const char *s)
4957 {
4958         if (!s) {
4959                 // Assumes an option without a true/false means true
4960                 return 1;
4961         } else if (strcasecmp(s, "yes") == EQUAL) {
4962                 return 1;
4963         } else if (strcasecmp(s, "true") == EQUAL) {
4964                 return 1;
4965         } else if (strcasecmp(s, "1") == EQUAL) {
4966                 return 1;
4967         }
4968         return 0;
4969 }
4970
4971 #ifdef X11
4972 static enum alignment string_to_alignment(const char *s)
4973 {
4974         if (strcasecmp(s, "top_left") == EQUAL) {
4975                 return TOP_LEFT;
4976         } else if (strcasecmp(s, "top_right") == EQUAL) {
4977                 return TOP_RIGHT;
4978         } else if (strcasecmp(s, "top_middle") == EQUAL) {
4979                 return TOP_MIDDLE;
4980         } else if (strcasecmp(s, "bottom_left") == EQUAL) {
4981                 return BOTTOM_LEFT;
4982         } else if (strcasecmp(s, "bottom_right") == EQUAL) {
4983                 return BOTTOM_RIGHT;
4984         } else if (strcasecmp(s, "bottom_middle") == EQUAL) {
4985                 return BOTTOM_MIDDLE;
4986         } else if (strcasecmp(s, "middle_left") == EQUAL) {
4987                 return MIDDLE_LEFT;
4988         } else if (strcasecmp(s, "middle_right") == EQUAL) {
4989                 return MIDDLE_RIGHT;
4990         } else if (strcasecmp(s, "tl") == EQUAL) {
4991                 return TOP_LEFT;
4992         } else if (strcasecmp(s, "tr") == EQUAL) {
4993                 return TOP_RIGHT;
4994         } else if (strcasecmp(s, "tm") == EQUAL) {
4995                 return TOP_MIDDLE;
4996         } else if (strcasecmp(s, "bl") == EQUAL) {
4997                 return BOTTOM_LEFT;
4998         } else if (strcasecmp(s, "br") == EQUAL) {
4999                 return BOTTOM_RIGHT;
5000         } else if (strcasecmp(s, "bm") == EQUAL) {
5001                 return BOTTOM_MIDDLE;
5002         } else if (strcasecmp(s, "ml") == EQUAL) {
5003                 return MIDDLE_LEFT;
5004         } else if (strcasecmp(s, "mr") == EQUAL) {
5005                 return MIDDLE_RIGHT;
5006         } else if (strcasecmp(s, "none") == EQUAL) {
5007                 return NONE;
5008         }
5009         return TOP_LEFT;
5010 }
5011 #endif /* X11 */
5012
5013 #ifdef X11
5014 static void set_default_configurations_for_x(void)
5015 {
5016         default_fg_color = WhitePixel(display, screen);
5017         default_bg_color = BlackPixel(display, screen);
5018         default_out_color = BlackPixel(display, screen);
5019         color0 = default_fg_color;
5020         color1 = default_fg_color;
5021         color2 = default_fg_color;
5022         color3 = default_fg_color;
5023         color4 = default_fg_color;
5024         color5 = default_fg_color;
5025         color6 = default_fg_color;
5026         color7 = default_fg_color;
5027         color8 = default_fg_color;
5028         color9 = default_fg_color;
5029         current_text_color = default_fg_color;
5030 }
5031 #endif /* X11 */
5032
5033 static void set_default_configurations(void)
5034 {
5035         int i;
5036 #ifdef MPD
5037         char *mpd_env_host;
5038         char *mpd_env_port;
5039 #endif
5040         update_uname();
5041         fork_to_background = 0;
5042         total_run_times = 0;
5043         info.cpu_avg_samples = 2;
5044         info.net_avg_samples = 2;
5045         info.diskio_avg_samples = 2;
5046         info.memmax = 0;
5047         top_cpu = 0;
5048         cpu_separate = 0;
5049         short_units = 0;
5050         format_human_readable = 1;
5051         top_mem = 0;
5052         top_time = 0;
5053 #ifdef IOSTATS
5054         top_io = 0;
5055 #endif
5056 #ifdef MPD
5057         mpd_env_host = getenv("MPD_HOST");
5058         mpd_env_port = getenv("MPD_PORT");
5059
5060         if (!mpd_env_host || !strlen(mpd_env_host)) {
5061                 mpd_set_host("localhost");
5062         } else {
5063                 /* MPD_HOST environment variable is set */
5064                 char *mpd_hostpart = strchr(mpd_env_host, '@');
5065                 if (!mpd_hostpart) {
5066                         mpd_set_host(mpd_env_host);
5067                 } else {
5068                         /* MPD_HOST contains a password */
5069                         char mpd_password[mpd_hostpart - mpd_env_host + 1];
5070                         snprintf(mpd_password, mpd_hostpart - mpd_env_host + 1, "%s", mpd_env_host);
5071
5072                         if (!strlen(mpd_hostpart + 1)) {
5073                                 mpd_set_host("localhost");
5074                         } else {
5075                                 mpd_set_host(mpd_hostpart + 1);
5076                         }
5077
5078                         mpd_set_password(mpd_password, 1);
5079                 }
5080         }
5081
5082
5083         if (!mpd_env_port || mpd_set_port(mpd_env_port)) {
5084                 /* failed to set port from environment variable */
5085                 mpd_set_port("6600");
5086         }
5087 #endif
5088 #ifdef XMMS2
5089         info.xmms2.artist = NULL;
5090         info.xmms2.album = NULL;
5091         info.xmms2.title = NULL;
5092         info.xmms2.genre = NULL;
5093         info.xmms2.comment = NULL;
5094         info.xmms2.url = NULL;
5095         info.xmms2.status = NULL;
5096         info.xmms2.playlist = NULL;
5097 #endif
5098         use_spacer = NO_SPACER;
5099 #ifdef X11
5100         output_methods = TO_X;
5101 #else
5102         output_methods = TO_STDOUT;
5103 #endif
5104 #ifdef X11
5105         show_graph_scale = 0;
5106         show_graph_range = 0;
5107         draw_shades = 1;
5108         draw_borders = 0;
5109         draw_graph_borders = 1;
5110         draw_outline = 0;
5111         set_first_font("6x10");
5112         gap_x = 5;
5113         gap_y = 60;
5114         minimum_width = 5;
5115         minimum_height = 5;
5116         maximum_width = 0;
5117 #ifdef OWN_WINDOW
5118         own_window = 0;
5119         window.type = TYPE_NORMAL;
5120         window.hints = 0;
5121         strcpy(window.class_name, PACKAGE_NAME);
5122         sprintf(window.title, PACKAGE_NAME" (%s)", info.uname_s.nodename);
5123 #endif
5124         stippled_borders = 0;
5125         window.border_inner_margin = 3;
5126         window.border_outer_margin = 1;
5127         window.border_width = 1;
5128         text_alignment = BOTTOM_LEFT;
5129         info.x11.monitor.number = 1;
5130         info.x11.monitor.current = 0;
5131         info.x11.desktop.current = 1; 
5132         info.x11.desktop.number = 1;
5133         info.x11.desktop.nitems = 0;
5134         info.x11.desktop.all_names = NULL; 
5135         info.x11.desktop.name = NULL; 
5136 #endif /* X11 */
5137
5138         for (i = 0; i < MAX_TEMPLATES; i++) {
5139                 if (template[i])
5140                         free(template[i]);
5141                 template[i] = strdup("");
5142         }
5143
5144         free(current_mail_spool);
5145         {
5146                 char buf[256];
5147
5148                 variable_substitute(MAIL_FILE, buf, 256);
5149                 if (buf[0] != '\0') {
5150                         current_mail_spool = strndup(buf, text_buffer_size);
5151                 }
5152         }
5153
5154         no_buffers = 1;
5155         set_update_interval(3);
5156         update_interval_bat = NOBATTERY;
5157         info.music_player_interval = 1.0;
5158         stuff_in_uppercase = 0;
5159         info.users.number = 1;
5160
5161 #ifdef TCP_PORT_MONITOR
5162         /* set default connection limit */
5163         tcp_portmon_set_max_connections(0);
5164 #endif
5165 }
5166
5167 /* returns 1 if you can overwrite or create the file at 'path' */
5168 static _Bool overwrite_works(const char *path)
5169 {
5170         FILE *filepointer;
5171
5172         if (!(filepointer = fopen(path, "w")))
5173                 return 0;
5174         fclose(filepointer);
5175         return 1;
5176 }
5177
5178 /* returns 1 if you can append or create the file at 'path' */
5179 static _Bool append_works(const char *path)
5180 {
5181         FILE *filepointer;
5182
5183         if (!(filepointer = fopen(path, "a")))
5184                 return 0;
5185         fclose(filepointer);
5186         return 1;
5187 }
5188
5189 #ifdef X11
5190 #ifdef DEBUG
5191 /* WARNING, this type not in Xlib spec */
5192 int x11_error_handler(Display *d, XErrorEvent *err)
5193         __attribute__((noreturn));
5194 int x11_error_handler(Display *d, XErrorEvent *err)
5195 {
5196         NORM_ERR("X Error: type %i Display %lx XID %li serial %lu error_code %i request_code %i minor_code %i other Display: %lx\n",
5197                         err->type,
5198                         (long unsigned)err->display,
5199                         (long)err->resourceid,
5200                         err->serial,
5201                         err->error_code,
5202                         err->request_code,
5203                         err->minor_code,
5204                         (long unsigned)d
5205                         );
5206         abort();
5207 }
5208
5209 int x11_ioerror_handler(Display *d)
5210         __attribute__((noreturn));
5211 int x11_ioerror_handler(Display *d)
5212 {
5213         NORM_ERR("X Error: Display %lx\n",
5214                         (long unsigned)d
5215                         );
5216         abort();
5217 }
5218 #endif /* DEBUG */
5219
5220 static void X11_initialisation(void)
5221 {
5222         if (x_initialised == YES) return;
5223         output_methods |= TO_X;
5224         init_X11(disp);
5225         set_default_configurations_for_x();
5226         x_initialised = YES;
5227 #ifdef DEBUG
5228         _Xdebug = 1;
5229         /* WARNING, this type not in Xlib spec */
5230         XSetErrorHandler(&x11_error_handler);
5231         XSetIOErrorHandler(&x11_ioerror_handler);
5232 #endif /* DEBUG */
5233 }
5234
5235 static char **xargv = 0;
5236 static int xargc = 0;
5237
5238 static void X11_create_window(void)
5239 {
5240         if (output_methods & TO_X) {
5241 #ifdef OWN_WINDOW
5242                 init_window(own_window, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
5243                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, background_colour,
5244                                 xargv, xargc);
5245 #else /* OWN_WINDOW */
5246                 init_window(0, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
5247                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, 0,
5248                                 xargv, xargc);
5249 #endif /* OWN_WINDOW */
5250
5251                 setup_fonts();
5252                 load_fonts();
5253                 update_text_area();     /* to position text/window on screen */
5254
5255 #ifdef OWN_WINDOW
5256                 if (own_window && !fixed_pos) {
5257                         XMoveWindow(display, window.window, window.x, window.y);
5258                 }
5259                 if (own_window) {
5260                         set_transparent_background(window.window);
5261                 }
5262 #endif
5263
5264                 create_gc();
5265
5266                 draw_stuff();
5267
5268                 x11_stuff.region = XCreateRegion();
5269 #ifdef HAVE_XDAMAGE
5270                 if (!XDamageQueryExtension(display, &x11_stuff.event_base, &x11_stuff.error_base)) {
5271                         NORM_ERR("Xdamage extension unavailable");
5272                 }
5273                 x11_stuff.damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
5274                 x11_stuff.region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
5275                 x11_stuff.part = XFixesCreateRegionFromWindow(display, window.window, 0);
5276 #endif /* HAVE_XDAMAGE */
5277
5278                 selected_font = 0;
5279                 update_text_area();     /* to get initial size of the window */
5280         }
5281 #ifdef HAVE_LUA
5282         /* setup lua window globals */
5283         llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
5284 #endif /* HAVE_LUA */
5285 }
5286 #endif /* X11 */
5287
5288 #define CONF_ERR NORM_ERR("%s: %d: config file error", f, line)
5289 #define CONF_ERR2(a) NORM_ERR("%s: %d: config file error: %s", f, line, a)
5290 #define CONF2(a) if (strcasecmp(name, a) == 0)
5291 #define CONF(a) else CONF2(a)
5292 #define CONF3(a, b) else if (strcasecmp(name, a) == 0 \
5293                 || strcasecmp(name, b) == 0)
5294 #define CONF_CONTINUE 1
5295 #define CONF_BREAK 2
5296 #define CONF_BUFF_SIZE 512
5297
5298 static FILE *open_config_file(const char *f)
5299 {
5300 #ifdef CONFIG_OUTPUT
5301         if (!strcmp(f, "==builtin==")) {
5302                 return conf_cookie_open();
5303         } else
5304 #endif /* CONFIG_OUTPUT */
5305                 return fopen(f, "r");
5306 }
5307
5308 static int do_config_step(int *line, FILE *fp, char *buf, char **name, char **value)
5309 {
5310         char *p, *p2;
5311         (*line)++;
5312         if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
5313                 return CONF_BREAK;
5314         }
5315         remove_comments(buf);
5316
5317         p = buf;
5318
5319         /* skip spaces */
5320         while (*p && isspace((int) *p)) {
5321                 p++;
5322         }
5323         if (*p == '\0') {
5324                 return CONF_CONTINUE;   /* empty line */
5325         }
5326
5327         *name = p;
5328
5329         /* skip name */
5330         p2 = p;
5331         while (*p2 && !isspace((int) *p2)) {
5332                 p2++;
5333         }
5334         if (*p2 != '\0') {
5335                 *p2 = '\0';     /* break at name's end */
5336                 p2++;
5337         }
5338
5339         /* get value */
5340         if (*p2) {
5341                 p = p2;
5342                 while (*p && isspace((int) *p)) {
5343                         p++;
5344                 }
5345
5346                 *value = p;
5347
5348                 p2 = *value + strlen(*value);
5349                 while (isspace((int) *(p2 - 1))) {
5350                         *--p2 = '\0';
5351                 }
5352         } else {
5353                 *value = 0;
5354         }
5355         return 0;
5356 }
5357
5358 char load_config_file(const char *f)
5359 {
5360         int line = 0;
5361         FILE *fp;
5362
5363         fp = open_config_file(f);
5364         if (!fp) {
5365                 return FALSE;
5366         }
5367         DBGP("reading contents from config file '%s'", f);
5368
5369         while (!feof(fp)) {
5370                 char buff[CONF_BUFF_SIZE], *name, *value;
5371                 int ret = do_config_step(&line, fp, buff, &name, &value);
5372                 if (ret == CONF_BREAK) {
5373                         break;
5374                 } else if (ret == CONF_CONTINUE) {
5375                         continue;
5376                 }
5377
5378 #ifdef X11
5379                 CONF2("out_to_x") {
5380                         /* don't listen if X is already initialised or
5381                          * if we already know we don't want it */
5382                         if(x_initialised != YES) {
5383                                 if (string_to_bool(value)) {
5384                                         output_methods &= TO_X;
5385                                 } else {
5386                                         output_methods &= ~TO_X;
5387                                         x_initialised = NEVER;
5388                                 }
5389                         }
5390                 }
5391                 CONF("display") {
5392                         if (!value || x_initialised == YES) {
5393                                 CONF_ERR;
5394                         } else {
5395                                 if (disp)
5396                                         free(disp);
5397                                 disp = strdup(value);
5398                         }
5399                 }
5400                 CONF("alignment") {
5401 #ifdef OWN_WINDOW
5402                         if (window.type == TYPE_DOCK)
5403                                 ;
5404                         else
5405 #endif /*OWN_WINDOW */
5406                         if (value) {
5407                                 int a = string_to_alignment(value);
5408
5409                                 if (a <= 0) {
5410                                         CONF_ERR;
5411                                 } else {
5412                                         text_alignment = a;
5413                                 }
5414                         } else {
5415                                 CONF_ERR;
5416                         }
5417                 }
5418                 CONF("background") {
5419                         fork_to_background = string_to_bool(value);
5420                 }
5421 #else
5422                 CONF2("background") {
5423                         fork_to_background = string_to_bool(value);
5424                 }
5425 #endif /* X11 */
5426 #ifdef X11
5427                 CONF("show_graph_scale") {
5428                         show_graph_scale = string_to_bool(value);
5429                 }
5430                 CONF("show_graph_range") {
5431                         show_graph_range = string_to_bool(value);
5432                 }
5433                 CONF("border_inner_margin") {
5434                         if (value) {
5435                                 window.border_inner_margin = strtol(value, 0, 0);
5436                                 if (window.border_inner_margin < 0) window.border_inner_margin = 0;
5437                         } else {
5438                                 CONF_ERR;
5439                         }
5440                 }
5441                 CONF("border_outer_margin") {
5442                         if (value) {
5443                                 window.border_outer_margin = strtol(value, 0, 0);
5444                                 if (window.border_outer_margin < 0) window.border_outer_margin = 0;
5445                         } else {
5446                                 CONF_ERR;
5447                         }
5448                 }
5449                 CONF("border_width") {
5450                         if (value) {
5451                                 window.border_width = strtol(value, 0, 0);
5452                                 if (window.border_width < 0) window.border_width = 0;
5453                         } else {
5454                                 CONF_ERR;
5455                         }
5456                 }
5457 #endif /* X11 */
5458 #define TEMPLATE_CONF(n) \
5459                 CONF("template"#n) { \
5460                         if (value) { \
5461                                 free(template[n]); \
5462                                 template[n] = strdup(value); \
5463                         } else { \
5464                                 CONF_ERR; \
5465                         } \
5466                 }
5467                 TEMPLATE_CONF(0)
5468                 TEMPLATE_CONF(1)
5469                 TEMPLATE_CONF(2)
5470                 TEMPLATE_CONF(3)
5471                 TEMPLATE_CONF(4)
5472                 TEMPLATE_CONF(5)
5473                 TEMPLATE_CONF(6)
5474                 TEMPLATE_CONF(7)
5475                 TEMPLATE_CONF(8)
5476                 TEMPLATE_CONF(9)
5477                 CONF("imap") {
5478                         if (value) {
5479                                 info.mail = parse_mail_args(IMAP_TYPE, value);
5480                         } else {
5481                                 CONF_ERR;
5482                         }
5483                 }
5484                 CONF("pop3") {
5485                         if (value) {
5486                                 info.mail = parse_mail_args(POP3_TYPE, value);
5487                         } else {
5488                                 CONF_ERR;
5489                         }
5490                 }
5491                 CONF("default_bar_size") {
5492                         char err = 0;
5493                         if (value) {
5494                                 if (sscanf(value, "%d %d", &default_bar_width, &default_bar_height) != 2) {
5495                                         err = 1;
5496                                 }
5497                         } else {
5498                                 err = 1;
5499                         }
5500                         if (err) {
5501                                 CONF_ERR2("default_bar_size takes 2 integer arguments (ie. 'default_bar_size 0 6')")
5502                         }
5503                 }
5504 #ifdef X11
5505                 CONF("default_graph_size") {
5506                         char err = 0;
5507                         if (value) {
5508                                 if (sscanf(value, "%d %d", &default_graph_width, &default_graph_height) != 2) {
5509                                         err = 1;
5510                                 }
5511                         } else {
5512                                 err = 1;
5513                         }
5514                         if (err) {
5515                                 CONF_ERR2("default_graph_size takes 2 integer arguments (ie. 'default_graph_size 0 6')")
5516                         }
5517                 }
5518                 CONF("default_gauge_size") {
5519                         char err = 0;
5520                         if (value) {
5521                                 if (sscanf(value, "%d %d", &default_gauge_width, &default_gauge_height) != 2) {
5522                                         err = 1;
5523                                 }
5524                         } else {
5525                                 err = 1;
5526                         }
5527                         if (err) {
5528                                 CONF_ERR2("default_gauge_size takes 2 integer arguments (ie. 'default_gauge_size 0 6')")
5529                         }
5530                 }
5531 #endif
5532 #ifdef MPD
5533                 CONF("mpd_host") {
5534                         if (value) {
5535                                 mpd_set_host(value);
5536                         } else {
5537                                 CONF_ERR;
5538                         }
5539                 }
5540                 CONF("mpd_port") {
5541                         if (value && mpd_set_port(value)) {
5542                                 CONF_ERR;
5543                         }
5544                 }
5545                 CONF("mpd_password") {
5546                         if (value) {
5547                                 mpd_set_password(value, 0);
5548                         } else {
5549                                 CONF_ERR;
5550                         }
5551                 }
5552 #endif
5553                 CONF("music_player_interval") {
5554                         if (value) {
5555                                 info.music_player_interval = strtod(value, 0);
5556                         } else {
5557                                 CONF_ERR;
5558                         }
5559                 }
5560 #ifdef __OpenBSD__
5561                 CONF("sensor_device") {
5562                         if (value) {
5563                                 sensor_device = strtol(value, 0, 0);
5564                         } else {
5565                                 CONF_ERR;
5566                         }
5567                 }
5568 #endif
5569                 CONF("cpu_avg_samples") {
5570                         if (value) {
5571                                 cpu_avg_samples = strtol(value, 0, 0);
5572                                 if (cpu_avg_samples < 1 || cpu_avg_samples > 14) {
5573                                         CONF_ERR;
5574                                 } else {
5575                                         info.cpu_avg_samples = cpu_avg_samples;
5576                                 }
5577                         } else {
5578                                 CONF_ERR;
5579                         }
5580                 }
5581                 CONF("net_avg_samples") {
5582                         if (value) {
5583                                 net_avg_samples = strtol(value, 0, 0);
5584                                 if (net_avg_samples < 1 || net_avg_samples > 14) {
5585                                         CONF_ERR;
5586                                 } else {
5587                                         info.net_avg_samples = net_avg_samples;
5588                                 }
5589                         } else {
5590                                 CONF_ERR;
5591                         }
5592                 }
5593                 CONF("diskio_avg_samples") {
5594                         if (value) {
5595                                 diskio_avg_samples = strtol(value, 0, 0);
5596                                 if (diskio_avg_samples < 1 || diskio_avg_samples > 14) {
5597                                         CONF_ERR;
5598                                 } else {
5599                                         info.diskio_avg_samples = diskio_avg_samples;
5600                                 }
5601                         } else {
5602                                 CONF_ERR;
5603                         }
5604                 }
5605
5606 #ifdef HAVE_XDBE
5607                 CONF("double_buffer") {
5608                         use_xdbe = string_to_bool(value);
5609                 }
5610 #endif
5611 #ifdef X11
5612                 CONF("override_utf8_locale") {
5613                         utf8_mode = string_to_bool(value);
5614                 }
5615                 CONF("draw_borders") {
5616                         draw_borders = string_to_bool(value);
5617                 }
5618                 CONF("draw_graph_borders") {
5619                         draw_graph_borders = string_to_bool(value);
5620                 }
5621                 CONF("draw_shades") {
5622                         draw_shades = string_to_bool(value);
5623                 }
5624                 CONF("draw_outline") {
5625                         draw_outline = string_to_bool(value);
5626                 }
5627 #endif /* X11 */
5628                 CONF("out_to_console") {
5629                         if(string_to_bool(value)) {
5630                                 output_methods |= TO_STDOUT;
5631                         } else {
5632                                 output_methods &= ~TO_STDOUT;
5633                         }
5634                 }
5635                 CONF("extra_newline") {
5636                         extra_newline = string_to_bool(value);
5637                 }
5638                 CONF("out_to_stderr") {
5639                         if(string_to_bool(value))
5640                                 output_methods |= TO_STDERR;
5641                 }
5642 #ifdef NCURSES
5643                 CONF("out_to_ncurses") {
5644                         if(string_to_bool(value)) {
5645                                 initscr();
5646                                 start_color();
5647                                 output_methods |= TO_NCURSES;
5648                         }
5649                 }
5650 #endif
5651                 CONF("overwrite_file") {
5652                         if(overwrite_file) {
5653                                 free(overwrite_file);
5654                                 overwrite_file = 0;
5655                         }
5656                         if(overwrite_works(value)) {
5657                                 overwrite_file = strdup(value);
5658                                 output_methods |= OVERWRITE_FILE;
5659                         } else
5660                                 NORM_ERR("overwrite_file won't be able to create/overwrite '%s'", value);
5661                 }
5662                 CONF("append_file") {
5663                         if(append_file) {
5664                                 free(append_file);
5665                                 append_file = 0;
5666                         }
5667                         if(append_works(value)) {
5668                                 append_file = strdup(value);
5669                                 output_methods |= APPEND_FILE;
5670                         } else
5671                                 NORM_ERR("append_file won't be able to create/append '%s'", value);
5672                 }
5673                 CONF("use_spacer") {
5674                         if (value) {
5675                                 if (strcasecmp(value, "left") == EQUAL) {
5676                                         use_spacer = LEFT_SPACER;
5677                                 } else if (strcasecmp(value, "right") == EQUAL) {
5678                                         use_spacer = RIGHT_SPACER;
5679                                 } else if (strcasecmp(value, "none") == EQUAL) {
5680                                         use_spacer = NO_SPACER;
5681                                 } else {
5682                                         use_spacer = string_to_bool(value);
5683                                         NORM_ERR("use_spacer should have an argument of left, right, or"
5684                                                 " none.  '%s' seems to be some form of '%s', so"
5685                                                 " defaulting to %s.", value,
5686                                                 use_spacer ? "true" : "false",
5687                                                 use_spacer ? "right" : "none");
5688                                         if (use_spacer) {
5689                                                 use_spacer = RIGHT_SPACER;
5690                                         } else {
5691                                                 use_spacer = NO_SPACER;
5692                                         }
5693                                 }
5694                         } else {
5695                                 NORM_ERR("use_spacer should have an argument. Defaulting to right.");
5696                                 use_spacer = RIGHT_SPACER;
5697                         }
5698                 }
5699 #ifdef X11
5700 #ifdef XFT
5701                 CONF("use_xft") {
5702                         use_xft = string_to_bool(value);
5703                 }
5704                 CONF("font") {
5705                         if (value) {
5706                                 set_first_font(value);
5707                         }
5708                 }
5709                 CONF("xftalpha") {
5710                         if (value && font_count >= 0) {
5711                                 fonts[0].font_alpha = atof(value) * 65535.0;
5712                         }
5713                 }
5714                 CONF("xftfont") {
5715                         if (use_xft) {
5716 #else
5717                 CONF("use_xft") {
5718                         if (string_to_bool(value)) {
5719                                 NORM_ERR("Xft not enabled at compile time");
5720                         }
5721                 }
5722                 CONF("xftfont") {
5723                         /* xftfont silently ignored when no Xft */
5724                 }
5725                 CONF("xftalpha") {
5726                         /* xftalpha is silently ignored when no Xft */
5727                 }
5728                 CONF("font") {
5729 #endif
5730                         if (value) {
5731                                 set_first_font(value);
5732                         }
5733 #ifdef XFT
5734                         }
5735 #endif
5736                 }
5737                 CONF("gap_x") {
5738                         if (value) {
5739                                 gap_x = atoi(value);
5740                         } else {
5741                                 CONF_ERR;
5742                         }
5743                 }
5744                 CONF("gap_y") {
5745                         if (value) {
5746                                 gap_y = atoi(value);
5747                         } else {
5748                                 CONF_ERR;
5749                         }
5750                 }
5751 #endif /* X11 */
5752                 CONF("mail_spool") {
5753                         if (value) {
5754                                 char buffer[256];
5755
5756                                 variable_substitute(value, buffer, 256);
5757
5758                                 if (buffer[0] != '\0') {
5759                                         if (current_mail_spool) {
5760                                                 free(current_mail_spool);
5761                                         }
5762                                         current_mail_spool = strndup(buffer, text_buffer_size);
5763                                 }
5764                         } else {
5765                                 CONF_ERR;
5766                         }
5767                 }
5768 #ifdef X11
5769                 CONF("minimum_size") {
5770                         if (value) {
5771                                 if (sscanf(value, "%d %d", &minimum_width, &minimum_height)
5772                                                 != 2) {
5773                                         if (sscanf(value, "%d", &minimum_width) != 1) {
5774                                                 CONF_ERR;
5775                                         }
5776                                 }
5777                         } else {
5778                                 CONF_ERR;
5779                         }
5780                 }
5781                 CONF("maximum_width") {
5782                         if (value) {
5783                                 if (sscanf(value, "%d", &maximum_width) != 1) {
5784                                         CONF_ERR;
5785                                 }
5786                         } else {
5787                                 CONF_ERR;
5788                         }
5789                 }
5790 #endif /* X11 */
5791                 CONF("no_buffers") {
5792                         no_buffers = string_to_bool(value);
5793                 }
5794                 CONF("top_name_width") {
5795                         if (value) {
5796                                 if (sscanf(value, "%u", &top_name_width) != 1) {
5797                                         CONF_ERR;
5798                                 }
5799                         } else {
5800                                 CONF_ERR;
5801                         }
5802                         if (top_name_width >= max_user_text) {
5803                                 top_name_width = max_user_text - 1;
5804                         }
5805                 }
5806                 CONF("top_cpu_separate") {
5807                         cpu_separate = string_to_bool(value);
5808                 }
5809                 CONF("short_units") {
5810                         short_units = string_to_bool(value);
5811                 }
5812                 CONF("format_human_readable") {
5813                         format_human_readable = string_to_bool(value);
5814                 }
5815                 CONF("pad_percents") {
5816                         pad_percents = atoi(value);
5817                 }
5818 #ifdef X11
5819 #ifdef OWN_WINDOW
5820                 CONF("own_window") {
5821                         if (value) {
5822                                 own_window = string_to_bool(value);
5823                         }
5824                 }
5825                 CONF("own_window_class") {
5826                         if (value) {
5827                                 memset(window.class_name, 0, sizeof(window.class_name));
5828                                 strncpy(window.class_name, value,
5829                                                 sizeof(window.class_name) - 1);
5830                         }
5831                 }
5832                 CONF("own_window_title") {
5833                         if (value) {
5834                                 memset(window.title, 0, sizeof(window.title));
5835                                 strncpy(window.title, value, sizeof(window.title) - 1);
5836                         }
5837                 }
5838                 CONF("own_window_transparent") {
5839                         if (value) {
5840                                 set_transparent = string_to_bool(value);
5841                         }
5842                 }
5843                 CONF("own_window_hints") {
5844                         if (value) {
5845                                 char *p_hint, *p_save;
5846                                 char delim[] = ", ";
5847
5848                                 /* tokenize the value into individual hints */
5849                                 if ((p_hint = strtok_r(value, delim, &p_save)) != NULL) {
5850                                         do {
5851                                                 /* fprintf(stderr, "hint [%s] parsed\n", p_hint); */
5852                                                 if (strncmp(p_hint, "undecorate", 10) == EQUAL) {
5853                                                         SET_HINT(window.hints, HINT_UNDECORATED);
5854                                                 } else if (strncmp(p_hint, "below", 5) == EQUAL) {
5855                                                         SET_HINT(window.hints, HINT_BELOW);
5856                                                 } else if (strncmp(p_hint, "above", 5) == EQUAL) {
5857                                                         SET_HINT(window.hints, HINT_ABOVE);
5858                                                 } else if (strncmp(p_hint, "sticky", 6) == EQUAL) {
5859                                                         SET_HINT(window.hints, HINT_STICKY);
5860                                                 } else if (strncmp(p_hint, "skip_taskbar", 12) == EQUAL) {
5861                                                         SET_HINT(window.hints, HINT_SKIP_TASKBAR);
5862                                                 } else if (strncmp(p_hint, "skip_pager", 10) == EQUAL) {
5863                                                         SET_HINT(window.hints, HINT_SKIP_PAGER);
5864                                                 } else {
5865                                                         CONF_ERR;
5866                                                 }
5867
5868                                                 p_hint = strtok_r(NULL, delim, &p_save);
5869                                         } while (p_hint != NULL);
5870                                 }
5871                         } else {
5872                                 CONF_ERR;
5873                         }
5874                 }
5875                 CONF("own_window_type") {
5876                         if (value) {
5877                                 if (strncmp(value, "normal", 6) == EQUAL) {
5878                                         window.type = TYPE_NORMAL;
5879                                 } else if (strncmp(value, "desktop", 7) == EQUAL) {
5880                                         window.type = TYPE_DESKTOP;
5881                                 } else if (strncmp(value, "dock", 4) == EQUAL) {
5882                                         window.type = TYPE_DOCK;
5883                                         text_alignment = TOP_LEFT;
5884                                 } else if (strncmp(value, "panel", 5) == EQUAL) {
5885                                         window.type = TYPE_PANEL;
5886                                 } else if (strncmp(value, "override", 8) == EQUAL) {
5887                                         window.type = TYPE_OVERRIDE;
5888                                 } else {
5889                                         CONF_ERR;
5890                                 }
5891                         } else {
5892                                 CONF_ERR;
5893                         }
5894                 }
5895 #endif
5896                 CONF("stippled_borders") {
5897                         if (value) {
5898                                 stippled_borders = strtol(value, 0, 0);
5899                         } else {
5900                                 stippled_borders = 4;
5901                         }
5902                 }
5903 #ifdef IMLIB2
5904                 CONF("imlib_cache_size") {
5905                         if (value) {
5906                                 cimlib_set_cache_size(atoi(value));
5907                         }
5908                 }
5909                 CONF("imlib_cache_flush_interval") {
5910                         if (value) {
5911                                 cimlib_set_cache_flush_interval(atoi(value));
5912                         }
5913                 }
5914 #endif /* IMLIB2 */
5915 #endif /* X11 */
5916                 CONF("update_interval_on_battery") {
5917                         if (value) {
5918                                 update_interval_bat = strtod(value, 0);
5919                         } else {
5920                                 CONF_ERR;
5921                         }
5922                 }
5923                 CONF("update_interval") {
5924                         if (value) {
5925                                 set_update_interval(strtod(value, 0));
5926                         } else {
5927                                 CONF_ERR;
5928                         }
5929                         if (info.music_player_interval == 0) {
5930                                 // default to update_interval
5931                                 info.music_player_interval = update_interval;
5932                         }
5933                 }
5934                 CONF("total_run_times") {
5935                         if (value) {
5936                                 total_run_times = strtod(value, 0);
5937                         } else {
5938                                 CONF_ERR;
5939                         }
5940                 }
5941                 CONF("uppercase") {
5942                         stuff_in_uppercase = string_to_bool(value);
5943                 }
5944                 CONF("max_specials") {
5945                         if (value) {
5946                                 max_specials = atoi(value);
5947                         } else {
5948                                 CONF_ERR;
5949                         }
5950                 }
5951                 CONF("max_user_text") {
5952                         if (value) {
5953                                 max_user_text = atoi(value);
5954                         } else {
5955                                 CONF_ERR;
5956                         }
5957                 }
5958                 CONF("text_buffer_size") {
5959                         if (value) {
5960                                 text_buffer_size = atoi(value);
5961                                 if (text_buffer_size < DEFAULT_TEXT_BUFFER_SIZE) {
5962                                         NORM_ERR("text_buffer_size must be >=%i bytes", DEFAULT_TEXT_BUFFER_SIZE);
5963                                         text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
5964                                 }
5965                         } else {
5966                                 CONF_ERR;
5967                         }
5968                 }
5969                 CONF("text") {
5970 #ifdef X11
5971                         if (output_methods & TO_X) {
5972                                 X11_initialisation();
5973                         }
5974 #endif
5975
5976                         if (global_text) {
5977                                 free(global_text);
5978                                 global_text = 0;
5979                         }
5980
5981                         global_text = (char *) malloc(1);
5982                         global_text[0] = '\0';
5983
5984                         while (!feof(fp)) {
5985                                 unsigned int l = strlen(global_text);
5986                                 unsigned int bl;
5987                                 char buf[CONF_BUFF_SIZE];
5988
5989                                 if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
5990                                         break;
5991                                 }
5992
5993                                 /* Remove \\-\n. */
5994                                 bl = strlen(buf);
5995                                 if (bl >= 2 && buf[bl-2] == '\\' && buf[bl-1] == '\n') {
5996                                         buf[bl-2] = '\0';
5997                                         bl -= 2;
5998                                         if (bl == 0) {
5999                                                 continue;
6000                                         }
6001                                 }
6002
6003                                 /* Check for continuation of \\-\n. */
6004                                 if (l > 0 && buf[0] == '\n' && global_text[l-1] == '\\') {
6005                                         global_text[l-1] = '\0';
6006                                         continue;
6007                                 }
6008
6009                                 global_text = (char *) realloc(global_text, l + bl + 1);
6010                                 strcat(global_text, buf);
6011
6012                                 if (strlen(global_text) > max_user_text) {
6013                                         break;
6014                                 }
6015                         }
6016                         fclose(fp);
6017                         if (strlen(global_text) < 1) {
6018                                 CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
6019                         }
6020                         global_text_lines = line + 1;
6021                         return TRUE;
6022                 }
6023 #ifdef TCP_PORT_MONITOR
6024                 CONF("max_port_monitor_connections") {
6025                         int max;
6026                         if (!value || (sscanf(value, "%d", &max) != 1)) {
6027                                 /* an error. use default, warn and continue. */
6028                                 tcp_portmon_set_max_connections(0);
6029                                 CONF_ERR;
6030                         } else if (tcp_portmon_set_max_connections(max)) {
6031                                 /* max is < 0, default has been set*/
6032                                 CONF_ERR;
6033                         }
6034                 }
6035 #endif
6036                 CONF("if_up_strictness") {
6037                         if (!value) {
6038                                 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
6039                                 ifup_strictness = IFUP_UP;
6040                         } else if (strcasecmp(value, "up") == EQUAL) {
6041                                 ifup_strictness = IFUP_UP;
6042                         } else if (strcasecmp(value, "link") == EQUAL) {
6043                                 ifup_strictness = IFUP_LINK;
6044                         } else if (strcasecmp(value, "address") == EQUAL) {
6045                                 ifup_strictness = IFUP_ADDR;
6046                         } else {
6047                                 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
6048                                 ifup_strictness = IFUP_UP;
6049                         }
6050                 }
6051
6052                 CONF("temperature_unit") {
6053                         if (!value) {
6054                                 NORM_ERR("config option 'temperature_unit' needs an argument, either 'celsius' or 'fahrenheit'");
6055                         } else if (set_temp_output_unit(value)) {
6056                                 NORM_ERR("temperature_unit: incorrect argument");
6057                         }
6058                 }
6059
6060 #ifdef HAVE_LUA
6061                 CONF("lua_load") {
6062                         if (value) {
6063                                 char *ptr = strtok(value, " ");
6064                                 while (ptr) {
6065                                         llua_load(ptr);
6066                                         ptr = strtok(NULL, " ");
6067                                 }
6068                         } else {
6069                                 CONF_ERR;
6070                         }
6071                 }
6072 #ifdef X11
6073                 CONF("lua_draw_hook_pre") {
6074                         if (value) {
6075                                 llua_set_draw_pre_hook(value);
6076                         } else {
6077                                 CONF_ERR;
6078                         }
6079                 }
6080                 CONF("lua_draw_hook_post") {
6081                         if (value) {
6082                                 llua_set_draw_post_hook(value);
6083                         } else {
6084                                 CONF_ERR;
6085                         }
6086                 }
6087                 CONF("lua_startup_hook") {
6088                         if (value) {
6089                                 llua_set_startup_hook(value);
6090                         } else {
6091                                 CONF_ERR;
6092                         }
6093                 }
6094                 CONF("lua_shutdown_hook") {
6095                         if (value) {
6096                                 llua_set_shutdown_hook(value);
6097                         } else {
6098                                 CONF_ERR;
6099                         }
6100                 }
6101 #endif /* X11 */
6102 #endif /* HAVE_LUA */
6103
6104                 CONF("color0"){}
6105                 CONF("color1"){}
6106                 CONF("color2"){}
6107                 CONF("color3"){}
6108                 CONF("color4"){}
6109                 CONF("color5"){}
6110                 CONF("color6"){}
6111                 CONF("color7"){}
6112                 CONF("color8"){}
6113                 CONF("color9"){}
6114                 CONF("default_color"){}
6115                 CONF3("default_shade_color", "default_shadecolor"){}
6116                 CONF3("default_outline_color", "default_outlinecolor") {}
6117                 CONF("own_window_colour") {}
6118
6119                 else {
6120                         NORM_ERR("%s: %d: no such configuration: '%s'", f, line, name);
6121                 }
6122         }
6123
6124         fclose(fp);
6125
6126         if (info.music_player_interval == 0) {
6127                 // default to update_interval
6128                 info.music_player_interval = update_interval;
6129         }
6130         if (!global_text) { // didn't supply any text
6131                 CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
6132         }
6133         return TRUE;
6134 }
6135
6136 #ifdef X11
6137 static void load_config_file_x11(const char *f)
6138 {
6139         int line = 0;
6140         FILE *fp;
6141
6142         fp = open_config_file(f);
6143         if (!fp) {
6144                 return;
6145         }
6146         DBGP("reading contents from config file '%s'", f);
6147
6148         while (!feof(fp)) {
6149                 char buff[CONF_BUFF_SIZE], *name, *value;
6150                 int ret = do_config_step(&line, fp, buff, &name, &value);
6151                 if (ret == CONF_BREAK) {
6152                         break;
6153                 } else if (ret == CONF_CONTINUE) {
6154                         continue;
6155                 }
6156
6157                 CONF2("color0") {
6158                         X11_initialisation();
6159                         if (x_initialised == YES) {
6160                                 if (value) {
6161                                         color0 = get_x11_color(value);
6162                                 } else {
6163                                         CONF_ERR;
6164                                 }
6165                         }
6166                 }
6167                 CONF("color1") {
6168                         X11_initialisation();
6169                         if (x_initialised == YES) {
6170                                 if (value) {
6171                                         color1 = get_x11_color(value);
6172                                 } else {
6173                                         CONF_ERR;
6174                                 }
6175                         }
6176                 }
6177                 CONF("color2") {
6178                         X11_initialisation();
6179                         if (x_initialised == YES) {
6180                                 if (value) {
6181                                         color2 = get_x11_color(value);
6182                                 } else {
6183                                         CONF_ERR;
6184                                 }
6185                         }
6186                 }
6187                 CONF("color3") {
6188                         X11_initialisation();
6189                         if (x_initialised == YES) {
6190                                 if (value) {
6191                                         color3 = get_x11_color(value);
6192                                 } else {
6193                                         CONF_ERR;
6194                                 }
6195                         }
6196                 }
6197                 CONF("color4") {
6198                         X11_initialisation();
6199                         if (x_initialised == YES) {
6200                                 if (value) {
6201                                         color4 = get_x11_color(value);
6202                                 } else {
6203                                         CONF_ERR;
6204                                 }
6205                         }
6206                 }
6207                 CONF("color5") {
6208                         X11_initialisation();
6209                         if (x_initialised == YES) {
6210                                 if (value) {
6211                                         color5 = get_x11_color(value);
6212                                 } else {
6213                                         CONF_ERR;
6214                                 }
6215                         }
6216                 }
6217                 CONF("color6") {
6218                         X11_initialisation();
6219                         if (x_initialised == YES) {
6220                                 if (value) {
6221                                         color6 = get_x11_color(value);
6222                                 } else {
6223                                         CONF_ERR;
6224                                 }
6225                         }
6226                 }
6227                 CONF("color7") {
6228                         X11_initialisation();
6229                         if (x_initialised == YES) {
6230                                 if (value) {
6231                                         color7 = get_x11_color(value);
6232                                 } else {
6233                                         CONF_ERR;
6234                                 }
6235                         }
6236                 }
6237                 CONF("color8") {
6238                         X11_initialisation();
6239                         if (x_initialised == YES) {
6240                                 if (value) {
6241                                         color8 = get_x11_color(value);
6242                                 } else {
6243                                         CONF_ERR;
6244                                 }
6245                         }
6246                 }
6247                 CONF("color9") {
6248                         X11_initialisation();
6249                         if (x_initialised == YES) {
6250                                 if (value) {
6251                                         color9 = get_x11_color(value);
6252                                 } else {
6253                                         CONF_ERR;
6254                                 }
6255                         }
6256                 }
6257                 CONF("default_color") {
6258                         X11_initialisation();
6259                         if (x_initialised == YES) {
6260                                 if (value) {
6261                                         default_fg_color = get_x11_color(value);
6262                                 } else {
6263                                         CONF_ERR;
6264                                 }
6265                         }
6266                 }
6267                 CONF3("default_shade_color", "default_shadecolor") {
6268                         X11_initialisation();
6269                         if (x_initialised == YES) {
6270                                 if (value) {
6271                                         default_bg_color = get_x11_color(value);
6272                                 } else {
6273                                         CONF_ERR;
6274                                 }
6275                         }
6276                 }
6277                 CONF3("default_outline_color", "default_outlinecolor") {
6278                         X11_initialisation();
6279                         if (x_initialised == YES) {
6280                                 if (value) {
6281                                         default_out_color = get_x11_color(value);
6282                                 } else {
6283                                         CONF_ERR;
6284                                 }
6285                         }
6286                 }
6287 #ifdef OWN_WINDOW
6288                 CONF("own_window_colour") {
6289                         X11_initialisation();
6290                         if (x_initialised == YES) {
6291                                 if (value) {
6292                                         background_colour = get_x11_color(value);
6293                                 } else {
6294                                         NORM_ERR("Invalid colour for own_window_colour (try omitting the "
6295                                                 "'#' for hex colours");
6296                                 }
6297                         }
6298                 }
6299 #endif
6300                 CONF("text") {
6301                         /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
6302                         if(output_methods & TO_X) {
6303                                 X11_initialisation();
6304                         }
6305                 }
6306 #undef CONF
6307 #undef CONF2
6308 #undef CONF3
6309 #undef CONF_ERR
6310 #undef CONF_ERR2
6311 #undef CONF_BREAK
6312 #undef CONF_CONTINUE
6313 #undef CONF_BUFF_SIZE
6314         }
6315
6316         fclose(fp);
6317
6318 }
6319 #endif /* X11 */
6320
6321 static void print_help(const char *prog_name) {
6322         printf("Usage: %s [OPTION]...\n"
6323                         PACKAGE_NAME" is a system monitor that renders text on desktop or to own transparent\n"
6324                         "window. Command line options will override configurations defined in config\n"
6325                         "file.\n"
6326                         "   -v, --version             version\n"
6327                         "   -q, --quiet               quiet mode\n"
6328                         "   -D, --debug               increase debugging output, ie. -DD for more debugging\n"
6329                         "   -c, --config=FILE         config file to load\n"
6330 #ifdef CONFIG_OUTPUT
6331                         "   -C, --print-config        print the builtin default config to stdout\n"
6332                         "                             e.g. 'conky -C > ~/.conkyrc' will create a new default config\n"
6333 #endif
6334                         "   -d, --daemonize           daemonize, fork to background\n"
6335                         "   -h, --help                help\n"
6336 #ifdef X11
6337                         "   -a, --alignment=ALIGNMENT text alignment on screen, {top,bottom,middle}_{left,right,middle}\n"
6338                         "   -f, --font=FONT           font to use\n"
6339                         "   -X, --display=DISPLAY     X11 display to use\n"
6340 #ifdef OWN_WINDOW
6341                         "   -o, --own-window          create own window to draw\n"
6342 #endif
6343 #ifdef HAVE_XDBE
6344                         "   -b, --double-buffer       double buffer (prevents flickering)\n"
6345 #endif
6346                         "   -w, --window-id=WIN_ID    window id to draw\n"
6347                         "   -x X                      x position\n"
6348                         "   -y Y                      y position\n"
6349 #endif /* X11 */
6350                         "   -t, --text=TEXT           text to render, remember single quotes, like -t '$uptime'\n"
6351                         "   -u, --interval=SECS       update interval\n"
6352                         "   -i COUNT                  number of times to update "PACKAGE_NAME" (and quit)\n",
6353                         prog_name
6354         );
6355 }
6356
6357 /* : means that character before that takes an argument */
6358 static const char *getopt_string = "vVqdDt:u:i:hc:"
6359 #ifdef X11
6360         "x:y:w:a:f:X:"
6361 #ifdef OWN_WINDOW
6362         "o"
6363 #endif
6364 #ifdef HAVE_XDBE
6365         "b"
6366 #endif
6367 #endif /* X11 */
6368 #ifdef CONFIG_OUTPUT
6369         "C"
6370 #endif
6371         ;
6372
6373 static const struct option longopts[] = {
6374         { "help", 0, NULL, 'h' },
6375         { "version", 0, NULL, 'V' },
6376         { "debug", 0, NULL, 'D' },
6377         { "config", 1, NULL, 'c' },
6378 #ifdef CONFIG_OUTPUT
6379         { "print-config", 0, NULL, 'C' },
6380 #endif
6381         { "daemonize", 0, NULL, 'd' },
6382 #ifdef X11
6383         { "alignment", 1, NULL, 'a' },
6384         { "font", 1, NULL, 'f' },
6385         { "display", 1, NULL, 'X' },
6386 #ifdef OWN_WINDOW
6387         { "own-window", 0, NULL, 'o' },
6388 #endif
6389 #ifdef HAVE_XDBE
6390         { "double-buffer", 0, NULL, 'b' },
6391 #endif
6392         { "window-id", 1, NULL, 'w' },
6393 #endif /* X11 */
6394         { "text", 1, NULL, 't' },
6395         { "interval", 0, NULL, 'u' },
6396         { 0, 0, 0, 0 }
6397 };
6398
6399 void initialisation(int argc, char **argv) {
6400         struct sigaction act, oact;
6401
6402         set_default_configurations();
6403         load_config_file(current_config);
6404         currentconffile = conftree_add(currentconffile, current_config);
6405
6406         /* init specials array */
6407         if ((specials = calloc(sizeof(struct special_t), max_specials)) == 0) {
6408                 NORM_ERR("failed to create specials array");
6409         }
6410
6411 #ifdef MAIL_FILE
6412         if (current_mail_spool == NULL) {
6413                 char buf[256];
6414
6415                 variable_substitute(MAIL_FILE, buf, 256);
6416
6417                 if (buf[0] != '\0') {
6418                         current_mail_spool = strndup(buf, text_buffer_size);
6419                 }
6420         }
6421 #endif
6422
6423         /* handle other command line arguments */
6424
6425 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) \
6426                 || defined(__NetBSD__)
6427         optind = optreset = 1;
6428 #else
6429         optind = 0;
6430 #endif
6431
6432 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
6433         if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
6434                         "kvm_open")) == NULL) {
6435                 CRIT_ERR(NULL, NULL, "cannot read kvm");
6436         }
6437 #endif
6438
6439         while (1) {
6440                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
6441
6442                 if (c == -1) {
6443                         break;
6444                 }
6445
6446                 switch (c) {
6447                         case 'd':
6448                                 fork_to_background = 1;
6449                                 break;
6450                         case 'D':
6451                                 global_debug_level++;
6452                                 break;
6453 #ifdef X11
6454                         case 'f':
6455                                 set_first_font(optarg);
6456                                 break;
6457                         case 'a':
6458                                 text_alignment = string_to_alignment(optarg);
6459                                 break;
6460
6461 #ifdef OWN_WINDOW
6462                         case 'o':
6463                                 own_window = 1;
6464                                 break;
6465 #endif
6466 #ifdef HAVE_XDBE
6467                         case 'b':
6468                                 use_xdbe = 1;
6469                                 break;
6470 #endif
6471 #endif /* X11 */
6472                         case 't':
6473                                 if (global_text) {
6474                                         free(global_text);
6475                                         global_text = 0;
6476                                 }
6477                                 global_text = strndup(optarg, max_user_text);
6478                                 convert_escapes(global_text);
6479                                 break;
6480
6481                         case 'u':
6482                                 update_interval = strtod(optarg, 0);
6483                                 update_interval_old = update_interval;
6484                                 if (info.music_player_interval == 0) {
6485                                         // default to update_interval
6486                                         info.music_player_interval = update_interval;
6487                                 }
6488                                 break;
6489
6490                         case 'i':
6491                                 total_run_times = strtod(optarg, 0);
6492                                 break;
6493 #ifdef X11
6494                         case 'x':
6495                                 gap_x = atoi(optarg);
6496                                 break;
6497
6498                         case 'y':
6499                                 gap_y = atoi(optarg);
6500                                 break;
6501 #endif /* X11 */
6502
6503                         case '?':
6504                                 exit(EXIT_FAILURE);
6505                 }
6506         }
6507
6508 #ifdef X11
6509         /* load font */
6510         if (output_methods & TO_X) {
6511                 load_config_file_x11(current_config);
6512         }
6513 #endif /* X11 */
6514
6515         /* generate text and get initial size */
6516         extract_variable_text(global_text);
6517         if (global_text) {
6518                 free(global_text);
6519                 global_text = 0;
6520         }
6521         global_text = NULL;
6522         /* fork */
6523         if (fork_to_background) {
6524                 int pid = fork();
6525
6526                 switch (pid) {
6527                         case -1:
6528                                 NORM_ERR(PACKAGE_NAME": couldn't fork() to background: %s",
6529                                         strerror(errno));
6530                                 break;
6531
6532                         case 0:
6533                                 /* child process */
6534                                 usleep(25000);
6535                                 fprintf(stderr, "\n");
6536                                 fflush(stderr);
6537                                 break;
6538
6539                         default:
6540                                 /* parent process */
6541                                 fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
6542                                         pid);
6543                                 fflush(stderr);
6544                                 exit(EXIT_SUCCESS);
6545                 }
6546         }
6547
6548         text_buffer = malloc(max_user_text);
6549         memset(text_buffer, 0, max_user_text);
6550         tmpstring1 = malloc(text_buffer_size);
6551         memset(tmpstring1, 0, text_buffer_size);
6552         tmpstring2 = malloc(text_buffer_size);
6553         memset(tmpstring2, 0, text_buffer_size);
6554
6555 #ifdef X11
6556         xargc = argc;
6557         xargv = argv;
6558         X11_create_window();
6559 #endif /* X11 */
6560 #ifdef HAVE_LUA
6561         llua_setup_info(&info, update_interval);
6562 #endif /* HAVE_LUA */
6563 #ifdef XOAP
6564         xmlInitParser();
6565 #endif /* XOAP */
6566
6567         /* Set signal handlers */
6568         act.sa_handler = signal_handler;
6569         sigemptyset(&act.sa_mask);
6570         act.sa_flags = 0;
6571 #ifdef SA_RESTART
6572         act.sa_flags |= SA_RESTART;
6573 #endif
6574
6575         if (            sigaction(SIGINT,  &act, &oact) < 0
6576                         ||      sigaction(SIGALRM, &act, &oact) < 0
6577                         ||      sigaction(SIGUSR1, &act, &oact) < 0
6578                         ||      sigaction(SIGHUP,  &act, &oact) < 0
6579                         ||      sigaction(SIGTERM, &act, &oact) < 0) {
6580                 NORM_ERR("error setting signal handler: %s", strerror(errno));
6581         }
6582
6583 #ifdef HAVE_LUA
6584         llua_startup_hook();
6585 #endif /* HAVE_LUA */
6586 }
6587
6588 int main(int argc, char **argv)
6589 {
6590 #ifdef X11
6591         char *s, *temp;
6592         unsigned int x;
6593 #endif
6594
6595         argc_copy = argc;
6596         argv_copy = argv;
6597         g_signal_pending = 0;
6598         max_user_text = MAX_USER_TEXT_DEFAULT;
6599         current_config = 0;
6600         memset(&info, 0, sizeof(info));
6601         memset(template, 0, sizeof(template));
6602         clear_net_stats();
6603
6604 #ifdef TCP_PORT_MONITOR
6605         /* set default connection limit */
6606         tcp_portmon_set_max_connections(0);
6607 #endif
6608
6609         /* handle command line parameters that don't change configs */
6610 #ifdef X11
6611         if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
6612                         || ((s = getenv("LANG")) && *s)) {
6613                 temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
6614                 if (temp == NULL) {
6615                         NORM_ERR("malloc failed");
6616                 }
6617                 for (x = 0; x < strlen(s); x++) {
6618                         temp[x] = tolower(s[x]);
6619                 }
6620                 temp[x] = 0;
6621                 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
6622                         utf8_mode = 1;
6623                 }
6624
6625                 free(temp);
6626         }
6627         if (!setlocale(LC_CTYPE, "")) {
6628                 NORM_ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
6629         }
6630 #endif /* X11 */
6631         while (1) {
6632                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
6633
6634                 if (c == -1) {
6635                         break;
6636                 }
6637
6638                 switch (c) {
6639                         case 'v':
6640                         case 'V':
6641                                 print_version();
6642                         case 'c':
6643                                 if (current_config) {
6644                                         free(current_config);
6645                                 }
6646                                 current_config = strndup(optarg, max_user_text);
6647                                 break;
6648                         case 'q':
6649                                 freopen("/dev/null", "w", stderr);
6650                                 break;
6651                         case 'h':
6652                                 print_help(argv[0]);
6653                                 return 0;
6654 #ifdef CONFIG_OUTPUT
6655                         case 'C':
6656                                 print_defconfig();
6657                                 return 0;
6658 #endif
6659 #ifdef X11
6660                         case 'w':
6661                                 window.window = strtol(optarg, 0, 0);
6662                                 break;
6663                         case 'X':
6664                                 if (disp)
6665                                         free(disp);
6666                                 disp = strdup(optarg);
6667                                 break;
6668 #endif /* X11 */
6669
6670                         case '?':
6671                                 exit(EXIT_FAILURE);
6672                 }
6673         }
6674
6675         /* check if specified config file is valid */
6676         if (current_config) {
6677                 struct stat sb;
6678                 if (stat(current_config, &sb) ||
6679                                 (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
6680                         NORM_ERR("invalid configuration file '%s'\n", current_config);
6681                         free(current_config);
6682                         current_config = 0;
6683                 }
6684         }
6685
6686         /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
6687
6688         if (!current_config) {
6689                 /* load default config file */
6690                 char buf[DEFAULT_TEXT_BUFFER_SIZE];
6691                 FILE *fp;
6692
6693                 /* Try to use personal config file first */
6694                 to_real_path(buf, CONFIG_FILE);
6695                 if (buf[0] && (fp = fopen(buf, "r"))) {
6696                         current_config = strndup(buf, max_user_text);
6697                         fclose(fp);
6698                 }
6699
6700                 /* Try to use system config file if personal config not readable */
6701                 if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
6702                         current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
6703                         fclose(fp);
6704                 }
6705
6706                 /* No readable config found */
6707                 if (!current_config) {
6708 #ifdef CONFIG_OUTPUT
6709                         current_config = strdup("==builtin==");
6710                         NORM_ERR("no readable personal or system-wide config file found,"
6711                                         " using builtin default");
6712 #else
6713                         CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
6714 #endif /* ! CONF_OUTPUT */
6715                 }
6716         }
6717
6718 #ifdef XOAP
6719         /* Load xoap keys, if existing */
6720         load_xoap_keys();
6721 #endif /* XOAP */
6722
6723 #ifdef HAVE_SYS_INOTIFY_H
6724         inotify_fd = inotify_init();
6725 #endif /* HAVE_SYS_INOTIFY_H */
6726
6727         initialisation(argc, argv);
6728
6729         main_loop();
6730
6731 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
6732         kvm_close(kd);
6733 #endif
6734
6735         return 0;
6736
6737 }
6738
6739 void alarm_handler(void) {
6740         if(childpid > 0) {
6741                 kill(childpid, SIGTERM);
6742         }
6743 }
6744
6745 static void signal_handler(int sig)
6746 {
6747         /* signal handler is light as a feather, as it should be.
6748          * we will poll g_signal_pending with each loop of conky
6749          * and do any signal processing there, NOT here (except 
6750          * SIGALRM because this is caused when conky is hanging) */
6751         if(sig == SIGALRM) {
6752                 alarm_handler();
6753         } else {
6754                 g_signal_pending = sig;
6755         }
6756 }