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