1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
3 * Conky, a system monitor, based on torsmo
5 * Any original torsmo code is licensed under the BSD license
7 * All code written since the fork of torsmo is licensed under the GPL
9 * Please see COPYING for details
11 * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12 * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
14 * All rights reserved.
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.
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/>.
28 * vim: ts=4 sw=4 noet ai cindent syntax=c
33 #include "obj_display.h"
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
38 void remove_deleted_chars(char *string){
40 while(string[i] != 0){
41 if(string[i] == BACKSPACE){
43 strcpy( &(string[i-1]), &(string[i+1]) );
45 }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string
50 static inline void format_media_player_time(char *buf, const int size,
53 int days, hours, minutes;
55 days = seconds / (24 * 60 * 60);
56 seconds %= (24 * 60 * 60);
57 hours = seconds / (60 * 60);
59 minutes = seconds / 60;
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,
69 snprintf(buf, size, "%i:%02i", minutes, seconds);
73 static inline double get_barnum(char *buf)
85 if (sscanf(buf, "%lf", &barnum) == 0) {
86 NORM_ERR("reading exec value failed (perhaps it's not the "
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");
98 char *format_time(unsigned long timeval, const int width)
101 unsigned long nt; // narrow time, for speed on 32-bit
102 unsigned cc; // centiseconds
103 unsigned nn; // multi-purpose whatever
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",
112 return strndup(buf, text_buffer_size);
114 if (width >= snprintf(buf, sizeof buf, "%lu:%02u", nt, nn)) {
115 return strndup(buf, text_buffer_size);
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);
122 nn = nt; // now also hours
123 if (width >= snprintf(buf, sizeof buf, "%uh", nn)) {
124 return strndup(buf, text_buffer_size);
126 nn /= 24; // now days
127 if (width >= snprintf(buf, sizeof buf, "%ud", nn)) {
128 return strndup(buf, text_buffer_size);
130 nn /= 7; // now weeks
131 if (width >= snprintf(buf, sizeof buf, "%uw", nn)) {
132 return strndup(buf, text_buffer_size);
134 // well shoot, this outta' fit...
135 return strndup("<inf>", text_buffer_size);
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, ...)
150 tempbuf = malloc(size * sizeof(char));
152 // Passes the varargs along to vsnprintf
153 va_start(argp, width);
154 vsnprintf(tempbuf, size, format, argp);
157 switch (use_spacer) {
159 len = snprintf(buf, size, "%s", tempbuf);
162 len = snprintf(buf, size, "%*s", width, tempbuf);
165 len = snprintf(buf, size, "%-*s", width, tempbuf);
172 /* print percentage values
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)
178 return spaced_print(buf, size, "%u", pad_percents, value);
181 static const char *suffixes[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "" };
183 /* converts from bytes to human readable format (K, M, G, T)
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)
190 const char **suffix = suffixes;
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));
209 if (llabs(num) < 1000LL) {
210 spaced_print(buf, size, format, width, 0, (float)num, *suffix);
214 while (llabs(num / 1024) >= 1000LL && **(suffix + 2)) {
222 /* fnum should now be < 1000, so looks like 'AAA.BBBBB'
224 * The goal is to always have a significance of 3, by
225 * adjusting the decimal part of the number. Sample output:
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).
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. */
239 precision = 0; /* print 100-999 without decimal part */
241 precision = 1; /* print 10-99 with one decimal place */
243 precision = 2; /* print 0-9 with two decimal places */
245 spaced_print(buf, size, format, width, precision, fnum, *suffix);
248 /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows
249 * multiline objects like $exec work with $align[rc] and friends
251 void substitute_newlines(char *p, long l)
255 while (p && *p && p < s + l) {
257 /* only substitute if it's not the last newline */
258 *p = SECRIT_MULTILINE_CHAR;
264 void evaluate(const char *text, char *buffer)
266 struct information *tmp_info;
267 struct text_object subroot;
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);
274 free_text_objects(&subroot, 1);
278 static struct mail_s *ensure_mail_thread(conky_context *ctx, struct text_object *obj,
279 void *thread(void *), const char *text)
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);
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);
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);
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);
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);
324 void generate_text_internal(conky_context *ctx, char *p, int p_max_size, struct
327 struct text_object *obj;
328 struct information *cur = &ctx->info;
330 int need_to_load_fonts = 0;
333 /* for the OBJ_top* handler */
334 struct process **needed = 0;
337 char buff_in[p_max_size];
339 set_iconv_converting(0);
340 #endif /* HAVE_ICONV */
344 while (obj && p_max_size > 0) {
345 needed = 0; /* reset for top stuff */
347 /* IFBLOCK jumping algorithm
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
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.
368 obj = obj->data.ifblock.next; \
371 #define OBJ(a) break; case OBJ_##a:
375 NORM_ERR("not implemented obj type %d", obj->type);
378 struct sockaddr_in addr;
379 struct hostent* he = gethostbyname(obj->data.read_tcp.host);
381 sock = socket(he->h_addrtype, SOCK_STREAM, 0);
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) {
391 FD_SET(sock, &readfds);
394 if(select(sock + 1, &readfds, NULL, NULL, &tv) > 0){
395 received = recv(sock, p, p_max_size, 0);
400 NORM_ERR("read_tcp: Couldn't create a connection");
403 NORM_ERR("read_tcp: Couldn't create a socket");
406 NORM_ERR("read_tcp: Problem with resolving the hostname");
411 temp_print(p, p_max_size, get_acpi_temperature(obj->data.i), TEMP_CELSIUS);
413 #endif /* !__OpenBSD__ */
416 obj->a = get_freq(p, p_max_size, "%.0f", 1,
417 obj->data.cpu_index);
423 obj->a = get_freq(p, p_max_size, "%'.2f", 1000,
424 obj->data.cpu_index);
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 */
432 #if defined(__linux__)
435 obj->a = get_voltage(p, p_max_size, "%.0f", 1,
436 obj->data.cpu_index);
441 obj->a = get_voltage(p, p_max_size, "%'.3f", 1000,
442 obj->data.cpu_index);
447 OBJ(wireless_essid) {
448 snprintf(p, p_max_size, "%s", obj->data.net->essid);
451 snprintf(p, p_max_size, "%s", obj->data.net->mode);
453 OBJ(wireless_bitrate) {
454 snprintf(p, p_max_size, "%s", obj->data.net->bitrate);
457 snprintf(p, p_max_size, "%s", obj->data.net->ap);
459 OBJ(wireless_link_qual) {
460 spaced_print(p, p_max_size, "%d", 4,
461 obj->data.net->link_qual);
463 OBJ(wireless_link_qual_max) {
464 spaced_print(p, p_max_size, "%d", 4,
465 obj->data.net->link_qual_max);
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);
473 spaced_print(p, p_max_size, "unk", 5);
476 OBJ(wireless_link_bar) {
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);
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);
490 #endif /* HAVE_IWLIB */
492 #endif /* __linux__ */
496 get_adt746x_cpu(p, p_max_size);
499 get_adt746x_fan(p, p_max_size);
502 get_acpi_fan(p, p_max_size);
505 get_acpi_ac_adapter(p, p_max_size);
508 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_STATUS);
511 get_battery_stuff(p, p_max_size, obj->data.s, BATTERY_TIME);
513 OBJ(battery_percent) {
514 percent_print(p, p_max_size, get_battery_perct(obj->data.s));
518 if(output_methods & TO_X) {
519 new_bar(p, obj->a, obj->b, get_battery_perct_bar(obj->data.s));
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);
529 get_battery_short_status(p, p_max_size, obj->data.s);
531 #endif /* __OpenBSD__ */
534 human_readable(cur->buffers * 1024, p, 255);
537 human_readable(cur->cached * 1024, p, 255);
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!");
545 percent_print(p, p_max_size,
546 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 100.0));
550 new_gauge(p, obj->a, obj->b,
551 round_to_int(cur->cpu_usage[obj->data.cpu_index] * 255.0));
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));
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);
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);
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);
578 new_fg(p, obj->data.l);
613 snprintf(p, p_max_size, "%s", VERSION);
615 OBJ(conky_build_date) {
616 snprintf(p, p_max_size, "%s", BUILD_DATE);
618 OBJ(conky_build_arch) {
619 snprintf(p, p_max_size, "%s", BUILD_ARCH);
621 #if defined(__linux__)
623 snprintf(p, p_max_size, "%s",
624 get_disk_protect_queue(obj->data.s));
627 snprintf(p, p_max_size, "%s", i8k.version);
630 snprintf(p, p_max_size, "%s", i8k.bios);
633 snprintf(p, p_max_size, "%s", i8k.serial);
638 sscanf(i8k.cpu_temp, "%d", &cpu_temp);
639 temp_print(p, p_max_size, (double)cpu_temp, TEMP_CELSIUS);
641 OBJ(i8k_left_fan_status) {
644 sscanf(i8k.left_fan_status, "%d", &left_fan_status);
645 if (left_fan_status == 0) {
646 snprintf(p, p_max_size, "off");
648 if (left_fan_status == 1) {
649 snprintf(p, p_max_size, "low");
651 if (left_fan_status == 2) {
652 snprintf(p, p_max_size, "high");
655 OBJ(i8k_right_fan_status) {
656 int right_fan_status;
658 sscanf(i8k.right_fan_status, "%d", &right_fan_status);
659 if (right_fan_status == 0) {
660 snprintf(p, p_max_size, "off");
662 if (right_fan_status == 1) {
663 snprintf(p, p_max_size, "low");
665 if (right_fan_status == 2) {
666 snprintf(p, p_max_size, "high");
669 OBJ(i8k_left_fan_rpm) {
670 snprintf(p, p_max_size, "%s", i8k.left_fan_rpm);
672 OBJ(i8k_right_fan_rpm) {
673 snprintf(p, p_max_size, "%s", i8k.right_fan_rpm);
678 sscanf(i8k.ac_status, "%d", &ac_status);
679 if (ac_status == -1) {
680 snprintf(p, p_max_size, "disabled (read i8k docs)");
682 if (ac_status == 0) {
683 snprintf(p, p_max_size, "off");
685 if (ac_status == 1) {
686 snprintf(p, p_max_size, "on");
689 OBJ(i8k_buttons_status) {
690 snprintf(p, p_max_size, "%s", i8k.buttons_status);
694 get_ibm_acpi_fan(p, p_max_size);
697 get_ibm_acpi_temps();
698 temp_print(p, p_max_size,
699 ibm_acpi.temps[obj->data.sensor], TEMP_CELSIUS);
702 get_ibm_acpi_volume(p, p_max_size);
704 OBJ(ibm_brightness) {
705 get_ibm_acpi_brightness(p, p_max_size);
708 /* information from sony_laptop kernel module
709 * /sys/devices/platform/sony-laptop */
711 get_sony_fanspeed(p, p_max_size);
714 if (!cur->gw_info.count) {
719 snprintf(p, p_max_size, "%s", cur->gw_info.iface);
722 snprintf(p, p_max_size, "%s", cur->gw_info.ip);
725 snprintf(p, p_max_size, "%d", get_laptop_mode());
728 get_powerbook_batt_info(p, p_max_size, obj->data.i);
730 #endif /* __linux__ */
731 #if (defined(__FreeBSD__) || defined(__linux__))
733 if ((obj->data.ifblock.s)
734 && (!interface_up(obj->data.ifblock.s))) {
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],
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]);
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]);
760 get_obsd_vendor(p, p_max_size);
763 get_obsd_product(p, p_max_size);
765 #endif /* __OpenBSD__ */
768 new_font(p, obj->data.s);
769 need_to_load_fonts = 1;
772 /* TODO: move this correction from kB to kB/s elsewhere
773 * (or get rid of it??) */
775 human_readable((obj->data.diskio->current / update_interval) * 1024LL,
779 human_readable((obj->data.diskio->current_write / update_interval) * 1024LL,
783 human_readable((obj->data.diskio->current_read / update_interval) * 1024LL,
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);
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);
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);
801 human_readable(obj->data.net->recv_speed, p, 255);
804 spaced_print(p, p_max_size, "%.1f", 8,
805 obj->data.net->recv_speed / 1024.0);
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);
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.
818 obj = obj->data.ifblock.next;
822 /* harmless object, just ignore */
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");
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);
838 #if defined(__linux__)
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);
844 strcpy(p, "0.0.0.0");
847 #endif /* __linux__ */
848 #if defined(IMLIB2) && defined(X11)
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);
856 evaluate(obj->data.s, p);
859 read_exec(obj->data.s, p, text_buffer_size);
860 remove_deleted_chars(p);
863 struct information *tmp_info;
864 struct text_object subroot;
866 read_exec(obj->data.s, p, text_buffer_size);
868 tmp_info = malloc(sizeof(struct information));
869 memcpy(tmp_info, cur, sizeof(struct information));
870 parse_conky_vars(&subroot, p, p, tmp_info);
872 free_text_objects(&subroot, 1);
879 read_exec(obj->data.s, p, text_buffer_size);
880 barnum = get_barnum(p); /*using the same function*/
884 new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0));
891 read_exec(obj->data.s, p, text_buffer_size);
892 barnum = get_barnum(p);
896 if(output_methods & TO_X) {
898 new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0));
901 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
902 new_bar_in_shell(p, p_max_size, barnum, obj->a);
910 char showaslog = FALSE;
911 char tempgrad = FALSE;
913 char *cmd = obj->data.s;
915 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
917 cmd += strlen(" "TEMPGRAD);
919 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
921 cmd += strlen(" "LOGGRAPH);
923 read_exec(cmd, p, text_buffer_size);
924 barnum = get_barnum(p);
927 new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum),
928 100, 1, showaslog, tempgrad);
933 if (current_update_time - obj->data.execi.last_update
934 >= obj->data.execi.interval) {
937 read_exec(obj->data.execi.cmd, p, text_buffer_size);
938 barnum = get_barnum(p);
943 obj->data.execi.last_update = current_update_time;
946 if(output_methods & TO_X) {
947 new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55));
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);
958 if (current_update_time - obj->data.execi.last_update
959 >= obj->data.execi.interval) {
961 char showaslog = FALSE;
962 char tempgrad = FALSE;
963 char *cmd = obj->data.execi.cmd;
965 if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) {
967 cmd += strlen(" "TEMPGRAD);
969 if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) {
971 cmd += strlen(" "LOGGRAPH);
973 obj->char_a = showaslog;
974 obj->char_b = tempgrad;
975 read_exec(cmd, p, text_buffer_size);
976 barnum = get_barnum(p);
981 obj->data.execi.last_update = current_update_time;
983 new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b);
986 if (current_update_time - obj->data.execi.last_update
987 >= obj->data.execi.interval) {
990 read_exec(obj->data.execi.cmd, p, text_buffer_size);
991 barnum = get_barnum(p);
994 obj->f = 255 * barnum / 100.0;
996 obj->data.execi.last_update = current_update_time;
998 new_gauge(p, obj->a, obj->b, round_to_int(obj->f));
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,
1007 obj->data.execi.last_update = current_update_time;
1009 snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer);
1012 struct text_object subroot;
1013 struct information *tmp_info =
1014 malloc(sizeof(struct information));
1015 memcpy(tmp_info, cur, sizeof(struct information));
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);
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);
1028 output[length] = '\0';
1029 if (length > 0 && output[length - 1] == '\n') {
1030 output[length - 1] = '\0';
1033 parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info);
1034 obj->data.execi.last_update = current_update_time;
1036 free_text_objects(&subroot, 1);
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");
1048 * note that we don't register this thread with the
1049 * timed_thread list, because we destroy it manually
1051 if (timed_thread_run(obj->data.texeci.p_timed_thread)) {
1052 NORM_ERR("Error running texeci timed thread");
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);
1061 struct mail_s *mail = ensure_mail_thread(ctx, obj, imap_thread, "imap");
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);
1069 OBJ(imap_messages) {
1070 struct mail_s *mail = ensure_mail_thread(ctx, obj, imap_thread, "imap");
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);
1079 struct mail_s *mail = ensure_mail_thread(ctx, obj, pop3_thread, "pop3");
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);
1088 struct mail_s *mail = ensure_mail_thread(ctx, obj, pop3_thread, "pop3");
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);
1098 if (obj->data.fs != NULL) {
1099 if (obj->data.fs->size == 0) {
1101 if(output_methods & TO_X) {
1102 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
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);
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));
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);
1128 if (obj->data.fs != NULL) {
1129 human_readable(obj->data.fs->avail, p, 255);
1133 if (obj->data.fs != NULL) {
1136 if (obj->data.fs->size) {
1137 val = obj->data.fs->avail * 100 / obj->data.fs->size;
1140 percent_print(p, p_max_size, val);
1144 if (obj->data.fs != NULL) {
1145 human_readable(obj->data.fs->size, p, 255);
1149 if (obj->data.fs != NULL)
1150 snprintf(p, p_max_size, "%s", obj->data.fs->type);
1153 if (obj->data.fs != NULL) {
1154 human_readable(obj->data.fs->size - obj->data.fs->free, p,
1159 if (obj->data.fs != NULL) {
1160 if (obj->data.fs->size == 0) {
1162 if(output_methods & TO_X) {
1163 new_bar(p, obj->data.fsbar.w, obj->data.fsbar.h, 255);
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);
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));
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);
1189 if (obj->data.fs != NULL) {
1192 if (obj->data.fs->size) {
1193 val = obj->data.fs->free
1198 percent_print(p, p_max_size, 100 - val);
1202 float *v = info.loadavg;
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]);
1219 new_goto(p, obj->data.i);
1222 new_tab(p, obj->data.pair.a, obj->data.pair.b);
1226 new_hr(p, obj->data.i);
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]);
1236 char *skill = eve(obj->data.eve.userid, obj->data.eve.apikey, obj->data.eve.charid);
1237 snprintf(p, p_max_size, "%s", skill);
1242 if (obj->data.curl.uri != NULL) {
1243 ccurl_process_info(p, p_max_size, obj->data.curl.uri, obj->data.curl.interval);
1245 NORM_ERR("error processing Curl data");
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);
1254 NORM_ERR("error processing RSS data");
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);
1263 NORM_ERR("error processing weather data, check that you have a valid XOAP key if using 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);
1272 NORM_ERR("error processing weather forecast data, check that you have a valid XOAP key if using XOAP.");
1278 char *str = llua_getstring(obj->data.s);
1280 snprintf(p, p_max_size, "%s", str);
1285 char *str = llua_getstring(obj->data.s);
1293 if (llua_getnumber(obj->data.s, &per)) {
1295 if(output_methods & TO_X) {
1296 new_bar(p, obj->a, obj->b, (per/100.0 * 255));
1299 if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X;
1300 new_bar_in_shell(p, p_max_size, per, obj->a);
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);
1316 if (llua_getnumber(obj->data.s, &per)) {
1317 new_gauge(p, obj->a, obj->b, (per/100.0 * 255));
1321 #endif /* HAVE_LUA */
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;
1333 if (!obj->data.hddtemp.temp) {
1334 snprintf(p, p_max_size, "N/A");
1336 val = strtol(obj->data.hddtemp.temp + 1, &endptr, 10);
1337 unit = obj->data.hddtemp.temp[0];
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);
1346 snprintf(p, p_max_size, "N/A");
1351 new_offset(p, obj->data.i);
1354 new_voffset(p, obj->data.i);
1360 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1361 obj->data.sysfs.devtype, obj->data.sysfs.type);
1363 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
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);
1370 snprintf(p, p_max_size, "%.1f", r);
1376 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1377 obj->data.sysfs.devtype, obj->data.sysfs.type);
1379 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
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);
1386 snprintf(p, p_max_size, "%.1f", r);
1392 r = get_sysfs_info(&obj->data.sysfs.fd, obj->data.sysfs.arg,
1393 obj->data.sysfs.devtype, obj->data.sysfs.type);
1395 r = r * obj->data.sysfs.factor + obj->data.sysfs.offset;
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);
1402 snprintf(p, p_max_size, "%.1f", r);
1405 #endif /* __linux__ */
1407 new_alignr(p, obj->data.i);
1410 new_alignc(p, obj->data.i);
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);
1420 if (strlen(buf) != 0) {
1426 char expression[max_user_text];
1428 struct information *tmp_info;
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);
1436 val = compare(expression);
1438 NORM_ERR("compare failed for expression '%s'",
1446 if (obj->data.ifblock.str
1447 && !check_contains(obj->data.ifblock.s,
1448 obj->data.ifblock.str)) {
1450 } else if (obj->data.ifblock.s
1451 && access(obj->data.ifblock.s, F_OK)) {
1456 if ((obj->data.ifblock.s)
1457 && (!check_mount(obj->data.ifblock.s))) {
1463 if (!get_process_by_name(obj->data.ifblock.s)) {
1465 if ((obj->data.ifblock.s) && system(obj->data.ifblock.s)) {
1470 #if defined(__linux__)
1472 snprintf(p, p_max_size, "%s", get_ioscheduler(obj->data.s));
1476 snprintf(p, p_max_size, "%s", cur->uname_s.release);
1479 snprintf(p, p_max_size, "%s", cur->uname_s.machine);
1484 human_readable(cur->mem * 1024, p, 255);
1487 human_readable(cur->memeasyfree * 1024, p, 255);
1490 human_readable(cur->memfree * 1024, p, 255);
1493 human_readable(cur->memmax * 1024, p, 255);
1497 percent_print(p, p_max_size, cur->mem * 100 / cur->memmax);
1501 new_gauge(p, obj->data.pair.a, obj->data.pair.b,
1502 cur->memmax ? (cur->mem * 255) / (cur->memmax) : 0);
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);
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);
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);
1527 percent_print(p, p_max_size, mixer_get_avg(obj->data.l));
1530 percent_print(p, p_max_size, mixer_get_left(obj->data.l));
1533 percent_print(p, p_max_size, mixer_get_right(obj->data.l));
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)));
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)));
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)));
1549 OBJ(if_mixer_mute) {
1550 if (!mixer_is_mute(obj->data.ifblock.i)) {
1555 #define NOT_IN_X "Not running in X"
1557 if(x_initialised != YES) {
1558 strncpy(p, NOT_IN_X, p_max_size);
1560 snprintf(p, p_max_size, "%d", cur->x11.monitor.current);
1563 OBJ(monitor_number) {
1564 if(x_initialised != YES) {
1565 strncpy(p, NOT_IN_X, p_max_size);
1567 snprintf(p, p_max_size, "%d", cur->x11.monitor.number);
1571 if(x_initialised != YES) {
1572 strncpy(p, NOT_IN_X, p_max_size);
1574 snprintf(p, p_max_size, "%d", cur->x11.desktop.current);
1577 OBJ(desktop_number) {
1578 if(x_initialised != YES) {
1579 strncpy(p, NOT_IN_X, p_max_size);
1581 snprintf(p, p_max_size, "%d", cur->x11.desktop.number);
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);
1595 update_mail_count(&obj->data.local_mail);
1596 snprintf(p, p_max_size, "%d", obj->data.local_mail.mail_count);
1599 update_mail_count(&obj->data.local_mail);
1600 snprintf(p, p_max_size, "%d",
1601 obj->data.local_mail.new_mail_count);
1604 update_mail_count(&obj->data.local_mail);
1605 snprintf(p, p_max_size, "%d",
1606 obj->data.local_mail.seen_mail_count);
1609 update_mail_count(&obj->data.local_mail);
1610 snprintf(p, p_max_size, "%d",
1611 obj->data.local_mail.unseen_mail_count);
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);
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);
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);
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);
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);
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);
1644 update_mail_count(&obj->data.local_mail);
1645 snprintf(p, p_max_size, "%d",
1646 obj->data.local_mail.draft_mail_count);
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);
1654 mbox_scan(obj->data.mboxscan.args, obj->data.mboxscan.output,
1656 snprintf(p, p_max_size, "%s", obj->data.mboxscan.output);
1659 snprintf(p, p_max_size, "%s", cur->uname_s.nodename);
1662 new_outline(p, obj->data.l);
1665 spaced_print(p, p_max_size, "%hu", 4, cur->procs);
1667 OBJ(running_processes) {
1668 spaced_print(p, p_max_size, "%hu", 4, cur->run_procs);
1671 snprintf(p, p_max_size, "%s", obj->data.s);
1675 new_bg(p, obj->data.l);
1678 new_stippled_hr(p, obj->data.pair.a, obj->data.pair.b);
1682 human_readable(cur->swap * 1024, p, 255);
1685 human_readable(cur->swapfree * 1024, p, 255);
1688 human_readable(cur->swapmax * 1024, p, 255);
1691 if (cur->swapmax == 0) {
1692 strncpy(p, "No swap", p_max_size);
1694 percent_print(p, p_max_size, cur->swap * 100 / cur->swapmax);
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);
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);
1711 snprintf(p, p_max_size, "%s", cur->uname_s.sysname);
1714 time_t t = time(NULL);
1715 struct tm *tm = localtime(&t);
1717 setlocale(LC_TIME, "");
1718 strftime(p, p_max_size, obj->data.s, tm);
1721 time_t t = time(NULL);
1722 struct tm *tm = gmtime(&t);
1724 strftime(p, p_max_size, obj->data.s, tm);
1731 if (obj->data.tztime.tz) {
1732 oldTZ = getenv("TZ");
1733 setenv("TZ", obj->data.tztime.tz, 1);
1739 setlocale(LC_TIME, "");
1740 strftime(p, p_max_size, obj->data.tztime.fmt, tm);
1742 setenv("TZ", oldTZ, 1);
1747 // Needless to free oldTZ since getenv gives ptr to static data
1750 human_readable(obj->data.net->recv, p, 255);
1753 human_readable(obj->data.net->trans, p, 255);
1756 snprintf(p, p_max_size, "%d", total_updates);
1759 if(total_updates % updatereset != obj->data.ifblock.i - 1) {
1764 human_readable(obj->data.net->trans_speed, p, 255);
1767 spaced_print(p, p_max_size, "%.1f", 8,
1768 obj->data.net->trans_speed / 1024.0);
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);
1777 format_seconds_short(p, p_max_size, (int) cur->uptime);
1780 format_seconds(p, p_max_size, (int) cur->uptime);
1783 snprintf(p, p_max_size, "%s", cur->users.names);
1786 snprintf(p, p_max_size, "%s", cur->users.terms);
1789 snprintf(p, p_max_size, "%s", cur->users.times);
1792 snprintf(p, p_max_size, "%d", cur->users.number);
1794 #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \
1795 || defined(__OpenBSD__)) && (defined(i386) || defined(__i386__))
1799 msg = get_apm_adapter();
1800 snprintf(p, p_max_size, "%s", msg);
1803 OBJ(apm_battery_life) {
1806 msg = get_apm_battery_life();
1807 snprintf(p, p_max_size, "%s", msg);
1810 OBJ(apm_battery_time) {
1813 msg = get_apm_battery_time();
1814 snprintf(p, p_max_size, "%s", msg);
1817 #endif /* __FreeBSD__ __OpenBSD__ */
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); \
1826 snprintf(p, obj->data.i, "%s", mpd_get_info()->val); \
1831 mpd_sprintf(artist);
1835 mpd_printf("%s", random);
1837 mpd_printf("%s", repeat);
1845 mpd_printf("%d", volume);
1847 mpd_printf("%d", bitrate);
1849 mpd_printf("%s", status);
1851 format_media_player_time(p, p_max_size, mpd_get_info()->elapsed);
1854 format_media_player_time(p, p_max_size, mpd_get_info()->length);
1857 percent_print(p, p_max_size, (int)(mpd_get_info()->progress * 100));
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));
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);
1873 struct mpd_s *mpd = mpd_get_info();
1874 int len = obj->data.i;
1875 if (len == 0 || len > p_max_size)
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,
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);
1893 OBJ(if_mpd_playing) {
1894 if (!mpd_get_info()->is_playing) {
1903 #define MOC_PRINT(t, a) \
1904 snprintf(p, p_max_size, "%s", (moc.t ? moc.t : a))
1906 MOC_PRINT(state, "??");
1909 MOC_PRINT(file, "no file");
1912 MOC_PRINT(title, "no title");
1915 MOC_PRINT(artist, "no artist");
1918 MOC_PRINT(song, "no song");
1921 MOC_PRINT(album, "no album");
1923 OBJ(moc_totaltime) {
1924 MOC_PRINT(totaltime, "0:00");
1927 MOC_PRINT(timeleft, "0:00");
1930 MOC_PRINT(curtime, "0:00");
1933 MOC_PRINT(bitrate, "0Kbps");
1936 MOC_PRINT(rate, "0KHz");
1942 snprintf(p, p_max_size, "%s", cur->xmms2.artist);
1945 snprintf(p, p_max_size, "%s", cur->xmms2.album);
1948 snprintf(p, p_max_size, "%s", cur->xmms2.title);
1951 snprintf(p, p_max_size, "%s", cur->xmms2.genre);
1953 OBJ(xmms2_comment) {
1954 snprintf(p, p_max_size, "%s", cur->xmms2.comment);
1957 snprintf(p, p_max_size, "%s", cur->xmms2.url);
1960 snprintf(p, p_max_size, "%s", cur->xmms2.status);
1963 snprintf(p, p_max_size, "%s", cur->xmms2.date);
1965 OBJ(xmms2_tracknr) {
1966 if (cur->xmms2.tracknr != -1) {
1967 snprintf(p, p_max_size, "%i", cur->xmms2.tracknr);
1970 OBJ(xmms2_bitrate) {
1971 snprintf(p, p_max_size, "%i", cur->xmms2.bitrate);
1974 snprintf(p, p_max_size, "%u", cur->xmms2.id);
1977 snprintf(p, p_max_size, "%2.1f", cur->xmms2.size);
1979 OBJ(xmms2_elapsed) {
1980 snprintf(p, p_max_size, "%02d:%02d", cur->xmms2.elapsed / 60000,
1981 (cur->xmms2.elapsed / 1000) % 60);
1983 OBJ(xmms2_duration) {
1984 snprintf(p, p_max_size, "%02d:%02d",
1985 cur->xmms2.duration / 60000,
1986 (cur->xmms2.duration / 1000) % 60);
1988 OBJ(xmms2_percent) {
1989 snprintf(p, p_max_size, "%2.0f", cur->xmms2.progress * 100);
1993 new_bar(p, obj->data.pair.a, obj->data.pair.b,
1994 (int) (cur->xmms2.progress * 255.0f));
1997 OBJ(xmms2_playlist) {
1998 snprintf(p, p_max_size, "%s", cur->xmms2.playlist);
2000 OBJ(xmms2_timesplayed) {
2001 snprintf(p, p_max_size, "%i", cur->xmms2.timesplayed);
2004 if (strlen(cur->xmms2.title) < 2
2005 && strlen(cur->xmms2.title) < 2) {
2006 snprintf(p, p_max_size, "%s", cur->xmms2.url);
2008 snprintf(p, p_max_size, "%s - %s", cur->xmms2.artist,
2012 OBJ(if_xmms2_connected) {
2013 if (cur->xmms2.conn_state != 1) {
2019 OBJ(audacious_status) {
2020 snprintf(p, p_max_size, "%s",
2021 cur->audacious.items[AUDACIOUS_STATUS]);
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]);
2028 OBJ(audacious_length) {
2029 snprintf(p, p_max_size, "%s",
2030 cur->audacious.items[AUDACIOUS_LENGTH]);
2032 OBJ(audacious_length_seconds) {
2033 snprintf(p, p_max_size, "%s",
2034 cur->audacious.items[AUDACIOUS_LENGTH_SECONDS]);
2036 OBJ(audacious_position) {
2037 snprintf(p, p_max_size, "%s",
2038 cur->audacious.items[AUDACIOUS_POSITION]);
2040 OBJ(audacious_position_seconds) {
2041 snprintf(p, p_max_size, "%s",
2042 cur->audacious.items[AUDACIOUS_POSITION_SECONDS]);
2044 OBJ(audacious_bitrate) {
2045 snprintf(p, p_max_size, "%s",
2046 cur->audacious.items[AUDACIOUS_BITRATE]);
2048 OBJ(audacious_frequency) {
2049 snprintf(p, p_max_size, "%s",
2050 cur->audacious.items[AUDACIOUS_FREQUENCY]);
2052 OBJ(audacious_channels) {
2053 snprintf(p, p_max_size, "%s",
2054 cur->audacious.items[AUDACIOUS_CHANNELS]);
2056 OBJ(audacious_filename) {
2057 snprintf(p, p_max_size, "%s",
2058 cur->audacious.items[AUDACIOUS_FILENAME]);
2060 OBJ(audacious_playlist_length) {
2061 snprintf(p, p_max_size, "%s",
2062 cur->audacious.items[AUDACIOUS_PLAYLIST_LENGTH]);
2064 OBJ(audacious_playlist_position) {
2065 snprintf(p, p_max_size, "%s",
2066 cur->audacious.items[AUDACIOUS_PLAYLIST_POSITION]);
2068 OBJ(audacious_main_volume) {
2069 snprintf(p, p_max_size, "%s",
2070 cur->audacious.items[AUDACIOUS_MAIN_VOLUME]);
2073 OBJ(audacious_bar) {
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));
2082 #endif /* AUDACIOUS */
2086 snprintf(p, p_max_size, "%s", cur->bmpx.title);
2089 snprintf(p, p_max_size, "%s", cur->bmpx.artist);
2092 snprintf(p, p_max_size, "%s", cur->bmpx.album);
2095 snprintf(p, p_max_size, "%s", cur->bmpx.uri);
2098 snprintf(p, p_max_size, "%i", cur->bmpx.track);
2101 snprintf(p, p_max_size, "%i", cur->bmpx.bitrate);
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. */
2109 parse_top_args("top", obj->data.top.s, obj);
2110 if (!needed) needed = cur->cpu;
2112 parse_top_args("top_mem", obj->data.top.s, obj);
2113 if (!needed) needed = cur->memu;
2115 parse_top_args("top_time", obj->data.top.s, obj);
2116 if (!needed) needed = cur->time;
2119 parse_top_args("top_io", obj->data.top.s, obj);
2120 if (!needed) needed = cur->io;
2123 if (needed[obj->data.top.num]) {
2126 switch (obj->data.top.type) {
2128 snprintf(p, top_name_width + 1, "%-*s", top_name_width,
2129 needed[obj->data.top.num]->name);
2132 snprintf(p, 7, "%6.2f",
2133 needed[obj->data.top.num]->amount);
2136 snprintf(p, 6, "%5i",
2137 needed[obj->data.top.num]->pid);
2140 snprintf(p, 7, "%6.2f",
2141 needed[obj->data.top.num]->totalmem);
2144 timeval = format_time(
2145 needed[obj->data.top.num]->total_cpu_time, 9);
2146 snprintf(p, 10, "%9s", timeval);
2150 human_readable(needed[obj->data.top.num]->rss,
2154 human_readable(needed[obj->data.top.num]->vsize,
2158 case TOP_READ_BYTES:
2159 human_readable(needed[obj->data.top.num]->read_bytes / update_interval,
2162 case TOP_WRITE_BYTES:
2163 human_readable(needed[obj->data.top.num]->write_bytes / update_interval,
2167 snprintf(p, 7, "%6.2f",
2168 needed[obj->data.top.num]->io_perc);
2174 print_tailhead("tail", obj, p, p_max_size);
2177 print_tailhead("head", obj, p, p_max_size);
2180 FILE *fp = open_file(obj->data.s, &obj->a);
2183 /* FIXME: use something more general (see also tail.c, head.c */
2184 #define BUFSZ 0x1000
2189 while(fgets(buf, BUFSZ, fp) != NULL){
2190 for(j = 0; buf[j] != 0; j++) {
2191 if(buf[j] == '\n') {
2196 sprintf(p, "%d", lines);
2199 sprintf(p, "File Unreadable");
2204 FILE *fp = open_file(obj->data.s, &obj->a);
2209 char inword = FALSE;
2212 while(fgets(buf, BUFSZ, fp) != NULL){
2213 for(j = 0; buf[j] != 0; j++) {
2214 if(!isspace(buf[j])) {
2215 if(inword == FALSE) {
2224 sprintf(p, "%d", words);
2227 sprintf(p, "File Unreadable");
2230 #ifdef TCP_PORT_MONITOR
2232 tcp_portmon_action(p, p_max_size,
2233 &obj->data.tcp_port_monitor);
2235 #endif /* TCP_PORT_MONITOR */
2239 set_iconv_converting(1);
2240 set_iconv_selected(obj->a);
2243 set_iconv_converting(0);
2244 set_iconv_selected(0);
2246 #endif /* HAVE_ICONV */
2248 OBJ(entropy_avail) {
2249 snprintf(p, p_max_size, "%d", cur->entropy.entropy_avail);
2252 percent_print(p, p_max_size,
2253 cur->entropy.entropy_avail *
2254 100 / cur->entropy.poolsize);
2256 OBJ(entropy_poolsize) {
2257 snprintf(p, p_max_size, "%d", cur->entropy.poolsize);
2260 double entropy_perc;
2262 entropy_perc = (double) cur->entropy.entropy_avail /
2263 (double) cur->entropy.poolsize;
2265 if(output_methods & TO_X) {
2266 new_bar(p, obj->a, obj->b, (int) (entropy_perc * 255.0f));
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);
2279 s = smapi_get_val(obj->data.s);
2280 snprintf(p, p_max_size, "%s", s);
2284 OBJ(if_smapi_bat_installed) {
2286 if(obj->data.ifblock.s && sscanf(obj->data.ifblock.s, "%i", &idx) == 1) {
2287 if(!smapi_bat_installed(idx)) {
2291 NORM_ERR("argument to if_smapi_bat_installed must be an integer");
2293 OBJ(smapi_bat_perc) {
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);
2300 NORM_ERR("argument to smapi_bat_perc must be an integer");
2302 OBJ(smapi_bat_temp) {
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);
2310 NORM_ERR("argument to smapi_bat_temp must be an integer");
2312 OBJ(smapi_bat_power) {
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));
2320 NORM_ERR("argument to smapi_bat_power must be an integer");
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));
2328 new_bar(p, obj->a, obj->b, 0);
2334 char buf[max_user_text];
2336 generate_text_internal(buf, max_user_text, *obj->sub, cur);
2337 snprintf(p, p_max_size, "%s", buf);
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];
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++) {
2356 char buf[max_user_text];
2358 char unit[16]; // 16 because we can also have long names (like mega-bytes)
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);
2368 snprintf(p, p_max_size, "%s", buf);
2371 unsigned int j, colorchanges = 0, frontcolorchanges = 0, visibcolorchanges = 0, strend;
2373 char buf[max_user_text];
2374 generate_text_internal(buf, max_user_text,
2376 for(j = 0; buf[j] != 0; j++) {
2378 case '\n': //place all the lines behind each other with LINESEPARATOR between them
2379 #define LINESEPARATOR '|'
2380 buf[j]=LINESEPARATOR;
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);
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++;
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++;
2402 //if there is still room fill it with spaces
2405 for(; j < obj->data.scroll.show + visibcolorchanges; j++) {
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++;
2413 pwithcolors=malloc(strlen(p) + 1 + colorchanges - visibcolorchanges);
2414 for(j = 0; j < frontcolorchanges; j++) {
2415 pwithcolors[j] = SPECIAL_CHAR;
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;
2424 pwithcolors[strend + j] = 0;
2425 strcpy(p, pwithcolors);
2428 obj->data.scroll.start += obj->data.scroll.step;
2429 if(buf[obj->data.scroll.start] == 0){
2430 obj->data.scroll.start = 0;
2433 //reset color when scroll is finished
2434 new_fg(p + strlen(p), obj->data.scroll.resetcolor);
2438 char buf[2][max_user_text];
2445 struct llrows* next;
2447 struct llrows *ll_rows[2], *current[2];
2448 struct text_object * objsub = obj->sub;
2451 for(i=0; i<2; i++) {
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') {
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;
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];
2475 for(j=0; j < (nr_rows[0] > nr_rows[1] ? nr_rows[0] : nr_rows[1] ); j++) {
2477 strcat(p, current[0]->row);
2478 i=strlen(current[0]->row);
2480 while(i < longest) {
2485 strcat(p, obj->data.combine.seperation);
2486 strcat(p, current[1]->row);
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;
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;
2508 int value = get_nvidia_value(obj->data.nvidia.type, display);
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);
2517 snprintf(p, p_max_size, "%d", value);
2522 /* This is just a meta-object to set host:port */
2525 snprintf(p, p_max_size, "%s",
2526 cur->apcupsd.items[APCUPSD_NAME]);
2528 OBJ(apcupsd_model) {
2529 snprintf(p, p_max_size, "%s",
2530 cur->apcupsd.items[APCUPSD_MODEL]);
2532 OBJ(apcupsd_upsmode) {
2533 snprintf(p, p_max_size, "%s",
2534 cur->apcupsd.items[APCUPSD_UPSMODE]);
2536 OBJ(apcupsd_cable) {
2537 snprintf(p, p_max_size, "%s",
2538 cur->apcupsd.items[APCUPSD_CABLE]);
2540 OBJ(apcupsd_status) {
2541 snprintf(p, p_max_size, "%s",
2542 cur->apcupsd.items[APCUPSD_STATUS]);
2544 OBJ(apcupsd_linev) {
2545 snprintf(p, p_max_size, "%s",
2546 cur->apcupsd.items[APCUPSD_LINEV]);
2549 snprintf(p, p_max_size, "%s",
2550 cur->apcupsd.items[APCUPSD_LOAD]);
2552 OBJ(apcupsd_loadbar) {
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);
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);
2568 OBJ(apcupsd_loadgraph) {
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);
2574 OBJ(apcupsd_loadgauge) {
2576 progress = atof(cur->apcupsd.items[APCUPSD_LOAD]) / 100.0 * 255.0;
2577 new_gauge(p, obj->a, obj->b,
2581 OBJ(apcupsd_charge) {
2582 snprintf(p, p_max_size, "%s",
2583 cur->apcupsd.items[APCUPSD_CHARGE]);
2585 OBJ(apcupsd_timeleft) {
2586 snprintf(p, p_max_size, "%s",
2587 cur->apcupsd.items[APCUPSD_TIMELEFT]);
2590 snprintf(p, p_max_size, "%s",
2591 cur->apcupsd.items[APCUPSD_TEMP]);
2593 OBJ(apcupsd_lastxfer) {
2594 snprintf(p, p_max_size, "%s",
2595 cur->apcupsd.items[APCUPSD_LASTXFER]);
2597 #endif /* APCUPSD */
2604 size_t a = strlen(p);
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);
2618 /* load any new fonts we may have had */
2619 if (need_to_load_fonts) {