Revert "auesnthaeou"
[monky] / src / obj_display.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  * vim: ts=4 sw=4 noet ai cindent syntax=c
29  *
30  */
31
32 /* local headers */
33 #include "obj_display.h"
34
35 //remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat"
36 //string has to end with \0 and it's length should fit in a int
37 #define BACKSPACE 8
38 void remove_deleted_chars(char *string){
39         int i = 0;
40         while(string[i] != 0){
41                 if(string[i] == BACKSPACE){
42                         if(i != 0){
43                                 strcpy( &(string[i-1]), &(string[i+1]) );
44                                 i--;
45                         }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string
46                 }else i++;
47         }
48 }
49
50 static inline void format_media_player_time(char *buf, const int size,
51                 int seconds)
52 {
53         int days, hours, minutes;
54
55         days = seconds / (24 * 60 * 60);
56         seconds %= (24 * 60 * 60);
57         hours = seconds / (60 * 60);
58         seconds %= (60 * 60);
59         minutes = seconds / 60;
60         seconds %= 60;
61
62         if (days > 0) {
63                 snprintf(buf, size, "%i days %i:%02i:%02i", days,
64                                 hours, minutes, seconds);
65         } else if (hours > 0) {
66                 snprintf(buf, size, "%i:%02i:%02i", hours, minutes,
67                                 seconds);
68         } else {
69                 snprintf(buf, size, "%i:%02i", minutes, seconds);
70         }
71 }
72
73 static inline double get_barnum(char *buf)
74 {
75         char *c = buf;
76         double barnum;
77
78         while (*c) {
79                 if (*c == '\001') {
80                         *c = ' ';
81                 }
82                 c++;
83         }
84
85         if (sscanf(buf, "%lf", &barnum) == 0) {
86                 NORM_ERR("reading exec value failed (perhaps it's not the "
87                                 "correct format?)");
88                 return -1;
89         }
90         if (barnum > 100.0 || barnum < 0.0) {
91                 NORM_ERR("your exec value is not between 0 and 100, "
92                                 "therefore it will be ignored");
93                 return -1;
94         }
95         return barnum;
96 }
97
98 char *format_time(unsigned long timeval, const int width)
99 {
100         char buf[10];
101         unsigned long nt;       // narrow time, for speed on 32-bit
102         unsigned cc;            // centiseconds
103         unsigned nn;            // multi-purpose whatever
104
105         nt = timeval;
106         cc = nt % 100;          // centiseconds past second
107         nt /= 100;                      // total seconds
108         nn = nt % 60;           // seconds past the minute
109         nt /= 60;                       // total minutes
110         if (width >= snprintf(buf, sizeof buf, "%lu:%02u.%02u",
111                                 nt, nn, cc)) {
112                 return strndup(buf, text_buffer_size);
113         }
114         if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
115                 return strndup(buf, text_buffer_size);
116         }
117         nn = nt % 60;           // minutes past the hour
118         nt /= 60;                       // total hours
119         if (width >= snprintf(buf, sizeof buf, "%lu,%02u", nt, nn)) {
120                 return strndup(buf, text_buffer_size);
121         }
122         nn = nt;                        // now also hours
123         if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
124                 return strndup(buf, text_buffer_size);
125         }
126         nn /= 24;                       // now days
127         if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
128                 return strndup(buf, text_buffer_size);
129         }
130         nn /= 7;                        // now weeks
131         if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
132                 return strndup(buf, text_buffer_size);
133         }
134         // well shoot, this outta' fit...
135         return strndup("<inf>", text_buffer_size);
136 }
137
138 /* Prints anything normally printed with snprintf according to the current value
139  * of use_spacer.  Actually slightly more flexible than snprintf, as you can
140  * safely specify the destination buffer as one of your inputs.  */
141 int spaced_print(char *buf, int size, const char *format, int width, ...)
142 {
143         int len = 0;
144         va_list argp;
145         char *tempbuf;
146
147         if (size < 1) {
148                 return 0;
149         }
150         tempbuf = malloc(size * sizeof(char));
151
152         // Passes the varargs along to vsnprintf
153         va_start(argp, width);
154         vsnprintf(tempbuf, size, format, argp);
155         va_end(argp);
156
157         switch (use_spacer) {
158                 case NO_SPACER:
159                         len = snprintf(buf, size, "%s", tempbuf);
160                         break;
161                 case LEFT_SPACER:
162                         len = snprintf(buf, size, "%*s", width, tempbuf);
163                         break;
164                 case RIGHT_SPACER:
165                         len = snprintf(buf, size, "%-*s", width, tempbuf);
166                         break;
167         }
168         free(tempbuf);
169         return len;
170 }
171
172 /* print percentage values
173  *
174  * - i.e., unsigned values between 0 and 100
175  * - respect the value of pad_percents */
176 static int percent_print(char *buf, int size, unsigned value)
177 {
178         return spaced_print(buf, size, "%u", pad_percents, value);
179 }
180
181 static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
182
183 /* converts from bytes to human readable format (K, M, G, T)
184  *
185  * The algorithm always divides by 1024, as unit-conversion of byte
186  * counts suggests. But for output length determination we need to
187  * compare with 1000 here, as we print in decimal form. */
188 static void human_readable(long long num, char *buf, int size)
189 {
190         const char **suffix = suffixes;
191         float fnum;
192         int precision;
193         int width;
194         const char *format;
195
196         /* Possibly just output as usual, for example for stdout usage */
197         if (!format_human_readable) {
198                 spaced_print(buf, size, "%d", 6, round_to_int(num));
199                 return;
200         }
201         if (short_units) {
202                 width = 5;
203                 format = "%.*f%.1s";
204         } else {
205                 width = 7;
206                 format = "%.*f%-3s";
207         }
208
209         if (llabs(num) < 1000LL) {
210                 spaced_print(buf, size, format, width, 0, (float)num, *suffix);
211                 return;
212         }
213
214         while (llabs(num / 1024) >= 1000LL && **(suffix + 2)) {
215                 num /= 1024;
216                 suffix++;
217         }
218
219         suffix++;
220         fnum = num / 1024.0;
221
222         /* fnum should now be < 1000, so looks like 'AAA.BBBBB'
223          *
224          * The goal is to always have a significance of 3, by
225          * adjusting the decimal part of the number. Sample output:
226          *  123MiB
227          * 23.4GiB
228          * 5.12B
229          * so the point of alignment resides between number and unit. The
230          * upside of this is that there is minimal padding necessary, though
231          * there should be a way to make alignment take place at the decimal
232          * dot (then with fixed width decimal part).
233          *
234          * Note the repdigits below: when given a precision value, printf()
235          * rounds the float to it, not just cuts off the remaining digits. So
236          * e.g. 99.95 with a precision of 1 gets 100.0, which again should be
237          * printed with a precision of 0. Yay. */
238
239         precision = 0;          /* print 100-999 without decimal part */
240         if (fnum < 99.95)
241                 precision = 1;  /* print 10-99 with one decimal place */
242         if (fnum < 9.995)
243                 precision = 2;  /* print 0-9 with two decimal places */
244
245         spaced_print(buf, size, format, width, precision, fnum, *suffix);
246 }
247
248 /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
249  * multiline objects like $exec work with $align[rc] and friends
250  */
251 void substitute_newlines(char *p, long l)
252 {
253         char *s = p;
254         if (l < 0) return;
255         while (p && *p && p < s + l) {
256                 if (*p == '\n') {
257                         /* only substitute if it's not the last newline */
258                         *p = SECRIT_MULTILINE_CHAR;
259                 }
260                 p++;
261         }
262 }
263
264 void evaluate(const char *text, char *buffer)
265 {
266         struct information *tmp_info;
267         struct text_object subroot;
268
269         tmp_info = malloc(sizeof(struct information));
270         memcpy(tmp_info, &ctx->info, sizeof(struct information));
271         parse_conky_vars(&subroot, text, buffer, tmp_info);
272         DBGP("evaluated '%s' to '%s'", text, buffer);
273
274         free_text_objects(&subroot, 1);
275         free(tmp_info);
276 }
277
278 void generate_text_internal(char *p, int p_max_size, struct text_object root,
279                 struct information *cur)
280 {
281         struct text_object *obj;
282 #ifdef X11
283         int need_to_load_fonts = 0;
284 #endif /* X11 */
285
286         /* for the OBJ_top* handler */
287         struct process **needed = 0;
288
289 #ifdef HAVE_ICONV
290         char buff_in[p_max_size];
291         buff_in[0] = 0;
292         set_iconv_converting(0);
293 #endif /* HAVE_ICONV */
294
295         p[0] = 0;
296         obj = root.next;
297         while (obj && p_max_size > 0) {
298                 needed = 0; /* reset for top stuff */
299
300 /* IFBLOCK jumping algorithm
301  *
302  * This is easier as it looks like:
303  * - each IF checks it's condition
304  *   - on FALSE: call DO_JUMP
305  *   - on TRUE: don't care
306  * - each ELSE calls DO_JUMP unconditionally
307  * - each ENDIF is silently being ignored
308  *
309  * Why this works:
310  * DO_JUMP overwrites the "obj" variable of the loop and sets it to the target
311  * (i.e. the corresponding ELSE or ENDIF). After that, processing for the given
312  * object can continue, free()ing stuff e.g., then the for-loop does the rest: as
313  * regularly, "obj" is being updated to point to obj->next, so object parsing
314  * continues right after the corresponding ELSE or ENDIF. This means that if we
315  * find an ELSE, it's corresponding IF must not have jumped, so we need to jump
316  * always. If we encounter an ENDIF, it's corresponding IF or ELSE has not
317  * jumped, and there is nothing to do.
318  */
319 #define DO_JUMP { \
320         DBGP2("jumping"); \
321         obj = obj->data.ifblock.next; \
322 }
323
324 #define OBJ(a) break; case OBJ_##a:
325
326                 switch (obj->type) {
327                         default:
328                                 NORM_ERR("not implemented obj type %d", obj->type);
329                         OBJ(read_tcp) {
330                                 int sock, received;
331                                 struct sockaddr_in addr;
332                                 struct hostent* he = gethostbyname(obj->data.read_tcp.host);
333                                 if(he != NULL) {
334                                         sock = socket(he->h_addrtype, SOCK_STREAM, 0);
335                                         if(sock != -1) {
336                                                 memset(&addr, 0, sizeof(addr));
337                                                 addr.sin_family = AF_INET;
338                                                 addr.sin_port = obj->data.read_tcp.port;
339                                                 memcpy(&addr.sin_addr, he->h_addr, he->h_length);
340                                                 if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr)) == 0) {
341                                                         fd_set readfds;
342                                                         struct timeval tv;
343                                                         FD_ZERO(&readfds);
344                                                         FD_SET(sock, &readfds);
345                                                         tv.tv_sec = 1;
346                                                         tv.tv_usec = 0;
347                                                         if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
348                                                                 received = recv(sock, p, p_max_size, 0);
349                                                                 p[received] = 0;
350                                                         }
351                                                         close(sock);
352                                                 } else {
353                                                         NORM_ERR("read_tcp: Couldn't create a connection");
354                                                 }
355                                         }else{
356                                                 NORM_ERR("read_tcp: Couldn't create a socket");
357                                         }
358                                 }else{
359                                         NORM_ERR("read_tcp: Problem with resolving the hostname");
360                                 }
361                         }
362 #ifndef __OpenBSD__
363                         OBJ(acpitemp) {
364                                 temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
365                         }
366 #endif /* !__OpenBSD__ */
367                         OBJ(freq) {
368                                 if (obj->a) {
369                                         obj->a = get_freq(p, p_max_size, "%.0f", 1,
370                                                         obj->data.cpu_index);
371                                 }
372                         }
373                         OBJ(freq_g) {
374                                 if (obj->a) {
375 #ifndef __OpenBSD__
376                                         obj->a = get_freq(p, p_max_size, "%'.2f", 1000,
377                                                         obj->data.cpu_index);
378 #else
379                                         /* OpenBSD has no such flag (SUSv2) */
380                                         obj->a = get_freq(p, p_max_size, "%.2f", 1000,
381                                                         obj->data.cpu_index);
382 #endif /* __OpenBSD */
383                                 }
384                         }
385 #if defined(__linux__)
386                         OBJ(voltage_mv) {
387                                 if (obj->a) {
388                                         obj->a = get_voltage(p, p_max_size, "%.0f", 1,
389                                                         obj->data.cpu_index);
390                                 }
391                         }
392                         OBJ(voltage_v) {
393                                 if (obj->a) {
394                                         obj->a = get_voltage(p, p_max_size, "%'.3f", 1000,
395                                                         obj->data.cpu_index);
396                                 }
397                         }
398
399 #ifdef HAVE_IWLIB
400                         OBJ(wireless_essid) {
401                                 snprintf(p, p_max_size, "%s", obj->data.net->essid);
402                         }
403                         OBJ(wireless_mode) {
404                                 snprintf(p, p_max_size, "%s", obj->data.net->mode);
405                         }
406                         OBJ(wireless_bitrate) {
407                                 snprintf(p, p_max_size, "%s", obj->data.net->bitrate);
408                         }
409                         OBJ(wireless_ap) {
410                                 snprintf(p, p_max_size, "%s", obj->data.net->ap);
411                         }
412                         OBJ(wireless_link_qual) {
413                                 spaced_print(p, p_max_size, "%d", 4,
414                                                 obj->data.net->link_qual);
415                         }
416                         OBJ(wireless_link_qual_max) {
417                                 spaced_print(p, p_max_size, "%d", 4,
418                                                 obj->data.net->link_qual_max);
419                         }
420                         OBJ(wireless_link_qual_perc) {
421                                 if (obj->data.net->link_qual_max > 0) {
422                                         spaced_print(p, p_max_size, "%.0f", 5,
423                                                         (double) obj->data.net->link_qual /
424                                                         obj->data.net->link_qual_max * 100);
425                                 } else {
426                                         spaced_print(p, p_max_size, "unk", 5);
427                                 }
428                         }
429                         OBJ(wireless_link_bar) {
430 #ifdef X11
431                                 if(output_methods & TO_X) {
432                                         new_bar(p, obj->a, obj->b, ((double) obj->data.net->link_qual /
433                                                 obj->data.net->link_qual_max) * 255.0);
434                                 }else{
435 #endif /* X11 */
436                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
437                                         new_bar_in_shell(p, p_max_size, ((double) obj->data.net->link_qual /
438                                                 obj->data.net->link_qual_max) * 100.0, obj->a);
439 #ifdef X11
440                                 }
441 #endif /* X11 */
442                         }
443 #endif /* HAVE_IWLIB */
444
445 #endif /* __linux__ */
446
447 #ifndef __OpenBSD__
448                         OBJ(adt746xcpu) {
449                                 get_adt746x_cpu(p, p_max_size);
450                         }
451                         OBJ(adt746xfan) {
452                                 get_adt746x_fan(p, p_max_size);
453                         }
454                         OBJ(acpifan) {
455                                 get_acpi_fan(p, p_max_size);
456                         }
457                         OBJ(acpiacadapter) {
458                                 get_acpi_ac_adapter(p, p_max_size);
459                         }
460                         OBJ(battery) {
461                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
462                         }
463                         OBJ(battery_time) {
464                                 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
465                         }
466                         OBJ(battery_percent) {
467                                 percent_print(p, p_max_size, get_battery_perct(obj->data.s));
468                         }
469                         OBJ(battery_bar) {
470 #ifdef X11
471                                 if(output_methods & TO_X) {
472                                         new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
473                                 }else{
474 #endif /* X11 */
475                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
476                                         new_bar_in_shell(p, p_max_size, get_battery_perct_bar(obj->data.s) / 2.55, obj->a);
477 #ifdef X11
478                                 }
479 #endif /* X11 */
480                         }
481                         OBJ(battery_short) {
482                                 get_battery_short_status(p, p_max_size, obj->data.s);
483                         }
484 #endif /* __OpenBSD__ */
485
486                         OBJ(buffers) {
487                                 human_readable(cur->buffers * 1024, p, 255);
488                         }
489                         OBJ(cached) {
490                                 human_readable(cur->cached * 1024, p, 255);
491                         }
492                         OBJ(cpu) {
493                                 if (obj->data.cpu_index > info.cpu_count) {
494                                         NORM_ERR("obj->data.cpu_index %i info.cpu_count %i",
495                                                         obj->data.cpu_index, info.cpu_count);
496                                         CRIT_ERR(NULL, NULL, "attempting to use more CPUs than you have!");
497                                 }
498                                 percent_print(p, p_max_size,
499                                               round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
500                         }
501 #ifdef X11
502                         OBJ(cpugauge)
503                                 new_gauge(p, obj->a, obj->b,
504                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
505 #endif /* X11 */
506                         OBJ(cpubar) {
507 #ifdef X11
508                                 if(output_methods & TO_X) {
509                                         new_bar(p, obj->a, obj->b,
510                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
511                                 }else{
512 #endif /* X11 */
513                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
514                                         new_bar_in_shell(p, p_max_size, round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100), obj->a);
515 #ifdef X11
516                                 }
517 #endif /* X11 */
518                         }
519 #ifdef X11
520                         OBJ(cpugraph) {
521                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
522                                                 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100),
523                                                 100, 1, obj->char_a, obj->char_b);
524                         }
525                         OBJ(loadgraph) {
526                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, cur->loadavg[0],
527                                                 obj->e, 1, obj->char_a, obj->char_b);
528                         }
529 #endif /* X11 */
530                         OBJ(color) {
531                                 new_fg(p, obj->data.l);
532                         }
533 #ifdef X11
534                         OBJ(color0) {
535                                 new_fg(p, color0);
536                         }
537                         OBJ(color1) {
538                                 new_fg(p, color1);
539                         }
540                         OBJ(color2) {
541                                 new_fg(p, color2);
542                         }
543                         OBJ(color3) {
544                                 new_fg(p, color3);
545                         }
546                         OBJ(color4) {
547                                 new_fg(p, color4);
548                         }
549                         OBJ(color5) {
550                                 new_fg(p, color5);
551                         }
552                         OBJ(color6) {
553                                 new_fg(p, color6);
554                         }
555                         OBJ(color7) {
556                                 new_fg(p, color7);
557                         }
558                         OBJ(color8) {
559                                 new_fg(p, color8);
560                         }
561                         OBJ(color9) {
562                                 new_fg(p, color9);
563                         }
564 #endif /* X11 */
565                         OBJ(conky_version) {
566                                 snprintf(p, p_max_size, "%s", VERSION);
567                         }
568                         OBJ(conky_build_date) {
569                                 snprintf(p, p_max_size, "%s", BUILD_DATE);
570                         }
571                         OBJ(conky_build_arch) {
572                                 snprintf(p, p_max_size, "%s", BUILD_ARCH);
573                         }
574 #if defined(__linux__)
575                         OBJ(disk_protect) {
576                                 snprintf(p, p_max_size, "%s",
577                                                 get_disk_protect_queue(obj->data.s));
578                         }
579                         OBJ(i8k_version) {
580                                 snprintf(p, p_max_size, "%s", i8k.version);
581                         }
582                         OBJ(i8k_bios) {
583                                 snprintf(p, p_max_size, "%s", i8k.bios);
584                         }
585                         OBJ(i8k_serial) {
586                                 snprintf(p, p_max_size, "%s", i8k.serial);
587                         }
588                         OBJ(i8k_cpu_temp) {
589                                 int cpu_temp;
590
591                                 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
592                                 temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
593                         }
594                         OBJ(i8k_left_fan_status) {
595                                 int left_fan_status;
596
597                                 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
598                                 if (left_fan_status == 0) {
599                                         snprintf(p, p_max_size, "off");
600                                 }
601                                 if (left_fan_status == 1) {
602                                         snprintf(p, p_max_size, "low");
603                                 }
604                                 if (left_fan_status == 2) {
605                                         snprintf(p, p_max_size, "high");
606                                 }
607                         }
608                         OBJ(i8k_right_fan_status) {
609                                 int right_fan_status;
610
611                                 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
612                                 if (right_fan_status == 0) {
613                                         snprintf(p, p_max_size, "off");
614                                 }
615                                 if (right_fan_status == 1) {
616                                         snprintf(p, p_max_size, "low");
617                                 }
618                                 if (right_fan_status == 2) {
619                                         snprintf(p, p_max_size, "high");
620                                 }
621                         }
622                         OBJ(i8k_left_fan_rpm) {
623                                 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
624                         }
625                         OBJ(i8k_right_fan_rpm) {
626                                 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
627                         }
628                         OBJ(i8k_ac_status) {
629                                 int ac_status;
630
631                                 sscanf(i8k.ac_status, "%d", &ac_status);
632                                 if (ac_status == -1) {
633                                         snprintf(p, p_max_size, "disabled (read i8k docs)");
634                                 }
635                                 if (ac_status == 0) {
636                                         snprintf(p, p_max_size, "off");
637                                 }
638                                 if (ac_status == 1) {
639                                         snprintf(p, p_max_size, "on");
640                                 }
641                         }
642                         OBJ(i8k_buttons_status) {
643                                 snprintf(p, p_max_size, "%s", i8k.buttons_status);
644                         }
645 #if defined(IBM)
646                         OBJ(ibm_fan) {
647                                 get_ibm_acpi_fan(p, p_max_size);
648                         }
649                         OBJ(ibm_temps) {
650                                 get_ibm_acpi_temps();
651                                 temp_print(p, p_max_size,
652                                            ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
653                         }
654                         OBJ(ibm_volume) {
655                                 get_ibm_acpi_volume(p, p_max_size);
656                         }
657                         OBJ(ibm_brightness) {
658                                 get_ibm_acpi_brightness(p, p_max_size);
659                         }
660 #endif /* IBM */
661                         /* information from sony_laptop kernel module
662                          * /sys/devices/platform/sony-laptop */
663                         OBJ(sony_fanspeed) {
664                                 get_sony_fanspeed(p, p_max_size);
665                         }
666                         OBJ(if_gw) {
667                                 if (!cur->gw_info.count) {
668                                         DO_JUMP;
669                                 }
670                         }
671                         OBJ(gw_iface) {
672                                 snprintf(p, p_max_size, "%s", cur->gw_info.iface);
673                         }
674                         OBJ(gw_ip) {
675                                 snprintf(p, p_max_size, "%s", cur->gw_info.ip);
676                         }
677                         OBJ(laptop_mode) {
678                                 snprintf(p, p_max_size, "%d", get_laptop_mode());
679                         }
680                         OBJ(pb_battery) {
681                                 get_powerbook_batt_info(p, p_max_size, obj->data.i);
682                         }
683 #endif /* __linux__ */
684 #if (defined(__FreeBSD__) || defined(__linux__))
685                         OBJ(if_up) {
686                                 if ((obj->data.ifblock.s)
687                                                 && (!interface_up(obj->data.ifblock.s))) {
688                                         DO_JUMP;
689                                 }
690                         }
691 #endif
692 #ifdef __OpenBSD__
693                         OBJ(obsd_sensors_temp) {
694                                 obsd_sensors.device = sensor_device;
695                                 update_obsd_sensors();
696                                 temp_print(p, p_max_size,
697                                            obsd_sensors.temp[obsd_sensors.device][obj->data.sensor],
698                                            TEMP_CELSIUS);
699                         }
700                         OBJ(obsd_sensors_fan) {
701                                 obsd_sensors.device = sensor_device;
702                                 update_obsd_sensors();
703                                 snprintf(p, p_max_size, "%d",
704                                                 obsd_sensors.fan[obsd_sensors.device][obj->data.sensor]);
705                         }
706                         OBJ(obsd_sensors_volt) {
707                                 obsd_sensors.device = sensor_device;
708                                 update_obsd_sensors();
709                                 snprintf(p, p_max_size, "%.2f",
710                                                 obsd_sensors.volt[obsd_sensors.device][obj->data.sensor]);
711                         }
712                         OBJ(obsd_vendor) {
713                                 get_obsd_vendor(p, p_max_size);
714                         }
715                         OBJ(obsd_product) {
716                                 get_obsd_product(p, p_max_size);
717                         }
718 #endif /* __OpenBSD__ */
719 #ifdef X11
720                         OBJ(font) {
721                                 new_font(p, obj->data.s);
722                                 need_to_load_fonts = 1;
723                         }
724 #endif /* X11 */
725                         /* TODO: move this correction from kB to kB/s elsewhere
726                          * (or get rid of it??) */
727                         OBJ(diskio) {
728                                 human_readable((obj->data.diskio->current / update_interval) * 1024LL,
729                                                 p, p_max_size);
730                         }
731                         OBJ(diskio_write) {
732                                 human_readable((obj->data.diskio->current_write / update_interval) * 1024LL,
733                                                 p, p_max_size);
734                         }
735                         OBJ(diskio_read) {
736                                 human_readable((obj->data.diskio->current_read / update_interval) * 1024LL,
737                                                 p, p_max_size);
738                         }
739 #ifdef X11
740                         OBJ(diskiograph) {
741                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
742                                           obj->data.diskio->current, obj->e, 1, obj->char_a, obj->char_b);
743                         }
744                         OBJ(diskiograph_read) {
745                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
746                                           obj->data.diskio->current_read, obj->e, 1, obj->char_a, obj->char_b);
747                         }
748                         OBJ(diskiograph_write) {
749                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
750                                           obj->data.diskio->current_write, obj->e, 1, obj->char_a, obj->char_b);
751                         }
752 #endif /* X11 */
753                         OBJ(downspeed) {
754                                 human_readable(obj->data.net->recv_speed, p, 255);
755                         }
756                         OBJ(downspeedf) {
757                                 spaced_print(p, p_max_size, "%.1f", 8,
758                                                 obj->data.net->recv_speed / 1024.0);
759                         }
760 #ifdef X11
761                         OBJ(downspeedgraph) {
762                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
763                                         obj->data.net->recv_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
764                         }
765 #endif /* X11 */
766                         OBJ(else) {
767                                 /* Since we see you, you're if has not jumped.
768                                  * Do Ninja jump here: without leaving traces.
769                                  * This is to prevent us from stale jumped flags.
770                                  */
771                                 obj = obj->data.ifblock.next;
772                                 continue;
773                         }
774                         OBJ(endif) {
775                                 /* harmless object, just ignore */
776                         }
777                         OBJ(addr) {
778                                 if ((obj->data.net->addr.sa_data[2] & 255) == 0
779                                                 && (obj->data.net->addr.sa_data[3] & 255) == 0
780                                                 && (obj->data.net->addr.sa_data[4] & 255) == 0
781                                                 && (obj->data.net->addr.sa_data[5] & 255) == 0) {
782                                         snprintf(p, p_max_size, "No Address");
783                                 } else {
784                                         snprintf(p, p_max_size, "%u.%u.%u.%u",
785                                                 obj->data.net->addr.sa_data[2] & 255,
786                                                 obj->data.net->addr.sa_data[3] & 255,
787                                                 obj->data.net->addr.sa_data[4] & 255,
788                                                 obj->data.net->addr.sa_data[5] & 255);
789                                 }
790                         }
791 #if defined(__linux__)
792                         OBJ(addrs) {
793                                 if (NULL != obj->data.net->addrs && strlen(obj->data.net->addrs) > 2) {
794                                         obj->data.net->addrs[strlen(obj->data.net->addrs) - 2] = 0; /* remove ", " from end of string */
795                                         strcpy(p, obj->data.net->addrs);
796                                 } else {
797                                         strcpy(p, "0.0.0.0");
798                                 }
799                         }
800 #endif /* __linux__ */
801 #if defined(IMLIB2) && defined(X11)
802                         OBJ(image) {
803                                 /* doesn't actually draw anything, just queues it omp.  the
804                                  * image will get drawn after the X event loop */
805                                 cimlib_add_image(obj->data.s);
806                         }
807 #endif /* IMLIB2 */
808                         OBJ(eval) {
809                                 evaluate(obj->data.s, p);
810                         }
811                         OBJ(exec) {
812                                 read_exec(obj->data.s, p, text_buffer_size);
813                                 remove_deleted_chars(p);
814                         }
815                         OBJ(execp) {
816                                 struct information *tmp_info;
817                                 struct text_object subroot;
818
819                                 read_exec(obj->data.s, p, text_buffer_size);
820
821                                 tmp_info = malloc(sizeof(struct information));
822                                 memcpy(tmp_info, cur, sizeof(struct information));
823                                 parse_conky_vars(&subroot, p, p, tmp_info);
824
825                                 free_text_objects(&subroot, 1);
826                                 free(tmp_info);
827                         }
828 #ifdef X11
829                         OBJ(execgauge) {
830                                 double barnum;
831
832                                 read_exec(obj->data.s, p, text_buffer_size);
833                                 barnum = get_barnum(p); /*using the same function*/
834
835                                 if (barnum >= 0.0) {
836                                         barnum /= 100;
837                                         new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
838                                 }
839                         }
840 #endif /* X11 */
841                         OBJ(execbar) {
842                                 double barnum;
843
844                                 read_exec(obj->data.s, p, text_buffer_size);
845                                 barnum = get_barnum(p);
846
847                                 if (barnum >= 0.0) {
848 #ifdef X11
849                                         if(output_methods & TO_X) {
850                                                 barnum /= 100;
851                                                 new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
852                                         }else{
853 #endif /* X11 */
854                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
855                                                 new_bar_in_shell(p, p_max_size, barnum, obj->a);
856 #ifdef X11
857                                         }
858 #endif /* X11 */
859                                 }
860                         }
861 #ifdef X11
862                         OBJ(execgraph) {
863                                 char showaslog = FALSE;
864                                 char tempgrad = FALSE;
865                                 double barnum;
866                                 char *cmd = obj->data.s;
867
868                                 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
869                                         tempgrad = TRUE;
870                                         cmd += strlen(" "TEMPGRAD);
871                                 }
872                                 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
873                                         showaslog = TRUE;
874                                         cmd += strlen(" "LOGGRAPH);
875                                 }
876                                 read_exec(cmd, p, text_buffer_size);
877                                 barnum = get_barnum(p);
878
879                                 if (barnum > 0) {
880                                         new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
881                                                         100, 1, showaslog, tempgrad);
882                                 }
883                         }
884 #endif /* X11 */
885                         OBJ(execibar) {
886                                 if (current_update_time - obj->data.execi.last_update
887                                                 >= obj->data.execi.interval) {
888                                         double barnum;
889
890                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
891                                         barnum = get_barnum(p);
892
893                                         if (barnum >= 0.0) {
894                                                 obj->f = barnum;
895                                         }
896                                         obj->data.execi.last_update = current_update_time;
897                                 }
898 #ifdef X11
899                                 if(output_methods & TO_X) {
900                                         new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
901                                 } else {
902 #endif /* X11 */
903                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
904                                         new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a);
905 #ifdef X11
906                                 }
907 #endif /* X11 */
908                         }
909 #ifdef X11
910                         OBJ(execigraph) {
911                                 if (current_update_time - obj->data.execi.last_update
912                                                 >= obj->data.execi.interval) {
913                                         double barnum;
914                                         char showaslog = FALSE;
915                                         char tempgrad = FALSE;
916                                         char *cmd = obj->data.execi.cmd;
917
918                                         if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
919                                                 tempgrad = TRUE;
920                                                 cmd += strlen(" "TEMPGRAD);
921                                         }
922                                         if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
923                                                 showaslog = TRUE;
924                                                 cmd += strlen(" "LOGGRAPH);
925                                         }
926                                         obj->char_a = showaslog;
927                                         obj->char_b = tempgrad;
928                                         read_exec(cmd, p, text_buffer_size);
929                                         barnum = get_barnum(p);
930
931                                         if (barnum >= 0.0) {
932                                                 obj->f = barnum;
933                                         }
934                                         obj->data.execi.last_update = current_update_time;
935                                 }
936                                 new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b);
937                         }
938                         OBJ(execigauge) {
939                                 if (current_update_time - obj->data.execi.last_update
940                                                 >= obj->data.execi.interval) {
941                                         double barnum;
942
943                                         read_exec(obj->data.execi.cmd, p, text_buffer_size);
944                                         barnum = get_barnum(p);
945
946                                         if (barnum >= 0.0) {
947                                                 obj->f = 255 * barnum / 100.0;
948                                         }
949                                         obj->data.execi.last_update = current_update_time;
950                                 }
951                                 new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
952                         }
953 #endif /* X11 */
954                         OBJ(execi) {
955                                 if (current_update_time - obj->data.execi.last_update
956                                                 >= obj->data.execi.interval
957                                                 && obj->data.execi.interval != 0) {
958                                         read_exec(obj->data.execi.cmd, obj->data.execi.buffer,
959                                                 text_buffer_size);
960                                         obj->data.execi.last_update = current_update_time;
961                                 }
962                                 snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
963                         }
964                         OBJ(execpi) {
965                                 struct text_object subroot;
966                                 struct information *tmp_info =
967                                         malloc(sizeof(struct information));
968                                 memcpy(tmp_info, cur, sizeof(struct information));
969
970                                 if (current_update_time - obj->data.execi.last_update
971                                                 < obj->data.execi.interval
972                                                 || obj->data.execi.interval == 0) {
973                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
974                                 } else {
975                                         char *output = obj->data.execi.buffer;
976                                         FILE *fp = pid_popen(obj->data.execi.cmd, "r", &childpid);
977                                         int length = fread(output, 1, text_buffer_size, fp);
978
979                                         pclose(fp);
980
981                                         output[length] = '\0';
982                                         if (length > 0 && output[length - 1] == '\n') {
983                                                 output[length - 1] = '\0';
984                                         }
985
986                                         parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
987                                         obj->data.execi.last_update = current_update_time;
988                                 }
989                                 free_text_objects(&subroot, 1);
990                                 free(tmp_info);
991                         }
992                         OBJ(texeci) {
993                                 if (!obj->data.texeci.p_timed_thread) {
994                                         obj->data.texeci.p_timed_thread =
995                                                 timed_thread_create(&threaded_exec,
996                                                 (void *) obj, obj->data.texeci.interval * 1000000);
997                                         if (!obj->data.texeci.p_timed_thread) {
998                                                 NORM_ERR("Error creating texeci timed thread");
999                                         }
1000                                         /*
1001                                          * note that we don't register this thread with the
1002                                          * timed_thread list, because we destroy it manually
1003                                          */
1004                                         if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
1005                                                 NORM_ERR("Error running texeci timed thread");
1006                                         }
1007                                 } else {
1008                                         timed_thread_lock(obj->data.texeci.p_timed_thread);
1009                                         snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer);
1010                                         timed_thread_unlock(obj->data.texeci.p_timed_thread);
1011                                 }
1012                         }
1013                         OBJ(imap_unseen) {
1014                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1015
1016                                 if (mail && mail->p_timed_thread) {
1017                                         timed_thread_lock(mail->p_timed_thread);
1018                                         snprintf(p, p_max_size, "%lu", mail->unseen);
1019                                         timed_thread_unlock(mail->p_timed_thread);
1020                                 }
1021                         }
1022                         OBJ(imap_messages) {
1023                                 struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap");
1024
1025                                 if (mail && mail->p_timed_thread) {
1026                                         timed_thread_lock(mail->p_timed_thread);
1027                                         snprintf(p, p_max_size, "%lu", mail->messages);
1028                                         timed_thread_unlock(mail->p_timed_thread);
1029                                 }
1030                         }
1031                         OBJ(pop3_unseen) {
1032                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1033
1034                                 if (mail && mail->p_timed_thread) {
1035                                         timed_thread_lock(mail->p_timed_thread);
1036                                         snprintf(p, p_max_size, "%lu", mail->unseen);
1037                                         timed_thread_unlock(mail->p_timed_thread);
1038                                 }
1039                         }
1040                         OBJ(pop3_used) {
1041                                 struct mail_s *mail = ensure_mail_thread(obj, pop3_thread, "pop3");
1042
1043                                 if (mail && mail->p_timed_thread) {
1044                                         timed_thread_lock(mail->p_timed_thread);
1045                                         snprintf(p, p_max_size, "%.1f",
1046                                                 mail->used / 1024.0 / 1024.0);
1047                                         timed_thread_unlock(mail->p_timed_thread);
1048                                 }
1049                         }
1050                         OBJ(fs_bar) {
1051                                 if (obj->data.fs != NULL) {
1052                                         if (obj->data.fs->size == 0) {
1053 #ifdef X11
1054                                                 if(output_methods & TO_X) {
1055                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1056                                                 }else{
1057 #endif /* X11 */
1058                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1059                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1060 #ifdef X11
1061                                                 }
1062 #endif /* X11 */
1063                                         } else {
1064 #ifdef X11
1065                                                 if(output_methods & TO_X) {
1066                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1067                                                                 (int) (255 - obj->data.fsbar.fs->avail * 255 /
1068                                                                 obj->data.fs->size));
1069                                                 }else{
1070 #endif /* X11 */
1071                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1072                                                         new_bar_in_shell(p, p_max_size,
1073                                                                 (int) (100 - obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1074 #ifdef X11
1075                                                 }
1076 #endif /* X11 */
1077                                         }
1078                                 }
1079                         }
1080                         OBJ(fs_free) {
1081                                 if (obj->data.fs != NULL) {
1082                                         human_readable(obj->data.fs->avail, p, 255);
1083                                 }
1084                         }
1085                         OBJ(fs_free_perc) {
1086                                 if (obj->data.fs != NULL) {
1087                                         int val = 0;
1088
1089                                         if (obj->data.fs->size) {
1090                                                 val = obj->data.fs->avail * 100 / obj->data.fs->size;
1091                                         }
1092
1093                                         percent_print(p, p_max_size, val);
1094                                 }
1095                         }
1096                         OBJ(fs_size) {
1097                                 if (obj->data.fs != NULL) {
1098                                         human_readable(obj->data.fs->size, p, 255);
1099                                 }
1100                         }
1101                         OBJ(fs_type) {
1102                                 if (obj->data.fs != NULL)
1103                                         snprintf(p, p_max_size, "%s", obj->data.fs->type);
1104                         }
1105                         OBJ(fs_used) {
1106                                 if (obj->data.fs != NULL) {
1107                                         human_readable(obj->data.fs->size - obj->data.fs->free, p,
1108                                                         255);
1109                                 }
1110                         }
1111                         OBJ(fs_bar_free) {
1112                                 if (obj->data.fs != NULL) {
1113                                         if (obj->data.fs->size == 0) {
1114 #ifdef X11
1115                                                 if(output_methods & TO_X) {
1116                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
1117                                                 }else{
1118 #endif /* X11 */
1119                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1120                                                         new_bar_in_shell(p, p_max_size, 100, obj->data.fsbar.w);
1121 #ifdef X11
1122                                                 }
1123 #endif /* X11 */
1124                                         } else {
1125 #ifdef X11
1126                                                 if(output_methods & TO_X) {
1127                                                         new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h,
1128                                                                 (int) (obj->data.fsbar.fs->avail * 255 /
1129                                                                 obj->data.fs->size));
1130                                                 }else{
1131 #endif /* X11 */
1132                                                         if(!obj->data.fsbar.w) obj->data.fsbar.w = DEFAULT_BAR_WIDTH_NO_X;
1133                                                         new_bar_in_shell(p, p_max_size,
1134                                                                 (int) (obj->data.fsbar.fs->avail * 100 / obj->data.fs->size), obj->data.fsbar.w);
1135 #ifdef X11
1136                                                 }
1137 #endif /* X11 */
1138                                         }
1139                                 }
1140                         }
1141                         OBJ(fs_used_perc) {
1142                                 if (obj->data.fs != NULL) {
1143                                         int val = 0;
1144
1145                                         if (obj->data.fs->size) {
1146                                                 val = obj->data.fs->free
1147                                                                 * 100 /
1148                                                         obj->data.fs->size;
1149                                         }
1150
1151                                         percent_print(p, p_max_size, 100 - val);
1152                                 }
1153                         }
1154                         OBJ(loadavg) {
1155                                 float *v = info.loadavg;
1156
1157                                 if (obj->data.loadavg[2]) {
1158                                         snprintf(p, p_max_size, "%.2f %.2f %.2f",
1159                                                 v[obj->data.loadavg[0] - 1],
1160                                                 v[obj->data.loadavg[1] - 1],
1161                                                 v[obj->data.loadavg[2] - 1]);
1162                                 } else if (obj->data.loadavg[1]) {
1163                                         snprintf(p, p_max_size, "%.2f %.2f",
1164                                                 v[obj->data.loadavg[0] - 1],
1165                                                 v[obj->data.loadavg[1] - 1]);
1166                                 } else if (obj->data.loadavg[0]) {
1167                                         snprintf(p, p_max_size, "%.2f",
1168                                                 v[obj->data.loadavg[0] - 1]);
1169                                 }
1170                         }
1171                         OBJ(goto) {
1172                                 new_goto(p, obj->data.i);
1173                         }
1174                         OBJ(tab) {
1175                                 new_tab(p, obj->data.pair.a, obj->data.pair.b);
1176                         }
1177 #ifdef X11
1178                         OBJ(hr) {
1179                                 new_hr(p, obj->data.i);
1180                         }
1181 #endif
1182                         OBJ(nameserver) {
1183                                 if (cur->nameserver_info.nscount > obj->data.i)
1184                                         snprintf(p, p_max_size, "%s",
1185                                                         cur->nameserver_info.ns_list[obj->data.i]);
1186                         }
1187 #ifdef EVE
1188                         OBJ(eve) {
1189                                 char *skill = eve(obj->data.eve.userid, obj->data.eve.apikey, obj->data.eve.charid);
1190                                 snprintf(p, p_max_size, "%s", skill);
1191                         }
1192 #endif
1193 #ifdef HAVE_CURL
1194                         OBJ(curl) {
1195                                 if (obj->data.curl.uri != NULL) {
1196                                         ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval);
1197                                 } else {
1198                                         NORM_ERR("error processing Curl data");
1199                                 }
1200                         }
1201 #endif
1202 #ifdef RSS
1203                         OBJ(rss) {
1204                                 if (obj->data.rss.uri != NULL) {
1205                                         rss_process_info(p, p_max_size, obj->data.rss.uri, obj->data.rss.action, obj->data.rss.act_par, obj->data.rss.interval, obj->data.rss.nrspaces);
1206                                 } else {
1207                                         NORM_ERR("error processing RSS data");
1208                                 }
1209                         }
1210 #endif
1211 #ifdef WEATHER
1212                         OBJ(weather) {
1213                                 if (obj->data.weather.uri != NULL) {
1214                                         weather_process_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
1215                                 } else {
1216                                         NORM_ERR("error processing weather data, check that you have a valid XOAP key if using XOAP.");
1217                                 }
1218                         }
1219 #endif
1220 #ifdef XOAP
1221                         OBJ(weather_forecast) {
1222                                 if (obj->data.weather_forecast.uri != NULL) {
1223                                         weather_forecast_process_info(p, p_max_size, obj->data.weather_forecast.uri, obj->data.weather_forecast.day, obj->data.weather_forecast.data_type, obj->data.weather_forecast.interval);
1224                                 } else {
1225                                         NORM_ERR("error processing weather forecast data, check that you have a valid XOAP key if using XOAP.");
1226                                 }
1227                         }
1228 #endif
1229 #ifdef HAVE_LUA
1230                         OBJ(lua) {
1231                                 char *str = llua_getstring(obj->data.s);
1232                                 if (str) {
1233                                         snprintf(p, p_max_size, "%s", str);
1234                                         free(str);
1235                                 }
1236                         }
1237                         OBJ(lua_parse) {
1238                                 char *str = llua_getstring(obj->data.s);
1239                                 if (str) {
1240                                         evaluate(str, p);
1241                                         free(str);
1242                                 }
1243                         }
1244                         OBJ(lua_bar) {
1245                                 double per;
1246                                 if (llua_getnumber(obj->data.s, &per)) {
1247 #ifdef X11
1248                                         if(output_methods & TO_X) {
1249                                                 new_bar(p, obj->a, obj->b, (per/100.0 * 255));
1250                                         } else {
1251 #endif /* X11 */
1252                                                 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1253                                                 new_bar_in_shell(p, p_max_size, per, obj->a);
1254 #ifdef X11
1255                                         }
1256 #endif /* X11 */
1257                                 }
1258                         }
1259 #ifdef X11
1260                         OBJ(lua_graph) {
1261                                 double per;
1262                                 if (llua_getnumber(obj->data.s, &per)) {
1263                                         new_graph(p, obj->a, obj->b, obj->c, obj->d,
1264                                                         per, obj->e, 1, obj->char_a, obj->char_b);
1265                                 }
1266                         }
1267                         OBJ(lua_gauge) {
1268                                 double per;
1269                                 if (llua_getnumber(obj->data.s, &per)) {
1270                                         new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
1271                                 }
1272                         }
1273 #endif /* X11 */
1274 #endif /* HAVE_LUA */
1275 #ifdef HDDTEMP
1276                         OBJ(hddtemp) {
1277                                 char *endptr, unit;
1278                                 long val;
1279                                 if (obj->data.hddtemp.update_time < current_update_time - 30) {
1280                                         if (obj->data.hddtemp.temp)
1281                                                 free(obj->data.hddtemp.temp);
1282                                         obj->data.hddtemp.temp = get_hddtemp_info(obj->data.hddtemp.dev,
1283                                                         obj->data.hddtemp.addr, obj->data.hddtemp.port);
1284                                         obj->data.hddtemp.update_time = current_update_time;
1285                                 }
1286                                 if (!obj->data.hddtemp.temp) {
1287                                         snprintf(p, p_max_size, "N/A");
1288                                 } else {
1289                                         val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
1290                                         unit = obj->data.hddtemp.temp[0];
1291
1292                                         if (*endptr != '\0')
1293                                                 snprintf(p, p_max_size, "N/A");
1294                                         else if (unit == 'C')
1295                                                 temp_print(p, p_max_size, (double)val, TEMP_CELSIUS);
1296                                         else if (unit == 'F')
1297                                                 temp_print(p, p_max_size, (double)val, TEMP_FAHRENHEIT);
1298                                         else
1299                                                 snprintf(p, p_max_size, "N/A");
1300                                 }
1301                         }
1302 #endif
1303                         OBJ(offset) {
1304                                 new_offset(p, obj->data.i);
1305                         }
1306                         OBJ(voffset) {
1307                                 new_voffset(p, obj->data.i);
1308                         }
1309 #ifdef __linux__
1310                         OBJ(i2c) {
1311                                 double r;
1312
1313                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1314                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
1315
1316                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1317
1318                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1319                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
1320                                 } else if (r >= 100.0 || r == 0) {
1321                                         snprintf(p, p_max_size, "%d", (int) r);
1322                                 } else {
1323                                         snprintf(p, p_max_size, "%.1f", r);
1324                                 }
1325                         }
1326                         OBJ(platform) {
1327                                 double r;
1328
1329                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1330                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
1331
1332                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1333
1334                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1335                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
1336                                 } else if (r >= 100.0 || r == 0) {
1337                                         snprintf(p, p_max_size, "%d", (int) r);
1338                                 } else {
1339                                         snprintf(p, p_max_size, "%.1f", r);
1340                                 }
1341                         }
1342                         OBJ(hwmon) {
1343                                 double r;
1344
1345                                 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1346                                         obj->data.sysfs.devtype, obj->data.sysfs.type);
1347
1348                                 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
1349
1350                                 if (!strncmp(obj->data.sysfs.type, "temp", 4)) {
1351                                         temp_print(p, p_max_size, r, TEMP_CELSIUS);
1352                                 } else if (r >= 100.0 || r == 0) {
1353                                         snprintf(p, p_max_size, "%d", (int) r);
1354                                 } else {
1355                                         snprintf(p, p_max_size, "%.1f", r);
1356                                 }
1357                         }
1358 #endif /* __linux__ */
1359                         OBJ(alignr) {
1360                                 new_alignr(p, obj->data.i);
1361                         }
1362                         OBJ(alignc) {
1363                                 new_alignc(p, obj->data.i);
1364                         }
1365                         OBJ(if_empty) {
1366                                 char buf[max_user_text];
1367                                 struct information *tmp_info =
1368                                         malloc(sizeof(struct information));
1369                                 memcpy(tmp_info, cur, sizeof(struct information));
1370                                 generate_text_internal(buf, max_user_text,
1371                                                        *obj->sub, tmp_info);
1372
1373                                 if (strlen(buf) != 0) {
1374                                         DO_JUMP;
1375                                 }
1376                                 free(tmp_info);
1377                         }
1378                         OBJ(if_match) {
1379                                 char expression[max_user_text];
1380                                 int val;
1381                                 struct information *tmp_info;
1382
1383                                 tmp_info = malloc(sizeof(struct information));
1384                                 memcpy(tmp_info, cur, sizeof(struct information));
1385                                 generate_text_internal(expression, max_user_text,
1386                                                        *obj->sub, tmp_info);
1387                                 DBGP("parsed arg into '%s'", expression);
1388
1389                                 val = compare(expression);
1390                                 if (val == -2) {
1391                                         NORM_ERR("compare failed for expression '%s'",
1392                                                         expression);
1393                                 } else if (!val) {
1394                                         DO_JUMP;
1395                                 }
1396                                 free(tmp_info);
1397                         }
1398                         OBJ(if_existing) {
1399                                 if (obj->data.ifblock.str
1400                                     && !check_contains(obj->data.ifblock.s,
1401                                                        obj->data.ifblock.str)) {
1402                                         DO_JUMP;
1403                                 } else if (obj->data.ifblock.s
1404                                            && access(obj->data.ifblock.s, F_OK)) {
1405                                         DO_JUMP;
1406                                 }
1407                         }
1408                         OBJ(if_mounted) {
1409                                 if ((obj->data.ifblock.s)
1410                                                 && (!check_mount(obj->data.ifblock.s))) {
1411                                         DO_JUMP;
1412                                 }
1413                         }
1414                         OBJ(if_running) {
1415 #ifdef __linux__
1416                                 if (!get_process_by_name(obj->data.ifblock.s)) {
1417 #else
1418                                 if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
1419 #endif
1420                                         DO_JUMP;
1421                                 }
1422                         }
1423 #if defined(__linux__)
1424                         OBJ(ioscheduler) {
1425                                 snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
1426                         }
1427 #endif
1428                         OBJ(kernel) {
1429                                 snprintf(p, p_max_size, "%s", cur->uname_s.release);
1430                         }
1431                         OBJ(machine) {
1432                                 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
1433                         }
1434
1435                         /* memory stuff */
1436                         OBJ(mem) {
1437                                 human_readable(cur->mem * 1024, p, 255);
1438                         }
1439                         OBJ(memeasyfree) {
1440                                 human_readable(cur->memeasyfree * 1024, p, 255);
1441                         }
1442                         OBJ(memfree) {
1443                                 human_readable(cur->memfree * 1024, p, 255);
1444                         }
1445                         OBJ(memmax) {
1446                                 human_readable(cur->memmax * 1024, p, 255);
1447                         }
1448                         OBJ(memperc) {
1449                                 if (cur->memmax)
1450                                         percent_print(p, p_max_size, cur->mem * 100 / cur->memmax);
1451                         }
1452 #ifdef X11
1453                         OBJ(memgauge){
1454                                 new_gauge(p, obj->data.pair.a, obj->data.pair.b,
1455                                         cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
1456                         }
1457 #endif /* X11 */
1458                         OBJ(membar) {
1459 #ifdef X11
1460                                 if(output_methods & TO_X) {
1461                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
1462                                                 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
1463                                 }else{
1464 #endif /* X11 */
1465                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1466                                         new_bar_in_shell(p, p_max_size, cur->memmax ? (cur->mem * 100) / (cur->memmax) : 0, obj->data.pair.a);
1467 #ifdef X11
1468                                 }
1469 #endif /* X11 */
1470                         }
1471 #ifdef X11
1472                         OBJ(memgraph) {
1473                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1474                                         cur->memmax ? (cur->mem * 100.0) / (cur->memmax) : 0.0,
1475                                         100, 1, obj->char_a, obj->char_b);
1476                         }
1477 #endif /* X11 */
1478                         /* mixer stuff */
1479                         OBJ(mixer) {
1480                                 percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
1481                         }
1482                         OBJ(mixerl) {
1483                                 percent_print(p, p_max_size, mixer_get_left(obj->data.l));
1484                         }
1485                         OBJ(mixerr) {
1486                                 percent_print(p, p_max_size, mixer_get_right(obj->data.l));
1487                         }
1488 #ifdef X11
1489                         OBJ(mixerbar) {
1490                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1491                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_avg(obj->data.mixerbar.l)));
1492                         }
1493                         OBJ(mixerlbar) {
1494                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1495                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_left(obj->data.mixerbar.l)));
1496                         }
1497                         OBJ(mixerrbar) {
1498                                 new_bar(p, obj->data.mixerbar.w, obj->data.mixerbar.h,
1499                                         mixer_to_255(obj->data.mixerbar.l,mixer_get_right(obj->data.mixerbar.l)));
1500                         }
1501 #endif /* X11 */
1502                         OBJ(if_mixer_mute) {
1503                                 if (!mixer_is_mute(obj->data.ifblock.i)) {
1504                                         DO_JUMP;
1505                                 }
1506                         }
1507 #ifdef X11
1508 #define NOT_IN_X "Not running in X"
1509                         OBJ(monitor) {
1510                                 if(x_initialised != YES) {
1511                                         strncpy(p, NOT_IN_X, p_max_size);
1512                                 }else{
1513                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
1514                                 }
1515                         }
1516                         OBJ(monitor_number) {
1517                                 if(x_initialised != YES) {
1518                                         strncpy(p, NOT_IN_X, p_max_size);
1519                                 }else{
1520                                         snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
1521                                 }
1522                         }
1523                         OBJ(desktop) {
1524                                 if(x_initialised != YES) {
1525                                         strncpy(p, NOT_IN_X, p_max_size);
1526                                 }else{
1527                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
1528                                 }
1529                         }
1530                         OBJ(desktop_number) {
1531                                 if(x_initialised != YES) {
1532                                         strncpy(p, NOT_IN_X, p_max_size);
1533                                 }else{
1534                                         snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
1535                                 }
1536                         }
1537                         OBJ(desktop_name) {
1538                                 if(x_initialised != YES) {
1539                                         strncpy(p, NOT_IN_X, p_max_size);
1540                                 }else if(cur->x11.desktop.name != NULL) {
1541                                         strncpy(p, cur->x11.desktop.name, p_max_size);
1542                                 }
1543                         }
1544 #endif /* X11 */
1545
1546                         /* mail stuff */
1547                         OBJ(mails) {
1548                                 update_mail_count(&obj->data.local_mail);
1549                                 snprintf(p, p_max_size, "%d", obj->data.local_mail.mail_count);
1550                         }
1551                         OBJ(new_mails) {
1552                                 update_mail_count(&obj->data.local_mail);
1553                                 snprintf(p, p_max_size, "%d",
1554                                         obj->data.local_mail.new_mail_count);
1555                         }
1556                         OBJ(seen_mails) {
1557                                 update_mail_count(&obj->data.local_mail);
1558                                 snprintf(p, p_max_size, "%d",
1559                                         obj->data.local_mail.seen_mail_count);
1560                         }
1561                         OBJ(unseen_mails) {
1562                                 update_mail_count(&obj->data.local_mail);
1563                                 snprintf(p, p_max_size, "%d",
1564                                         obj->data.local_mail.unseen_mail_count);
1565                         }
1566                         OBJ(flagged_mails) {
1567                                 update_mail_count(&obj->data.local_mail);
1568                                 snprintf(p, p_max_size, "%d",
1569                                         obj->data.local_mail.flagged_mail_count);
1570                         }
1571                         OBJ(unflagged_mails) {
1572                                 update_mail_count(&obj->data.local_mail);
1573                                 snprintf(p, p_max_size, "%d",
1574                                         obj->data.local_mail.unflagged_mail_count);
1575                         }
1576                         OBJ(forwarded_mails) {
1577                                 update_mail_count(&obj->data.local_mail);
1578                                 snprintf(p, p_max_size, "%d",
1579                                         obj->data.local_mail.forwarded_mail_count);
1580                         }
1581                         OBJ(unforwarded_mails) {
1582                                 update_mail_count(&obj->data.local_mail);
1583                                 snprintf(p, p_max_size, "%d",
1584                                         obj->data.local_mail.unforwarded_mail_count);
1585                         }
1586                         OBJ(replied_mails) {
1587                                 update_mail_count(&obj->data.local_mail);
1588                                 snprintf(p, p_max_size, "%d",
1589                                         obj->data.local_mail.replied_mail_count);
1590                         }
1591                         OBJ(unreplied_mails) {
1592                                 update_mail_count(&obj->data.local_mail);
1593                                 snprintf(p, p_max_size, "%d",
1594                                         obj->data.local_mail.unreplied_mail_count);
1595                         }
1596                         OBJ(draft_mails) {
1597                                 update_mail_count(&obj->data.local_mail);
1598                                 snprintf(p, p_max_size, "%d",
1599                                         obj->data.local_mail.draft_mail_count);
1600                         }
1601                         OBJ(trashed_mails) {
1602                                 update_mail_count(&obj->data.local_mail);
1603                                 snprintf(p, p_max_size, "%d",
1604                                         obj->data.local_mail.trashed_mail_count);
1605                         }
1606                         OBJ(mboxscan) {
1607                                 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
1608                                         text_buffer_size);
1609                                 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
1610                         }
1611                         OBJ(nodename) {
1612                                 snprintf(p, p_max_size, "%s", cur->uname_s.nodename);
1613                         }
1614                         OBJ(outlinecolor) {
1615                                 new_outline(p, obj->data.l);
1616                         }
1617                         OBJ(processes) {
1618                                 spaced_print(p, p_max_size, "%hu", 4, cur->procs);
1619                         }
1620                         OBJ(running_processes) {
1621                                 spaced_print(p, p_max_size, "%hu", 4, cur->run_procs);
1622                         }
1623                         OBJ(text) {
1624                                 snprintf(p, p_max_size, "%s", obj->data.s);
1625                         }
1626 #ifdef X11
1627                         OBJ(shadecolor) {
1628                                 new_bg(p, obj->data.l);
1629                         }
1630                         OBJ(stippled_hr) {
1631                                 new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
1632                         }
1633 #endif /* X11 */
1634                         OBJ(swap) {
1635                                 human_readable(cur->swap * 1024, p, 255);
1636                         }
1637                         OBJ(swapfree) {
1638                                 human_readable(cur->swapfree * 1024, p, 255);
1639                         }
1640                         OBJ(swapmax) {
1641                                 human_readable(cur->swapmax * 1024, p, 255);
1642                         }
1643                         OBJ(swapperc) {
1644                                 if (cur->swapmax == 0) {
1645                                         strncpy(p, "No swap", p_max_size);
1646                                 } else {
1647                                         percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
1648                                 }
1649                         }
1650                         OBJ(swapbar) {
1651 #ifdef X11
1652                                 if(output_methods & TO_X) {
1653                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
1654                                                 cur->swapmax ? (cur->swap * 255) / (cur->swapmax) : 0);
1655                                 }else{
1656 #endif /* X11 */
1657                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1658                                         new_bar_in_shell(p, p_max_size, cur->swapmax ? (cur->swap * 100) / (cur->swapmax) : 0, obj->data.pair.a);
1659 #ifdef X11
1660                                 }
1661 #endif /* X11 */
1662                         }
1663                         OBJ(sysname) {
1664                                 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
1665                         }
1666                         OBJ(time) {
1667                                 time_t t = time(NULL);
1668                                 struct tm *tm = localtime(&t);
1669
1670                                 setlocale(LC_TIME, "");
1671                                 strftime(p, p_max_size, obj->data.s, tm);
1672                         }
1673                         OBJ(utime) {
1674                                 time_t t = time(NULL);
1675                                 struct tm *tm = gmtime(&t);
1676
1677                                 strftime(p, p_max_size, obj->data.s, tm);
1678                         }
1679                         OBJ(tztime) {
1680                                 char *oldTZ = NULL;
1681                                 time_t t;
1682                                 struct tm *tm;
1683
1684                                 if (obj->data.tztime.tz) {
1685                                         oldTZ = getenv("TZ");
1686                                         setenv("TZ", obj->data.tztime.tz, 1);
1687                                         tzset();
1688                                 }
1689                                 t = time(NULL);
1690                                 tm = localtime(&t);
1691
1692                                 setlocale(LC_TIME, "");
1693                                 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
1694                                 if (oldTZ) {
1695                                         setenv("TZ", oldTZ, 1);
1696                                         tzset();
1697                                 } else {
1698                                         unsetenv("TZ");
1699                                 }
1700                                 // Needless to free oldTZ since getenv gives ptr to static data
1701                         }
1702                         OBJ(totaldown) {
1703                                 human_readable(obj->data.net->recv, p, 255);
1704                         }
1705                         OBJ(totalup) {
1706                                 human_readable(obj->data.net->trans, p, 255);
1707                         }
1708                         OBJ(updates) {
1709                                 snprintf(p, p_max_size, "%d", total_updates);
1710                         }
1711                         OBJ(if_updatenr) {
1712                                 if(total_updates % updatereset != obj->data.ifblock.i - 1) {
1713                                         DO_JUMP;
1714                                 }
1715                         }
1716                         OBJ(upspeed) {
1717                                 human_readable(obj->data.net->trans_speed, p, 255);
1718                         }
1719                         OBJ(upspeedf) {
1720                                 spaced_print(p, p_max_size, "%.1f", 8,
1721                                         obj->data.net->trans_speed / 1024.0);
1722                         }
1723 #ifdef X11
1724                         OBJ(upspeedgraph) {
1725                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
1726                                         obj->data.net->trans_speed / 1024.0, obj->e, 1, obj->char_a, obj->char_b);
1727                         }
1728 #endif /* X11 */
1729                         OBJ(uptime_short) {
1730                                 format_seconds_short(p, p_max_size, (int) cur->uptime);
1731                         }
1732                         OBJ(uptime) {
1733                                 format_seconds(p, p_max_size, (int) cur->uptime);
1734                         }
1735                         OBJ(user_names) {
1736                                 snprintf(p, p_max_size, "%s", cur->users.names);
1737                         }
1738                         OBJ(user_terms) {
1739                                 snprintf(p, p_max_size, "%s", cur->users.terms);
1740                         }
1741                         OBJ(user_times) {
1742                                 snprintf(p, p_max_size, "%s", cur->users.times);
1743                         }
1744                         OBJ(user_number) {
1745                                 snprintf(p, p_max_size, "%d", cur->users.number);
1746                         }
1747 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
1748                 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
1749                         OBJ(apm_adapter) {
1750                                 char *msg;
1751
1752                                 msg = get_apm_adapter();
1753                                 snprintf(p, p_max_size, "%s", msg);
1754                                 free(msg);
1755                         }
1756                         OBJ(apm_battery_life) {
1757                                 char *msg;
1758
1759                                 msg = get_apm_battery_life();
1760                                 snprintf(p, p_max_size, "%s", msg);
1761                                 free(msg);
1762                         }
1763                         OBJ(apm_battery_time) {
1764                                 char *msg;
1765
1766                                 msg = get_apm_battery_time();
1767                                 snprintf(p, p_max_size, "%s", msg);
1768                                 free(msg);
1769                         }
1770 #endif /* __FreeBSD__ __OpenBSD__ */
1771
1772 #ifdef MPD
1773 #define mpd_printf(fmt, val) \
1774         snprintf(p, p_max_size, fmt, mpd_get_info()->val)
1775 #define mpd_sprintf(val) { \
1776         if (!obj->data.i || obj->data.i > p_max_size) \
1777                 mpd_printf("%s", val); \
1778         else \
1779                 snprintf(p, obj->data.i, "%s", mpd_get_info()->val); \
1780 }
1781                         OBJ(mpd_title)
1782                                 mpd_sprintf(title);
1783                         OBJ(mpd_artist)
1784                                 mpd_sprintf(artist);
1785                         OBJ(mpd_album)
1786                                 mpd_sprintf(album);
1787                         OBJ(mpd_random)
1788                                 mpd_printf("%s", random);
1789                         OBJ(mpd_repeat)
1790                                 mpd_printf("%s", repeat);
1791                         OBJ(mpd_track)
1792                                 mpd_sprintf(track);
1793                         OBJ(mpd_name)
1794                                 mpd_sprintf(name);
1795                         OBJ(mpd_file)
1796                                 mpd_sprintf(file);
1797                         OBJ(mpd_vol)
1798                                 mpd_printf("%d", volume);
1799                         OBJ(mpd_bitrate)
1800                                 mpd_printf("%d", bitrate);
1801                         OBJ(mpd_status)
1802                                 mpd_printf("%s", status);
1803                         OBJ(mpd_elapsed) {
1804                                 format_media_player_time(p, p_max_size, mpd_get_info()->elapsed);
1805                         }
1806                         OBJ(mpd_length) {
1807                                 format_media_player_time(p, p_max_size, mpd_get_info()->length);
1808                         }
1809                         OBJ(mpd_percent) {
1810                                 percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
1811                         }
1812                         OBJ(mpd_bar) {
1813 #ifdef X11
1814                                 if(output_methods & TO_X) {
1815                                         new_bar(p, obj->data.pair.a, obj->data.pair.b,
1816                                                 (int) (mpd_get_info()->progress * 255.0f));
1817                                 } else {
1818 #endif /* X11 */
1819                                         if(!obj->data.pair.a) obj->data.pair.a = DEFAULT_BAR_WIDTH_NO_X;
1820                                         new_bar_in_shell(p, p_max_size, (int) (mpd_get_info()->progress * 100.0f), obj->data.pair.a);
1821 #ifdef X11
1822                                 }
1823 #endif /* X11 */
1824                         }
1825                         OBJ(mpd_smart) {
1826                                 struct mpd_s *mpd = mpd_get_info();
1827                                 int len = obj->data.i;
1828                                 if (len == 0 || len > p_max_size)
1829                                         len = p_max_size;
1830
1831                                 memset(p, 0, p_max_size);
1832                                 if (mpd->artist && *mpd->artist &&
1833                                     mpd->title && *mpd->title) {
1834                                         snprintf(p, len, "%s - %s", mpd->artist,
1835                                                 mpd->title);
1836                                 } else if (mpd->title && *mpd->title) {
1837                                         snprintf(p, len, "%s", mpd->title);
1838                                 } else if (mpd->artist && *mpd->artist) {
1839                                         snprintf(p, len, "%s", mpd->artist);
1840                                 } else if (mpd->file && *mpd->file) {
1841                                         snprintf(p, len, "%s", mpd->file);
1842                                 } else {
1843                                         *p = 0;
1844                                 }
1845                         }
1846                         OBJ(if_mpd_playing) {
1847                                 if (!mpd_get_info()->is_playing) {
1848                                         DO_JUMP;
1849                                 }
1850                         }
1851 #undef mpd_sprintf
1852 #undef mpd_printf
1853 #endif
1854
1855 #ifdef MOC
1856 #define MOC_PRINT(t, a) \
1857         snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
1858                         OBJ(moc_state) {
1859                                 MOC_PRINT(state, "??");
1860                         }
1861                         OBJ(moc_file) {
1862                                 MOC_PRINT(file, "no file");
1863                         }
1864                         OBJ(moc_title) {
1865                                 MOC_PRINT(title, "no title");
1866                         }
1867                         OBJ(moc_artist) {
1868                                 MOC_PRINT(artist, "no artist");
1869                         }
1870                         OBJ(moc_song) {
1871                                 MOC_PRINT(song, "no song");
1872                         }
1873                         OBJ(moc_album) {
1874                                 MOC_PRINT(album, "no album");
1875                         }
1876                         OBJ(moc_totaltime) {
1877                                 MOC_PRINT(totaltime, "0:00");
1878                         }
1879                         OBJ(moc_timeleft) {
1880                                 MOC_PRINT(timeleft, "0:00");
1881                         }
1882                         OBJ(moc_curtime) {
1883                                 MOC_PRINT(curtime, "0:00");
1884                         }
1885                         OBJ(moc_bitrate) {
1886                                 MOC_PRINT(bitrate, "0Kbps");
1887                         }
1888                         OBJ(moc_rate) {
1889                                 MOC_PRINT(rate, "0KHz");
1890                         }
1891 #undef MOC_PRINT
1892 #endif /* MOC */
1893 #ifdef XMMS2
1894                         OBJ(xmms2_artist) {
1895                                 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
1896                         }
1897                         OBJ(xmms2_album) {
1898                                 snprintf(p, p_max_size, "%s", cur->xmms2.album);
1899                         }
1900                         OBJ(xmms2_title) {
1901                                 snprintf(p, p_max_size, "%s", cur->xmms2.title);
1902                         }
1903                         OBJ(xmms2_genre) {
1904                                 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
1905                         }
1906                         OBJ(xmms2_comment) {
1907                                 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
1908                         }
1909                         OBJ(xmms2_url) {
1910                                 snprintf(p, p_max_size, "%s", cur->xmms2.url);
1911                         }
1912                         OBJ(xmms2_status) {
1913                                 snprintf(p, p_max_size, "%s", cur->xmms2.status);
1914                         }
1915                         OBJ(xmms2_date) {
1916                                 snprintf(p, p_max_size, "%s", cur->xmms2.date);
1917                         }
1918                         OBJ(xmms2_tracknr) {
1919                                 if (cur->xmms2.tracknr != -1) {
1920                                         snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
1921                                 }
1922                         }
1923                         OBJ(xmms2_bitrate) {
1924                                 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
1925                         }
1926                         OBJ(xmms2_id) {
1927                                 snprintf(p, p_max_size, "%u", cur->xmms2.id);
1928                         }
1929                         OBJ(xmms2_size) {
1930                                 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
1931                         }
1932                         OBJ(xmms2_elapsed) {
1933                                 snprintf(p, p_max_size, "%02d:%02d", cur->xmms2.elapsed / 60000,
1934                                         (cur->xmms2.elapsed / 1000) % 60);
1935                         }
1936                         OBJ(xmms2_duration) {
1937                                 snprintf(p, p_max_size, "%02d:%02d",
1938                                         cur->xmms2.duration / 60000,
1939                                         (cur->xmms2.duration / 1000) % 60);
1940                         }
1941                         OBJ(xmms2_percent) {
1942                                 snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
1943                         }
1944 #ifdef X11
1945                         OBJ(xmms2_bar) {
1946                                 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1947                                         (int) (cur->xmms2.progress * 255.0f));
1948                         }
1949 #endif /* X11 */
1950                         OBJ(xmms2_playlist) {
1951                                 snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
1952                         }
1953                         OBJ(xmms2_timesplayed) {
1954                                 snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
1955                         }
1956                         OBJ(xmms2_smart) {
1957                                 if (strlen(cur->xmms2.title) < 2
1958                                                 && strlen(cur->xmms2.title) < 2) {
1959                                         snprintf(p, p_max_size, "%s", cur->xmms2.url);
1960                                 } else {
1961                                         snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist,
1962                                                 cur->xmms2.title);
1963                                 }
1964                         }
1965                         OBJ(if_xmms2_connected) {
1966                                 if (cur->xmms2.conn_state != 1) {
1967                                         DO_JUMP;
1968                                 }
1969                         }
1970 #endif /* XMMS */
1971 #ifdef AUDACIOUS
1972                         OBJ(audacious_status) {
1973                                 snprintf(p, p_max_size, "%s",
1974                                         cur->audacious.items[AUDACIOUS_STATUS]);
1975                         }
1976                         OBJ(audacious_title) {
1977                                 snprintf(p, cur->audacious.max_title_len > 0
1978                                         ? cur->audacious.max_title_len : p_max_size, "%s",
1979                                         cur->audacious.items[AUDACIOUS_TITLE]);
1980                         }
1981                         OBJ(audacious_length) {
1982                                 snprintf(p, p_max_size, "%s",
1983                                         cur->audacious.items[AUDACIOUS_LENGTH]);
1984                         }
1985                         OBJ(audacious_length_seconds) {
1986                                 snprintf(p, p_max_size, "%s",
1987                                         cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
1988                         }
1989                         OBJ(audacious_position) {
1990                                 snprintf(p, p_max_size, "%s",
1991                                         cur->audacious.items[AUDACIOUS_POSITION]);
1992                         }
1993                         OBJ(audacious_position_seconds) {
1994                                 snprintf(p, p_max_size, "%s",
1995                                         cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
1996                         }
1997                         OBJ(audacious_bitrate) {
1998                                 snprintf(p, p_max_size, "%s",
1999                                         cur->audacious.items[AUDACIOUS_BITRATE]);
2000                         }
2001                         OBJ(audacious_frequency) {
2002                                 snprintf(p, p_max_size, "%s",
2003                                         cur->audacious.items[AUDACIOUS_FREQUENCY]);
2004                         }
2005                         OBJ(audacious_channels) {
2006                                 snprintf(p, p_max_size, "%s",
2007                                         cur->audacious.items[AUDACIOUS_CHANNELS]);
2008                         }
2009                         OBJ(audacious_filename) {
2010                                 snprintf(p, p_max_size, "%s",
2011                                         cur->audacious.items[AUDACIOUS_FILENAME]);
2012                         }
2013                         OBJ(audacious_playlist_length) {
2014                                 snprintf(p, p_max_size, "%s",
2015                                         cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
2016                         }
2017                         OBJ(audacious_playlist_position) {
2018                                 snprintf(p, p_max_size, "%s",
2019                                         cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
2020                         }
2021                         OBJ(audacious_main_volume) {
2022                                 snprintf(p, p_max_size, "%s",
2023                                         cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
2024                         }
2025 #ifdef X11
2026                         OBJ(audacious_bar) {
2027                                 double progress;
2028
2029                                 progress =
2030                                         atof(cur->audacious.items[AUDACIOUS_POSITION_SECONDS]) /
2031                                         atof(cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
2032                                 new_bar(p, obj->a, obj->b, (int) (progress * 255.0f));
2033                         }
2034 #endif /* X11 */
2035 #endif /* AUDACIOUS */
2036
2037 #ifdef BMPX
2038                         OBJ(bmpx_title) {
2039                                 snprintf(p, p_max_size, "%s", cur->bmpx.title);
2040                         }
2041                         OBJ(bmpx_artist) {
2042                                 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
2043                         }
2044                         OBJ(bmpx_album) {
2045                                 snprintf(p, p_max_size, "%s", cur->bmpx.album);
2046                         }
2047                         OBJ(bmpx_uri) {
2048                                 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
2049                         }
2050                         OBJ(bmpx_track) {
2051                                 snprintf(p, p_max_size, "%i", cur->bmpx.track);
2052                         }
2053                         OBJ(bmpx_bitrate) {
2054                                 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
2055                         }
2056 #endif /* BMPX */
2057                         /* we have four different types of top (top, top_mem,
2058                          * top_time and top_io). To avoid having almost-same code four
2059                          * times, we have this special handler. */
2060                         break;
2061                         case OBJ_top:
2062                                 parse_top_args("top", obj->data.top.s, obj);
2063                                 if (!needed) needed = cur->cpu;
2064                         case OBJ_top_mem:
2065                                 parse_top_args("top_mem", obj->data.top.s, obj);
2066                                 if (!needed) needed = cur->memu;
2067                         case OBJ_top_time:
2068                                 parse_top_args("top_time", obj->data.top.s, obj);
2069                                 if (!needed) needed = cur->time;
2070 #ifdef IOSTATS
2071                         case OBJ_top_io:
2072                                 parse_top_args("top_io", obj->data.top.s, obj);
2073                                 if (!needed) needed = cur->io;
2074 #endif
2075
2076                                 if (needed[obj->data.top.num]) {
2077                                         char *timeval;
2078
2079                                         switch (obj->data.top.type) {
2080                                                 case TOP_NAME:
2081                                                         snprintf(p, top_name_width + 1, "%-*s", top_name_width,
2082                                                                         needed[obj->data.top.num]->name);
2083                                                         break;
2084                                                 case TOP_CPU:
2085                                                         snprintf(p, 7, "%6.2f",
2086                                                                         needed[obj->data.top.num]->amount);
2087                                                         break;
2088                                                 case TOP_PID:
2089                                                         snprintf(p, 6, "%5i",
2090                                                                         needed[obj->data.top.num]->pid);
2091                                                         break;
2092                                                 case TOP_MEM:
2093                                                         snprintf(p, 7, "%6.2f",
2094                                                                         needed[obj->data.top.num]->totalmem);
2095                                                         break;
2096                                                 case TOP_TIME:
2097                                                         timeval = format_time(
2098                                                                         needed[obj->data.top.num]->total_cpu_time, 9);
2099                                                         snprintf(p, 10, "%9s", timeval);
2100                                                         free(timeval);
2101                                                         break;
2102                                                 case TOP_MEM_RES:
2103                                                         human_readable(needed[obj->data.top.num]->rss,
2104                                                                         p, 255);
2105                                                         break;
2106                                                 case TOP_MEM_VSIZE:
2107                                                         human_readable(needed[obj->data.top.num]->vsize,
2108                                                                         p, 255);
2109                                                         break;
2110 #ifdef IOSTATS
2111                                                 case TOP_READ_BYTES:
2112                                                         human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
2113                                                                         p, 255);
2114                                                         break;
2115                                                 case TOP_WRITE_BYTES:
2116                                                         human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
2117                                                                         p, 255);
2118                                                         break;
2119                                                 case TOP_IO_PERC:
2120                                                         snprintf(p, 7, "%6.2f",
2121                                                                         needed[obj->data.top.num]->io_perc);
2122                                                         break;
2123 #endif
2124                                         }
2125                                 }
2126                         OBJ(tail) {
2127                                 print_tailhead("tail", obj, p, p_max_size);
2128                         }
2129                         OBJ(head) {
2130                                 print_tailhead("head", obj, p, p_max_size);
2131                         }
2132                         OBJ(lines) {
2133                                 FILE *fp = open_file(obj->data.s, &obj->a);
2134
2135                                 if(fp != NULL) {
2136 /* FIXME: use something more general (see also tail.c, head.c */
2137 #define BUFSZ 0x1000
2138                                         char buf[BUFSZ];
2139                                         int j, lines;
2140
2141                                         lines = 0;
2142                                         while(fgets(buf, BUFSZ, fp) != NULL){
2143                                                 for(j = 0; buf[j] != 0; j++) {
2144                                                         if(buf[j] == '\n') {
2145                                                                 lines++;
2146                                                         }
2147                                                 }
2148                                         }
2149                                         sprintf(p, "%d", lines);
2150                                         fclose(fp);
2151                                 } else {
2152                                         sprintf(p, "File Unreadable");
2153                                 }
2154                         }
2155
2156                         OBJ(words) {
2157                                 FILE *fp = open_file(obj->data.s, &obj->a);
2158
2159                                 if(fp != NULL) {
2160                                         char buf[BUFSZ];
2161                                         int j, words;
2162                                         char inword = FALSE;
2163
2164                                         words = 0;
2165                                         while(fgets(buf, BUFSZ, fp) != NULL){
2166                                                 for(j = 0; buf[j] != 0; j++) {
2167                                                         if(!isspace(buf[j])) {
2168                                                                 if(inword == FALSE) {
2169                                                                         words++;
2170                                                                         inword = TRUE;
2171                                                                 }
2172                                                         } else {
2173                                                                 inword = FALSE;
2174                                                         }
2175                                                 }
2176                                         }
2177                                         sprintf(p, "%d", words);
2178                                         fclose(fp);
2179                                 } else {
2180                                         sprintf(p, "File Unreadable");
2181                                 }
2182                         }
2183 #ifdef TCP_PORT_MONITOR
2184                         OBJ(tcp_portmon) {
2185                                 tcp_portmon_action(p, p_max_size,
2186                                                    &obj->data.tcp_port_monitor);
2187                         }
2188 #endif /* TCP_PORT_MONITOR */
2189
2190 #ifdef HAVE_ICONV
2191                         OBJ(iconv_start) {
2192                                 set_iconv_converting(1);
2193                                 set_iconv_selected(obj->a);
2194                         }
2195                         OBJ(iconv_stop) {
2196                                 set_iconv_converting(0);
2197                                 set_iconv_selected(0);
2198                         }
2199 #endif /* HAVE_ICONV */
2200
2201                         OBJ(entropy_avail) {
2202                                 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
2203                         }
2204                         OBJ(entropy_perc) {
2205                                 percent_print(p, p_max_size,
2206                                               cur->entropy.entropy_avail *
2207                                               100 / cur->entropy.poolsize);
2208                         }
2209                         OBJ(entropy_poolsize) {
2210                                 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
2211                         }
2212                         OBJ(entropy_bar) {
2213                                 double entropy_perc;
2214
2215                                 entropy_perc = (double) cur->entropy.entropy_avail /
2216                                         (double) cur->entropy.poolsize;
2217 #ifdef X11
2218                                 if(output_methods & TO_X) {
2219                                         new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
2220                                 } else {
2221 #endif /* X11 */
2222                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
2223                                         new_bar_in_shell(p, p_max_size, (int) (entropy_perc * 100.0f), obj->a);
2224 #ifdef X11
2225                                 }
2226 #endif /* X11 */
2227                         }
2228 #ifdef IBM
2229                         OBJ(smapi) {
2230                                 char *s;
2231                                 if(obj->data.s) {
2232                                         s = smapi_get_val(obj->data.s);
2233                                         snprintf(p, p_max_size, "%s", s);
2234                                         free(s);
2235                                 }
2236                         }
2237                         OBJ(if_smapi_bat_installed) {
2238                                 int idx;
2239                                 if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
2240                                         if(!smapi_bat_installed(idx)) {
2241                                                 DO_JUMP;
2242                                         }
2243                                 } else
2244                                         NORM_ERR("argument to if_smapi_bat_installed must be an integer");
2245                         }
2246                         OBJ(smapi_bat_perc) {
2247                                 int idx, val;
2248                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2249                                         val = smapi_bat_installed(idx) ?
2250                                                 smapi_get_bat_int(idx, "remaining_percent") : 0;
2251                                         percent_print(p, p_max_size, val);
2252                                 } else
2253                                         NORM_ERR("argument to smapi_bat_perc must be an integer");
2254                         }
2255                         OBJ(smapi_bat_temp) {
2256                                 int idx, val;
2257                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2258                                         val = smapi_bat_installed(idx) ?
2259                                                 smapi_get_bat_int(idx, "temperature") : 0;
2260                                         /* temperature is in milli degree celsius */
2261                                         temp_print(p, p_max_size, val / 1000, TEMP_CELSIUS);
2262                                 } else
2263                                         NORM_ERR("argument to smapi_bat_temp must be an integer");
2264                         }
2265                         OBJ(smapi_bat_power) {
2266                                 int idx, val;
2267                                 if(obj->data.s && sscanf(obj->data.s, "%i", &idx) == 1) {
2268                                         val = smapi_bat_installed(idx) ?
2269                                                 smapi_get_bat_int(idx, "power_now") : 0;
2270                                         /* power_now is in mW, set to W with one digit precision */
2271                                         snprintf(p, p_max_size, "%.1f", ((double)val / 1000));
2272                                 } else
2273                                         NORM_ERR("argument to smapi_bat_power must be an integer");
2274                         }
2275 #ifdef X11
2276                         OBJ(smapi_bat_bar) {
2277                                 if(obj->data.i >= 0 && smapi_bat_installed(obj->data.i))
2278                                         new_bar(p, obj->a, obj->b, (int)
2279                                                         (255 * smapi_get_bat_int(obj->data.i, "remaining_percent") / 100));
2280                                 else
2281                                         new_bar(p, obj->a, obj->b, 0);
2282                         }
2283 #endif /* X11 */
2284 #endif /* IBM */
2285                         OBJ(include) {
2286                                 if(obj->sub) {
2287                                         char buf[max_user_text];
2288
2289                                         generate_text_internal(buf, max_user_text, *obj->sub, cur);
2290                                         snprintf(p, p_max_size, "%s", buf);
2291                                 } else {
2292                                         p[0] = 0;
2293                                 }
2294                         }
2295                         OBJ(blink) {
2296                                 //blinking like this can look a bit ugly if the chars in the font don't have the same width
2297                                 char buf[max_user_text];
2298                                 unsigned int j;
2299
2300                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2301                                 snprintf(p, p_max_size, "%s", buf);
2302                                 if(total_updates % 2) {
2303                                         for(j=0; p[j] != 0; j++) {
2304                                                 p[j] = ' ';
2305                                         }
2306                                 }
2307                         }
2308                         OBJ(to_bytes) {
2309                                 char buf[max_user_text];
2310                                 long long bytes;
2311                                 char unit[16];  // 16 because we can also have long names (like mega-bytes)
2312
2313                                 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2314                                 if(sscanf(buf, "%lli%s", &bytes, unit) == 2 && strlen(unit) < 16){
2315                                         if(strncasecmp("b", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes);
2316                                         else if(strncasecmp("k", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024);
2317                                         else if(strncasecmp("m", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024);
2318                                         else if(strncasecmp("g", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024);
2319                                         else if(strncasecmp("t", unit, 1) == 0) snprintf(buf, max_user_text, "%lli", bytes * 1024 * 1024 * 1024 * 1024);
2320                                 }
2321                                 snprintf(p, p_max_size, "%s", buf);
2322                         }
2323                         OBJ(scroll) {
2324                                 unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
2325                                 char *pwithcolors;
2326                                 char buf[max_user_text];
2327                                 generate_text_internal(buf, max_user_text,
2328                                                        *obj->sub, cur);
2329                                 for(j = 0; buf[j] != 0; j++) {
2330                                         switch(buf[j]) {
2331                                         case '\n':      //place all the lines behind each other with LINESEPARATOR between them
2332 #define LINESEPARATOR '|'
2333                                                 buf[j]=LINESEPARATOR;
2334                                                 break;
2335                                         case SPECIAL_CHAR:
2336                                                 colorchanges++;
2337                                                 break;
2338                                         }
2339                                 }
2340                                 //no scrolling necessary if the length of the text to scroll is too short
2341                                 if (strlen(buf) - colorchanges <= obj->data.scroll.show) {
2342                                         snprintf(p, p_max_size, "%s", buf);
2343                                         break;
2344                                 }
2345                                 //make sure a colorchange at the front is not part of the string we are going to show
2346                                 while(*(buf + obj->data.scroll.start) == SPECIAL_CHAR) {
2347                                         obj->data.scroll.start++;
2348                                 }
2349                                 //place all chars that should be visible in p, including colorchanges
2350                                 for(j=0; j < obj->data.scroll.show + visibcolorchanges; j++) {
2351                                         p[j] = *(buf + obj->data.scroll.start + j);
2352                                         if(p[j] == SPECIAL_CHAR) {
2353                                                 visibcolorchanges++;
2354                                         }
2355                                         //if there is still room fill it with spaces
2356                                         if( ! p[j]) break;
2357                                 }
2358                                 for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
2359                                         p[j] = ' ';
2360                                 }
2361                                 p[j] = 0;
2362                                 //count colorchanges in front of the visible part and place that many colorchanges in front of the visible part
2363                                 for(j = 0; j < obj->data.scroll.start; j++) {
2364                                         if(buf[j] == SPECIAL_CHAR) frontcolorchanges++;
2365                                 }
2366                                 pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
2367                                 for(j = 0; j < frontcolorchanges; j++) {
2368                                         pwithcolors[j] = SPECIAL_CHAR;
2369                                 }
2370                                 pwithcolors[j] = 0;
2371                                 strcat(pwithcolors,p);
2372                                 strend = strlen(pwithcolors);
2373                                 //and place the colorchanges not in front or in the visible part behind the visible part
2374                                 for(j = 0; j < colorchanges - frontcolorchanges - visibcolorchanges; j++) {
2375                                         pwithcolors[strend + j] = SPECIAL_CHAR;
2376                                 }
2377                                 pwithcolors[strend + j] = 0;
2378                                 strcpy(p, pwithcolors);
2379                                 free(pwithcolors);
2380                                 //scroll
2381                                 obj->data.scroll.start += obj->data.scroll.step;
2382                                 if(buf[obj->data.scroll.start] == 0){
2383                                          obj->data.scroll.start = 0;
2384                                 }
2385 #ifdef X11
2386                                 //reset color when scroll is finished
2387                                 new_fg(p + strlen(p), obj->data.scroll.resetcolor);
2388 #endif
2389                         }
2390                         OBJ(combine) {
2391                                 char buf[2][max_user_text];
2392                                 int i, j;
2393                                 long longest=0;
2394                                 int nextstart;
2395                                 int nr_rows[2];
2396                                 struct llrows {
2397                                         char* row;
2398                                         struct llrows* next;
2399                                 };
2400                                 struct llrows *ll_rows[2], *current[2];
2401                                 struct text_object * objsub = obj->sub;
2402
2403                                 p[0]=0;
2404                                 for(i=0; i<2; i++) {
2405                                         nr_rows[i] = 1;
2406                                         nextstart = 0;
2407                                         ll_rows[i] = malloc(sizeof(struct llrows));
2408                                         current[i] = ll_rows[i];
2409                                         for(j=0; j<i; j++) objsub = objsub->sub;
2410                                         generate_text_internal(buf[i], max_user_text, *objsub, cur);
2411                                         for(j=0; buf[i][j] != 0; j++) {
2412                                                 if(buf[i][j] == '\t') buf[i][j] = ' ';
2413                                                 if(buf[i][j] == '\n') {
2414                                                         buf[i][j] = 0;
2415                                                         current[i]->row = strdup(buf[i]+nextstart);
2416                                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
2417                                                         current[i]->next = malloc(sizeof(struct llrows));
2418                                                         current[i] = current[i]->next;
2419                                                         nextstart = j + 1;
2420                                                         nr_rows[i]++;
2421                                                 }
2422                                         }
2423                                         current[i]->row = strdup(buf[i]+nextstart);
2424                                         if(i==0 && (long)strlen(current[i]->row) > longest) longest = (long)strlen(current[i]->row);
2425                                         current[i]->next = NULL;
2426                                         current[i] = ll_rows[i];
2427                                 }
2428                                 for(j=0; j < (nr_rows[0] > nr_rows[1] ? nr_rows[0] : nr_rows[1] ); j++) {
2429                                         if(current[0]) {
2430                                                 strcat(p, current[0]->row);
2431                                                 i=strlen(current[0]->row);
2432                                         }else i = 0;
2433                                         while(i < longest) {
2434                                                 strcat(p, " ");
2435                                                 i++;
2436                                         }
2437                                         if(current[1]) {
2438                                                 strcat(p, obj->data.combine.seperation);
2439                                                 strcat(p, current[1]->row);
2440                                         }
2441                                         strcat(p, "\n");
2442                                         #ifdef HAVE_OPENMP
2443                                         #pragma omp parallel for schedule(dynamic,10)
2444                                         #endif /* HAVE_OPENMP */
2445                                         for(i=0; i<2; i++) if(current[i]) current[i]=current[i]->next;
2446                                 }
2447                                 #ifdef HAVE_OPENMP
2448                                 #pragma omp parallel for schedule(dynamic,10)
2449                                 #endif /* HAVE_OPENMP */
2450                                 for(i=0; i<2; i++) {
2451                                         while(ll_rows[i] != NULL) {
2452                                                 current[i]=ll_rows[i];
2453                                                 free(current[i]->row);
2454                                                 ll_rows[i]=current[i]->next;
2455                                                 free(current[i]);
2456                                         }
2457                                 }
2458                         }
2459 #ifdef NVIDIA
2460                         OBJ(nvidia) {
2461                                 int value = get_nvidia_value(obj->data.nvidia.type, display);
2462                                 if(value == -1)
2463                                         snprintf(p, p_max_size, "N/A");
2464                                 else if (obj->data.nvidia.type == NV_TEMP)
2465                                         temp_print(p, p_max_size, (double)value, TEMP_CELSIUS);
2466                                 else if (obj->data.nvidia.print_as_float &&
2467                                                 value > 0 && value < 100)
2468                                         snprintf(p, p_max_size, "%.1f", (float)value);
2469                                 else
2470                                         snprintf(p, p_max_size, "%d", value);
2471                         }
2472 #endif /* NVIDIA */
2473 #ifdef APCUPSD
2474                         OBJ(apcupsd) {
2475                                 /* This is just a meta-object to set host:port */
2476                         }
2477                         OBJ(apcupsd_name) {
2478                                 snprintf(p, p_max_size, "%s",
2479                                                  cur->apcupsd.items[APCUPSD_NAME]);
2480                         }
2481                         OBJ(apcupsd_model) {
2482                                 snprintf(p, p_max_size, "%s",
2483                                                  cur->apcupsd.items[APCUPSD_MODEL]);
2484                         }
2485                         OBJ(apcupsd_upsmode) {
2486                                 snprintf(p, p_max_size, "%s",
2487                                                  cur->apcupsd.items[APCUPSD_UPSMODE]);
2488                         }
2489                         OBJ(apcupsd_cable) {
2490                                 snprintf(p, p_max_size, "%s",
2491                                                  cur->apcupsd.items[APCUPSD_CABLE]);
2492                         }
2493                         OBJ(apcupsd_status) {
2494                                 snprintf(p, p_max_size, "%s",
2495                                                  cur->apcupsd.items[APCUPSD_STATUS]);
2496                         }
2497                         OBJ(apcupsd_linev) {
2498                                 snprintf(p, p_max_size, "%s",
2499                                                  cur->apcupsd.items[APCUPSD_LINEV]);
2500                         }
2501                         OBJ(apcupsd_load) {
2502                                 snprintf(p, p_max_size, "%s",
2503                                                  cur->apcupsd.items[APCUPSD_LOAD]);
2504                         }
2505                         OBJ(apcupsd_loadbar) {
2506                                 double progress;
2507 #ifdef X11
2508                                 if(output_methods & TO_X) {
2509                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
2510                                         new_bar(p, obj->a, obj->b, (int) progress);
2511                                 } else {
2512 #endif /* X11 */
2513                                         progress = atof(cur->apcupsd.items[APCUPSD_LOAD]);
2514                                         if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
2515                                         new_bar_in_shell(p, p_max_size, (int) progress, obj->a);
2516 #ifdef X11
2517                                 }
2518 #endif /* X11 */
2519                         }
2520 #ifdef X11
2521                         OBJ(apcupsd_loadgraph) {
2522                                 double progress;
2523                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]);
2524                                 new_graph(p, obj->a, obj->b, obj->c, obj->d,
2525                                                   (int)progress, 100, 1, obj->char_a, obj->char_b);
2526                         }
2527                         OBJ(apcupsd_loadgauge) {
2528                                 double progress;
2529                                 progress =      atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
2530                                 new_gauge(p, obj->a, obj->b,
2531                                                   (int)progress);
2532                         }
2533 #endif /* X11 */
2534                         OBJ(apcupsd_charge) {
2535                                 snprintf(p, p_max_size, "%s",
2536                                                  cur->apcupsd.items[APCUPSD_CHARGE]);
2537                         }
2538                         OBJ(apcupsd_timeleft) {
2539                                 snprintf(p, p_max_size, "%s",
2540                                                  cur->apcupsd.items[APCUPSD_TIMELEFT]);
2541                         }
2542                         OBJ(apcupsd_temp) {
2543                                 snprintf(p, p_max_size, "%s",
2544                                                  cur->apcupsd.items[APCUPSD_TEMP]);
2545                         }
2546                         OBJ(apcupsd_lastxfer) {
2547                                 snprintf(p, p_max_size, "%s",
2548                                                  cur->apcupsd.items[APCUPSD_LASTXFER]);
2549                         }
2550 #endif /* APCUPSD */
2551                         break;
2552                 }
2553 #undef DO_JUMP
2554
2555
2556                 {
2557                         size_t a = strlen(p);
2558
2559 #ifdef HAVE_ICONV
2560                         iconv_convert(a, buff_in, p, p_max_size);
2561 #endif /* HAVE_ICONV */
2562                         if (obj->type != OBJ_text && obj->type != OBJ_execp && obj->type != OBJ_execpi) {
2563                                 substitute_newlines(p, a - 2);
2564                         }
2565                         p += a;
2566                         p_max_size -= a;
2567                 }
2568                 obj = obj->next;
2569         }
2570 #ifdef X11
2571         /* load any new fonts we may have had */
2572         if (need_to_load_fonts) {
2573                 load_fonts();
2574         }
2575 #endif /* X11 */
2576 }
2577