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