update machinery: clean up
[monky] / src / core.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  * vim: ts=4 sw=4 noet ai cindent syntax=c
29  *
30  */
31
32 /* local headers */
33 #include "core.h"
34 #include "text_object.h"
35 #include "algebra.h"
36 #include "build.h"
37 #include "colours.h"
38 #include "diskio.h"
39 #ifdef X11
40 #include "fonts.h"
41 #endif
42 #include "fs.h"
43 #include "logging.h"
44 #include "mixer.h"
45 #include "mail.h"
46 #include "mboxscan.h"
47 #include "specials.h"
48 #include "temphelper.h"
49 #include "template.h"
50 #include "tailhead.h"
51 #include "top.h"
52
53 /* check for OS and include appropriate headers */
54 #if defined(__linux__)
55 #include "linux.h"
56 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
57 #include "freebsd.h"
58 #elif defined(__OpenBSD__)
59 #include "openbsd.h"
60 #endif
61
62 /* OS specific prototypes to be implemented by linux.c & Co. */
63 void update_entropy(void);
64
65 #include <string.h>
66 #include <ctype.h>
67
68 #ifdef HAVE_ICONV
69 #include <iconv.h>
70
71 #ifdef NCURSES
72 #include <ncurses.h>
73 #endif
74
75 #define ICONV_CODEPAGE_LENGTH 20
76
77 int register_iconv(iconv_t *new_iconv);
78
79 long iconv_selected;
80 long iconv_count = 0;
81 char iconv_converting;
82 static iconv_t **iconv_cd = 0;
83
84 char is_iconv_converting(void)
85 {
86         return iconv_converting;
87 }
88
89 void set_iconv_converting(char i)
90 {
91         iconv_converting = i;
92 }
93
94 long get_iconv_selected(void)
95 {
96         return iconv_selected;
97 }
98
99 void set_iconv_selected(long i)
100 {
101         iconv_selected = i;
102 }
103
104 int register_iconv(iconv_t *new_iconv)
105 {
106         iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1));
107         if (!iconv_cd) {
108                 CRIT_ERR(NULL, NULL, "Out of memory");
109         }
110         iconv_cd[iconv_count] = malloc(sizeof(iconv_t));
111         if (!iconv_cd[iconv_count]) {
112                 CRIT_ERR(NULL, NULL, "Out of memory");
113         }
114         memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t));
115         iconv_count++;
116         return iconv_count;
117 }
118
119 void free_iconv(void)
120 {
121         if (iconv_cd) {
122                 long i;
123
124                 for (i = 0; i < iconv_count; i++) {
125                         if (iconv_cd[i]) {
126                                 iconv_close(*iconv_cd[i]);
127                                 free(iconv_cd[i]);
128                         }
129                 }
130                 free(iconv_cd);
131         }
132         iconv_cd = 0;
133 }
134
135 void iconv_convert(size_t a, char *buff_in, char *p, size_t p_max_size)
136 {
137         if (a > 0 && is_iconv_converting() && get_iconv_selected() > 0
138                         && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) {
139                 int bytes;
140                 size_t dummy1, dummy2;
141 #ifdef __FreeBSD__
142                 const char *ptr = buff_in;
143 #else
144                 char *ptr = buff_in;
145 #endif
146                 char *outptr = p;
147
148                 dummy1 = dummy2 = a;
149
150                 strncpy(buff_in, p, p_max_size);
151
152                 iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL);
153                 while (dummy1 > 0) {
154                         bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1,
155                                         &outptr, &dummy2);
156                         if (bytes == -1) {
157                                 NORM_ERR("Iconv codeset conversion failed");
158                                 break;
159                         }
160                 }
161
162                 /* It is nessecary when we are converting from multibyte to
163                  * singlebyte codepage */
164                 a = outptr - p;
165         }
166 }
167 #endif /* HAVE_ICONV */
168
169 /* strip a leading /dev/ if any, following symlinks first
170  *
171  * BEWARE: this function returns a pointer to static content
172  *         which gets overwritten in consecutive calls. I.e.:
173  *         this function is NOT reentrant.
174  */
175 static const char *dev_name(const char *path)
176 {
177         static char buf[255];   /* should be enough for pathnames */
178         ssize_t buflen;
179
180         if (!path)
181                 return NULL;
182
183 #define DEV_NAME(x) \
184   x != NULL && strlen(x) > 5 && strncmp(x, "/dev/", 5) == 0 ? x + 5 : x
185         if ((buflen = readlink(path, buf, 254)) == -1)
186                 return DEV_NAME(path);
187         buf[buflen] = '\0';
188         return DEV_NAME(buf);
189 #undef DEV_NAME
190 }
191
192 static struct text_object *new_text_object_internal(void)
193 {
194         struct text_object *obj = malloc(sizeof(struct text_object));
195         memset(obj, 0, sizeof(struct text_object));
196         return obj;
197 }
198
199 static struct text_object *create_plain_text(const char *s)
200 {
201         struct text_object *obj;
202
203         if (s == NULL || *s == '\0') {
204                 return NULL;
205         }
206
207         obj = new_text_object_internal();
208
209         obj->type = OBJ_text;
210         obj->data.s = strndup(s, text_buffer_size);
211         return obj;
212 }
213
214 /* construct_text_object() creates a new text_object */
215 struct text_object *construct_text_object(const char *s, const char *arg, long
216                 line, void **ifblock_opaque, void *free_at_crash)
217 {
218         // struct text_object *obj = new_text_object();
219         struct text_object *obj = new_text_object_internal();
220
221         obj->line = line;
222
223 #define CALLBACK(x) (-(long)x)
224
225 #define OBJ(a, n) if (strcmp(s, #a) == 0) { \
226         obj->type = OBJ_##a; \
227         if (n > 0) { need_mask |= (1ULL << n); } \
228         else if (n < 0) { add_update_callback((void (*)(void))CALLBACK(n)); } {
229 #define OBJ_IF(a, n) if (strcmp(s, #a) == 0) { \
230         obj->type = OBJ_##a; obj_be_ifblock_if(ifblock_opaque, obj); \
231         if (n > 0) { need_mask |= (1ULL << n); } \
232         else if (n < 0) { add_update_callback((void (*)(void))CALLBACK(n)); } {
233 #define END } } else
234
235 #define SIZE_DEFAULTS(arg) { \
236         obj->a = default_##arg##_width; \
237         obj->b = default_##arg##_height; \
238 }
239
240 #ifdef X11
241         if (s[0] == '#') {
242                 obj->type = OBJ_color;
243                 obj->data.l = get_x11_color(s);
244         } else
245 #endif /* X11 */
246 #ifdef __OpenBSD__
247         OBJ(freq, 0)
248 #else
249         OBJ(acpitemp, 0)
250                 obj->data.i = open_acpi_temperature(arg);
251         END OBJ(acpiacadapter, 0)
252         END OBJ(freq, 0)
253 #endif /* !__OpenBSD__ */
254                 get_cpu_count();
255                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
256                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
257                         obj->data.cpu_index = 1;
258                         /* NORM_ERR("freq: Invalid CPU number or you don't have that many CPUs! "
259                                 "Displaying the clock for CPU 1."); */
260                 } else {
261                         obj->data.cpu_index = atoi(&arg[0]);
262                 }
263                 obj->a = 1;
264         END OBJ(freq_g, 0)
265                 get_cpu_count();
266                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
267                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
268                         obj->data.cpu_index = 1;
269                         /* NORM_ERR("freq_g: Invalid CPU number or you don't have that many "
270                                 "CPUs! Displaying the clock for CPU 1."); */
271                 } else {
272                         obj->data.cpu_index = atoi(&arg[0]);
273                 }
274                 obj->a = 1;
275         END OBJ(read_tcp, 0)
276                 if (arg) {
277                         obj->data.read_tcp.host = malloc(text_buffer_size);
278                         sscanf(arg, "%s", obj->data.read_tcp.host);
279                         sscanf(arg+strlen(obj->data.read_tcp.host), "%u", &(obj->data.read_tcp.port));
280                         if(obj->data.read_tcp.port == 0) {
281                                 obj->data.read_tcp.port = atoi(obj->data.read_tcp.host);
282                                 strcpy(obj->data.read_tcp.host,"localhost");
283                         }
284                         obj->data.read_tcp.port = htons(obj->data.read_tcp.port);
285                         if(obj->data.read_tcp.port < 1 || obj->data.read_tcp.port > 65535) {
286                                 CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
287                         }
288                 }else{
289                         CRIT_ERR(obj, free_at_crash, "read_tcp: Needs \"(host) port\" as argument(s)");
290                 }
291 #if defined(__linux__)
292         END OBJ(voltage_mv, 0)
293                 get_cpu_count();
294                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
295                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
296                         obj->data.cpu_index = 1;
297                         /* NORM_ERR("voltage_mv: Invalid CPU number or you don't have that many "
298                                 "CPUs! Displaying voltage for CPU 1."); */
299                 } else {
300                         obj->data.cpu_index = atoi(&arg[0]);
301                 }
302                 obj->a = 1;
303         END OBJ(voltage_v, 0)
304                 get_cpu_count();
305                 if (!arg || !isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) == 0
306                                 || (unsigned int) atoi(&arg[0]) > info.cpu_count) {
307                         obj->data.cpu_index = 1;
308                         /* NORM_ERR("voltage_v: Invalid CPU number or you don't have that many "
309                                 "CPUs! Displaying voltage for CPU 1."); */
310                 } else {
311                         obj->data.cpu_index = atoi(&arg[0]);
312                 }
313                 obj->a = 1;
314
315 #ifdef HAVE_IWLIB
316         END OBJ(wireless_essid, CALLBACK(&update_net_stats))
317                 if (arg) {
318                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
319                 } else {
320                         // default to DEFAULTNETDEV
321                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
322                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
323                         free(buf);
324                 }
325         END OBJ(wireless_mode, CALLBACK(&update_net_stats))
326                 if (arg) {
327                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
328                 } else {
329                         // default to DEFAULTNETDEV
330                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
331                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
332                         free(buf);
333                 }
334         END OBJ(wireless_bitrate, CALLBACK(&update_net_stats))
335                 if (arg) {
336                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
337                 } else {
338                         // default to DEFAULTNETDEV
339                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
340                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
341                         free(buf);
342                 }
343         END OBJ(wireless_ap, CALLBACK(&update_net_stats))
344                 if (arg) {
345                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
346                 } else {
347                         // default to DEFAULTNETDEV
348                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
349                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
350                         free(buf);
351                 }
352         END OBJ(wireless_link_qual, CALLBACK(&update_net_stats))
353                 if (arg) {
354                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
355                 } else {
356                         // default to DEFAULTNETDEV
357                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
358                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
359                         free(buf);
360                 }
361         END OBJ(wireless_link_qual_max, CALLBACK(&update_net_stats))
362                 if (arg) {
363                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
364                 } else {
365                         // default to DEFAULTNETDEV
366                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
367                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
368                         free(buf);
369                 }
370         END OBJ(wireless_link_qual_perc, CALLBACK(&update_net_stats))
371                 if (arg) {
372                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
373                 } else {
374                         // default to DEFAULTNETDEV
375                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
376                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
377                         free(buf);
378                 }
379         END OBJ(wireless_link_bar, CALLBACK(&update_net_stats))
380                 SIZE_DEFAULTS(bar);
381                 if (arg) {
382                         arg = scan_bar(arg, &obj->a, &obj->b);
383                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
384                 } else {
385                         // default to DEFAULTNETDEV
386                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
387                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
388                         free(buf);
389                 }
390 #endif /* HAVE_IWLIB */
391
392 #endif /* __linux__ */
393
394 #ifndef __OpenBSD__
395         END OBJ(acpifan, 0)
396         END OBJ(battery, 0)
397                 char bat[64];
398
399                 if (arg) {
400                         sscanf(arg, "%63s", bat);
401                 } else {
402                         strcpy(bat, "BAT0");
403                 }
404                 obj->data.s = strndup(bat, text_buffer_size);
405         END OBJ(battery_short, 0)
406                 char bat[64];
407
408                 if (arg) {
409                         sscanf(arg, "%63s", bat);
410                 } else {
411                         strcpy(bat, "BAT0");
412                 }
413                 obj->data.s = strndup(bat, text_buffer_size);
414         END OBJ(battery_time, 0)
415                 char bat[64];
416
417                 if (arg) {
418                         sscanf(arg, "%63s", bat);
419                 } else {
420                         strcpy(bat, "BAT0");
421                 }
422                 obj->data.s = strndup(bat, text_buffer_size);
423         END OBJ(battery_percent, 0)
424                 char bat[64];
425
426                 if (arg) {
427                         sscanf(arg, "%63s", bat);
428                 } else {
429                         strcpy(bat, "BAT0");
430                 }
431                 obj->data.s = strndup(bat, text_buffer_size);
432         END OBJ(battery_bar, 0)
433                 char bat[64];
434                 SIZE_DEFAULTS(bar);
435                 obj->b = 6;
436                 if (arg) {
437                         arg = scan_bar(arg, &obj->a, &obj->b);
438                         sscanf(arg, "%63s", bat);
439                 } else {
440                         strcpy(bat, "BAT0");
441                 }
442                 obj->data.s = strndup(bat, text_buffer_size);
443 #endif /* !__OpenBSD__ */
444
445 #if defined(__linux__)
446         END OBJ(disk_protect, 0)
447                 if (arg)
448                         obj->data.s = strndup(dev_name(arg), text_buffer_size);
449                 else
450                         CRIT_ERR(obj, free_at_crash, "disk_protect needs an argument");
451         END OBJ(i8k_version, CALLBACK(&update_i8k))
452         END OBJ(i8k_bios, CALLBACK(&update_i8k))
453         END OBJ(i8k_serial, CALLBACK(&update_i8k))
454         END OBJ(i8k_cpu_temp, CALLBACK(&update_i8k))
455         END OBJ(i8k_left_fan_status, CALLBACK(&update_i8k))
456         END OBJ(i8k_right_fan_status, CALLBACK(&update_i8k))
457         END OBJ(i8k_left_fan_rpm, CALLBACK(&update_i8k))
458         END OBJ(i8k_right_fan_rpm, CALLBACK(&update_i8k))
459         END OBJ(i8k_ac_status, CALLBACK(&update_i8k))
460         END OBJ(i8k_buttons_status, CALLBACK(&update_i8k))
461 #if defined(IBM)
462         END OBJ(ibm_fan, 0)
463         END OBJ(ibm_temps, 0)
464                 if (!arg) {
465                         CRIT_ERR(obj, free_at_crash, "ibm_temps: needs an argument");
466                 }
467                 if (!isdigit(arg[0]) || strlen(arg) >= 2 || atoi(&arg[0]) >= 8) {
468                         obj->data.sensor = 0;
469                         NORM_ERR("Invalid temperature sensor! Sensor number must be 0 to 7. "
470                                 "Using 0 (CPU temp sensor).");
471                 }
472                 obj->data.sensor = atoi(&arg[0]);
473         END OBJ(ibm_volume, 0)
474         END OBJ(ibm_brightness, 0)
475 #endif
476         /* information from sony_laptop kernel module
477          * /sys/devices/platform/sony-laptop */
478         END OBJ(sony_fanspeed, 0)
479         END OBJ_IF(if_gw, CALLBACK(&update_gateway_info))
480         END OBJ(ioscheduler, 0)
481                 if (!arg) {
482                         CRIT_ERR(obj, free_at_crash, "get_ioscheduler needs an argument (e.g. hda)");
483                         obj->data.s = 0;
484                 } else
485                         obj->data.s = strndup(dev_name(arg), text_buffer_size);
486         END OBJ(laptop_mode, 0)
487         END OBJ(pb_battery, 0)
488                 if (arg && strcmp(arg, "status") == EQUAL) {
489                         obj->data.i = PB_BATT_STATUS;
490                 } else if (arg && strcmp(arg, "percent") == EQUAL) {
491                         obj->data.i = PB_BATT_PERCENT;
492                 } else if (arg && strcmp(arg, "time") == EQUAL) {
493                         obj->data.i = PB_BATT_TIME;
494                 } else {
495                         NORM_ERR("pb_battery: needs one argument: status, percent or time");
496                         free(obj);
497                         return NULL;
498                 }
499
500 #endif /* __linux__ */
501 #if (defined(__FreeBSD__) || defined(__linux__))
502         END OBJ_IF(if_up, 0)
503                 if (!arg) {
504                         NORM_ERR("if_up needs an argument");
505                         obj->data.ifblock.s = 0;
506                 } else {
507                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
508                 }
509 #endif
510 #if defined(__OpenBSD__)
511         END OBJ(obsd_sensors_temp, 0)
512                 if (!arg) {
513                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_temp: needs an argument");
514                 }
515                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
516                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
517                         obj->data.sensor = 0;
518                         NORM_ERR("Invalid temperature sensor number!");
519                 }
520                 obj->data.sensor = atoi(&arg[0]);
521         END OBJ(obsd_sensors_fan, 0)
522                 if (!arg) {
523                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_fan: needs 2 arguments (device and sensor "
524                                 "number)");
525                 }
526                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
527                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
528                         obj->data.sensor = 0;
529                         NORM_ERR("Invalid fan sensor number!");
530                 }
531                 obj->data.sensor = atoi(&arg[0]);
532         END OBJ(obsd_sensors_volt, 0)
533                 if (!arg) {
534                         CRIT_ERR(obj, free_at_crash, "obsd_sensors_volt: needs 2 arguments (device and sensor "
535                                 "number)");
536                 }
537                 if (!isdigit(arg[0]) || atoi(&arg[0]) < 0
538                                 || atoi(&arg[0]) > OBSD_MAX_SENSORS - 1) {
539                         obj->data.sensor = 0;
540                         NORM_ERR("Invalid voltage sensor number!");
541                 }
542                 obj->data.sensor = atoi(&arg[0]);
543         END OBJ(obsd_vendor, 0)
544         END OBJ(obsd_product, 0)
545 #endif /* __OpenBSD__ */
546         END OBJ(buffers, CALLBACK(&update_meminfo))
547         END OBJ(cached, CALLBACK(&update_meminfo))
548 #define SCAN_CPU(__arg, __var) { \
549         int __offset = 0; \
550         if (__arg && sscanf(__arg, " cpu%u %n", &__var, &__offset) > 0) \
551                 __arg += __offset; \
552         else \
553                 __var = 0; \
554 }
555         END OBJ(cpu, CALLBACK(&update_cpu_usage))
556                 SCAN_CPU(arg, obj->data.cpu_index);
557                 DBGP2("Adding $cpu for CPU %d", obj->data.cpu_index);
558 #ifdef X11
559         END OBJ(cpugauge, CALLBACK(&update_cpu_usage))
560                 SIZE_DEFAULTS(gauge);
561                 SCAN_CPU(arg, obj->data.cpu_index);
562                 scan_gauge(arg, &obj->a, &obj->b);
563                 DBGP2("Adding $cpugauge for CPU %d", obj->data.cpu_index);
564 #endif /* X11 */
565         END OBJ(cpubar, CALLBACK(&update_cpu_usage))
566                 SIZE_DEFAULTS(bar);
567                 SCAN_CPU(arg, obj->data.cpu_index);
568                 scan_bar(arg, &obj->a, &obj->b);
569                 DBGP2("Adding $cpubar for CPU %d", obj->data.cpu_index);
570 #ifdef X11
571         END OBJ(cpugraph, CALLBACK(&update_cpu_usage))
572                 char *buf = 0;
573                 SIZE_DEFAULTS(graph);
574                 SCAN_CPU(arg, obj->data.cpu_index);
575                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
576                         &obj->e, &obj->char_a, &obj->char_b);
577                 DBGP2("Adding $cpugraph for CPU %d", obj->data.cpu_index);
578                 if (buf) free(buf);
579         END OBJ(loadgraph, CALLBACK(&update_load_average))
580                 char *buf = 0;
581                 SIZE_DEFAULTS(graph);
582                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
583                                 &obj->e, &obj->char_a, &obj->char_b);
584                 if (buf) {
585                         int a = 1, r = 3;
586                         if (arg) {
587                                 r = sscanf(arg, "%d", &a);
588                         }
589                         obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
590                         free(buf);
591                 }
592 #endif /* X11 */
593         END OBJ(diskio, CALLBACK(&update_diskio))
594                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
595         END OBJ(diskio_read, CALLBACK(&update_diskio))
596                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
597         END OBJ(diskio_write, CALLBACK(&update_diskio))
598                 obj->data.diskio = prepare_diskio_stat(dev_name(arg));
599 #ifdef X11
600         END OBJ(diskiograph, CALLBACK(&update_diskio))
601                 char *buf = 0;
602                 SIZE_DEFAULTS(graph);
603                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
604                                 &obj->e, &obj->char_a, &obj->char_b);
605
606                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
607                 if (buf) free(buf);
608         END OBJ(diskiograph_read, CALLBACK(&update_diskio))
609                 char *buf = 0;
610                 SIZE_DEFAULTS(graph);
611                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
612                                 &obj->e, &obj->char_a, &obj->char_b);
613
614                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
615                 if (buf) free(buf);
616         END OBJ(diskiograph_write, CALLBACK(&update_diskio))
617                 char *buf = 0;
618                 SIZE_DEFAULTS(graph);
619                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
620                                 &obj->e, &obj->char_a, &obj->char_b);
621
622                 obj->data.diskio = prepare_diskio_stat(dev_name(buf));
623                 if (buf) free(buf);
624 #endif /* X11 */
625         END OBJ(color, 0)
626 #ifdef X11
627                 if (output_methods & TO_X) {
628                         obj->data.l = arg ? get_x11_color(arg) : default_fg_color;
629                         set_current_text_color(obj->data.l);
630                 }
631 #endif /* X11 */
632 #ifdef NCURSES
633                 if (output_methods & TO_NCURSES) {
634                         obj->data.l = COLOR_WHITE;
635                         if(arg) {
636                                 if(strcasecmp(arg, "red") == 0) {
637                                         obj->data.l = COLOR_RED;
638                                 }else if(strcasecmp(arg, "green") == 0) {
639                                         obj->data.l = COLOR_GREEN;
640                                 }else if(strcasecmp(arg, "yellow") == 0) {
641                                         obj->data.l = COLOR_YELLOW;
642                                 }else if(strcasecmp(arg, "blue") == 0) {
643                                         obj->data.l = COLOR_BLUE;
644                                 }else if(strcasecmp(arg, "magenta") == 0) {
645                                         obj->data.l = COLOR_MAGENTA;
646                                 }else if(strcasecmp(arg, "cyan") == 0) {
647                                         obj->data.l = COLOR_CYAN;
648                                 }else if(strcasecmp(arg, "black") == 0) {
649                                         obj->data.l = COLOR_BLACK;
650                                 }
651                         }
652                         set_current_text_color(obj->data.l);
653                         init_pair(obj->data.l, obj->data.l, COLOR_BLACK);
654                 }
655 #endif /* NCURSES */
656         END OBJ(color0, 0)
657                 obj->data.l = color0;
658                 set_current_text_color(obj->data.l);
659         END OBJ(color1, 0)
660                 obj->data.l = color1;
661                 set_current_text_color(obj->data.l);
662         END OBJ(color2, 0)
663                 obj->data.l = color2;
664                 set_current_text_color(obj->data.l);
665         END OBJ(color3, 0)
666                 obj->data.l = color3;
667                 set_current_text_color(obj->data.l);
668         END OBJ(color4, 0)
669                 obj->data.l = color4;
670                 set_current_text_color(obj->data.l);
671         END OBJ(color5, 0)
672                 obj->data.l = color5;
673                 set_current_text_color(obj->data.l);
674         END OBJ(color6, 0)
675                 obj->data.l = color6;
676                 set_current_text_color(obj->data.l);
677         END OBJ(color7, 0)
678                 obj->data.l = color7;
679                 set_current_text_color(obj->data.l);
680         END OBJ(color8, 0)
681                 obj->data.l = color8;
682                 set_current_text_color(obj->data.l);
683         END OBJ(color9, 0)
684                 obj->data.l = color9;
685                 set_current_text_color(obj->data.l);
686 #ifdef X11
687         END OBJ(font, 0)
688                 obj->data.s = scan_font(arg);
689 #endif /* X11 */
690         END OBJ(conky_version, 0)
691         END OBJ(conky_build_date, 0)
692         END OBJ(conky_build_arch, 0)
693         END OBJ(downspeed, CALLBACK(&update_net_stats))
694                 if (arg) {
695                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
696                 } else {
697                         // default to DEFAULTNETDEV
698                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
699                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
700                         free(buf);
701                 }
702         END OBJ(downspeedf, CALLBACK(&update_net_stats))
703                 if (arg) {
704                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
705                 } else {
706                         // default to DEFAULTNETDEV
707                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
708                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
709                         free(buf);
710                 }
711 #ifdef X11
712         END OBJ(downspeedgraph, CALLBACK(&update_net_stats))
713                 char *buf = 0;
714                 SIZE_DEFAULTS(graph);
715                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
716                                 &obj->e, &obj->char_a, &obj->char_b);
717
718                 // default to DEFAULTNETDEV
719                 buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
720                 obj->data.net = get_net_stat(buf, obj, free_at_crash);
721                 free(buf);
722 #endif /* X11 */
723         END OBJ(else, 0)
724                 obj_be_ifblock_else(ifblock_opaque, obj);
725         END OBJ(endif, 0)
726                 obj_be_ifblock_endif(ifblock_opaque, obj);
727         END OBJ(eval, 0)
728                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
729         END OBJ(image, 0)
730                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
731         END OBJ(exec, 0)
732                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
733         END OBJ(execp, 0)
734                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
735         END OBJ(execbar, 0)
736                 SIZE_DEFAULTS(bar);
737                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
738 #ifdef X11
739         END OBJ(execgauge, 0)
740                 SIZE_DEFAULTS(gauge);
741                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
742         END OBJ(execgraph, 0)
743                 SIZE_DEFAULTS(graph);
744                 obj->data.s = strndup(arg ? arg : "", text_buffer_size);
745 #endif /* X11 */
746         END OBJ(execibar, 0)
747                 int n;
748                 SIZE_DEFAULTS(bar);
749
750                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
751                         char buf[256];
752
753                         NORM_ERR("${execibar <interval> command}");
754                         obj->type = OBJ_text;
755                         snprintf(buf, 256, "${%s}", s);
756                         obj->data.s = strndup(buf, text_buffer_size);
757                 } else {
758                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
759                 }
760 #ifdef X11
761         END OBJ(execigraph, 0)
762                 int n;
763                 SIZE_DEFAULTS(graph);
764
765                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
766                         char buf[256];
767
768                         NORM_ERR("${execigraph <interval> command}");
769                         obj->type = OBJ_text;
770                         snprintf(buf, 256, "${%s}", s);
771                         obj->data.s = strndup(buf, text_buffer_size);
772                 } else {
773                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
774                 }
775         END OBJ(execigauge, 0)
776                 int n;
777                 SIZE_DEFAULTS(gauge);
778
779                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
780                         char buf[256];
781
782                         NORM_ERR("${execigauge <interval> command}");
783                         obj->type = OBJ_text;
784                         snprintf(buf, 256, "${%s}", s);
785                         obj->data.s = strndup(buf, text_buffer_size);
786                 } else {
787                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
788                 }
789 #endif /* X11 */
790         END OBJ(execi, 0)
791                 int n;
792
793                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
794                         char buf[256];
795
796                         NORM_ERR("${execi <interval> command}");
797                         obj->type = OBJ_text;
798                         snprintf(buf, 256, "${%s}", s);
799                         obj->data.s = strndup(buf, text_buffer_size);
800                 } else {
801                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
802                         obj->data.execi.buffer = malloc(text_buffer_size);
803                 }
804         END OBJ(execpi, 0)
805                 int n;
806
807                 if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) {
808                         char buf[256];
809
810                         NORM_ERR("${execi <interval> command}");
811                         obj->type = OBJ_text;
812                         snprintf(buf, 256, "${%s}", s);
813                         obj->data.s = strndup(buf, text_buffer_size);
814                 } else {
815                         obj->data.execi.cmd = strndup(arg + n, text_buffer_size);
816                         obj->data.execi.buffer = malloc(text_buffer_size);
817                 }
818         END OBJ(texeci, 0)
819                         int n;
820
821                         if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) {
822                                 char buf[256];
823
824                                 NORM_ERR("${texeci <interval> command}");
825                                 obj->type = OBJ_text;
826                                 snprintf(buf, 256, "${%s}", s);
827                                 obj->data.s = strndup(buf, text_buffer_size);
828                         } else {
829                                 obj->data.texeci.cmd = strndup(arg + n, text_buffer_size);
830                                 obj->data.texeci.buffer = malloc(text_buffer_size);
831                         }
832                         obj->data.texeci.p_timed_thread = NULL;
833         END OBJ(pre_exec, 0)
834                 obj->type = OBJ_text;
835                 if (arg) {
836                         char buf[2048];
837
838                         do_read_exec(arg, buf, sizeof(buf));
839                         obj->data.s = strndup(buf, text_buffer_size);
840                 } else {
841                         obj->data.s = strndup("", text_buffer_size);
842                 }
843         END OBJ(fs_bar, CALLBACK(&update_fs_stats))
844                 SIZE_DEFAULTS(bar);
845                 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
846                 if (arg) {
847                         while (isspace(*arg)) {
848                                 arg++;
849                         }
850                         if (*arg == '\0') {
851                                 arg = "/";
852                         }
853                 } else {
854                         arg = "/";
855                 }
856                 obj->data.fsbar.fs = prepare_fs_stat(arg);
857         END OBJ(fs_bar_free, CALLBACK(&update_fs_stats))
858                 SIZE_DEFAULTS(bar);
859                 arg = scan_bar(arg, &obj->data.fsbar.w, &obj->data.fsbar.h);
860                 if (arg) {
861                         while (isspace(*arg)) {
862                                 arg++;
863                         }
864                         if (*arg == '\0') {
865                                 arg = "/";
866                         }
867                 } else {
868                         arg = "/";
869                 }
870
871                 obj->data.fsbar.fs = prepare_fs_stat(arg);
872         END OBJ(fs_free, CALLBACK(&update_fs_stats))
873                 if (!arg) {
874                         arg = "/";
875                 }
876                 obj->data.fs = prepare_fs_stat(arg);
877         END OBJ(fs_used_perc, CALLBACK(&update_fs_stats))
878                 if (!arg) {
879                         arg = "/";
880                 }
881                 obj->data.fs = prepare_fs_stat(arg);
882         END OBJ(fs_free_perc, CALLBACK(&update_fs_stats))
883                 if (!arg) {
884                         arg = "/";
885                 }
886                 obj->data.fs = prepare_fs_stat(arg);
887         END OBJ(fs_size, CALLBACK(&update_fs_stats))
888                 if (!arg) {
889                         arg = "/";
890                 }
891                 obj->data.fs = prepare_fs_stat(arg);
892         END OBJ(fs_type, CALLBACK(&update_fs_stats))
893                 if (!arg) {
894                         arg = "/";
895                 }
896                 obj->data.fs = prepare_fs_stat(arg);
897         END OBJ(fs_used, CALLBACK(&update_fs_stats))
898                 if (!arg) {
899                         arg = "/";
900                 }
901                 obj->data.fs = prepare_fs_stat(arg);
902         END OBJ(hr, 0)
903                 obj->data.i = arg ? atoi(arg) : 1;
904         END OBJ(nameserver, CALLBACK(&update_dns_data))
905                 obj->data.i = arg ? atoi(arg) : 0;
906         END OBJ(offset, 0)
907                 obj->data.i = arg ? atoi(arg) : 1;
908         END OBJ(voffset, 0)
909                 obj->data.i = arg ? atoi(arg) : 1;
910         END OBJ(goto, 0)
911
912                 if (!arg) {
913                         NORM_ERR("goto needs arguments");
914                         obj->type = OBJ_text;
915                         obj->data.s = strndup("${goto}", text_buffer_size);
916                         return NULL;
917                 }
918
919                 obj->data.i = atoi(arg);
920
921         END OBJ(tab, 0)
922                 int a = 10, b = 0;
923
924                 if (arg) {
925                         if (sscanf(arg, "%d %d", &a, &b) != 2) {
926                                 sscanf(arg, "%d", &b);
927                         }
928                 }
929                 if (a <= 0) {
930                         a = 1;
931                 }
932                 obj->data.pair.a = a;
933                 obj->data.pair.b = b;
934
935 #ifdef __linux__
936         END OBJ(i2c, 0)
937                 char buf1[64], buf2[64];
938                 float factor, offset;
939                 int n, found = 0;
940
941                 if (!arg) {
942                         NORM_ERR("i2c needs arguments");
943                         obj->type = OBJ_text;
944                         // obj->data.s = strndup("${i2c}", text_buffer_size);
945                         return NULL;
946                 }
947
948 #define HWMON_RESET() {\
949                 buf1[0] = 0; \
950                 factor = 1.0; \
951                 offset = 0.0; }
952
953                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
954                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
955                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
956                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
957
958                 if (!found) {
959                         NORM_ERR("i2c failed to parse arguments");
960                         obj->type = OBJ_text;
961                         return NULL;
962                 }
963                 DBGP("parsed i2c args: '%s' '%s' %d %f %f\n", buf1, buf2, n, factor, offset);
964                 obj->data.sysfs.fd = open_i2c_sensor((*buf1) ? buf1 : 0, buf2, n,
965                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
966                 strncpy(obj->data.sysfs.type, buf2, 63);
967                 obj->data.sysfs.factor = factor;
968                 obj->data.sysfs.offset = offset;
969
970         END OBJ(platform, 0)
971                 char buf1[64], buf2[64];
972                 float factor, offset;
973                 int n, found = 0;
974
975                 if (!arg) {
976                         NORM_ERR("platform needs arguments");
977                         obj->type = OBJ_text;
978                         return NULL;
979                 }
980
981                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
982                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
983                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
984                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
985
986                 if (!found) {
987                         NORM_ERR("platform failed to parse arguments");
988                         obj->type = OBJ_text;
989                         return NULL;
990                 }
991                 DBGP("parsed platform args: '%s' '%s' %d %f %f", buf1, buf2, n, factor, offset);
992                 obj->data.sysfs.fd = open_platform_sensor((*buf1) ? buf1 : 0, buf2, n,
993                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
994                 strncpy(obj->data.sysfs.type, buf2, 63);
995                 obj->data.sysfs.factor = factor;
996                 obj->data.sysfs.offset = offset;
997
998         END OBJ(hwmon, 0)
999                 char buf1[64], buf2[64];
1000                 float factor, offset;
1001                 int n, found = 0;
1002
1003                 if (!arg) {
1004                         NORM_ERR("hwmon needs argumanets");
1005                         obj->type = OBJ_text;
1006                         return NULL;
1007                 }
1008
1009                 if (sscanf(arg, "%63s %d %f %f", buf2, &n, &factor, &offset) == 4) found = 1; else HWMON_RESET();
1010                 if (!found && sscanf(arg, "%63s %63s %d %f %f", buf1, buf2, &n, &factor, &offset) == 5) found = 1; else if (!found) HWMON_RESET();
1011                 if (!found && sscanf(arg, "%63s %63s %d", buf1, buf2, &n) == 3) found = 1; else if (!found) HWMON_RESET();
1012                 if (!found && sscanf(arg, "%63s %d", buf2, &n) == 2) found = 1; else if (!found) HWMON_RESET();
1013
1014 #undef HWMON_RESET
1015
1016                 if (!found) {
1017                         NORM_ERR("hwmon failed to parse arguments");
1018                         obj->type = OBJ_text;
1019                         return NULL;
1020                 }
1021                 DBGP("parsed hwmon args: '%s' '%s' %d %f %f\n", buf1, buf2, n, factor, offset);
1022                 obj->data.sysfs.fd = open_hwmon_sensor((*buf1) ? buf1 : 0, buf2, n,
1023                                 &obj->data.sysfs.arg, obj->data.sysfs.devtype);
1024                 strncpy(obj->data.sysfs.type, buf2, 63);
1025                 obj->data.sysfs.factor = factor;
1026                 obj->data.sysfs.offset = offset;
1027
1028 #endif /* !__OpenBSD__ */
1029
1030         END
1031         /* we have four different types of top (top, top_mem, top_time and top_io). To
1032          * avoid having almost-same code four times, we have this special
1033          * handler. */
1034         if (strncmp(s, "top", 3) == EQUAL) {
1035                 add_update_callback(&update_meminfo);
1036                 if (!parse_top_args(s, arg, obj)) {
1037                         return NULL;
1038                 }
1039         } else OBJ(addr, CALLBACK(&update_net_stats))
1040                 if (arg) {
1041                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1042                 } else {
1043                         // default to DEFAULTNETDEV
1044                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1045                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1046                         free(buf);
1047                 }
1048 #if defined(__linux__)
1049         END OBJ(addrs, CALLBACK(&update_net_stats))
1050                 if (arg) {
1051                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1052                 } else {
1053                         // default to DEFAULTNETDEV
1054                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1055                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1056                         free(buf);
1057                 }
1058 #endif /* __linux__ */
1059         END OBJ(tail, 0)
1060                 init_tailhead("tail", arg, obj, free_at_crash);
1061         END OBJ(head, 0)
1062                 init_tailhead("head", arg, obj, free_at_crash);
1063         END OBJ(lines, 0)
1064                 if (arg) {
1065                         obj->data.s = strndup(arg, text_buffer_size);
1066                 }else{
1067                         CRIT_ERR(obj, free_at_crash, "lines needs a argument");
1068                 }
1069         END OBJ(words, 0)
1070                 if (arg) {
1071                         obj->data.s = strndup(arg, text_buffer_size);
1072                 }else{
1073                         CRIT_ERR(obj, free_at_crash, "words needs a argument");
1074                 }
1075         END OBJ(loadavg, CALLBACK(&update_load_average))
1076                 int a = 1, b = 2, c = 3, r = 3;
1077
1078                 if (arg) {
1079                         r = sscanf(arg, "%d %d %d", &a, &b, &c);
1080                         if (r >= 3 && (c < 1 || c > 3)) {
1081                                 r--;
1082                         }
1083                         if (r >= 2 && (b < 1 || b > 3)) {
1084                                 r--, b = c;
1085                         }
1086                         if (r >= 1 && (a < 1 || a > 3)) {
1087                                 r--, a = b, b = c;
1088                         }
1089                 }
1090                 obj->data.loadavg[0] = (r >= 1) ? (unsigned char) a : 0;
1091                 obj->data.loadavg[1] = (r >= 2) ? (unsigned char) b : 0;
1092                 obj->data.loadavg[2] = (r >= 3) ? (unsigned char) c : 0;
1093         END OBJ_IF(if_empty, 0)
1094                 if (!arg) {
1095                         NORM_ERR("if_empty needs an argument");
1096                         obj->data.ifblock.s = 0;
1097                 } else {
1098                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1099                         obj->sub = malloc(sizeof(struct text_object));
1100                         extract_variable_text_internal(obj->sub,
1101                                                        obj->data.ifblock.s);
1102                 }
1103         END OBJ_IF(if_match, 0)
1104                 if (!arg) {
1105                         NORM_ERR("if_match needs arguments");
1106                         obj->data.ifblock.s = 0;
1107                 } else {
1108                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1109                         obj->sub = malloc(sizeof(struct text_object));
1110                         extract_variable_text_internal(obj->sub,
1111                                                        obj->data.ifblock.s);
1112                 }
1113         END OBJ_IF(if_existing, 0)
1114                 if (!arg) {
1115                         NORM_ERR("if_existing needs an argument or two");
1116                         obj->data.ifblock.s = NULL;
1117                         obj->data.ifblock.str = NULL;
1118                 } else {
1119                         char buf1[256], buf2[256];
1120                         int r = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
1121
1122                         if (r == 1) {
1123                                 obj->data.ifblock.s = strndup(buf1, text_buffer_size);
1124                                 obj->data.ifblock.str = NULL;
1125                         } else {
1126                                 obj->data.ifblock.s = strndup(buf1, text_buffer_size);
1127                                 obj->data.ifblock.str = strndup(buf2, text_buffer_size);
1128                         }
1129                 }
1130                 DBGP("if_existing: '%s' '%s'", obj->data.ifblock.s, obj->data.ifblock.str);
1131         END OBJ_IF(if_mounted, 0)
1132                 if (!arg) {
1133                         NORM_ERR("if_mounted needs an argument");
1134                         obj->data.ifblock.s = 0;
1135                 } else {
1136                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1137                 }
1138 #ifdef __linux__
1139         END OBJ_IF(if_running, CALLBACK(&update_top))
1140                 if (arg) {
1141                         top_running = 1;
1142                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1143 #else
1144         END OBJ_IF(if_running, 0)
1145                 if (arg) {
1146                         char buf[256];
1147
1148                         snprintf(buf, 256, "pidof %s >/dev/null", arg);
1149                         obj->data.ifblock.s = strndup(buf, text_buffer_size);
1150 #endif
1151                 } else {
1152                         NORM_ERR("if_running needs an argument");
1153                         obj->data.ifblock.s = 0;
1154                 }
1155         END OBJ(kernel, 0)
1156         END OBJ(machine, 0)
1157         END OBJ(mails, 0)
1158                 float n1;
1159                 char mbox[256], dst[256];
1160
1161                 if (!arg) {
1162                         n1 = 9.5;
1163                         /* Kapil: Changed from MAIL_FILE to
1164                            current_mail_spool since the latter
1165                            is a copy of the former if undefined
1166                            but the latter should take precedence
1167                            if defined */
1168                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1169                 } else {
1170                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1171                                 n1 = 9.5;
1172                                 strncpy(mbox, arg, sizeof(mbox));
1173                         }
1174                 }
1175
1176                 variable_substitute(mbox, dst, sizeof(dst));
1177                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1178                 obj->data.local_mail.interval = n1;
1179         END OBJ(new_mails, 0)
1180                 float n1;
1181                 char mbox[256], dst[256];
1182
1183                 if (!arg) {
1184                         n1 = 9.5;
1185                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1186                 } else {
1187                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1188                                 n1 = 9.5;
1189                                 strncpy(mbox, arg, sizeof(mbox));
1190                         }
1191                 }
1192
1193                 variable_substitute(mbox, dst, sizeof(dst));
1194                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1195                 obj->data.local_mail.interval = n1;
1196         END OBJ(seen_mails, 0)
1197                 float n1;
1198                 char mbox[256], dst[256];
1199
1200                 if (!arg) {
1201                         n1 = 9.5;
1202                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1203                 } else {
1204                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1205                                 n1 = 9.5;
1206                                 strncpy(mbox, arg, sizeof(mbox));
1207                         }
1208                 }
1209
1210                 variable_substitute(mbox, dst, sizeof(dst));
1211                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1212                 obj->data.local_mail.interval = n1;
1213         END OBJ(unseen_mails, 0)
1214                 float n1;
1215                 char mbox[256], dst[256];
1216
1217                 if (!arg) {
1218                         n1 = 9.5;
1219                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1220                 } else {
1221                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1222                                 n1 = 9.5;
1223                                 strncpy(mbox, arg, sizeof(mbox));
1224                         }
1225                 }
1226
1227                 variable_substitute(mbox, dst, sizeof(dst));
1228                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1229                 obj->data.local_mail.interval = n1;
1230         END OBJ(flagged_mails, 0)
1231                 float n1;
1232                 char mbox[256], dst[256];
1233
1234                 if (!arg) {
1235                         n1 = 9.5;
1236                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1237                 } else {
1238                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1239                                 n1 = 9.5;
1240                                 strncpy(mbox, arg, sizeof(mbox));
1241                         }
1242                 }
1243
1244                 variable_substitute(mbox, dst, sizeof(dst));
1245                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1246                 obj->data.local_mail.interval = n1;
1247         END OBJ(unflagged_mails, 0)
1248                 float n1;
1249                 char mbox[256], dst[256];
1250
1251                 if (!arg) {
1252                         n1 = 9.5;
1253                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1254                 } else {
1255                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1256                                 n1 = 9.5;
1257                                 strncpy(mbox, arg, sizeof(mbox));
1258                         }
1259                 }
1260
1261                 variable_substitute(mbox, dst, sizeof(dst));
1262                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1263                 obj->data.local_mail.interval = n1;
1264         END OBJ(forwarded_mails, 0)
1265                 float n1;
1266                 char mbox[256], dst[256];
1267
1268                 if (!arg) {
1269                         n1 = 9.5;
1270                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1271                 } else {
1272                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1273                                 n1 = 9.5;
1274                                 strncpy(mbox, arg, sizeof(mbox));
1275                         }
1276                 }
1277
1278                 variable_substitute(mbox, dst, sizeof(dst));
1279                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1280                 obj->data.local_mail.interval = n1;
1281         END OBJ(unforwarded_mails, 0)
1282                 float n1;
1283                 char mbox[256], dst[256];
1284
1285                 if (!arg) {
1286                         n1 = 9.5;
1287                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1288                 } else {
1289                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1290                                 n1 = 9.5;
1291                                 strncpy(mbox, arg, sizeof(mbox));
1292                         }
1293                 }
1294
1295                 variable_substitute(mbox, dst, sizeof(dst));
1296                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1297                 obj->data.local_mail.interval = n1;
1298         END OBJ(replied_mails, 0)
1299                 float n1;
1300                 char mbox[256], dst[256];
1301
1302                 if (!arg) {
1303                         n1 = 9.5;
1304                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1305                 } else {
1306                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1307                                 n1 = 9.5;
1308                                 strncpy(mbox, arg, sizeof(mbox));
1309                         }
1310                 }
1311
1312                 variable_substitute(mbox, dst, sizeof(dst));
1313                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1314                 obj->data.local_mail.interval = n1;
1315         END OBJ(unreplied_mails, 0)
1316                 float n1;
1317                 char mbox[256], dst[256];
1318
1319                 if (!arg) {
1320                         n1 = 9.5;
1321                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1322                 } else {
1323                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1324                                 n1 = 9.5;
1325                                 strncpy(mbox, arg, sizeof(mbox));
1326                         }
1327                 }
1328
1329                 variable_substitute(mbox, dst, sizeof(dst));
1330                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1331                 obj->data.local_mail.interval = n1;
1332         END OBJ(draft_mails, 0)
1333                 float n1;
1334                 char mbox[256], dst[256];
1335
1336                 if (!arg) {
1337                         n1 = 9.5;
1338                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1339                 } else {
1340                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1341                                 n1 = 9.5;
1342                                 strncpy(mbox, arg, sizeof(mbox));
1343                         }
1344                 }
1345
1346                 variable_substitute(mbox, dst, sizeof(dst));
1347                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1348                 obj->data.local_mail.interval = n1;
1349         END OBJ(trashed_mails, 0)
1350                 float n1;
1351                 char mbox[256], dst[256];
1352
1353                 if (!arg) {
1354                         n1 = 9.5;
1355                         strncpy(mbox, current_mail_spool, sizeof(mbox));
1356                 } else {
1357                         if (sscanf(arg, "%s %f", mbox, &n1) != 2) {
1358                                 n1 = 9.5;
1359                                 strncpy(mbox, arg, sizeof(mbox));
1360                         }
1361                 }
1362
1363                 variable_substitute(mbox, dst, sizeof(dst));
1364                 obj->data.local_mail.mbox = strndup(dst, text_buffer_size);
1365                 obj->data.local_mail.interval = n1;
1366         END OBJ(mboxscan, 0)
1367                 obj->data.mboxscan.args = (char *) malloc(text_buffer_size);
1368                 obj->data.mboxscan.output = (char *) malloc(text_buffer_size);
1369                 /* if '1' (in mboxscan.c) then there was SIGUSR1, hmm */
1370                 obj->data.mboxscan.output[0] = 1;
1371                 strncpy(obj->data.mboxscan.args, arg, text_buffer_size);
1372         END OBJ(mem, CALLBACK(&update_meminfo))
1373         END OBJ(memeasyfree, CALLBACK(&update_meminfo))
1374         END OBJ(memfree, CALLBACK(&update_meminfo))
1375         END OBJ(memmax, CALLBACK(&update_meminfo))
1376         END OBJ(memperc, CALLBACK(&update_meminfo))
1377 #ifdef X11
1378         END OBJ(memgauge, CALLBACK(&update_meminfo))
1379                 SIZE_DEFAULTS(gauge);
1380                 scan_gauge(arg, &obj->data.pair.a, &obj->data.pair.b);
1381 #endif /* X11*/
1382         END OBJ(membar, CALLBACK(&update_meminfo))
1383                 SIZE_DEFAULTS(bar);
1384                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1385 #ifdef X11
1386         END OBJ(memgraph, CALLBACK(&update_meminfo))
1387                 char *buf = 0;
1388                 SIZE_DEFAULTS(graph);
1389                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1390                                 &obj->e, &obj->char_a, &obj->char_b);
1391
1392                 if (buf) free(buf);
1393 #endif /* X11*/
1394         END OBJ(mixer, 0)
1395                 obj->data.l = mixer_init(arg);
1396         END OBJ(mixerl, 0)
1397                 obj->data.l = mixer_init(arg);
1398         END OBJ(mixerr, 0)
1399                 obj->data.l = mixer_init(arg);
1400 #ifdef X11
1401         END OBJ(mixerbar, 0)
1402                 SIZE_DEFAULTS(bar);
1403                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
1404                         &obj->data.mixerbar.h);
1405         END OBJ(mixerlbar, 0)
1406                 SIZE_DEFAULTS(bar);
1407                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
1408                         &obj->data.mixerbar.h);
1409         END OBJ(mixerrbar, 0)
1410                 SIZE_DEFAULTS(bar);
1411                 scan_mixer_bar(arg, &obj->data.mixerbar.l, &obj->data.mixerbar.w,
1412                         &obj->data.mixerbar.h);
1413 #endif
1414         END OBJ_IF(if_mixer_mute, 0)
1415                 obj->data.ifblock.i = mixer_init(arg);
1416 #ifdef X11
1417         END OBJ(monitor, CALLBACK(&update_x11info))
1418         END OBJ(monitor_number, CALLBACK(&update_x11info))
1419         END OBJ(desktop, CALLBACK(&update_x11info))
1420         END OBJ(desktop_number, CALLBACK(&update_x11info))
1421         END OBJ(desktop_name, CALLBACK(&update_x11info))
1422 #endif
1423         END OBJ(nodename, 0)
1424         END OBJ(processes, CALLBACK(&update_total_processes))
1425         END OBJ(running_processes, CALLBACK(&update_running_processes))
1426         END OBJ(shadecolor, 0)
1427 #ifdef X11
1428                 obj->data.l = arg ? get_x11_color(arg) : default_bg_color;
1429 #endif /* X11 */
1430         END OBJ(outlinecolor, 0)
1431 #ifdef X11
1432                 obj->data.l = arg ? get_x11_color(arg) : default_out_color;
1433 #endif /* X11 */
1434         END OBJ(stippled_hr, 0)
1435 #ifdef X11
1436                 int a = get_stippled_borders(), b = 1;
1437
1438                 if (arg) {
1439                         if (sscanf(arg, "%d %d", &a, &b) != 2) {
1440                                 sscanf(arg, "%d", &b);
1441                         }
1442                 }
1443                 if (a <= 0) {
1444                         a = 1;
1445                 }
1446                 obj->data.pair.a = a;
1447                 obj->data.pair.b = b;
1448 #endif /* X11 */
1449         END OBJ(swap, CALLBACK(&update_meminfo))
1450         END OBJ(swapfree, CALLBACK(&update_meminfo))
1451         END OBJ(swapmax, CALLBACK(&update_meminfo))
1452         END OBJ(swapperc, CALLBACK(&update_meminfo))
1453         END OBJ(swapbar, CALLBACK(&update_meminfo))
1454                 SIZE_DEFAULTS(bar);
1455                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1456         END OBJ(sysname, 0)
1457         END OBJ(time, 0)
1458                 obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
1459         END OBJ(utime, 0)
1460                 obj->data.s = strndup(arg ? arg : "%F %T", text_buffer_size);
1461         END OBJ(tztime, 0)
1462                 char buf1[256], buf2[256], *fmt, *tz;
1463
1464                 fmt = tz = NULL;
1465                 if (arg) {
1466                         int nArgs = sscanf(arg, "%255s %255[^\n]", buf1, buf2);
1467
1468                         switch (nArgs) {
1469                                 case 2:
1470                                         tz = buf1;
1471                                 case 1:
1472                                         fmt = buf2;
1473                         }
1474                 }
1475
1476                 obj->data.tztime.fmt = strndup(fmt ? fmt : "%F %T", text_buffer_size);
1477                 obj->data.tztime.tz = tz ? strndup(tz, text_buffer_size) : NULL;
1478 #ifdef HAVE_ICONV
1479         END OBJ(iconv_start, 0)
1480                 if (is_iconv_converting()) {
1481                         CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before "
1482                                 "starting another");
1483                 }
1484                 if (arg) {
1485                         char iconv_from[ICONV_CODEPAGE_LENGTH];
1486                         char iconv_to[ICONV_CODEPAGE_LENGTH];
1487
1488                         if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) {
1489                                 CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start");
1490                         } else {
1491                                 iconv_t new_iconv;
1492
1493                                 new_iconv = iconv_open(iconv_to, iconv_from);
1494                                 if (new_iconv == (iconv_t) (-1)) {
1495                                         NORM_ERR("Can't convert from %s to %s.", iconv_from, iconv_to);
1496                                 } else {
1497                                         obj->a = register_iconv(&new_iconv);
1498                                         set_iconv_converting(1);
1499                                 }
1500                         }
1501                 } else {
1502                         CRIT_ERR(obj, free_at_crash, "Iconv requires arguments");
1503                 }
1504         END OBJ(iconv_stop, 0)
1505                 set_iconv_converting(0);
1506
1507 #endif
1508         END OBJ(totaldown, CALLBACK(&update_net_stats))
1509                 if (arg) {
1510                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1511                 } else {
1512                         // default to DEFAULTNETDEV
1513                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1514                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1515                         free(buf);
1516                 }
1517         END OBJ(totalup, CALLBACK(&update_net_stats))
1518                 obj->data.net = get_net_stat(arg, obj, free_at_crash);
1519                 if (arg) {
1520                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1521                 } else {
1522                         // default to DEFAULTNETDEV
1523                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1524                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1525                         free(buf);
1526                 }
1527         END OBJ(updates, 0)
1528         END OBJ_IF(if_updatenr, 0)
1529                 obj->data.ifblock.i = arg ? atoi(arg) : 0;
1530                 if(obj->data.ifblock.i == 0) CRIT_ERR(obj, free_at_crash, "if_updatenr needs a number above 0 as argument");
1531                 set_updatereset(obj->data.ifblock.i > get_updatereset() ? obj->data.ifblock.i : get_updatereset());
1532         END OBJ(alignr, 0)
1533                 obj->data.i = arg ? atoi(arg) : 0;
1534         END OBJ(alignc, 0)
1535                 obj->data.i = arg ? atoi(arg) : 0;
1536         END OBJ(upspeed, CALLBACK(&update_net_stats))
1537                 if (arg) {
1538                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1539                 } else {
1540                         // default to DEFAULTNETDEV
1541                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1542                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1543                         free(buf);
1544                 }
1545         END OBJ(upspeedf, CALLBACK(&update_net_stats))
1546                 if (arg) {
1547                         obj->data.net = get_net_stat(arg, obj, free_at_crash);
1548                 } else {
1549                         // default to DEFAULTNETDEV
1550                         char *buf = strndup(DEFAULTNETDEV, text_buffer_size);
1551                         obj->data.net = get_net_stat(buf, obj, free_at_crash);
1552                         free(buf);
1553                 }
1554
1555 #ifdef X11
1556         END OBJ(upspeedgraph, CALLBACK(&update_net_stats))
1557                 char *buf = 0;
1558                 SIZE_DEFAULTS(graph);
1559                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1560                                 &obj->e, &obj->char_a, &obj->char_b);
1561
1562                 // default to DEFAULTNETDEV
1563                 buf = strndup(buf ? buf : DEFAULTNETDEV, text_buffer_size);
1564                 obj->data.net = get_net_stat(buf, obj, free_at_crash);
1565                 free(buf);
1566 #endif
1567         END OBJ(uptime_short, CALLBACK(&update_uptime))
1568         END OBJ(uptime, CALLBACK(&update_uptime))
1569         END OBJ(user_names, CALLBACK(&update_users))
1570         END OBJ(user_times, CALLBACK(&update_users))
1571         END OBJ(user_terms, CALLBACK(&update_users))
1572         END OBJ(user_number, CALLBACK(&update_users))
1573 #if defined(__linux__)
1574         END OBJ(gw_iface, CALLBACK(&update_gateway_info))
1575         END OBJ(gw_ip, CALLBACK(&update_gateway_info))
1576 #endif /* !__linux__ */
1577 #ifndef __OpenBSD__
1578         END OBJ(adt746xcpu, 0)
1579         END OBJ(adt746xfan, 0)
1580 #endif /* !__OpenBSD__ */
1581 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
1582                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
1583         END OBJ(apm_adapter, 0)
1584         END OBJ(apm_battery_life, 0)
1585         END OBJ(apm_battery_time, 0)
1586 #endif /* __FreeBSD__ */
1587         END OBJ(imap_unseen, 0)
1588                 if (arg) {
1589                         // proccss
1590                         obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
1591                         obj->char_b = 0;
1592                 } else {
1593                         obj->char_b = 1;
1594                 }
1595         END OBJ(imap_messages, 0)
1596                 if (arg) {
1597                         // proccss
1598                         obj->data.mail = parse_mail_args(IMAP_TYPE, arg);
1599                         obj->char_b = 0;
1600                 } else {
1601                         obj->char_b = 1;
1602                 }
1603         END OBJ(pop3_unseen, 0)
1604                 if (arg) {
1605                         // proccss
1606                         obj->data.mail = parse_mail_args(POP3_TYPE, arg);
1607                         obj->char_b = 0;
1608                 } else {
1609                         obj->char_b = 1;
1610                 }
1611         END OBJ(pop3_used, 0)
1612                 if (arg) {
1613                         // proccss
1614                         obj->data.mail = parse_mail_args(POP3_TYPE, arg);
1615                         obj->char_b = 0;
1616                 } else {
1617                         obj->char_b = 1;
1618                 }
1619 #ifdef IBM
1620         END OBJ(smapi, 0)
1621                 if (arg)
1622                         obj->data.s = strndup(arg, text_buffer_size);
1623                 else
1624                         NORM_ERR("smapi needs an argument");
1625         END OBJ_IF(if_smapi_bat_installed, 0)
1626                 if (!arg) {
1627                         NORM_ERR("if_smapi_bat_installed needs an argument");
1628                         obj->data.ifblock.s = 0;
1629                 } else
1630                         obj->data.ifblock.s = strndup(arg, text_buffer_size);
1631         END OBJ(smapi_bat_perc, 0)
1632                 if (arg)
1633                         obj->data.s = strndup(arg, text_buffer_size);
1634                 else
1635                         NORM_ERR("smapi_bat_perc needs an argument");
1636         END OBJ(smapi_bat_temp, 0)
1637                 if (arg)
1638                         obj->data.s = strndup(arg, text_buffer_size);
1639                 else
1640                         NORM_ERR("smapi_bat_temp needs an argument");
1641         END OBJ(smapi_bat_power, 0)
1642                 if (arg)
1643                         obj->data.s = strndup(arg, text_buffer_size);
1644                 else
1645                         NORM_ERR("smapi_bat_power needs an argument");
1646 #ifdef X11
1647         END OBJ(smapi_bat_bar, 0)
1648                 SIZE_DEFAULTS(bar);
1649                 if(arg) {
1650                         int cnt;
1651                         if(sscanf(arg, "%i %n", &obj->data.i, &cnt) <= 0) {
1652                                 NORM_ERR("first argument to smapi_bat_bar must be an integer value");
1653                                 obj->data.i = -1;
1654                         } else {
1655                                 obj->b = 4;
1656                                 arg = scan_bar(arg + cnt, &obj->a, &obj->b);
1657                         }
1658                 } else
1659                         NORM_ERR("smapi_bat_bar needs an argument");
1660 #endif /* X11 */
1661 #endif /* IBM */
1662 #ifdef MPD
1663 #define mpd_set_maxlen(name) \
1664                 if (arg) { \
1665                         int i; \
1666                         sscanf(arg, "%d", &i); \
1667                         if (i > 0) \
1668                                 obj->data.i = i + 1; \
1669                         else \
1670                                 NORM_ERR(#name ": invalid length argument"); \
1671                 }
1672         END OBJ(mpd_artist, CALLBACK(&update_mpd))
1673                 mpd_set_maxlen(mpd_artist);
1674                 init_mpd();
1675         END OBJ(mpd_title, CALLBACK(&update_mpd))
1676                 mpd_set_maxlen(mpd_title);
1677                 init_mpd();
1678         END OBJ(mpd_random, CALLBACK(&update_mpd)) init_mpd();
1679         END OBJ(mpd_repeat, CALLBACK(&update_mpd)) init_mpd();
1680         END OBJ(mpd_elapsed, CALLBACK(&update_mpd)) init_mpd();
1681         END OBJ(mpd_length, CALLBACK(&update_mpd)) init_mpd();
1682         END OBJ(mpd_track, CALLBACK(&update_mpd))
1683                 mpd_set_maxlen(mpd_track);
1684                 init_mpd();
1685         END OBJ(mpd_name, CALLBACK(&update_mpd))
1686                 mpd_set_maxlen(mpd_name);
1687                 init_mpd();
1688         END OBJ(mpd_file, CALLBACK(&update_mpd))
1689                 mpd_set_maxlen(mpd_file);
1690                 init_mpd();
1691         END OBJ(mpd_percent, CALLBACK(&update_mpd)) init_mpd();
1692         END OBJ(mpd_album, CALLBACK(&update_mpd))
1693                 mpd_set_maxlen(mpd_album);
1694                 init_mpd();
1695         END OBJ(mpd_vol, CALLBACK(&update_mpd)) init_mpd();
1696         END OBJ(mpd_bitrate, CALLBACK(&update_mpd)) init_mpd();
1697         END OBJ(mpd_status, CALLBACK(&update_mpd)) init_mpd();
1698         END OBJ(mpd_bar, CALLBACK(&update_mpd))
1699                 SIZE_DEFAULTS(bar);
1700                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1701                 init_mpd();
1702         END OBJ(mpd_smart, CALLBACK(&update_mpd))
1703                 mpd_set_maxlen(mpd_smart);
1704                 init_mpd();
1705         END OBJ_IF(if_mpd_playing, CALLBACK(&update_mpd))
1706                 init_mpd();
1707 #undef mpd_set_maxlen
1708 #endif /* MPD */
1709 #ifdef MOC
1710         END OBJ(moc_state, CALLBACK(&update_moc))
1711         END OBJ(moc_file, CALLBACK(&update_moc))
1712         END OBJ(moc_title, CALLBACK(&update_moc))
1713         END OBJ(moc_artist, CALLBACK(&update_moc))
1714         END OBJ(moc_song, CALLBACK(&update_moc))
1715         END OBJ(moc_album, CALLBACK(&update_moc))
1716         END OBJ(moc_totaltime, CALLBACK(&update_moc))
1717         END OBJ(moc_timeleft, CALLBACK(&update_moc))
1718         END OBJ(moc_curtime, CALLBACK(&update_moc))
1719         END OBJ(moc_bitrate, CALLBACK(&update_moc))
1720         END OBJ(moc_rate, CALLBACK(&update_moc))
1721 #endif /* MOC */
1722 #ifdef XMMS2
1723         END OBJ(xmms2_artist, CALLBACK(&update_xmms2))
1724         END OBJ(xmms2_album, CALLBACK(&update_xmms2))
1725         END OBJ(xmms2_title, CALLBACK(&update_xmms2))
1726         END OBJ(xmms2_genre, CALLBACK(&update_xmms2))
1727         END OBJ(xmms2_comment, CALLBACK(&update_xmms2))
1728         END OBJ(xmms2_url, CALLBACK(&update_xmms2))
1729         END OBJ(xmms2_tracknr, CALLBACK(&update_xmms2))
1730         END OBJ(xmms2_bitrate, CALLBACK(&update_xmms2))
1731         END OBJ(xmms2_date, CALLBACK(&update_xmms2))
1732         END OBJ(xmms2_id, CALLBACK(&update_xmms2))
1733         END OBJ(xmms2_duration, CALLBACK(&update_xmms2))
1734         END OBJ(xmms2_elapsed, CALLBACK(&update_xmms2))
1735         END OBJ(xmms2_size, CALLBACK(&update_xmms2))
1736         END OBJ(xmms2_status, CALLBACK(&update_xmms2))
1737         END OBJ(xmms2_percent, CALLBACK(&update_xmms2))
1738 #ifdef X11
1739         END OBJ(xmms2_bar, CALLBACK(&update_xmms2))
1740                 SIZE_DEFAULTS(bar);
1741                 scan_bar(arg, &obj->data.pair.a, &obj->data.pair.b);
1742 #endif /* X11 */
1743         END OBJ(xmms2_smart, CALLBACK(&update_xmms2))
1744         END OBJ(xmms2_playlist, CALLBACK(&update_xmms2))
1745         END OBJ(xmms2_timesplayed, CALLBACK(&update_xmms2))
1746         END OBJ_IF(if_xmms2_connected, CALLBACK(&update_xmms2))
1747 #endif
1748 #ifdef AUDACIOUS
1749         END OBJ(audacious_status, CALLBACK(&update_audacious))
1750         END OBJ(audacious_title, CALLBACK(&update_audacious))
1751                 if (arg) {
1752                         sscanf(arg, "%d", &info.audacious.max_title_len);
1753                         if (info.audacious.max_title_len > 0) {
1754                                 info.audacious.max_title_len++;
1755                         } else {
1756                                 CRIT_ERR(obj, free_at_crash, "audacious_title: invalid length argument");
1757                         }
1758                 }
1759         END OBJ(audacious_length, CALLBACK(&update_audacious))
1760         END OBJ(audacious_length_seconds, CALLBACK(&update_audacious))
1761         END OBJ(audacious_position, CALLBACK(&update_audacious))
1762         END OBJ(audacious_position_seconds, CALLBACK(&update_audacious))
1763         END OBJ(audacious_bitrate, CALLBACK(&update_audacious))
1764         END OBJ(audacious_frequency, CALLBACK(&update_audacious))
1765         END OBJ(audacious_channels, CALLBACK(&update_audacious))
1766         END OBJ(audacious_filename, CALLBACK(&update_audacious))
1767         END OBJ(audacious_playlist_length, CALLBACK(&update_audacious))
1768         END OBJ(audacious_playlist_position, CALLBACK(&update_audacious))
1769         END OBJ(audacious_main_volume, CALLBACK(&update_audacious))
1770 #ifdef X11
1771         END OBJ(audacious_bar, CALLBACK(&update_audacious))
1772                 SIZE_DEFAULTS(bar);
1773                 scan_bar(arg, &obj->a, &obj->b);
1774 #endif /* X11 */
1775 #endif
1776 #ifdef BMPX
1777         END OBJ(bmpx_title, CALLBACK(&update_bmpx))
1778                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1779         END OBJ(bmpx_artist, CALLBACK(&update_bmpx))
1780                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1781         END OBJ(bmpx_album, CALLBACK(&update_bmpx))
1782                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1783         END OBJ(bmpx_track, CALLBACK(&update_bmpx))
1784                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1785         END OBJ(bmpx_uri, CALLBACK(&update_bmpx))
1786                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1787         END OBJ(bmpx_bitrate, CALLBACK(&update_bmpx))
1788                 memset(&(info.bmpx), 0, sizeof(struct bmpx_s));
1789 #endif
1790 #ifdef EVE
1791         END OBJ(eve, 0)
1792                 if(arg) {
1793                         int argc;
1794                         char *userid = (char *) malloc(20 * sizeof(char));
1795                         char *apikey = (char *) malloc(64 * sizeof(char));
1796                         char *charid = (char *) malloc(20 * sizeof(char));
1797
1798                         argc = sscanf(arg, "%20s %64s %20s", userid, apikey, charid);
1799                         obj->data.eve.charid = charid;
1800                         obj->data.eve.userid = userid;
1801                         obj->data.eve.apikey = apikey;
1802
1803                         init_eve();
1804                 } else {
1805                         CRIT_ERR(obj, free_at_crash, "eve needs arguments: <userid> <apikey> <characterid>");
1806                 }
1807 #endif
1808 #ifdef HAVE_CURL
1809         END OBJ(curl, 0)
1810                 if (arg) {
1811                         int argc;
1812                         float interval = 0;
1813                         char *uri = (char *) malloc(128 * sizeof(char));
1814
1815                         argc = sscanf(arg, "%127s %f", uri, &interval);
1816                         if (argc == 2) {
1817                                 obj->data.curl.uri = uri;
1818                                 obj->data.curl.interval = interval > 0 ? interval * 60 : 15*60;
1819                         } else {
1820                                 NORM_ERR("wrong number of arguments for $curl");
1821                         }
1822                 } else {
1823                         CRIT_ERR(obj, free_at_crash, "curl needs arguments: <uri> <interval in minutes>");
1824                 }
1825 #endif
1826 #ifdef RSS
1827         END OBJ(rss, 0)
1828                 if (arg) {
1829                         float interval = 0;
1830                         int argc, act_par = 0;
1831                         unsigned int nrspaces = 0;
1832                         char *uri = (char *) malloc(128 * sizeof(char));
1833                         char *action = (char *) malloc(64 * sizeof(char));
1834
1835                         argc = sscanf(arg, "%127s %f %63s %d %u", uri, &interval, action,
1836                                         &act_par, &nrspaces);
1837                         if (argc >= 3) {
1838                                 obj->data.rss.uri = uri;
1839                                 obj->data.rss.interval = interval > 0 ? interval * 60 : 15*60;
1840                                 obj->data.rss.action = action;
1841                                 obj->data.rss.act_par = act_par;
1842                                 obj->data.rss.nrspaces = nrspaces;
1843                         } else {
1844                                 NORM_ERR("wrong number of arguments for $rss");
1845                         }
1846                 } else {
1847                         CRIT_ERR(obj, free_at_crash, "rss needs arguments: <uri> <interval in minutes> <action> "
1848                                         "[act_par] [spaces in front]");
1849                 }
1850 #endif
1851 #ifdef WEATHER
1852         END OBJ(weather, 0)
1853                 if (arg) {
1854                         int argc;
1855                         float interval = 0;
1856                         char *locID = (char *) malloc(9 * sizeof(char));
1857                         char *uri = (char *) malloc(128 * sizeof(char));
1858                         char *data_type = (char *) malloc(32 * sizeof(char));
1859
1860                         argc = sscanf(arg, "%119s %8s %31s %f", uri, locID, data_type, &interval);
1861
1862                         if (argc >= 3) {
1863                                 if (process_weather_uri(uri, locID, 0)) {
1864                                         free(data_type);
1865                                         free(uri);
1866                                         free(locID);
1867                                         CRIT_ERR(obj, free_at_crash, \
1868                                                         "could not recognize the weather uri");
1869                                 }
1870
1871                                 obj->data.weather.uri = uri;
1872                                 obj->data.weather.data_type = data_type;
1873
1874                                 /* Limit the data retrieval interval to half hour min */
1875                                 if (interval < 30) {
1876                                         interval = 30;
1877                                 }
1878
1879                                 /* Convert to seconds */
1880                                 obj->data.weather.interval = interval * 60;
1881                                 free(locID);
1882
1883                                 DBGP("weather: fetching %s from %s every %d seconds", \
1884                                                 data_type, uri, obj->data.weather.interval);
1885                         } else {
1886                                 free(data_type);
1887                                 free(uri);
1888                                 free(locID);
1889                                 CRIT_ERR(obj, free_at_crash, "wrong number of arguments for $weather");
1890                         }
1891                 } else {
1892                         CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <locID> <data_type> [interval in minutes]");
1893                 }
1894 #endif
1895 #ifdef XOAP
1896         END OBJ(weather_forecast, 0)
1897                 if (arg) {
1898                         int argc;
1899                         unsigned int day;
1900                         float interval = 0;
1901                         char *locID = (char *) malloc(9 * sizeof(char));
1902                         char *uri = (char *) malloc(128 * sizeof(char));
1903                         char *data_type = (char *) malloc(32 * sizeof(char));
1904
1905                         argc = sscanf(arg, "%119s %8s %1u %31s %f", uri, locID, &day, data_type, &interval);
1906
1907                         if (argc >= 4) {
1908                                 if (process_weather_uri(uri, locID, 1)) {
1909                                         free(data_type);
1910                                         free(uri);
1911                                         free(locID);
1912                                         CRIT_ERR(obj, free_at_crash, \
1913                                                         "could not recognize the weather forecast uri");
1914                                 }
1915
1916                                 obj->data.weather_forecast.uri = uri;
1917                                 obj->data.weather_forecast.data_type = data_type;
1918
1919                                 /* Limit the day between 0 (today) and FORECAST_DAYS */
1920                                 if (day >= FORECAST_DAYS) {
1921                                         day = FORECAST_DAYS-1;
1922                                 }
1923                                 obj->data.weather_forecast.day = day;
1924
1925                                 /* Limit the data retrieval interval to 3 hours and an half */
1926                                 if (interval < 210) {
1927                                         interval = 210;
1928                                 }
1929
1930                                 /* Convert to seconds */
1931                                 obj->data.weather_forecast.interval = interval * 60;
1932                                 free(locID);
1933
1934                                 DBGP("weather_forecast: fetching %s for day %d from %s every %d seconds", \
1935                                          data_type, day, uri, obj->data.weather_forecast.interval);
1936                         } else {
1937                                 free(data_type);
1938                                 free(uri);
1939                                 free(locID);
1940                                 CRIT_ERR(obj, free_at_crash, "wrong number of arguments for $weather_forecast");
1941                         }
1942                 } else {
1943                         CRIT_ERR(obj, free_at_crash, "weather_forecast needs arguments: <uri> <locID> <day> <data_type> [interval in minutes]");
1944                 }
1945 #endif
1946 #ifdef HAVE_LUA
1947         END OBJ(lua, 0)
1948                 if (arg) {
1949                         obj->data.s = strndup(arg, text_buffer_size);
1950                 } else {
1951                         CRIT_ERR(obj, free_at_crash, "lua needs arguments: <function name> [function parameters]");
1952                 }
1953         END OBJ(lua_parse, 0)
1954                 if (arg) {
1955                         obj->data.s = strndup(arg, text_buffer_size);
1956                 } else {
1957                         CRIT_ERR(obj, free_at_crash, "lua_parse needs arguments: <function name> [function parameters]");
1958                 }
1959         END OBJ(lua_bar, 0)
1960                 SIZE_DEFAULTS(bar);
1961                 if (arg) {
1962                         arg = scan_bar(arg, &obj->a, &obj->b);
1963                         if(arg) {
1964                                 obj->data.s = strndup(arg, text_buffer_size);
1965                         } else {
1966                                 CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
1967                         }
1968                 } else {
1969                         CRIT_ERR(obj, free_at_crash, "lua_bar needs arguments: <height>,<width> <function name> [function parameters]");
1970                 }
1971 #ifdef X11
1972         END OBJ(lua_graph, 0)
1973                 SIZE_DEFAULTS(graph);
1974                 if (arg) {
1975                         char *buf = 0;
1976                         buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
1977                                         &obj->e, &obj->char_a, &obj->char_b);
1978                         if (buf) {
1979                                 obj->data.s = buf;
1980                         } else {
1981                                 CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
1982                         }
1983                 } else {
1984                         CRIT_ERR(obj, free_at_crash, "lua_graph needs arguments: <function name> [height],[width] [gradient colour 1] [gradient colour 2] [scale] [-t] [-l]");
1985         }
1986         END OBJ(lua_gauge, 0)
1987                 SIZE_DEFAULTS(gauge);
1988                 if (arg) {
1989                         arg = scan_gauge(arg, &obj->a, &obj->b);
1990                         if (arg) {
1991                                 obj->data.s = strndup(arg, text_buffer_size);
1992                         } else {
1993                                 CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
1994                         }
1995                 } else {
1996                         CRIT_ERR(obj, free_at_crash, "lua_gauge needs arguments: <height>,<width> <function name> [function parameters]");
1997                 }
1998 #endif /* X11 */
1999 #endif /* HAVE_LUA */
2000 #ifdef HDDTEMP
2001         END OBJ(hddtemp, CALLBACK(&update_hddtemp))
2002                 if (arg)
2003                         obj->data.s = strndup(arg, text_buffer_size);
2004 #endif /* HDDTEMP */
2005 #ifdef TCP_PORT_MONITOR
2006         END OBJ(tcp_portmon, CALLBACK(&tcp_portmon_update))
2007                 tcp_portmon_init(arg, &obj->data.tcp_port_monitor);
2008 #endif /* TCP_PORT_MONITOR */
2009         END OBJ(entropy_avail, CALLBACK(&update_entropy))
2010         END OBJ(entropy_perc, CALLBACK(&update_entropy))
2011         END OBJ(entropy_poolsize, CALLBACK(&update_entropy))
2012         END OBJ(entropy_bar, CALLBACK(&update_entropy))
2013                 SIZE_DEFAULTS(bar);
2014                 scan_bar(arg, &obj->a, &obj->b);
2015         END OBJ(include, 0)
2016                 if(arg) {
2017                         struct conftree *leaf = conftree_add(currentconffile, arg);
2018                         if(leaf) {
2019                                 if (load_config_file(arg) == TRUE) {
2020                                         obj->sub = malloc(sizeof(struct text_object));
2021                                         currentconffile = leaf;
2022                                         extract_variable_text_internal(obj->sub, get_global_text());
2023                                         currentconffile = leaf->back;
2024                                 } else {
2025                                         NORM_ERR("Can't load configfile '%s'.", arg);
2026                                 }
2027                         } else {
2028                                 NORM_ERR("You are trying to load '%s' recursively, I'm only going to load it once to prevent an infinite loop.", arg);
2029                         }
2030                 } else {
2031                         CRIT_ERR(obj, free_at_crash, "include needs a argument");
2032                 }
2033         END OBJ(blink, 0)
2034                 if(arg) {
2035                         obj->sub = malloc(sizeof(struct text_object));
2036                         extract_variable_text_internal(obj->sub, arg);
2037                 }else{
2038                         CRIT_ERR(obj, free_at_crash, "blink needs a argument");
2039                 }
2040         END OBJ(to_bytes, 0)
2041                 if(arg) {
2042                         obj->sub = malloc(sizeof(struct text_object));
2043                         extract_variable_text_internal(obj->sub, arg);
2044                 }else{
2045                         CRIT_ERR(obj, free_at_crash, "to_bytes needs a argument");
2046                 }
2047         END OBJ(scroll, 0)
2048                 int n1 = 0, n2 = 0;
2049
2050                 obj->data.scroll.resetcolor = get_current_text_color();
2051                 obj->data.scroll.step = 1;
2052                 if (arg && sscanf(arg, "%u %n", &obj->data.scroll.show, &n1) > 0) {
2053                         sscanf(arg + n1, "%u %n", &obj->data.scroll.step, &n2);
2054                         if (*(arg + n1 + n2)) {
2055                                 n1 += n2;
2056                         } else {
2057                                 obj->data.scroll.step = 1;
2058                         }
2059                         obj->data.scroll.text = malloc(strlen(arg + n1) + obj->data.scroll.show + 1);
2060                         for(n2 = 0; (unsigned int) n2 < obj->data.scroll.show; n2++) {
2061                                 obj->data.scroll.text[n2] = ' ';
2062                         }
2063                         obj->data.scroll.text[n2] = 0;
2064                         strcat(obj->data.scroll.text, arg + n1);
2065                         obj->data.scroll.start = 0;
2066                         obj->sub = malloc(sizeof(struct text_object));
2067                         extract_variable_text_internal(obj->sub,
2068                                         obj->data.scroll.text);
2069                 } else {
2070                         CRIT_ERR(obj, free_at_crash, "scroll needs arguments: <length> [<step>] <text>");
2071                 }
2072         END OBJ(combine, 0)
2073                 if(arg) {
2074                         unsigned int i,j;
2075                         unsigned int indenting = 0;     //vars can be used as args for other vars
2076                         int startvar[2];
2077                         int endvar[2];
2078                         startvar[0] = endvar[0] = startvar[1] = endvar[1] = -1;
2079                         j=0;
2080                         for (i=0; arg[i] != 0 && j < 2; i++) {
2081                                 if(startvar[j] == -1) {
2082                                         if(arg[i] == '$') {
2083                                                 startvar[j] = i;
2084                                         }
2085                                 }else if(endvar[j] == -1) {
2086                                         if(arg[i] == '{') {
2087                                                 indenting++;
2088                                         }else if(arg[i] == '}') {
2089                                                 indenting--;
2090                                         }
2091                                         if (indenting == 0 && arg[i+1] < 48) {  //<48 has 0, $, and the most used chars not used in varnames but not { or }
2092                                                 endvar[j]=i+1;
2093                                                 j++;
2094                                         }
2095                                 }
2096                         }
2097                         if(startvar[0] >= 0 && endvar[0] >= 0 && startvar[1] >= 0 && endvar[1] >= 0) {
2098                                 obj->data.combine.left = malloc(endvar[0]-startvar[0] + 1);
2099                                 obj->data.combine.seperation = malloc(startvar[1] - endvar[0] + 1);
2100                                 obj->data.combine.right= malloc(endvar[1]-startvar[1] + 1);
2101
2102                                 strncpy(obj->data.combine.left, arg + startvar[0], endvar[0] - startvar[0]);
2103                                 obj->data.combine.left[endvar[0] - startvar[0]] = 0;
2104
2105                                 strncpy(obj->data.combine.seperation, arg + endvar[0], startvar[1] - endvar[0]);
2106                                 obj->data.combine.seperation[startvar[1] - endvar[0]] = 0;
2107
2108                                 strncpy(obj->data.combine.right, arg + startvar[1], endvar[1] - startvar[1]);
2109                                 obj->data.combine.right[endvar[1] - startvar[1]] = 0;
2110
2111                                 obj->sub = malloc(sizeof(struct text_object));
2112                                 extract_variable_text_internal(obj->sub, obj->data.combine.left);
2113                                 obj->sub->sub = malloc(sizeof(struct text_object));
2114                                 extract_variable_text_internal(obj->sub->sub, obj->data.combine.right);
2115                         } else {
2116                                 CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
2117                         }
2118                 } else {
2119                         CRIT_ERR(obj, free_at_crash, "combine needs arguments: <text1> <text2>");
2120                 }
2121 #ifdef NVIDIA
2122         END OBJ(nvidia, 0)
2123                 if (!arg) {
2124                         CRIT_ERR(obj, free_at_crash, "nvidia needs an argument\n");
2125                 } else if (set_nvidia_type(&obj->data.nvidia, arg)) {
2126                         CRIT_ERR(obj, free_at_crash, "nvidia: invalid argument"
2127                                  " specified: '%s'\n", arg);
2128                 }
2129 #endif /* NVIDIA */
2130 #ifdef APCUPSD
2131                 init_apcupsd();
2132                 END OBJ(apcupsd, CALLBACK(&update_apcupsd))
2133                         if (arg) {
2134                                 char host[64];
2135                                 int port;
2136                                 if (sscanf(arg, "%63s %d", host, &port) != 2) {
2137                                         CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
2138                                 } else {
2139                                         info.apcupsd.port = htons(port);
2140                                         strncpy(info.apcupsd.host, host, sizeof(info.apcupsd.host));
2141                                 }
2142                         } else {
2143                                 CRIT_ERR(obj, free_at_crash, "apcupsd needs arguments: <host> <port>");
2144                         }
2145                         END OBJ(apcupsd_name, CALLBACK(&update_apcupsd))
2146                         END OBJ(apcupsd_model, CALLBACK(&update_apcupsd))
2147                         END OBJ(apcupsd_upsmode, CALLBACK(&update_apcupsd))
2148                         END OBJ(apcupsd_cable, CALLBACK(&update_apcupsd))
2149                         END OBJ(apcupsd_status, CALLBACK(&update_apcupsd))
2150                         END OBJ(apcupsd_linev, CALLBACK(&update_apcupsd))
2151                         END OBJ(apcupsd_load, CALLBACK(&update_apcupsd))
2152                         END OBJ(apcupsd_loadbar, CALLBACK(&update_apcupsd))
2153                                 SIZE_DEFAULTS(bar);
2154                                 scan_bar(arg, &obj->a, &obj->b);
2155 #ifdef X11
2156                         END OBJ(apcupsd_loadgraph, CALLBACK(&update_apcupsd))
2157                                 char* buf = 0;
2158                                 SIZE_DEFAULTS(graph);
2159                                 buf = scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d,
2160                                                 &obj->e, &obj->char_a, &obj->char_b);
2161                                 if (buf) free(buf);
2162                         END OBJ(apcupsd_loadgauge, CALLBACK(&update_apcupsd))
2163                                 SIZE_DEFAULTS(gauge);
2164                                 scan_gauge(arg, &obj->a, &obj->b);
2165 #endif /* X11 */
2166                         END OBJ(apcupsd_charge, CALLBACK(&update_apcupsd))
2167                         END OBJ(apcupsd_timeleft, CALLBACK(&update_apcupsd))
2168                         END OBJ(apcupsd_temp, CALLBACK(&update_apcupsd))
2169                         END OBJ(apcupsd_lastxfer, CALLBACK(&update_apcupsd))
2170 #endif /* APCUPSD */
2171         END {
2172                 char buf[256];
2173
2174                 NORM_ERR("unknown variable %s", s);
2175                 obj->type = OBJ_text;
2176                 snprintf(buf, 256, "${%s}", s);
2177                 obj->data.s = strndup(buf, text_buffer_size);
2178         }
2179 #undef OBJ
2180
2181         return obj;
2182 }
2183
2184 /*
2185  * - assumes that *string is '#'
2186  * - removes the part from '#' to the end of line ('\n' or '\0')
2187  * - it removes the '\n'
2188  * - copies the last char into 'char *last' argument, which should be a pointer
2189  *   to a char rather than a string.
2190  */
2191 static size_t remove_comment(char *string, char *last)
2192 {
2193         char *end = string;
2194         while (*end != '\0' && *end != '\n') {
2195                 ++end;
2196         }
2197         if (last) *last = *end;
2198         if (*end == '\n') end++;
2199         strfold(string, end - string);
2200         return end - string;
2201 }
2202
2203 size_t remove_comments(char *string)
2204 {
2205         char *curplace;
2206         size_t folded = 0;
2207         for (curplace = string; *curplace != 0; curplace++) {
2208                 if (*curplace == '\\' && *(curplace + 1) == '#') {
2209                         // strcpy can't be used for overlapping strings
2210                         strfold(curplace, 1);
2211                         folded += 1;
2212                 } else if (*curplace == '#') {
2213                         folded += remove_comment(curplace, 0);
2214                 }
2215         }
2216         return folded;
2217 }
2218
2219 int extract_variable_text_internal(struct text_object *retval, const char *const_p)
2220 {
2221         struct text_object *obj;
2222         char *p, *s, *orig_p;
2223         long line;
2224         void *ifblock_opaque = NULL;
2225         char *tmp_p;
2226         char *arg = 0;
2227         size_t len = 0;
2228
2229         p = strndup(const_p, max_user_text - 1);
2230         while (text_contains_templates(p)) {
2231                 char *tmp;
2232                 tmp = find_and_replace_templates(p);
2233                 free(p);
2234                 p = tmp;
2235         }
2236         s = orig_p = p;
2237
2238         if (strcmp(p, const_p)) {
2239                 DBGP("replaced all templates in text: input is\n'%s'\noutput is\n'%s'", const_p, p);
2240         } else {
2241                 DBGP("no templates to replace");
2242         }
2243
2244         memset(retval, 0, sizeof(struct text_object));
2245
2246         line = global_text_lines;
2247
2248         while (*p) {
2249                 if (*p == '\n') {
2250                         line++;
2251                 }
2252                 if (*p == '$') {
2253                         *p = '\0';
2254                         obj = create_plain_text(s);
2255                         if (obj != NULL) {
2256                                 append_object(retval, obj);
2257                         }
2258                         *p = '$';
2259                         p++;
2260                         s = p;
2261
2262                         if (*p != '$') {
2263                                 char buf[256];
2264                                 const char *var;
2265
2266                                 /* variable is either $foo or ${foo} */
2267                                 if (*p == '{') {
2268                                         unsigned int brl = 1, brr = 0;
2269
2270                                         p++;
2271                                         s = p;
2272                                         while (*p && brl != brr) {
2273                                                 if (*p == '{') {
2274                                                         brl++;
2275                                                 }
2276                                                 if (*p == '}') {
2277                                                         brr++;
2278                                                 }
2279                                                 p++;
2280                                         }
2281                                         p--;
2282                                 } else {
2283                                         s = p;
2284                                         if (*p == '#') {
2285                                                 p++;
2286                                         }
2287                                         while (*p && (isalnum((int) *p) || *p == '_')) {
2288                                                 p++;
2289                                         }
2290                                 }
2291
2292                                 /* copy variable to buffer */
2293                                 len = (p - s > 255) ? 255 : (p - s);
2294                                 strncpy(buf, s, len);
2295                                 buf[len] = '\0';
2296
2297                                 if (*p == '}') {
2298                                         p++;
2299                                 }
2300                                 s = p;
2301
2302                                 /* search for variable in environment */
2303
2304                                 var = getenv(buf);
2305                                 if (var) {
2306                                         obj = create_plain_text(var);
2307                                         if (obj) {
2308                                                 append_object(retval, obj);
2309                                         }
2310                                         continue;
2311                                 }
2312
2313                                 /* if variable wasn't found in environment, use some special */
2314
2315                                 arg = 0;
2316
2317                                 /* split arg */
2318                                 if (strchr(buf, ' ')) {
2319                                         arg = strchr(buf, ' ');
2320                                         *arg = '\0';
2321                                         arg++;
2322                                         while (isspace((int) *arg)) {
2323                                                 arg++;
2324                                         }
2325                                         if (!*arg) {
2326                                                 arg = 0;
2327                                         }
2328                                 }
2329
2330                                 /* lowercase variable name */
2331                                 tmp_p = buf;
2332                                 while (*tmp_p) {
2333                                         *tmp_p = tolower(*tmp_p);
2334                                         tmp_p++;
2335                                 }
2336
2337                                 obj = construct_text_object(buf, arg,
2338                                                 line, &ifblock_opaque, orig_p);
2339                                 if (obj != NULL) {
2340                                         append_object(retval, obj);
2341                                 }
2342                                 continue;
2343                         } else {
2344                                 obj = create_plain_text("$");
2345                                 s = p + 1;
2346                                 if (obj != NULL) {
2347                                         append_object(retval, obj);
2348                                 }
2349                         }
2350                 } else if (*p == '\\' && *(p+1) == '#') {
2351                         strfold(p, 1);
2352                 } else if (*p == '#') {
2353                         char c;
2354                         if (remove_comment(p, &c) && p > orig_p && c == '\n') {
2355                                 /* if remove_comment removed a newline, we need to 'back up' with p */
2356                                 p--;
2357                         }
2358                 }
2359                 p++;
2360         }
2361         obj = create_plain_text(s);
2362         if (obj != NULL) {
2363                 append_object(retval, obj);
2364         }
2365
2366         if (!ifblock_stack_empty(&ifblock_opaque)) {
2367                 NORM_ERR("one or more $endif's are missing");
2368         }
2369
2370         free(orig_p);
2371         return 0;
2372 }
2373
2374 /*
2375  * Frees the list of text objects root points to.  When internal = 1, it won't
2376  * free global objects.
2377  */
2378 void free_text_objects(struct text_object *root, int internal)
2379 {
2380         struct text_object *obj;
2381
2382         if (!root->prev) {
2383                 return;
2384         }
2385
2386 #define data obj->data
2387         for (obj = root->prev; obj; obj = root->prev) {
2388                 root->prev = obj->prev;
2389                 switch (obj->type) {
2390 #ifndef __OpenBSD__
2391                         case OBJ_acpitemp:
2392                                 close(data.i);
2393                                 break;
2394 #endif /* !__OpenBSD__ */
2395 #ifdef __linux__
2396                         case OBJ_i2c:
2397                         case OBJ_platform:
2398                         case OBJ_hwmon:
2399                                 close(data.sysfs.fd);
2400                                 break;
2401 #endif /* __linux__ */
2402                         case OBJ_read_tcp:
2403                                 free(data.read_tcp.host);
2404                                 break;
2405                         case OBJ_time:
2406                         case OBJ_utime:
2407                                 free(data.s);
2408                                 break;
2409                         case OBJ_tztime:
2410                                 free(data.tztime.tz);
2411                                 free(data.tztime.fmt);
2412                                 break;
2413                         case OBJ_mboxscan:
2414                                 free(data.mboxscan.args);
2415                                 free(data.mboxscan.output);
2416                                 break;
2417                         case OBJ_mails:
2418                         case OBJ_new_mails:
2419                         case OBJ_seen_mails:
2420                         case OBJ_unseen_mails:
2421                         case OBJ_flagged_mails:
2422                         case OBJ_unflagged_mails:
2423                         case OBJ_forwarded_mails:
2424                         case OBJ_unforwarded_mails:
2425                         case OBJ_replied_mails:
2426                         case OBJ_unreplied_mails:
2427                         case OBJ_draft_mails:
2428                         case OBJ_trashed_mails:
2429                                 free(data.local_mail.mbox);
2430                                 break;
2431                         case OBJ_imap_unseen:
2432                                 if (!obj->char_b) {
2433                                         free(data.mail);
2434                                 }
2435                                 break;
2436                         case OBJ_imap_messages:
2437                                 if (!obj->char_b) {
2438                                         free(data.mail);
2439                                 }
2440                                 break;
2441                         case OBJ_pop3_unseen:
2442                                 if (!obj->char_b) {
2443                                         free(data.mail);
2444                                 }
2445                                 break;
2446                         case OBJ_pop3_used:
2447                                 if (!obj->char_b) {
2448                                         free(data.mail);
2449                                 }
2450                                 break;
2451                         case OBJ_if_empty:
2452                         case OBJ_if_match:
2453                                 free_text_objects(obj->sub, 1);
2454                                 free(obj->sub);
2455                                 /* fall through */
2456                         case OBJ_if_existing:
2457                         case OBJ_if_mounted:
2458                         case OBJ_if_running:
2459                                 free(data.ifblock.s);
2460                                 free(data.ifblock.str);
2461                                 break;
2462                         case OBJ_head:
2463                         case OBJ_tail:
2464                                 free(data.headtail.logfile);
2465                                 if(data.headtail.buffer) {
2466                                         free(data.headtail.buffer);
2467                                 }
2468                                 break;
2469                         case OBJ_text:
2470                         case OBJ_font:
2471                         case OBJ_image:
2472                         case OBJ_eval:
2473                         case OBJ_exec:
2474                         case OBJ_execbar:
2475 #ifdef X11
2476                         case OBJ_execgauge:
2477                         case OBJ_execgraph:
2478 #endif
2479                         case OBJ_execp:
2480                                 free(data.s);
2481                                 break;
2482 #ifdef HAVE_ICONV
2483                         case OBJ_iconv_start:
2484                                 free_iconv();
2485                                 break;
2486 #endif
2487 #ifdef __linux__
2488                         case OBJ_disk_protect:
2489                                 free(data.s);
2490                                 break;
2491                         case OBJ_if_gw:
2492                                 free(data.ifblock.s);
2493                                 free(data.ifblock.str);
2494                         case OBJ_gw_iface:
2495                         case OBJ_gw_ip:
2496                                 if (info.gw_info.iface) {
2497                                         free(info.gw_info.iface);
2498                                         info.gw_info.iface = 0;
2499                                 }
2500                                 if (info.gw_info.ip) {
2501                                         free(info.gw_info.ip);
2502                                         info.gw_info.ip = 0;
2503                                 }
2504                                 break;
2505                         case OBJ_ioscheduler:
2506                                 if(data.s)
2507                                         free(data.s);
2508                                 break;
2509 #endif
2510 #if (defined(__FreeBSD__) || defined(__linux__))
2511                         case OBJ_if_up:
2512                                 free(data.ifblock.s);
2513                                 free(data.ifblock.str);
2514                                 break;
2515 #endif
2516 #ifdef XMMS2
2517                         case OBJ_xmms2_artist:
2518                                 if (info.xmms2.artist) {
2519                                         free(info.xmms2.artist);
2520                                         info.xmms2.artist = 0;
2521                                 }
2522                                 break;
2523                         case OBJ_xmms2_album:
2524                                 if (info.xmms2.album) {
2525                                         free(info.xmms2.album);
2526                                         info.xmms2.album = 0;
2527                                 }
2528                                 break;
2529                         case OBJ_xmms2_title:
2530                                 if (info.xmms2.title) {
2531                                         free(info.xmms2.title);
2532                                         info.xmms2.title = 0;
2533                                 }
2534                                 break;
2535                         case OBJ_xmms2_genre:
2536                                 if (info.xmms2.genre) {
2537                                         free(info.xmms2.genre);
2538                                         info.xmms2.genre = 0;
2539                                 }
2540                                 break;
2541                         case OBJ_xmms2_comment:
2542                                 if (info.xmms2.comment) {
2543                                         free(info.xmms2.comment);
2544                                         info.xmms2.comment = 0;
2545                                 }
2546                                 break;
2547                         case OBJ_xmms2_url:
2548                                 if (info.xmms2.url) {
2549                                         free(info.xmms2.url);
2550                                         info.xmms2.url = 0;
2551                                 }
2552                                 break;
2553                         case OBJ_xmms2_date:
2554                                 if (info.xmms2.date) {
2555                                         free(info.xmms2.date);
2556                                         info.xmms2.date = 0;
2557                                 }
2558                                 break;
2559                         case OBJ_xmms2_status:
2560                                 if (info.xmms2.status) {
2561                                         free(info.xmms2.status);
2562                                         info.xmms2.status = 0;
2563                                 }
2564                                 break;
2565                         case OBJ_xmms2_playlist:
2566                                 if (info.xmms2.playlist) {
2567                                         free(info.xmms2.playlist);
2568                                         info.xmms2.playlist = 0;
2569                                 }
2570                                 break;
2571                         case OBJ_xmms2_smart:
2572                                 if (info.xmms2.artist) {
2573                                         free(info.xmms2.artist);
2574                                         info.xmms2.artist = 0;
2575                                 }
2576                                 if (info.xmms2.title) {
2577                                         free(info.xmms2.title);
2578                                         info.xmms2.title = 0;
2579                                 }
2580                                 if (info.xmms2.url) {
2581                                         free(info.xmms2.url);
2582                                         info.xmms2.url = 0;
2583                                 }
2584                                 break;
2585 #endif
2586 #ifdef BMPX
2587                         case OBJ_bmpx_title:
2588                         case OBJ_bmpx_artist:
2589                         case OBJ_bmpx_album:
2590                         case OBJ_bmpx_track:
2591                         case OBJ_bmpx_uri:
2592                         case OBJ_bmpx_bitrate:
2593                                 break;
2594 #endif
2595 #ifdef EVE
2596                         case OBJ_eve:
2597                                 break;
2598 #endif
2599 #ifdef HAVE_CURL
2600                         case OBJ_curl:
2601                                 free(data.curl.uri);
2602                                 break;
2603 #endif
2604 #ifdef RSS
2605                         case OBJ_rss:
2606                                 free(data.rss.uri);
2607                                 free(data.rss.action);
2608                                 break;
2609 #endif
2610 #ifdef WEATHER
2611                         case OBJ_weather:
2612                                 free(data.weather.uri);
2613                                 free(data.weather.data_type);
2614                                 break;
2615 #endif
2616 #ifdef XOAP
2617                         case OBJ_weather_forecast:
2618                                 free(data.weather_forecast.uri);
2619                                 free(data.weather_forecast.data_type);
2620                                 break;
2621 #endif
2622 #ifdef HAVE_LUA
2623                         case OBJ_lua:
2624                         case OBJ_lua_parse:
2625                         case OBJ_lua_bar:
2626 #ifdef X11
2627                         case OBJ_lua_graph:
2628                         case OBJ_lua_gauge:
2629 #endif /* X11 */
2630                                 free(data.s);
2631                                 break;
2632 #endif /* HAVE_LUA */
2633                         case OBJ_pre_exec:
2634                                 break;
2635 #ifndef __OpenBSD__
2636                         case OBJ_battery:
2637                                 free(data.s);
2638                                 break;
2639                         case OBJ_battery_short:
2640                                 free(data.s);
2641                                 break;
2642                         case OBJ_battery_time:
2643                                 free(data.s);
2644                                 break;
2645 #endif /* !__OpenBSD__ */
2646                         case OBJ_execpi:
2647                         case OBJ_execi:
2648                         case OBJ_execibar:
2649 #ifdef X11
2650                         case OBJ_execigraph:
2651                         case OBJ_execigauge:
2652 #endif /* X11 */
2653                                 free(data.execi.cmd);
2654                                 free(data.execi.buffer);
2655                                 break;
2656                         case OBJ_texeci:
2657                                 if (data.texeci.p_timed_thread) timed_thread_destroy(data.texeci.p_timed_thread, &data.texeci.p_timed_thread);
2658                                 free(data.texeci.cmd);
2659                                 free(data.texeci.buffer);
2660                                 break;
2661                         case OBJ_nameserver:
2662                                 free_dns_data();
2663                                 break;
2664                         case OBJ_top:
2665                         case OBJ_top_mem:
2666                         case OBJ_top_time:
2667 #ifdef IOSTATS
2668                         case OBJ_top_io:
2669 #endif
2670                                 if (info.first_process && !internal) {
2671                                         free_all_processes();
2672                                         info.first_process = NULL;
2673                                 }
2674                                 if (data.top.s) free(data.top.s);
2675                                 break;
2676 #ifdef HDDTEMP
2677                         case OBJ_hddtemp:
2678                                 if (data.s) {
2679                                         free(data.s);
2680                                         data.s = NULL;
2681                                 }
2682                                 free_hddtemp();
2683                                 break;
2684 #endif /* HDDTEMP */
2685                         case OBJ_entropy_avail:
2686                         case OBJ_entropy_perc:
2687                         case OBJ_entropy_poolsize:
2688                         case OBJ_entropy_bar:
2689                                 break;
2690                         case OBJ_user_names:
2691                                 if (info.users.names) {
2692                                         free(info.users.names);
2693                                         info.users.names = 0;
2694                                 }
2695                                 break;
2696                         case OBJ_user_terms:
2697                                 if (info.users.terms) {
2698                                         free(info.users.terms);
2699                                         info.users.terms = 0;
2700                                 }
2701                                 break;
2702                         case OBJ_user_times:
2703                                 if (info.users.times) {
2704                                         free(info.users.times);
2705                                         info.users.times = 0;
2706                                 }
2707                                 break;
2708 #ifdef IBM
2709                         case OBJ_smapi:
2710                         case OBJ_smapi_bat_perc:
2711                         case OBJ_smapi_bat_temp:
2712                         case OBJ_smapi_bat_power:
2713                                 free(data.s);
2714                                 break;
2715                         case OBJ_if_smapi_bat_installed:
2716                                 free(data.ifblock.s);
2717                                 free(data.ifblock.str);
2718                                 break;
2719 #endif /* IBM */
2720 #ifdef NVIDIA
2721                         case OBJ_nvidia:
2722                                 break;
2723 #endif /* NVIDIA */
2724 #ifdef MPD
2725                         case OBJ_mpd_title:
2726                         case OBJ_mpd_artist:
2727                         case OBJ_mpd_album:
2728                         case OBJ_mpd_random:
2729                         case OBJ_mpd_repeat:
2730                         case OBJ_mpd_vol:
2731                         case OBJ_mpd_bitrate:
2732                         case OBJ_mpd_status:
2733                         case OBJ_mpd_bar:
2734                         case OBJ_mpd_elapsed:
2735                         case OBJ_mpd_length:
2736                         case OBJ_mpd_track:
2737                         case OBJ_mpd_name:
2738                         case OBJ_mpd_file:
2739                         case OBJ_mpd_percent:
2740                         case OBJ_mpd_smart:
2741                         case OBJ_if_mpd_playing:
2742                                 free_mpd();
2743                                 break;
2744 #endif /* MPD */
2745 #ifdef MOC
2746                         case OBJ_moc_state:
2747                         case OBJ_moc_file:
2748                         case OBJ_moc_title:
2749                         case OBJ_moc_artist:
2750                         case OBJ_moc_song:
2751                         case OBJ_moc_album:
2752                         case OBJ_moc_totaltime:
2753                         case OBJ_moc_timeleft:
2754                         case OBJ_moc_curtime:
2755                         case OBJ_moc_bitrate:
2756                         case OBJ_moc_rate:
2757                                 free_moc();
2758                                 break;
2759 #endif /* MOC */
2760                         case OBJ_include:
2761                         case OBJ_blink:
2762                         case OBJ_to_bytes:
2763                                 if(obj->sub) {
2764                                         free_text_objects(obj->sub, 1);
2765                                         free(obj->sub);
2766                                 }
2767                                 break;
2768                         case OBJ_scroll:
2769                                 free(data.scroll.text);
2770                                 free_text_objects(obj->sub, 1);
2771                                 free(obj->sub);
2772                                 break;
2773                         case OBJ_combine:
2774                                 free(data.combine.left);
2775                                 free(data.combine.seperation);
2776                                 free(data.combine.right);
2777                                 free_text_objects(obj->sub, 1);
2778                                 free(obj->sub);
2779                                 break;
2780 #ifdef APCUPSD
2781                         case OBJ_apcupsd:
2782                         case OBJ_apcupsd_name:
2783                         case OBJ_apcupsd_model:
2784                         case OBJ_apcupsd_upsmode:
2785                         case OBJ_apcupsd_cable:
2786                         case OBJ_apcupsd_status:
2787                         case OBJ_apcupsd_linev:
2788                         case OBJ_apcupsd_load:
2789                         case OBJ_apcupsd_loadbar:
2790 #ifdef X11
2791                         case OBJ_apcupsd_loadgraph:
2792                         case OBJ_apcupsd_loadgauge:
2793 #endif /* X11 */
2794                         case OBJ_apcupsd_charge:
2795                         case OBJ_apcupsd_timeleft:
2796                         case OBJ_apcupsd_temp:
2797                         case OBJ_apcupsd_lastxfer:
2798                                 break;
2799 #endif /* APCUPSD */
2800 #ifdef X11
2801                         case OBJ_desktop:
2802                         case OBJ_desktop_number:
2803                         case OBJ_desktop_name:
2804                                 if(info.x11.desktop.name) {
2805                                   free(info.x11.desktop.name);
2806                                   info.x11.desktop.name = NULL;
2807                                 }
2808                                 if(info.x11.desktop.all_names) {
2809                                   free(info.x11.desktop.all_names);
2810                                   info.x11.desktop.all_names = NULL;
2811                                 }
2812                                 break;
2813 #endif /* X11 */
2814                 }
2815                 free(obj);
2816         }
2817 #undef data
2818 }
2819