Exit properly when forking.
[monky] / src / conky.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Any original torsmo code is licensed under the BSD license
4  *
5  * All code written since the fork of torsmo is licensed under the GPL
6  *
7  * Please see COPYING for details
8  *
9  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
10  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
11  *      (see AUTHORS)
12  * All rights reserved.
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * You should have received a copy of the GNU General Public License
24  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27
28 #include "config.h"
29 #include "text_object.h"
30 #include "conky.h"
31 #include "common.h"
32 #include <stdarg.h>
33 #include <math.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <locale.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <limits.h>
40 #if HAVE_DIRENT_H
41 #include <dirent.h>
42 #endif
43 #include <sys/time.h>
44 #include <sys/param.h>
45 #ifdef HAVE_SYS_INOTIFY_H
46 #include <sys/inotify.h>
47 #endif /* HAVE_SYS_INOTIFY_H */
48 #ifdef X11
49 #include "x11.h"
50 #include <X11/Xutil.h>
51 #ifdef HAVE_XDAMAGE
52 #include <X11/extensions/Xdamage.h>
53 #endif
54 #ifdef IMLIB2
55 #include "imlib2.h"
56 #endif /* IMLIB2 */
57 #endif /* X11 */
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <netinet/in.h>
61 #include <netdb.h>
62 #include <fcntl.h>
63 #include <getopt.h>
64
65 /* local headers */
66 #include "algebra.h"
67 #include "build.h"
68 #include "colours.h"
69 #include "diskio.h"
70 #ifdef X11
71 #include "fonts.h"
72 #endif
73 #include "fs.h"
74 #include "logging.h"
75 #include "mixer.h"
76 #include "mail.h"
77 #include "mboxscan.h"
78 #include "specials.h"
79 #include "temphelper.h"
80 #include "tailhead.h"
81 #include "top.h"
82
83 /* check for OS and include appropriate headers */
84 #if defined(__linux__)
85 #include "linux.h"
86 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
87 #include "freebsd.h"
88 #elif defined(__OpenBSD__)
89 #include "openbsd.h"
90 #endif
91
92 #if defined(__FreeBSD_kernel__)
93 #include <bsd/bsd.h>
94 #endif
95
96 /* FIXME: apm_getinfo is unused here. maybe it's meant for common.c */
97 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
98                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
99 int apm_getinfo(int fd, apm_info_t aip);
100 char *get_apm_adapter(void);
101 char *get_apm_battery_life(void);
102 char *get_apm_battery_time(void);
103 #endif
104
105 #ifdef HAVE_ICONV
106 #include <iconv.h>
107 #endif
108
109 #ifdef CONFIG_OUTPUT
110 #include "defconfig.h"
111 #include "conf_cookie.h"
112 #endif
113
114 #ifndef S_ISSOCK
115 #define S_ISSOCK(x)   ((x & S_IFMT) == S_IFSOCK)
116 #endif
117
118 #define MAIL_FILE "$MAIL"
119 #define MAX_IF_BLOCK_DEPTH 5
120
121 //#define SIGNAL_BLOCKING
122 #undef SIGNAL_BLOCKING
123
124 /* debugging level, used by logging.h */
125 int global_debug_level = 0;
126
127 /* two strings for internal use */
128 static char *tmpstring1, *tmpstring2;
129
130 /* variables holding various config settings */
131 int short_units;
132 int format_human_readable;
133 int cpu_separate;
134 enum {
135         NO_SPACER = 0,
136         LEFT_SPACER,
137         RIGHT_SPACER
138 } use_spacer;
139 int top_cpu, top_mem, top_time;
140 #ifdef IOSTATS
141 int top_io;
142 #endif
143 static unsigned int top_name_width = 15;
144 int output_methods;
145 enum x_initialiser_state x_initialised = NO;
146 static volatile int g_signal_pending;
147 /* Update interval */
148 double update_interval;
149 void *global_cpu = NULL;
150
151 int argc_copy;
152 char** argv_copy;
153
154 /* prototypes for internally used functions */
155 static void signal_handler(int);
156 static void print_version(void) __attribute__((noreturn));
157 static void reload_config(void);
158 static void generate_text_internal(char *, int, struct text_object,
159                                    struct information *);
160 static int extract_variable_text_internal(struct text_object *,
161                                           const char *, char);
162
163 static void print_version(void)
164 {
165         printf(PACKAGE_NAME" "VERSION" compiled "BUILD_DATE" for "BUILD_ARCH"\n");
166
167         printf("\nCompiled in features:\n\n"
168                    "System config file: "SYSTEM_CONFIG_FILE"\n"
169                    "Package library path: "PACKAGE_LIBDIR"\n\n"
170 #ifdef X11
171                    " X11:\n"
172 # ifdef HAVE_XDAMAGE
173                    "  * Xdamage extension\n"
174 # endif /* HAVE_XDAMAGE */
175 # ifdef HAVE_XDBE
176                    "  * XDBE (double buffer extension)\n"
177 # endif /* HAVE_XDBE */
178 # ifdef XFT
179                    "  * Xft\n"
180 # endif /* XFT */
181 #endif /* X11 */
182                    "\n Music detection:\n"
183 #ifdef AUDACIOUS
184                    "  * Audacious\n"
185 #endif /* AUDACIOUS */
186 #ifdef BMPX
187                    "  * BMPx\n"
188 #endif /* BMPX */
189 #ifdef MPD
190                    "  * MPD\n"
191 #endif /* MPD */
192 #ifdef MOC
193                    "  * MOC\n"
194 #endif /* MOC */
195 #ifdef XMMS2
196                    "  * XMMS2\n"
197 #endif /* XMMS2 */
198                    "\n General:\n"
199 #ifdef HAVE_OPENMP
200                    "  * OpenMP\n"
201 #endif /* HAVE_OPENMP */
202 #ifdef MATH
203                    "  * math\n"
204 #endif /* Math */
205 #ifdef HDDTEMP
206                    "  * hddtemp\n"
207 #endif /* HDDTEMP */
208 #ifdef TCP_PORT_MONITOR
209                    "  * portmon\n"
210 #endif /* TCP_PORT_MONITOR */
211 #ifdef RSS
212                    "  * RSS\n"
213 #endif /* RSS */
214 #ifdef WEATHER
215                    "  * Weather (NOAA)\n"
216 #ifdef XOAP
217                    "  * Weather (XOAP)\n"
218 #endif /* XOAP */
219 #endif /* WEATHER */
220 #ifdef HAVE_IWLIB
221                    "  * wireless\n"
222 #endif /* HAVE_IWLIB */
223 #ifdef IBM
224                    "  * support for IBM/Lenovo notebooks\n"
225 #endif /* IBM */
226 #ifdef NVIDIA
227                    "  * nvidia\n"
228 #endif /* NVIDIA */
229 #ifdef EVE
230                    "  * eve-online\n"
231 #endif /* EVE */
232 #ifdef CONFIG_OUTPUT
233                    "  * config-output\n"
234 #endif /* CONFIG_OUTPUT */
235 #ifdef IMLIB2
236                    "  * Imlib2\n"
237 #endif /* IMLIB2 */
238 #ifdef MIXER_IS_ALSA
239                    "  * ALSA mixer support\n"
240 #endif /* MIXER_IS_ALSA */
241 #ifdef APCUPSD
242                    "  * apcupsd\n"
243 #endif /* APCUPSD */
244 #ifdef IOSTATS
245                    "  * iostats\n"
246 #endif /* IOSTATS */
247 #ifdef HAVE_LUA
248                    "  * Lua\n"
249                    "\n  Lua bindings:\n"
250 #ifdef HAVE_LUA_CAIRO
251                    "   * Cairo\n"
252 #endif /* HAVE_LUA_CAIRO */
253 #ifdef HAVE_LUA_IMLIB2
254                    "   * Imlib2\n"
255 #endif /* IMLIB2 */
256 #endif /* HAVE_LUA */
257         );
258
259         exit(0);
260 }
261
262 static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
263
264
265 #ifdef X11
266
267 static void X11_create_window(void);
268 static void X11_initialisation(void);
269
270 struct _x11_stuff_s {
271         Region region;
272 #ifdef HAVE_XDAMAGE
273         Damage damage;
274         XserverRegion region2, part;
275         int event_base, error_base;
276 #endif
277 } x11_stuff;
278
279 /* text size */
280
281 static int text_start_x, text_start_y;  /* text start position in window */
282 static int text_width, text_height;
283
284 /* alignments */
285 enum alignment {
286         TOP_LEFT = 1,
287         TOP_RIGHT,
288         TOP_MIDDLE,
289         BOTTOM_LEFT,
290         BOTTOM_RIGHT,
291         BOTTOM_MIDDLE,
292         MIDDLE_LEFT,
293         MIDDLE_RIGHT,
294         NONE
295 };
296
297 /* display to connect to */
298 static char *disp = NULL;
299
300 #endif /* X11 */
301
302 /* struct that has all info to be shared between
303  * instances of the same text object */
304 struct information info;
305
306 /* path to config file */
307 char *current_config;
308
309 /* set to 1 if you want all text to be in uppercase */
310 static unsigned int stuff_in_uppercase;
311
312 /* Run how many times? */
313 static unsigned long total_run_times;
314
315 /* fork? */
316 static int fork_to_background;
317
318 static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
319
320 /* filenames for output */
321 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
322 char *append_file = NULL; FILE *append_fpointer = NULL;
323
324 /* xoap suffix for weather from weather.com */
325 #ifdef WEATHER
326 static char *xoap = NULL;
327 #endif /* WEATHER */
328
329 #ifdef X11
330
331 static int show_graph_scale;
332 static int show_graph_range;
333
334 /* Position on the screen */
335 static int text_alignment;
336 static int gap_x, gap_y;
337
338 /* border */
339 static int draw_borders;
340 static int draw_graph_borders;
341 static int stippled_borders;
342
343 static int draw_shades, draw_outline;
344
345 static long default_fg_color, default_bg_color, default_out_color;
346
347 /* create own window or draw stuff to root? */
348 static int set_transparent = 0;
349
350 #ifdef OWN_WINDOW
351 static int own_window = 0;
352 static int background_colour = 0;
353
354 /* fixed size/pos is set if wm/user changes them */
355 static int fixed_size = 0, fixed_pos = 0;
356 #endif
357
358 static int minimum_width, minimum_height;
359 static int maximum_width;
360
361 #endif /* X11 */
362
363 #ifdef __OpenBSD__
364 static int sensor_device;
365 #endif
366
367 static long color0, color1, color2, color3, color4, color5, color6, color7,
368         color8, color9;
369
370 #define MAX_TEMPLATES 10
371 static char *template[MAX_TEMPLATES];
372
373 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
374 unsigned int max_user_text;
375
376 /* maximum size of individual text buffers, ie $exec buffer size */
377 unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
378
379 #ifdef HAVE_ICONV
380 #define CODEPAGE_LENGTH 20
381 long iconv_selected;
382 long iconv_count = 0;
383 char iconv_converting;
384 static iconv_t **iconv_cd = 0;
385
386 int register_iconv(iconv_t *new_iconv)
387 {
388         iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1));
389         if (!iconv_cd) {
390                 CRIT_ERR(NULL, NULL, "Out of memory");
391         }
392         iconv_cd[iconv_count] = malloc(sizeof(iconv_t));
393         if (!iconv_cd[iconv_count]) {
394                 CRIT_ERR(NULL, NULL, "Out of memory");
395         }
396         memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t));
397         iconv_count++;
398         return iconv_count;
399 }
400
401 void free_iconv(void)
402 {
403         if (iconv_cd) {
404                 long i;
405
406                 for (i = 0; i < iconv_count; i++) {
407                         if (iconv_cd[i]) {
408                                 iconv_close(*iconv_cd[i]);
409                                 free(iconv_cd[i]);
410                         }
411                 }
412                 free(iconv_cd);
413         }
414         iconv_cd = 0;
415 }
416
417 #endif
418
419 /* UTF-8 */
420 int utf8_mode = 0;
421
422 /* no buffers in used memory? */
423 int no_buffers;
424
425 /* pad percentages to decimals? */
426 static int pad_percents = 0;
427
428 static char *global_text = 0;
429 long global_text_lines;
430
431 static int total_updates;
432 static int updatereset;
433
434 int check_contains(char *f, char *s)
435 {
436         int ret = 0;
437         FILE *where = open_file(f, 0);
438
439         if (where) {
440                 char buf1[256];
441
442                 while (fgets(buf1, 256, where)) {
443                         if (strstr(buf1, s)) {
444                                 ret = 1;
445                                 break;
446                         }
447                 }
448                 fclose(where);
449         } else {
450                 ERR("Could not open the file");
451         }
452         return ret;
453 }
454
455 #ifdef X11
456
457 #define SECRIT_MULTILINE_CHAR '\x02'
458
459 static inline int calc_text_width(const char *s, int l)
460 {
461         if ((output_methods & TO_X) == 0) {
462                 return 0;
463         }
464 #ifdef XFT
465         if (use_xft) {
466                 XGlyphInfo gi;
467
468                 if (utf8_mode) {
469                         XftTextExtentsUtf8(display, fonts[selected_font].xftfont,
470                                 (const FcChar8 *) s, l, &gi);
471                 } else {
472                         XftTextExtents8(display, fonts[selected_font].xftfont,
473                                 (const FcChar8 *) s, l, &gi);
474                 }
475                 return gi.xOff;
476         } else
477 #endif
478         {
479                 return XTextWidth(fonts[selected_font].font, s, l);
480         }
481 }
482 #endif /* X11 */
483
484 /* formatted text to render on screen, generated in generate_text(),
485  * drawn in draw_stuff() */
486
487 static char *text_buffer;
488
489 /* quite boring functions */
490
491 static inline void for_each_line(char *b, int f(char *, int))
492 {
493         char *ps, *pe;
494         int special_index = 0; /* specials index */
495
496         for (ps = b, pe = b; *pe; pe++) {
497                 if (*pe == '\n') {
498                         *pe = '\0';
499                         special_index = f(ps, special_index);
500                         *pe = '\n';
501                         ps = pe + 1;
502                 }
503         }
504
505         if (ps < pe) {
506                 f(ps, special_index);
507         }
508 }
509
510 static void convert_escapes(char *buf)
511 {
512         char *p = buf, *s = buf;
513
514         while (*s) {
515                 if (*s == '\\') {
516                         s++;
517                         if (*s == 'n') {
518                                 *p++ = '\n';
519                         } else if (*s == '\\') {
520                                 *p++ = '\\';
521                         }
522                         s++;
523                 } else {
524                         *p++ = *s++;
525                 }
526         }
527         *p = '\0';
528 }
529
530 /* Prints anything normally printed with snprintf according to the current value
531  * of use_spacer.  Actually slightly more flexible than snprintf, as you can
532  * safely specify the destination buffer as one of your inputs.  */
533 int spaced_print(char *buf, int size, const char *format, int width, ...)
534 {
535         int len = 0;
536         va_list argp;
537         char *tempbuf;
538
539         if (size < 1) {
540                 return 0;
541         }
542         tempbuf = malloc(size * sizeof(char));
543
544         // Passes the varargs along to vsnprintf
545         va_start(argp, width);
546         vsnprintf(tempbuf, size, format, argp);
547         va_end(argp);
548
549         switch (use_spacer) {
550                 case NO_SPACER:
551                         len = snprintf(buf, size, "%s", tempbuf);
552                         break;
553                 case LEFT_SPACER:
554                         len = snprintf(buf, size, "%*s", width, tempbuf);
555                         break;
556                 case RIGHT_SPACER:
557                         len = snprintf(buf, size, "%-*s", width, tempbuf);
558                         break;
559         }
560         free(tempbuf);
561         return len;
562 }
563
564 /* print percentage values
565  *
566  * - i.e., unsigned values between 0 and 100
567  * - respect the value of pad_percents */
568 static int percent_print(char *buf, int size, unsigned value)
569 {
570         return spaced_print(buf, size, "%u", pad_percents, value);
571 }
572
573 /* converts from bytes to human readable format (K, M, G, T)
574  *
575  * The algorithm always divides by 1024, as unit-conversion of byte
576  * counts suggests. But for output length determination we need to
577  * compare with 1000 here, as we print in decimal form. */
578 static void human_readable(long long num, char *buf, int size)
579 {
580         const char **suffix = suffixes;
581         float fnum;
582         int precision;
583         int width;
584         const char *format;
585
586         /* Possibly just output as usual, for example for stdout usage */
587         if (!format_human_readable) {
588                 spaced_print(buf, size, "%d", 6, round_to_int(num));
589                 return;
590         }
591         if (short_units) {
592                 width = 5;
593                 format = "%.*f%.1s";
594         } else {
595                 width = 7;
596                 format = "%.*f%-3s";
597         }
598
599         if (llabs(num) < 1000LL) {
600                 spaced_print(buf, size, format, width, 0, (float)num, *suffix);
601                 return;
602         }
603
604         while (llabs(num / 1024) >= 1000LL && **(suffix + 2)) {
605                 num /= 1024;
606                 suffix++;
607         }
608
609         suffix++;
610         fnum = num / 1024.0;
611
612         /* fnum should now be < 1000, so looks like 'AAA.BBBBB'
613          *
614          * The goal is to always have a significance of 3, by
615          * adjusting the decimal part of the number. Sample output:
616          *  123MiB
617          * 23.4GiB
618          * 5.12B   
619          * so the point of alignment resides between number and unit. The
620          * upside of this is that there is minimal padding necessary, though
621          * there should be a way to make alignment take place at the decimal
622          * dot (then with fixed width decimal part). 
623          *
624          * Note the repdigits below: when given a precision value, printf()
625          * rounds the float to it, not just cuts off the remaining digits. So
626          * e.g. 99.95 with a precision of 1 gets 100.0, which again should be
627          * printed with a precision of 0. Yay. */
628
629         precision = 0;          /* print 100-999 without decimal part */
630         if (fnum < 99.95)
631                 precision = 1;  /* print 10-99 with one decimal place */
632         if (fnum < 9.995)
633                 precision = 2;  /* print 0-9 with two decimal places */
634
635         spaced_print(buf, size, format, width, precision, fnum, *suffix);
636 }
637
638 /* global object list root element */
639 static struct text_object global_root_object;
640
641 static inline void read_exec(const char *data, char *buf, const int size)
642 {
643         FILE *fp = popen(data, "r");
644         int length = fread(buf, 1, size, fp);
645
646         pclose(fp);
647         buf[length] = '\0';
648         if (length > 0 && buf[length - 1] == '\n') {
649                 buf[length - 1] = '\0';
650         }
651 }
652
653 void *threaded_exec(void *) __attribute__((noreturn));
654
655 void *threaded_exec(void *arg)
656 {
657         char *buff, *p2;
658         struct text_object *obj = (struct text_object *)arg;
659
660         while (1) {
661                 buff = malloc(text_buffer_size);
662                 read_exec(obj->data.texeci.cmd, buff,
663                         text_buffer_size);
664                 p2 = buff;
665                 while (*p2) {
666                         if (*p2 == '\001') {
667                                 *p2 = ' ';
668                         }
669                         p2++;
670                 }
671                 timed_thread_lock(obj->data.texeci.p_timed_thread);
672                 strncpy(obj->data.texeci.buffer, buff, text_buffer_size);
673                 timed_thread_unlock(obj->data.texeci.p_timed_thread);
674                 free(buff);
675                 if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) {
676                         timed_thread_exit(obj->data.texeci.p_timed_thread);
677                 }
678         }
679         /* never reached */
680 }
681
682 static struct text_object *new_text_object_internal(void)
683 {
684         struct text_object *obj = malloc(sizeof(struct text_object));
685         memset(obj, 0, sizeof(struct text_object));
686         return obj;
687 }
688
689 /*
690  * Frees the list of text objects root points to.  When internal = 1, it won't
691  * free global objects.
692  */
693 static void free_text_objects(struct text_object *root, int internal)
694 {
695         struct text_object *obj;
696
697         if (!root->prev) {
698                 return;
699         }
700
701 #define data obj->data
702         for (obj = root->prev; obj; obj = root->prev) {
703                 root->prev = obj->prev;
704                 switch (obj->type) {
705 #ifndef __OpenBSD__
706                         case OBJ_acpitemp:
707                                 close(data.i);
708                                 break;
709 #endif /* !__OpenBSD__ */
710 #ifdef __linux__
711                         case OBJ_i2c:
712                         case OBJ_platform:
713                         case OBJ_hwmon:
714                                 close(data.sysfs.fd);
715                                 break;
716 #endif /* __linux__ */
717                         case OBJ_read_tcp:
718                                 free(data.read_tcp.host);
719                                 break;
720                         case OBJ_time:
721                         case OBJ_utime:
722                                 free(data.s);
723                                 break;
724                         case OBJ_tztime:
725                                 free(data.tztime.tz);
726                                 free(data.tztime.fmt);
727                                 break;
728                         case OBJ_mboxscan:
729                                 free(data.mboxscan.args);
730                                 free(data.mboxscan.output);
731                                 break;
732                         case OBJ_mails:
733                         case OBJ_new_mails:
734                         case OBJ_seen_mails:
735                         case OBJ_unseen_mails:
736                         case OBJ_flagged_mails:
737                         case OBJ_unflagged_mails:
738                         case OBJ_forwarded_mails:
739                         case OBJ_unforwarded_mails:
740                         case OBJ_replied_mails:
741                         case OBJ_unreplied_mails:
742                         case OBJ_draft_mails:
743                         case OBJ_trashed_mails:
744                                 free(data.local_mail.box);
745                                 break;
746                         case OBJ_imap_unseen:
747                                 if (!obj->char_b) {
748                                         free(data.mail);
749                                 }
750                                 break;
751                         case OBJ_imap_messages:
752                                 if (!obj->char_b) {
753                                         free(data.mail);
754                                 }
755                                 break;
756                         case OBJ_pop3_unseen:
757                                 if (!obj->char_b) {
758                                         free(data.mail);
759                                 }
760                                 break;
761                         case OBJ_pop3_used:
762                                 if (!obj->char_b) {
763                                         free(data.mail);
764                                 }
765                                 break;
766                         case OBJ_if_empty:
767                         case OBJ_if_match:
768                                 free_text_objects(obj->sub, 1);
769                                 free(obj->sub);
770                                 /* fall through */
771                         case OBJ_if_existing:
772                         case OBJ_if_mounted:
773                         case OBJ_if_running:
774                                 free(data.ifblock.s);
775                                 free(data.ifblock.str);
776                                 break;
777                         case OBJ_tail:
778                                 free(data.tail.logfile);
779                                 free(data.tail.buffer);
780                                 break;
781                         case OBJ_text:
782                         case OBJ_font:
783                         case OBJ_image:
784                         case OBJ_eval:
785                         case OBJ_exec:
786                         case OBJ_execbar:
787 #ifdef X11
788                         case OBJ_execgauge:
789                         case OBJ_execgraph:
790 #endif
791                         case OBJ_execp:
792                                 free(data.s);
793                                 break;
794 #ifdef HAVE_ICONV
795                         case OBJ_iconv_start:
796                                 free_iconv();
797                                 break;
798 #endif
799 #ifdef __linux__
800                         case OBJ_disk_protect:
801                                 free(data.s);
802                                 break;
803                         case OBJ_if_gw:
804                                 free(data.ifblock.s);
805                                 free(data.ifblock.str);
806                         case OBJ_gw_iface:
807                         case OBJ_gw_ip:
808                                 if (info.gw_info.iface) {
809                                         free(info.gw_info.iface);
810                                         info.gw_info.iface = 0;
811                                 }
812                                 if (info.gw_info.ip) {
813                                         free(info.gw_info.ip);
814                                         info.gw_info.ip = 0;
815                                 }
816                                 break;
817                         case OBJ_ioscheduler:
818                                 if(data.s)
819                                         free(data.s);
820                                 break;
821 #endif
822 #if (defined(__FreeBSD__) || defined(__linux__))
823                         case OBJ_if_up:
824                                 free(data.ifblock.s);
825                                 free(data.ifblock.str);
826                                 break;
827 #endif
828 #ifdef XMMS2
829                         case OBJ_xmms2_artist:
830                                 if (info.xmms2.artist) {
831                                         free(info.xmms2.artist);
832                                         info.xmms2.artist = 0;
833                                 }
834                                 break;
835                         case OBJ_xmms2_album:
836                                 if (info.xmms2.album) {
837                                         free(info.xmms2.album);
838                                         info.xmms2.album = 0;
839                                 }
840                                 break;
841                         case OBJ_xmms2_title:
842                                 if (info.xmms2.title) {
843                                         free(info.xmms2.title);
844                                         info.xmms2.title = 0;
845                                 }
846                                 break;
847                         case OBJ_xmms2_genre:
848                                 if (info.xmms2.genre) {
849                                         free(info.xmms2.genre);
850                                         info.xmms2.genre = 0;
851                                 }
852                                 break;
853                         case OBJ_xmms2_comment:
854                                 if (info.xmms2.comment) {
855                                         free(info.xmms2.comment);
856                                         info.xmms2.comment = 0;
857                                 }
858                                 break;
859                         case OBJ_xmms2_url:
860                                 if (info.xmms2.url) {
861                                         free(info.xmms2.url);
862                                         info.xmms2.url = 0;
863                                 }
864                                 break;
865                         case OBJ_xmms2_date:
866                                 if (info.xmms2.date) {
867                                         free(info.xmms2.date);
868                                         info.xmms2.date = 0;
869                                 }
870                                 break;
871                         case OBJ_xmms2_status:
872                                 if (info.xmms2.status) {
873                                         free(info.xmms2.status);
874                                         info.xmms2.status = 0;
875                                 }
876                                 break;
877                         case OBJ_xmms2_playlist:
878                                 if (info.xmms2.playlist) {
879                                         free(info.xmms2.playlist);
880                                         info.xmms2.playlist = 0;
881                                 }
882                                 break;
883                         case OBJ_xmms2_smart:
884                                 if (info.xmms2.artist) {
885                                         free(info.xmms2.artist);
886                                         info.xmms2.artist = 0;
887                                 }
888                                 if (info.xmms2.title) {
889                                         free(info.xmms2.title);
890                                         info.xmms2.title = 0;
891                                 }
892                                 if (info.xmms2.url) {
893                                         free(info.xmms2.url);
894                                         info.xmms2.url = 0;
895                                 }
896                                 break;
897 #endif
898 #ifdef BMPX
899                         case OBJ_bmpx_title:
900                         case OBJ_bmpx_artist:
901                         case OBJ_bmpx_album:
902                         case OBJ_bmpx_track:
903                         case OBJ_bmpx_uri:
904                         case OBJ_bmpx_bitrate:
905                                 break;
906 #endif
907 #ifdef EVE
908                         case OBJ_eve:
909                                 break;
910 #endif
911 #ifdef RSS
912                         case OBJ_rss:
913                                 free(data.rss.uri);
914                                 free(data.rss.action);
915                                 break;
916 #endif
917 #ifdef WEATHER
918                         case OBJ_weather:
919                                 free(data.weather.uri);
920                                 free(data.weather.data_type);
921                                 break;
922 #endif
923 #ifdef HAVE_LUA
924                         case OBJ_lua:
925                         case OBJ_lua_bar:
926 #ifdef X11
927                         case OBJ_lua_graph:
928                         case OBJ_lua_gauge:
929 #endif /* X11 */
930                                 free(data.s);
931                                 break;
932 #endif /* HAVE_LUA */
933                         case OBJ_pre_exec:
934                                 break;
935 #ifndef __OpenBSD__
936                         case OBJ_battery:
937                                 free(data.s);
938                                 break;
939                         case OBJ_battery_short:
940                                 free(data.s);
941                                 break;
942                         case OBJ_battery_time:
943                                 free(data.s);
944                                 break;
945 #endif /* !__OpenBSD__ */
946                         case OBJ_execpi:
947                         case OBJ_execi:
948                         case OBJ_execibar:
949 #ifdef X11
950                         case OBJ_execigraph:
951                         case OBJ_execigauge:
952 #endif /* X11 */
953                                 free(data.execi.cmd);
954                                 free(data.execi.buffer);
955                                 break;
956                         case OBJ_texeci:
957                                 free(data.texeci.cmd);
958                                 free(data.texeci.buffer);
959                                 break;
960                         case OBJ_nameserver:
961                                 free_dns_data();
962                                 break;
963                         case OBJ_top:
964                         case OBJ_top_mem:
965                         case OBJ_top_time:
966 #ifdef IOSTATS
967                         case OBJ_top_io:
968 #endif
969                                 if (info.first_process && !internal) {
970                                         free_all_processes();
971                                         info.first_process = NULL;
972                                 }
973                                 if (data.top.s) free(data.top.s);
974                                 break;
975 #ifdef HDDTEMP
976                         case OBJ_hddtemp:
977                                 free(data.hddtemp.dev);
978                                 free(data.hddtemp.addr);
979                                 if (data.hddtemp.temp)
980                                         free(data.hddtemp.temp);
981                                 break;
982 #endif /* HDDTEMP */
983                         case OBJ_entropy_avail:
984                         case OBJ_entropy_perc:
985                         case OBJ_entropy_poolsize:
986                         case OBJ_entropy_bar:
987                                 break;
988                         case OBJ_user_names:
989                                 if (info.users.names) {
990                                         free(info.users.names);
991                                         info.users.names = 0;
992                                 }
993                                 break;
994                         case OBJ_user_terms:
995                                 if (info.users.terms) {
996                                         free(info.users.terms);
997                                         info.users.terms = 0;
998                                 }
999                                 break;
1000                         case OBJ_user_times:
1001                                 if (info.users.times) {
1002                                         free(info.users.times);
1003                                         info.users.times = 0;
1004                                 }
1005                                 break;
1006 #ifdef IBM
1007                         case OBJ_smapi:
1008                         case OBJ_smapi_bat_perc:
1009                         case OBJ_smapi_bat_temp:
1010                         case OBJ_smapi_bat_power:
1011                                 free(data.s);
1012                                 break;
1013                         case OBJ_if_smapi_bat_installed:
1014                                 free(data.ifblock.s);
1015                                 free(data.ifblock.str);
1016                                 break;
1017 #endif /* IBM */
1018 #ifdef NVIDIA
1019                         case OBJ_nvidia:
1020                                 break;
1021 #endif /* NVIDIA */
1022 #ifdef MPD
1023                         case OBJ_mpd_title:
1024                         case OBJ_mpd_artist:
1025                         case OBJ_mpd_album:
1026                         case OBJ_mpd_random:
1027                         case OBJ_mpd_repeat:
1028                         case OBJ_mpd_vol:
1029                         case OBJ_mpd_bitrate:
1030                         case OBJ_mpd_status:
1031                         case OBJ_mpd_bar:
1032                         case OBJ_mpd_elapsed:
1033                         case OBJ_mpd_length:
1034                         case OBJ_mpd_track:
1035                         case OBJ_mpd_name:
1036                         case OBJ_mpd_file:
1037                         case OBJ_mpd_percent:
1038                         case OBJ_mpd_smart:
1039                         case OBJ_if_mpd_playing:
1040                                 free_mpd();
1041                                 break;
1042 #endif /* MPD */
1043 #ifdef MOC
1044                         case OBJ_moc_state:
1045                         case OBJ_moc_file:
1046                         case OBJ_moc_title:
1047                         case OBJ_moc_artist:
1048                         case OBJ_moc_song:
1049                         case OBJ_moc_album:
1050                         case OBJ_moc_totaltime:
1051                         case OBJ_moc_timeleft:
1052                         case OBJ_moc_curtime:
1053                         case OBJ_moc_bitrate:
1054                         case OBJ_moc_rate:
1055                                 free_moc();
1056                                 break;
1057 #endif /* MOC */
1058                         case OBJ_blink:
1059                         case OBJ_to_bytes:
1060                                 free_text_objects(obj->sub, 1);
1061                                 free(obj->sub);
1062                                 break;
1063                         case OBJ_scroll:
1064                                 free(data.scroll.text);
1065                                 free_text_objects(obj->sub, 1);
1066                                 free(obj->sub);
1067                                 break;
1068                         case OBJ_combine:
1069                                 free(data.combine.left);
1070                                 free(data.combine.seperation);
1071                                 free(data.combine.right);
1072                                 free_text_objects(obj->sub, 1);
1073                                 free(obj->sub);
1074                                 break;
1075 #ifdef APCUPSD
1076                         case OBJ_apcupsd:
1077                         case OBJ_apcupsd_name:
1078                         case OBJ_apcupsd_model:
1079                         case OBJ_apcupsd_upsmode:
1080                         case OBJ_apcupsd_cable:
1081                         case OBJ_apcupsd_status:
1082                         case OBJ_apcupsd_linev:
1083                         case OBJ_apcupsd_load:
1084                         case OBJ_apcupsd_loadbar:
1085 #ifdef X11
1086                         case OBJ_apcupsd_loadgraph:
1087                         case OBJ_apcupsd_loadgauge:
1088 #endif /* X11 */
1089                         case OBJ_apcupsd_charge:
1090                         case OBJ_apcupsd_timeleft:
1091                         case OBJ_apcupsd_temp:
1092                         case OBJ_apcupsd_lastxfer:
1093                                 break;
1094 #endif /* APCUPSD */
1095 #ifdef X11
1096                         case OBJ_desktop:
1097                         case OBJ_desktop_number:
1098                         case OBJ_desktop_name:
1099                                 if(info.x11.desktop.name) {
1100                                   free(info.x11.desktop.name);
1101                                   info.x11.desktop.name = NULL;
1102                                 }
1103                                 if(info.x11.desktop.all_names) {
1104                                   free(info.x11.desktop.all_names);
1105                                   info.x11.desktop.all_names = NULL;
1106                                 }
1107                                 break;
1108 #endif /* X11 */
1109                 }
1110                 free(obj);
1111         }
1112 #undef data
1113 }
1114
1115 #ifdef X11
1116 void scan_mixer_bar(const char *arg, int *a, int *w, int *h)
1117 {
1118         char buf1[64];
1119         int n;
1120
1121         if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
1122                 *a = mixer_init(buf1);
1123                 scan_bar(arg + n, w, h);
1124         } else {
1125                 *a = mixer_init(NULL);
1126                 scan_bar(arg, w, h);
1127         }
1128 }
1129 #endif /* X11 */
1130
1131 /* strip a leading /dev/ if any, following symlinks first
1132  *
1133  * BEWARE: this function returns a pointer to static content
1134  *         which gets overwritten in consecutive calls. I.e.:
1135  *         this function is NOT reentrant.
1136  */
1137 static const char *dev_name(const char *path)
1138 {
1139         static char buf[255];   /* should be enough for pathnames */
1140         ssize_t buflen;
1141
1142         if (!path)
1143                 return NULL;
1144
1145 #define DEV_NAME(x) \
1146   x != NULL && strlen(x) > 5 && strncmp(x, "/dev/", 5) == 0 ? x + 5 : x
1147         if ((buflen = readlink(path, buf, 254)) == -1)
1148                 return DEV_NAME(path);
1149         buf[buflen] = '\0';
1150         return DEV_NAME(buf);
1151 #undef DEV_NAME
1152 }
1153
1154 static int parse_top_args(const char *s, const char *arg, struct text_object *obj)
1155 {
1156         char buf[64];
1157         int n;
1158
1159         if (obj->data.top.was_parsed) {
1160                 return 1;
1161         }
1162         obj->data.top.was_parsed = 1;
1163
1164         if (arg && !obj->data.top.s) {
1165                 obj->data.top.s = strndup(arg, text_buffer_size);
1166         }
1167
1168         need_mask |= (1 << INFO_TOP);
1169
1170         if (s[3] == 0) {
1171                 obj->type = OBJ_top;
1172                 top_cpu = 1;
1173         } else if (strcmp(&s[3], "_mem") == EQUAL) {
1174                 obj->type = OBJ_top_mem;
1175                 top_mem = 1;
1176         } else if (strcmp(&s[3], "_time") == EQUAL) {
1177                 obj->type = OBJ_top_time;
1178                 top_time = 1;
1179 #ifdef IOSTATS
1180         } else if (strcmp(&s[3], "_io") == EQUAL) {
1181                 obj->type = OBJ_top_io;
1182                 top_io = 1;
1183 #endif
1184         } else {
1185 #ifdef IOSTATS
1186                 ERR("Must be top, top_mem, top_time or top_io");
1187 #else
1188                 ERR("Must be top, top_mem or top_time");
1189 #endif
1190                 return 0;
1191         }
1192
1193         if (!arg) {
1194                 ERR("top needs arguments");
1195                 return 0;
1196         }
1197
1198         if (sscanf(arg, "%63s %i", buf, &n) == 2) {
1199                 if (strcmp(buf, "name") == EQUAL) {
1200                         obj->data.top.type = TOP_NAME;
1201                 } else if (strcmp(buf, "cpu") == EQUAL) {
1202                         obj->data.top.type = TOP_CPU;
1203                 } else if (strcmp(buf, "pid") == EQUAL) {
1204                         obj->data.top.type = TOP_PID;
1205                 } else if (strcmp(buf, "mem") == EQUAL) {
1206                         obj->data.top.type = TOP_MEM;
1207                 } else if (strcmp(buf, "time") == EQUAL) {
1208                         obj->data.top.type = TOP_TIME;
1209                 } else if (strcmp(buf, "mem_res") == EQUAL) {
1210                         obj->data.top.type = TOP_MEM_RES;
1211                 } else if (strcmp(buf, "mem_vsize") == EQUAL) {
1212                         obj->data.top.type = TOP_MEM_VSIZE;
1213 #ifdef IOSTATS
1214                 } else if (strcmp(buf, "io_read") == EQUAL) {
1215                         obj->data.top.type = TOP_READ_BYTES;
1216                 } else if (strcmp(buf, "io_write") == EQUAL) {
1217                         obj->data.top.type = TOP_WRITE_BYTES;
1218                 } else if (strcmp(buf, "io_perc") == EQUAL) {
1219                         obj->data.top.type = TOP_IO_PERC;
1220 #endif
1221                 } else {
1222                         ERR("invalid type arg for top");
1223 #ifdef IOSTATS
1224                         ERR("must be one of: name, cpu, pid, mem, time, mem_res, mem_vsize, "
1225                                         "io_read, io_write, io_perc");
1226 #else
1227                         ERR("must be one of: name, cpu, pid, mem, time, mem_res, mem_vsize");
1228 #endif
1229                         return 0;
1230                 }
1231                 if (n < 1 || n > 10) {
1232                         ERR("invalid num arg for top. Must be between 1 and 10.");
1233                         return 0;
1234                 } else {
1235                         obj->data.top.num = n - 1;
1236                 }
1237         } else {
1238                 ERR("invalid argument count for top");
1239                 return 0;
1240         }
1241         return 1;
1242 }
1243
1244 long current_text_color;
1245
1246 /* construct_text_object() creates a new text_object */
1247 static struct text_object *construct_text_object(const char *s,
1248                 const char *arg, long line, char allow_threaded, void **ifblock_opaque, void *free_at_crash)
1249 {
1250         // struct text_object *obj = new_text_object();
1251         struct text_object *obj = new_text_object_internal();
1252
1253         obj->line = line;
1254
1255 #define OBJ(a, n) if (strcmp(s, #a) == 0) { \
1256         obj->type = OBJ_##a; need_mask |= (1ULL << n); {
1257 #define OBJ_IF(a, n) if (strcmp(s, #a) == 0) { \
1258         obj->type = OBJ_##a; need_mask |= (1ULL << n); \
1259         obj_be_ifblock_if(ifblock_opaque, obj); {
1260 #define OBJ_THREAD(a, n) if (strcmp(s, #a) == 0 && allow_threaded) { \
1261         obj->type = OBJ_##a; need_mask |= (1ULL << n); {
1262 #define END } } else
1263
1264 #define SIZE_DEFAULTS(arg) { \
1265         obj->a = default_##arg##_width; \
1266         obj->b = default_##arg##_height; \
1267 }
1268
1269 #ifdef X11
1270         if (s[0] == '#') {
1271                 obj->type = OBJ_color;
1272                 obj->data.l = get_x11_color(s);
1273         } else
1274 #endif /* X11 */
1275 #ifdef __OpenBSD__
1276         OBJ(freq, INFO_FREQ)
1277 #else
1278         OBJ(acpitemp, 0)
1279                 obj->data.i = open_acpi_temperature(arg);
1280         END OBJ(acpiacadapter, 0)
1281         END OBJ(freq, INFO_FREQ)
1282 #endif /* !__OpenBSD__ */
1283                 get_cpu_count();
1284                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
1285                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
1286                         obj->data.cpu_index = 1;
1287                         /* ERR("freq: Invalid CPU number or you don't have that many CPUs! "
1288                                 "Displaying the clock for CPU 1."); */
1289                 } else {
1290                         obj->data.cpu_index = atoi(&arg[0]);
1291                 }
1292                 obj->a = 1;
1293         END OBJ(freq_g, INFO_FREQ)
1294                 get_cpu_count();
1295                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
1296                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
1297                         obj->data.cpu_index = 1;
1298                         /* ERR("freq_g: Invalid CPU number or you don't have that many "
1299                                 "CPUs! Displaying the clock for CPU 1."); */
1300                 } else {
1301                         obj->data.cpu_index = atoi(&arg[0]);
1302                 }
1303                 obj->a = 1;
1304         END OBJ(read_tcp, 0)
1305                 if (arg) {
1306                         obj->data.read_tcp.host = malloc(text_buffer_size);
1307                         sscanf(arg, "%s", obj->data.read_tcp.host);
1308                         sscanf(arg+strlen(obj->data.read_tcp.host), "%u", &(obj->data.read_tcp.port));
1309                         if(obj->data.read_tcp.port == 0) {
1310                                 obj->data.read_tcp.port = atoi(obj->data.read_tcp.host);
1311                                 strcpy(obj->data.read_tcp.host,"localhost");
1312                         }
1313                         obj->data.read_tcp.port = htons(obj->data.read_tcp.port);
1314                         if(obj->data.read_tcp.port < 1 || obj->data.read_tcp.port > 65535) {
1315                                 CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
1316                         }
1317                 }else{
1318                         CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
1319                 }
1320 #if defined(__linux__)
1321         END OBJ(voltage_mv, 0)
1322                 get_cpu_count();
1323                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
1324                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
1325                         obj->data.cpu_index = 1;
1326                         /* ERR("voltage_mv: Invalid CPU number or you don't have that many "
1327                                 "CPUs! Displaying voltage for CPU 1."); */
1328                 } else {
1329                         obj->data.cpu_index = atoi(&arg[0]);
1330                 }
1331                 obj->a = 1;
1332         END OBJ(voltage_v, 0)
1333                 get_cpu_count();
1334                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
1335                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
1336                         obj->data.cpu_index = 1;
1337                         /* ERR("voltage_v: Invalid CPU number or you don't have that many "
1338                                 "CPUs! Displaying voltage for CPU 1."); */
1339                 } else {
1340                         obj->data.cpu_index = atoi(&arg[0]);
1341                 }
1342                 obj->a = 1;
1343
1344 #ifdef HAVE_IWLIB
1345         END OBJ(wireless_essid, INFO_NET)
1346                 if (arg) {
1347                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1348                 } else {
1349                         // default to DEFAULTNETDEV
1350                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1351                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1352                         free(buf);
1353                 }
1354         END OBJ(wireless_mode, INFO_NET)
1355                 if (arg) {
1356                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1357                 } else {
1358                         // default to DEFAULTNETDEV
1359                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1360                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1361                         free(buf);
1362                 }
1363         END OBJ(wireless_bitrate, INFO_NET)
1364                 if (arg) {
1365                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1366                 } else {
1367                         // default to DEFAULTNETDEV
1368                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1369                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1370                         free(buf);
1371                 }
1372         END OBJ(wireless_ap, INFO_NET)
1373                 if (arg) {
1374                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1375                 } else {
1376                         // default to DEFAULTNETDEV
1377                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1378                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1379                         free(buf);
1380                 }
1381         END OBJ(wireless_link_qual, INFO_NET)
1382                 if (arg) {
1383                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1384                 } else {
1385                         // default to DEFAULTNETDEV
1386                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1387                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1388                         free(buf);
1389                 }
1390         END OBJ(wireless_link_qual_max, INFO_NET)
1391                 if (arg) {
1392                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1393                 } else {
1394                         // default to DEFAULTNETDEV
1395                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1396                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1397                         free(buf);
1398                 }
1399         END OBJ(wireless_link_qual_perc, INFO_NET)
1400                 if (arg) {
1401                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1402                 } else {
1403                         // default to DEFAULTNETDEV
1404                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1405                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1406                         free(buf);
1407                 }
1408         END OBJ(wireless_link_bar, INFO_NET)
1409                 SIZE_DEFAULTS(bar);
1410                 if (arg) {
1411                         arg = scan_bar(arg, &obj->a, &obj->b);
1412                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1413                 } else {
1414                         // default to DEFAULTNETDEV
1415                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1416                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1417                         free(buf);
1418                 }
1419 #endif /* HAVE_IWLIB */
1420
1421 #endif /* __linux__ */
1422
1423 #ifndef __OpenBSD__
1424         END OBJ(acpifan, 0)
1425         END OBJ(battery, 0)
1426                 char bat[64];
1427
1428                 if (arg) {
1429                         sscanf(arg, "%63s", bat);
1430                 } else {
1431                         strcpy(bat, "BAT0");
1432                 }
1433                 obj->data.s = strndup(bat, text_buffer_size);
1434         END OBJ(battery_short, 0)
1435                 char bat[64];
1436
1437                 if (arg) {
1438                         sscanf(arg, "%63s", bat);
1439                 } else {
1440                         strcpy(bat, "BAT0");
1441                 }
1442                 obj->data.s = strndup(bat, text_buffer_size);
1443         END OBJ(battery_time, 0)
1444                 char bat[64];
1445
1446                 if (arg) {
1447                         sscanf(arg, "%63s", bat);
1448                 } else {
1449                         strcpy(bat, "BAT0");
1450                 }
1451                 obj->data.s = strndup(bat, text_buffer_size);
1452         END OBJ(battery_percent, 0)
1453                 char bat[64];
1454
1455                 if (arg) {
1456                         sscanf(arg, "%63s", bat);
1457                 } else {
1458                         strcpy(bat, "BAT0");
1459                 }
1460                 obj->data.s = strndup(bat, text_buffer_size);
1461         END OBJ(battery_bar, 0)
1462                 char bat[64];
1463                 SIZE_DEFAULTS(bar);
1464                 obj->b = 6;
1465                 if (arg) {
1466                         arg = scan_bar(arg, &obj->a, &obj->b);
1467                         sscanf(arg, "%63s", bat);
1468                 } else {
1469                         strcpy(bat, "BAT0");
1470                 }
1471                 obj->data.s = strndup(bat, text_buffer_size);
1472 #endif /* !__OpenBSD__ */
1473
1474 #if defined(__linux__)
1475         END OBJ(disk_protect, 0)
1476                 if (arg)
1477                         obj->data.s = strndup(dev_name(arg), text_buffer_size);
1478                 else
1479                         CRIT_ERR(obj, free_at_crash, "disk_protect needs an argument");
1480         END OBJ(i8k_version, INFO_I8K)
1481         END OBJ(i8k_bios, INFO_I8K)
1482         END OBJ(i8k_serial, INFO_I8K)
1483         END OBJ(i8k_cpu_temp, INFO_I8K)
1484         END OBJ(i8k_left_fan_status, INFO_I8K)
1485         END OBJ(i8k_right_fan_status, INFO_I8K)
1486         END OBJ(i8k_left_fan_rpm, INFO_I8K)
1487         END OBJ(i8k_right_fan_rpm, INFO_I8K)
1488         END OBJ(i8k_ac_status, INFO_I8K)
1489         END OBJ(i8k_buttons_status, INFO_I8K)
1490 #if defined(IBM)
1491         END OBJ(ibm_fan, 0)
1492         END OBJ(ibm_temps, 0)
1493                 if (!arg) {
1494                         CRIT_ERR(obj, free_at_crash, "ibm_temps: needs an argument");
1495                 }
1496                 if (!isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) >= 8) {
1497                         obj->data.sensor = 0;
1498                         ERR("Invalid temperature sensor! Sensor number must be 0 to 7. "
1499                                 "Using 0 (CPU temp sensor).");
1500                 }
1501                 obj->data.sensor = atoi(&arg[0]);
1502         END OBJ(ibm_volume, 0)
1503         END OBJ(ibm_brightness, 0)
1504 #endif
1505         /* information from sony_laptop kernel module
1506          * /sys/devices/platform/sony-laptop */
1507         END OBJ(sony_fanspeed, 0)
1508         END OBJ_IF(if_gw, INFO_GW)
1509         END OBJ(ioscheduler, 0)
1510                 if (!arg) {
1511                         CRIT_ERR(obj, free_at_crash, "get_ioscheduler needs an argument (e.g. hda)");
1512                         obj->data.s = 0;
1513                 } else
1514                         obj->data.s = strndup(dev_name(arg), text_buffer_size);
1515         END OBJ(laptop_mode, 0)
1516         END OBJ(pb_battery, 0)
1517                 if (arg && strcmp(arg, "status") == EQUAL) {
1518                         obj->data.i = PB_BATT_STATUS;
1519                 } else if (arg && strcmp(arg, "percent") == EQUAL) {
1520                         obj->data.i = PB_BATT_PERCENT;
1521                 } else if (arg && strcmp(arg, "time") == EQUAL) {
1522                         obj->data.i = PB_BATT_TIME;
1523                 } else {
1524                         ERR("pb_battery: needs one argument: status, percent or time");
1525                         free(obj);
1526                         return NULL;
1527                 }
1528
1529 #endif /* __linux__ */
1530 #if (defined(__FreeBSD__) || defined(__linux__))
1531         END OBJ_IF(if_up, 0)
1532                 if (!arg) {
1533                         ERR("if_up needs an argument");
1534                         obj->data.ifblock.s = 0;
1535                 } else {
1536                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1537                 }
1538 #endif
1539 #if defined(__OpenBSD__)
1540         END OBJ(obsd_sensors_temp, 0)
1541                 if (!arg) {
1542                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_temp: needs an argument");
1543                 }
1544                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
1545                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
1546                         obj->data.sensor = 0;
1547                         ERR("Invalid temperature sensor number!");
1548                 }
1549                 obj->data.sensor = atoi(&arg[0]);
1550         END OBJ(obsd_sensors_fan, 0)
1551                 if (!arg) {
1552                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_fan: needs 2 arguments (device and sensor "
1553                                 "number)");
1554                 }
1555                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
1556                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
1557                         obj->data.sensor = 0;
1558                         ERR("Invalid fan sensor number!");
1559                 }
1560                 obj->data.sensor = atoi(&arg[0]);
1561         END OBJ(obsd_sensors_volt, 0)
1562                 if (!arg) {
1563                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_volt: needs 2 arguments (device and sensor "
1564                                 "number)");
1565                 }
1566                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
1567                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
1568                         obj->data.sensor = 0;
1569                         ERR("Invalid voltage sensor number!");
1570                 }
1571                 obj->data.sensor = atoi(&arg[0]);
1572         END OBJ(obsd_vendor, 0)
1573         END OBJ(obsd_product, 0)
1574 #endif /* __OpenBSD__ */
1575         END OBJ(buffers, INFO_BUFFERS)
1576         END OBJ(cached, INFO_BUFFERS)
1577 #define SCAN_CPU(__arg, __var) { \
1578         int __offset = 0; \
1579         if (__arg && sscanf(__arg, " cpu%u %n", &__var, &__offset) > 0) \
1580                 __arg += __offset; \
1581         else \
1582                 __var = 0; \
1583 }
1584         END OBJ(cpu, INFO_CPU)
1585                 SCAN_CPU(arg, obj->data.cpu_index);
1586                 DBGP2("Adding $cpu for CPU %d", obj->data.cpu_index);
1587 #ifdef X11
1588         END OBJ(cpugauge, INFO_CPU)
1589                 SIZE_DEFAULTS(gauge);
1590                 SCAN_CPU(arg, obj->data.cpu_index);
1591                 scan_gauge(arg, &obj->a, &obj->b);
1592                 DBGP2("Adding $cpugauge for CPU %d", obj->data.cpu_index);
1593 #endif /* X11 */
1594         END OBJ(cpubar, INFO_CPU)
1595                 SIZE_DEFAULTS(bar);
1596                 SCAN_CPU(arg, obj->data.cpu_index);
1597                 scan_bar(arg, &obj->a, &obj->b);
1598                 DBGP2("Adding $cpubar for CPU %d", obj->data.cpu_index);
1599 #ifdef X11
1600         END OBJ(cpugraph, INFO_CPU)
1601                 char *buf = 0;
1602                 SIZE_DEFAULTS(graph);
1603                 SCAN_CPU(arg, obj->data.cpu_index);
1604                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1605                         &obj->e, &obj->char_a, &obj->char_b);
1606                 DBGP2("Adding $cpugraph for CPU %d", obj->data.cpu_index);
1607                 if (buf) free(buf);
1608         END OBJ(loadgraph, INFO_LOADAVG)
1609                 char *buf = 0;
1610                 SIZE_DEFAULTS(graph);
1611                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1612                                 &obj->e, &obj->char_a, &obj->char_b);
1613                 if (buf) {
1614                         int a = 1, r = 3;
1615                         if (arg) {
1616                                 r = sscanf(arg, "%d", &a);
1617                         }
1618                         obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
1619                         free(buf);
1620                 }
1621 #endif /* X11 */
1622         END OBJ(diskio, INFO_DISKIO)
1623                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
1624         END OBJ(diskio_read, INFO_DISKIO)
1625                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
1626         END OBJ(diskio_write, INFO_DISKIO)
1627                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
1628 #ifdef X11
1629         END OBJ(diskiograph, INFO_DISKIO)
1630                 char *buf = 0;
1631                 SIZE_DEFAULTS(graph);
1632                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1633                                 &obj->e, &obj->char_a, &obj->char_b);
1634
1635                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
1636                 if (buf) free(buf);
1637         END OBJ(diskiograph_read, INFO_DISKIO)
1638                 char *buf = 0;
1639                 SIZE_DEFAULTS(graph);
1640                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1641                                 &obj->e, &obj->char_a, &obj->char_b);
1642
1643                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
1644                 if (buf) free(buf);
1645         END OBJ(diskiograph_write, INFO_DISKIO)
1646                 char *buf = 0;
1647                 SIZE_DEFAULTS(graph);
1648                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1649                                 &obj->e, &obj->char_a, &obj->char_b);
1650
1651                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
1652                 if (buf) free(buf);
1653 #endif /* X11 */
1654         END OBJ(color, 0)
1655 #ifdef X11
1656                 if (output_methods & TO_X) {
1657                         obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
1658                         current_text_color = obj->data.l;
1659                 }
1660 #endif /* X11 */
1661         END OBJ(color0, 0)
1662                 obj->data.l = color0;
1663                 current_text_color = obj->data.l;
1664         END OBJ(color1, 0)
1665                 obj->data.l = color1;
1666                 current_text_color = obj->data.l;
1667         END OBJ(color2, 0)
1668                 obj->data.l = color2;
1669                 current_text_color = obj->data.l;
1670         END OBJ(color3, 0)
1671                 obj->data.l = color3;
1672                 current_text_color = obj->data.l;
1673         END OBJ(color4, 0)
1674                 obj->data.l = color4;
1675                 current_text_color = obj->data.l;
1676         END OBJ(color5, 0)
1677                 obj->data.l = color5;
1678                 current_text_color = obj->data.l;
1679         END OBJ(color6, 0)
1680                 obj->data.l = color6;
1681                 current_text_color = obj->data.l;
1682         END OBJ(color7, 0)
1683                 obj->data.l = color7;
1684                 current_text_color = obj->data.l;
1685         END OBJ(color8, 0)
1686                 obj->data.l = color8;
1687                 current_text_color = obj->data.l;
1688         END OBJ(color9, 0)
1689                 obj->data.l = color9;
1690                 current_text_color = obj->data.l;
1691 #ifdef X11
1692         END OBJ(font, 0)
1693                 obj->data.s = scan_font(arg);
1694 #endif /* X11 */
1695         END OBJ(conky_version, 0)
1696         END OBJ(conky_build_date, 0)
1697         END OBJ(conky_build_arch, 0)
1698         END OBJ(downspeed, INFO_NET)
1699                 if (arg) {
1700                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1701                 } else {
1702                         // default to DEFAULTNETDEV
1703                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1704                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1705                         free(buf);
1706                 }
1707         END OBJ(downspeedf, INFO_NET)
1708                 if (arg) {
1709                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1710                 } else {
1711                         // default to DEFAULTNETDEV
1712                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1713                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1714                         free(buf);
1715                 }
1716 #ifdef X11
1717         END OBJ(downspeedgraph, INFO_NET)
1718                 char *buf = 0;
1719                 SIZE_DEFAULTS(graph);
1720                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1721                                 &obj->e, &obj->char_a, &obj->char_b);
1722
1723                 // default to DEFAULTNETDEV
1724                 buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
1725                 obj->data.net = get_net_stat(buf, obj, free_at_crash);
1726                 free(buf);
1727 #endif /* X11 */
1728         END OBJ(else, 0)
1729                 obj_be_ifblock_else(ifblock_opaque, obj);
1730         END OBJ(endif, 0)
1731                 obj_be_ifblock_endif(ifblock_opaque, obj);
1732         END OBJ(eval, 0)
1733                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1734         END OBJ(image, 0)
1735                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1736 #ifdef HAVE_POPEN
1737         END OBJ(exec, 0)
1738                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1739         END OBJ(execp, 0)
1740                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1741         END OBJ(execbar, 0)
1742                 SIZE_DEFAULTS(bar);
1743                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1744 #ifdef X11
1745         END OBJ(execgauge, 0)
1746                 SIZE_DEFAULTS(gauge);
1747                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1748         END OBJ(execgraph, 0)
1749                 SIZE_DEFAULTS(graph);
1750                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
1751 #endif /* X11 */
1752         END OBJ(execibar, 0)
1753                 int n;
1754                 SIZE_DEFAULTS(bar);
1755
1756                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1757                         char buf[256];
1758
1759                         ERR("${execibar <interval> command}");
1760                         obj->type = OBJ_text;
1761                         snprintf(buf, 256, "${%s}", s);
1762                         obj->data.s = strndup(buf, text_buffer_size);
1763                 } else {
1764                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
1765                 }
1766 #ifdef X11
1767         END OBJ(execigraph, 0)
1768                 int n;
1769                 SIZE_DEFAULTS(graph);
1770
1771                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1772                         char buf[256];
1773
1774                         ERR("${execigraph <interval> command}");
1775                         obj->type = OBJ_text;
1776                         snprintf(buf, 256, "${%s}", s);
1777                         obj->data.s = strndup(buf, text_buffer_size);
1778                 } else {
1779                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
1780                 }
1781         END OBJ(execigauge, 0)
1782                 int n;
1783                 SIZE_DEFAULTS(gauge);
1784
1785                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1786                         char buf[256];
1787
1788                         ERR("${execigauge <interval> command}");
1789                         obj->type = OBJ_text;
1790                         snprintf(buf, 256, "${%s}", s);
1791                         obj->data.s = strndup(buf, text_buffer_size);
1792                 } else {
1793                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
1794                 }
1795 #endif /* X11 */
1796         END OBJ(execi, 0)
1797                 int n;
1798
1799                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1800                         char buf[256];
1801
1802                         ERR("${execi <interval> command}");
1803                         obj->type = OBJ_text;
1804                         snprintf(buf, 256, "${%s}", s);
1805                         obj->data.s = strndup(buf, text_buffer_size);
1806                 } else {
1807                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
1808                         obj->data.execi.buffer = malloc(text_buffer_size);
1809                 }
1810         END OBJ(execpi, 0)
1811                 int n;
1812
1813                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
1814                         char buf[256];
1815
1816                         ERR("${execi <interval> command}");
1817                         obj->type = OBJ_text;
1818                         snprintf(buf, 256, "${%s}", s);
1819                         obj->data.s = strndup(buf, text_buffer_size);
1820                 } else {
1821                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
1822                         obj->data.execi.buffer = malloc(text_buffer_size);
1823                 }
1824         END OBJ_THREAD(texeci, 0)
1825                         int n;
1826
1827                         if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) {
1828                                 char buf[256];
1829
1830                                 ERR("${texeci <interval> command}");
1831                                 obj->type = OBJ_text;
1832                                 snprintf(buf, 256, "${%s}", s);
1833                                 obj->data.s = strndup(buf, text_buffer_size);
1834                         } else {
1835                                 obj->data.texeci.cmd = strndup(arg + n, text_buffer_size);
1836                                 obj->data.texeci.buffer = malloc(text_buffer_size);
1837                         }
1838                         obj->data.texeci.p_timed_thread = NULL;
1839         END     OBJ(pre_exec, 0)
1840                 obj->type = OBJ_text;
1841         if (arg) {
1842                 char buf[2048];
1843
1844                 read_exec(arg, buf, sizeof(buf));
1845                 obj->data.s = strndup(buf, text_buffer_size);
1846         } else {
1847                 obj->data.s = strndup("", text_buffer_size);
1848         }
1849 #endif
1850         END OBJ(fs_bar, INFO_FS)
1851                 SIZE_DEFAULTS(bar);
1852                 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
1853                 if (arg) {
1854                         while (isspace(*arg)) {
1855                                 arg++;
1856                         }
1857                         if (*arg == '\0') {
1858                                 arg = "/";
1859                         }
1860                 } else {
1861                         arg = "/";
1862                 }
1863                 obj->data.fsbar.fs = prepare_fs_stat(arg);
1864         END OBJ(fs_bar_free, INFO_FS)
1865                 SIZE_DEFAULTS(bar);
1866                 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
1867                 if (arg) {
1868                         while (isspace(*arg)) {
1869                                 arg++;
1870                         }
1871                         if (*arg == '\0') {
1872                                 arg = "/";
1873                         }
1874                 } else {
1875                         arg = "/";
1876                 }
1877
1878                 obj->data.fsbar.fs = prepare_fs_stat(arg);
1879         END OBJ(fs_free, INFO_FS)
1880                 if (!arg) {
1881                         arg = "/";
1882                 }
1883                 obj->data.fs = prepare_fs_stat(arg);
1884         END OBJ(fs_used_perc, INFO_FS)
1885                 if (!arg) {
1886                         arg = "/";
1887                 }
1888                 obj->data.fs = prepare_fs_stat(arg);
1889         END OBJ(fs_free_perc, INFO_FS)
1890                 if (!arg) {
1891                         arg = "/";
1892                 }
1893                 obj->data.fs = prepare_fs_stat(arg);
1894         END OBJ(fs_size, INFO_FS)
1895                 if (!arg) {
1896                         arg = "/";
1897                 }
1898                 obj->data.fs = prepare_fs_stat(arg);
1899         END OBJ(fs_type, INFO_FS)
1900                 if (!arg) {
1901                         arg = "/";
1902                 }
1903                 obj->data.fs = prepare_fs_stat(arg);
1904         END OBJ(fs_used, INFO_FS)
1905                 if (!arg) {
1906                         arg = "/";
1907                 }
1908                 obj->data.fs = prepare_fs_stat(arg);
1909         END OBJ(hr, 0)
1910                 obj->data.i = arg ? atoi(arg) : 1;
1911         END OBJ(nameserver, INFO_DNS)
1912                 obj->data.i = arg ? atoi(arg) : 0;
1913         END OBJ(offset, 0)
1914                 obj->data.i = arg ? atoi(arg) : 1;
1915         END OBJ(voffset, 0)
1916                 obj->data.i = arg ? atoi(arg) : 1;
1917         END OBJ(goto, 0)
1918
1919                 if (!arg) {
1920                         ERR("goto needs arguments");
1921                         obj->type = OBJ_text;
1922                         obj->data.s = strndup("${goto}", text_buffer_size);
1923                         return NULL;
1924                 }
1925
1926                 obj->data.i = atoi(arg);
1927
1928         END OBJ(tab, 0)
1929                 int a = 10, b = 0;
1930
1931                 if (arg) {
1932                         if (sscanf(arg, "%d %d", &a, &b) != 2) {
1933                                 sscanf(arg, "%d", &b);
1934                         }
1935                 }
1936                 if (a <= 0) {
1937                         a = 1;
1938                 }
1939                 obj->data.pair.a = a;
1940                 obj->data.pair.b = b;
1941
1942 #ifdef __linux__
1943         END OBJ(i2c, INFO_SYSFS)
1944                 char buf1[64], buf2[64];
1945                 float factor, offset;
1946                 int n, found = 0;
1947
1948                 if (!arg) {
1949                         ERR("i2c needs arguments");
1950                         obj->type = OBJ_text;
1951                         // obj->data.s = strndup("${i2c}", text_buffer_size);
1952                         return NULL;
1953                 }
1954
1955 #define HWMON_RESET() {\
1956                 buf1[0] = 0; \
1957                 factor = 1.0; \
1958                 offset = 0.0; }
1959
1960                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1961                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1962                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1963                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1964
1965                 if (!found) {
1966                         ERR("i2c failed to parse arguments");
1967                         obj->type = OBJ_text;
1968                         return NULL;
1969                 }
1970                 DBGP("parsed i2c args: '%s' '%s' %d %f %f\n", buf1, buf2, n, factor, offset);
1971                 obj->data.sysfs.fd = open_i2c_sensor((*buf1) ? buf1 : 0, buf2, n,
1972                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
1973                 strncpy(obj->data.sysfs.type, buf2, 63);
1974                 obj->data.sysfs.factor = factor;
1975                 obj->data.sysfs.offset = offset;
1976
1977         END OBJ(platform, INFO_SYSFS)
1978                 char buf1[64], buf2[64];
1979                 float factor, offset;
1980                 int n, found = 0;
1981
1982                 if (!arg) {
1983                         ERR("platform needs arguments");
1984                         obj->type = OBJ_text;
1985                         return NULL;
1986                 }
1987
1988                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1989                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1990                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1991                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1992
1993                 if (!found) {
1994                         ERR("platform failed to parse arguments");
1995                         obj->type = OBJ_text;
1996                         return NULL;
1997                 }
1998                 DBGP("parsed platform args: '%s' '%s' %d %f %f\n", buf1, buf2, n, factor, offset);
1999                 obj->data.sysfs.fd = open_platform_sensor((*buf1) ? buf1 : 0, buf2, n,
2000                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
2001                 strncpy(obj->data.sysfs.type, buf2, 63);
2002                 obj->data.sysfs.factor = factor;
2003                 obj->data.sysfs.offset = offset;
2004
2005         END OBJ(hwmon, INFO_SYSFS)
2006                 char buf1[64], buf2[64];
2007                 float factor, offset;
2008                 int n, found = 0;
2009
2010                 if (!arg) {
2011                         ERR("hwmon needs argumanets");
2012                         obj->type = OBJ_text;
2013                         return NULL;
2014                 }
2015
2016                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
2017                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
2018                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
2019                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
2020
2021 #undef HWMON_RESET
2022
2023                 if (!found) {
2024                         ERR("hwmon failed to parse arguments");
2025                         obj->type = OBJ_text;
2026                         return NULL;
2027                 }
2028                 DBGP("parsed hwmon args: '%s' '%s' %d %f %f\n", buf1, buf2, n, factor, offset);
2029                 obj->data.sysfs.fd = open_hwmon_sensor((*buf1) ? buf1 : 0, buf2, n,
2030                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
2031                 strncpy(obj->data.sysfs.type, buf2, 63);
2032                 obj->data.sysfs.factor = factor;
2033                 obj->data.sysfs.offset = offset;
2034
2035 #endif /* !__OpenBSD__ */
2036
2037         END
2038         /* we have four different types of top (top, top_mem, top_time and top_io). To
2039          * avoid having almost-same code four times, we have this special
2040          * handler. */
2041         if (strncmp(s, "top", 3) == EQUAL) {
2042                 if (!parse_top_args(s, arg, obj)) {
2043                         return NULL;
2044                 }
2045         } else OBJ(addr, INFO_NET)
2046                 if (arg) {
2047                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2048                 } else {
2049                         // default to DEFAULTNETDEV
2050                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2051                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2052                         free(buf);
2053                 }
2054 #if defined(__linux__)
2055         END OBJ(addrs, INFO_NET)
2056                 if (arg) {
2057                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2058                 } else {
2059                         // default to DEFAULTNETDEV
2060                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2061                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2062                         free(buf);
2063                 }
2064 #endif /* __linux__ */
2065         END OBJ(tail, 0)
2066                 if (init_tail_object(obj, arg)) {
2067                         obj->type = OBJ_text;
2068                         obj->data.s = strndup("${tail}", text_buffer_size);
2069                 }
2070         END OBJ(head, 0)
2071                 if (init_head_object(obj, arg)) {
2072                         obj->type = OBJ_text;
2073                         obj->data.s = strndup("${head}", text_buffer_size);
2074                 }
2075         END OBJ(lines, 0)
2076                 if (arg) {
2077                         obj->data.s = strndup(arg, text_buffer_size);
2078                 }else{
2079                         CRIT_ERR(obj, free_at_crash, "lines needs a argument");
2080                 }
2081         END OBJ(words, 0)
2082                 if (arg) {
2083                         obj->data.s = strndup(arg, text_buffer_size);
2084                 }else{
2085                         CRIT_ERR(obj, free_at_crash, "words needs a argument");
2086                 }
2087         END OBJ(loadavg, INFO_LOADAVG)
2088                 int a = 1, b = 2, c = 3, r = 3;
2089
2090                 if (arg) {
2091                         r = sscanf(arg, "%d %d %d", &a, &b, &c);
2092                         if (r >= 3 && (c < 1 || c > 3)) {
2093                                 r--;
2094                         }
2095                         if (r >= 2 && (b < 1 || b > 3)) {
2096                                 r--, b = c;
2097                         }
2098                         if (r >= 1 && (a < 1 || a > 3)) {
2099                                 r--, a = b, b = c;
2100                         }
2101                 }
2102                 obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
2103                 obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
2104                 obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
2105         END OBJ_IF(if_empty, 0)
2106                 if (!arg) {
2107                         ERR("if_empty needs an argument");
2108                         obj->data.ifblock.s = 0;
2109                 } else {
2110                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
2111                         obj->sub = malloc(sizeof(struct text_object));
2112                         extract_variable_text_internal(obj->sub,
2113                                                        obj->data.ifblock.s, 0);
2114                 }
2115         END OBJ_IF(if_match, 0)
2116                 if (!arg) {
2117                         ERR("if_match needs arguments");
2118                         obj->data.ifblock.s = 0;
2119                 } else {
2120                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
2121                         obj->sub = malloc(sizeof(struct text_object));
2122                         extract_variable_text_internal(obj->sub,
2123                                                        obj->data.ifblock.s, 0);
2124                 }
2125         END OBJ_IF(if_existing, 0)
2126                 if (!arg) {
2127                         ERR("if_existing needs an argument or two");
2128                         obj->data.ifblock.s = NULL;
2129                         obj->data.ifblock.str = NULL;
2130                 } else {
2131                         char buf1[256], buf2[256];
2132                         int r = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
2133
2134                         if (r == 1) {
2135                                 obj->data.ifblock.s = strndup(buf1, text_buffer_size);
2136                                 obj->data.ifblock.str = NULL;
2137                         } else {
2138                                 obj->data.ifblock.s = strndup(buf1, text_buffer_size);
2139                                 obj->data.ifblock.str = strndup(buf2, text_buffer_size);
2140                         }
2141                 }
2142                 DBGP("if_existing: '%s' '%s'", obj->data.ifblock.s, obj->data.ifblock.str);
2143         END OBJ_IF(if_mounted, 0)
2144                 if (!arg) {
2145                         ERR("if_mounted needs an argument");
2146                         obj->data.ifblock.s = 0;
2147                 } else {
2148                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
2149                 }
2150 #ifdef __linux__
2151         END OBJ_IF(if_running, INFO_TOP)
2152                 if (arg) {
2153                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
2154 #else
2155         END OBJ_IF(if_running, 0)
2156                 if (arg) {
2157                         char buf[256];
2158
2159                         snprintf(buf, 256, "pidof %s >/dev/null", arg);
2160                         obj->data.ifblock.s = strndup(buf, text_buffer_size);
2161 #endif
2162                 } else {
2163                         ERR("if_running needs an argument");
2164                         obj->data.ifblock.s = 0;
2165                 }
2166         END OBJ(kernel, 0)
2167         END OBJ(machine, 0)
2168         END OBJ(mails, 0)
2169                 float n1;
2170                 char box[256], dst[256];
2171
2172                 if (!arg) {
2173                         n1 = 9.5;
2174                         /* Kapil: Changed from MAIL_FILE to
2175                            current_mail_spool since the latter
2176                            is a copy of the former if undefined
2177                            but the latter should take precedence
2178                            if defined */
2179                         strncpy(box, current_mail_spool, sizeof(box));
2180                 } else {
2181                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2182                                 n1 = 9.5;
2183                                 strncpy(box, arg, sizeof(box));
2184                         }
2185                 }
2186
2187                 variable_substitute(box, dst, sizeof(dst));
2188                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2189                 obj->data.local_mail.interval = n1;
2190         END OBJ(new_mails, 0)
2191                 float n1;
2192                 char box[256], dst[256];
2193
2194                 if (!arg) {
2195                         n1 = 9.5;
2196                         strncpy(box, current_mail_spool, sizeof(box));
2197                 } else {
2198                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2199                                 n1 = 9.5;
2200                                 strncpy(box, arg, sizeof(box));
2201                         }
2202                 }
2203
2204                 variable_substitute(box, dst, sizeof(dst));
2205                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2206                 obj->data.local_mail.interval = n1;
2207         END OBJ(seen_mails, 0)
2208                 float n1;
2209                 char box[256], dst[256];
2210
2211                 if (!arg) {
2212                         n1 = 9.5;
2213                         strncpy(box, current_mail_spool, sizeof(box));
2214                 } else {
2215                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2216                                 n1 = 9.5;
2217                                 strncpy(box, arg, sizeof(box));
2218                         }
2219                 }
2220
2221                 variable_substitute(box, dst, sizeof(dst));
2222                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2223                 obj->data.local_mail.interval = n1;
2224         END OBJ(unseen_mails, 0)
2225                 float n1;
2226                 char box[256], dst[256];
2227
2228                 if (!arg) {
2229                         n1 = 9.5;
2230                         strncpy(box, current_mail_spool, sizeof(box));
2231                 } else {
2232                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2233                                 n1 = 9.5;
2234                                 strncpy(box, arg, sizeof(box));
2235                         }
2236                 }
2237
2238                 variable_substitute(box, dst, sizeof(dst));
2239                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2240                 obj->data.local_mail.interval = n1;
2241         END OBJ(flagged_mails, 0)
2242                 float n1;
2243                 char box[256], dst[256];
2244
2245                 if (!arg) {
2246                         n1 = 9.5;
2247                         strncpy(box, current_mail_spool, sizeof(box));
2248                 } else {
2249                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2250                                 n1 = 9.5;
2251                                 strncpy(box, arg, sizeof(box));
2252                         }
2253                 }
2254
2255                 variable_substitute(box, dst, sizeof(dst));
2256                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2257                 obj->data.local_mail.interval = n1;
2258         END OBJ(unflagged_mails, 0)
2259                 float n1;
2260                 char box[256], dst[256];
2261
2262                 if (!arg) {
2263                         n1 = 9.5;
2264                         strncpy(box, current_mail_spool, sizeof(box));
2265                 } else {
2266                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2267                                 n1 = 9.5;
2268                                 strncpy(box, arg, sizeof(box));
2269                         }
2270                 }
2271
2272                 variable_substitute(box, dst, sizeof(dst));
2273                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2274                 obj->data.local_mail.interval = n1;
2275         END OBJ(forwarded_mails, 0)
2276                 float n1;
2277                 char box[256], dst[256];
2278
2279                 if (!arg) {
2280                         n1 = 9.5;
2281                         strncpy(box, current_mail_spool, sizeof(box));
2282                 } else {
2283                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2284                                 n1 = 9.5;
2285                                 strncpy(box, arg, sizeof(box));
2286                         }
2287                 }
2288
2289                 variable_substitute(box, dst, sizeof(dst));
2290                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2291                 obj->data.local_mail.interval = n1;
2292         END OBJ(unforwarded_mails, 0)
2293                 float n1;
2294                 char box[256], dst[256];
2295
2296                 if (!arg) {
2297                         n1 = 9.5;
2298                         strncpy(box, current_mail_spool, sizeof(box));
2299                 } else {
2300                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2301                                 n1 = 9.5;
2302                                 strncpy(box, arg, sizeof(box));
2303                         }
2304                 }
2305
2306                 variable_substitute(box, dst, sizeof(dst));
2307                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2308                 obj->data.local_mail.interval = n1;
2309         END OBJ(replied_mails, 0)
2310                 float n1;
2311                 char box[256], dst[256];
2312
2313                 if (!arg) {
2314                         n1 = 9.5;
2315                         strncpy(box, current_mail_spool, sizeof(box));
2316                 } else {
2317                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2318                                 n1 = 9.5;
2319                                 strncpy(box, arg, sizeof(box));
2320                         }
2321                 }
2322
2323                 variable_substitute(box, dst, sizeof(dst));
2324                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2325                 obj->data.local_mail.interval = n1;
2326         END OBJ(unreplied_mails, 0)
2327                 float n1;
2328                 char box[256], dst[256];
2329
2330                 if (!arg) {
2331                         n1 = 9.5;
2332                         strncpy(box, current_mail_spool, sizeof(box));
2333                 } else {
2334                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2335                                 n1 = 9.5;
2336                                 strncpy(box, arg, sizeof(box));
2337                         }
2338                 }
2339
2340                 variable_substitute(box, dst, sizeof(dst));
2341                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2342                 obj->data.local_mail.interval = n1;
2343         END OBJ(draft_mails, 0)
2344                 float n1;
2345                 char box[256], dst[256];
2346
2347                 if (!arg) {
2348                         n1 = 9.5;
2349                         strncpy(box, current_mail_spool, sizeof(box));
2350                 } else {
2351                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2352                                 n1 = 9.5;
2353                                 strncpy(box, arg, sizeof(box));
2354                         }
2355                 }
2356
2357                 variable_substitute(box, dst, sizeof(dst));
2358                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2359                 obj->data.local_mail.interval = n1;
2360         END OBJ(trashed_mails, 0)
2361                 float n1;
2362                 char box[256], dst[256];
2363
2364                 if (!arg) {
2365                         n1 = 9.5;
2366                         strncpy(box, current_mail_spool, sizeof(box));
2367                 } else {
2368                         if (sscanf(arg, "%s %f", box, &n1) != 2) {
2369                                 n1 = 9.5;
2370                                 strncpy(box, arg, sizeof(box));
2371                         }
2372                 }
2373
2374                 variable_substitute(box, dst, sizeof(dst));
2375                 obj->data.local_mail.box = strndup(dst, text_buffer_size);
2376                 obj->data.local_mail.interval = n1;
2377         END OBJ(mboxscan, 0)
2378                 obj->data.mboxscan.args = (char *) malloc(text_buffer_size);
2379                 obj->data.mboxscan.output = (char *) malloc(text_buffer_size);
2380                 /* if '1' (in mboxscan.c) then there was SIGUSR1, hmm */
2381                 obj->data.mboxscan.output[0] = 1;
2382                 strncpy(obj->data.mboxscan.args, arg, text_buffer_size);
2383         END OBJ(mem, INFO_MEM)
2384         END OBJ(memeasyfree, INFO_MEM)
2385         END OBJ(memfree, INFO_MEM)
2386         END OBJ(memmax, INFO_MEM)
2387         END OBJ(memperc, INFO_MEM)
2388 #ifdef X11
2389         END OBJ(memgauge, INFO_MEM)
2390                 SIZE_DEFAULTS(gauge);
2391                 scan_gauge(arg, &obj->data.pair.a, &obj->data.pair.b);
2392 #endif /* X11*/
2393         END OBJ(membar, INFO_MEM)
2394                 SIZE_DEFAULTS(bar);
2395                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2396 #ifdef X11
2397         END OBJ(memgraph, INFO_MEM)
2398                 char *buf = 0;
2399                 SIZE_DEFAULTS(graph);
2400                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
2401                                 &obj->e, &obj->char_a, &obj->char_b);
2402
2403                 if (buf) free(buf);
2404 #endif /* X11*/
2405         END OBJ(mixer, INFO_MIXER)
2406                 obj->data.l = mixer_init(arg);
2407         END OBJ(mixerl, INFO_MIXER)
2408                 obj->data.l = mixer_init(arg);
2409         END OBJ(mixerr, INFO_MIXER)
2410                 obj->data.l = mixer_init(arg);
2411 #ifdef X11
2412         END OBJ(mixerbar, INFO_MIXER)
2413                 SIZE_DEFAULTS(bar);
2414                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
2415                         &obj->data.mixerbar.h);
2416         END OBJ(mixerlbar, INFO_MIXER)
2417                 SIZE_DEFAULTS(bar);
2418                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
2419                         &obj->data.mixerbar.h);
2420         END OBJ(mixerrbar, INFO_MIXER)
2421                 SIZE_DEFAULTS(bar);
2422                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
2423                         &obj->data.mixerbar.h);
2424 #endif
2425         END OBJ_IF(if_mixer_mute, INFO_MIXER)
2426                 obj->data.ifblock.i = mixer_init(arg);
2427 #ifdef X11
2428         END OBJ(monitor, INFO_X11)
2429         END OBJ(monitor_number, INFO_X11)
2430         END OBJ(desktop, INFO_X11)
2431         END OBJ(desktop_number, INFO_X11)
2432         END OBJ(desktop_name, INFO_X11)
2433 #endif
2434         END OBJ(nodename, 0)
2435         END OBJ(processes, INFO_PROCS)
2436         END OBJ(running_processes, INFO_RUN_PROCS)
2437         END OBJ(shadecolor, 0)
2438 #ifdef X11
2439                 obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
2440 #endif /* X11 */
2441         END OBJ(outlinecolor, 0)
2442 #ifdef X11
2443                 obj->data.l = arg ? get_x11_color(arg) : default_out_color;
2444 #endif /* X11 */
2445         END OBJ(stippled_hr, 0)
2446 #ifdef X11
2447                 int a = stippled_borders, b = 1;
2448
2449                 if (arg) {
2450                         if (sscanf(arg, "%d %d", &a, &b) != 2) {
2451                                 sscanf(arg, "%d", &b);
2452                         }
2453                 }
2454                 if (a <= 0) {
2455                         a = 1;
2456                 }
2457                 obj->data.pair.a = a;
2458                 obj->data.pair.b = b;
2459 #endif /* X11 */
2460         END OBJ(swap, INFO_MEM)
2461         END OBJ(swapfree, INFO_MEM)
2462         END OBJ(swapmax, INFO_MEM)
2463         END OBJ(swapperc, INFO_MEM)
2464         END OBJ(swapbar, INFO_MEM)
2465                 SIZE_DEFAULTS(bar);
2466                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2467         END OBJ(sysname, 0)
2468         END OBJ(time, 0)
2469                 obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
2470         END OBJ(utime, 0)
2471                 obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
2472         END OBJ(tztime, 0)
2473                 char buf1[256], buf2[256], *fmt, *tz;
2474
2475                 fmt = tz = NULL;
2476                 if (arg) {
2477                         int nArgs = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
2478
2479                         switch (nArgs) {
2480                                 case 2:
2481                                         tz = buf1;
2482                                 case 1:
2483                                         fmt = buf2;
2484                         }
2485                 }
2486
2487                 obj->data.tztime.fmt = strndup(fmt ? fmt : "%F %T", text_buffer_size);
2488                 obj->data.tztime.tz = tz ? strndup(tz, text_buffer_size) : NULL;
2489 #ifdef HAVE_ICONV
2490         END OBJ(iconv_start, 0)
2491                 if (iconv_converting) {
2492                         CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before "
2493                                 "starting another");
2494                 }
2495                 if (arg) {
2496                         char iconv_from[CODEPAGE_LENGTH];
2497                         char iconv_to[CODEPAGE_LENGTH];
2498
2499                         if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) {
2500                                 CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start");
2501                         } else {
2502                                 iconv_t new_iconv;
2503
2504                                 new_iconv = iconv_open(iconv_to, iconv_from);
2505                                 if (new_iconv == (iconv_t) (-1)) {
2506                                         ERR("Can't convert from %s to %s.", iconv_from, iconv_to);
2507                                 } else {
2508                                         obj->a = register_iconv(&new_iconv);
2509                                         iconv_converting = 1;
2510                                 }
2511                         }
2512                 } else {
2513                         CRIT_ERR(obj, free_at_crash, "Iconv requires arguments");
2514                 }
2515         END OBJ(iconv_stop, 0)
2516                 iconv_converting = 0;
2517
2518 #endif
2519         END OBJ(totaldown, INFO_NET)
2520                 if (arg) {
2521                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2522                 } else {
2523                         // default to DEFAULTNETDEV
2524                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2525                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2526                         free(buf);
2527                 }
2528         END OBJ(totalup, INFO_NET)
2529                 obj->data.net = get_net_stat(arg, obj, free_at_crash);
2530                 if (arg) {
2531                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2532                 } else {
2533                         // default to DEFAULTNETDEV
2534                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2535                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2536                         free(buf);
2537                 }
2538         END OBJ(updates, 0)
2539         END OBJ_IF(if_updatenr, 0)
2540                 obj->data.ifblock.i = arg ? atoi(arg) : 0;
2541                 if(obj->data.ifblock.i == 0) CRIT_ERR(obj, free_at_crash, "if_updatenr needs a number above 0 as argument");
2542                 updatereset = obj->data.ifblock.i > updatereset ? obj->data.ifblock.i : updatereset;
2543         END OBJ(alignr, 0)
2544                 obj->data.i = arg ? atoi(arg) : 0;
2545         END OBJ(alignc, 0)
2546                 obj->data.i = arg ? atoi(arg) : 0;
2547         END OBJ(upspeed, INFO_NET)
2548                 if (arg) {
2549                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2550                 } else {
2551                         // default to DEFAULTNETDEV
2552                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2553                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2554                         free(buf);
2555                 }
2556         END OBJ(upspeedf, INFO_NET)
2557                 if (arg) {
2558                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
2559                 } else {
2560                         // default to DEFAULTNETDEV
2561                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
2562                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
2563                         free(buf);
2564                 }
2565
2566 #ifdef X11
2567         END OBJ(upspeedgraph, INFO_NET)
2568                 char *buf = 0;
2569                 SIZE_DEFAULTS(graph);
2570                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
2571                                 &obj->e, &obj->char_a, &obj->char_b);
2572
2573                 // default to DEFAULTNETDEV
2574                 buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
2575                 obj->data.net = get_net_stat(buf, obj, free_at_crash);
2576                 free(buf);
2577 #endif
2578         END OBJ(uptime_short, INFO_UPTIME)
2579         END OBJ(uptime, INFO_UPTIME)
2580         END OBJ(user_names, INFO_USERS)
2581         END OBJ(user_times, INFO_USERS)
2582         END OBJ(user_terms, INFO_USERS)
2583         END OBJ(user_number, INFO_USERS)
2584 #if defined(__linux__)
2585         END OBJ(gw_iface, INFO_GW)
2586         END OBJ(gw_ip, INFO_GW)
2587 #endif /* !__linux__ */
2588 #ifndef __OpenBSD__
2589         END OBJ(adt746xcpu, 0)
2590         END OBJ(adt746xfan, 0)
2591 #endif /* !__OpenBSD__ */
2592 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
2593                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
2594         END OBJ(apm_adapter, 0)
2595         END OBJ(apm_battery_life, 0)
2596         END OBJ(apm_battery_time, 0)
2597 #endif /* __FreeBSD__ */
2598         END OBJ_THREAD(imap_unseen, 0)
2599                 if (arg) {
2600                         // proccss
2601                         obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
2602                         obj->char_b = 0;
2603                 } else {
2604                         obj->char_b = 1;
2605                 }
2606         END OBJ_THREAD(imap_messages, 0)
2607                 if (arg) {
2608                         // proccss
2609                         obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
2610                         obj->char_b = 0;
2611                 } else {
2612                         obj->char_b = 1;
2613                 }
2614         END OBJ_THREAD(pop3_unseen, 0)
2615                 if (arg) {
2616                         // proccss
2617                         obj->data.mail = parse_mail_args(POP3_TYPE, arg);
2618                         obj->char_b = 0;
2619                 } else {
2620                         obj->char_b = 1;
2621                 }
2622         END OBJ_THREAD(pop3_used, 0)
2623                 if (arg) {
2624                         // proccss
2625                         obj->data.mail = parse_mail_args(POP3_TYPE, arg);
2626                         obj->char_b = 0;
2627                 } else {
2628                         obj->char_b = 1;
2629                 }
2630 #ifdef IBM
2631         END OBJ(smapi, 0)
2632                 if (arg)
2633                         obj->data.s = strndup(arg, text_buffer_size);
2634                 else
2635                         ERR("smapi needs an argument");
2636         END OBJ_IF(if_smapi_bat_installed, 0)
2637                 if (!arg) {
2638                         ERR("if_smapi_bat_installed needs an argument");
2639                         obj->data.ifblock.s = 0;
2640                 } else
2641                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
2642         END OBJ(smapi_bat_perc, 0)
2643                 if (arg)
2644                         obj->data.s = strndup(arg, text_buffer_size);
2645                 else
2646                         ERR("smapi_bat_perc needs an argument");
2647         END OBJ(smapi_bat_temp, 0)
2648                 if (arg)
2649                         obj->data.s = strndup(arg, text_buffer_size);
2650                 else
2651                         ERR("smapi_bat_temp needs an argument");
2652         END OBJ(smapi_bat_power, 0)
2653                 if (arg)
2654                         obj->data.s = strndup(arg, text_buffer_size);
2655                 else
2656                         ERR("smapi_bat_power needs an argument");
2657 #ifdef X11
2658         END OBJ(smapi_bat_bar, 0)
2659                 SIZE_DEFAULTS(bar);
2660                 if(arg) {
2661                         int cnt;
2662                         if(sscanf(arg, "%i %n", &obj->data.i, &cnt) <= 0) {
2663                                 ERR("first argument to smapi_bat_bar must be an integer value");
2664                                 obj->data.i = -1;
2665                         } else {
2666                                 obj->b = 4;
2667                                 arg = scan_bar(arg + cnt, &obj->a, &obj->b);
2668                         }
2669                 } else
2670                         ERR("smapi_bat_bar needs an argument");
2671 #endif /* X11 */
2672 #endif /* IBM */
2673 #ifdef MPD
2674 #define mpd_set_maxlen(name) \
2675                 if (arg) { \
2676                         int i; \
2677                         sscanf(arg, "%d", &i); \
2678                         if (i > 0) \
2679                                 obj->data.i = i + 1; \
2680                         else \
2681                                 ERR(#name ": invalid length argument"); \
2682                 }
2683         END OBJ(mpd_artist, INFO_MPD)
2684                 mpd_set_maxlen(mpd_artist);
2685                 init_mpd();
2686         END OBJ(mpd_title, INFO_MPD)
2687                 mpd_set_maxlen(mpd_title);
2688                 init_mpd();
2689         END OBJ(mpd_random, INFO_MPD) init_mpd();
2690         END OBJ(mpd_repeat, INFO_MPD) init_mpd();
2691         END OBJ(mpd_elapsed, INFO_MPD) init_mpd();
2692         END OBJ(mpd_length, INFO_MPD) init_mpd();
2693         END OBJ(mpd_track, INFO_MPD)
2694                 mpd_set_maxlen(mpd_track);
2695                 init_mpd();
2696         END OBJ(mpd_name, INFO_MPD)
2697                 mpd_set_maxlen(mpd_name);
2698                 init_mpd();
2699         END OBJ(mpd_file, INFO_MPD)
2700                 mpd_set_maxlen(mpd_file);
2701                 init_mpd();
2702         END OBJ(mpd_percent, INFO_MPD) init_mpd();
2703         END OBJ(mpd_album, INFO_MPD)
2704                 mpd_set_maxlen(mpd_album);
2705                 init_mpd();
2706         END OBJ(mpd_vol, INFO_MPD) init_mpd();
2707         END OBJ(mpd_bitrate, INFO_MPD) init_mpd();
2708         END OBJ(mpd_status, INFO_MPD) init_mpd();
2709         END OBJ(mpd_bar, INFO_MPD)
2710                 SIZE_DEFAULTS(bar);
2711                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2712                 init_mpd();
2713         END OBJ(mpd_smart, INFO_MPD)
2714                 mpd_set_maxlen(mpd_smart);
2715                 init_mpd();
2716         END OBJ_IF(if_mpd_playing, INFO_MPD)
2717                 init_mpd();
2718 #undef mpd_set_maxlen
2719 #endif /* MPD */
2720 #ifdef MOC
2721         END OBJ(moc_state, INFO_MOC)
2722         END OBJ(moc_file, INFO_MOC)
2723         END OBJ(moc_title, INFO_MOC)
2724         END OBJ(moc_artist, INFO_MOC)
2725         END OBJ(moc_song, INFO_MOC)
2726         END OBJ(moc_album, INFO_MOC)
2727         END OBJ(moc_totaltime, INFO_MOC)
2728         END OBJ(moc_timeleft, INFO_MOC)
2729         END OBJ(moc_curtime, INFO_MOC)
2730         END OBJ(moc_bitrate, INFO_MOC)
2731         END OBJ(moc_rate, INFO_MOC)
2732 #endif /* MOC */
2733 #ifdef XMMS2
2734         END OBJ(xmms2_artist, INFO_XMMS2)
2735         END OBJ(xmms2_album, INFO_XMMS2)
2736         END OBJ(xmms2_title, INFO_XMMS2)
2737         END OBJ(xmms2_genre, INFO_XMMS2)
2738         END OBJ(xmms2_comment, INFO_XMMS2)
2739         END OBJ(xmms2_url, INFO_XMMS2)
2740         END OBJ(xmms2_tracknr, INFO_XMMS2)
2741         END OBJ(xmms2_bitrate, INFO_XMMS2)
2742         END OBJ(xmms2_date, INFO_XMMS2)
2743         END OBJ(xmms2_id, INFO_XMMS2)
2744         END OBJ(xmms2_duration, INFO_XMMS2)
2745         END OBJ(xmms2_elapsed, INFO_XMMS2)
2746         END OBJ(xmms2_size, INFO_XMMS2)
2747         END OBJ(xmms2_status, INFO_XMMS2)
2748         END OBJ(xmms2_percent, INFO_XMMS2)
2749 #ifdef X11
2750         END OBJ(xmms2_bar, INFO_XMMS2)
2751                 SIZE_DEFAULTS(bar);
2752                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
2753 #endif /* X11 */
2754         END OBJ(xmms2_smart, INFO_XMMS2)
2755         END OBJ(xmms2_playlist, INFO_XMMS2)
2756         END OBJ(xmms2_timesplayed, INFO_XMMS2)
2757         END OBJ_IF(if_xmms2_connected, INFO_XMMS2)
2758 #endif
2759 #ifdef AUDACIOUS
2760         END OBJ(audacious_status, INFO_AUDACIOUS)
2761         END OBJ(audacious_title, INFO_AUDACIOUS)
2762                 if (arg) {
2763                         sscanf(arg, "%d", &info.audacious.max_title_len);
2764                         if (info.audacious.max_title_len > 0) {
2765                                 info.audacious.max_title_len++;
2766                         } else {
2767                                 CRIT_ERR(obj, free_at_crash, "audacious_title: invalid length argument");
2768                         }
2769                 }
2770         END OBJ(audacious_length, INFO_AUDACIOUS)
2771         END OBJ(audacious_length_seconds, INFO_AUDACIOUS)
2772         END OBJ(audacious_position, INFO_AUDACIOUS)
2773         END OBJ(audacious_position_seconds, INFO_AUDACIOUS)
2774         END OBJ(audacious_bitrate, INFO_AUDACIOUS)
2775         END OBJ(audacious_frequency, INFO_AUDACIOUS)
2776         END OBJ(audacious_channels, INFO_AUDACIOUS)
2777         END OBJ(audacious_filename, INFO_AUDACIOUS)
2778         END OBJ(audacious_playlist_length, INFO_AUDACIOUS)
2779         END OBJ(audacious_playlist_position, INFO_AUDACIOUS)
2780         END OBJ(audacious_main_volume, INFO_AUDACIOUS)
2781 #ifdef X11
2782         END OBJ(audacious_bar, INFO_AUDACIOUS)
2783                 SIZE_DEFAULTS(bar);
2784                 scan_bar(arg, &obj->a, &obj->b);
2785 #endif /* X11 */
2786 #endif
2787 #ifdef BMPX
2788         END OBJ(bmpx_title, INFO_BMPX)
2789                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2790         END OBJ(bmpx_artist, INFO_BMPX)
2791                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2792         END OBJ(bmpx_album, INFO_BMPX)
2793                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2794         END OBJ(bmpx_track, INFO_BMPX)
2795                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2796         END OBJ(bmpx_uri, INFO_BMPX)
2797                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2798         END OBJ(bmpx_bitrate, INFO_BMPX)
2799                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
2800 #endif
2801 #ifdef EVE
2802         END OBJ(eve, 0)
2803                 if(arg) {
2804                         int argc;
2805                         char *userid = (char *) malloc(20 * sizeof(char));
2806                         char *apikey = (char *) malloc(64 * sizeof(char));
2807                         char *charid = (char *) malloc(20 * sizeof(char));
2808
2809                         argc = sscanf(arg, "%20s %64s %20s", userid, apikey, charid);
2810                         obj->data.eve.charid = charid;
2811                         obj->data.eve.userid = userid;
2812                         obj->data.eve.apikey = apikey;
2813
2814                         init_eve();
2815                 } else {
2816                         CRIT_ERR(obj, free_at_crash, "eve needs arguments: <userid> <apikey> <characterid>");
2817                 }
2818 #endif
2819 #ifdef RSS
2820         END OBJ(rss, 0)
2821                 if (arg) {
2822                         int argc, delay, act_par;
2823                         unsigned int nrspaces = 0;
2824                         char *uri = (char *) malloc(128 * sizeof(char));
2825                         char *action = (char *) malloc(64 * sizeof(char));
2826
2827                         argc = sscanf(arg, "%127s %d %63s %d %u", uri, &delay, action,
2828                                         &act_par, &nrspaces);
2829                         obj->data.rss.uri = uri;
2830                         obj->data.rss.delay = delay;
2831                         obj->data.rss.action = action;
2832                         obj->data.rss.act_par = act_par;
2833                         obj->data.rss.nrspaces = nrspaces;
2834
2835                         init_rss_info();
2836                 } else {
2837                         CRIT_ERR(obj, free_at_crash, "rss needs arguments: <uri> <delay in minutes> <action> "
2838                                         "[act_par] [spaces in front]");
2839                 }
2840 #endif
2841 #ifdef WEATHER
2842         END OBJ_THREAD(weather, 0)
2843                 if (arg) {
2844                         int argc, interval;
2845                         char *locID = (char *) malloc(9 * sizeof(char));
2846                         char *uri = (char *) malloc(128 * sizeof(char));
2847                         char *data_type = (char *) malloc(32 * sizeof(char));
2848                         char *tmp_p;
2849
2850                         argc = sscanf(arg, "%119s %8s %31s %d", uri, locID, data_type, &interval);
2851
2852                         //locID MUST BE upper-case
2853                         tmp_p = locID;
2854                         while (*tmp_p) {
2855                           *tmp_p = toupper(*tmp_p);
2856                           tmp_p++;
2857                         }
2858
2859                         //Construct complete uri
2860                         if (strstr(uri, "xoap.weather.com")) {
2861                           if(xoap != NULL) {
2862                             strcat(uri, locID);
2863                             strcat(uri, xoap);
2864                           } else {
2865                             free(uri);
2866                             uri = NULL;
2867                           }
2868                         } else if (strstr(uri, "weather.noaa.gov")) {
2869                             strcat(uri, locID);
2870                             strcat(uri, ".TXT");
2871                         } else  if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
2872                               CRIT_ERR(obj, free_at_crash, \
2873                                        "could not recognize the weather uri");
2874                         }
2875
2876                         obj->data.weather.uri = uri;
2877                         obj->data.weather.data_type = data_type;
2878
2879                         //Limit the data retrieval interval to half hour min
2880                         if (interval < 30) {
2881                                 interval = 30;
2882                         }
2883
2884                         //Convert to seconds
2885                         obj->data.weather.interval = interval * 60;
2886                         free(locID);
2887
2888                         DBGP("weather: fetching %s from %s every %d seconds", \
2889                              data_type, uri, obj->data.weather.interval);
2890                 } else {
2891                         CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <locID> <data_type> [interval in minutes]");
2892                 }
2893 #endif
2894 #ifdef HAVE_LUA
2895         END OBJ(lua, 0)
2896                 if (arg) {
2897                         obj->data.s = strndup(arg, text_buffer_size);
2898                 } else {
2899                         CRIT_ERR(obj, free_at_crash, "lua needs arguments: <function name> [function parameters]");
2900                 }
2901         END OBJ(lua_parse, 0)
2902                 if (arg) {
2903                         obj->data.s = strndup(arg, text_buffer_size);
2904                 } else {
2905                         CRIT_ERR(obj, free_at_crash, "lua_parse needs arguments: <function name> [function parameters]");
2906                 }
2907         END OBJ(lua_bar, 0)
2908                 SIZE_DEFAULTS(bar);
2909                 if (arg) {
2910                         arg = scan_bar(arg, &obj->a, &obj->b);
2911                         if(arg) {
2912                                 obj->data.s = strndup(arg, text_buffer_size);
2913                         } else {
2914                                 CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
2915                         }
2916                 } else {
2917                         CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
2918                 }
2919 #ifdef X11
2920         END OBJ(lua_graph, 0)
2921                 SIZE_DEFAULTS(graph);
2922                 if (arg) {
2923                         char *buf = 0;
2924                         buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
2925                                         &obj->e, &obj->char_a, &obj->char_b);
2926                         if (buf) {
2927                                 obj->data.s = buf;
2928                         } else {
2929                                 CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
2930                         }
2931                 } else {
2932                         CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
2933         }
2934         END OBJ(lua_gauge, 0)
2935                 SIZE_DEFAULTS(gauge);
2936                 if (arg) {
2937                         arg = scan_gauge(arg, &obj->a, &obj->b);
2938                         if (arg) {
2939                                 obj->data.s = strndup(arg, text_buffer_size);
2940                         } else {
2941                                 CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
2942                         }
2943                 } else {
2944                         CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
2945                 }
2946 #endif /* X11 */
2947 #endif /* HAVE_LUA */
2948 #ifdef HDDTEMP
2949         END OBJ(hddtemp, 0)
2950                 if (scan_hddtemp(arg, &obj->data.hddtemp.dev,
2951                                  &obj->data.hddtemp.addr, &obj->data.hddtemp.port)) {
2952                         ERR("hddtemp needs arguments");
2953                         obj->type = OBJ_text;
2954                         obj->data.s = strndup("${hddtemp}", text_buffer_size);
2955                         obj->data.hddtemp.update_time = 0;
2956                 } else
2957                         obj->data.hddtemp.temp = NULL;
2958 #endif /* HDDTEMP */
2959 #ifdef TCP_PORT_MONITOR
2960         END OBJ(tcp_portmon, INFO_TCP_PORT_MONITOR)
2961                 tcp_portmon_init(arg, &obj->data.tcp_port_monitor);
2962 #endif /* TCP_PORT_MONITOR */
2963         END OBJ(entropy_avail, INFO_ENTROPY)
2964         END OBJ(entropy_perc, INFO_ENTROPY)
2965         END OBJ(entropy_poolsize, INFO_ENTROPY)
2966         END OBJ(entropy_bar, INFO_ENTROPY)
2967                 SIZE_DEFAULTS(bar);
2968                 scan_bar(arg, &obj->a, &obj->b);
2969         END OBJ(blink, 0)
2970                 if(arg) {
2971                         obj->sub = malloc(sizeof(struct text_object));
2972                         extract_variable_text_internal(obj->sub, arg, 0);
2973                 }else{
2974                         CRIT_ERR(obj, free_at_crash, "blink needs a argument");
2975                 }
2976         END OBJ(to_bytes, 0)
2977                 if(arg) {
2978                         obj->sub = malloc(sizeof(struct text_object));
2979                         extract_variable_text_internal(obj->sub, arg, 0);
2980                 }else{
2981                         CRIT_ERR(obj, free_at_crash, "to_bytes needs a argument");
2982                 }
2983         END OBJ(scroll, 0)
2984                 int n1 = 0, n2 = 0;
2985
2986                 obj->data.scroll.resetcolor = current_text_color;
2987                 obj->data.scroll.step = 1;
2988                 if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
2989                         sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2);
2990                         if (*(arg + n1 + n2)) {
2991                                 n1 += n2;
2992                         } else {
2993                                 obj->data.scroll.step = 1;
2994                         }
2995                         obj->data.scroll.text = malloc(strlen(arg + n1) + obj->data.scroll.show + 1);
2996                         for(n2 = 0; (unsigned int) n2 < obj->data.scroll.show; n2++) {
2997                                 obj->data.scroll.text[n2] = ' ';
2998                         }
2999                         obj->data.scroll.text[n2] = 0;
3000                         strcat(obj->data.scroll.text, arg + n1);
3001                         obj->data.scroll.start = 0;
3002                         obj->sub = malloc(sizeof(struct text_object));
3003                         extract_variable_text_internal(obj->sub,
3004                                         obj->data.scroll.text, 0);
3005                 } else {
3006                         CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
3007                 }
3008         END OBJ(combine, 0)
3009                 if(arg) {
3010                         unsigned int i,j;
3011                         unsigned int indenting = 0;     //vars can be used as args for other vars
3012                         int startvar[2];
3013                         int endvar[2];
3014                         startvar[0] = endvar[0] = startvar[1] = endvar[1] = -1;
3015                         j=0;
3016                         for (i=0; arg[i] != 0 && j < 2; i++) {
3017                                 if(startvar[j] == -1) {
3018                                         if(arg[i] == '$') {
3019                                                 startvar[j] = i;
3020                                         }
3021                                 }else if(endvar[j] == -1) {
3022                                         if(arg[i] == '{') {
3023                                                 indenting++;
3024                                         }else if(arg[i] == '}') {
3025                                                 indenting--;
3026                                         }
3027                                         if (indenting == 0 && arg[i+1] < 48) {  //<48 has 0, $, and the most used chars not used in varnames but not { or }
3028                                                 endvar[j]=i+1;
3029                                                 j++;
3030                                         }
3031                                 }
3032                         }
3033                         if(startvar[0] >= 0 && endvar[0] >= 0 && startvar[1] >= 0 && endvar[1] >= 0) {
3034                                 obj->data.combine.left = malloc(endvar[0]-startvar[0] + 1);
3035                                 obj->data.combine.seperation = malloc(startvar[1] - endvar[0] + 1);
3036                                 obj->data.combine.right= malloc(endvar[1]-startvar[1] + 1);
3037                                 
3038                                 strncpy(obj->data.combine.left, arg + startvar[0], endvar[0] - startvar[0]);
3039                                 obj->data.combine.left[endvar[0] - startvar[0]] = 0;
3040                                 
3041                                 strncpy(obj->data.combine.seperation, arg + endvar[0], startvar[1] - endvar[0]);
3042                                 obj->data.combine.seperation[startvar[1] - endvar[0]] = 0;
3043                                 
3044                                 strncpy(obj->data.combine.right, arg + startvar[1], endvar[1] - startvar[1]);
3045                                 obj->data.combine.right[endvar[1] - startvar[1]] = 0;
3046
3047                                 obj->sub = malloc(sizeof(struct text_object));
3048                                 extract_variable_text_internal(obj->sub, obj->data.combine.left, 0);
3049                                 obj->sub->sub = malloc(sizeof(struct text_object));
3050                                 extract_variable_text_internal(obj->sub->sub, obj->data.combine.right, 0);
3051                         } else {
3052                                 CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
3053                         }
3054                 } else {
3055                         CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
3056                 }
3057 #ifdef NVIDIA
3058         END OBJ(nvidia, 0)
3059                 if (!arg) {
3060                         CRIT_ERR(obj, free_at_crash, "nvidia needs an argument\n");
3061                 } else if (set_nvidia_type(&obj->data.nvidia, arg)) {
3062                         CRIT_ERR(obj, free_at_crash, "nvidia: invalid argument"
3063                                  " specified: '%s'\n", arg);
3064                 }
3065 #endif /* NVIDIA */
3066 #ifdef APCUPSD
3067                 init_apcupsd();
3068                 END OBJ(apcupsd, INFO_APCUPSD)
3069                         if (arg) {
3070                                 char host[64];
3071                                 int port;
3072                                 if (sscanf(arg, "%63s %d", host, &port) != 2) {
3073                                         CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
3074                                 } else {
3075                                         info.apcupsd.port = htons(port);
3076                                         strncpy(info.apcupsd.host, host, sizeof(info.apcupsd.host));
3077                                 }
3078                         } else {
3079                                 CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
3080                         }
3081                         END OBJ(apcupsd_name, INFO_APCUPSD)
3082                         END OBJ(apcupsd_model, INFO_APCUPSD)
3083                         END OBJ(apcupsd_upsmode, INFO_APCUPSD)
3084                         END OBJ(apcupsd_cable, INFO_APCUPSD)
3085                         END OBJ(apcupsd_status, INFO_APCUPSD)
3086                         END OBJ(apcupsd_linev, INFO_APCUPSD)
3087                         END OBJ(apcupsd_load, INFO_APCUPSD)
3088                         END OBJ(apcupsd_loadbar, INFO_APCUPSD)
3089                                 SIZE_DEFAULTS(bar);
3090                                 scan_bar(arg, &obj->a, &obj->b);
3091 #ifdef X11
3092                         END OBJ(apcupsd_loadgraph, INFO_APCUPSD)
3093                                 char* buf = 0;
3094                                 SIZE_DEFAULTS(graph);
3095                                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
3096                                                 &obj->e, &obj->char_a, &obj->char_b);
3097                                 if (buf) free(buf);
3098                         END OBJ(apcupsd_loadgauge, INFO_APCUPSD)
3099                                 SIZE_DEFAULTS(gauge);
3100                                 scan_gauge(arg, &obj->a, &obj->b);
3101 #endif /* X11 */
3102                         END OBJ(apcupsd_charge, INFO_APCUPSD)
3103                         END OBJ(apcupsd_timeleft, INFO_APCUPSD)
3104                         END OBJ(apcupsd_temp, INFO_APCUPSD)
3105                         END OBJ(apcupsd_lastxfer, INFO_APCUPSD)
3106 #endif /* APCUPSD */
3107         END {
3108                 char buf[256];
3109
3110                 ERR("unknown variable %s", s);
3111                 obj->type = OBJ_text;
3112                 snprintf(buf, 256, "${%s}", s);
3113                 obj->data.s = strndup(buf, text_buffer_size);
3114         }
3115 #undef OBJ
3116
3117         return obj;
3118 }
3119
3120 static struct text_object *create_plain_text(const char *s)
3121 {
3122         struct text_object *obj;
3123
3124         if (s == NULL || *s == '\0') {
3125                 return NULL;
3126         }
3127
3128         obj = new_text_object_internal();
3129
3130         obj->type = OBJ_text;
3131         obj->data.s = strndup(s, text_buffer_size);
3132         return obj;
3133 }
3134
3135 /* backslash_escape - do the actual substitution task for template objects
3136  *
3137  * The field templates is used for substituting the \N occurences. Set it to
3138  * NULL to leave them as they are.
3139  */
3140 static char *backslash_escape(const char *src, char **templates, unsigned int template_count)
3141 {
3142         char *src_dup;
3143         const char *p;
3144         unsigned int dup_idx = 0, dup_len;
3145
3146         dup_len = strlen(src) + 1;
3147         src_dup = malloc(dup_len * sizeof(char));
3148
3149         p = src;
3150         while (*p) {
3151                 switch (*p) {
3152                 case '\\':
3153                         if (!*(p + 1))
3154                                 break;
3155                         if (*(p + 1) == '\\') {
3156                                 src_dup[dup_idx++] = '\\';
3157                                 p++;
3158                         } else if (*(p + 1) == ' ') {
3159                                 src_dup[dup_idx++] = ' ';
3160                                 p++;
3161                         } else if (*(p + 1) == 'n') {
3162                                 src_dup[dup_idx++] = '\n';
3163                                 p++;
3164                         } else if (templates) {
3165                                 unsigned int tmpl_num;
3166                                 int digits;
3167                                 if ((sscanf(p + 1, "%u%n", &tmpl_num, &digits) <= 0) ||
3168                                     (tmpl_num > template_count))
3169                                         break;
3170                                 dup_len += strlen(templates[tmpl_num - 1]);
3171                                 src_dup = realloc(src_dup, dup_len * sizeof(char));
3172                                 sprintf(src_dup + dup_idx, "%s", templates[tmpl_num - 1]);
3173                                 dup_idx += strlen(templates[tmpl_num - 1]);
3174                                 p += digits;
3175                         }
3176                         break;
3177                 default:
3178                         src_dup[dup_idx++] = *p;
3179                         break;
3180                 }
3181                 p++;
3182         }
3183         src_dup[dup_idx] = '\0';
3184         src_dup = realloc(src_dup, (strlen(src_dup) + 1) * sizeof(char));
3185         return src_dup;
3186 }
3187
3188 /* handle_template_object - core logic of the template object
3189  *
3190  * use config variables like this:
3191  * template1 = "$\1\2"
3192  * template2 = "\1: ${fs_bar 4,100 \2} ${fs_used \2} / ${fs_size \2}"
3193  *
3194  * and use them like this:
3195  * ${template1 node name}
3196  * ${template2 root /}
3197  * ${template2 cdrom /mnt/cdrom}
3198  */
3199 static char *handle_template(const char *tmpl, const char *args)
3200 {
3201         char *args_dup = NULL;
3202         char *p, *p_old;
3203         char **argsp = NULL;
3204         unsigned int argcnt = 0, template_idx, i;
3205         char *eval_text;
3206
3207         if ((sscanf(tmpl, "template%u", &template_idx) != 1) ||
3208             (template_idx >= MAX_TEMPLATES))
3209                 return NULL;
3210
3211         if(args) {
3212                 args_dup = strdup(args);
3213                 p = args_dup;
3214                 while (*p) {
3215                         while (*p && (*p == ' ' && (p == args_dup || *(p - 1) != '\\')))
3216                                 p++;
3217                         if (p > args_dup && *(p - 1) == '\\')
3218                                 p--;
3219                         p_old = p;
3220                         while (*p && (*p != ' ' || (p > args_dup && *(p - 1) == '\\')))
3221                                 p++;
3222                         if (*p) {
3223                                 (*p) = '\0';
3224                                 p++;
3225                         }
3226                         argsp = realloc(argsp, ++argcnt * sizeof(char *));
3227                         argsp[argcnt - 1] = p_old;
3228                 }
3229                 for (i = 0; i < argcnt; i++) {
3230                         char *tmp;
3231                         tmp = backslash_escape(argsp[i], NULL, 0);
3232                         DBGP2("%s: substituted arg '%s' to '%s'", tmpl, argsp[i], tmp);
3233                         argsp[i] = tmp;
3234                 }
3235         }
3236
3237         eval_text = backslash_escape(template[template_idx], argsp, argcnt);
3238         DBGP("substituted %s, output is '%s'", tmpl, eval_text);
3239         free(args_dup);
3240         for (i = 0; i < argcnt; i++)
3241                 free(argsp[i]);
3242         free(argsp);
3243         return eval_text;
3244 }
3245
3246 static char *find_and_replace_templates(const char *inbuf)
3247 {
3248         char *outbuf, *indup, *p, *o, *templ, *args, *tmpl_out;
3249         int stack, outlen;
3250
3251         outlen = strlen(inbuf) + 1;
3252         o = outbuf = calloc(outlen, sizeof(char));
3253         memset(outbuf, 0, outlen * sizeof(char));
3254
3255         p = indup = strdup(inbuf);
3256         while (*p) {
3257                 while (*p && *p != '$')
3258                         *(o++) = *(p++);
3259
3260                 if (!(*p))
3261                         break;
3262
3263                 if (strncmp(p, "$template", 9) && strncmp(p, "${template", 10)) {
3264                         *(o++) = *(p++);
3265                         continue;
3266                 }
3267
3268                 if (*(p + 1) == '{') {
3269                         p += 2;
3270                         templ = p;
3271                         while (*p && !isspace(*p) && *p != '{' && *p != '}')
3272                                 p++;
3273                         if (*p == '}')
3274                                 args = NULL;
3275                         else
3276                                 args = p;
3277
3278                         stack = 1;
3279                         while (*p && stack > 0) {
3280                                 if (*p == '{')
3281                                         stack++;
3282                                 else if (*p == '}')
3283                                         stack--;
3284                                 p++;
3285                         }
3286                         if (stack == 0) {
3287                                 // stack is empty. that means the previous char was }, so we zero it
3288                                 *(p - 1) = '\0';
3289                         } else {
3290                                 // we ran into the end of string without finding a closing }, bark
3291                                 CRIT_ERR(NULL, NULL, "cannot find a closing '}' in template expansion");
3292                         }
3293                 } else {
3294                         templ = p + 1;
3295                         while (*p && !isspace(*p))
3296                                 p++;
3297                         args = NULL;
3298                 }
3299                 tmpl_out = handle_template(templ, args);
3300                 if (tmpl_out) {
3301                         outlen += strlen(tmpl_out);
3302                         *o = '\0';
3303                         outbuf = realloc(outbuf, outlen * sizeof(char));
3304                         strcat (outbuf, tmpl_out);
3305                         free(tmpl_out);
3306                         o = outbuf + strlen(outbuf);
3307                 } else {
3308                         ERR("failed to handle template '%s' with args '%s'", templ, args);
3309                 }
3310         }
3311         *o = '\0';
3312         outbuf = realloc(outbuf, (strlen(outbuf) + 1) * sizeof(char));
3313         free(indup);
3314         return outbuf;
3315 }
3316
3317 static int text_contains_templates(const char *text)
3318 {
3319         if (strcasestr(text, "${template") != NULL)
3320                 return 1;
3321         if (strcasestr(text, "$template") != NULL)
3322                 return 1;
3323         return 0;
3324 }
3325
3326 /* folds a string over top of itself, like so:
3327  *
3328  * if start is "blah", and you call it with count = 1, the result will be "lah"
3329  */
3330 static void strfold(char *start, int count)
3331 {
3332         char *curplace;
3333         for (curplace = start + count; *curplace != 0; curplace++) {
3334                 *(curplace - count) = *curplace;
3335         }
3336         *(curplace - count) = 0;
3337 }
3338
3339 /*
3340  * - assumes that *string is '#'
3341  * - removes the part from '#' to the end of line ('\n' or '\0')
3342  * - it removes the '\n'
3343  * - copies the last char into 'char *last' argument, which should be a pointer
3344  *   to a char rather than a string.
3345  */
3346 static size_t remove_comment(char *string, char *last)
3347 {
3348         char *end = string;
3349         while (*end != '\0' && *end != '\n') {
3350                 ++end;
3351         }
3352         if (last) *last = *end;
3353         if (*end == '\n') end++;
3354         strfold(string, end - string);
3355         return end - string;
3356 }
3357
3358 static size_t remove_comments(char *string)
3359 {
3360         char *curplace;
3361         size_t folded = 0;
3362         for (curplace = string; *curplace != 0; curplace++) {
3363                 if (*curplace == '\\' && *(curplace + 1) == '#') {
3364                         // strcpy can't be used for overlapping strings
3365                         strfold(curplace, 1);
3366                         folded += 1;
3367                 } else if (*curplace == '#') {
3368                         folded += remove_comment(curplace, 0);
3369                 }
3370         }
3371         return folded;
3372 }
3373
3374 static int extract_variable_text_internal(struct text_object *retval, const char *const_p, char allow_threaded)
3375 {
3376         struct text_object *obj;
3377         char *p, *s, *orig_p;
3378         long line;
3379         void *ifblock_opaque = NULL;
3380         char *tmp_p;
3381         char *arg = 0;
3382         size_t len = 0;
3383
3384         p = strndup(const_p, max_user_text - 1);
3385         while (text_contains_templates(p)) {
3386                 char *tmp;
3387                 tmp = find_and_replace_templates(p);
3388                 free(p);
3389                 p = tmp;
3390         }
3391         s = orig_p = p;
3392
3393         if (strcmp(p, const_p)) {
3394                 DBGP("replaced all templates in text: input is\n'%s'\noutput is\n'%s'", const_p, p);
3395         } else {
3396                 DBGP("no templates to replace");
3397         }
3398
3399         memset(retval, 0, sizeof(struct text_object));
3400
3401         line = global_text_lines;
3402
3403         while (*p) {
3404                 if (*p == '\n') {
3405                         line++;
3406                 }
3407                 if (*p == '$') {
3408                         *p = '\0';
3409                         obj = create_plain_text(s);
3410                         if (obj != NULL) {
3411                                 append_object(retval, obj);
3412                         }
3413                         *p = '$';
3414                         p++;
3415                         s = p;
3416
3417                         if (*p != '$') {
3418                                 char buf[256];
3419                                 const char *var;
3420
3421                                 /* variable is either $foo or ${foo} */
3422                                 if (*p == '{') {
3423                                         unsigned int brl = 1, brr = 0;
3424
3425                                         p++;
3426                                         s = p;
3427                                         while (*p && brl != brr) {
3428                                                 if (*p == '{') {
3429                                                         brl++;
3430                                                 }
3431                                                 if (*p == '}') {
3432                                                         brr++;
3433                                                 }
3434                                                 p++;
3435                                         }
3436                                         p--;
3437                                 } else {
3438                                         s = p;
3439                                         if (*p == '#') {
3440                                                 p++;
3441                                         }
3442                                         while (*p && (isalnum((int) *p) || *p == '_')) {
3443                                                 p++;
3444                                         }
3445                                 }
3446
3447                                 /* copy variable to buffer */
3448                                 len = (p - s > 255) ? 255 : (p - s);
3449                                 strncpy(buf, s, len);
3450                                 buf[len] = '\0';
3451
3452                                 if (*p == '}') {
3453                                         p++;
3454                                 }
3455                                 s = p;
3456
3457                                 /* search for variable in environment */
3458
3459                                 var = getenv(buf);
3460                                 if (var) {
3461                                         obj = create_plain_text(var);
3462                                         if (obj) {
3463                                                 append_object(retval, obj);
3464                                         }
3465                                         continue;
3466                                 }
3467
3468                                 /* if variable wasn't found in environment, use some special */
3469
3470                                 arg = 0;
3471
3472                                 /* split arg */
3473                                 if (strchr(buf, ' ')) {
3474                                         arg = strchr(buf, ' ');
3475                                         *arg = '\0';
3476                                         arg++;
3477                                         while (isspace((int) *arg)) {
3478                                                 arg++;
3479                                         }
3480                                         if (!*arg) {
3481                                                 arg = 0;
3482                                         }
3483                                 }
3484
3485                                 /* lowercase variable name */
3486                                 tmp_p = buf;
3487                                 while (*tmp_p) {
3488                                         *tmp_p = tolower(*tmp_p);
3489                                         tmp_p++;
3490                                 }
3491
3492                                 obj = construct_text_object(buf, arg,
3493                                                 line, allow_threaded,
3494                                                 &ifblock_opaque, orig_p);
3495                                 if (obj != NULL) {
3496                                         append_object(retval, obj);
3497                                 }
3498                                 continue;
3499                         } else {
3500                                 obj = create_plain_text("$");
3501                                 s = p + 1;
3502                                 if (obj != NULL) {
3503                                         append_object(retval, obj);
3504                                 }
3505                         }
3506                 } else if (*p == '\\' && *(p+1) == '#') {
3507                         strfold(p, 1);
3508                 } else if (*p == '#') {
3509                         char c;
3510                         if (remove_comment(p, &c) && p > orig_p && c == '\n') {
3511                                 /* if remove_comment removed a newline, we need to 'back up' with p */
3512                                 p--;
3513                         }
3514                 }
3515                 p++;
3516         }
3517         obj = create_plain_text(s);
3518         if (obj != NULL) {
3519                 append_object(retval, obj);
3520         }
3521
3522         if (!ifblock_stack_empty(&ifblock_opaque)) {
3523                 ERR("one or more $endif's are missing");
3524         }
3525
3526         free(orig_p);
3527         return 0;
3528 }
3529
3530 static void extract_variable_text(const char *p)
3531 {
3532         free_text_objects(&global_root_object, 0);
3533         if (tmpstring1) {
3534                 free(tmpstring1);
3535                 tmpstring1 = 0;
3536         }
3537         if (tmpstring2) {
3538                 free(tmpstring2);
3539                 tmpstring2 = 0;
3540         }
3541         if (text_buffer) {
3542                 free(text_buffer);
3543                 text_buffer = 0;
3544         }
3545
3546         extract_variable_text_internal(&global_root_object, p, 1);
3547 }
3548
3549 void parse_conky_vars(struct text_object *root, char *txt, char *p, struct information *cur)
3550 {
3551         extract_variable_text_internal(root, txt, 0);
3552         generate_text_internal(p, max_user_text, *root, cur);
3553         return;
3554 }
3555
3556 static inline struct mail_s *ensure_mail_thread(struct text_object *obj,
3557                 void *thread(void *), const char *text)
3558 {
3559         if (obj->char_b && info.mail) {
3560                 // this means we use info
3561                 if (!info.mail->p_timed_thread) {
3562                         info.mail->p_timed_thread =
3563                                 timed_thread_create(thread,
3564                                                 (void *) info.mail, info.mail->interval * 1000000);
3565                         if (!info.mail->p_timed_thread) {
3566                                 ERR("Error creating %s timed thread", text);
3567                         }
3568                         timed_thread_register(info.mail->p_timed_thread,
3569                                         &info.mail->p_timed_thread);
3570                         if (timed_thread_run(info.mail->p_timed_thread)) {
3571                                 ERR("Error running %s timed thread", text);
3572                         }
3573                 }
3574                 return info.mail;
3575         } else if (obj->data.mail) {
3576                 // this means we use obj
3577                 if (!obj->data.mail->p_timed_thread) {
3578                         obj->data.mail->p_timed_thread =
3579                                 timed_thread_create(thread,
3580                                                 (void *) obj->data.mail,
3581                                                 obj->data.mail->interval * 1000000);
3582                         if (!obj->data.mail->p_timed_thread) {
3583                                 ERR("Error creating %s timed thread", text);
3584                         }
3585                         timed_thread_register(obj->data.mail->p_timed_thread,
3586                                         &obj->data.mail->p_timed_thread);
3587                         if (timed_thread_run(obj->data.mail->p_timed_thread)) {
3588                                 ERR("Error running %s timed thread", text);
3589                         }
3590                 }
3591                 return obj->data.mail;
3592         } else if (!obj->a) {
3593                 // something is wrong, warn once then stop
3594                 ERR("There's a problem with your mail settings.  "
3595                                 "Check that the global mail settings are properly defined"
3596                                 " (line %li).", obj->line);
3597                 obj->a++;
3598         }
3599         return NULL;
3600 }
3601
3602 char *format_time(unsigned long timeval, const int width)
3603 {
3604         char buf[10];
3605         unsigned long nt;       // narrow time, for speed on 32-bit
3606         unsigned cc;            // centiseconds
3607         unsigned nn;            // multi-purpose whatever
3608
3609         nt = timeval;
3610         cc = nt % 100;          // centiseconds past second
3611         nt /= 100;                      // total seconds
3612         nn = nt % 60;           // seconds past the minute
3613         nt /= 60;                       // total minutes
3614         if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
3615                                 nt, nn, cc)) {
3616                 return strndup(buf, text_buffer_size);
3617         }
3618         if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
3619                 return strndup(buf, text_buffer_size);
3620         }
3621         nn = nt % 60;           // minutes past the hour
3622         nt /= 60;                       // total hours
3623         if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
3624                 return strndup(buf, text_buffer_size);
3625         }
3626         nn = nt;                        // now also hours
3627         if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
3628                 return strndup(buf, text_buffer_size);
3629         }
3630         nn /= 24;                       // now days
3631         if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
3632                 return strndup(buf, text_buffer_size);
3633         }
3634         nn /= 7;                        // now weeks
3635         if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
3636                 return strndup(buf, text_buffer_size);
3637         }
3638         // well shoot, this outta' fit...
3639         return strndup("<inf>", text_buffer_size);
3640 }
3641
3642 //remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat"
3643 //string has to end with \0 and it's length should fit in a int
3644 #define BACKSPACE 8
3645 void remove_deleted_chars(char *string){
3646         int i = 0;
3647         while(string[i] != 0){
3648                 if(string[i] == BACKSPACE){
3649                         if(i != 0){
3650                                 strcpy( &(string[i-1]), &(string[i+1]) );
3651                                 i--;
3652                         }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string
3653                 }else i++;
3654         }
3655 }
3656
3657 static inline void format_media_player_time(char *buf, const int size,
3658                 int seconds)
3659 {
3660         int days, hours, minutes;
3661
3662         days = seconds / (24 * 60 * 60);
3663         seconds %= (24 * 60 * 60);
3664         hours = seconds / (60 * 60);
3665         seconds %= (60 * 60);
3666         minutes = seconds / 60;
3667         seconds %= 60;
3668
3669         if (days > 0) {
3670                 snprintf(buf, size, "%i days %i:%02i:%02i", days,
3671                                 hours, minutes, seconds);
3672         } else if (hours > 0) {
3673                 snprintf(buf, size, "%i:%02i:%02i", hours, minutes,
3674                                 seconds);
3675         } else {
3676                 snprintf(buf, size, "%i:%02i", minutes, seconds);
3677         }
3678 }
3679
3680 static inline double get_barnum(char *buf)
3681 {
3682         char *c = buf;
3683         double barnum;
3684
3685         while (*c) {
3686                 if (*c == '\001') {
3687                         *c = ' ';
3688                 }
3689                 c++;
3690         }
3691
3692         if (sscanf(buf, "%lf", &barnum) == 0) {
3693                 ERR("reading exec value failed (perhaps it's not the "
3694                                 "correct format?)");
3695                 return -1;
3696         }
3697         if (barnum > 100.0 || barnum < 0.0) {
3698                 ERR("your exec value is not between 0 and 100, "
3699                                 "therefore it will be ignored");
3700                 return -1;
3701         }
3702         return barnum;
3703 }
3704
3705 /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
3706  * multiline objects like $exec work with $align[rc] and friends
3707  */
3708 void substitute_newlines(char *p, long l)
3709 {
3710         char *s = p;
3711         if (l < 0) return;
3712         while (p && *p && p < s + l) {
3713                 if (*p == '\n') {
3714                         /* only substitute if it's not the last newline */
3715                         *p = SECRIT_MULTILINE_CHAR;
3716                 }
3717                 p++;
3718         }
3719 }
3720
3721 static void generate_text_internal(char *p, int p_max_size,
3722                 struct text_object root, struct information *cur)
3723 {
3724         struct text_object *obj;
3725 #ifdef X11
3726         int need_to_load_fonts = 0;
3727 #endif /* X11 */
3728
3729         /* for the OBJ_top* handler */
3730         struct process **needed = 0;
3731
3732 #ifdef HAVE_ICONV
3733         char buff_in[p_max_size];
3734         buff_in[0] = 0;
3735         iconv_converting = 0;
3736 #endif /* HAVE_ICONV */
3737
3738         p[0] = 0;
3739         obj = root.next;
3740         while (obj && p_max_size > 0) {
3741                 needed = 0; /* reset for top stuff */
3742
3743 /* IFBLOCK jumping algorithm
3744  *
3745  * This is easier as it looks like:
3746  * - each IF checks it's condition
3747  *   - on FALSE: call DO_JUMP
3748  *   - on TRUE: don't care
3749  * - each ELSE calls DO_JUMP unconditionally
3750  * - each ENDIF is silently being ignored
3751  *
3752  * Why this works:
3753  * DO_JUMP overwrites the "obj" variable of the loop and sets it to the target
3754  * (i.e. the corresponding ELSE or ENDIF). After that, processing for the given
3755  * object can continue, free()ing stuff e.g., then the for-loop does the rest: as
3756  * regularly, "obj" is being updated to point to obj->next, so object parsing
3757  * continues right after the corresponding ELSE or ENDIF. This means that if we
3758  * find an ELSE, it's corresponding IF must not have jumped, so we need to jump
3759  * always. If we encounter an ENDIF, it's corresponding IF or ELSE has not
3760  * jumped, and there is nothing to do.
3761  */
3762 #define DO_JUMP { \
3763         DBGP2("jumping"); \
3764         obj = obj->data.ifblock.next; \
3765 }
3766
3767 #define OBJ(a) break; case OBJ_##a:
3768
3769                 switch (obj->type) {
3770                         default:
3771                                 ERR("not implemented obj type %d", obj->type);
3772                         OBJ(read_tcp) {
3773                                 int sock, received;
3774                                 struct sockaddr_in addr;
3775                                 struct hostent* he = gethostbyname(obj->data.read_tcp.host);
3776                                 if(he != NULL) {
3777                                         sock = socket(he->h_addrtype, SOCK_STREAM, 0);
3778                                         if(sock != -1) {
3779                                                 memset(&addr, 0, sizeof(addr));
3780                                                 addr.sin_family = AF_INET;
3781                                                 addr.sin_port = obj->data.read_tcp.port;
3782                                                 memcpy(&addr.sin_addr, he->h_addr, he->h_length);
3783                                                 if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == 0) {
3784                                                         fd_set readfds;
3785                                                         struct timeval tv;
3786                                                         FD_ZERO(&readfds);
3787                                                         FD_SET(sock, &readfds);
3788                                                         tv.tv_sec = 1;
3789                                                         tv.tv_usec = 0;
3790                                                         if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
3791                                                                 received = recv(sock, p, p_max_size, 0);
3792                                                                 p[received] = 0;
3793                                                         }
3794                                                         close(sock);
3795                                                 } else {
3796                                                         ERR("read_tcp: Couldn't create a connection");
3797                                                 }
3798                                         }else{
3799                                                 ERR("read_tcp: Couldn't create a socket");
3800                                         }
3801                                 }else{
3802                                         ERR("read_tcp: Problem with resolving the hostname");
3803                                 }
3804                         }
3805 #ifndef __OpenBSD__
3806                         OBJ(acpitemp) {
3807                                 temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
3808                         }
3809 #endif /* !__OpenBSD__ */
3810                         OBJ(freq) {
3811                                 if (obj->a) {
3812                                         obj->a = get_freq(p, p_max_size, "%.0f", 1,
3813                                                         obj->data.cpu_index);
3814                                 }
3815                         }
3816                         OBJ(freq_g) {
3817                                 if (obj->a) {
3818 #ifndef __OpenBSD__
3819                                         obj->a = get_freq(p, p_max_size, "%'.2f", 1000,
3820                                                         obj->data.cpu_index);
3821 #else
3822                                         /* OpenBSD has no such flag (SUSv2) */
3823                                         obj->a = get_freq(p, p_max_size, "%.2f", 1000,
3824                                                         obj->data.cpu_index);
3825 #endif /* __OpenBSD */
3826                                 }
3827                         }
3828 #if defined(__linux__)
3829                         OBJ(voltage_mv) {
3830                                 if (obj->a) {
3831                                         obj->a = get_voltage(p, p_max_size, "%.0f", 1,
3832                                                         obj->data.cpu_index);
3833                                 }
3834                         }
3835                         OBJ(voltage_v) {
3836                                 if (obj->a) {
3837                                         obj->a = get_voltage(p, p_max_size, "%'.3f", 1000,
3838                                                         obj->data.cpu_index);
3839                                 }
3840                         }
3841
3842 #ifdef HAVE_IWLIB
3843                         OBJ(wireless_essid) {
3844                                 snprintf(p, p_max_size, "%s", obj->data.net->essid);
3845                         }
3846                         OBJ(wireless_mode) {
3847                                 snprintf(p, p_max_size, "%s", obj->data.net->mode);
3848                         }
3849                         OBJ(wireless_bitrate) {
3850                                 snprintf(p, p_max_size, "%s", obj->data.net->bitrate);
3851                         }
3852                         OBJ(wireless_ap) {
3853                                 snprintf(p, p_max_size, "%s", obj->data.net->ap);
3854                         }
3855                         OBJ(wireless_link_qual) {
3856                                 spaced_print(p, p_max_size, "%d", 4,
3857                                                 obj->data.net->link_qual);
3858                         }
3859                         OBJ(wireless_link_qual_max) {
3860                                 spaced_print(p, p_max_size, "%d", 4,
3861                                                 obj->data.net->link_qual_max);
3862                         }
3863                         OBJ(wireless_link_qual_perc) {
3864                                 if (obj->data.net->link_qual_max > 0) {
3865                                         spaced_print(p, p_max_size, "%.0f", 5,
3866                                                         (double) obj->data.net->link_qual /
3867                                                         obj->data.net->link_qual_max * 100);
3868                                 } else {
3869                                         spaced_print(p, p_max_size, "unk", 5);
3870                                 }
3871                         }
3872                         OBJ(wireless_link_bar) {
3873 #ifdef X11
3874                                 if(output_methods & TO_X) {
3875                                         new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
3876                                                 obj->data.net->link_qual_max) * 255.0);
3877                                 }else{
3878 #endif /* X11 */
3879                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
3880                                         new_bar_in_shell(p, p_max_size, ((double) obj->data.net->link_qual /
3881                                                 obj->data.net->link_qual_max) * 100.0, obj->a);
3882 #ifdef X11
3883                                 }
3884 #endif /* X11 */
3885                         }
3886 #endif /* HAVE_IWLIB */
3887
3888 #endif /* __linux__ */
3889
3890 #ifndef __OpenBSD__
3891                         OBJ(adt746xcpu) {
3892                                 get_adt746x_cpu(p, p_max_size);
3893                         }
3894                         OBJ(adt746xfan) {
3895                                 get_adt746x_fan(p, p_max_size);
3896                         }
3897                         OBJ(acpifan) {
3898                                 get_acpi_fan(p, p_max_size);
3899                         }
3900                         OBJ(acpiacadapter) {
3901                                 get_acpi_ac_adapter(p, p_max_size);
3902                         }
3903                         OBJ(battery) {
3904                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
3905                         }
3906                         OBJ(battery_time) {
3907                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
3908                         }
3909                         OBJ(battery_percent) {
3910                                 percent_print(p, p_max_size, get_battery_perct(obj->data.s));
3911                         }
3912                         OBJ(battery_bar) {
3913 #ifdef X11
3914                                 if(output_methods & TO_X) {
3915                                         new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
3916                                 }else{
3917 #endif /* X11 */
3918                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
3919                                         new_bar_in_shell(p, p_max_size, get_battery_perct_bar(obj->data.s) / 2.55, obj->a);
3920 #ifdef X11
3921                                 }
3922 #endif /* X11 */
3923                         }
3924                         OBJ(battery_short) {
3925                                 get_battery_short_status(p, p_max_size, obj->data.s);
3926                         }
3927 #endif /* __OpenBSD__ */
3928
3929                         OBJ(buffers) {
3930                                 human_readable(cur->buffers * 1024, p, 255);
3931                         }
3932                         OBJ(cached) {
3933                                 human_readable(cur->cached * 1024, p, 255);
3934                         }
3935                         OBJ(cpu) {
3936                                 if (obj->data.cpu_index > info.cpu_count) {
3937                                         ERR("obj->data.cpu_index %i info.cpu_count %i",
3938                                                         obj->data.cpu_index, info.cpu_count);
3939                                         CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
3940                                 }
3941                                 percent_print(p, p_max_size,
3942                                               round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
3943                         }
3944 #ifdef X11
3945                         OBJ(cpugauge)
3946                                 new_gauge(p, obj->a, obj->b,
3947                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
3948 #endif /* X11 */
3949                         OBJ(cpubar) {
3950 #ifdef X11
3951                                 if(output_methods & TO_X) {
3952                                         new_bar(p, obj->a, obj->b,
3953                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
3954                                 }else{
3955 #endif /* X11 */
3956                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
3957                                         new_bar_in_shell(p, p_max_size, round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100), obj->a);
3958 #ifdef X11
3959                                 }
3960 #endif /* X11 */
3961                         }
3962 #ifdef X11
3963                         OBJ(cpugraph) {
3964                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
3965                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100),
3966                                                 100, 1, obj->char_a, obj->char_b);
3967                         }
3968                         OBJ(loadgraph) {
3969                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, cur->loadavg[0],
3970                                                 obj->e, 1, obj->char_a, obj->char_b);
3971                         }
3972                         OBJ(color) {
3973                                 new_fg(p, obj->data.l);
3974                         }
3975                         OBJ(color0) {
3976                                 new_fg(p, color0);
3977                         }
3978                         OBJ(color1) {
3979                                 new_fg(p, color1);
3980                         }
3981                         OBJ(color2) {
3982                                 new_fg(p, color2);
3983                         }
3984                         OBJ(color3) {
3985                                 new_fg(p, color3);
3986                         }
3987                         OBJ(color4) {
3988                                 new_fg(p, color4);
3989                         }
3990                         OBJ(color5) {
3991                                 new_fg(p, color5);
3992                         }
3993                         OBJ(color6) {
3994                                 new_fg(p, color6);
3995                         }
3996                         OBJ(color7) {
3997                                 new_fg(p, color7);
3998                         }
3999                         OBJ(color8) {
4000                                 new_fg(p, color8);
4001                         }
4002                         OBJ(color9) {
4003                                 new_fg(p, color9);
4004                         }
4005 #endif /* X11 */
4006                         OBJ(conky_version) {
4007                                 snprintf(p, p_max_size, "%s", VERSION);
4008                         }
4009                         OBJ(conky_build_date) {
4010                                 snprintf(p, p_max_size, "%s", BUILD_DATE);
4011                         }
4012                         OBJ(conky_build_arch) {
4013                                 snprintf(p, p_max_size, "%s", BUILD_ARCH);
4014                         }
4015 #if defined(__linux__)
4016                         OBJ(disk_protect) {
4017                                 snprintf(p, p_max_size, "%s",
4018                                                 get_disk_protect_queue(obj->data.s));
4019                         }
4020                         OBJ(i8k_version) {
4021                                 snprintf(p, p_max_size, "%s", i8k.version);
4022                         }
4023                         OBJ(i8k_bios) {
4024                                 snprintf(p, p_max_size, "%s", i8k.bios);
4025                         }
4026                         OBJ(i8k_serial) {
4027                                 snprintf(p, p_max_size, "%s", i8k.serial);
4028                         }
4029                         OBJ(i8k_cpu_temp) {
4030                                 int cpu_temp;
4031
4032                                 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
4033                                 temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
4034                         }
4035                         OBJ(i8k_left_fan_status) {
4036                                 int left_fan_status;
4037
4038                                 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
4039                                 if (left_fan_status == 0) {
4040                                         snprintf(p, p_max_size, "off");
4041                                 }
4042                                 if (left_fan_status == 1) {
4043                                         snprintf(p, p_max_size, "low");
4044                                 }
4045                                 if (left_fan_status == 2) {
4046                                         snprintf(p, p_max_size, "high");
4047                                 }
4048                         }
4049                         OBJ(i8k_right_fan_status) {
4050                                 int right_fan_status;
4051
4052                                 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
4053                                 if (right_fan_status == 0) {
4054                                         snprintf(p, p_max_size, "off");
4055                                 }
4056                                 if (right_fan_status == 1) {
4057                                         snprintf(p, p_max_size, "low");
4058                                 }
4059                                 if (right_fan_status == 2) {
4060                                         snprintf(p, p_max_size, "high");
4061                                 }
4062                         }
4063                         OBJ(i8k_left_fan_rpm) {
4064                                 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
4065                         }
4066                         OBJ(i8k_right_fan_rpm) {
4067                                 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
4068                         }
4069                         OBJ(i8k_ac_status) {
4070                                 int ac_status;
4071
4072                                 sscanf(i8k.ac_status, "%d", &ac_status);
4073                                 if (ac_status == -1) {
4074                                         snprintf(p, p_max_size, "disabled (read i8k docs)");
4075                                 }
4076                                 if (ac_status == 0) {
4077                                         snprintf(p, p_max_size, "off");
4078                                 }
4079                                 if (ac_status == 1) {
4080                                         snprintf(p, p_max_size, "on");
4081                                 }
4082                         }
4083                         OBJ(i8k_buttons_status) {
4084                                 snprintf(p, p_max_size, "%s", i8k.buttons_status);
4085                         }
4086 #if defined(IBM)
4087                         OBJ(ibm_fan) {
4088                                 get_ibm_acpi_fan(p, p_max_size);
4089                         }
4090                         OBJ(ibm_temps) {
4091                                 get_ibm_acpi_temps();
4092                                 temp_print(p, p_max_size,
4093                                            ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
4094                         }
4095                         OBJ(ibm_volume) {
4096                                 get_ibm_acpi_volume(p, p_max_size);
4097                         }
4098                         OBJ(ibm_brightness) {
4099                                 get_ibm_acpi_brightness(p, p_max_size);
4100                         }
4101 #endif /* IBM */
4102                         /* information from sony_laptop kernel module
4103                          * /sys/devices/platform/sony-laptop */
4104                         OBJ(sony_fanspeed) {
4105                                 get_sony_fanspeed(p, p_max_size);
4106                         }
4107                         OBJ(if_gw) {
4108                                 if (!cur->gw_info.count) {
4109                                         DO_JUMP;
4110                                 }
4111                         }
4112                         OBJ(gw_iface) {
4113                                 snprintf(p, p_max_size, "%s", cur->gw_info.iface);
4114                         }
4115                         OBJ(gw_ip) {
4116                                 snprintf(p, p_max_size, "%s", cur->gw_info.ip);
4117                         }
4118                         OBJ(laptop_mode) {
4119                                 snprintf(p, p_max_size, "%d", get_laptop_mode());
4120                         }
4121                         OBJ(pb_battery) {
4122                                 get_powerbook_batt_info(p, p_max_size, obj->data.i);
4123                         }
4124 #endif /* __linux__ */
4125 #if (defined(__FreeBSD__) || defined(__linux__))
4126                         OBJ(if_up) {
4127                                 if ((obj->data.ifblock.s)
4128                                                 && (!interface_up(obj->data.ifblock.s))) {
4129                                         DO_JUMP;
4130                                 }
4131                         }
4132 #endif
4133 #ifdef __OpenBSD__
4134                         OBJ(obsd_sensors_temp) {
4135                                 obsd_sensors.device = sensor_device;
4136                                 update_obsd_sensors();
4137                                 temp_print(p, p_max_size,
4138                                            obsd_sensors.temp[obsd_sensors.device][obj->data.sensor],
4139                                            TEMP_CELSIUS);
4140                         }
4141                         OBJ(obsd_sensors_fan) {
4142                                 obsd_sensors.device = sensor_device;
4143                                 update_obsd_sensors();
4144                                 snprintf(p, p_max_size, "%d",
4145                                                 obsd_sensors.fan[obsd_sensors.device][obj->data.sensor]);
4146                         }
4147                         OBJ(obsd_sensors_volt) {
4148                                 obsd_sensors.device = sensor_device;
4149                                 update_obsd_sensors();
4150                                 snprintf(p, p_max_size, "%.2f",
4151                                                 obsd_sensors.volt[obsd_sensors.device][obj->data.sensor]);
4152                         }
4153                         OBJ(obsd_vendor) {
4154                                 get_obsd_vendor(p, p_max_size);
4155                         }
4156                         OBJ(obsd_product) {
4157                                 get_obsd_product(p, p_max_size);
4158                         }
4159 #endif /* __OpenBSD__ */
4160 #ifdef X11
4161                         OBJ(font) {
4162                                 new_font(p, obj->data.s);
4163                                 need_to_load_fonts = 1;
4164                         }
4165 #endif /* X11 */
4166                         /* TODO: move this correction from kB to kB/s elsewhere
4167                          * (or get rid of it??) */
4168                         OBJ(diskio) {
4169                                 human_readable((obj->data.diskio->current / update_interval) * 1024LL,
4170                                                 p, p_max_size);
4171                         }
4172                         OBJ(diskio_write) {
4173                                 human_readable((obj->data.diskio->current_write / update_interval) * 1024LL,
4174                                                 p, p_max_size);
4175                         }
4176                         OBJ(diskio_read) {
4177                                 human_readable((obj->data.diskio->current_read / update_interval) * 1024LL,
4178                                                 p, p_max_size);
4179                         }
4180 #ifdef X11
4181                         OBJ(diskiograph) {
4182                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4183                                           obj->data.diskio->current, obj->e, 1, obj->char_a, obj->char_b);
4184                         }
4185                         OBJ(diskiograph_read) {
4186                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4187                                           obj->data.diskio->current_read, obj->e, 1, obj->char_a, obj->char_b);
4188                         }
4189                         OBJ(diskiograph_write) {
4190                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4191                                           obj->data.diskio->current_write, obj->e, 1, obj->char_a, obj->char_b);
4192                         }
4193 #endif /* X11 */
4194                         OBJ(downspeed) {
4195                                 human_readable(obj->data.net->recv_speed, p, 255);
4196                         }
4197                         OBJ(downspeedf) {
4198                                 spaced_print(p, p_max_size, "%.1f", 8,
4199                                                 obj->data.net->recv_speed / 1024.0);
4200                         }
4201 #ifdef X11
4202                         OBJ(downspeedgraph) {
4203                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4204                                         obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
4205                         }
4206 #endif /* X11 */
4207                         OBJ(else) {
4208                                 /* Since we see you, you're if has not jumped.
4209                                  * Do Ninja jump here: without leaving traces.
4210                                  * This is to prevent us from stale jumped flags.
4211                                  */
4212                                 obj = obj->data.ifblock.next;
4213                                 continue;
4214                         }
4215                         OBJ(endif) {
4216                                 /* harmless object, just ignore */
4217                         }
4218 #ifdef HAVE_POPEN
4219                         OBJ(addr) {
4220                                 if ((obj->data.net->addr.sa_data[2] & 255) == 0
4221                                                 && (obj->data.net->addr.sa_data[3] & 255) == 0
4222                                                 && (obj->data.net->addr.sa_data[4] & 255) == 0
4223                                                 && (obj->data.net->addr.sa_data[5] & 255) == 0) {
4224                                         snprintf(p, p_max_size, "No Address");
4225                                 } else {
4226                                         snprintf(p, p_max_size, "%u.%u.%u.%u",
4227                                                 obj->data.net->addr.sa_data[2] & 255,
4228                                                 obj->data.net->addr.sa_data[3] & 255,
4229                                                 obj->data.net->addr.sa_data[4] & 255,
4230                                                 obj->data.net->addr.sa_data[5] & 255);
4231                                 }
4232                         }
4233 #if defined(__linux__)
4234                         OBJ(addrs) {
4235                                 if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
4236                                         obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
4237                                         strcpy(p, obj->data.net->addrs);
4238                                 } else {
4239                                         strcpy(p, "0.0.0.0");
4240                                 }
4241                         }
4242 #endif /* __linux__ */
4243 #if defined(IMLIB2) && defined(X11)
4244                         OBJ(image) {
4245                                 /* doesn't actually draw anything, just queues it omp.  the
4246                                  * image will get drawn after the X event loop */
4247                                 cimlib_add_image(obj->data.s);
4248                         }
4249 #endif /* IMLIB2 */
4250                         OBJ(eval) {
4251                                 evaluate(obj->data.s, p);
4252                         }
4253                         OBJ(exec) {
4254                                 read_exec(obj->data.s, p, text_buffer_size);
4255                                 remove_deleted_chars(p);
4256                         }
4257                         OBJ(execp) {
4258                                 struct information *tmp_info;
4259                                 struct text_object subroot;
4260
4261                                 read_exec(obj->data.s, p, text_buffer_size);
4262
4263                                 tmp_info = malloc(sizeof(struct information));
4264                                 memcpy(tmp_info, cur, sizeof(struct information));
4265                                 parse_conky_vars(&subroot, p, p, tmp_info);
4266
4267                                 free_text_objects(&subroot, 1);
4268                                 free(tmp_info);
4269                         }
4270 #ifdef X11
4271                         OBJ(execgauge) {
4272                                 double barnum;
4273
4274                                 read_exec(obj->data.s, p, text_buffer_size);
4275                                 barnum = get_barnum(p); /*using the same function*/
4276
4277                                 if (barnum >= 0.0) {
4278                                         barnum /= 100;
4279                                         new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
4280                                 }
4281                         }
4282 #endif /* X11 */
4283                         OBJ(execbar) {
4284                                 double barnum;
4285
4286                                 read_exec(obj->data.s, p, text_buffer_size);
4287                                 barnum = get_barnum(p);
4288
4289                                 if (barnum >= 0.0) {
4290 #ifdef X11
4291                                         if(output_methods & TO_X) {
4292                                                 barnum /= 100;
4293                                                 new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
4294                                         }else{
4295 #endif /* X11 */
4296                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
4297                                                 new_bar_in_shell(p, p_max_size, barnum, obj->a);
4298 #ifdef X11
4299                                         }
4300 #endif /* X11 */
4301                                 }
4302                         }
4303 #ifdef X11
4304                         OBJ(execgraph) {
4305                                 char showaslog = FALSE;
4306                                 char tempgrad = FALSE;
4307                                 double barnum;
4308                                 char *cmd = obj->data.s;
4309
4310                                 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
4311                                         tempgrad = TRUE;
4312                                         cmd += strlen(" "TEMPGRAD);
4313                                 }
4314                                 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
4315                                         showaslog = TRUE;
4316                                         cmd += strlen(" "LOGGRAPH);
4317                                 }
4318                                 read_exec(cmd, p, text_buffer_size);
4319                                 barnum = get_barnum(p);
4320
4321                                 if (barnum > 0) {
4322                                         new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
4323                                                         100, 1, showaslog, tempgrad);
4324                                 }
4325                         }
4326 #endif /* X11 */
4327                         OBJ(execibar) {
4328                                 if (current_update_time - obj->data.execi.last_update
4329                                                 >= obj->data.execi.interval) {
4330                                         double barnum;
4331
4332                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
4333                                         barnum = get_barnum(p);
4334
4335                                         if (barnum >= 0.0) {
4336                                                 obj->f = barnum;
4337                                         }
4338                                         obj->data.execi.last_update = current_update_time;
4339                                 }
4340 #ifdef X11
4341                                 if(output_methods & TO_X) {
4342                                         new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
4343                                 } else {
4344 #endif /* X11 */
4345                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
4346                                         new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a);
4347 #ifdef X11
4348                                 }
4349 #endif /* X11 */
4350                         }
4351 #ifdef X11
4352                         OBJ(execigraph) {
4353                                 if (current_update_time - obj->data.execi.last_update
4354                                                 >= obj->data.execi.interval) {
4355                                         double barnum;
4356                                         char showaslog = FALSE;
4357                                         char tempgrad = FALSE;
4358                                         char *cmd = obj->data.execi.cmd;
4359
4360                                         if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
4361                                                 tempgrad = TRUE;
4362                                                 cmd += strlen(" "TEMPGRAD);
4363                                         }
4364                                         if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
4365                                                 showaslog = TRUE;
4366                                                 cmd += strlen(" "LOGGRAPH);
4367                                         }
4368                                         obj->char_a = showaslog;
4369                                         obj->char_b = tempgrad;
4370                                         read_exec(cmd, p, text_buffer_size);
4371                                         barnum = get_barnum(p);
4372
4373                                         if (barnum >= 0.0) {
4374                                                 obj->f = barnum;
4375                                         }
4376                                         obj->data.execi.last_update = current_update_time;
4377                                 }
4378                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b);
4379                         }
4380                         OBJ(execigauge) {
4381                                 if (current_update_time - obj->data.execi.last_update
4382                                                 >= obj->data.execi.interval) {
4383                                         double barnum;
4384
4385                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
4386                                         barnum = get_barnum(p);
4387
4388                                         if (barnum >= 0.0) {
4389                                                 obj->f = 255 * barnum / 100.0;
4390                                         }
4391                                         obj->data.execi.last_update = current_update_time;
4392                                 }
4393                                 new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
4394                         }
4395 #endif /* X11 */
4396                         OBJ(execi) {
4397                                 if (current_update_time - obj->data.execi.last_update
4398                                                 >= obj->data.execi.interval
4399                                                 && obj->data.execi.interval != 0) {
4400                                         read_exec(obj->data.execi.cmd, obj->data.execi.buffer,
4401                                                 text_buffer_size);
4402                                         obj->data.execi.last_update = current_update_time;
4403                                 }
4404                                 snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
4405                         }
4406                         OBJ(execpi) {
4407                                 struct text_object subroot;
4408                                 struct information *tmp_info =
4409                                         malloc(sizeof(struct information));
4410                                 memcpy(tmp_info, cur, sizeof(struct information));
4411
4412                                 if (current_update_time - obj->data.execi.last_update
4413                                                 < obj->data.execi.interval
4414                                                 || obj->data.execi.interval == 0) {
4415                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
4416                                 } else {
4417                                         char *output = obj->data.execi.buffer;
4418                                         FILE *fp = popen(obj->data.execi.cmd, "r");
4419                                         int length = fread(output, 1, text_buffer_size, fp);
4420
4421                                         pclose(fp);
4422
4423                                         output[length] = '\0';
4424                                         if (length > 0 && output[length - 1] == '\n') {
4425                                                 output[length - 1] = '\0';
4426                                         }
4427
4428                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
4429                                         obj->data.execi.last_update = current_update_time;
4430                                 }
4431                                 free_text_objects(&subroot, 1);
4432                                 free(tmp_info);
4433                         }
4434                         OBJ(texeci) {
4435                                 if (!obj->data.texeci.p_timed_thread) {
4436                                         obj->data.texeci.p_timed_thread =
4437                                                 timed_thread_create(&threaded_exec,
4438                                                 (void *) obj, obj->data.texeci.interval * 1000000);
4439                                         if (!obj->data.texeci.p_timed_thread) {
4440                                                 ERR("Error creating texeci timed thread");
4441                                         }
4442                                         timed_thread_register(obj->data.texeci.p_timed_thread,
4443                                                 &obj->data.texeci.p_timed_thread);
4444                                         if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
4445                                                 ERR("Error running texeci timed thread");
4446                                         }
4447                                 } else {
4448                                         timed_thread_lock(obj->data.texeci.p_timed_thread);
4449                                         snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer);
4450                                         timed_thread_unlock(obj->data.texeci.p_timed_thread);
4451                                 }
4452                         }
4453 #endif /* HAVE_POPEN */
4454                         OBJ(imap_unseen) {
4455                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
4456
4457                                 if (mail && mail->p_timed_thread) {
4458                                         timed_thread_lock(mail->p_timed_thread);
4459                                         snprintf(p, p_max_size, "%lu", mail->unseen);
4460                                         timed_thread_unlock(mail->p_timed_thread);
4461                                 }
4462                         }
4463                         OBJ(imap_messages) {
4464                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
4465
4466                                 if (mail && mail->p_timed_thread) {
4467                                         timed_thread_lock(mail->p_timed_thread);
4468                                         snprintf(p, p_max_size, "%lu", mail->messages);
4469                                         timed_thread_unlock(mail->p_timed_thread);
4470                                 }
4471                         }
4472                         OBJ(pop3_unseen) {
4473                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
4474
4475                                 if (mail && mail->p_timed_thread) {
4476                                         timed_thread_lock(mail->p_timed_thread);
4477                                         snprintf(p, p_max_size, "%lu", mail->unseen);
4478                                         timed_thread_unlock(mail->p_timed_thread);
4479                                 }
4480                         }
4481                         OBJ(pop3_used) {
4482                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
4483
4484                                 if (mail && mail->p_timed_thread) {
4485                                         timed_thread_lock(mail->p_timed_thread);
4486                                         snprintf(p, p_max_size, "%.1f",
4487                                                 mail->used / 1024.0 / 1024.0);
4488                                         timed_thread_unlock(mail->p_timed_thread);
4489                                 }
4490                         }
4491                         OBJ(fs_bar) {
4492                                 if (obj->data.fs != NULL) {
4493                                         if (obj->data.fs->size == 0) {
4494 #ifdef X11
4495                                                 if(output_methods & TO_X) {
4496                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
4497                                                 }else{
4498 #endif /* X11 */
4499                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
4500                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
4501 #ifdef X11
4502                                                 }
4503 #endif /* X11 */
4504                                         } else {
4505 #ifdef X11
4506                                                 if(output_methods & TO_X) {
4507                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
4508                                                                 (int) (255 - obj->data.fsbar.fs->avail * 255 /
4509                                                                 obj->data.fs->size));
4510                                                 }else{
4511 #endif /* X11 */
4512                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
4513                                                         new_bar_in_shell(p, p_max_size,
4514                                                                 (int) (100 - obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
4515 #ifdef X11
4516                                                 }
4517 #endif /* X11 */
4518                                         }
4519                                 }
4520                         }
4521                         OBJ(fs_free) {
4522                                 if (obj->data.fs != NULL) {
4523                                         human_readable(obj->data.fs->avail, p, 255);
4524                                 }
4525                         }
4526                         OBJ(fs_free_perc) {
4527                                 if (obj->data.fs != NULL) {
4528                                         int val = 0;
4529
4530                                         if (obj->data.fs->size) {
4531                                                 val = obj->data.fs->avail * 100 / obj->data.fs->size;
4532                                         }
4533
4534                                         percent_print(p, p_max_size, val);
4535                                 }
4536                         }
4537                         OBJ(fs_size) {
4538                                 if (obj->data.fs != NULL) {
4539                                         human_readable(obj->data.fs->size, p, 255);
4540                                 }
4541                         }
4542                         OBJ(fs_type) {
4543                                 if (obj->data.fs != NULL)
4544                                         snprintf(p, p_max_size, "%s", obj->data.fs->type);
4545                         }
4546                         OBJ(fs_used) {
4547                                 if (obj->data.fs != NULL) {
4548                                         human_readable(obj->data.fs->size - obj->data.fs->free, p,
4549                                                         255);
4550                                 }
4551                         }
4552                         OBJ(fs_bar_free) {
4553                                 if (obj->data.fs != NULL) {
4554                                         if (obj->data.fs->size == 0) {
4555 #ifdef X11
4556                                                 if(output_methods & TO_X) {
4557                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
4558                                                 }else{
4559 #endif /* X11 */
4560                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
4561                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
4562 #ifdef X11
4563                                                 }
4564 #endif /* X11 */
4565                                         } else {
4566 #ifdef X11
4567                                                 if(output_methods & TO_X) {
4568                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
4569                                                                 (int) (obj->data.fsbar.fs->avail * 255 /
4570                                                                 obj->data.fs->size));
4571                                                 }else{
4572 #endif /* X11 */
4573                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
4574                                                         new_bar_in_shell(p, p_max_size,
4575                                                                 (int) (obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
4576 #ifdef X11
4577                                                 }
4578 #endif /* X11 */
4579                                         }
4580                                 }
4581                         }
4582                         OBJ(fs_used_perc) {
4583                                 if (obj->data.fs != NULL) {
4584                                         int val = 0;
4585
4586                                         if (obj->data.fs->size) {
4587                                                 val = obj->data.fs->free
4588                                                                 * 100 /
4589                                                         obj->data.fs->size;
4590                                         }
4591
4592                                         percent_print(p, p_max_size, 100 - val);
4593                                 }
4594                         }
4595                         OBJ(loadavg) {
4596                                 float *v = info.loadavg;
4597
4598                                 if (obj->data.loadavg[2]) {
4599                                         snprintf(p, p_max_size, "%.2f %.2f %.2f",
4600                                                 v[obj->data.loadavg[0] - 1],
4601                                                 v[obj->data.loadavg[1] - 1],
4602                                                 v[obj->data.loadavg[2] - 1]);
4603                                 } else if (obj->data.loadavg[1]) {
4604                                         snprintf(p, p_max_size, "%.2f %.2f",
4605                                                 v[obj->data.loadavg[0] - 1],
4606                                                 v[obj->data.loadavg[1] - 1]);
4607                                 } else if (obj->data.loadavg[0]) {
4608                                         snprintf(p, p_max_size, "%.2f",
4609                                                 v[obj->data.loadavg[0] - 1]);
4610                                 }
4611                         }
4612                         OBJ(goto) {
4613                                 new_goto(p, obj->data.i);
4614                         }
4615                         OBJ(tab) {
4616                                 new_tab(p, obj->data.pair.a, obj->data.pair.b);
4617                         }
4618 #ifdef X11
4619                         OBJ(hr) {
4620                                 new_hr(p, obj->data.i);
4621                         }
4622 #endif
4623                         OBJ(nameserver) {
4624                                 if (cur->nameserver_info.nscount > obj->data.i)
4625                                         snprintf(p, p_max_size, "%s",
4626                                                         cur->nameserver_info.ns_list[obj->data.i]);
4627                         }
4628 #ifdef EVE
4629                         OBJ(eve) {
4630                                 char *skill = eve(obj->data.eve.userid, obj->data.eve.apikey, obj->data.eve.charid);
4631                                 snprintf(p, p_max_size, "%s", skill);
4632                         }
4633 #endif
4634 #ifdef RSS
4635                         OBJ(rss) {
4636                                 PRSS *data = get_rss_info(obj->data.rss.uri,
4637                                         obj->data.rss.delay);
4638                                 char *str;
4639
4640                                 if (data == NULL) {
4641                                         snprintf(p, p_max_size, "prss: Error reading RSS data\n");
4642                                 } else {
4643                                         if (strcmp(obj->data.rss.action, "feed_title") == EQUAL) {
4644                                                 str = data->title;
4645                                                 // remove trailing new line if one exists
4646                                                 if (str[strlen(str) - 1] == '\n') {
4647                                                         str[strlen(str) - 1] = 0;
4648                                                 }
4649                                                 snprintf(p, p_max_size, "%s", str);
4650                                         } else if (strcmp(obj->data.rss.action, "item_title") == EQUAL) {
4651                                                 if (obj->data.rss.act_par < data->item_count) {
4652                                                         str = data->items[obj->data.rss.act_par].title;
4653                                                         // remove trailing new line if one exists
4654                                                         if (str[strlen(str) - 1] == '\n') {
4655                                                                 str[strlen(str) - 1] = 0;
4656                                                         }
4657                                                         snprintf(p, p_max_size, "%s", str);
4658                                                 }
4659                                         } else if (strcmp(obj->data.rss.action, "item_desc") == EQUAL) {
4660                                                 if (obj->data.rss.act_par < data->item_count) {
4661                                                         str =
4662                                                                 data->items[obj->data.rss.act_par].description;
4663                                                         // remove trailing new line if one exists
4664                                                         if (str[strlen(str) - 1] == '\n') {
4665                                                                 str[strlen(str) - 1] = 0;
4666                                                         }
4667                                                         snprintf(p, p_max_size, "%s", str);
4668                                                 }
4669                                         } else if (strcmp(obj->data.rss.action, "item_titles") == EQUAL) {
4670                                                 if (data->item_count > 0) {
4671                                                         int itmp;
4672                                                         int show;
4673                                                         //'tmpspaces' is a string with spaces too be placed in front of each title
4674                                                         char *tmpspaces = malloc(obj->data.rss.nrspaces + 1);
4675                                                         memset(tmpspaces, ' ', obj->data.rss.nrspaces);
4676                                                         tmpspaces[obj->data.rss.nrspaces]=0;
4677
4678                                                         p[0] = 0;
4679
4680                                                         if (obj->data.rss.act_par > data->item_count) {
4681                                                                 show = data->item_count;
4682                                                         } else {
4683                                                                 show = obj->data.rss.act_par;
4684                                                         }
4685                                                         for (itmp = 0; itmp < show; itmp++) {
4686                                                                 PRSS_Item *item = &data->items[itmp];
4687
4688                                                                 str = item->title;
4689                                                                 if (str) {
4690                                                                         // don't add new line before first item
4691                                                                         if (itmp > 0) {
4692                                                                                 strncat(p, "\n", p_max_size);
4693                                                                         }
4694                                                                         /* remove trailing new line if one exists,
4695                                                                          * we have our own */
4696                                                                         if (str[strlen(str) - 1] == '\n') {
4697                                                                                 str[strlen(str) - 1] = 0;
4698                                                                         }
4699                                                                         strncat(p, tmpspaces, p_max_size);
4700                                                                         strncat(p, str, p_max_size);
4701                                                                 }
4702                                                         }
4703                                                         free(tmpspaces);
4704                                                 }
4705                                         }
4706                                 }
4707                         }
4708 #endif
4709 #ifdef WEATHER
4710                         OBJ(weather) {
4711                                 if( obj->data.weather.uri != NULL ) {
4712                                         process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
4713                                 } else {
4714                                   strncpy(p, "either invalid xoap keys file or compiled without xoap support",  p_max_size);
4715                                 }
4716                         }
4717 #endif
4718 #ifdef HAVE_LUA
4719                         OBJ(lua) {
4720                                 char *str = llua_getstring(obj->data.s);
4721                                 if (str) {
4722                                         snprintf(p, p_max_size, "%s", str);
4723                                         free(str);
4724                                 }
4725                         }
4726                         OBJ(lua_parse) {
4727                                 char *str = llua_getstring(obj->data.s);
4728                                 if (str) {
4729                                         evaluate(str, p);
4730                                 }
4731                         }
4732                         OBJ(lua_bar) {
4733                                 double per;
4734                                 if (llua_getnumber(obj->data.s, &per)) {
4735 #ifdef X11
4736                                         if(output_methods & TO_X) {
4737                                                 new_bar(p, obj->a, obj->b, (per/100.0 * 255));
4738                                         } else {
4739 #endif /* X11 */
4740                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
4741                                                 new_bar_in_shell(p, p_max_size, per, obj->a);
4742 #ifdef X11
4743                                         }
4744 #endif /* X11 */
4745                                 }
4746                         }
4747 #ifdef X11
4748                         OBJ(lua_graph) {
4749                                 double per;
4750                                 if (llua_getnumber(obj->data.s, &per)) {
4751                                         new_graph(p, obj->a, obj->b, obj->c, obj->d,
4752                                                         per, obj->e, 1, obj->char_a, obj->char_b);
4753                                 }
4754                         }
4755                         OBJ(lua_gauge) {
4756                                 double per;
4757                                 if (llua_getnumber(obj->data.s, &per)) {
4758                                         new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
4759                                 }
4760                         }
4761 #endif /* X11 */
4762 #endif /* HAVE_LUA */
4763 #ifdef HDDTEMP
4764                         OBJ(hddtemp) {
4765                                 char *endptr, unit;
4766                                 long val;
4767                                 if (obj->data.hddtemp.update_time < current_update_time - 30) {
4768                                         if (obj->data.hddtemp.temp)
4769                                                 free(obj->data.hddtemp.temp);
4770                                         obj->data.hddtemp.temp = get_hddtemp_info(obj->data.hddtemp.dev,
4771                                                         obj->data.hddtemp.addr, obj->data.hddtemp.port);
4772                                         obj->data.hddtemp.update_time = current_update_time;
4773                                 }
4774                                 if (!obj->data.hddtemp.temp) {
4775                                         snprintf(p, p_max_size, "N/A");
4776                                 } else {
4777                                         val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
4778                                         unit = obj->data.hddtemp.temp[0];
4779
4780                                         if (*endptr != '\0')
4781                                                 snprintf(p, p_max_size, "N/A");
4782                                         else if (unit == 'C')
4783                                                 temp_print(p, p_max_size, (double)val, TEMP_CELSIUS);
4784                                         else if (unit == 'F')
4785                                                 temp_print(p, p_max_size, (double)val, TEMP_FAHRENHEIT);
4786                                         else
4787                                                 snprintf(p, p_max_size, "N/A");
4788                                 }
4789                         }
4790 #endif
4791                         OBJ(offset) {
4792                                 new_offset(p, obj->data.i);
4793                         }
4794                         OBJ(voffset) {
4795                                 new_voffset(p, obj->data.i);
4796                         }
4797 #ifdef __linux__
4798                         OBJ(i2c) {
4799                                 double r;
4800
4801                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
4802                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
4803
4804                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
4805
4806                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
4807                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
4808                                 } else if (r >= 100.0 || r == 0) {
4809                                         snprintf(p, p_max_size, "%d", (int) r);
4810                                 } else {
4811                                         snprintf(p, p_max_size, "%.1f", r);
4812                                 }
4813                         }
4814                         OBJ(platform) {
4815                                 double r;
4816
4817                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
4818                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
4819
4820                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
4821
4822                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
4823                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
4824                                 } else if (r >= 100.0 || r == 0) {
4825                                         snprintf(p, p_max_size, "%d", (int) r);
4826                                 } else {
4827                                         snprintf(p, p_max_size, "%.1f", r);
4828                                 }
4829                         }
4830                         OBJ(hwmon) {
4831                                 double r;
4832
4833                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
4834                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
4835
4836                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
4837
4838                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
4839                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
4840                                 } else if (r >= 100.0 || r == 0) {
4841                                         snprintf(p, p_max_size, "%d", (int) r);
4842                                 } else {
4843                                         snprintf(p, p_max_size, "%.1f", r);
4844                                 }
4845                         }
4846 #endif /* __linux__ */
4847                         OBJ(alignr) {
4848                                 new_alignr(p, obj->data.i);
4849                         }
4850                         OBJ(alignc) {
4851                                 new_alignc(p, obj->data.i);
4852                         }
4853                         OBJ(if_empty) {
4854                                 char buf[max_user_text];
4855                                 struct information *tmp_info =
4856                                         malloc(sizeof(struct information));
4857                                 memcpy(tmp_info, cur, sizeof(struct information));
4858                                 generate_text_internal(buf, max_user_text,
4859                                                        *obj->sub, tmp_info);
4860
4861                                 if (strlen(buf) != 0) {
4862                                         DO_JUMP;
4863                                 }
4864                                 free(tmp_info);
4865                         }
4866                         OBJ(if_match) {
4867                                 char expression[max_user_text];
4868                                 int val;
4869                                 struct information *tmp_info;
4870
4871                                 tmp_info = malloc(sizeof(struct information));
4872                                 memcpy(tmp_info, cur, sizeof(struct information));
4873                                 generate_text_internal(expression, max_user_text,
4874                                                        *obj->sub, tmp_info);
4875                                 DBGP("parsed arg into '%s'", expression);
4876
4877                                 val = compare(expression);
4878                                 if (val == -2) {
4879                                         ERR("compare failed for expression '%s'",
4880                                                         expression);
4881                                 } else if (!val) {
4882                                         DO_JUMP;
4883                                 }
4884                                 free(tmp_info);
4885                         }
4886                         OBJ(if_existing) {
4887                                 if (obj->data.ifblock.str
4888                                     && !check_contains(obj->data.ifblock.s,
4889                                                        obj->data.ifblock.str)) {
4890                                         DO_JUMP;
4891                                 } else if (obj->data.ifblock.s
4892                                            && access(obj->data.ifblock.s, F_OK)) {
4893                                         DO_JUMP;
4894                                 }
4895                         }
4896                         OBJ(if_mounted) {
4897                                 if ((obj->data.ifblock.s)
4898                                                 && (!check_mount(obj->data.ifblock.s))) {
4899                                         DO_JUMP;
4900                                 }
4901                         }
4902                         OBJ(if_running) {
4903 #ifdef __linux__
4904                                 if (!get_process_by_name(obj->data.ifblock.s)) {
4905 #else
4906                                 if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
4907 #endif
4908                                         DO_JUMP;
4909                                 }
4910                         }
4911 #if defined(__linux__)
4912                         OBJ(ioscheduler) {
4913                                 snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
4914                         }
4915 #endif
4916                         OBJ(kernel) {
4917                                 snprintf(p, p_max_size, "%s", cur->uname_s.release);
4918                         }
4919                         OBJ(machine) {
4920                                 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
4921                         }
4922
4923                         /* memory stuff */
4924                         OBJ(mem) {
4925                                 human_readable(cur->mem * 1024, p, 255);
4926                         }
4927                         OBJ(memeasyfree) {
4928                                 human_readable(cur->memeasyfree * 1024, p, 255);
4929                         }
4930                         OBJ(memfree) {
4931                                 human_readable(cur->memfree * 1024, p, 255);
4932                         }
4933                         OBJ(memmax) {
4934                                 human_readable(cur->memmax * 1024, p, 255);
4935                         }
4936                         OBJ(memperc) {
4937                                 if (cur->memmax)
4938                                         percent_print(p, p_max_size, cur->mem * 100 / cur->memmax);
4939                         }
4940 #ifdef X11
4941                         OBJ(memgauge){
4942                                 new_gauge(p, obj->data.pair.a, obj->data.pair.b,
4943                                         cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
4944                         }
4945 #endif /* X11 */
4946                         OBJ(membar) {
4947 #ifdef X11
4948                                 if(output_methods & TO_X) {
4949                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
4950                                                 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
4951                                 }else{
4952 #endif /* X11 */
4953                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
4954                                         new_bar_in_shell(p, p_max_size, cur->memmax ? (cur->mem * 100) / (cur->memmax) : 0, obj->data.pair.a);
4955 #ifdef X11
4956                                 }
4957 #endif /* X11 */
4958                         }
4959 #ifdef X11
4960                         OBJ(memgraph) {
4961                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
4962                                         cur->memmax ? (cur->mem * 100.0) / (cur->memmax) : 0.0,
4963                                         100, 1, obj->char_a, obj->char_b);
4964                         }
4965 #endif /* X11 */
4966                         /* mixer stuff */
4967                         OBJ(mixer) {
4968                                 percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
4969                         }
4970                         OBJ(mixerl) {
4971                                 percent_print(p, p_max_size, mixer_get_left(obj->data.l));
4972                         }
4973                         OBJ(mixerr) {
4974                                 percent_print(p, p_max_size, mixer_get_right(obj->data.l));
4975                         }
4976 #ifdef X11
4977                         OBJ(mixerbar) {
4978                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
4979                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_avg(obj->data.mixerbar.l)));
4980                         }
4981                         OBJ(mixerlbar) {
4982                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
4983                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_left(obj->data.mixerbar.l)));
4984                         }
4985                         OBJ(mixerrbar) {
4986                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
4987                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_right(obj->data.mixerbar.l)));
4988                         }
4989 #endif /* X11 */
4990                         OBJ(if_mixer_mute) {
4991                                 if (!mixer_is_mute(obj->data.ifblock.i)) {
4992                                         DO_JUMP;
4993                                 }
4994                         }
4995 #ifdef X11
4996 #define NOT_IN_X "Not running in X"
4997                         OBJ(monitor) {
4998                                 if(x_initialised != YES) {
4999                                         strncpy(p, NOT_IN_X, p_max_size);
5000                                 }else{
5001                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
5002                                 }
5003                         }
5004                         OBJ(monitor_number) {
5005                                 if(x_initialised != YES) {
5006                                         strncpy(p, NOT_IN_X, p_max_size);
5007                                 }else{
5008                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
5009                                 }
5010                         }
5011                         OBJ(desktop) {
5012                                 if(x_initialised != YES) {
5013                                         strncpy(p, NOT_IN_X, p_max_size);
5014                                 }else{
5015                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
5016                                 }
5017                         }
5018                         OBJ(desktop_number) {
5019                                 if(x_initialised != YES) {
5020                                         strncpy(p, NOT_IN_X, p_max_size);
5021                                 }else{
5022                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
5023                                 }
5024                         }
5025                         OBJ(desktop_name) {
5026                                 if(x_initialised != YES) {
5027                                         strncpy(p, NOT_IN_X, p_max_size);
5028                                 }else if(cur->x11.desktop.name != NULL) {
5029                                         strncpy(p, cur->x11.desktop.name, p_max_size);
5030                                 }
5031                         }
5032 #endif /* X11 */
5033
5034                         /* mail stuff */
5035                         OBJ(mails) {
5036                                 update_mail_count(&obj->data.local_mail);
5037                                 snprintf(p, p_max_size, "%d", obj->data.local_mail.mail_count);
5038                         }
5039                         OBJ(new_mails) {
5040                                 update_mail_count(&obj->data.local_mail);
5041                                 snprintf(p, p_max_size, "%d",
5042                                         obj->data.local_mail.new_mail_count);
5043                         }
5044                         OBJ(seen_mails) {
5045                                 update_mail_count(&obj->data.local_mail);
5046                                 snprintf(p, p_max_size, "%d",
5047                                         obj->data.local_mail.seen_mail_count);
5048                         }
5049                         OBJ(unseen_mails) {
5050                                 update_mail_count(&obj->data.local_mail);
5051                                 snprintf(p, p_max_size, "%d",
5052                                         obj->data.local_mail.unseen_mail_count);
5053                         }
5054                         OBJ(flagged_mails) {
5055                                 update_mail_count(&obj->data.local_mail);
5056                                 snprintf(p, p_max_size, "%d",
5057                                         obj->data.local_mail.flagged_mail_count);
5058                         }
5059                         OBJ(unflagged_mails) {
5060                                 update_mail_count(&obj->data.local_mail);
5061                                 snprintf(p, p_max_size, "%d",
5062                                         obj->data.local_mail.unflagged_mail_count);
5063                         }
5064                         OBJ(forwarded_mails) {
5065                                 update_mail_count(&obj->data.local_mail);
5066                                 snprintf(p, p_max_size, "%d",
5067                                         obj->data.local_mail.forwarded_mail_count);
5068                         }
5069                         OBJ(unforwarded_mails) {
5070                                 update_mail_count(&obj->data.local_mail);
5071                                 snprintf(p, p_max_size, "%d",
5072                                         obj->data.local_mail.unforwarded_mail_count);
5073                         }
5074                         OBJ(replied_mails) {
5075                                 update_mail_count(&obj->data.local_mail);
5076                                 snprintf(p, p_max_size, "%d",
5077                                         obj->data.local_mail.replied_mail_count);
5078                         }
5079                         OBJ(unreplied_mails) {
5080                                 update_mail_count(&obj->data.local_mail);
5081                                 snprintf(p, p_max_size, "%d",
5082                                         obj->data.local_mail.unreplied_mail_count);
5083                         }
5084                         OBJ(draft_mails) {
5085                                 update_mail_count(&obj->data.local_mail);
5086                                 snprintf(p, p_max_size, "%d",
5087                                         obj->data.local_mail.draft_mail_count);
5088                         }
5089                         OBJ(trashed_mails) {
5090                                 update_mail_count(&obj->data.local_mail);
5091                                 snprintf(p, p_max_size, "%d",
5092                                         obj->data.local_mail.trashed_mail_count);
5093                         }
5094                         OBJ(mboxscan) {
5095                                 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
5096                                         text_buffer_size);
5097                                 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
5098                         }
5099                         OBJ(nodename) {
5100                                 snprintf(p, p_max_size, "%s", cur->uname_s.nodename);
5101                         }
5102                         OBJ(outlinecolor) {
5103                                 new_outline(p, obj->data.l);
5104                         }
5105                         OBJ(processes) {
5106                                 spaced_print(p, p_max_size, "%hu", 4, cur->procs);
5107                         }
5108                         OBJ(running_processes) {
5109                                 spaced_print(p, p_max_size, "%hu", 4, cur->run_procs);
5110                         }
5111                         OBJ(text) {
5112                                 snprintf(p, p_max_size, "%s", obj->data.s);
5113                         }
5114 #ifdef X11
5115                         OBJ(shadecolor) {
5116                                 new_bg(p, obj->data.l);
5117                         }
5118                         OBJ(stippled_hr) {
5119                                 new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
5120                         }
5121 #endif /* X11 */
5122                         OBJ(swap) {
5123                                 human_readable(cur->swap * 1024, p, 255);
5124                         }
5125                         OBJ(swapfree) {
5126                                 human_readable(cur->swapfree * 1024, p, 255);
5127                         }
5128                         OBJ(swapmax) {
5129                                 human_readable(cur->swapmax * 1024, p, 255);
5130                         }
5131                         OBJ(swapperc) {
5132                                 if (cur->swapmax == 0) {
5133                                         strncpy(p, "No swap", p_max_size);
5134                                 } else {
5135                                         percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
5136                                 }
5137                         }
5138                         OBJ(swapbar) {
5139 #ifdef X11
5140                                 if(output_methods & TO_X) {
5141                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
5142                                                 cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
5143                                 }else{
5144 #endif /* X11 */
5145                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
5146                                         new_bar_in_shell(p, p_max_size, cur->swapmax ? (cur->swap * 100) / (cur->swapmax) : 0, obj->data.pair.a);
5147 #ifdef X11
5148                                 }
5149 #endif /* X11 */
5150                         }
5151                         OBJ(sysname) {
5152                                 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
5153                         }
5154                         OBJ(time) {
5155                                 time_t t = time(NULL);
5156                                 struct tm *tm = localtime(&t);
5157
5158                                 setlocale(LC_TIME, "");
5159                                 strftime(p, p_max_size, obj->data.s, tm);
5160                         }
5161                         OBJ(utime) {
5162                                 time_t t = time(NULL);
5163                                 struct tm *tm = gmtime(&t);
5164
5165                                 strftime(p, p_max_size, obj->data.s, tm);
5166                         }
5167                         OBJ(tztime) {
5168                                 char *oldTZ = NULL;
5169                                 time_t t;
5170                                 struct tm *tm;
5171
5172                                 if (obj->data.tztime.tz) {
5173                                         oldTZ = getenv("TZ");
5174                                         setenv("TZ", obj->data.tztime.tz, 1);
5175                                         tzset();
5176                                 }
5177                                 t = time(NULL);
5178                                 tm = localtime(&t);
5179
5180                                 setlocale(LC_TIME, "");
5181                                 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
5182                                 if (oldTZ) {
5183                                         setenv("TZ", oldTZ, 1);
5184                                         tzset();
5185                                 } else {
5186                                         unsetenv("TZ");
5187                                 }
5188                                 // Needless to free oldTZ since getenv gives ptr to static data
5189                         }
5190                         OBJ(totaldown) {
5191                                 human_readable(obj->data.net->recv, p, 255);
5192                         }
5193                         OBJ(totalup) {
5194                                 human_readable(obj->data.net->trans, p, 255);
5195                         }
5196                         OBJ(updates) {
5197                                 snprintf(p, p_max_size, "%d", total_updates);
5198                         }
5199                         OBJ(if_updatenr) {
5200                                 if(total_updates % updatereset != obj->data.ifblock.i - 1) {
5201                                         DO_JUMP;
5202                                 }
5203                         }
5204                         OBJ(upspeed) {
5205                                 human_readable(obj->data.net->trans_speed, p, 255);
5206                         }
5207                         OBJ(upspeedf) {
5208                                 spaced_print(p, p_max_size, "%.1f", 8,
5209                                         obj->data.net->trans_speed / 1024.0);
5210                         }
5211 #ifdef X11
5212                         OBJ(upspeedgraph) {
5213                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
5214                                         obj->data.net->trans_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
5215                         }
5216 #endif /* X11 */
5217                         OBJ(uptime_short) {
5218                                 format_seconds_short(p, p_max_size, (int) cur->uptime);
5219                         }
5220                         OBJ(uptime) {
5221                                 format_seconds(p, p_max_size, (int) cur->uptime);
5222                         }
5223                         OBJ(user_names) {
5224                                 snprintf(p, p_max_size, "%s", cur->users.names);
5225                         }
5226                         OBJ(user_terms) {
5227                                 snprintf(p, p_max_size, "%s", cur->users.terms);
5228                         }
5229                         OBJ(user_times) {
5230                                 snprintf(p, p_max_size, "%s", cur->users.times);
5231                         }
5232                         OBJ(user_number) {
5233                                 snprintf(p, p_max_size, "%d", cur->users.number);
5234                         }
5235 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
5236                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
5237                         OBJ(apm_adapter) {
5238                                 char *msg;
5239
5240                                 msg = get_apm_adapter();
5241                                 snprintf(p, p_max_size, "%s", msg);
5242                                 free(msg);
5243                         }
5244                         OBJ(apm_battery_life) {
5245                                 char *msg;
5246
5247                                 msg = get_apm_battery_life();
5248                                 snprintf(p, p_max_size, "%s", msg);
5249                                 free(msg);
5250                         }
5251                         OBJ(apm_battery_time) {
5252                                 char *msg;
5253
5254                                 msg = get_apm_battery_time();
5255                                 snprintf(p, p_max_size, "%s", msg);
5256                                 free(msg);
5257                         }
5258 #endif /* __FreeBSD__ __OpenBSD__ */
5259
5260 #ifdef MPD
5261 #define mpd_printf(fmt, val) \
5262         snprintf(p, p_max_size, fmt, mpd_get_info()->val)
5263 #define mpd_sprintf(val) { \
5264         if (!obj->data.i || obj->data.i > p_max_size) \
5265                 mpd_printf("%s", val); \
5266         else \
5267                 snprintf(p, obj->data.i, "%s", mpd_get_info()->val); \
5268 }
5269                         OBJ(mpd_title)
5270                                 mpd_sprintf(title);
5271                         OBJ(mpd_artist)
5272                                 mpd_sprintf(artist);
5273                         OBJ(mpd_album)
5274                                 mpd_sprintf(album);
5275                         OBJ(mpd_random)
5276                                 mpd_printf("%s", random);
5277                         OBJ(mpd_repeat)
5278                                 mpd_printf("%s", repeat);
5279                         OBJ(mpd_track)
5280                                 mpd_sprintf(track);
5281                         OBJ(mpd_name)
5282                                 mpd_sprintf(name);
5283                         OBJ(mpd_file)
5284                                 mpd_sprintf(file);
5285                         OBJ(mpd_vol)
5286                                 mpd_printf("%d", volume);
5287                         OBJ(mpd_bitrate)
5288                                 mpd_printf("%d", bitrate);
5289                         OBJ(mpd_status)
5290                                 mpd_printf("%s", status);
5291                         OBJ(mpd_elapsed) {
5292                                 format_media_player_time(p, p_max_size, mpd_get_info()->elapsed);
5293                         }
5294                         OBJ(mpd_length) {
5295                                 format_media_player_time(p, p_max_size, mpd_get_info()->length);
5296                         }
5297                         OBJ(mpd_percent) {
5298                                 percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
5299                         }
5300                         OBJ(mpd_bar) {
5301 #ifdef X11
5302                                 if(output_methods & TO_X) {
5303                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
5304                                                 (int) (mpd_get_info()->progress * 255.0f));
5305                                 } else {
5306 #endif /* X11 */
5307                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
5308                                         new_bar_in_shell(p, p_max_size, (int) (mpd_get_info()->progress * 100.0f), obj->data.pair.a);
5309 #ifdef X11
5310                                 }
5311 #endif /* X11 */
5312                         }
5313                         OBJ(mpd_smart) {
5314                                 struct mpd_s *mpd = mpd_get_info();
5315                                 int len = obj->data.i;
5316                                 if (len == 0 || len > p_max_size)
5317                                         len = p_max_size;
5318
5319                                 memset(p, 0, p_max_size);
5320                                 if (mpd->artist && *mpd->artist &&
5321                                     mpd->title && *mpd->title) {
5322                                         snprintf(p, len, "%s - %s", mpd->artist,
5323                                                 mpd->title);
5324                                 } else if (mpd->title && *mpd->title) {
5325                                         snprintf(p, len, "%s", mpd->title);
5326                                 } else if (mpd->artist && *mpd->artist) {
5327                                         snprintf(p, len, "%s", mpd->artist);
5328                                 } else if (mpd->file && *mpd->file) {
5329                                         snprintf(p, len, "%s", mpd->file);
5330                                 } else {
5331                                         *p = 0;
5332                                 }
5333                         }
5334                         OBJ(if_mpd_playing) {
5335                                 if (!mpd_get_info()->is_playing) {
5336                                         DO_JUMP;
5337                                 }
5338                         }
5339 #undef mpd_sprintf
5340 #undef mpd_printf
5341 #endif
5342
5343 #ifdef MOC
5344 #define MOC_PRINT(t, a) \
5345         snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
5346                         OBJ(moc_state) {
5347                                 MOC_PRINT(state, "??");
5348                         }
5349                         OBJ(moc_file) {
5350                                 MOC_PRINT(file, "no file");
5351                         }
5352                         OBJ(moc_title) {
5353                                 MOC_PRINT(title, "no title");
5354                         }
5355                         OBJ(moc_artist) {
5356                                 MOC_PRINT(artist, "no artist");
5357                         }
5358                         OBJ(moc_song) {
5359                                 MOC_PRINT(song, "no song");
5360                         }
5361                         OBJ(moc_album) {
5362                                 MOC_PRINT(album, "no album");
5363                         }
5364                         OBJ(moc_totaltime) {
5365                                 MOC_PRINT(totaltime, "0:00");
5366                         }
5367                         OBJ(moc_timeleft) {
5368                                 MOC_PRINT(timeleft, "0:00");
5369                         }
5370                         OBJ(moc_curtime) {
5371                                 MOC_PRINT(curtime, "0:00");
5372                         }
5373                         OBJ(moc_bitrate) {
5374                                 MOC_PRINT(bitrate, "0Kbps");
5375                         }
5376                         OBJ(moc_rate) {
5377                                 MOC_PRINT(rate, "0KHz");
5378                         }
5379 #undef MOC_PRINT
5380 #endif /* MOC */
5381 #ifdef XMMS2
5382                         OBJ(xmms2_artist) {
5383                                 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
5384                         }
5385                         OBJ(xmms2_album) {
5386                                 snprintf(p, p_max_size, "%s", cur->xmms2.album);
5387                         }
5388                         OBJ(xmms2_title) {
5389                                 snprintf(p, p_max_size, "%s", cur->xmms2.title);
5390                         }
5391                         OBJ(xmms2_genre) {
5392                                 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
5393                         }
5394                         OBJ(xmms2_comment) {
5395                                 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
5396                         }
5397                         OBJ(xmms2_url) {
5398                                 snprintf(p, p_max_size, "%s", cur->xmms2.url);
5399                         }
5400                         OBJ(xmms2_status) {
5401                                 snprintf(p, p_max_size, "%s", cur->xmms2.status);
5402                         }
5403                         OBJ(xmms2_date) {
5404                                 snprintf(p, p_max_size, "%s", cur->xmms2.date);
5405                         }
5406                         OBJ(xmms2_tracknr) {
5407                                 if (cur->xmms2.tracknr != -1) {
5408                                         snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
5409                                 }
5410                         }
5411                         OBJ(xmms2_bitrate) {
5412                                 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
5413                         }
5414                         OBJ(xmms2_id) {
5415                                 snprintf(p, p_max_size, "%u", cur->xmms2.id);
5416                         }
5417                         OBJ(xmms2_size) {
5418                                 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
5419                         }
5420                         OBJ(xmms2_elapsed) {
5421                                 snprintf(p, p_max_size, "%02d:%02d", cur->xmms2.elapsed / 60000,
5422                                         (cur->xmms2.elapsed / 1000) % 60);
5423                         }
5424                         OBJ(xmms2_duration) {
5425                                 snprintf(p, p_max_size, "%02d:%02d",
5426                                         cur->xmms2.duration / 60000,
5427                                         (cur->xmms2.duration / 1000) % 60);
5428                         }
5429                         OBJ(xmms2_percent) {
5430                                 snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
5431                         }
5432 #ifdef X11
5433                         OBJ(xmms2_bar) {
5434                                 new_bar(p, obj->data.pair.a, obj->data.pair.b,
5435                                         (int) (cur->xmms2.progress * 255.0f));
5436                         }
5437 #endif /* X11 */
5438                         OBJ(xmms2_playlist) {
5439                                 snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
5440                         }
5441                         OBJ(xmms2_timesplayed) {
5442                                 snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
5443                         }
5444                         OBJ(xmms2_smart) {
5445                                 if (strlen(cur->xmms2.title) < 2
5446                                                 && strlen(cur->xmms2.title) < 2) {
5447                                         snprintf(p, p_max_size, "%s", cur->xmms2.url);
5448                                 } else {
5449                                         snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist,
5450                                                 cur->xmms2.title);
5451                                 }
5452                         }
5453                         OBJ(if_xmms2_connected) {
5454                                 if (cur->xmms2.conn_state != 1) {
5455                                         DO_JUMP;
5456                                 }
5457                         }
5458 #endif /* XMMS */
5459 #ifdef AUDACIOUS
5460                         OBJ(audacious_status) {
5461                                 snprintf(p, p_max_size, "%s",
5462                                         cur->audacious.items[AUDACIOUS_STATUS]);
5463                         }
5464                         OBJ(audacious_title) {
5465                                 snprintf(p, cur->audacious.max_title_len > 0
5466                                         ? cur->audacious.max_title_len : p_max_size, "%s",
5467                                         cur->audacious.items[AUDACIOUS_TITLE]);
5468                         }
5469                         OBJ(audacious_length) {
5470                                 snprintf(p, p_max_size, "%s",
5471                                         cur->audacious.items[AUDACIOUS_LENGTH]);
5472                         }
5473                         OBJ(audacious_length_seconds) {
5474                                 snprintf(p, p_max_size, "%s",
5475                                         cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
5476                         }
5477                         OBJ(audacious_position) {
5478                                 snprintf(p, p_max_size, "%s",
5479                                         cur->audacious.items[AUDACIOUS_POSITION]);
5480                         }
5481                         OBJ(audacious_position_seconds) {
5482                                 snprintf(p, p_max_size, "%s",
5483                                         cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
5484                         }
5485                         OBJ(audacious_bitrate) {
5486                                 snprintf(p, p_max_size, "%s",
5487                                         cur->audacious.items[AUDACIOUS_BITRATE]);
5488                         }
5489                         OBJ(audacious_frequency) {
5490                                 snprintf(p, p_max_size, "%s",
5491                                         cur->audacious.items[AUDACIOUS_FREQUENCY]);
5492                         }
5493                         OBJ(audacious_channels) {
5494                                 snprintf(p, p_max_size, "%s",
5495                                         cur->audacious.items[AUDACIOUS_CHANNELS]);
5496                         }
5497                         OBJ(audacious_filename) {
5498                                 snprintf(p, p_max_size, "%s",
5499                                         cur->audacious.items[AUDACIOUS_FILENAME]);
5500                         }
5501                         OBJ(audacious_playlist_length) {
5502                                 snprintf(p, p_max_size, "%s",
5503                                         cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
5504                         }
5505                         OBJ(audacious_playlist_position) {
5506                                 snprintf(p, p_max_size, "%s",
5507                                         cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
5508                         }
5509                         OBJ(audacious_main_volume) {
5510                                 snprintf(p, p_max_size, "%s",
5511                                         cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
5512                         }
5513 #ifdef X11
5514                         OBJ(audacious_bar) {
5515                                 double progress;
5516
5517                                 progress =
5518                                         atof(cur->audacious.items[AUDACIOUS_POSITION_SECONDS]) /
5519                                         atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
5520                                 new_bar(p, obj->a, obj->b, (int) (progress * 255.0f));
5521                         }
5522 #endif /* X11 */
5523 #endif /* AUDACIOUS */
5524
5525 #ifdef BMPX
5526                         OBJ(bmpx_title) {
5527                                 snprintf(p, p_max_size, "%s", cur->bmpx.title);
5528                         }
5529                         OBJ(bmpx_artist) {
5530                                 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
5531                         }
5532                         OBJ(bmpx_album) {
5533                                 snprintf(p, p_max_size, "%s", cur->bmpx.album);
5534                         }
5535                         OBJ(bmpx_uri) {
5536                                 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
5537                         }
5538                         OBJ(bmpx_track) {
5539                                 snprintf(p, p_max_size, "%i", cur->bmpx.track);
5540                         }
5541                         OBJ(bmpx_bitrate) {
5542                                 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
5543                         }
5544 #endif /* BMPX */
5545                         /* we have four different types of top (top, top_mem,
5546                          * top_time and top_io). To avoid having almost-same code four
5547                          * times, we have this special handler. */
5548                         break;
5549                         case OBJ_top:
5550                                 parse_top_args("top", obj->data.top.s, obj);
5551                                 if (!needed) needed = cur->cpu;
5552                         case OBJ_top_mem:
5553                                 parse_top_args("top_mem", obj->data.top.s, obj);
5554                                 if (!needed) needed = cur->memu;
5555                         case OBJ_top_time:
5556                                 parse_top_args("top_time", obj->data.top.s, obj);
5557                                 if (!needed) needed = cur->time;
5558 #ifdef IOSTATS
5559                         case OBJ_top_io:
5560                                 parse_top_args("top_io", obj->data.top.s, obj);
5561                                 if (!needed) needed = cur->io;
5562 #endif
5563
5564                                 if (needed[obj->data.top.num]) {
5565                                         char *timeval;
5566
5567                                         switch (obj->data.top.type) {
5568                                                 case TOP_NAME:
5569                                                         snprintf(p, top_name_width + 1, "%-*s", top_name_width,
5570                                                                         needed[obj->data.top.num]->name);
5571                                                         break;
5572                                                 case TOP_CPU:
5573                                                         snprintf(p, 7, "%6.2f",
5574                                                                         needed[obj->data.top.num]->amount);
5575                                                         break;
5576                                                 case TOP_PID:
5577                                                         snprintf(p, 6, "%5i",
5578                                                                         needed[obj->data.top.num]->pid);
5579                                                         break;
5580                                                 case TOP_MEM:
5581                                                         snprintf(p, 7, "%6.2f",
5582                                                                         needed[obj->data.top.num]->totalmem);
5583                                                         break;
5584                                                 case TOP_TIME:
5585                                                         timeval = format_time(
5586                                                                         needed[obj->data.top.num]->total_cpu_time, 9);
5587                                                         snprintf(p, 10, "%9s", timeval);
5588                                                         free(timeval);
5589                                                         break;
5590                                                 case TOP_MEM_RES:
5591                                                         human_readable(needed[obj->data.top.num]->rss,
5592                                                                         p, 255);
5593                                                         break;
5594                                                 case TOP_MEM_VSIZE:
5595                                                         human_readable(needed[obj->data.top.num]->vsize,
5596                                                                         p, 255);
5597                                                         break;
5598 #ifdef IOSTATS
5599                                                 case TOP_READ_BYTES:
5600                                                         human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
5601                                                                         p, 255);
5602                                                         break;
5603                                                 case TOP_WRITE_BYTES:
5604                                                         human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
5605                                                                         p, 255);
5606                                                         break;
5607                                                 case TOP_IO_PERC:
5608                                                         snprintf(p, 7, "%6.2f",
5609                                                                         needed[obj->data.top.num]->io_perc);
5610                                                         break;
5611 #endif
5612                                         }
5613                                 }
5614                         OBJ(tail)
5615                                 print_tail_object(obj, p, p_max_size);
5616                         OBJ(head)
5617                                 print_head_object(obj, p, p_max_size);
5618                         OBJ(lines) {
5619                                 FILE *fp = open_file(obj->data.s, &obj->a);
5620
5621                                 if(fp != NULL) {
5622 /* FIXME: use something more general (see also tail.c, head.c */
5623 #define BUFSZ 0x1000
5624                                         char buf[BUFSZ];
5625                                         int j, lines;
5626
5627                                         lines = 0;
5628                                         while(fgets(buf, BUFSZ, fp) != NULL){
5629                                                 for(j = 0; buf[j] != 0; j++) {
5630                                                         if(buf[j] == '\n') {
5631                                                                 lines++;
5632                                                         }
5633                                                 }
5634                                         }
5635                                         sprintf(p, "%d", lines);
5636                                         fclose(fp);
5637                                 } else {
5638                                         sprintf(p, "File Unreadable");
5639                                 }
5640                         }
5641
5642                         OBJ(words) {
5643                                 FILE *fp = open_file(obj->data.s, &obj->a);
5644
5645                                 if(fp != NULL) {
5646                                         char buf[BUFSZ];
5647                                         int j, words;
5648                                         char inword = FALSE;
5649
5650                                         words = 0;
5651                                         while(fgets(buf, BUFSZ, fp) != NULL){
5652                                                 for(j = 0; buf[j] != 0; j++) {
5653                                                         if(!isspace(buf[j])) {
5654                                                                 if(inword == FALSE) {
5655                                                                         words++;
5656                                                                         inword = TRUE;
5657                                                                 }
5658                                                         } else {
5659                                                                 inword = FALSE;
5660                                                         }
5661                                                 }
5662                                         }
5663                                         sprintf(p, "%d", words);
5664                                         fclose(fp);
5665                                 } else {
5666                                         sprintf(p, "File Unreadable");
5667                                 }
5668                         }
5669 #ifdef TCP_PORT_MONITOR
5670                         OBJ(tcp_portmon) {
5671                                 tcp_portmon_action(p, p_max_size,
5672                                                    &obj->data.tcp_port_monitor);
5673                         }
5674 #endif /* TCP_PORT_MONITOR */
5675
5676 #ifdef HAVE_ICONV
5677                         OBJ(iconv_start) {
5678                                 iconv_converting = 1;
5679                                 iconv_selected = obj->a;
5680                         }
5681                         OBJ(iconv_stop) {
5682                                 iconv_converting = 0;
5683                                 iconv_selected = 0;
5684                         }
5685 #endif /* HAVE_ICONV */
5686
5687                         OBJ(entropy_avail) {
5688                                 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
5689                         }
5690                         OBJ(entropy_perc) {
5691                                 percent_print(p, p_max_size,
5692                                               cur->entropy.entropy_avail *
5693                                               100 / cur->entropy.poolsize);
5694                         }
5695                         OBJ(entropy_poolsize) {
5696                                 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
5697                         }
5698                         OBJ(entropy_bar) {
5699                                 double entropy_perc;
5700
5701                                 entropy_perc = (double) cur->entropy.entropy_avail /
5702                                         (double) cur->entropy.poolsize;
5703 #ifdef X11
5704                                 if(output_methods & TO_X) {
5705                                         new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
5706                                 } else {
5707 #endif /* X11 */
5708                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
5709                                         new_bar_in_shell(p, p_max_size, (int) (entropy_perc * 100.0f), obj->a);
5710 #ifdef X11
5711                                 }
5712 #endif /* X11 */
5713                         }
5714 #ifdef IBM
5715                         OBJ(smapi) {
5716                                 char *s;
5717                                 if(obj->data.s) {
5718                                         s = smapi_get_val(obj->data.s);
5719                                         snprintf(p, p_max_size, "%s", s);
5720                                         free(s);
5721                                 }
5722                         }
5723                         OBJ(if_smapi_bat_installed) {
5724                                 int idx;
5725                                 if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
5726                                         if(!smapi_bat_installed(idx)) {
5727                                                 DO_JUMP;
5728                                         }
5729                                 } else
5730                                         ERR("argument to if_smapi_bat_installed must be an integer");
5731                         }
5732                         OBJ(smapi_bat_perc) {
5733                                 int idx, val;
5734                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
5735                                         val = smapi_bat_installed(idx) ?
5736                                                 smapi_get_bat_int(idx, "remaining_percent") : 0;
5737                                         percent_print(p, p_max_size, val);
5738                                 } else
5739                                         ERR("argument to smapi_bat_perc must be an integer");
5740                         }
5741                         OBJ(smapi_bat_temp) {
5742                                 int idx, val;
5743                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
5744                                         val = smapi_bat_installed(idx) ?
5745                                                 smapi_get_bat_int(idx, "temperature") : 0;
5746                                         /* temperature is in milli degree celsius */
5747                                         temp_print(p, p_max_size, val / 1000, TEMP_CELSIUS);
5748                                 } else
5749                                         ERR("argument to smapi_bat_temp must be an integer");
5750                         }
5751                         OBJ(smapi_bat_power) {
5752                                 int idx, val;
5753                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
5754                                         val = smapi_bat_installed(idx) ?
5755                                                 smapi_get_bat_int(idx, "power_now") : 0;
5756                                         /* power_now is in mW, set to W with one digit precision */
5757                                         snprintf(p, p_max_size, "%.1f", ((double)val / 1000));
5758                                 } else
5759                                         ERR("argument to smapi_bat_power must be an integer");
5760                         }
5761 #ifdef X11
5762                         OBJ(smapi_bat_bar) {
5763                                 if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
5764                                         new_bar(p, obj->a, obj->b, (int)
5765                                                         (255 * smapi_get_bat_int(obj->data.i, "remaining_percent") / 100));
5766                                 else
5767                                         new_bar(p, obj->a, obj->b, 0);
5768                         }
5769 #endif /* X11 */
5770 #endif /* IBM */
5771                         OBJ(blink) {
5772                                 //blinking like this can look a bit ugly if the chars in the font don't have the same width
5773                                 char buf[max_user_text];
5774                                 unsigned int j;
5775
5776                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
5777                                 snprintf(p, p_max_size, "%s", buf);
5778                                 if(total_updates % 2) {
5779                                         for(j=0; p[j] != 0; j++) {
5780                                                 p[j] = ' ';
5781                                         }
5782                                 }
5783                         }
5784                         OBJ(to_bytes) {
5785                                 char buf[max_user_text];
5786                                 long long bytes;
5787                                 char unit[16];  // 16 because we can also have long names (like mega-bytes)
5788
5789                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
5790                                 if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
5791                                         if(strncasecmp("b", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes);
5792                                         else if(strncasecmp("k", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024);
5793                                         else if(strncasecmp("m", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024);
5794                                         else if(strncasecmp("g", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024);
5795                                         else if(strncasecmp("t", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024 * 1024);
5796                                 }
5797                                 snprintf(p, p_max_size, "%s", buf);
5798                         }
5799                         OBJ(scroll) {
5800                                 unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
5801                                 char *pwithcolors;
5802                                 char buf[max_user_text];
5803                                 generate_text_internal(buf, max_user_text,
5804                                                        *obj->sub, cur);
5805                                 for(j = 0; buf[j] != 0; j++) {
5806                                         switch(buf[j]) {
5807                                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
5808 #define LINESEPARATOR '|'
5809                                                 buf[j]=LINESEPARATOR;
5810                                                 break;
5811                                         case SPECIAL_CHAR:
5812                                                 colorchanges++;
5813                                                 break;
5814                                         }
5815                                 }
5816                                 //no scrolling necessary if the length of the text to scroll is too short
5817                                 if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
5818                                         snprintf(p, p_max_size, "%s", buf);
5819                                         break;
5820                                 }
5821                                 //make sure a colorchange at the front is not part of the string we are going to show
5822                                 while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
5823                                         obj->data.scroll.start++;
5824                                 }
5825                                 //place all chars that should be visible in p, including colorchanges
5826                                 for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
5827                                         p[j] = *(buf + obj->data.scroll.start + j);
5828                                         if(p[j] == SPECIAL_CHAR) {
5829                                                 visibcolorchanges++;
5830                                         }
5831                                         //if there is still room fill it with spaces
5832                                         if( ! p[j]) break;
5833                                 }
5834                                 for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
5835                                         p[j] = ' ';
5836                                 }
5837                                 p[j] = 0;
5838                                 //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
5839                                 for(j = 0; j < obj->data.scroll.start; j++) {
5840                                         if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
5841                                 }
5842                                 pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
5843                                 for(j = 0; j < frontcolorchanges; j++) {
5844                                         pwithcolors[j] = SPECIAL_CHAR;
5845                                 }
5846                                 pwithcolors[j] = 0;
5847                                 strcat(pwithcolors,p);
5848                                 strend = strlen(pwithcolors);
5849                                 //and place the colorchanges not in front or in the visible part behind the visible part
5850                                 for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
5851                                         pwithcolors[strend + j] = SPECIAL_CHAR;
5852                                 }
5853                                 pwithcolors[strend + j] = 0;
5854                                 strcpy(p, pwithcolors);
5855                                 free(pwithcolors);
5856                                 //scroll
5857                                 obj->data.scroll.start += obj->data.scroll.step;
5858                                 if(buf[obj->data.scroll.start] == 0){
5859                                          obj->data.scroll.start = 0;
5860                                 }
5861                                 //reset color when scroll is finished
5862                                 new_fg(p + strlen(p), obj->data.scroll.resetcolor);
5863                         }
5864                         OBJ(combine) {
5865                                 char buf[2][max_user_text];
5866                                 int i, j;
5867                                 long longest=0;
5868                                 int nextstart;
5869                                 int nr_rows[2];
5870                                 struct llrows {
5871                                         char* row;
5872                                         struct llrows* next;
5873                                 };
5874                                 struct llrows *ll_rows[2], *current[2];
5875                                 struct text_object * objsub = obj->sub;
5876
5877                                 p[0]=0;
5878                                 for(i=0; i<2; i++) {
5879                                         nr_rows[i] = 1;
5880                                         nextstart = 0;
5881                                         ll_rows[i] = malloc(sizeof(struct llrows));
5882                                         current[i] = ll_rows[i];
5883                                         for(j=0; j<i; j++) objsub = objsub->sub;
5884                                         generate_text_internal(buf[i], max_user_text, *objsub, cur);
5885                                         for(j=0; buf[i][j] != 0; j++) {
5886                                                 if(buf[i][j] == '\t') buf[i][j] = ' ';
5887                                                 if(buf[i][j] == '\n') {
5888                                                         buf[i][j] = 0;
5889                                                         current[i]->row = strdup(buf[i]+nextstart);
5890                                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
5891                                                         current[i]->next = malloc(sizeof(struct llrows));
5892                                                         current[i] = current[i]->next;
5893                                                         nextstart = j + 1;
5894                                                         nr_rows[i]++;
5895                                                 }
5896                                         }
5897                                         current[i]->row = strdup(buf[i]+nextstart);
5898                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
5899                                         current[i]->next = NULL;
5900                                         current[i] = ll_rows[i];
5901                                 }
5902                                 for(j=0; j < (nr_rows[0] > nr_rows[1] ? nr_rows[0] : nr_rows[1] ); j++) {
5903                                         if(current[0]) {
5904                                                 strcat(p, current[0]->row);
5905                                                 i=strlen(current[0]->row);
5906                                         }else i = 0;
5907                                         while(i < longest) {
5908                                                 strcat(p, " ");
5909                                                 i++;
5910                                         }
5911                                         if(current[1]) {
5912                                                 strcat(p, obj->data.combine.seperation);
5913                                                 strcat(p, current[1]->row);
5914                                         }
5915                                         strcat(p, "\n");
5916                                         #ifdef HAVE_OPENMP
5917                                         #pragma omp parallel for schedule(dynamic,10)
5918                                         #endif /* HAVE_OPENMP */
5919                                         for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
5920                                 }
5921                                 #ifdef HAVE_OPENMP
5922                                 #pragma omp parallel for schedule(dynamic,10)
5923                                 #endif /* HAVE_OPENMP */
5924                                 for(i=0; i<2; i++) {
5925                                         while(ll_rows[i] != NULL) {
5926                                                 current[i]=ll_rows[i];
5927                                                 free(current[i]->row);
5928                                                 ll_rows[i]=current[i]->next;
5929                                                 free(current[i]);
5930                                         }
5931                                 }
5932                         }
5933 #ifdef NVIDIA
5934                         OBJ(nvidia) {
5935                                 int value = get_nvidia_value(obj->data.nvidia.type, display);
5936                                 if(value == -1)
5937                                         snprintf(p, p_max_size, "N/A");
5938                                 else if (obj->data.nvidia.type == NV_TEMP)
5939                                         temp_print(p, p_max_size, (double)value, TEMP_CELSIUS);
5940                                 else if (obj->data.nvidia.print_as_float &&
5941                                                 value > 0 && value < 100)
5942                                         snprintf(p, p_max_size, "%.1f", (float)value);
5943                                 else
5944                                         snprintf(p, p_max_size, "%d", value);
5945                         }
5946 #endif /* NVIDIA */
5947 #ifdef APCUPSD
5948                         OBJ(apcupsd) {
5949                                 /* This is just a meta-object to set host:port */
5950                         }
5951                         OBJ(apcupsd_name) {
5952                                 snprintf(p, p_max_size, "%s",
5953                                                  cur->apcupsd.items[APCUPSD_NAME]);
5954                         }
5955                         OBJ(apcupsd_model) {
5956                                 snprintf(p, p_max_size, "%s",
5957                                                  cur->apcupsd.items[APCUPSD_MODEL]);
5958                         }
5959                         OBJ(apcupsd_upsmode) {
5960                                 snprintf(p, p_max_size, "%s",
5961                                                  cur->apcupsd.items[APCUPSD_UPSMODE]);
5962                         }
5963                         OBJ(apcupsd_cable) {
5964                                 snprintf(p, p_max_size, "%s",
5965                                                  cur->apcupsd.items[APCUPSD_CABLE]);
5966                         }
5967                         OBJ(apcupsd_status) {
5968                                 snprintf(p, p_max_size, "%s",
5969                                                  cur->apcupsd.items[APCUPSD_STATUS]);
5970                         }
5971                         OBJ(apcupsd_linev) {
5972                                 snprintf(p, p_max_size, "%s",
5973                                                  cur->apcupsd.items[APCUPSD_LINEV]);
5974                         }
5975                         OBJ(apcupsd_load) {
5976                                 snprintf(p, p_max_size, "%s",
5977                                                  cur->apcupsd.items[APCUPSD_LOAD]);
5978                         }
5979                         OBJ(apcupsd_loadbar) {
5980                                 double progress;
5981 #ifdef X11
5982                                 if(output_methods & TO_X) {
5983                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
5984                                         new_bar(p, obj->a, obj->b, (int) progress);
5985                                 } else {
5986 #endif /* X11 */
5987                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
5988                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
5989                                         new_bar_in_shell(p, p_max_size, (int) progress, obj->a);
5990 #ifdef X11
5991                                 }
5992 #endif /* X11 */
5993                         }
5994 #ifdef X11
5995                         OBJ(apcupsd_loadgraph) {
5996                                 double progress;
5997                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]);
5998                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
5999                                                   (int)progress, 100, 1, obj->char_a, obj->char_b);
6000                         }
6001                         OBJ(apcupsd_loadgauge) {
6002                                 double progress;
6003                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
6004                                 new_gauge(p, obj->a, obj->b,
6005                                                   (int)progress);
6006                         }
6007 #endif /* X11 */
6008                         OBJ(apcupsd_charge) {
6009                                 snprintf(p, p_max_size, "%s",
6010                                                  cur->apcupsd.items[APCUPSD_CHARGE]);
6011                         }
6012                         OBJ(apcupsd_timeleft) {
6013                                 snprintf(p, p_max_size, "%s",
6014                                                  cur->apcupsd.items[APCUPSD_TIMELEFT]);
6015                         }
6016                         OBJ(apcupsd_temp) {
6017                                 snprintf(p, p_max_size, "%s",
6018                                                  cur->apcupsd.items[APCUPSD_TEMP]);
6019                         }
6020                         OBJ(apcupsd_lastxfer) {
6021                                 snprintf(p, p_max_size, "%s",
6022                                                  cur->apcupsd.items[APCUPSD_LASTXFER]);
6023                         }
6024 #endif /* APCUPSD */
6025                         break;
6026                 }
6027 #undef DO_JUMP
6028
6029
6030                 {
6031                         unsigned int a = strlen(p);
6032
6033 #ifdef HAVE_ICONV
6034                         if (a > 0 && iconv_converting && iconv_selected > 0
6035                                         && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) {
6036                                 int bytes;
6037                                 size_t dummy1, dummy2;
6038 #ifdef __FreeBSD__
6039                                 const char *ptr = buff_in;
6040 #else
6041                                 char *ptr = buff_in;
6042 #endif
6043                                 char *outptr = p;
6044
6045                                 dummy1 = dummy2 = a;
6046
6047                                 strncpy(buff_in, p, p_max_size);
6048
6049                                 iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL);
6050                                 while (dummy1 > 0) {
6051                                         bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1,
6052                                                         &outptr, &dummy2);
6053                                         if (bytes == -1) {
6054                                                 ERR("Iconv codeset conversion failed");
6055                                                 break;
6056                                         }
6057                                 }
6058
6059                                 /* It is nessecary when we are converting from multibyte to
6060                                  * singlebyte codepage */
6061                                 a = outptr - p;
6062                         }
6063 #endif /* HAVE_ICONV */
6064                         if (obj->type != OBJ_text) {
6065                                 substitute_newlines(p, a - 2);
6066                         }
6067                         p += a;
6068                         p_max_size -= a;
6069                 }
6070                 obj = obj->next;
6071         }
6072 #ifdef X11
6073         /* load any new fonts we may have had */
6074         if (need_to_load_fonts) {
6075                 load_fonts();
6076         }
6077 #endif /* X11 */
6078 }
6079
6080 void evaluate(char *text, char *buffer)
6081 {
6082         struct information *tmp_info;
6083         struct text_object subroot;
6084
6085         tmp_info = malloc(sizeof(struct information));
6086         memcpy(tmp_info, &info, sizeof(struct information));
6087         parse_conky_vars(&subroot, text, buffer, tmp_info);
6088         DBGP("evaluated '%s' to '%s'", text, buffer);
6089
6090         free_text_objects(&subroot, 1);
6091         free(tmp_info);
6092 }
6093
6094 double current_update_time, next_update_time, last_update_time;
6095
6096 static void generate_text(void)
6097 {
6098         struct information *cur = &info;
6099         char *p;
6100
6101         special_count = 0;
6102
6103         /* update info */
6104
6105         current_update_time = get_time();
6106
6107         update_stuff();
6108
6109         /* add things to the buffer */
6110
6111         /* generate text */
6112
6113         p = text_buffer;
6114
6115         generate_text_internal(p, max_user_text, global_root_object, cur);
6116
6117         if (stuff_in_uppercase) {
6118                 char *tmp_p;
6119
6120                 tmp_p = text_buffer;
6121                 while (*tmp_p) {
6122                         *tmp_p = toupper(*tmp_p);
6123                         tmp_p++;
6124                 }
6125         }
6126
6127         next_update_time += update_interval;
6128         if (next_update_time < get_time()) {
6129                 next_update_time = get_time() + update_interval;
6130         } else if (next_update_time > get_time() + update_interval) {
6131                 next_update_time = get_time() + update_interval;
6132         }
6133         last_update_time = current_update_time;
6134         total_updates++;
6135 }
6136
6137 static inline int get_string_width(const char *s)
6138 {
6139 #ifdef X11
6140         if (output_methods & TO_X) {
6141                 return *s ? calc_text_width(s, strlen(s)) : 0;
6142         }
6143 #endif /* X11 */
6144         return strlen(s);
6145 }
6146
6147 static int get_string_width_special(char *s, int special_index)
6148 {
6149 #ifdef X11
6150         char *p, *final;
6151         int idx = 1;
6152         int width = 0;
6153         long i;
6154
6155         if ((output_methods & TO_X) == 0) {
6156 #endif /* X11 */
6157                 return (s) ? strlen(s) : 0;
6158 #ifdef X11
6159         }
6160
6161         if (!s) {
6162                 return 0;
6163         }
6164
6165         p = strndup(s, text_buffer_size);
6166         final = p;
6167
6168         while (*p) {
6169                 if (*p == SPECIAL_CHAR) {
6170                         /* shift everything over by 1 so that the special char
6171                          * doesn't mess up the size calculation */
6172                         for (i = 0; i < (long)strlen(p); i++) {
6173                                 *(p + i) = *(p + i + 1);
6174                         }
6175                         if (specials[special_index + idx].type == GRAPH
6176                                         || specials[special_index + idx].type == GAUGE
6177                                         || specials[special_index + idx].type == BAR) {
6178                                 width += specials[special_index + idx].width;
6179                         }
6180                         idx++;
6181                 } else if (*p == SECRIT_MULTILINE_CHAR) {
6182                         *p = 0;
6183                         break;
6184                 } else {
6185                         p++;
6186                 }
6187         }
6188         if (strlen(final) > 1) {
6189                 width += calc_text_width(final, strlen(final));
6190         }
6191         free(final);
6192         return width;
6193 #endif /* X11 */
6194 }
6195
6196 #ifdef X11
6197 static int text_size_updater(char *s, int special_index);
6198
6199 int last_font_height;
6200 static void update_text_area(void)
6201 {
6202         int x = 0, y = 0;
6203
6204         if ((output_methods & TO_X) == 0)
6205                 return;
6206         /* update text size if it isn't fixed */
6207 #ifdef OWN_WINDOW
6208         if (!fixed_size)
6209 #endif
6210         {
6211                 text_width = minimum_width;
6212                 text_height = 0;
6213                 last_font_height = font_height();
6214                 for_each_line(text_buffer, text_size_updater);
6215                 text_width += 1;
6216                 if (text_height < minimum_height) {
6217                         text_height = minimum_height;
6218                 }
6219                 if (text_width > maximum_width && maximum_width > 0) {
6220                         text_width = maximum_width;
6221                 }
6222         }
6223
6224         /* get text position on workarea */
6225         switch (text_alignment) {
6226                 case TOP_LEFT:
6227                         x = gap_x;
6228                         y = gap_y;
6229                         break;
6230
6231                 case TOP_RIGHT:
6232                         x = workarea[2] - text_width - gap_x;
6233                         y = gap_y;
6234                         break;
6235
6236                 case TOP_MIDDLE:
6237                         x = workarea[2] / 2 - text_width / 2 - gap_x;
6238                         y = gap_y;
6239                         break;
6240
6241                 default:
6242                 case BOTTOM_LEFT:
6243                         x = gap_x;
6244                         y = workarea[3] - text_height - gap_y;
6245                         break;
6246
6247                 case BOTTOM_RIGHT:
6248                         x = workarea[2] - text_width - gap_x;
6249                         y = workarea[3] - text_height - gap_y;
6250                         break;
6251
6252                 case BOTTOM_MIDDLE:
6253                         x = workarea[2] / 2 - text_width / 2 - gap_x;
6254                         y = workarea[3] - text_height - gap_y;
6255                         break;
6256
6257                 case MIDDLE_LEFT:
6258                         x = gap_x;
6259                         y = workarea[3] / 2 - text_height / 2 - gap_y;
6260                         break;
6261
6262                 case MIDDLE_RIGHT:
6263                         x = workarea[2] - text_width - gap_x;
6264                         y = workarea[3] / 2 - text_height / 2 - gap_y;
6265                         break;
6266
6267 #ifdef OWN_WINDOW
6268                 case NONE:      // Let the WM manage the window
6269                         x = window.x;
6270                         y = window.y;
6271
6272                         fixed_pos = 1;
6273                         fixed_size = 1;
6274                         break;
6275 #endif
6276         }
6277 #ifdef OWN_WINDOW
6278
6279         if (own_window && !fixed_pos) {
6280                 x += workarea[0];
6281                 y += workarea[1];
6282                 text_start_x = window.border_inner_margin + window.border_outer_margin + window.border_width;
6283                 text_start_y = window.border_inner_margin + window.border_outer_margin + window.border_width;
6284                 window.x = x - window.border_inner_margin - window.border_outer_margin - window.border_width;
6285                 window.y = y - window.border_inner_margin - window.border_outer_margin - window.border_width;
6286         } else
6287 #endif
6288         {
6289                 /* If window size doesn't match to workarea's size,
6290                  * then window probably includes panels (gnome).
6291                  * Blah, doesn't work on KDE. */
6292                 if (workarea[2] != window.width || workarea[3] != window.height) {
6293                         y += workarea[1];
6294                         x += workarea[0];
6295                 }
6296
6297                 text_start_x = x;
6298                 text_start_y = y;
6299         }
6300 #ifdef HAVE_LUA
6301         /* update lua window globals */
6302         llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
6303 #endif /* HAVE_LUA */
6304 }
6305
6306 /* drawing stuff */
6307
6308 static int cur_x, cur_y;        /* current x and y for drawing */
6309 #endif
6310 //draw_mode also without X11 because we only need to print to stdout with FG
6311 static int draw_mode;           /* FG, BG or OUTLINE */
6312 #ifdef X11
6313 static long current_color;
6314
6315 static int text_size_updater(char *s, int special_index)
6316 {
6317         int w = 0;
6318         char *p;
6319
6320         if ((output_methods & TO_X) == 0)
6321                 return 0;
6322         /* get string widths and skip specials */
6323         p = s;
6324         while (*p) {
6325                 if (*p == SPECIAL_CHAR) {
6326                         *p = '\0';
6327                         w += get_string_width(s);
6328                         *p = SPECIAL_CHAR;
6329
6330                         if (specials[special_index].type == BAR
6331                                         || specials[special_index].type == GAUGE
6332                                         || specials[special_index].type == GRAPH) {
6333                                 w += specials[special_index].width;
6334                                 if (specials[special_index].height > last_font_height) {
6335                                         last_font_height = specials[special_index].height;
6336                                         last_font_height += font_height();
6337                                 }
6338                         } else if (specials[special_index].type == OFFSET) {
6339                                 if (specials[special_index].arg > 0) {
6340                                         w += specials[special_index].arg;
6341                                 }
6342                         } else if (specials[special_index].type == VOFFSET) {
6343                                 last_font_height += specials[special_index].arg;
6344                         } else if (specials[special_index].type == GOTO) {
6345                                 if (specials[special_index].arg > cur_x) {
6346                                         w = (int) specials[special_index].arg;
6347                                 }
6348                         } else if (specials[special_index].type == TAB) {
6349                                 int start = specials[special_index].arg;
6350                                 int step = specials[special_index].width;
6351
6352                                 if (!step || step < 0) {
6353                                         step = 10;
6354                                 }
6355                                 w += step - (cur_x - text_start_x - start) % step;
6356                         } else if (specials[special_index].type == FONT) {
6357                                 selected_font = specials[special_index].font_added;
6358                                 if (font_height() > last_font_height) {
6359                                         last_font_height = font_height();
6360                                 }
6361                         }
6362
6363                         special_index++;
6364                         s = p + 1;
6365                 } else if (*p == SECRIT_MULTILINE_CHAR) {
6366                         int lw;
6367                         *p = '\0';
6368                         lw = get_string_width(s);
6369                         *p = SECRIT_MULTILINE_CHAR;
6370                         s = p + 1;
6371                         w = lw > w ? lw : w;
6372                         text_height += last_font_height;
6373                 }
6374                 p++;
6375         }
6376         w += get_string_width(s);
6377         if (w > text_width) {
6378                 text_width = w;
6379         }
6380         if (text_width > maximum_width && maximum_width) {
6381                 text_width = maximum_width;
6382         }
6383
6384         text_height += last_font_height;
6385         last_font_height = font_height();
6386         return special_index;
6387 }
6388
6389 static inline void set_foreground_color(long c)
6390 {
6391         if ((output_methods & TO_X) == 0)
6392                 return;
6393         current_color = c;
6394         XSetForeground(display, window.gc, c);
6395 }
6396 #endif /* X11 */
6397
6398 static void draw_string(const char *s)
6399 {
6400         int i, i2, pos, width_of_s;
6401         int max = 0;
6402         int added;
6403
6404         if (s[0] == '\0') {
6405                 return;
6406         }
6407
6408         width_of_s = get_string_width(s);
6409         if ((output_methods & TO_STDOUT) && draw_mode == FG) {
6410                 printf("%s\n", s);
6411                 fflush(stdout); /* output immediately, don't buffer */
6412         }
6413         if ((output_methods & TO_STDERR) && draw_mode == FG) {
6414                 fprintf(stderr, "%s\n", s);
6415                 fflush(stderr); /* output immediately, don't buffer */
6416         }
6417         if ((output_methods & OVERWRITE_FILE) && draw_mode == FG && overwrite_fpointer) {
6418                 fprintf(overwrite_fpointer, "%s\n", s);
6419         }
6420         if ((output_methods & APPEND_FILE) && draw_mode == FG && append_fpointer) {
6421                 fprintf(append_fpointer, "%s\n", s);
6422         }
6423         memset(tmpstring1, 0, text_buffer_size);
6424         memset(tmpstring2, 0, text_buffer_size);
6425         strncpy(tmpstring1, s, text_buffer_size - 1);
6426         pos = 0;
6427         added = 0;
6428
6429 #ifdef X11
6430         if (output_methods & TO_X) {
6431                 max = ((text_width - width_of_s) / get_string_width(" "));
6432         }
6433 #endif /* X11 */
6434         /* This code looks for tabs in the text and coverts them to spaces.
6435          * The trick is getting the correct number of spaces, and not going
6436          * over the window's size without forcing the window larger. */
6437         for (i = 0; i < (int) text_buffer_size; i++) {
6438                 if (tmpstring1[i] == '\t') {
6439                         i2 = 0;
6440                         for (i2 = 0; i2 < (8 - (1 + pos) % 8) && added <= max; i2++) {
6441                                 /* guard against overrun */
6442                                 tmpstring2[MIN(pos + i2, (int)text_buffer_size - 1)] = ' ';
6443                                 added++;
6444                         }
6445                         pos += i2;
6446                 } else {
6447                         /* guard against overrun */
6448                         tmpstring2[MIN(pos, (int) text_buffer_size - 1)] = tmpstring1[i];
6449                         pos++;
6450                 }
6451         }
6452 #ifdef X11
6453         if (output_methods & TO_X) {
6454                 if (text_width == maximum_width) {
6455                         /* this means the text is probably pushing the limit,
6456                          * so we'll chop it */
6457                         while (cur_x + get_string_width(tmpstring2) - text_start_x
6458                                         > maximum_width && strlen(tmpstring2) > 0) {
6459                                 tmpstring2[strlen(tmpstring2) - 1] = '\0';
6460                         }
6461                 }
6462         }
6463 #endif /* X11 */
6464         s = tmpstring2;
6465 #ifdef X11
6466         if (output_methods & TO_X) {
6467 #ifdef XFT
6468                 if (use_xft) {
6469                         XColor c;
6470                         XftColor c2;
6471
6472                         c.pixel = current_color;
6473                         XQueryColor(display, DefaultColormap(display, screen), &c);
6474
6475                         c2.pixel = c.pixel;
6476                         c2.color.red = c.red;
6477                         c2.color.green = c.green;
6478                         c2.color.blue = c.blue;
6479                         c2.color.alpha = fonts[selected_font].font_alpha;
6480                         if (utf8_mode) {
6481                                 XftDrawStringUtf8(window.xftdraw, &c2, fonts[selected_font].xftfont,
6482                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
6483                         } else {
6484                                 XftDrawString8(window.xftdraw, &c2, fonts[selected_font].xftfont,
6485                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
6486                         }
6487                 } else
6488 #endif
6489                 {
6490                         XDrawString(display, window.drawable, window.gc, cur_x, cur_y, s,
6491                                 strlen(s));
6492                 }
6493                 cur_x += width_of_s;
6494         }
6495 #endif /* X11 */
6496         memcpy(tmpstring1, s, text_buffer_size);
6497 }
6498
6499 #ifdef X11
6500 int draw_each_line_inner(char *s, int special_index, int last_special_applied)
6501 {
6502         int font_h = font_height();
6503         int cur_y_add = 0;
6504         char *recurse = 0;
6505         char *p = s;
6506         int last_special_needed = -1;
6507         int orig_special_index = special_index;
6508
6509         cur_x = text_start_x;
6510         cur_y += font_ascent();
6511
6512         while (*p) {
6513                 if (*p == SECRIT_MULTILINE_CHAR) {
6514                         /* special newline marker for multiline objects */
6515                         recurse = p + 1;
6516                         *p = '\0';
6517                         break;
6518                 }
6519                 if (*p == SPECIAL_CHAR || last_special_applied > -1) {
6520                         int w = 0;
6521
6522                         /* draw string before special, unless we're dealing multiline
6523                          * specials */
6524                         if (last_special_applied > -1) {
6525                                 special_index = last_special_applied;
6526                         } else {
6527                                 *p = '\0';
6528                                 draw_string(s);
6529                                 *p = SPECIAL_CHAR;
6530                                 s = p + 1;
6531                         }
6532                         /* draw special */
6533                         switch (specials[special_index].type) {
6534                                 case HORIZONTAL_LINE:
6535                                 {
6536                                         int h = specials[special_index].height;
6537                                         int mid = font_ascent() / 2;
6538
6539                                         w = text_start_x + text_width - cur_x;
6540
6541                                         XSetLineAttributes(display, window.gc, h, LineSolid,
6542                                                 CapButt, JoinMiter);
6543                                         XDrawLine(display, window.drawable, window.gc, cur_x,
6544                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
6545                                         break;
6546                                 }
6547
6548                                 case STIPPLED_HR:
6549                                 {
6550                                         int h = specials[special_index].height;
6551                                         int tmp_s = specials[special_index].arg;
6552                                         int mid = font_ascent() / 2;
6553                                         char ss[2] = { tmp_s, tmp_s };
6554
6555                                         w = text_start_x + text_width - cur_x - 1;
6556                                         XSetLineAttributes(display, window.gc, h, LineOnOffDash,
6557                                                 CapButt, JoinMiter);
6558                                         XSetDashes(display, window.gc, 0, ss, 2);
6559                                         XDrawLine(display, window.drawable, window.gc, cur_x,
6560                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
6561                                         break;
6562                                 }
6563
6564                                 case BAR:
6565                                 {
6566                                         int h, bar_usage, by;
6567                                         if (cur_x - text_start_x > maximum_width
6568                                                         && maximum_width > 0) {
6569                                                 break;
6570                                         }
6571                                         h = specials[special_index].height;
6572                                         bar_usage = specials[special_index].arg;
6573                                         by = cur_y - (font_ascent() / 2) - 1;
6574
6575                                         if (h < font_h) {
6576                                                 by -= h / 2 - 1;
6577                                         }
6578                                         w = specials[special_index].width;
6579                                         if (w == 0) {
6580                                                 w = text_start_x + text_width - cur_x - 1;
6581                                         }
6582                                         if (w < 0) {
6583                                                 w = 0;
6584                                         }
6585
6586                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
6587                                                 CapButt, JoinMiter);
6588
6589                                         XDrawRectangle(display, window.drawable, window.gc, cur_x,
6590                                                 by, w, h);
6591                                         XFillRectangle(display, window.drawable, window.gc, cur_x,
6592                                                 by, w * bar_usage / 255, h);
6593                                         if (h > cur_y_add
6594                                                         && h > font_h) {
6595                                                 cur_y_add = h;
6596                                         }
6597                                         break;
6598                                 }
6599
6600                                 case GAUGE: /* new GAUGE  */
6601                                 {
6602                                         int h, by = 0;
6603                                         unsigned long last_colour = current_color;
6604 #ifdef MATH
6605                                         float angle, px, py;
6606                                         int usage;
6607 #endif /* MATH */
6608
6609                                         if (cur_x - text_start_x > maximum_width
6610                                                         && maximum_width > 0) {
6611                                                 break;
6612                                         }
6613
6614                                         h = specials[special_index].height;
6615                                         by = cur_y - (font_ascent() / 2) - 1;
6616
6617                                         if (h < font_h) {
6618                                                 by -= h / 2 - 1;
6619                                         }
6620                                         w = specials[special_index].width;
6621                                         if (w == 0) {
6622                                                 w = text_start_x + text_width - cur_x - 1;
6623                                         }
6624                                         if (w < 0) {
6625                                                 w = 0;
6626                                         }
6627
6628                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
6629                                                         CapButt, JoinMiter);
6630
6631                                         XDrawArc(display, window.drawable, window.gc,
6632                                                         cur_x, by, w, h * 2, 0, 180*64);
6633
6634 #ifdef MATH
6635                                         usage = specials[special_index].arg;
6636                                         angle = (M_PI)*(float)(usage)/255.;
6637                                         px = (float)(cur_x+(w/2.))-(float)(w/2.)*cos(angle);
6638                                         py = (float)(by+(h))-(float)(h)*sin(angle);
6639
6640                                         XDrawLine(display, window.drawable, window.gc,
6641                                                         cur_x + (w/2.), by+(h), (int)(px), (int)(py));
6642 #endif /* MATH */
6643
6644                                         if (h > cur_y_add
6645                                                         && h > font_h) {
6646                                                 cur_y_add = h;
6647                                         }
6648
6649                                         set_foreground_color(last_colour);
6650
6651                                         break;
6652
6653                                 }
6654
6655                                 case GRAPH:
6656                                 {
6657                                         int h, by, i = 0, j = 0;
6658                                         int colour_idx = 0;
6659                                         unsigned long last_colour = current_color;
6660                                         unsigned long *tmpcolour = 0;
6661                                         if (cur_x - text_start_x > maximum_width
6662                                                         && maximum_width > 0) {
6663                                                 break;
6664                                         }
6665                                         h = specials[special_index].height;
6666                                         by = cur_y - (font_ascent() / 2) - 1;
6667
6668                                         if (h < font_h) {
6669                                                 by -= h / 2 - 1;
6670                                         }
6671                                         w = specials[special_index].width;
6672                                         if (w == 0) {
6673                                                 w = text_start_x + text_width - cur_x - 1;
6674                                         }
6675                                         if (w < 0) {
6676                                                 w = 0;
6677                                         }
6678                                         if (draw_graph_borders) {
6679                                                 XSetLineAttributes(display, window.gc, 1, LineSolid,
6680                                                         CapButt, JoinMiter);
6681                                                 XDrawRectangle(display, window.drawable, window.gc,
6682                                                         cur_x, by, w, h);
6683                                         }
6684                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
6685                                                 CapButt, JoinMiter);
6686
6687                                         if (specials[special_index].last_colour != 0
6688                                                         || specials[special_index].first_colour != 0) {
6689                                                 tmpcolour = do_gradient(w - 1, specials[special_index].last_colour, specials[special_index].first_colour);
6690                                         }
6691                                         colour_idx = 0;
6692                                         for (i = w - 2; i > -1; i--) {
6693                                                 if (specials[special_index].last_colour != 0
6694                                                                 || specials[special_index].first_colour != 0) {
6695                                                         if (specials[special_index].tempgrad) {
6696 #ifdef DEBUG_lol
6697                                                                 assert(
6698                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
6699                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
6700                                                                                 < w - 1
6701                                                                           );
6702                                                                 assert(
6703                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
6704                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
6705                                                                                 > -1
6706                                                                           );
6707                                                                 if (specials[special_index].graph[j] == specials[special_index].graph_scale) {
6708                                                                         assert(
6709                                                                                         (int)((float)(w - 2) - specials[special_index].graph[j] *
6710                                                                                                 (w - 2) / (float)specials[special_index].graph_scale)
6711                                                                                         == 0
6712                                                                                   );
6713                                                                 }
6714 #endif /* DEBUG_lol */
6715                                                                 XSetForeground(display, window.gc, tmpcolour[
6716                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
6717                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
6718                                                                                 ]);
6719                                                         } else {
6720                                                                 XSetForeground(display, window.gc, tmpcolour[colour_idx++]);
6721                                                         }
6722                                                 }
6723                                                 /* this is mugfugly, but it works */
6724                                                 XDrawLine(display, window.drawable, window.gc,
6725                                                                 cur_x + i + 1, by + h, cur_x + i + 1,
6726                                                                 round_to_int((double)by + h - specials[special_index].graph[j] *
6727                                                                         (h - 1) / specials[special_index].graph_scale));
6728                                                 if ((w - i) / ((float) (w - 2) /
6729                                                                         (specials[special_index].graph_width)) > j
6730                                                                 && j < MAX_GRAPH_DEPTH - 3) {
6731                                                         j++;
6732                                                 }
6733                                         }
6734                                         if (tmpcolour) free(tmpcolour);
6735                                         if (h > cur_y_add
6736                                                         && h > font_h) {
6737                                                 cur_y_add = h;
6738                                         }
6739                                         /* if (draw_mode == BG) {
6740                                                 set_foreground_color(default_bg_color);
6741                                         } else if (draw_mode == OUTLINE) {
6742                                                 set_foreground_color(default_out_color);
6743                                         } else {
6744                                                 set_foreground_color(default_fg_color);
6745                                         } */
6746                                         if (show_graph_range) {
6747                                                 int tmp_x = cur_x;
6748                                                 int tmp_y = cur_y;
6749                                                 unsigned short int seconds = update_interval * w;
6750                                                 char *tmp_day_str;
6751                                                 char *tmp_hour_str;
6752                                                 char *tmp_min_str;
6753                                                 char *tmp_sec_str;
6754                                                 char *tmp_str;
6755                                                 unsigned short int timeunits;
6756                                                 if (seconds != 0) {
6757                                                         timeunits = seconds / 86400; seconds %= 86400;
6758                                                         if (timeunits > 0) {
6759                                                                 asprintf(&tmp_day_str, "%dd", timeunits);
6760                                                         } else {
6761                                                                 tmp_day_str = strdup("");
6762                                                         }
6763                                                         timeunits = seconds / 3600; seconds %= 3600;
6764                                                         if (timeunits > 0) {
6765                                                                 asprintf(&tmp_hour_str, "%dh", timeunits);
6766                                                         } else {
6767                                                                 tmp_hour_str = strdup("");
6768                                                         }
6769                                                         timeunits = seconds / 60; seconds %= 60;
6770                                                         if (timeunits > 0) {
6771                                                                 asprintf(&tmp_min_str, "%dm", timeunits);
6772                                                         } else {
6773                                                                 tmp_min_str = strdup("");
6774                                                         }
6775                                                         if (seconds > 0) {
6776                                                                 asprintf(&tmp_sec_str, "%ds", seconds);
6777                                                         } else {
6778                                                                 tmp_sec_str = strdup("");
6779                                                         }
6780                                                         asprintf(&tmp_str, "%s%s%s%s", tmp_day_str, tmp_hour_str, tmp_min_str, tmp_sec_str);
6781                                                         free(tmp_day_str); free(tmp_hour_str); free(tmp_min_str); free(tmp_sec_str);
6782                                                 } else {
6783                                                         asprintf(&tmp_str, "Range not possible"); // should never happen, but better safe then sorry
6784                                                 }
6785                                                 cur_x += (w / 2) - (font_ascent() * (strlen(tmp_str) / 2));
6786                                                 cur_y += font_h / 2;
6787                                                 draw_string(tmp_str);
6788                                                 free(tmp_str);
6789                                                 cur_x = tmp_x;
6790                                                 cur_y = tmp_y;
6791                                         }
6792 #ifdef MATH
6793                                         if (show_graph_scale && (specials[special_index].show_scale == 1)) {
6794                                                 int tmp_x = cur_x;
6795                                                 int tmp_y = cur_y;
6796                                                 char *tmp_str;
6797                                                 cur_x += font_ascent() / 2;
6798                                                 cur_y += font_h / 2;
6799                                                 tmp_str = (char *)
6800                                                         calloc(log10(floor(specials[special_index].graph_scale)) + 4,
6801                                                                         sizeof(char));
6802                                                 sprintf(tmp_str, "%.1f", specials[special_index].graph_scale);
6803                                                 draw_string(tmp_str);
6804                                                 free(tmp_str);
6805                                                 cur_x = tmp_x;
6806                                                 cur_y = tmp_y;
6807                                         }
6808 #endif
6809                                         set_foreground_color(last_colour);
6810                                         break;
6811                                 }
6812
6813                                 case FONT:
6814                                 {
6815                                         int old = font_ascent();
6816
6817                                         cur_y -= font_ascent();
6818                                         selected_font = specials[special_index].font_added;
6819                                         set_font();
6820                                         if (cur_y + font_ascent() < cur_y + old) {
6821                                                 cur_y += old;
6822                                         } else {
6823                                                 cur_y += font_ascent();
6824                                         }
6825                                         font_h = font_height();
6826                                         break;
6827                                 }
6828                                 case FG:
6829                                         if (draw_mode == FG) {
6830                                                 set_foreground_color(specials[special_index].arg);
6831                                         }
6832                                         break;
6833
6834                                 case BG:
6835                                         if (draw_mode == BG) {
6836                                                 set_foreground_color(specials[special_index].arg);
6837                                         }
6838                                         break;
6839
6840                                 case OUTLINE:
6841                                         if (draw_mode == OUTLINE) {
6842                                                 set_foreground_color(specials[special_index].arg);
6843                                         }
6844                                         break;
6845
6846                                 case OFFSET:
6847                                         w += specials[special_index].arg;
6848                                         last_special_needed = special_index;
6849                                         break;
6850
6851                                 case VOFFSET:
6852                                         cur_y += specials[special_index].arg;
6853                                         break;
6854
6855                                 case GOTO:
6856                                         if (specials[special_index].arg >= 0) {
6857                                                 cur_x = (int) specials[special_index].arg;
6858                                         }
6859                                         last_special_needed = special_index;
6860                                         break;
6861
6862                                 case TAB:
6863                                 {
6864                                         int start = specials[special_index].arg;
6865                                         int step = specials[special_index].width;
6866
6867                                         if (!step || step < 0) {
6868                                                 step = 10;
6869                                         }
6870                                         w = step - (cur_x - text_start_x - start) % step;
6871                                         last_special_needed = special_index;
6872                                         break;
6873                                 }
6874
6875                                 case ALIGNR:
6876                                 {
6877                                         /* TODO: add back in "+ window.border_inner_margin" to the end of
6878                                          * this line? */
6879                                         int pos_x = text_start_x + text_width -
6880                                                 get_string_width_special(s, special_index);
6881
6882                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
6883                                                 "get_string_width(p) %i gap_x %i "
6884                                                 "specials[special_index].arg %i window.border_inner_margin %i "
6885                                                 "window.border_width %i\n", pos_x, text_start_x, text_width,
6886                                                 cur_x, get_string_width_special(s), gap_x,
6887                                                 specials[special_index].arg, window.border_inner_margin,
6888                                                 window.border_width); */
6889                                         if (pos_x > specials[special_index].arg && pos_x > cur_x) {
6890                                                 cur_x = pos_x - specials[special_index].arg;
6891                                         }
6892                                         last_special_needed = special_index;
6893                                         break;
6894                                 }
6895
6896                                 case ALIGNC:
6897                                 {
6898                                         int pos_x = (text_width) / 2 - get_string_width_special(s,
6899                                                         special_index) / 2 - (cur_x -
6900                                                                 text_start_x);
6901                                         /* int pos_x = text_start_x + text_width / 2 -
6902                                                 get_string_width_special(s) / 2; */
6903
6904                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
6905                                                 "get_string_width(p) %i gap_x %i "
6906                                                 "specials[special_index].arg %i\n", pos_x, text_start_x,
6907                                                 text_width, cur_x, get_string_width(s), gap_x,
6908                                                 specials[special_index].arg); */
6909                                         if (pos_x > specials[special_index].arg) {
6910                                                 w = pos_x - specials[special_index].arg;
6911                                         }
6912                                         last_special_needed = special_index;
6913                                         break;
6914                                 }
6915                         }
6916
6917                         cur_x += w;
6918
6919                         if (special_index != last_special_applied) {
6920                                 special_index++;
6921                         } else {
6922                                 special_index = orig_special_index;
6923                                 last_special_applied = -1;
6924                         }
6925                 }
6926                 p++;
6927         }
6928
6929         cur_y += cur_y_add;
6930         draw_string(s);
6931         cur_y += font_descent();
6932         if (recurse && *recurse) {
6933                 special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
6934                 *(recurse - 1) = SECRIT_MULTILINE_CHAR;
6935         }
6936         return special_index;
6937 }
6938 #endif /* X11 */
6939
6940 static int draw_line(char *s, int special_index)
6941 {
6942 #ifdef X11
6943         if ((output_methods & TO_X) == 0) {
6944 #endif /* X11 */
6945                 draw_string(s);
6946                 return 0;
6947 #ifdef X11
6948         }
6949
6950         /* find specials and draw stuff */
6951         return draw_each_line_inner(s, special_index, -1);
6952 #endif /* X11 */
6953 }
6954
6955 static void draw_text(void)
6956 {
6957 #ifdef X11
6958 #ifdef HAVE_LUA
6959         llua_draw_pre_hook();
6960 #endif /* HAVE_LUA */
6961         if (output_methods & TO_X) {
6962                 cur_y = text_start_y;
6963
6964                 /* draw borders */
6965                 if (draw_borders && window.border_width > 0) {
6966                         if (stippled_borders) {
6967                                 char ss[2] = { stippled_borders, stippled_borders };
6968                                 XSetLineAttributes(display, window.gc, window.border_width, LineOnOffDash,
6969                                         CapButt, JoinMiter);
6970                                 XSetDashes(display, window.gc, 0, ss, 2);
6971                         } else {
6972                                 XSetLineAttributes(display, window.gc, window.border_width, LineSolid,
6973                                         CapButt, JoinMiter);
6974                         }
6975
6976                         XDrawRectangle(display, window.drawable, window.gc,
6977                                 text_start_x - window.border_inner_margin - window.border_width,
6978                                 text_start_y - window.border_inner_margin - window.border_width,
6979                                 text_width + window.border_inner_margin * 2 + window.border_width * 2,
6980                                 text_height + window.border_inner_margin * 2 + window.border_width * 2);
6981                 }
6982
6983                 /* draw text */
6984         }
6985         setup_fonts();
6986 #endif /* X11 */
6987         for_each_line(text_buffer, draw_line);
6988 #if defined(HAVE_LUA) && defined(X11)
6989         llua_draw_post_hook();
6990 #endif /* HAVE_LUA */
6991 }
6992
6993 static void draw_stuff(void)
6994 {
6995         if (overwrite_file) {
6996                 overwrite_fpointer = fopen(overwrite_file, "w");
6997                 if(!overwrite_fpointer)
6998                         ERR("Can't overwrite '%s' anymore", overwrite_file);
6999         }
7000         if (append_file) {
7001                 append_fpointer = fopen(append_file, "a");
7002                 if(!append_fpointer)
7003                         ERR("Can't append '%s' anymore", append_file);
7004         }
7005 #ifdef X11
7006         if (output_methods & TO_X) {
7007                 selected_font = 0;
7008                 if (draw_shades && !draw_outline) {
7009                         text_start_x++;
7010                         text_start_y++;
7011                         set_foreground_color(default_bg_color);
7012                         draw_mode = BG;
7013                         draw_text();
7014                         text_start_x--;
7015                         text_start_y--;
7016                 }
7017
7018                 if (draw_outline) {
7019                         int i, j;
7020                         selected_font = 0;
7021
7022                         for (i = -1; i < 2; i++) {
7023                                 for (j = -1; j < 2; j++) {
7024                                         if (i == 0 && j == 0) {
7025                                                 continue;
7026                                         }
7027                                         text_start_x += i;
7028                                         text_start_y += j;
7029                                         set_foreground_color(default_out_color);
7030                                         draw_mode = OUTLINE;
7031                                         draw_text();
7032                                         text_start_x -= i;
7033                                         text_start_y -= j;
7034                                 }
7035                         }
7036                 }
7037
7038                 set_foreground_color(default_fg_color);
7039         }
7040 #endif /* X11 */
7041         draw_mode = FG;
7042         draw_text();
7043 #ifdef X11
7044         if (output_methods & TO_X) {
7045 #ifdef HAVE_XDBE
7046                 if (use_xdbe) {
7047                         XdbeSwapInfo swap;
7048
7049                         swap.swap_window = window.window;
7050                         swap.swap_action = XdbeBackground;
7051                         XdbeSwapBuffers(display, &swap, 1);
7052                 }
7053 #endif
7054         }
7055 #endif /* X11 */
7056         if(overwrite_fpointer) {
7057                 fclose(overwrite_fpointer);
7058                 overwrite_fpointer = 0;
7059         }
7060         if(append_fpointer) {
7061                 fclose(append_fpointer);
7062                 append_fpointer = 0;
7063         }
7064 }
7065
7066 #ifdef X11
7067 static void clear_text(int exposures)
7068 {
7069 #ifdef HAVE_XDBE
7070         if (use_xdbe) {
7071                 /* The swap action is XdbeBackground, which clears */
7072                 return;
7073         } else
7074 #endif
7075         if (display && window.window) { // make sure these are !null
7076                 /* there is some extra space for borders and outlines */
7077                 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
7078                         text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
7079                         text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
7080                         text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, exposures ? True : 0);
7081         }
7082 }
7083 #endif /* X11 */
7084
7085 static int need_to_update;
7086
7087 /* update_text() generates new text and clears old text area */
7088 static void update_text(void)
7089 {
7090 #ifdef IMLIB2
7091         cimlib_cleanup();
7092 #endif /* IMLIB2 */
7093         generate_text();
7094 #ifdef X11
7095         if (output_methods & TO_X)
7096                 clear_text(1);
7097 #endif /* X11 */
7098         need_to_update = 1;
7099 }
7100
7101 #ifdef HAVE_SYS_INOTIFY_H
7102 int inotify_fd;
7103 #endif
7104
7105 static void main_loop(void)
7106 {
7107         int terminate = 0;
7108 #ifdef SIGNAL_BLOCKING
7109         sigset_t newmask, oldmask;
7110 #endif
7111         double t;
7112 #ifdef HAVE_SYS_INOTIFY_H
7113         int inotify_config_wd = -1;
7114 #define INOTIFY_EVENT_SIZE  (sizeof(struct inotify_event))
7115 #define INOTIFY_BUF_LEN     (20 * (INOTIFY_EVENT_SIZE + 16))
7116         char inotify_buff[INOTIFY_BUF_LEN];
7117 #endif /* HAVE_SYS_INOTIFY_H */
7118
7119
7120 #ifdef SIGNAL_BLOCKING
7121         sigemptyset(&newmask);
7122         sigaddset(&newmask, SIGINT);
7123         sigaddset(&newmask, SIGTERM);
7124         sigaddset(&newmask, SIGUSR1);
7125 #endif
7126
7127         last_update_time = 0.0;
7128         next_update_time = get_time();
7129         info.looped = 0;
7130         while (terminate == 0 && (total_run_times == 0 || info.looped < total_run_times)) {
7131                 info.looped++;
7132
7133 #ifdef SIGNAL_BLOCKING
7134                 /* block signals.  we will inspect for pending signals later */
7135                 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
7136                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
7137                 }
7138 #endif
7139
7140 #ifdef X11
7141                 if (output_methods & TO_X) {
7142                         XFlush(display);
7143
7144                         /* wait for X event or timeout */
7145
7146                         if (!XPending(display)) {
7147                                 fd_set fdsr;
7148                                 struct timeval tv;
7149                                 int s;
7150                                 t = next_update_time - get_time();
7151
7152                                 if (t < 0) {
7153                                         t = 0;
7154                                 } else if (t > update_interval) {
7155                                         t = update_interval;
7156                                 }
7157
7158                                 tv.tv_sec = (long) t;
7159                                 tv.tv_usec = (long) (t * 1000000) % 1000000;
7160                                 FD_ZERO(&fdsr);
7161                                 FD_SET(ConnectionNumber(display), &fdsr);
7162
7163                                 s = select(ConnectionNumber(display) + 1, &fdsr, 0, 0, &tv);
7164                                 if (s == -1) {
7165                                         if (errno != EINTR) {
7166                                                 ERR("can't select(): %s", strerror(errno));
7167                                         }
7168                                 } else {
7169                                         /* timeout */
7170                                         if (s == 0) {
7171                                                 update_text();
7172                                         }
7173                                 }
7174                         }
7175
7176                         if (need_to_update) {
7177 #ifdef OWN_WINDOW
7178                                 int wx = window.x, wy = window.y;
7179 #endif
7180
7181                                 need_to_update = 0;
7182                                 selected_font = 0;
7183                                 update_text_area();
7184 #ifdef OWN_WINDOW
7185                                 if (own_window) {
7186                                         int changed = 0;
7187
7188                                         /* resize window if it isn't right size */
7189                                         if (!fixed_size
7190                                                 && (text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.width
7191                                                 || text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2 != window.height)) {
7192                                                         window.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7193                                                         window.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7194                                                         XResizeWindow(display, window.window, window.width,
7195                                                                 window.height);
7196                                                         set_transparent_background(window.window);
7197
7198                                                         changed++;
7199                                         }
7200
7201                                         /* move window if it isn't in right position */
7202                                         if (!fixed_pos && (window.x != wx || window.y != wy)) {
7203                                                 XMoveWindow(display, window.window, window.x, window.y);
7204                                                 changed++;
7205                                         }
7206
7207                                         /* update struts */
7208                                         if (changed && window.type == TYPE_PANEL) {
7209                                                 int sidenum = -1;
7210
7211                                                 fprintf(stderr, PACKAGE_NAME": defining struts\n");
7212                                                 fflush(stderr);
7213
7214                                                 switch (text_alignment) {
7215                                                         case TOP_LEFT:
7216                                                         case TOP_RIGHT:
7217                                                         case TOP_MIDDLE:
7218                                                         {
7219                                                                 sidenum = 2;
7220                                                                 break;
7221                                                         }
7222                                                         case BOTTOM_LEFT:
7223                                                         case BOTTOM_RIGHT:
7224                                                         case BOTTOM_MIDDLE:
7225                                                         {
7226                                                                 sidenum = 3;
7227                                                                 break;
7228                                                         }
7229                                                         case MIDDLE_LEFT:
7230                                                         {
7231                                                                 sidenum = 0;
7232                                                                 break;
7233                                                         }
7234                                                         case MIDDLE_RIGHT:
7235                                                         {
7236                                                                 sidenum = 1;
7237                                                                 break;
7238                                                         }
7239                                                 }
7240
7241                                                 set_struts(sidenum);
7242                                         }
7243                                 }
7244 #endif
7245
7246                                 clear_text(1);
7247
7248 #ifdef HAVE_XDBE
7249                                 if (use_xdbe) {
7250                                         XRectangle r;
7251
7252                                         r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
7253                                         r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
7254                                         r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7255                                         r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7256                                         XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
7257                                 }
7258 #endif
7259                         }
7260
7261                         /* handle X events */
7262                         while (XPending(display)) {
7263                                 XEvent ev;
7264
7265                                 XNextEvent(display, &ev);
7266                                 switch (ev.type) {
7267                                         case Expose:
7268                                         {
7269                                                 XRectangle r;
7270                                                 r.x = ev.xexpose.x;
7271                                                 r.y = ev.xexpose.y;
7272                                                 r.width = ev.xexpose.width;
7273                                                 r.height = ev.xexpose.height;
7274                                                 XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
7275                                                 break;
7276                                         }
7277
7278                                         case PropertyNotify:
7279                                         {
7280                                                 if ( ev.xproperty.state == PropertyNewValue ) {
7281                                                         get_x11_desktop_info( ev.xproperty.display, ev.xproperty.atom );
7282                                                 }
7283                                                 break;
7284                                         }
7285
7286 #ifdef OWN_WINDOW
7287                                         case ReparentNotify:
7288                                                 /* set background to ParentRelative for all parents */
7289                                                 if (own_window) {
7290                                                         set_transparent_background(window.window);
7291                                                 }
7292                                                 break;
7293
7294                                         case ConfigureNotify:
7295                                                 if (own_window) {
7296                                                         /* if window size isn't what expected, set fixed size */
7297                                                         if (ev.xconfigure.width != window.width
7298                                                                         || ev.xconfigure.height != window.height) {
7299                                                                 if (window.width != 0 && window.height != 0) {
7300                                                                         fixed_size = 1;
7301                                                                 }
7302
7303                                                                 /* clear old stuff before screwing up
7304                                                                  * size and pos */
7305                                                                 clear_text(1);
7306
7307                                                                 {
7308                                                                         XWindowAttributes attrs;
7309                                                                         if (XGetWindowAttributes(display,
7310                                                                                         window.window, &attrs)) {
7311                                                                                 window.width = attrs.width;
7312                                                                                 window.height = attrs.height;
7313                                                                         }
7314                                                                 }
7315
7316                                                                 text_width = window.width - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
7317                                                                 text_height = window.height - window.border_inner_margin * 2 - window.border_outer_margin * 2 - window.border_width * 2;
7318                                                                 if (text_width > maximum_width
7319                                                                                 && maximum_width > 0) {
7320                                                                         text_width = maximum_width;
7321                                                                 }
7322                                                         }
7323
7324                                                         /* if position isn't what expected, set fixed pos
7325                                                          * total_updates avoids setting fixed_pos when window
7326                                                          * is set to weird locations when started */
7327                                                         /* // this is broken
7328                                                         if (total_updates >= 2 && !fixed_pos
7329                                                                         && (window.x != ev.xconfigure.x
7330                                                                         || window.y != ev.xconfigure.y)
7331                                                                         && (ev.xconfigure.x != 0
7332                                                                         || ev.xconfigure.y != 0)) {
7333                                                                 fixed_pos = 1;
7334                                                         } */
7335                                                 }
7336                                                 break;
7337
7338                                         case ButtonPress:
7339                                                 if (own_window) {
7340                                                         /* if an ordinary window with decorations */
7341                                                         if ((window.type == TYPE_NORMAL)
7342                                                                 && (!TEST_HINT(window.hints,
7343                                                                 HINT_UNDECORATED))) {
7344                                                                 /* allow conky to hold input focus. */
7345                                                                 break;
7346                                                         } else {
7347                                                                 /* forward the click to the desktop window */
7348                                                                 XUngrabPointer(display, ev.xbutton.time);
7349                                                                 ev.xbutton.window = window.desktop;
7350                                                                 ev.xbutton.x = ev.xbutton.x_root;
7351                                                                 ev.xbutton.y = ev.xbutton.y_root;
7352                                                                 XSendEvent(display, ev.xbutton.window, False,
7353                                                                         ButtonPressMask, &ev);
7354                                                                 XSetInputFocus(display, ev.xbutton.window,
7355                                                                         RevertToParent, ev.xbutton.time);
7356                                                         }
7357                                                 }
7358                                                 break;
7359
7360                                         case ButtonRelease:
7361                                                 if (own_window) {
7362                                                         /* if an ordinary window with decorations */
7363                                                         if ((window.type == TYPE_NORMAL)
7364                                                                         && (!TEST_HINT(window.hints,
7365                                                                         HINT_UNDECORATED))) {
7366                                                                 /* allow conky to hold input focus. */
7367                                                                 break;
7368                                                         } else {
7369                                                                 /* forward the release to the desktop window */
7370                                                                 ev.xbutton.window = window.desktop;
7371                                                                 ev.xbutton.x = ev.xbutton.x_root;
7372                                                                 ev.xbutton.y = ev.xbutton.y_root;
7373                                                                 XSendEvent(display, ev.xbutton.window, False,
7374                                                                         ButtonReleaseMask, &ev);
7375                                                         }
7376                                                 }
7377                                                 break;
7378
7379 #endif
7380
7381                                         default:
7382 #ifdef HAVE_XDAMAGE
7383                                                 if (ev.type == x11_stuff.event_base + XDamageNotify) {
7384                                                         XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &ev;
7385
7386                                                         XFixesSetRegion(display, x11_stuff.part, &dev->area, 1);
7387                                                         XFixesUnionRegion(display, x11_stuff.region2, x11_stuff.region2, x11_stuff.part);
7388                                                 }
7389 #endif /* HAVE_XDAMAGE */
7390                                                 break;
7391                                 }
7392                         }
7393
7394 #ifdef HAVE_XDAMAGE
7395                         XDamageSubtract(display, x11_stuff.damage, x11_stuff.region2, None);
7396                         XFixesSetRegion(display, x11_stuff.region2, 0, 0);
7397 #endif /* HAVE_XDAMAGE */
7398
7399                         /* XDBE doesn't seem to provide a way to clear the back buffer without
7400                          * interfering with the front buffer, other than passing XdbeBackground
7401                          * to XdbeSwapBuffers. That means that if we're using XDBE, we need to
7402                          * redraw the text even if it wasn't part of the exposed area. OTOH,
7403                          * if we're not going to call draw_stuff at all, then no swap happens
7404                          * and we can safely do nothing. */
7405
7406                         if (!XEmptyRegion(x11_stuff.region)) {
7407 #ifdef HAVE_XDBE
7408                                 if (use_xdbe) {
7409                                         XRectangle r;
7410
7411                                         r.x = text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width;
7412                                         r.y = text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width;
7413                                         r.width = text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7414                                         r.height = text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2;
7415                                         XUnionRectWithRegion(&r, x11_stuff.region, x11_stuff.region);
7416                                 }
7417 #endif
7418                                 XSetRegion(display, window.gc, x11_stuff.region);
7419 #ifdef XFT
7420                                 if (use_xft) {
7421                                         XftDrawSetClip(window.xftdraw, x11_stuff.region);
7422                                 }
7423 #endif
7424 #ifdef IMLIB2
7425                                 cimlib_render(text_start_x, text_start_y, window.width, window.height);
7426 #endif /* IMLIB2 */
7427                                 draw_stuff();
7428                                 XDestroyRegion(x11_stuff.region);
7429                                 x11_stuff.region = XCreateRegion();
7430                         }
7431                 } else {
7432 #endif /* X11 */
7433                         t = (next_update_time - get_time()) * 1000000;
7434                         if(t > 0) usleep((useconds_t)t);
7435                         update_text();
7436                         draw_stuff();
7437 #ifdef X11
7438                 }
7439 #endif /* X11 */
7440
7441 #ifdef SIGNAL_BLOCKING
7442                 /* unblock signals of interest and let handler fly */
7443                 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
7444                         CRIT_ERR(NULL, NULL, "unable to sigprocmask()");
7445                 }
7446 #endif
7447
7448                 switch (g_signal_pending) {
7449                         case SIGHUP:
7450                         case SIGUSR1:
7451                                 ERR("received SIGHUP or SIGUSR1. reloading the config file.");
7452                                 reload_config();
7453                                 break;
7454                         case SIGINT:
7455                         case SIGTERM:
7456                                 ERR("received SIGINT or SIGTERM to terminate. bye!");
7457                                 terminate = 1;
7458 #ifdef X11
7459                                 if (output_methods & TO_X) {
7460                                         XDestroyRegion(x11_stuff.region);
7461                                         x11_stuff.region = NULL;
7462 #ifdef HAVE_XDAMAGE
7463                                         XDamageDestroy(display, x11_stuff.damage);
7464                                         XFixesDestroyRegion(display, x11_stuff.region2);
7465                                         XFixesDestroyRegion(display, x11_stuff.part);
7466 #endif /* HAVE_XDAMAGE */
7467                                         if (disp) {
7468                                                 free(disp);
7469                                         }
7470                                 }
7471 #endif /* X11 */
7472                                 if(overwrite_file) {
7473                                         free(overwrite_file);
7474                                         overwrite_file = 0;
7475                                 }
7476                                 if(append_file) {
7477                                         free(append_file);
7478                                         append_file = 0;
7479                                 }
7480                                 break;
7481                         default:
7482                                 /* Reaching here means someone set a signal
7483                                  * (SIGXXXX, signal_handler), but didn't write any code
7484                                  * to deal with it.
7485                                  * If you don't want to handle a signal, don't set a handler on
7486                                  * it in the first place. */
7487                                 if (g_signal_pending) {
7488                                         ERR("ignoring signal (%d)", g_signal_pending);
7489                                 }
7490                                 break;
7491                 }
7492 #ifdef HAVE_SYS_INOTIFY_H
7493                 if (inotify_fd != -1 && inotify_config_wd == -1 && current_config != 0) {
7494                         inotify_config_wd = inotify_add_watch(inotify_fd,
7495                                         current_config,
7496                                         IN_MODIFY);
7497                 }
7498                 if (inotify_fd != -1 && inotify_config_wd != -1 && current_config != 0) {
7499                         int len = 0, idx = 0;
7500                         fd_set descriptors;
7501                         struct timeval time_to_wait;
7502
7503                         FD_ZERO(&descriptors);
7504                         FD_SET(inotify_fd, &descriptors);
7505
7506                         time_to_wait.tv_sec = time_to_wait.tv_usec = 0;
7507
7508                         select(inotify_fd + 1, &descriptors, NULL, NULL, &time_to_wait);
7509                         if (FD_ISSET(inotify_fd, &descriptors)) {
7510                                 /* process inotify events */
7511                                 len = read(inotify_fd, inotify_buff, INOTIFY_BUF_LEN);
7512                                 while (len > 0 && idx < len) {
7513                                         struct inotify_event *ev = (struct inotify_event *) &inotify_buff[idx];
7514                                         if (ev->wd == inotify_config_wd && (ev->mask & IN_MODIFY || ev->mask & IN_IGNORED)) {
7515                                                 /* current_config should be reloaded */
7516                                                 ERR("'%s' modified, reloading...", current_config);
7517                                                 reload_config();
7518                                                 if (ev->mask & IN_IGNORED) {
7519                                                         /* for some reason we get IN_IGNORED here
7520                                                          * sometimes, so we need to re-add the watch */
7521                                                         inotify_config_wd = inotify_add_watch(inotify_fd,
7522                                                                         current_config,
7523                                                                         IN_MODIFY);
7524                                                 }
7525                                         }
7526 #ifdef HAVE_LUA
7527                                         else {
7528                                                 llua_inotify_query(ev->wd, ev->mask);
7529                                         }
7530 #endif /* HAVE_LUA */
7531                                         idx += INOTIFY_EVENT_SIZE + ev->len;
7532                                 }
7533                         }
7534                 }
7535 #endif /* HAVE_SYS_INOTIFY_H */
7536
7537                 g_signal_pending = 0;
7538         }
7539         clean_up(NULL, NULL);
7540
7541 #ifdef HAVE_SYS_INOTIFY_H
7542         if (inotify_fd != -1) {
7543                 inotify_rm_watch(inotify_fd, inotify_config_wd);
7544                 close(inotify_fd);
7545                 inotify_fd = inotify_config_wd = 0;
7546         }
7547 #endif /* HAVE_SYS_INOTIFY_H */
7548 }
7549
7550 static void load_config_file(const char *);
7551 #ifdef X11
7552 static void load_config_file_x11(const char *);
7553 #endif /* X11 */
7554 void initialisation(int argc, char** argv);
7555
7556         /* reload the config file */
7557 static void reload_config(void)
7558 {
7559         char *current_config_copy = strdup(current_config);
7560         clean_up(NULL, NULL);
7561         current_config = current_config_copy;
7562         initialisation(argc_copy, argv_copy);
7563 }
7564
7565 void clean_up(void *memtofree1, void* memtofree2)
7566 {
7567         int i;
7568         if(memtofree1) {
7569                 free(memtofree1);
7570         }
7571         if(memtofree2) {
7572                 free(memtofree2);
7573         }
7574         timed_thread_destroy_registered_threads();
7575
7576         if (info.cpu_usage) {
7577                 free(info.cpu_usage);
7578                 info.cpu_usage = NULL;
7579         }
7580 #ifdef X11
7581         if (x_initialised == YES) {
7582                 destroy_window();
7583                 free_fonts();
7584                 if(x11_stuff.region) {
7585                         XDestroyRegion(x11_stuff.region);
7586                         x11_stuff.region = NULL;
7587                 }
7588                 XClearWindow(display, RootWindow(display, screen));
7589                 XCloseDisplay(display);
7590                 display = NULL;
7591                 if(info.x11.desktop.all_names) {
7592                         free(info.x11.desktop.all_names);
7593                         info.x11.desktop.all_names = NULL;
7594                 }
7595                 if (info.x11.desktop.name) {
7596                         free(info.x11.desktop.name);
7597                         info.x11.desktop.name = NULL;
7598                 }
7599                 x_initialised = NO;
7600         }else{
7601                 free(fonts);    //in set_default_configurations a font is set but not loaded
7602                 font_count = -1;
7603         }
7604
7605 #endif /* X11 */
7606
7607         for (i = 0; i < MAX_TEMPLATES; i++) {
7608                 if (template[i]) {
7609                         free(template[i]);
7610                         template[i] = NULL;
7611                 }
7612         }
7613
7614         free_text_objects(&global_root_object, 0);
7615         if (tmpstring1) {
7616                 free(tmpstring1);
7617                 tmpstring1 = 0;
7618         }
7619         if (tmpstring2) {
7620                 free(tmpstring2);
7621                 tmpstring2 = 0;
7622         }
7623         if (text_buffer) {
7624                 free(text_buffer);
7625                 text_buffer = 0;
7626         }
7627
7628         if (global_text) {
7629                 free(global_text);
7630                 global_text = 0;
7631         }
7632
7633         free(current_config);
7634         current_config = 0;
7635
7636 #ifdef TCP_PORT_MONITOR
7637         tcp_portmon_clear();
7638 #endif
7639 #ifdef RSS
7640         free_rss_info();
7641 #endif
7642 #ifdef WEATHER
7643         free_weather_info();
7644 #endif
7645 #ifdef HAVE_LUA
7646         llua_close();
7647 #endif /* HAVE_LUA */
7648
7649         if (specials) {
7650                 for (i = 0; i < special_count; i++) {
7651                         if (specials[i].type == GRAPH) {
7652                                 free(specials[i].graph);
7653                         }
7654                 }
7655                 free(specials);
7656                 specials = NULL;
7657         }
7658
7659         clear_net_stats();
7660         clear_diskio_stats();
7661         if(global_cpu != NULL) {
7662                 free(global_cpu);
7663                 global_cpu = NULL;
7664         }
7665 }
7666
7667 static int string_to_bool(const char *s)
7668 {
7669         if (!s) {
7670                 // Assumes an option without a true/false means true
7671                 return 1;
7672         } else if (strcasecmp(s, "yes") == EQUAL) {
7673                 return 1;
7674         } else if (strcasecmp(s, "true") == EQUAL) {
7675                 return 1;
7676         } else if (strcasecmp(s, "1") == EQUAL) {
7677                 return 1;
7678         }
7679         return 0;
7680 }
7681
7682 #ifdef X11
7683 static enum alignment string_to_alignment(const char *s)
7684 {
7685         if (strcasecmp(s, "top_left") == EQUAL) {
7686                 return TOP_LEFT;
7687         } else if (strcasecmp(s, "top_right") == EQUAL) {
7688                 return TOP_RIGHT;
7689         } else if (strcasecmp(s, "top_middle") == EQUAL) {
7690                 return TOP_MIDDLE;
7691         } else if (strcasecmp(s, "bottom_left") == EQUAL) {
7692                 return BOTTOM_LEFT;
7693         } else if (strcasecmp(s, "bottom_right") == EQUAL) {
7694                 return BOTTOM_RIGHT;
7695         } else if (strcasecmp(s, "bottom_middle") == EQUAL) {
7696                 return BOTTOM_MIDDLE;
7697         } else if (strcasecmp(s, "middle_left") == EQUAL) {
7698                 return MIDDLE_LEFT;
7699         } else if (strcasecmp(s, "middle_right") == EQUAL) {
7700                 return MIDDLE_RIGHT;
7701         } else if (strcasecmp(s, "tl") == EQUAL) {
7702                 return TOP_LEFT;
7703         } else if (strcasecmp(s, "tr") == EQUAL) {
7704                 return TOP_RIGHT;
7705         } else if (strcasecmp(s, "tm") == EQUAL) {
7706                 return TOP_MIDDLE;
7707         } else if (strcasecmp(s, "bl") == EQUAL) {
7708                 return BOTTOM_LEFT;
7709         } else if (strcasecmp(s, "br") == EQUAL) {
7710                 return BOTTOM_RIGHT;
7711         } else if (strcasecmp(s, "bm") == EQUAL) {
7712                 return BOTTOM_MIDDLE;
7713         } else if (strcasecmp(s, "ml") == EQUAL) {
7714                 return MIDDLE_LEFT;
7715         } else if (strcasecmp(s, "mr") == EQUAL) {
7716                 return MIDDLE_RIGHT;
7717         } else if (strcasecmp(s, "none") == EQUAL) {
7718                 return NONE;
7719         }
7720         return TOP_LEFT;
7721 }
7722 #endif /* X11 */
7723
7724 #ifdef X11
7725 static void set_default_configurations_for_x(void)
7726 {
7727         default_fg_color = WhitePixel(display, screen);
7728         default_bg_color = BlackPixel(display, screen);
7729         default_out_color = BlackPixel(display, screen);
7730         color0 = default_fg_color;
7731         color1 = default_fg_color;
7732         color2 = default_fg_color;
7733         color3 = default_fg_color;
7734         color4 = default_fg_color;
7735         color5 = default_fg_color;
7736         color6 = default_fg_color;
7737         color7 = default_fg_color;
7738         color8 = default_fg_color;
7739         color9 = default_fg_color;
7740         current_text_color = default_fg_color;
7741 }
7742 #endif /* X11 */
7743
7744 static void set_default_configurations(void)
7745 {
7746         int i;
7747 #ifdef MPD
7748         char *mpd_env_host;
7749         char *mpd_env_port;
7750 #endif
7751         update_uname();
7752         fork_to_background = 0;
7753         total_run_times = 0;
7754         info.cpu_avg_samples = 2;
7755         info.net_avg_samples = 2;
7756         info.diskio_avg_samples = 2;
7757         info.memmax = 0;
7758         top_cpu = 0;
7759         cpu_separate = 0;
7760         short_units = 0;
7761         format_human_readable = 1;
7762         top_mem = 0;
7763         top_time = 0;
7764 #ifdef IOSTATS
7765         top_io = 0;
7766 #endif
7767 #ifdef MPD
7768         mpd_env_host = getenv("MPD_HOST");
7769         mpd_env_port = getenv("MPD_PORT");
7770
7771         if (!mpd_env_host || !strlen(mpd_env_host)) {
7772                 mpd_set_host("localhost");
7773         } else {
7774                 /* MPD_HOST environment variable is set */
7775                 char *mpd_hostpart = strchr(mpd_env_host, '@');
7776                 if (!mpd_hostpart) {
7777                         mpd_set_host(mpd_env_host);
7778                 } else {
7779                         /* MPD_HOST contains a password */
7780                         char mpd_password[mpd_hostpart - mpd_env_host + 1];
7781                         snprintf(mpd_password, mpd_hostpart - mpd_env_host + 1, "%s", mpd_env_host);
7782
7783                         if (!strlen(mpd_hostpart + 1)) {
7784                                 mpd_set_host("localhost");
7785                         } else {
7786                                 mpd_set_host(mpd_hostpart + 1);
7787                         }
7788
7789                         mpd_set_password(mpd_password, 1);
7790                 }
7791         }
7792
7793
7794         if (!mpd_env_port || mpd_set_port(mpd_env_port)) {
7795                 /* failed to set port from environment variable */
7796                 mpd_set_port("6600");
7797         }
7798 #endif
7799 #ifdef XMMS2
7800         info.xmms2.artist = NULL;
7801         info.xmms2.album = NULL;
7802         info.xmms2.title = NULL;
7803         info.xmms2.genre = NULL;
7804         info.xmms2.comment = NULL;
7805         info.xmms2.url = NULL;
7806         info.xmms2.status = NULL;
7807         info.xmms2.playlist = NULL;
7808 #endif
7809         use_spacer = NO_SPACER;
7810 #ifdef X11
7811         output_methods = TO_X;
7812 #else
7813         output_methods = TO_STDOUT;
7814 #endif
7815 #ifdef X11
7816         show_graph_scale = 0;
7817         show_graph_range = 0;
7818         draw_shades = 1;
7819         draw_borders = 0;
7820         draw_graph_borders = 1;
7821         draw_outline = 0;
7822         set_first_font("6x10");
7823         gap_x = 5;
7824         gap_y = 60;
7825         minimum_width = 5;
7826         minimum_height = 5;
7827         maximum_width = 0;
7828 #ifdef OWN_WINDOW
7829         own_window = 0;
7830         window.type = TYPE_NORMAL;
7831         window.hints = 0;
7832         strcpy(window.class_name, PACKAGE_NAME);
7833         sprintf(window.title, PACKAGE_NAME" (%s)", info.uname_s.nodename);
7834 #endif
7835         stippled_borders = 0;
7836         window.border_inner_margin = 3;
7837         window.border_outer_margin = 1;
7838         window.border_width = 1;
7839         text_alignment = BOTTOM_LEFT;
7840         info.x11.monitor.number = 1;
7841         info.x11.monitor.current = 0;
7842         info.x11.desktop.current = 1; 
7843         info.x11.desktop.number = 1;
7844         info.x11.desktop.nitems = 0;
7845         info.x11.desktop.all_names = NULL; 
7846         info.x11.desktop.name = NULL; 
7847 #endif /* X11 */
7848
7849         for (i = 0; i < MAX_TEMPLATES; i++) {
7850                 if (template[i])
7851                         free(template[i]);
7852                 template[i] = strdup("");
7853         }
7854
7855         free(current_mail_spool);
7856         {
7857                 char buf[256];
7858
7859                 variable_substitute(MAIL_FILE, buf, 256);
7860                 if (buf[0] != '\0') {
7861                         current_mail_spool = strndup(buf, text_buffer_size);
7862                 }
7863         }
7864
7865         no_buffers = 1;
7866         update_interval = 3.0;
7867         info.music_player_interval = 1.0;
7868         stuff_in_uppercase = 0;
7869         info.users.number = 1;
7870
7871 #ifdef TCP_PORT_MONITOR
7872         /* set default connection limit */
7873         tcp_portmon_set_max_connections(0);
7874 #endif
7875 }
7876
7877 /* returns 1 if you can overwrite or create the file at 'path' */
7878 static _Bool overwrite_works(const char *path)
7879 {
7880         FILE *filepointer;
7881
7882         if (!(filepointer = fopen(path, "w")))
7883                 return 0;
7884         fclose(filepointer);
7885         return 1;
7886 }
7887
7888 /* returns 1 if you can append or create the file at 'path' */
7889 static _Bool append_works(const char *path)
7890 {
7891         FILE *filepointer;
7892
7893         if (!(filepointer = fopen(path, "a")))
7894                 return 0;
7895         fclose(filepointer);
7896         return 1;
7897 }
7898
7899 #ifdef X11
7900 #ifdef DEBUG
7901 /* WARNING, this type not in Xlib spec */
7902 int x11_error_handler(Display *d, XErrorEvent *err)
7903         __attribute__((noreturn));
7904 int x11_error_handler(Display *d, XErrorEvent *err)
7905 {
7906         ERR("X Error: type %i Display %lx XID %li serial %lu error_code %i request_code %i minor_code %i other Display: %lx\n",
7907                         err->type,
7908                         (long unsigned)err->display,
7909                         (long)err->resourceid,
7910                         err->serial,
7911                         err->error_code,
7912                         err->request_code,
7913                         err->minor_code,
7914                         (long unsigned)d
7915                         );
7916         abort();
7917 }
7918
7919 int x11_ioerror_handler(Display *d)
7920         __attribute__((noreturn));
7921 int x11_ioerror_handler(Display *d)
7922 {
7923         ERR("X Error: Display %lx\n",
7924                         (long unsigned)d
7925                         );
7926         abort();
7927 }
7928 #endif /* DEBUG */
7929
7930 static void X11_initialisation(void)
7931 {
7932         if (x_initialised == YES) return;
7933         output_methods |= TO_X;
7934         init_X11(disp);
7935         set_default_configurations_for_x();
7936         x_initialised = YES;
7937 #ifdef DEBUG
7938         _Xdebug = 1;
7939         /* WARNING, this type not in Xlib spec */
7940         XSetErrorHandler(&x11_error_handler);
7941         XSetIOErrorHandler(&x11_ioerror_handler);
7942 #endif /* DEBUG */
7943 }
7944
7945 static char **xargv = 0;
7946 static int xargc = 0;
7947
7948 static void X11_create_window(void)
7949 {
7950         if (output_methods & TO_X) {
7951 #ifdef OWN_WINDOW
7952                 init_window(own_window, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
7953                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, background_colour,
7954                                 xargv, xargc);
7955 #else /* OWN_WINDOW */
7956                 init_window(0, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
7957                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, 0,
7958                                 xargv, xargc);
7959 #endif /* OWN_WINDOW */
7960
7961                 setup_fonts();
7962                 load_fonts();
7963                 update_text_area();     /* to position text/window on screen */
7964
7965 #ifdef OWN_WINDOW
7966                 if (own_window && !fixed_pos) {
7967                         XMoveWindow(display, window.window, window.x, window.y);
7968                 }
7969                 if (own_window) {
7970                         set_transparent_background(window.window);
7971                 }
7972 #endif
7973
7974                 create_gc();
7975
7976                 draw_stuff();
7977
7978                 x11_stuff.region = XCreateRegion();
7979 #ifdef HAVE_XDAMAGE
7980                 if (!XDamageQueryExtension(display, &x11_stuff.event_base, &x11_stuff.error_base)) {
7981                         ERR("Xdamage extension unavailable");
7982                 }
7983                 x11_stuff.damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
7984                 x11_stuff.region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
7985                 x11_stuff.part = XFixesCreateRegionFromWindow(display, window.window, 0);
7986 #endif /* HAVE_XDAMAGE */
7987
7988                 selected_font = 0;
7989                 update_text_area();     /* to get initial size of the window */
7990         }
7991 #ifdef HAVE_LUA
7992         /* setup lua window globals */
7993         llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
7994 #endif /* HAVE_LUA */
7995 }
7996 #endif /* X11 */
7997
7998 #define CONF_ERR ERR("%s: %d: config file error", f, line)
7999 #define CONF_ERR2(a) ERR("%s: %d: config file error: %s", f, line, a)
8000 #define CONF2(a) if (strcasecmp(name, a) == 0)
8001 #define CONF(a) else CONF2(a)
8002 #define CONF3(a, b) else if (strcasecmp(name, a) == 0 \
8003                 || strcasecmp(name, b) == 0)
8004 #define CONF_CONTINUE 1
8005 #define CONF_BREAK 2
8006 #define CONF_BUFF_SIZE 512
8007
8008 static FILE *open_config_file(const char *f)
8009 {
8010 #ifdef CONFIG_OUTPUT
8011         if (!strcmp(f, "==builtin==")) {
8012                 return conf_cookie_open();
8013         } else
8014 #endif /* CONFIG_OUTPUT */
8015                 return fopen(f, "r");
8016 }
8017
8018 static int do_config_step(int *line, FILE *fp, char *buf, char **name, char **value)
8019 {
8020         char *p, *p2;
8021         (*line)++;
8022         if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
8023                 return CONF_BREAK;
8024         }
8025         remove_comments(buf);
8026
8027         p = buf;
8028
8029         /* skip spaces */
8030         while (*p && isspace((int) *p)) {
8031                 p++;
8032         }
8033         if (*p == '\0') {
8034                 return CONF_CONTINUE;   /* empty line */
8035         }
8036
8037         *name = p;
8038
8039         /* skip name */
8040         p2 = p;
8041         while (*p2 && !isspace((int) *p2)) {
8042                 p2++;
8043         }
8044         if (*p2 != '\0') {
8045                 *p2 = '\0';     /* break at name's end */
8046                 p2++;
8047         }
8048
8049         /* get value */
8050         if (*p2) {
8051                 p = p2;
8052                 while (*p && isspace((int) *p)) {
8053                         p++;
8054                 }
8055
8056                 *value = p;
8057
8058                 p2 = *value + strlen(*value);
8059                 while (isspace((int) *(p2 - 1))) {
8060                         *--p2 = '\0';
8061                 }
8062         } else {
8063                 *value = 0;
8064         }
8065         return 0;
8066 }
8067
8068 static void load_config_file(const char *f)
8069 {
8070         int line = 0;
8071         FILE *fp;
8072
8073         set_default_configurations();
8074         fp = open_config_file(f);
8075         if (!fp) {
8076                 return;
8077         }
8078         DBGP("reading contents from config file '%s'", f);
8079
8080         while (!feof(fp)) {
8081                 char buff[CONF_BUFF_SIZE], *name, *value;
8082                 int ret = do_config_step(&line, fp, buff, &name, &value);
8083                 if (ret == CONF_BREAK) {
8084                         break;
8085                 } else if (ret == CONF_CONTINUE) {
8086                         continue;
8087                 }
8088
8089 #ifdef X11
8090                 CONF2("out_to_x") {
8091                         /* don't listen if X is already initialised or
8092                          * if we already know we don't want it */
8093                         if(x_initialised != YES) {
8094                                 if (string_to_bool(value)) {
8095                                         output_methods &= TO_X;
8096                                 } else {
8097                                         output_methods &= ~TO_X;
8098                                         x_initialised = NEVER;
8099                                 }
8100                         }
8101                 }
8102                 CONF("display") {
8103                         if (!value || x_initialised == YES) {
8104                                 CONF_ERR;
8105                         } else {
8106                                 if (disp)
8107                                         free(disp);
8108                                 disp = strdup(value);
8109                         }
8110                 }
8111                 CONF("alignment") {
8112 #ifdef OWN_WINDOW
8113                         if (window.type == TYPE_DOCK)
8114                                 ;
8115                         else
8116 #endif /*OWN_WINDOW */
8117                         if (value) {
8118                                 int a = string_to_alignment(value);
8119
8120                                 if (a <= 0) {
8121                                         CONF_ERR;
8122                                 } else {
8123                                         text_alignment = a;
8124                                 }
8125                         } else {
8126                                 CONF_ERR;
8127                         }
8128                 }
8129                 CONF("background") {
8130                         fork_to_background = string_to_bool(value);
8131                 }
8132 #else
8133                 CONF2("background") {
8134                         fork_to_background = string_to_bool(value);
8135                 }
8136 #endif /* X11 */
8137 #ifdef X11
8138                 CONF("show_graph_scale") {
8139                         show_graph_scale = string_to_bool(value);
8140                 }
8141                 CONF("show_graph_range") {
8142                         show_graph_range = string_to_bool(value);
8143                 }
8144                 CONF("border_margin") {
8145                         ERR("border_margin is deprecated, please use window.border_inner_margin instead");
8146                         if (value) {
8147                                 window.border_inner_margin = strtol(value, 0, 0);
8148                                 if (window.border_inner_margin < 0) window.border_inner_margin = 0;
8149                         } else {
8150                                 CONF_ERR;
8151                         }
8152                 }
8153                 CONF("border_inner_margin") {
8154                         if (value) {
8155                                 window.border_inner_margin = strtol(value, 0, 0);
8156                                 if (window.border_inner_margin < 0) window.border_inner_margin = 0;
8157                         } else {
8158                                 CONF_ERR;
8159                         }
8160                 }
8161                 CONF("border_outer_margin") {
8162                         if (value) {
8163                                 window.border_outer_margin = strtol(value, 0, 0);
8164                                 if (window.border_outer_margin < 0) window.border_outer_margin = 0;
8165                         } else {
8166                                 CONF_ERR;
8167                         }
8168                 }
8169                 CONF("border_width") {
8170                         if (value) {
8171                                 window.border_width = strtol(value, 0, 0);
8172                                 if (window.border_width < 0) window.border_width = 0;
8173                         } else {
8174                                 CONF_ERR;
8175                         }
8176                 }
8177 #endif /* X11 */
8178 #define TEMPLATE_CONF(n) \
8179                 CONF("template"#n) { \
8180                         if (value) { \
8181                                 free(template[n]); \
8182                                 template[n] = strdup(value); \
8183                         } else { \
8184                                 CONF_ERR; \
8185                         } \
8186                 }
8187                 TEMPLATE_CONF(0)
8188                 TEMPLATE_CONF(1)
8189                 TEMPLATE_CONF(2)
8190                 TEMPLATE_CONF(3)
8191                 TEMPLATE_CONF(4)
8192                 TEMPLATE_CONF(5)
8193                 TEMPLATE_CONF(6)
8194                 TEMPLATE_CONF(7)
8195                 TEMPLATE_CONF(8)
8196                 TEMPLATE_CONF(9)
8197                 CONF("imap") {
8198                         if (value) {
8199                                 info.mail = parse_mail_args(IMAP_TYPE, value);
8200                         } else {
8201                                 CONF_ERR;
8202                         }
8203                 }
8204                 CONF("pop3") {
8205                         if (value) {
8206                                 info.mail = parse_mail_args(POP3_TYPE, value);
8207                         } else {
8208                                 CONF_ERR;
8209                         }
8210                 }
8211                 CONF("default_bar_size") {
8212                         char err = 0;
8213                         if (value) {
8214                                 if (sscanf(value, "%d %d", &default_bar_width, &default_bar_height) != 2) {
8215                                         err = 1;
8216                                 }
8217                         } else {
8218                                 err = 1;
8219                         }
8220                         if (err) {
8221                                 CONF_ERR2("default_bar_size takes 2 integer arguments (ie. 'default_bar_size 0 6')")
8222                         }
8223                 }
8224 #ifdef X11
8225                 CONF("default_graph_size") {
8226                         char err = 0;
8227                         if (value) {
8228                                 if (sscanf(value, "%d %d", &default_graph_width, &default_graph_height) != 2) {
8229                                         err = 1;
8230                                 }
8231                         } else {
8232                                 err = 1;
8233                         }
8234                         if (err) {
8235                                 CONF_ERR2("default_graph_size takes 2 integer arguments (ie. 'default_graph_size 0 6')")
8236                         }
8237                 }
8238                 CONF("default_gauge_size") {
8239                         char err = 0;
8240                         if (value) {
8241                                 if (sscanf(value, "%d %d", &default_gauge_width, &default_gauge_height) != 2) {
8242                                         err = 1;
8243                                 }
8244                         } else {
8245                                 err = 1;
8246                         }
8247                         if (err) {
8248                                 CONF_ERR2("default_gauge_size takes 2 integer arguments (ie. 'default_gauge_size 0 6')")
8249                         }
8250                 }
8251 #endif
8252 #ifdef MPD
8253                 CONF("mpd_host") {
8254                         if (value) {
8255                                 mpd_set_host(value);
8256                         } else {
8257                                 CONF_ERR;
8258                         }
8259                 }
8260                 CONF("mpd_port") {
8261                         if (value && mpd_set_port(value)) {
8262                                 CONF_ERR;
8263                         }
8264                 }
8265                 CONF("mpd_password") {
8266                         if (value) {
8267                                 mpd_set_password(value, 0);
8268                         } else {
8269                                 CONF_ERR;
8270                         }
8271                 }
8272 #endif
8273                 CONF("music_player_interval") {
8274                         if (value) {
8275                                 info.music_player_interval = strtod(value, 0);
8276                         } else {
8277                                 CONF_ERR;
8278                         }
8279                 }
8280 #ifdef __OpenBSD__
8281                 CONF("sensor_device") {
8282                         if (value) {
8283                                 sensor_device = strtol(value, 0, 0);
8284                         } else {
8285                                 CONF_ERR;
8286                         }
8287                 }
8288 #endif
8289                 CONF("cpu_avg_samples") {
8290                         if (value) {
8291                                 cpu_avg_samples = strtol(value, 0, 0);
8292                                 if (cpu_avg_samples < 1 || cpu_avg_samples > 14) {
8293                                         CONF_ERR;
8294                                 } else {
8295                                         info.cpu_avg_samples = cpu_avg_samples;
8296                                 }
8297                         } else {
8298                                 CONF_ERR;
8299                         }
8300                 }
8301                 CONF("net_avg_samples") {
8302                         if (value) {
8303                                 net_avg_samples = strtol(value, 0, 0);
8304                                 if (net_avg_samples < 1 || net_avg_samples > 14) {
8305                                         CONF_ERR;
8306                                 } else {
8307                                         info.net_avg_samples = net_avg_samples;
8308                                 }
8309                         } else {
8310                                 CONF_ERR;
8311                         }
8312                 }
8313                 CONF("diskio_avg_samples") {
8314                         if (value) {
8315                                 diskio_avg_samples = strtol(value, 0, 0);
8316                                 if (diskio_avg_samples < 1 || diskio_avg_samples > 14) {
8317                                         CONF_ERR;
8318                                 } else {
8319                                         info.diskio_avg_samples = diskio_avg_samples;
8320                                 }
8321                         } else {
8322                                 CONF_ERR;
8323                         }
8324                 }
8325
8326 #ifdef HAVE_XDBE
8327                 CONF("double_buffer") {
8328                         use_xdbe = string_to_bool(value);
8329                 }
8330 #endif
8331 #ifdef X11
8332                 CONF("override_utf8_locale") {
8333                         utf8_mode = string_to_bool(value);
8334                 }
8335                 CONF("draw_borders") {
8336                         draw_borders = string_to_bool(value);
8337                 }
8338                 CONF("draw_graph_borders") {
8339                         draw_graph_borders = string_to_bool(value);
8340                 }
8341                 CONF("draw_shades") {
8342                         draw_shades = string_to_bool(value);
8343                 }
8344                 CONF("draw_outline") {
8345                         draw_outline = string_to_bool(value);
8346                 }
8347 #endif /* X11 */
8348                 CONF("out_to_console") {
8349                         if(string_to_bool(value))
8350                                 output_methods |= TO_STDOUT;
8351                 }
8352                 CONF("out_to_stderr") {
8353                         if(string_to_bool(value))
8354                                 output_methods |= TO_STDERR;
8355                 }
8356                 CONF("overwrite_file") {
8357                         if(overwrite_file) {
8358                                 free(overwrite_file);
8359                                 overwrite_file = 0;
8360                         }
8361                         if(overwrite_works(value)) {
8362                                 overwrite_file = strdup(value);
8363                                 output_methods |= OVERWRITE_FILE;
8364                         } else
8365                                 ERR("overwrite_file won't be able to create/overwrite '%s'", value);
8366                 }
8367                 CONF("append_file") {
8368                         if(append_file) {
8369                                 free(append_file);
8370                                 append_file = 0;
8371                         }
8372                         if(append_works(value)) {
8373                                 append_file = strdup(value);
8374                                 output_methods |= APPEND_FILE;
8375                         } else
8376                                 ERR("append_file won't be able to create/append '%s'", value);
8377                 }
8378                 CONF("use_spacer") {
8379                         if (value) {
8380                                 if (strcasecmp(value, "left") == EQUAL) {
8381                                         use_spacer = LEFT_SPACER;
8382                                 } else if (strcasecmp(value, "right") == EQUAL) {
8383                                         use_spacer = RIGHT_SPACER;
8384                                 } else if (strcasecmp(value, "none") == EQUAL) {
8385                                         use_spacer = NO_SPACER;
8386                                 } else {
8387                                         use_spacer = string_to_bool(value);
8388                                         ERR("use_spacer should have an argument of left, right, or"
8389                                                 " none.  '%s' seems to be some form of '%s', so"
8390                                                 " defaulting to %s.", value,
8391                                                 use_spacer ? "true" : "false",
8392                                                 use_spacer ? "right" : "none");
8393                                         if (use_spacer) {
8394                                                 use_spacer = RIGHT_SPACER;
8395                                         } else {
8396                                                 use_spacer = NO_SPACER;
8397                                         }
8398                                 }
8399                         } else {
8400                                 ERR("use_spacer should have an argument. Defaulting to right.");
8401                                 use_spacer = RIGHT_SPACER;
8402                         }
8403                 }
8404 #ifdef X11
8405 #ifdef XFT
8406                 CONF("use_xft") {
8407                         use_xft = string_to_bool(value);
8408                 }
8409                 CONF("font") {
8410                         if (value) {
8411                                 set_first_font(value);
8412                         }
8413                 }
8414                 CONF("xftalpha") {
8415                         if (value && font_count >= 0) {
8416                                 fonts[0].font_alpha = atof(value) * 65535.0;
8417                         }
8418                 }
8419                 CONF("xftfont") {
8420                         if (use_xft) {
8421 #else
8422                 CONF("use_xft") {
8423                         if (string_to_bool(value)) {
8424                                 ERR("Xft not enabled at compile time");
8425                         }
8426                 }
8427                 CONF("xftfont") {
8428                         /* xftfont silently ignored when no Xft */
8429                 }
8430                 CONF("xftalpha") {
8431                         /* xftalpha is silently ignored when no Xft */
8432                 }
8433                 CONF("font") {
8434 #endif
8435                         if (value) {
8436                                 set_first_font(value);
8437                         }
8438 #ifdef XFT
8439                         }
8440 #endif
8441                 }
8442                 CONF("gap_x") {
8443                         if (value) {
8444                                 gap_x = atoi(value);
8445                         } else {
8446                                 CONF_ERR;
8447                         }
8448                 }
8449                 CONF("gap_y") {
8450                         if (value) {
8451                                 gap_y = atoi(value);
8452                         } else {
8453                                 CONF_ERR;
8454                         }
8455                 }
8456 #endif /* X11 */
8457                 CONF("mail_spool") {
8458                         if (value) {
8459                                 char buffer[256];
8460
8461                                 variable_substitute(value, buffer, 256);
8462
8463                                 if (buffer[0] != '\0') {
8464                                         if (current_mail_spool) {
8465                                                 free(current_mail_spool);
8466                                         }
8467                                         current_mail_spool = strndup(buffer, text_buffer_size);
8468                                 }
8469                         } else {
8470                                 CONF_ERR;
8471                         }
8472                 }
8473 #ifdef X11
8474                 CONF("minimum_size") {
8475                         if (value) {
8476                                 if (sscanf(value, "%d %d", &minimum_width, &minimum_height)
8477                                                 != 2) {
8478                                         if (sscanf(value, "%d", &minimum_width) != 1) {
8479                                                 CONF_ERR;
8480                                         }
8481                                 }
8482                         } else {
8483                                 CONF_ERR;
8484                         }
8485                 }
8486                 CONF("maximum_width") {
8487                         if (value) {
8488                                 if (sscanf(value, "%d", &maximum_width) != 1) {
8489                                         CONF_ERR;
8490                                 }
8491                         } else {
8492                                 CONF_ERR;
8493                         }
8494                 }
8495 #endif /* X11 */
8496                 CONF("no_buffers") {
8497                         no_buffers = string_to_bool(value);
8498                 }
8499                 CONF("top_name_width") {
8500                         if (value) {
8501                                 if (sscanf(value, "%u", &top_name_width) != 1) {
8502                                         CONF_ERR;
8503                                 }
8504                         } else {
8505                                 CONF_ERR;
8506                         }
8507                         if (top_name_width >= max_user_text) {
8508                                 top_name_width = max_user_text - 1;
8509                         }
8510                 }
8511                 CONF("top_cpu_separate") {
8512                         cpu_separate = string_to_bool(value);
8513                 }
8514                 CONF("short_units") {
8515                         short_units = string_to_bool(value);
8516                 }
8517                 CONF("format_human_readable") {
8518                         format_human_readable = string_to_bool(value);
8519                 }
8520                 CONF("pad_percents") {
8521                         pad_percents = atoi(value);
8522                 }
8523 #ifdef X11
8524 #ifdef OWN_WINDOW
8525                 CONF("own_window") {
8526                         if (value) {
8527                                 own_window = string_to_bool(value);
8528                         }
8529                 }
8530                 CONF("own_window_class") {
8531                         if (value) {
8532                                 memset(window.class_name, 0, sizeof(window.class_name));
8533                                 strncpy(window.class_name, value,
8534                                                 sizeof(window.class_name) - 1);
8535                         }
8536                 }
8537                 CONF("own_window_title") {
8538                         if (value) {
8539                                 memset(window.title, 0, sizeof(window.title));
8540                                 strncpy(window.title, value, sizeof(window.title) - 1);
8541                         }
8542                 }
8543                 CONF("own_window_transparent") {
8544                         if (value) {
8545                                 set_transparent = string_to_bool(value);
8546                         }
8547                 }
8548                 CONF("own_window_hints") {
8549                         if (value) {
8550                                 char *p_hint, *p_save;
8551                                 char delim[] = ", ";
8552
8553                                 /* tokenize the value into individual hints */
8554                                 if ((p_hint = strtok_r(value, delim, &p_save)) != NULL) {
8555                                         do {
8556                                                 /* fprintf(stderr, "hint [%s] parsed\n", p_hint); */
8557                                                 if (strncmp(p_hint, "undecorate", 10) == EQUAL) {
8558                                                         SET_HINT(window.hints, HINT_UNDECORATED);
8559                                                 } else if (strncmp(p_hint, "below", 5) == EQUAL) {
8560                                                         SET_HINT(window.hints, HINT_BELOW);
8561                                                 } else if (strncmp(p_hint, "above", 5) == EQUAL) {
8562                                                         SET_HINT(window.hints, HINT_ABOVE);
8563                                                 } else if (strncmp(p_hint, "sticky", 6) == EQUAL) {
8564                                                         SET_HINT(window.hints, HINT_STICKY);
8565                                                 } else if (strncmp(p_hint, "skip_taskbar", 12) == EQUAL) {
8566                                                         SET_HINT(window.hints, HINT_SKIP_TASKBAR);
8567                                                 } else if (strncmp(p_hint, "skip_pager", 10) == EQUAL) {
8568                                                         SET_HINT(window.hints, HINT_SKIP_PAGER);
8569                                                 } else {
8570                                                         CONF_ERR;
8571                                                 }
8572
8573                                                 p_hint = strtok_r(NULL, delim, &p_save);
8574                                         } while (p_hint != NULL);
8575                                 }
8576                         } else {
8577                                 CONF_ERR;
8578                         }
8579                 }
8580                 CONF("own_window_type") {
8581                         if (value) {
8582                                 if (strncmp(value, "normal", 6) == EQUAL) {
8583                                         window.type = TYPE_NORMAL;
8584                                 } else if (strncmp(value, "desktop", 7) == EQUAL) {
8585                                         window.type = TYPE_DESKTOP;
8586                                 } else if (strncmp(value, "dock", 4) == EQUAL) {
8587                                         window.type = TYPE_DOCK;
8588                                         text_alignment = TOP_LEFT;
8589                                 } else if (strncmp(value, "panel", 5) == EQUAL) {
8590                                         window.type = TYPE_PANEL;
8591                                 } else if (strncmp(value, "override", 8) == EQUAL) {
8592                                         window.type = TYPE_OVERRIDE;
8593                                 } else {
8594                                         CONF_ERR;
8595                                 }
8596                         } else {
8597                                 CONF_ERR;
8598                         }
8599                 }
8600 #endif
8601                 CONF("stippled_borders") {
8602                         if (value) {
8603                                 stippled_borders = strtol(value, 0, 0);
8604                         } else {
8605                                 stippled_borders = 4;
8606                         }
8607                 }
8608 #ifdef IMLIB2
8609                 CONF("imlib_cache_size") {
8610                         if (value) {
8611                                 cimlib_set_cache_size(atoi(value));
8612                         }
8613                 }
8614                 CONF("imlib_cache_flush_interval") {
8615                         if (value) {
8616                                 cimlib_set_cache_flush_interval(atoi(value));
8617                         }
8618                 }
8619 #endif /* IMLIB2 */
8620 #endif /* X11 */
8621                 CONF("update_interval") {
8622                         if (value) {
8623                                 update_interval = strtod(value, 0);
8624                         } else {
8625                                 CONF_ERR;
8626                         }
8627                         if (info.music_player_interval == 0) {
8628                                 // default to update_interval
8629                                 info.music_player_interval = update_interval;
8630                         }
8631                 }
8632                 CONF("total_run_times") {
8633                         if (value) {
8634                                 total_run_times = strtod(value, 0);
8635                         } else {
8636                                 CONF_ERR;
8637                         }
8638                 }
8639                 CONF("uppercase") {
8640                         stuff_in_uppercase = string_to_bool(value);
8641                 }
8642                 CONF("max_specials") {
8643                         if (value) {
8644                                 max_specials = atoi(value);
8645                         } else {
8646                                 CONF_ERR;
8647                         }
8648                 }
8649                 CONF("max_user_text") {
8650                         if (value) {
8651                                 max_user_text = atoi(value);
8652                         } else {
8653                                 CONF_ERR;
8654                         }
8655                 }
8656                 CONF("text_buffer_size") {
8657                         if (value) {
8658                                 text_buffer_size = atoi(value);
8659                                 if (text_buffer_size < DEFAULT_TEXT_BUFFER_SIZE) {
8660                                         ERR("text_buffer_size must be >=%i bytes", DEFAULT_TEXT_BUFFER_SIZE);
8661                                         text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
8662                                 }
8663                         } else {
8664                                 CONF_ERR;
8665                         }
8666                 }
8667                 CONF("text") {
8668 #ifdef X11
8669                         if (output_methods & TO_X) {
8670                                 X11_initialisation();
8671                         }
8672 #endif
8673
8674                         if (global_text) {
8675                                 free(global_text);
8676                                 global_text = 0;
8677                         }
8678
8679                         global_text = (char *) malloc(1);
8680                         global_text[0] = '\0';
8681
8682                         while (!feof(fp)) {
8683                                 unsigned int l = strlen(global_text);
8684                                 unsigned int bl;
8685                                 char buf[CONF_BUFF_SIZE];
8686
8687                                 if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
8688                                         break;
8689                                 }
8690
8691                                 /* Remove \\-\n. */
8692                                 bl = strlen(buf);
8693                                 if (bl >= 2 && buf[bl-2] == '\\' && buf[bl-1] == '\n') {
8694                                         buf[bl-2] = '\0';
8695                                         bl -= 2;
8696                                         if (bl == 0) {
8697                                                 continue;
8698                                         }
8699                                 }
8700
8701                                 /* Check for continuation of \\-\n. */
8702                                 if (l > 0 && buf[0] == '\n' && global_text[l-1] == '\\') {
8703                                         global_text[l-1] = '\0';
8704                                         continue;
8705                                 }
8706
8707                                 global_text = (char *) realloc(global_text, l + bl + 1);
8708                                 strcat(global_text, buf);
8709
8710                                 if (strlen(global_text) > max_user_text) {
8711                                         break;
8712                                 }
8713                         }
8714                         fclose(fp);
8715                         if (strlen(global_text) < 1) {
8716                                 CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
8717                         }
8718                         global_text_lines = line + 1;
8719                         return;
8720                 }
8721 #ifdef TCP_PORT_MONITOR
8722                 CONF("max_port_monitor_connections") {
8723                         int max;
8724                         if (!value || (sscanf(value, "%d", &max) != 1)) {
8725                                 /* an error. use default, warn and continue. */
8726                                 tcp_portmon_set_max_connections(0);
8727                                 CONF_ERR;
8728                         } else if (tcp_portmon_set_max_connections(max)) {
8729                                 /* max is < 0, default has been set*/
8730                                 CONF_ERR;
8731                         }
8732                 }
8733 #endif
8734                 CONF("if_up_strictness") {
8735                         if (!value) {
8736                                 ERR("incorrect if_up_strictness value, defaulting to 'up'");
8737                                 ifup_strictness = IFUP_UP;
8738                         } else if (strcasecmp(value, "up") == EQUAL) {
8739                                 ifup_strictness = IFUP_UP;
8740                         } else if (strcasecmp(value, "link") == EQUAL) {
8741                                 ifup_strictness = IFUP_LINK;
8742                         } else if (strcasecmp(value, "address") == EQUAL) {
8743                                 ifup_strictness = IFUP_ADDR;
8744                         } else {
8745                                 ERR("incorrect if_up_strictness value, defaulting to 'up'");
8746                                 ifup_strictness = IFUP_UP;
8747                         }
8748                 }
8749
8750                 CONF("temperature_unit") {
8751                         if (!value) {
8752                                 ERR("config option 'temperature_unit' needs an argument, either 'celsius' or 'fahrenheit'");
8753                         } else if (set_temp_output_unit(value)) {
8754                                 ERR("temperature_unit: incorrect argument");
8755                         }
8756                 }
8757
8758                 CONF("alias") {
8759                         if (value) {
8760                                 size_t maxlength = strlen(value);       //+1 for terminating 0 not needed, 'cause of the space in the middle of value
8761                                 char *skey = malloc(maxlength);
8762                                 char *svalue = malloc(maxlength);
8763                                 char *oldvalue;
8764                                 if (sscanf(value, "%[0-9a-zA-Z_] %[^\n]", skey, svalue) == 2) {
8765                                         oldvalue = getenv(skey);
8766                                         if (oldvalue == NULL) {
8767                                                 setenv(skey, svalue, 0);
8768                                         }
8769                                         //PS: Don't free oldvalue, it's the real envvar, not a copy
8770                                 } else {
8771                                         CONF_ERR;
8772                                 }
8773                                 free(skey);
8774                                 free(svalue);
8775                         } else {
8776                                 CONF_ERR;
8777                         }
8778                 }
8779 #ifdef HAVE_LUA
8780                 CONF("lua_load") {
8781                         if (value) {
8782                                 char *ptr = strtok(value, " ");
8783                                 while (ptr) {
8784                                         llua_load(ptr);
8785                                         ptr = strtok(NULL, " ");
8786                                 }
8787                         } else {
8788                                 CONF_ERR;
8789                         }
8790                 }
8791 #ifdef X11
8792                 CONF("lua_draw_hook_pre") {
8793                         if (value) {
8794                                 llua_set_draw_pre_hook(value);
8795                         } else {
8796                                 CONF_ERR;
8797                         }
8798                 }
8799                 CONF("lua_draw_hook_post") {
8800                         if (value) {
8801                                 llua_set_draw_post_hook(value);
8802                         } else {
8803                                 CONF_ERR;
8804                         }
8805                 }
8806 #endif /* X11 */
8807 #endif /* HAVE_LUA */
8808
8809                 CONF("color0"){}
8810                 CONF("color1"){}
8811                 CONF("color2"){}
8812                 CONF("color3"){}
8813                 CONF("color4"){}
8814                 CONF("color5"){}
8815                 CONF("color6"){}
8816                 CONF("color7"){}
8817                 CONF("color8"){}
8818                 CONF("color9"){}
8819                 CONF("default_color"){}
8820                 CONF3("default_shade_color", "default_shadecolor"){}
8821                 CONF3("default_outline_color", "default_outlinecolor") {}
8822                 CONF("own_window_colour") {}
8823
8824                 else {
8825                         ERR("%s: %d: no such configuration: '%s'", f, line, name);
8826                 }
8827         }
8828
8829         fclose(fp);
8830
8831         if (info.music_player_interval == 0) {
8832                 // default to update_interval
8833                 info.music_player_interval = update_interval;
8834         }
8835         if (!global_text) { // didn't supply any text
8836                 CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
8837         }
8838 }
8839
8840 #ifdef X11
8841 static void load_config_file_x11(const char *f)
8842 {
8843         int line = 0;
8844         FILE *fp;
8845
8846         fp = open_config_file(f);
8847         if (!fp) {
8848                 return;
8849         }
8850         DBGP("reading contents from config file '%s'", f);
8851
8852         while (!feof(fp)) {
8853                 char buff[CONF_BUFF_SIZE], *name, *value;
8854                 int ret = do_config_step(&line, fp, buff, &name, &value);
8855                 if (ret == CONF_BREAK) {
8856                         break;
8857                 } else if (ret == CONF_CONTINUE) {
8858                         continue;
8859                 }
8860
8861                 CONF2("color0") {
8862                         X11_initialisation();
8863                         if (x_initialised == YES) {
8864                                 if (value) {
8865                                         color0 = get_x11_color(value);
8866                                 } else {
8867                                         CONF_ERR;
8868                                 }
8869                         }
8870                 }
8871                 CONF("color1") {
8872                         X11_initialisation();
8873                         if (x_initialised == YES) {
8874                                 if (value) {
8875                                         color1 = get_x11_color(value);
8876                                 } else {
8877                                         CONF_ERR;
8878                                 }
8879                         }
8880                 }
8881                 CONF("color2") {
8882                         X11_initialisation();
8883                         if (x_initialised == YES) {
8884                                 if (value) {
8885                                         color2 = get_x11_color(value);
8886                                 } else {
8887                                         CONF_ERR;
8888                                 }
8889                         }
8890                 }
8891                 CONF("color3") {
8892                         X11_initialisation();
8893                         if (x_initialised == YES) {
8894                                 if (value) {
8895                                         color3 = get_x11_color(value);
8896                                 } else {
8897                                         CONF_ERR;
8898                                 }
8899                         }
8900                 }
8901                 CONF("color4") {
8902                         X11_initialisation();
8903                         if (x_initialised == YES) {
8904                                 if (value) {
8905                                         color4 = get_x11_color(value);
8906                                 } else {
8907                                         CONF_ERR;
8908                                 }
8909                         }
8910                 }
8911                 CONF("color5") {
8912                         X11_initialisation();
8913                         if (x_initialised == YES) {
8914                                 if (value) {
8915                                         color5 = get_x11_color(value);
8916                                 } else {
8917                                         CONF_ERR;
8918                                 }
8919                         }
8920                 }
8921                 CONF("color6") {
8922                         X11_initialisation();
8923                         if (x_initialised == YES) {
8924                                 if (value) {
8925                                         color6 = get_x11_color(value);
8926                                 } else {
8927                                         CONF_ERR;
8928                                 }
8929                         }
8930                 }
8931                 CONF("color7") {
8932                         X11_initialisation();
8933                         if (x_initialised == YES) {
8934                                 if (value) {
8935                                         color7 = get_x11_color(value);
8936                                 } else {
8937                                         CONF_ERR;
8938                                 }
8939                         }
8940                 }
8941                 CONF("color8") {
8942                         X11_initialisation();
8943                         if (x_initialised == YES) {
8944                                 if (value) {
8945                                         color8 = get_x11_color(value);
8946                                 } else {
8947                                         CONF_ERR;
8948                                 }
8949                         }
8950                 }
8951                 CONF("color9") {
8952                         X11_initialisation();
8953                         if (x_initialised == YES) {
8954                                 if (value) {
8955                                         color9 = get_x11_color(value);
8956                                 } else {
8957                                         CONF_ERR;
8958                                 }
8959                         }
8960                 }
8961                 CONF("default_color") {
8962                         X11_initialisation();
8963                         if (x_initialised == YES) {
8964                                 if (value) {
8965                                         default_fg_color = get_x11_color(value);
8966                                 } else {
8967                                         CONF_ERR;
8968                                 }
8969                         }
8970                 }
8971                 CONF3("default_shade_color", "default_shadecolor") {
8972                         X11_initialisation();
8973                         if (x_initialised == YES) {
8974                                 if (value) {
8975                                         default_bg_color = get_x11_color(value);
8976                                 } else {
8977                                         CONF_ERR;
8978                                 }
8979                         }
8980                 }
8981                 CONF3("default_outline_color", "default_outlinecolor") {
8982                         X11_initialisation();
8983                         if (x_initialised == YES) {
8984                                 if (value) {
8985                                         default_out_color = get_x11_color(value);
8986                                 } else {
8987                                         CONF_ERR;
8988                                 }
8989                         }
8990                 }
8991 #ifdef OWN_WINDOW
8992                 CONF("own_window_colour") {
8993                         X11_initialisation();
8994                         if (x_initialised == YES) {
8995                                 if (value) {
8996                                         background_colour = get_x11_color(value);
8997                                 } else {
8998                                         ERR("Invalid colour for own_window_colour (try omitting the "
8999                                                 "'#' for hex colours");
9000                                 }
9001                         }
9002                 }
9003 #endif
9004                 CONF("text") {
9005                         /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
9006                         if(output_methods & TO_X) {
9007                                 X11_initialisation();
9008                         }
9009                 }
9010 #undef CONF
9011 #undef CONF2
9012 #undef CONF3
9013 #undef CONF_ERR
9014 #undef CONF_ERR2
9015 #undef CONF_BREAK
9016 #undef CONF_CONTINUE
9017 #undef CONF_BUFF_SIZE
9018         }
9019
9020         fclose(fp);
9021
9022 }
9023 #endif /* X11 */
9024
9025 #if defined(WEATHER) && defined(XOAP)
9026 /*
9027  * TODO: make the xoap keys file readable from the config file
9028  *       make the keys directly readable from the config file
9029  *       make the xoap keys file giveable as a command line option
9030  */
9031 static void load_xoap_keys(void)
9032 {
9033   FILE *fp;
9034   char *par = (char *) malloc(11 * sizeof(char));
9035   char *key = (char *) malloc(17 * sizeof(char));
9036
9037   xoap = (char *) malloc(64 * sizeof(char));
9038   to_real_path(xoap, XOAP_FILE);
9039   fp = fopen(xoap, "r");
9040   if (fp != NULL) {
9041     if( fscanf(fp, "%10s %16s", par, key) == 2 ) {
9042       strcpy(xoap, "?cc=*&link=xoap&prod=xoap&par=");
9043       strcat(xoap, par);
9044       strcat(xoap, "&key=");
9045       strcat(xoap, key);
9046       strcat(xoap, "&unit=m");
9047     } else {
9048       free(xoap);
9049       xoap = NULL;
9050     }
9051     fclose(fp);
9052   } else {
9053     free(xoap);
9054     xoap = NULL;
9055   }
9056   free(par);
9057   free(key);
9058 }
9059 #endif /* WEATHER && XOAP */
9060
9061 static void print_help(const char *prog_name) {
9062         printf("Usage: %s [OPTION]...\n"
9063                         PACKAGE_NAME" is a system monitor that renders text on desktop or to own transparent\n"
9064                         "window. Command line options will override configurations defined in config\n"
9065                         "file.\n"
9066                         "   -v, --version             version\n"
9067                         "   -q, --quiet               quiet mode\n"
9068                         "   -D, --debug               increase debugging output, ie. -DD for more debugging\n"
9069                         "   -c, --config=FILE         config file to load\n"
9070 #ifdef CONFIG_OUTPUT
9071                         "   -C, --print-config        print the builtin default config to stdout\n"
9072                         "                             e.g. 'conky -C > ~/.conkyrc' will create a new default config\n"
9073 #endif
9074                         "   -d, --daemonize           daemonize, fork to background\n"
9075                         "   -h, --help                help\n"
9076 #ifdef X11
9077                         "   -a, --alignment=ALIGNMENT text alignment on screen, {top,bottom,middle}_{left,right,middle}\n"
9078                         "   -f, --font=FONT           font to use\n"
9079                         "   -X, --display=DISPLAY     X11 display to use\n"
9080 #ifdef OWN_WINDOW
9081                         "   -o, --own-window          create own window to draw\n"
9082 #endif
9083 #ifdef HAVE_XDBE
9084                         "   -b, --double-buffer       double buffer (prevents flickering)\n"
9085 #endif
9086                         "   -w, --window-id=WIN_ID    window id to draw\n"
9087                         "   -x X                      x position\n"
9088                         "   -y Y                      y position\n"
9089 #endif /* X11 */
9090                         "   -t, --text=TEXT           text to render, remember single quotes, like -t '$uptime'\n"
9091                         "   -u, --interval=SECS       update interval\n"
9092                         "   -i COUNT                  number of times to update "PACKAGE_NAME" (and quit)\n",
9093                         prog_name
9094         );
9095 }
9096
9097 /* : means that character before that takes an argument */
9098 static const char *getopt_string = "vVqdDt:u:i:hc:"
9099 #ifdef X11
9100         "x:y:w:a:f:X:"
9101 #ifdef OWN_WINDOW
9102         "o"
9103 #endif
9104 #ifdef HAVE_XDBE
9105         "b"
9106 #endif
9107 #endif /* X11 */
9108 #ifdef CONFIG_OUTPUT
9109         "C"
9110 #endif
9111         ;
9112
9113 static const struct option longopts[] = {
9114         { "help", 0, NULL, 'h' },
9115         { "version", 0, NULL, 'V' },
9116         { "debug", 0, NULL, 'D' },
9117         { "config", 1, NULL, 'c' },
9118 #ifdef CONFIG_OUTPUT
9119         { "print-config", 0, NULL, 'C' },
9120 #endif
9121         { "daemonize", 0, NULL, 'd' },
9122 #ifdef X11
9123         { "alignment", 1, NULL, 'a' },
9124         { "font", 1, NULL, 'f' },
9125         { "display", 1, NULL, 'X' },
9126 #ifdef OWN_WINDOW
9127         { "own-window", 0, NULL, 'o' },
9128 #endif
9129 #ifdef HAVE_XDBE
9130         { "double-buffer", 0, NULL, 'b' },
9131 #endif
9132         { "window-id", 1, NULL, 'w' },
9133 #endif /* X11 */
9134         { "text", 1, NULL, 't' },
9135         { "interval", 0, NULL, 'u' },
9136         { 0, 0, 0, 0 }
9137 };
9138
9139 void initialisation(int argc, char **argv) {
9140         struct sigaction act, oact;
9141
9142         load_config_file(current_config);
9143
9144         /* init specials array */
9145         if ((specials = calloc(sizeof(struct special_t), max_specials)) == 0) {
9146                 ERR("failed to create specials array");
9147         }
9148
9149 #ifdef MAIL_FILE
9150         if (current_mail_spool == NULL) {
9151                 char buf[256];
9152
9153                 variable_substitute(MAIL_FILE, buf, 256);
9154
9155                 if (buf[0] != '\0') {
9156                         current_mail_spool = strndup(buf, text_buffer_size);
9157                 }
9158         }
9159 #endif
9160
9161         /* handle other command line arguments */
9162
9163 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) \
9164                 || defined(__NetBSD__)
9165         optind = optreset = 1;
9166 #else
9167         optind = 0;
9168 #endif
9169
9170 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
9171         if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY,
9172                         "kvm_open")) == NULL) {
9173                 CRIT_ERR(NULL, NULL, "cannot read kvm");
9174         }
9175 #endif
9176
9177         while (1) {
9178                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
9179
9180                 if (c == -1) {
9181                         break;
9182                 }
9183
9184                 switch (c) {
9185                         case 'd':
9186                                 fork_to_background = 1;
9187                                 break;
9188                         case 'D':
9189                                 global_debug_level++;
9190                                 break;
9191 #ifdef X11
9192                         case 'f':
9193                                 set_first_font(optarg);
9194                                 break;
9195                         case 'a':
9196                                 text_alignment = string_to_alignment(optarg);
9197                                 break;
9198                         case 'X':
9199                                 if (disp)
9200                                         free(disp);
9201                                 disp = strdup(optarg);
9202                                 break;
9203
9204 #ifdef OWN_WINDOW
9205                         case 'o':
9206                                 own_window = 1;
9207                                 break;
9208 #endif
9209 #ifdef HAVE_XDBE
9210                         case 'b':
9211                                 use_xdbe = 1;
9212                                 break;
9213 #endif
9214 #endif /* X11 */
9215                         case 't':
9216                                 if (global_text) {
9217                                         free(global_text);
9218                                         global_text = 0;
9219                                 }
9220                                 global_text = strndup(optarg, max_user_text);
9221                                 convert_escapes(global_text);
9222                                 break;
9223
9224                         case 'u':
9225                                 update_interval = strtod(optarg, 0);
9226                                 if (info.music_player_interval == 0) {
9227                                         // default to update_interval
9228                                         info.music_player_interval = update_interval;
9229                                 }
9230                                 break;
9231
9232                         case 'i':
9233                                 total_run_times = strtod(optarg, 0);
9234                                 break;
9235 #ifdef X11
9236                         case 'x':
9237                                 gap_x = atoi(optarg);
9238                                 break;
9239
9240                         case 'y':
9241                                 gap_y = atoi(optarg);
9242                                 break;
9243 #endif /* X11 */
9244
9245                         case '?':
9246                                 exit(EXIT_FAILURE);
9247                 }
9248         }
9249
9250 #ifdef X11
9251         /* load font */
9252         if (output_methods & TO_X) {
9253                 load_config_file_x11(current_config);
9254         }
9255 #endif /* X11 */
9256
9257         /* generate text and get initial size */
9258         extract_variable_text(global_text);
9259         if (global_text) {
9260                 free(global_text);
9261                 global_text = 0;
9262         }
9263         global_text = NULL;
9264         /* fork */
9265         if (fork_to_background) {
9266                 int pid = fork();
9267
9268                 switch (pid) {
9269                         case -1:
9270                                 ERR(PACKAGE_NAME": couldn't fork() to background: %s",
9271                                         strerror(errno));
9272                                 break;
9273
9274                         case 0:
9275                                 /* child process */
9276                                 usleep(25000);
9277                                 fprintf(stderr, "\n");
9278                                 fflush(stderr);
9279                                 break;
9280
9281                         default:
9282                                 /* parent process */
9283                                 fprintf(stderr, PACKAGE_NAME": forked to background, pid is %d\n",
9284                                         pid);
9285                                 fflush(stderr);
9286                                 exit(EXIT_SUCCESS);
9287                 }
9288         }
9289
9290         text_buffer = malloc(max_user_text);
9291         memset(text_buffer, 0, max_user_text);
9292         tmpstring1 = malloc(text_buffer_size);
9293         memset(tmpstring1, 0, text_buffer_size);
9294         tmpstring2 = malloc(text_buffer_size);
9295         memset(tmpstring2, 0, text_buffer_size);
9296
9297 #ifdef X11
9298         xargc = argc;
9299         xargv = argv;
9300         X11_create_window();
9301 #endif /* X11 */
9302
9303         /* Set signal handlers */
9304         act.sa_handler = signal_handler;
9305         sigemptyset(&act.sa_mask);
9306         act.sa_flags = 0;
9307 #ifdef SA_RESTART
9308         act.sa_flags |= SA_RESTART;
9309 #endif
9310
9311         if (            sigaction(SIGINT,  &act, &oact) < 0
9312                         ||      sigaction(SIGUSR1, &act, &oact) < 0
9313                         ||      sigaction(SIGHUP,  &act, &oact) < 0
9314                         ||      sigaction(SIGTERM, &act, &oact) < 0) {
9315                 ERR("error setting signal handler: %s", strerror(errno));
9316         }
9317
9318 }
9319
9320 int main(int argc, char **argv)
9321 {
9322 #ifdef X11
9323         char *s, *temp;
9324         unsigned int x;
9325 #endif
9326
9327         argc_copy = argc;
9328         argv_copy = argv;
9329         g_signal_pending = 0;
9330         max_user_text = MAX_USER_TEXT_DEFAULT;
9331         current_config = 0;
9332         memset(&info, 0, sizeof(info));
9333         memset(template, 0, sizeof(template));
9334         clear_net_stats();
9335
9336 #ifdef TCP_PORT_MONITOR
9337         /* set default connection limit */
9338         tcp_portmon_set_max_connections(0);
9339 #endif
9340
9341         /* handle command line parameters that don't change configs */
9342 #ifdef X11
9343         if (((s = getenv("LC_ALL")) && *s) || ((s = getenv("LC_CTYPE")) && *s)
9344                         || ((s = getenv("LANG")) && *s)) {
9345                 temp = (char *) malloc((strlen(s) + 1) * sizeof(char));
9346                 if (temp == NULL) {
9347                         ERR("malloc failed");
9348                 }
9349                 for (x = 0; x < strlen(s); x++) {
9350                         temp[x] = tolower(s[x]);
9351                 }
9352                 temp[x] = 0;
9353                 if (strstr(temp, "utf-8") || strstr(temp, "utf8")) {
9354                         utf8_mode = 1;
9355                 }
9356
9357                 free(temp);
9358         }
9359         if (!setlocale(LC_CTYPE, "")) {
9360                 ERR("Can't set the specified locale!\nCheck LANG, LC_CTYPE, LC_ALL.");
9361         }
9362 #endif /* X11 */
9363         while (1) {
9364                 int c = getopt_long(argc, argv, getopt_string, longopts, NULL);
9365
9366                 if (c == -1) {
9367                         break;
9368                 }
9369
9370                 switch (c) {
9371                         case 'v':
9372                         case 'V':
9373                                 print_version();
9374                         case 'c':
9375                                 if (current_config) {
9376                                         free(current_config);
9377                                 }
9378                                 current_config = strndup(optarg, max_user_text);
9379                                 break;
9380                         case 'q':
9381                                 freopen("/dev/null", "w", stderr);
9382                                 break;
9383                         case 'h':
9384                                 print_help(argv[0]);
9385                                 return 0;
9386 #ifdef CONFIG_OUTPUT
9387                         case 'C':
9388                                 print_defconfig();
9389                                 return 0;
9390 #endif
9391 #ifdef X11
9392                         case 'w':
9393                                 window.window = strtol(optarg, 0, 0);
9394                                 break;
9395 #endif /* X11 */
9396
9397                         case '?':
9398                                 exit(EXIT_FAILURE);
9399                 }
9400         }
9401
9402         /* check if specified config file is valid */
9403         if (current_config) {
9404                 struct stat sb;
9405                 if (stat(current_config, &sb) ||
9406                                 (!S_ISREG(sb.st_mode) && !S_ISLNK(sb.st_mode))) {
9407                         ERR("invalid configuration file '%s'\n", current_config);
9408                         free(current_config);
9409                         current_config = 0;
9410                 }
9411         }
9412
9413         /* load current_config, CONFIG_FILE or SYSTEM_CONFIG_FILE */
9414
9415         if (!current_config) {
9416                 /* load default config file */
9417                 char buf[DEFAULT_TEXT_BUFFER_SIZE];
9418                 FILE *fp;
9419
9420                 /* Try to use personal config file first */
9421                 to_real_path(buf, CONFIG_FILE);
9422                 if (buf[0] && (fp = fopen(buf, "r"))) {
9423                         current_config = strndup(buf, max_user_text);
9424                         fclose(fp);
9425                 }
9426
9427                 /* Try to use system config file if personal config not readable */
9428                 if (!current_config && (fp = fopen(SYSTEM_CONFIG_FILE, "r"))) {
9429                         current_config = strndup(SYSTEM_CONFIG_FILE, max_user_text);
9430                         fclose(fp);
9431                 }
9432
9433                 /* No readable config found */
9434                 if (!current_config) {
9435 #ifdef CONFIG_OUTPUT
9436                         current_config = strdup("==builtin==");
9437                         ERR("no readable personal or system-wide config file found,"
9438                                         " using builtin default");
9439 #else
9440                         CRIT_ERR(NULL, NULL, "no readable personal or system-wide config file found");
9441 #endif /* ! CONF_OUTPUT */
9442                 }
9443         }
9444
9445 #if defined(WEATHER) && defined(XOAP)
9446         /* Load xoap keys, if existing */
9447         load_xoap_keys();
9448 #endif /* WEATHER && XOAP */
9449
9450 #ifdef HAVE_SYS_INOTIFY_H
9451         inotify_fd = inotify_init();
9452 #endif /* HAVE_SYS_INOTIFY_H */
9453
9454         initialisation(argc, argv);
9455
9456         main_loop();
9457
9458 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
9459         kvm_close(kd);
9460 #endif
9461
9462         return 0;
9463 }
9464
9465 static void signal_handler(int sig)
9466 {
9467         /* signal handler is light as a feather, as it should be.
9468          * we will poll g_signal_pending with each loop of conky
9469          * and do any signal processing there, NOT here. */
9470         g_signal_pending = sig;
9471 }
9472