Uhh..ansohus
[monky] / src / core.c
1 /* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al.
13  *      (see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  * vim: ts=4 sw=4 noet ai cindent syntax=c
29  *
30  */
31
32 #include "config.h"
33 #include "structs.h"
34 #include "core.h"
35
36 #include "text_object.h"
37 #include "obj_destroy.h"
38 #include "common.h"
39 #include "specials.h"
40 #include "logging.h"
41
42 #include <sys/types.h>
43 #include <sys/wait.h>
44
45 #ifdef X11
46
47 static void X11_initialisation(conky_context *ctx);
48
49 /* display to connect to */
50 static char *disp = NULL;
51
52 #endif /* X11 */
53
54 /* path to config file */
55 char *current_config;
56
57 /* set to 1 if you want all text to be in uppercase */
58 static unsigned int stuff_in_uppercase;
59
60 /* Run how many times? */
61 static unsigned long total_run_times;
62
63 /* fork? */
64 static int fork_to_background;
65
66 static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
67
68 /* filenames for output */
69 char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
70 char *append_file = NULL; FILE *append_fpointer = NULL;
71
72 #ifdef X11
73
74 static int show_graph_scale;
75 static int show_graph_range;
76
77 /* Position on the screen */
78 static int text_alignment;
79 static int gap_x, gap_y;
80
81 /* border */
82 static int draw_borders;
83 static int draw_graph_borders;
84 static int stippled_borders;
85
86 int get_stippled_borders(void)
87 {
88         return stippled_borders;
89 }
90
91 static int draw_shades, draw_outline;
92
93 long default_fg_color, default_bg_color, default_out_color;
94
95 /* create own window or draw stuff to root? */
96 static int set_transparent = 0;
97
98 #ifdef OWN_WINDOW
99 static int own_window = 0;
100 static int background_colour = 0;
101
102 /* fixed size/pos is set if wm/user changes them */
103 static int fixed_size = 0, fixed_pos = 0;
104 #endif
105
106 static int minimum_width, minimum_height;
107 static int maximum_width;
108
109 #endif /* X11 */
110
111 #ifdef __OpenBSD__
112 static int sensor_device;
113 #endif
114
115 long color0, color1, color2, color3, color4, color5, color6, color7, color8,
116          color9;
117
118 static char *template[MAX_TEMPLATES];
119
120 char **get_templates(void)
121 {
122         return template;
123 }
124
125 /* maximum size of config TEXT buffer, i.e. below TEXT line. */
126 unsigned int max_user_text;
127
128 /* maximum size of individual text buffers, ie $exec buffer size */
129 unsigned int text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
130
131 /* UTF-8 */
132 int utf8_mode = 0;
133
134 /* no buffers in used memory? */
135 int no_buffers;
136
137 /* pad percentages to decimals? */
138 static int pad_percents = 0;
139
140 static char *global_text = 0;
141
142 char *get_global_text(void)
143 {
144         return global_text;
145 }
146
147 long global_text_lines;
148
149 static int total_updates;
150 static int updatereset;
151
152 void set_updatereset(int i)
153 {
154         updatereset = i;
155 }
156
157 int get_updatereset(void)
158 {
159         return updatereset;
160 }
161
162 int check_contains(char *f, char *s)
163 {
164         int ret = 0;
165         FILE *where = open_file(f, 0);
166
167         if (where) {
168                 char buf1[256];
169
170                 while (fgets(buf1, 256, where)) {
171                         if (strstr(buf1, s)) {
172                                 ret = 1;
173                                 break;
174                         }
175                 }
176                 fclose(where);
177         } else {
178                 NORM_ERR("Could not open the file");
179         }
180         return ret;
181 }
182
183 #ifdef X11
184
185 static inline int calc_text_width(conky_context *ctx, const char *s, int l)
186 {
187         if ((ctx->output_methods & TO_X) == 0) {
188                 return 0;
189         }
190 #ifdef XFT
191         if (use_xft) {
192                 XGlyphInfo gi;
193
194                 if (utf8_mode) {
195                         XftTextExtentsUtf8(display, ctx->fonts[ctx->selected_font].xftfont,
196                                 (const FcChar8 *) s, l, &gi);
197                 } else {
198                         XftTextExtents8(display, ctx->fonts[ctx->selected_font].xftfont,
199                                 (const FcChar8 *) s, l, &gi);
200                 }
201                 return gi.xOff;
202         } else
203 #endif
204         {
205                 return XTextWidth(ctx->fonts[ctx->selected_font].font, s, l);
206         }
207 }
208 #endif /* X11 */
209
210 /* quite boring functions */
211
212 static inline void for_each_line(char *b, int f(char *, int))
213 {
214         char *ps, *pe;
215         int special_index = 0; /* specials index */
216
217         for (ps = b, pe = b; *pe; pe++) {
218                 if (*pe == '\n') {
219                         *pe = '\0';
220                         special_index = f(ps, special_index);
221                         *pe = '\n';
222                         ps = pe + 1;
223                 }
224         }
225
226         if (ps < pe) {
227                 f(ps, special_index);
228         }
229 }
230
231 void convert_escapes(char *buf)
232 {
233         char *p = buf, *s = buf;
234
235         while (*s) {
236                 if (*s == '\\') {
237                         s++;
238                         if (*s == 'n') {
239                                 *p++ = '\n';
240                         } else if (*s == '\\') {
241                                 *p++ = '\\';
242                         }
243                         s++;
244                 } else {
245                         *p++ = *s++;
246                 }
247         }
248         *p = '\0';
249 }
250
251 /* global object list root element */
252 static struct text_object global_root_object;
253
254 /* our own implementation of popen, the difference : the value of 'childpid'
255  * will be filled with the pid of the running 'command'. This is useful if want
256  * to kill it when it hangs while reading or writing to it. We have to kill it
257  * because pclose will wait until the process dies by itself */
258 FILE* pid_popen(const char *command, const char *mode, pid_t *child)
259 {
260         int ends[2];
261         int parentend, childend;
262
263         /* by running pipe after the strcmp's we make sure that we don't have to
264          * create a pipe and close the ends if mode is something illegal */
265         if(strcmp(mode, "r") == 0) {
266                 if(pipe(ends) != 0) {
267                         return NULL;
268                 }
269                 parentend = ends[0];
270                 childend = ends[1];
271         } else if(strcmp(mode, "w") == 0) {
272                 if(pipe(ends) != 0) {
273                         return NULL;
274                 }
275                 parentend = ends[1];
276                 childend = ends[0];
277         } else {
278                 return NULL;
279         }
280         *child = fork();
281         if(*child == -1) {
282                 close(parentend);
283                 close(childend);
284                 return NULL;
285         } else if(*child > 0) {
286                 close(childend);
287                 waitpid(*child, NULL, 0);
288         } else {
289                 /* don't read from both stdin and pipe or write to both stdout and pipe */
290                 if(childend == ends[0]) {
291                         close(0);
292                 } else {
293                         close(1);
294                 }
295                 dup(childend);  /* by dupping childend, the returned fd will have close-on-exec turned off */
296                 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
297                 _exit(EXIT_FAILURE); /* child should die here, (normally execl will take care of this but it can fail) */
298         }
299         return fdopen(parentend, mode);
300 }
301
302 void read_exec(const char *data, char *buf, const int size)
303 {
304         FILE *fp;
305         pid_t childpid;
306
307         fp = pid_popen(data, "r", &childpid);
308         if(fp) {
309                 int length;
310
311                 length = fread(buf, 1, size, fp);
312                 pclose(fp);
313                 buf[length] = '\0';
314                 if (length > 0 && buf[length - 1] == '\n') {
315                         buf[length - 1] = '\0';
316                 }
317         } else {
318                 buf[0] = '\0';
319         }
320 }
321
322 void *threaded_exec(void *, void *) __attribute__((noreturn));
323
324 void *threaded_exec(void *arg1, void *arg2)
325 {
326         char *buff, *p2;
327         struct text_object *obj = (struct text_object *)arg2;
328         conky_context *ctx = (conky_context *)arg1;
329
330         while (1) {
331                 buff = malloc(text_buffer_size);
332                 read_exec(obj->data.texeci.cmd, buff,
333                         ctx->text_buffer_size);
334                 p2 = buff;
335                 while (*p2) {
336                         if (*p2 == '\001') {
337                                 *p2 = ' ';
338                         }
339                         p2++;
340                 }
341                 timed_thread_lock(obj->data.texeci.p_timed_thread);
342                 strncpy(obj->data.texeci.buffer, buff, text_buffer_size);
343                 timed_thread_unlock(obj->data.texeci.p_timed_thread);
344                 free(buff);
345                 if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) {
346                         timed_thread_exit(obj->data.texeci.p_timed_thread);
347                 }
348         }
349         /* never reached */
350 }
351
352 static long current_text_color;
353
354 void set_current_text_color(long colour)
355 {
356         current_text_color = colour;
357 }
358
359 long get_current_text_color(void)
360 {
361         return current_text_color;
362 }
363
364 //adds newstring to to the tree unless you can already see it when travelling back.
365 //if it's possible to attach it then it returns a pointer to the leaf, else it returns NULL
366 struct conftree* conftree_add(struct conftree* previous, const char* newstring) {
367         struct conftree* node;
368         struct conftree* node2;
369
370         for(node = previous; node != NULL; node = node->back) {
371                 if(strcmp(node->string, newstring) == 0) {
372                         return NULL;
373                 }
374         }
375         node = malloc(sizeof(struct conftree));
376         if (previous != NULL) {
377                 if(previous->vert_next == NULL) {
378                         previous->vert_next = node;
379                 } else {
380                         for(node2 = previous->vert_next; node2->horz_next != NULL; node2 = node2->horz_next ) { }
381                         node2->horz_next = node;
382                 }
383         }
384         node->string = strdup(newstring);
385         node->horz_next = NULL;
386         node->vert_next = NULL;
387         node->back = previous;
388         return node;
389 }
390
391 void conftree_empty(struct conftree* tree) {
392         if(tree) {
393                 conftree_empty(tree->horz_next);
394                 conftree_empty(tree->vert_next);
395                 free(tree->string);
396                 free(tree);
397         }
398 }
399
400 struct conftree *currentconffile;
401
402 void extract_variable_text(conky_context *ctx, const char *p)
403 {
404         free_text_objects(&global_root_object, 0);
405         if (ctx->tmpstring1) {
406                 free(ctx->tmpstring1);
407                 ctx->tmpstring1 = 0;
408         }
409         if (ctx->tmpstring2) {
410                 free(ctx->tmpstring2);
411                 ctx->tmpstring2 = 0;
412         }
413         if (ctx->text_buffer) {
414                 free(ctx->text_buffer);
415                 ctx->text_buffer = 0;
416         }
417
418         extract_variable_text_internal(ctx, &global_root_object, p);
419 }
420
421 void parse_conky_vars(ctx, struct text_object *root, const char *txt, char *p)
422 {
423         extract_variable_text_internal(ctx, root, txt);
424         generate_text_internal(ctx, p, max_user_text, *root);
425 }
426
427 static inline struct mail_s *ensure_mail_thread(struct text_object *obj,
428                 void *thread(void *), const char *text)
429 {
430         if (obj->char_b && ctx->info.mail) {
431                 /* this means we use ctx->info */
432                 if (!ctx->info.mail->p_timed_thread) {
433                         ctx->info.mail->p_timed_thread =
434                                 timed_thread_create(thread,
435                                                 (void *) ctx->info.mail, ctx->info.mail->interval * 1000000);
436                         if (!ctx->info.mail->p_timed_thread) {
437                                 NORM_ERR("Error creating %s timed thread", text);
438                         }
439                         timed_thread_register(ctx->info.mail->p_timed_thread,
440                                         &ctx->info.mail->p_timed_thread);
441                         if (timed_thread_run(ctx->info.mail->p_timed_thread)) {
442                                 NORM_ERR("Error running %s timed thread", text);
443                         }
444                 }
445                 return ctx->info.mail;
446         } else if (obj->data.mail) {
447                 // this means we use obj
448                 if (!obj->data.mail->p_timed_thread) {
449                         obj->data.mail->p_timed_thread =
450                                 timed_thread_create(thread,
451                                                 (void *) obj->data.mail,
452                                                 obj->data.mail->interval * 1000000);
453                         if (!obj->data.mail->p_timed_thread) {
454                                 NORM_ERR("Error creating %s timed thread", text);
455                         }
456                         timed_thread_register(obj->data.mail->p_timed_thread,
457                                         &obj->data.mail->p_timed_thread);
458                         if (timed_thread_run(obj->data.mail->p_timed_thread)) {
459                                 NORM_ERR("Error running %s timed thread", text);
460                         }
461                 }
462                 return obj->data.mail;
463         } else if (!obj->a) {
464                 // something is wrong, warn once then stop
465                 NORM_ERR("There's a problem with your mail settings.  "
466                                 "Check that the global mail settings are properly defined"
467                                 " (line %li).", obj->line);
468                 obj->a++;
469         }
470         return NULL;
471 }
472
473 static void generate_text(void)
474 {
475         struct information *cur = &ctx->info;
476         char *p;
477
478         special_count = 0;
479
480         /* update ctx->info */
481
482         ctx->current_update_time = get_time();
483
484         update_stuff();
485
486         /* add things to the buffer */
487
488         /* generate text */
489
490         p = ctx->text_buffer;
491
492         generate_text_internal(ctx, p, max_user_text, global_root_object);
493
494         if (stuff_in_uppercase) {
495                 char *tmp_p;
496
497                 tmp_p = ctx->text_buffer;
498                 while (*tmp_p) {
499                         *tmp_p = toupper(*tmp_p);
500                         tmp_p++;
501                 }
502         }
503
504         ctx->next_update_time += ctx->update_interval;
505         if (ctx->next_update_time < get_time()) {
506                 ctx->next_update_time = get_time() + ctx->update_interval;
507         } else if (ctx->next_update_time > get_time() + ctx->update_interval) {
508                 ctx->next_update_time = get_time() + ctx->update_interval;
509         }
510         ctx->last_update_time = ctx->current_update_time;
511         ctx->total_updates++;
512 }
513
514 void set_update_interval(conky_context *ctx, double interval)
515 {
516         ctx->update_interval = interval;
517         ctx->update_interval_old = interval;
518 }
519
520 static inline int get_string_width(const char *s)
521 {
522 #ifdef X11
523         if (ctx->output_methods & TO_X) {
524                 return *s ? calc_text_width(s, strlen(s)) : 0;
525         }
526 #endif /* X11 */
527         return strlen(s);
528 }
529
530 #ifdef X11
531 static int get_string_width_special(char *s, int special_index)
532 {
533         char *p, *final;
534         int idx = 1;
535         int width = 0;
536         long i;
537
538         if ((ctx->output_methods & TO_X) == 0) {
539                 return (s) ? strlen(s) : 0;
540         }
541
542         if (!s) {
543                 return 0;
544         }
545
546         p = strndup(s, text_buffer_size);
547         final = p;
548
549         while (*p) {
550                 if (*p == SPECIAL_CHAR) {
551                         /* shift everything over by 1 so that the special char
552                          * doesn't mess up the size calculation */
553                         for (i = 0; i < (long)strlen(p); i++) {
554                                 *(p + i) = *(p + i + 1);
555                         }
556                         if (specials[special_index + idx].type == GRAPH
557                                         || specials[special_index + idx].type == GAUGE
558                                         || specials[special_index + idx].type == BAR) {
559                                 width += specials[special_index + idx].width;
560                         }
561                         idx++;
562                 } else if (*p == SECRIT_MULTILINE_CHAR) {
563                         *p = 0;
564                         break;
565                 } else {
566                         p++;
567                 }
568         }
569         if (strlen(final) > 1) {
570                 width += calc_text_width(final, strlen(final));
571         }
572         free(final);
573         return width;
574 }
575
576 static int text_size_updater(char *s, int special_index);
577
578 void update_text_area(conky_context *ctx)
579 {
580         int x = 0, y = 0;
581
582         if ((ctx->output_methods & TO_X) == 0)
583                 return;
584         /* update text size if it isn't fixed */
585 #ifdef OWN_WINDOW
586         if (!fixed_size)
587 #endif
588         {
589                 text_width = minimum_width;
590                 text_height = 0;
591                 last_font_height = font_height();
592                 for_each_line(ctx->text_buffer, text_size_updater);
593                 text_width += 1;
594                 if (text_height < minimum_height) {
595                         text_height = minimum_height;
596                 }
597                 if (text_width > maximum_width && maximum_width > 0) {
598                         text_width = maximum_width;
599                 }
600         }
601
602         /* get text position on workarea */
603         switch (text_alignment) {
604                 case TOP_LEFT:
605                         x = gap_x;
606                         y = gap_y;
607                         break;
608
609                 case TOP_RIGHT:
610                         x = workarea[2] - text_width - gap_x;
611                         y = gap_y;
612                         break;
613
614                 case TOP_MIDDLE:
615                         x = workarea[2] / 2 - text_width / 2 - gap_x;
616                         y = gap_y;
617                         break;
618
619                 default:
620                 case BOTTOM_LEFT:
621                         x = gap_x;
622                         y = workarea[3] - text_height - gap_y;
623                         break;
624
625                 case BOTTOM_RIGHT:
626                         x = workarea[2] - text_width - gap_x;
627                         y = workarea[3] - text_height - gap_y;
628                         break;
629
630                 case BOTTOM_MIDDLE:
631                         x = workarea[2] / 2 - text_width / 2 - gap_x;
632                         y = workarea[3] - text_height - gap_y;
633                         break;
634
635                 case MIDDLE_LEFT:
636                         x = gap_x;
637                         y = workarea[3] / 2 - text_height / 2 - gap_y;
638                         break;
639
640                 case MIDDLE_RIGHT:
641                         x = workarea[2] - text_width - gap_x;
642                         y = workarea[3] / 2 - text_height / 2 - gap_y;
643                         break;
644
645 #ifdef OWN_WINDOW
646                 case NONE:      // Let the WM manage the window
647                         x = window.x;
648                         y = window.y;
649
650                         fixed_pos = 1;
651                         fixed_size = 1;
652                         break;
653 #endif
654         }
655 #ifdef OWN_WINDOW
656
657         if (own_window && !fixed_pos) {
658                 x += workarea[0];
659                 y += workarea[1];
660                 text_start_x = window.border_inner_margin + window.border_outer_margin + window.border_width;
661                 text_start_y = window.border_inner_margin + window.border_outer_margin + window.border_width;
662                 window.x = x - window.border_inner_margin - window.border_outer_margin - window.border_width;
663                 window.y = y - window.border_inner_margin - window.border_outer_margin - window.border_width;
664         } else
665 #endif
666         {
667                 /* If window size doesn't match to workarea's size,
668                  * then window probably includes panels (gnome).
669                  * Blah, doesn't work on KDE. */
670                 if (workarea[2] != window.width || workarea[3] != window.height) {
671                         y += workarea[1];
672                         x += workarea[0];
673                 }
674
675                 text_start_x = x;
676                 text_start_y = y;
677         }
678 #ifdef HAVE_LUA
679         /* update lua window globals */
680         llua_update_window_table(text_start_x, text_start_y, text_width, text_height);
681 #endif /* HAVE_LUA */
682 }
683
684 /* drawing stuff */
685
686 static int cur_x, cur_y;        /* current x and y for drawing */
687 #endif
688 //draw_mode also without X11 because we only need to print to stdout with FG
689 static int draw_mode;           /* FG, BG or OUTLINE */
690 #ifdef X11
691 static long current_color;
692
693 static int text_size_updater(char *s, int special_index)
694 {
695         int w = 0;
696         char *p;
697
698         if ((ctx->output_methods & TO_X) == 0)
699                 return 0;
700         /* get string widths and skip specials */
701         p = s;
702         while (*p) {
703                 if (*p == SPECIAL_CHAR) {
704                         *p = '\0';
705                         w += get_string_width(s);
706                         *p = SPECIAL_CHAR;
707
708                         if (specials[special_index].type == BAR
709                                         || specials[special_index].type == GAUGE
710                                         || specials[special_index].type == GRAPH) {
711                                 w += specials[special_index].width;
712                                 if (specials[special_index].height > last_font_height) {
713                                         last_font_height = specials[special_index].height;
714                                         last_font_height += font_height();
715                                 }
716                         } else if (specials[special_index].type == OFFSET) {
717                                 if (specials[special_index].arg > 0) {
718                                         w += specials[special_index].arg;
719                                 }
720                         } else if (specials[special_index].type == VOFFSET) {
721                                 last_font_height += specials[special_index].arg;
722                         } else if (specials[special_index].type == GOTO) {
723                                 if (specials[special_index].arg > cur_x) {
724                                         w = (int) specials[special_index].arg;
725                                 }
726                         } else if (specials[special_index].type == TAB) {
727                                 int start = specials[special_index].arg;
728                                 int step = specials[special_index].width;
729
730                                 if (!step || step < 0) {
731                                         step = 10;
732                                 }
733                                 w += step - (cur_x - text_start_x - start) % step;
734                         } else if (specials[special_index].type == FONT) {
735                                 ctx->selected_font = specials[special_index].font_added;
736                                 if (font_height() > last_font_height) {
737                                         last_font_height = font_height();
738                                 }
739                         }
740
741                         special_index++;
742                         s = p + 1;
743                 } else if (*p == SECRIT_MULTILINE_CHAR) {
744                         int lw;
745                         *p = '\0';
746                         lw = get_string_width(s);
747                         *p = SECRIT_MULTILINE_CHAR;
748                         s = p + 1;
749                         w = lw > w ? lw : w;
750                         text_height += last_font_height;
751                 }
752                 p++;
753         }
754         w += get_string_width(s);
755         if (w > text_width) {
756                 text_width = w;
757         }
758         if (text_width > maximum_width && maximum_width) {
759                 text_width = maximum_width;
760         }
761
762         text_height += last_font_height;
763         last_font_height = font_height();
764         return special_index;
765 }
766 #endif /* X11 */
767
768 static inline void set_foreground_color(long c)
769 {
770 #ifdef X11
771         if (ctx->output_methods & TO_X) {
772                 current_color = c;
773                 XSetForeground(display, window.gc, c);
774         }
775 #endif /* X11 */
776 #ifdef NCURSES
777         if (ctx->output_methods & TO_NCURSES) {
778                 attron(COLOR_PAIR(c));
779         }
780 #endif /* NCURSES */
781         UNUSED(c);
782         return;
783 }
784
785 static void draw_string(const char *s)
786 {
787         int i, i2, pos, width_of_s;
788         int max = 0;
789         int added;
790         char *s_with_newlines;
791
792         if (s[0] == '\0') {
793                 return;
794         }
795
796         width_of_s = get_string_width(s);
797         s_with_newlines = strdup(s);
798         for(i = 0; i < (int) strlen(s_with_newlines); i++) {
799                 if(s_with_newlines[i] == SECRIT_MULTILINE_CHAR) {
800                         s_with_newlines[i] = '\n';
801                 }
802         }
803         if ((ctx->output_methods & TO_STDOUT) && draw_mode == FG) {
804                 printf("%s\n", s_with_newlines);
805                 if (extra_newline) fputc('\n', stdout);
806                 fflush(stdout); /* output immediately, don't buffer */
807         }
808         if ((ctx->output_methods & TO_STDERR) && draw_mode == FG) {
809                 fprintf(stderr, "%s\n", s_with_newlines);
810                 fflush(stderr); /* output immediately, don't buffer */
811         }
812         if ((ctx->output_methods & OVERWRITE_FILE) && draw_mode == FG && overwrite_fpointer) {
813                 fprintf(overwrite_fpointer, "%s\n", s_with_newlines);
814         }
815         if ((ctx->output_methods & APPEND_FILE) && draw_mode == FG && append_fpointer) {
816                 fprintf(append_fpointer, "%s\n", s_with_newlines);
817         }
818 #ifdef NCURSES
819         if ((ctx->output_methods & TO_NCURSES) && draw_mode == FG) {
820                 printw("%s", s_with_newlines);
821         }
822 #endif
823         free(s_with_newlines);
824         memset(ctx->tmpstring1, 0, text_buffer_size);
825         memset(ctx->tmpstring2, 0, text_buffer_size);
826         strncpy(ctx->tmpstring1, s, text_buffer_size - 1);
827         pos = 0;
828         added = 0;
829
830 #ifdef X11
831         if (ctx->output_methods & TO_X) {
832                 max = ((text_width - width_of_s) / get_string_width(" "));
833         }
834 #endif /* X11 */
835         /* This code looks for tabs in the text and coverts them to spaces.
836          * The trick is getting the correct number of spaces, and not going
837          * over the window's size without forcing the window larger. */
838         for (i = 0; i < (int) text_buffer_size; i++) {
839                 if (ctx->tmpstring1[i] == '\t') {
840                         i2 = 0;
841                         for (i2 = 0; i2 < (8 - (1 + pos) % 8) && added <= max; i2++) {
842                                 /* guard against overrun */
843                                 ctx->tmpstring2[MIN(pos + i2, (int)text_buffer_size - 1)] = ' ';
844                                 added++;
845                         }
846                         pos += i2;
847                 } else {
848                         /* guard against overrun */
849                         ctx->tmpstring2[MIN(pos, (int) text_buffer_size - 1)] = ctx->tmpstring1[i];
850                         pos++;
851                 }
852         }
853 #ifdef X11
854         if (ctx->output_methods & TO_X) {
855                 if (text_width == maximum_width) {
856                         /* this means the text is probably pushing the limit,
857                          * so we'll chop it */
858                         while (cur_x + get_string_width(ctx->tmpstring2) - text_start_x
859                                         > maximum_width && strlen(ctx->tmpstring2) > 0) {
860                                 ctx->tmpstring2[strlen(ctx->tmpstring2) - 1] = '\0';
861                         }
862                 }
863         }
864 #endif /* X11 */
865         s = ctx->tmpstring2;
866 #ifdef X11
867         if (ctx->output_methods & TO_X) {
868 #ifdef XFT
869                 if (use_xft) {
870                         XColor c;
871                         XftColor c2;
872
873                         c.pixel = current_color;
874                         XQueryColor(display, DefaultColormap(display, screen), &c);
875
876                         c2.pixel = c.pixel;
877                         c2.color.red = c.red;
878                         c2.color.green = c.green;
879                         c2.color.blue = c.blue;
880                         c2.color.alpha = ctx->fonts[ctx->selected_font].font_alpha;
881                         if (utf8_mode) {
882                                 XftDrawStringUtf8(window.xftdraw, &c2, ctx->fonts[ctx->selected_font].xftfont,
883                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
884                         } else {
885                                 XftDrawString8(window.xftdraw, &c2, ctx->fonts[ctx->selected_font].xftfont,
886                                         cur_x, cur_y, (const XftChar8 *) s, strlen(s));
887                         }
888                 } else
889 #endif
890                 {
891                         XDrawString(display, window.drawable, window.gc, cur_x, cur_y, s,
892                                 strlen(s));
893                 }
894                 cur_x += width_of_s;
895         }
896 #endif /* X11 */
897         memcpy(ctx->tmpstring1, s, text_buffer_size);
898 }
899
900 int draw_each_line_inner(char *s, int special_index, int last_special_applied)
901 {
902 #ifdef X11
903         int font_h = font_height();
904         int cur_y_add = 0;
905 #endif /* X11 */
906         char *recurse = 0;
907         char *p = s;
908         int last_special_needed = -1;
909         int orig_special_index = special_index;
910
911 #ifdef X11
912         cur_x = text_start_x;
913         cur_y += font_ascent();
914 #endif /* X11 */
915
916         while (*p) {
917                 if (*p == SECRIT_MULTILINE_CHAR) {
918                         /* special newline marker for multiline objects */
919                         recurse = p + 1;
920                         *p = '\0';
921                         break;
922                 }
923                 if (*p == SPECIAL_CHAR || last_special_applied > -1) {
924 #ifdef X11
925                         int w = 0;
926 #endif /* X11 */
927
928                         /* draw string before special, unless we're dealing multiline
929                          * specials */
930                         if (last_special_applied > -1) {
931                                 special_index = last_special_applied;
932                         } else {
933                                 *p = '\0';
934                                 draw_string(s);
935                                 *p = SPECIAL_CHAR;
936                                 s = p + 1;
937                         }
938                         /* draw special */
939                         switch (specials[special_index].type) {
940 #ifdef X11
941                                 case HORIZONTAL_LINE:
942                                 {
943                                         int h = specials[special_index].height;
944                                         int mid = font_ascent() / 2;
945
946                                         w = text_start_x + text_width - cur_x;
947
948                                         XSetLineAttributes(display, window.gc, h, LineSolid,
949                                                 CapButt, JoinMiter);
950                                         XDrawLine(display, window.drawable, window.gc, cur_x,
951                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
952                                         break;
953                                 }
954
955                                 case STIPPLED_HR:
956                                 {
957                                         int h = specials[special_index].height;
958                                         int tmp_s = specials[special_index].arg;
959                                         int mid = font_ascent() / 2;
960                                         char ss[2] = { tmp_s, tmp_s };
961
962                                         w = text_start_x + text_width - cur_x - 1;
963                                         XSetLineAttributes(display, window.gc, h, LineOnOffDash,
964                                                 CapButt, JoinMiter);
965                                         XSetDashes(display, window.gc, 0, ss, 2);
966                                         XDrawLine(display, window.drawable, window.gc, cur_x,
967                                                 cur_y - mid / 2, cur_x + w, cur_y - mid / 2);
968                                         break;
969                                 }
970
971                                 case BAR:
972                                 {
973                                         int h, bar_usage, by;
974                                         if (cur_x - text_start_x > maximum_width
975                                                         && maximum_width > 0) {
976                                                 break;
977                                         }
978                                         h = specials[special_index].height;
979                                         bar_usage = specials[special_index].arg;
980                                         by = cur_y - (font_ascent() / 2) - 1;
981
982                                         if (h < font_h) {
983                                                 by -= h / 2 - 1;
984                                         }
985                                         w = specials[special_index].width;
986                                         if (w == 0) {
987                                                 w = text_start_x + text_width - cur_x - 1;
988                                         }
989                                         if (w < 0) {
990                                                 w = 0;
991                                         }
992
993                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
994                                                 CapButt, JoinMiter);
995
996                                         XDrawRectangle(display, window.drawable, window.gc, cur_x,
997                                                 by, w, h);
998                                         XFillRectangle(display, window.drawable, window.gc, cur_x,
999                                                 by, w * bar_usage / 255, h);
1000                                         if (h > cur_y_add
1001                                                         && h > font_h) {
1002                                                 cur_y_add = h;
1003                                         }
1004                                         break;
1005                                 }
1006
1007                                 case GAUGE: /* new GAUGE  */
1008                                 {
1009                                         int h, by = 0;
1010                                         unsigned long last_colour = current_color;
1011 #ifdef MATH
1012                                         float angle, px, py;
1013                                         int usage;
1014 #endif /* MATH */
1015
1016                                         if (cur_x - text_start_x > maximum_width
1017                                                         && maximum_width > 0) {
1018                                                 break;
1019                                         }
1020
1021                                         h = specials[special_index].height;
1022                                         by = cur_y - (font_ascent() / 2) - 1;
1023
1024                                         if (h < font_h) {
1025                                                 by -= h / 2 - 1;
1026                                         }
1027                                         w = specials[special_index].width;
1028                                         if (w == 0) {
1029                                                 w = text_start_x + text_width - cur_x - 1;
1030                                         }
1031                                         if (w < 0) {
1032                                                 w = 0;
1033                                         }
1034
1035                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
1036                                                         CapButt, JoinMiter);
1037
1038                                         XDrawArc(display, window.drawable, window.gc,
1039                                                         cur_x, by, w, h * 2, 0, 180*64);
1040
1041 #ifdef MATH
1042                                         usage = specials[special_index].arg;
1043                                         angle = (M_PI)*(float)(usage)/255.;
1044                                         px = (float)(cur_x+(w/2.))-(float)(w/2.)*cos(angle);
1045                                         py = (float)(by+(h))-(float)(h)*sin(angle);
1046
1047                                         XDrawLine(display, window.drawable, window.gc,
1048                                                         cur_x + (w/2.), by+(h), (int)(px), (int)(py));
1049 #endif /* MATH */
1050
1051                                         if (h > cur_y_add
1052                                                         && h > font_h) {
1053                                                 cur_y_add = h;
1054                                         }
1055
1056                                         set_foreground_color(last_colour);
1057
1058                                         break;
1059
1060                                 }
1061
1062                                 case GRAPH:
1063                                 {
1064                                         int h, by, i = 0, j = 0;
1065                                         int colour_idx = 0;
1066                                         unsigned long last_colour = current_color;
1067                                         unsigned long *tmpcolour = 0;
1068                                         if (cur_x - text_start_x > maximum_width
1069                                                         && maximum_width > 0) {
1070                                                 break;
1071                                         }
1072                                         h = specials[special_index].height;
1073                                         by = cur_y - (font_ascent() / 2) - 1;
1074
1075                                         if (h < font_h) {
1076                                                 by -= h / 2 - 1;
1077                                         }
1078                                         w = specials[special_index].width;
1079                                         if (w == 0) {
1080                                                 w = text_start_x + text_width - cur_x - 1;
1081                                         }
1082                                         if (w < 0) {
1083                                                 w = 0;
1084                                         }
1085                                         if (draw_graph_borders) {
1086                                                 XSetLineAttributes(display, window.gc, 1, LineSolid,
1087                                                         CapButt, JoinMiter);
1088                                                 XDrawRectangle(display, window.drawable, window.gc,
1089                                                         cur_x, by, w, h);
1090                                         }
1091                                         XSetLineAttributes(display, window.gc, 1, LineSolid,
1092                                                 CapButt, JoinMiter);
1093
1094                                         if (specials[special_index].last_colour != 0
1095                                                         || specials[special_index].first_colour != 0) {
1096                                                 tmpcolour = do_gradient(w - 1, specials[special_index].last_colour, specials[special_index].first_colour);
1097                                         }
1098                                         colour_idx = 0;
1099                                         for (i = w - 2; i > -1; i--) {
1100                                                 if (specials[special_index].last_colour != 0
1101                                                                 || specials[special_index].first_colour != 0) {
1102                                                         if (specials[special_index].tempgrad) {
1103 #ifdef DEBUG_lol
1104                                                                 assert(
1105                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
1106                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
1107                                                                                 < w - 1
1108                                                                           );
1109                                                                 assert(
1110                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
1111                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
1112                                                                                 > -1
1113                                                                           );
1114                                                                 if (specials[special_index].graph[j] == specials[special_index].graph_scale) {
1115                                                                         assert(
1116                                                                                         (int)((float)(w - 2) - specials[special_index].graph[j] *
1117                                                                                                 (w - 2) / (float)specials[special_index].graph_scale)
1118                                                                                         == 0
1119                                                                                   );
1120                                                                 }
1121 #endif /* DEBUG_lol */
1122                                                                 XSetForeground(display, window.gc, tmpcolour[
1123                                                                                 (int)((float)(w - 2) - specials[special_index].graph[j] *
1124                                                                                         (w - 2) / (float)specials[special_index].graph_scale)
1125                                                                                 ]);
1126                                                         } else {
1127                                                                 XSetForeground(display, window.gc, tmpcolour[colour_idx++]);
1128                                                         }
1129                                                 }
1130                                                 /* this is mugfugly, but it works */
1131                                                 XDrawLine(display, window.drawable, window.gc,
1132                                                                 cur_x + i + 1, by + h, cur_x + i + 1,
1133                                                                 round_to_int((double)by + h - specials[special_index].graph[j] *
1134                                                                         (h - 1) / specials[special_index].graph_scale));
1135                                                 if ((w - i) / ((float) (w - 2) /
1136                                                                         (specials[special_index].graph_width)) > j
1137                                                                 && j < MAX_GRAPH_DEPTH - 3) {
1138                                                         j++;
1139                                                 }
1140                                         }
1141                                         if (tmpcolour) free(tmpcolour);
1142                                         if (h > cur_y_add
1143                                                         && h > font_h) {
1144                                                 cur_y_add = h;
1145                                         }
1146                                         /* if (draw_mode == BG) {
1147                                                 set_foreground_color(default_bg_color);
1148                                         } else if (draw_mode == OUTLINE) {
1149                                                 set_foreground_color(default_out_color);
1150                                         } else {
1151                                                 set_foreground_color(default_fg_color);
1152                                         } */
1153                                         if (show_graph_range) {
1154                                                 int tmp_x = cur_x;
1155                                                 int tmp_y = cur_y;
1156                                                 unsigned short int seconds = update_interval * w;
1157                                                 char *tmp_day_str;
1158                                                 char *tmp_hour_str;
1159                                                 char *tmp_min_str;
1160                                                 char *tmp_sec_str;
1161                                                 char *tmp_str;
1162                                                 unsigned short int timeunits;
1163                                                 if (seconds != 0) {
1164                                                         timeunits = seconds / 86400; seconds %= 86400;
1165                                                         if (timeunits > 0) {
1166                                                                 asprintf(&tmp_day_str, "%dd", timeunits);
1167                                                         } else {
1168                                                                 tmp_day_str = strdup("");
1169                                                         }
1170                                                         timeunits = seconds / 3600; seconds %= 3600;
1171                                                         if (timeunits > 0) {
1172                                                                 asprintf(&tmp_hour_str, "%dh", timeunits);
1173                                                         } else {
1174                                                                 tmp_hour_str = strdup("");
1175                                                         }
1176                                                         timeunits = seconds / 60; seconds %= 60;
1177                                                         if (timeunits > 0) {
1178                                                                 asprintf(&tmp_min_str, "%dm", timeunits);
1179                                                         } else {
1180                                                                 tmp_min_str = strdup("");
1181                                                         }
1182                                                         if (seconds > 0) {
1183                                                                 asprintf(&tmp_sec_str, "%ds", seconds);
1184                                                         } else {
1185                                                                 tmp_sec_str = strdup("");
1186                                                         }
1187                                                         asprintf(&tmp_str, "%s%s%s%s", tmp_day_str, tmp_hour_str, tmp_min_str, tmp_sec_str);
1188                                                         free(tmp_day_str); free(tmp_hour_str); free(tmp_min_str); free(tmp_sec_str);
1189                                                 } else {
1190                                                         asprintf(&tmp_str, "Range not possible"); // should never happen, but better safe then sorry
1191                                                 }
1192                                                 cur_x += (w / 2) - (font_ascent() * (strlen(tmp_str) / 2));
1193                                                 cur_y += font_h / 2;
1194                                                 draw_string(tmp_str);
1195                                                 free(tmp_str);
1196                                                 cur_x = tmp_x;
1197                                                 cur_y = tmp_y;
1198                                         }
1199 #ifdef MATH
1200                                         if (show_graph_scale && (specials[special_index].show_scale == 1)) {
1201                                                 int tmp_x = cur_x;
1202                                                 int tmp_y = cur_y;
1203                                                 char *tmp_str;
1204                                                 cur_x += font_ascent() / 2;
1205                                                 cur_y += font_h / 2;
1206                                                 tmp_str = (char *)
1207                                                         calloc(log10(floor(specials[special_index].graph_scale)) + 4,
1208                                                                         sizeof(char));
1209                                                 sprintf(tmp_str, "%.1f", specials[special_index].graph_scale);
1210                                                 draw_string(tmp_str);
1211                                                 free(tmp_str);
1212                                                 cur_x = tmp_x;
1213                                                 cur_y = tmp_y;
1214                                         }
1215 #endif
1216                                         set_foreground_color(last_colour);
1217                                         break;
1218                                 }
1219
1220                                 case FONT:
1221                                 {
1222                                         int old = font_ascent();
1223
1224                                         cur_y -= font_ascent();
1225                                         ctx->selected_font = specials[special_index].font_added;
1226                                         set_font();
1227                                         if (cur_y + font_ascent() < cur_y + old) {
1228                                                 cur_y += old;
1229                                         } else {
1230                                                 cur_y += font_ascent();
1231                                         }
1232                                         font_h = font_height();
1233                                         break;
1234                                 }
1235 #endif /* X11 */
1236                                 case FG:
1237                                         if (draw_mode == FG) {
1238                                                 set_foreground_color(specials[special_index].arg);
1239                                         }
1240                                         break;
1241
1242 #ifdef X11
1243                                 case BG:
1244                                         if (draw_mode == BG) {
1245                                                 set_foreground_color(specials[special_index].arg);
1246                                         }
1247                                         break;
1248
1249                                 case OUTLINE:
1250                                         if (draw_mode == OUTLINE) {
1251                                                 set_foreground_color(specials[special_index].arg);
1252                                         }
1253                                         break;
1254
1255                                 case OFFSET:
1256                                         w += specials[special_index].arg;
1257                                         last_special_needed = special_index;
1258                                         break;
1259
1260                                 case VOFFSET:
1261                                         cur_y += specials[special_index].arg;
1262                                         break;
1263
1264                                 case GOTO:
1265                                         if (specials[special_index].arg >= 0) {
1266                                                 cur_x = (int) specials[special_index].arg;
1267                                         }
1268                                         last_special_needed = special_index;
1269                                         break;
1270
1271                                 case TAB:
1272                                 {
1273                                         int start = specials[special_index].arg;
1274                                         int step = specials[special_index].width;
1275
1276                                         if (!step || step < 0) {
1277                                                 step = 10;
1278                                         }
1279                                         w = step - (cur_x - text_start_x - start) % step;
1280                                         last_special_needed = special_index;
1281                                         break;
1282                                 }
1283
1284                                 case ALIGNR:
1285                                 {
1286                                         /* TODO: add back in "+ window.border_inner_margin" to the end of
1287                                          * this line? */
1288                                         int pos_x = text_start_x + text_width -
1289                                                 get_string_width_special(s, special_index);
1290
1291                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
1292                                                 "get_string_width(p) %i gap_x %i "
1293                                                 "specials[special_index].arg %i window.border_inner_margin %i "
1294                                                 "window.border_width %i\n", pos_x, text_start_x, text_width,
1295                                                 cur_x, get_string_width_special(s), gap_x,
1296                                                 specials[special_index].arg, window.border_inner_margin,
1297                                                 window.border_width); */
1298                                         if (pos_x > specials[special_index].arg && pos_x > cur_x) {
1299                                                 cur_x = pos_x - specials[special_index].arg;
1300                                         }
1301                                         last_special_needed = special_index;
1302                                         break;
1303                                 }
1304
1305                                 case ALIGNC:
1306                                 {
1307                                         int pos_x = (text_width) / 2 - get_string_width_special(s,
1308                                                         special_index) / 2 - (cur_x -
1309                                                                 text_start_x);
1310                                         /* int pos_x = text_start_x + text_width / 2 -
1311                                                 get_string_width_special(s) / 2; */
1312
1313                                         /* printf("pos_x %i text_start_x %i text_width %i cur_x %i "
1314                                                 "get_string_width(p) %i gap_x %i "
1315                                                 "specials[special_index].arg %i\n", pos_x, text_start_x,
1316                                                 text_width, cur_x, get_string_width(s), gap_x,
1317                                                 specials[special_index].arg); */
1318                                         if (pos_x > specials[special_index].arg) {
1319                                                 w = pos_x - specials[special_index].arg;
1320                                         }
1321                                         last_special_needed = special_index;
1322                                         break;
1323                                 }
1324 #endif /* X11 */
1325                         }
1326
1327 #ifdef X11
1328                         cur_x += w;
1329 #endif /* X11 */
1330
1331                         if (special_index != last_special_applied) {
1332                                 special_index++;
1333                         } else {
1334                                 special_index = orig_special_index;
1335                                 last_special_applied = -1;
1336                         }
1337                 }
1338                 p++;
1339         }
1340
1341 #ifdef X11
1342         cur_y += cur_y_add;
1343 #endif /* X11 */
1344         draw_string(s);
1345 #ifdef NCURSES
1346         if (ctx->output_methods & TO_NCURSES) {
1347                 printw("\n");
1348         }
1349 #endif /* NCURSES */
1350 #ifdef X11
1351         cur_y += font_descent();
1352 #endif /* X11 */
1353         if (recurse && *recurse) {
1354                 special_index = draw_each_line_inner(recurse, special_index, last_special_needed);
1355                 *(recurse - 1) = SECRIT_MULTILINE_CHAR;
1356         }
1357         return special_index;
1358 }
1359
1360 static int draw_line(char *s, int special_index)
1361 {
1362 #ifdef X11
1363         if (ctx->output_methods & TO_X) {
1364                 return draw_each_line_inner(s, special_index, -1);
1365         }
1366 #endif /* X11 */
1367 #ifdef NCURSES
1368         if (ctx->output_methods & TO_NCURSES) {
1369                 return draw_each_line_inner(s, special_index, -1);
1370         }
1371 #endif /* NCURSES */
1372         draw_string(s);
1373         UNUSED(special_index);
1374         return 0;
1375 }
1376
1377 static void draw_text(void)
1378 {
1379 #ifdef X11
1380 #ifdef HAVE_LUA
1381         llua_draw_pre_hook();
1382 #endif /* HAVE_LUA */
1383         if (ctx->output_methods & TO_X) {
1384                 cur_y = text_start_y;
1385
1386                 /* draw borders */
1387                 if (draw_borders && window.border_width > 0) {
1388                         if (stippled_borders) {
1389                                 char ss[2] = { stippled_borders, stippled_borders };
1390                                 XSetLineAttributes(display, window.gc, window.border_width, LineOnOffDash,
1391                                         CapButt, JoinMiter);
1392                                 XSetDashes(display, window.gc, 0, ss, 2);
1393                         } else {
1394                                 XSetLineAttributes(display, window.gc, window.border_width, LineSolid,
1395                                         CapButt, JoinMiter);
1396                         }
1397
1398                         XDrawRectangle(display, window.drawable, window.gc,
1399                                 text_start_x - window.border_inner_margin - window.border_width,
1400                                 text_start_y - window.border_inner_margin - window.border_width,
1401                                 text_width + window.border_inner_margin * 2 + window.border_width * 2,
1402                                 text_height + window.border_inner_margin * 2 + window.border_width * 2);
1403                 }
1404
1405                 /* draw text */
1406         }
1407         setup_fonts();
1408 #endif /* X11 */
1409 #ifdef NCURSES
1410         init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
1411         attron(COLOR_PAIR(COLOR_WHITE));
1412 #endif /* NCURSES */
1413         for_each_line(ctx->text_buffer, draw_line);
1414 #if defined(HAVE_LUA) && defined(X11)
1415         llua_draw_post_hook();
1416 #endif /* HAVE_LUA */
1417 }
1418
1419 void draw_stuff(conky_context *ctx)
1420 {
1421 #ifdef IMLIB2
1422         cimlib_render(text_start_x, text_start_y, window.width, window.height);
1423 #endif /* IMLIB2 */
1424         if (overwrite_file) {
1425                 overwrite_fpointer = fopen(overwrite_file, "w");
1426                 if(!overwrite_fpointer)
1427                         NORM_ERR("Can't overwrite '%s' anymore", overwrite_file);
1428         }
1429         if (append_file) {
1430                 append_fpointer = fopen(append_file, "a");
1431                 if(!append_fpointer)
1432                         NORM_ERR("Can't append '%s' anymore", append_file);
1433         }
1434 #ifdef X11
1435         if (ctx->output_methods & TO_X) {
1436                 ctx->selected_font = 0;
1437                 if (draw_shades && !draw_outline) {
1438                         text_start_x++;
1439                         text_start_y++;
1440                         set_foreground_color(default_bg_color);
1441                         draw_mode = BG;
1442                         draw_text();
1443                         text_start_x--;
1444                         text_start_y--;
1445                 }
1446
1447                 if (draw_outline) {
1448                         int i, j;
1449                         ctx->selected_font = 0;
1450
1451                         for (i = -1; i < 2; i++) {
1452                                 for (j = -1; j < 2; j++) {
1453                                         if (i == 0 && j == 0) {
1454                                                 continue;
1455                                         }
1456                                         text_start_x += i;
1457                                         text_start_y += j;
1458                                         set_foreground_color(default_out_color);
1459                                         draw_mode = OUTLINE;
1460                                         draw_text();
1461                                         text_start_x -= i;
1462                                         text_start_y -= j;
1463                                 }
1464                         }
1465                 }
1466
1467                 set_foreground_color(default_fg_color);
1468         }
1469 #endif /* X11 */
1470         draw_mode = FG;
1471         draw_text();
1472 #ifdef X11
1473         xdbe_swap_buffers();
1474         if (ctx->output_methods & TO_X) {
1475 #ifdef HAVE_XDBE
1476 #endif
1477         }
1478 #endif /* X11 */
1479         if(overwrite_fpointer) {
1480                 fclose(overwrite_fpointer);
1481                 overwrite_fpointer = 0;
1482         }
1483         if(append_fpointer) {
1484                 fclose(append_fpointer);
1485                 append_fpointer = 0;
1486         }
1487 }
1488
1489 #ifdef X11
1490 void clear_text(conky_context *ctx, int exposures)
1491 {
1492 #ifdef HAVE_XDBE
1493         if (use_xdbe) {
1494                 /* The swap action is XdbeBackground, which clears */
1495                 return;
1496         } else
1497 #endif
1498         if (display && window.window) { // make sure these are !null
1499                 /* there is some extra space for borders and outlines */
1500                 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
1501                         text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
1502                         text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1503                         text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, exposures ? True : 0);
1504         }
1505 }
1506 #endif /* X11 */
1507
1508 /* update_text() generates new text and clears old text area */
1509 void update_text(conky_context *ctx)
1510 {
1511 #ifdef IMLIB2
1512         cimlib_cleanup();
1513 #endif /* IMLIB2 */
1514         generate_text();
1515 #ifdef X11
1516         if (ctx->output_methods & TO_X)
1517                 clear_text(1);
1518 #endif /* X11 */
1519         ctx->need_to_update = 1;
1520 #ifdef HAVE_LUA
1521         llua_update_info(&ctx->info, update_interval);
1522 #endif /* HAVE_LUA */
1523 }
1524
1525 void initialisation(conky_context *ctx, int argc, char** argv);
1526
1527         /* reload the config file */
1528 static void reload_config(conky_context *ctx)
1529 {
1530         char *current_config_copy = strdup(current_config);
1531         clean_up(NULL, NULL);
1532         current_config = current_config_copy;
1533         initialisation(ctx, argc_copy, argv_copy);
1534 }
1535
1536 void clean_up(void *memtofree1, void *memtofree2)
1537 {
1538         int i;
1539
1540 #ifdef NCURSES
1541         if(ctx->output_methods & TO_NCURSES) {
1542                 endwin();
1543         }
1544 #endif
1545         conftree_empty(currentconffile);
1546         currentconffile = NULL;
1547         if (memtofree1) {
1548                 free(memtofree1);
1549         }
1550         if (memtofree2) {
1551                 free(memtofree2);
1552         }
1553         timed_thread_destroy_registered_threads();
1554
1555         if (ctx->info.cpu_usage) {
1556                 free(ctx->info.cpu_usage);
1557                 ctx->info.cpu_usage = NULL;
1558         }
1559 #ifdef X11
1560         if (x_initialised == YES) {
1561                 XClearArea(display, window.window, text_start_x - window.border_inner_margin - window.border_outer_margin - window.border_width,
1562                                 text_start_y - window.border_inner_margin - window.border_outer_margin - window.border_width,
1563                                 text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1564                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, 0);
1565                 destroy_window();
1566                 free_fonts();
1567                 if(x11_stuff.region) {
1568                         XDestroyRegion(x11_stuff.region);
1569                         x11_stuff.region = NULL;
1570                 }
1571                 XCloseDisplay(display);
1572                 display = NULL;
1573                 if(ctx->info.x11.desktop.all_names) {
1574                         free(ctx->info.x11.desktop.all_names);
1575                         ctx->info.x11.desktop.all_names = NULL;
1576                 }
1577                 if (ctx->info.x11.desktop.name) {
1578                         free(ctx->info.x11.desktop.name);
1579                         ctx->info.x11.desktop.name = NULL;
1580                 }
1581                 x_initialised = NO;
1582         } else {
1583                 free(ctx->fonts);       //in set_default_configurations a font is set but not loaded
1584                 font_count = -1;
1585         }
1586
1587 #endif /* X11 */
1588
1589         for (i = 0; i < MAX_TEMPLATES; i++) {
1590                 if (template[i]) {
1591                         free(template[i]);
1592                         template[i] = NULL;
1593                 }
1594         }
1595
1596         free_text_objects(&global_root_object, 0);
1597         if (ctx->tmpstring1) {
1598                 free(ctx->tmpstring1);
1599                 ctx->tmpstring1 = 0;
1600         }
1601         if (ctx->tmpstring2) {
1602                 free(ctx->tmpstring2);
1603                 ctx->tmpstring2 = 0;
1604         }
1605         if (ctx->text_buffer) {
1606                 free(ctx->text_buffer);
1607                 ctx->text_buffer = 0;
1608         }
1609
1610         if (global_text) {
1611                 free(global_text);
1612                 global_text = 0;
1613         }
1614
1615         free(current_config);
1616         current_config = 0;
1617
1618 #ifdef TCP_PORT_MONITOR
1619         tcp_portmon_clear();
1620 #endif
1621 #ifdef HAVE_CURL
1622         ccurl_free_info();
1623 #endif
1624 #ifdef RSS
1625         rss_free_info();
1626 #endif
1627 #ifdef WEATHER
1628         weather_free_info();
1629 #endif
1630 #ifdef HAVE_LUA
1631         llua_shutdown_hook();
1632         llua_close();
1633 #endif /* HAVE_LUA */
1634 #ifdef IMLIB2
1635         cimlib_deinit();
1636 #endif /* IMLIB2 */
1637 #ifdef XOAP
1638         xmlCleanupParser();
1639 #endif /* XOAP */
1640
1641         if (specials) {
1642                 for (i = 0; i < special_count; i++) {
1643                         if (specials[i].type == GRAPH) {
1644                                 free(specials[i].graph);
1645                         }
1646                 }
1647                 free(specials);
1648                 specials = NULL;
1649         }
1650
1651         clear_net_stats();
1652         clear_diskio_stats();
1653         clear_cpu_stats();
1654 }
1655
1656 static int string_to_bool(const char *s)
1657 {
1658         if (!s) {
1659                 // Assumes an option without a true/false means true
1660                 return 1;
1661         } else if (strcasecmp(s, "yes") == EQUAL) {
1662                 return 1;
1663         } else if (strcasecmp(s, "true") == EQUAL) {
1664                 return 1;
1665         } else if (strcasecmp(s, "1") == EQUAL) {
1666                 return 1;
1667         }
1668         return 0;
1669 }
1670
1671 #ifdef X11
1672 enum alignment string_to_alignment(const char *s)
1673 {
1674         if (strcasecmp(s, "top_left") == EQUAL) {
1675                 return TOP_LEFT;
1676         } else if (strcasecmp(s, "top_right") == EQUAL) {
1677                 return TOP_RIGHT;
1678         } else if (strcasecmp(s, "top_middle") == EQUAL) {
1679                 return TOP_MIDDLE;
1680         } else if (strcasecmp(s, "bottom_left") == EQUAL) {
1681                 return BOTTOM_LEFT;
1682         } else if (strcasecmp(s, "bottom_right") == EQUAL) {
1683                 return BOTTOM_RIGHT;
1684         } else if (strcasecmp(s, "bottom_middle") == EQUAL) {
1685                 return BOTTOM_MIDDLE;
1686         } else if (strcasecmp(s, "middle_left") == EQUAL) {
1687                 return MIDDLE_LEFT;
1688         } else if (strcasecmp(s, "middle_right") == EQUAL) {
1689                 return MIDDLE_RIGHT;
1690         } else if (strcasecmp(s, "tl") == EQUAL) {
1691                 return TOP_LEFT;
1692         } else if (strcasecmp(s, "tr") == EQUAL) {
1693                 return TOP_RIGHT;
1694         } else if (strcasecmp(s, "tm") == EQUAL) {
1695                 return TOP_MIDDLE;
1696         } else if (strcasecmp(s, "bl") == EQUAL) {
1697                 return BOTTOM_LEFT;
1698         } else if (strcasecmp(s, "br") == EQUAL) {
1699                 return BOTTOM_RIGHT;
1700         } else if (strcasecmp(s, "bm") == EQUAL) {
1701                 return BOTTOM_MIDDLE;
1702         } else if (strcasecmp(s, "ml") == EQUAL) {
1703                 return MIDDLE_LEFT;
1704         } else if (strcasecmp(s, "mr") == EQUAL) {
1705                 return MIDDLE_RIGHT;
1706         } else if (strcasecmp(s, "none") == EQUAL) {
1707                 return NONE;
1708         }
1709         return TOP_LEFT;
1710 }
1711 #endif /* X11 */
1712
1713 #ifdef X11
1714 static void set_default_configurations_for_x(void)
1715 {
1716         default_fg_color = WhitePixel(display, screen);
1717         default_bg_color = BlackPixel(display, screen);
1718         default_out_color = BlackPixel(display, screen);
1719         color0 = default_fg_color;
1720         color1 = default_fg_color;
1721         color2 = default_fg_color;
1722         color3 = default_fg_color;
1723         color4 = default_fg_color;
1724         color5 = default_fg_color;
1725         color6 = default_fg_color;
1726         color7 = default_fg_color;
1727         color8 = default_fg_color;
1728         color9 = default_fg_color;
1729         current_text_color = default_fg_color;
1730 }
1731 #endif /* X11 */
1732
1733 void set_default_configurations(conky_context *ctx)
1734 {
1735         int i;
1736 #ifdef MPD
1737         char *mpd_env_host;
1738         char *mpd_env_port;
1739 #endif
1740         ctx->text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
1741         update_uname();
1742         ctx->info.cpu_avg_samples = 2;
1743         ctx->info.net_avg_samples = 2;
1744         ctx->info.diskio_avg_samples = 2;
1745         format_human_readable = 1;
1746 #ifdef MPD
1747         mpd_env_host = getenv("MPD_HOST");
1748         mpd_env_port = getenv("MPD_PORT");
1749
1750         if (!mpd_env_host || !strlen(mpd_env_host)) {
1751                 mpd_set_host("localhost");
1752         } else {
1753                 /* MPD_HOST environment variable is set */
1754                 char *mpd_hostpart = strchr(mpd_env_host, '@');
1755                 if (!mpd_hostpart) {
1756                         mpd_set_host(mpd_env_host);
1757                 } else {
1758                         /* MPD_HOST contains a password */
1759                         char mpd_password[mpd_hostpart - mpd_env_host + 1];
1760                         snprintf(mpd_password, mpd_hostpart - mpd_env_host + 1, "%s", mpd_env_host);
1761
1762                         if (!strlen(mpd_hostpart + 1)) {
1763                                 mpd_set_host("localhost");
1764                         } else {
1765                                 mpd_set_host(mpd_hostpart + 1);
1766                         }
1767
1768                         mpd_set_password(mpd_password, 1);
1769                 }
1770         }
1771
1772
1773         if (!mpd_env_port || mpd_set_port(mpd_env_port)) {
1774                 /* failed to set port from environment variable */
1775                 mpd_set_port("6600");
1776         }
1777 #endif
1778 #ifdef XMMS2
1779         ctx->info.xmms2.artist = NULL;
1780         ctx->info.xmms2.album = NULL;
1781         ctx->info.xmms2.title = NULL;
1782         ctx->info.xmms2.genre = NULL;
1783         ctx->info.xmms2.comment = NULL;
1784         ctx->info.xmms2.url = NULL;
1785         ctx->info.xmms2.status = NULL;
1786         ctx->info.xmms2.playlist = NULL;
1787 #endif
1788         use_spacer = NO_SPACER;
1789 #ifdef X11
1790         ctx->output_methods = TO_X;
1791 #else
1792         ctx->output_methods = TO_STDOUT;
1793 #endif
1794 #ifdef X11
1795         show_graph_scale = 0;
1796         show_graph_range = 0;
1797         draw_shades = 1;
1798         draw_borders = 0;
1799         draw_graph_borders = 1;
1800         draw_outline = 0;
1801         set_first_font("6x10");
1802         gap_x = 5;
1803         gap_y = 60;
1804         minimum_width = 5;
1805         minimum_height = 5;
1806         maximum_width = 0;
1807 #ifdef OWN_WINDOW
1808         own_window = 0;
1809         window.type = TYPE_NORMAL;
1810         window.hints = 0;
1811         strcpy(window.class_name, PACKAGE_NAME);
1812         sprintf(window.title, PACKAGE_NAME" (%s)", ctx->info.uname_s.nodename);
1813 #endif
1814         stippled_borders = 0;
1815         window.border_inner_margin = 3;
1816         window.border_outer_margin = 1;
1817         window.border_width = 1;
1818         text_alignment = BOTTOM_LEFT;
1819         ctx->info.x11.monitor.number = 1;
1820         ctx->info.x11.monitor.current = 0;
1821         ctx->info.x11.desktop.current = 1; 
1822         ctx->info.x11.desktop.number = 1;
1823         ctx->info.x11.desktop.nitems = 0;
1824         ctx->info.x11.desktop.all_names = NULL; 
1825         ctx->info.x11.desktop.name = NULL; 
1826 #endif /* X11 */
1827
1828         for (i = 0; i < MAX_TEMPLATES; i++) {
1829                 if (template[i])
1830                         free(template[i]);
1831                 template[i] = strdup("");
1832         }
1833
1834         free(current_mail_spool);
1835         {
1836                 char buf[256];
1837
1838                 variable_substitute(MAIL_FILE, buf, 256);
1839                 if (buf[0] != '\0') {
1840                         current_mail_spool = strndup(buf, text_buffer_size);
1841                 }
1842         }
1843
1844         no_buffers = 1;
1845         set_update_interval(3);
1846         update_interval_bat = NOBATTERY;
1847         ctx->info.music_player_interval = 1.0;
1848         stuff_in_uppercase = 0;
1849         ctx->info.users.number = 1;
1850
1851 #ifdef TCP_PORT_MONITOR
1852         /* set default connection limit */
1853         tcp_portmon_set_max_connections(0);
1854 #endif
1855 }
1856
1857 /* returns 1 if you can overwrite or create the file at 'path' */
1858 static _Bool overwrite_works(const char *path)
1859 {
1860         FILE *filepointer;
1861
1862         if (!(filepointer = fopen(path, "w")))
1863                 return 0;
1864         fclose(filepointer);
1865         return 1;
1866 }
1867
1868 /* returns 1 if you can append or create the file at 'path' */
1869 static _Bool append_works(const char *path)
1870 {
1871         FILE *filepointer;
1872
1873         if (!(filepointer = fopen(path, "a")))
1874                 return 0;
1875         fclose(filepointer);
1876         return 1;
1877 }
1878
1879 #ifdef X11
1880 #ifdef DEBUG
1881 /* WARNING, this type not in Xlib spec */
1882 int x11_error_handler(Display *d, XErrorEvent *err)
1883         __attribute__((noreturn));
1884 int x11_error_handler(Display *d, XErrorEvent *err)
1885 {
1886         NORM_ERR("X Error: type %i Display %lx XID %li serial %lu error_code %i request_code %i minor_code %i other Display: %lx\n",
1887                         err->type,
1888                         (long unsigned)err->display,
1889                         (long)err->resourceid,
1890                         err->serial,
1891                         err->error_code,
1892                         err->request_code,
1893                         err->minor_code,
1894                         (long unsigned)d
1895                         );
1896         abort();
1897 }
1898
1899 int x11_ioerror_handler(Display *d)
1900         __attribute__((noreturn));
1901 int x11_ioerror_handler(Display *d)
1902 {
1903         NORM_ERR("X Error: Display %lx\n",
1904                         (long unsigned)d
1905                         );
1906         abort();
1907 }
1908 #endif /* DEBUG */
1909
1910 static void X11_initialisation(conky_context *ctx)
1911 {
1912         if (x_initialised == YES) return;
1913         ctx->output_methods |= TO_X;
1914         init_X11(disp);
1915         set_default_configurations_for_x();
1916         x_initialised = YES;
1917 #ifdef DEBUG
1918         _Xdebug = 1;
1919         /* WARNING, this type not in Xlib spec */
1920         XSetErrorHandler(&x11_error_handler);
1921         XSetIOErrorHandler(&x11_ioerror_handler);
1922 #endif /* DEBUG */
1923 }
1924
1925 void X11_create_window(conky_context *ctx)
1926 {
1927         if (ctx->output_methods & TO_X) {
1928 #ifdef OWN_WINDOW
1929                 init_window(own_window, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1930                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, background_colour,
1931                                 ctx->xargv, ctx->xargc);
1932 #else /* OWN_WINDOW */
1933                 init_window(0, text_width + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2,
1934                                 text_height + window.border_inner_margin * 2 + window.border_outer_margin * 2 + window.border_width * 2, set_transparent, 0,
1935                                 ctx->xargv, ctx->xargc);
1936 #endif /* OWN_WINDOW */
1937
1938                 setup_fonts();
1939                 load_fonts();
1940                 update_text_area();     /* to position text/window on screen */
1941
1942 #ifdef OWN_WINDOW
1943                 if (own_window && !fixed_pos) {
1944                         XMoveWindow(display, window.window, window.x, window.y);
1945                 }
1946                 if (own_window) {
1947                         set_transparent_background(window.window);
1948                 }
1949 #endif
1950
1951                 create_gc();
1952
1953                 draw_stuff();
1954
1955                 x11_stuff.region = XCreateRegion();
1956 #ifdef HAVE_XDAMAGE
1957                 if (!XDamageQueryExtension(display, &x11_stuff.event_base, &x11_stuff.error_base)) {
1958                         NORM_ERR("Xdamage extension unavailable");
1959                 }
1960                 x11_stuff.damage = XDamageCreate(display, window.window, XDamageReportNonEmpty);
1961                 x11_stuff.region2 = XFixesCreateRegionFromWindow(display, window.window, 0);
1962                 x11_stuff.part = XFixesCreateRegionFromWindow(display, window.window, 0);
1963 #endif /* HAVE_XDAMAGE */
1964
1965                 ctx->selected_font = 0;
1966                 update_text_area();     /* to get initial size of the window */
1967         }
1968 #ifdef HAVE_LUA
1969         /* setup lua window globals */
1970         llua_setup_window_table(text_start_x, text_start_y, text_width, text_height);
1971 #endif /* HAVE_LUA */
1972 }
1973 #endif /* X11 */
1974
1975 #define CONF_ERR NORM_ERR("%s: %d: config file error", f, line)
1976 #define CONF_ERR2(a) NORM_ERR("%s: %d: config file error: %s", f, line, a)
1977 #define CONF2(a) if (strcasecmp(name, a) == 0)
1978 #define CONF(a) else CONF2(a)
1979 #define CONF3(a, b) else if (strcasecmp(name, a) == 0 \
1980                 || strcasecmp(name, b) == 0)
1981 #define CONF_CONTINUE 1
1982 #define CONF_BREAK 2
1983 #define CONF_BUFF_SIZE 512
1984
1985 static FILE *open_config_file(const char *f)
1986 {
1987 #ifdef CONFIG_OUTPUT
1988         if (!strcmp(f, "==builtin==")) {
1989                 return conf_cookie_open();
1990         } else
1991 #endif /* CONFIG_OUTPUT */
1992                 return fopen(f, "r");
1993 }
1994
1995 static int do_config_step(int *line, FILE *fp, char *buf, char **name, char **value)
1996 {
1997         char *p, *p2;
1998         (*line)++;
1999         if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
2000                 return CONF_BREAK;
2001         }
2002         remove_comments(buf);
2003
2004         p = buf;
2005
2006         /* skip spaces */
2007         while (*p && isspace((int) *p)) {
2008                 p++;
2009         }
2010         if (*p == '\0') {
2011                 return CONF_CONTINUE;   /* empty line */
2012         }
2013
2014         *name = p;
2015
2016         /* skip name */
2017         p2 = p;
2018         while (*p2 && !isspace((int) *p2)) {
2019                 p2++;
2020         }
2021         if (*p2 != '\0') {
2022                 *p2 = '\0';     /* break at name's end */
2023                 p2++;
2024         }
2025
2026         /* get value */
2027         if (*p2) {
2028                 p = p2;
2029                 while (*p && isspace((int) *p)) {
2030                         p++;
2031                 }
2032
2033                 *value = p;
2034
2035                 p2 = *value + strlen(*value);
2036                 while (isspace((int) *(p2 - 1))) {
2037                         *--p2 = '\0';
2038                 }
2039         } else {
2040                 *value = 0;
2041         }
2042         return 0;
2043 }
2044
2045 char load_config_file(conky_context *ctx, const char *f)
2046 {
2047         int line = 0;
2048         FILE *fp;
2049
2050         fp = open_config_file(f);
2051         if (!fp) {
2052                 return FALSE;
2053         }
2054         DBGP("reading contents from config file '%s'", f);
2055
2056         while (!feof(fp)) {
2057                 char buff[CONF_BUFF_SIZE], *name, *value;
2058                 int ret = do_config_step(&line, fp, buff, &name, &value);
2059                 if (ret == CONF_BREAK) {
2060                         break;
2061                 } else if (ret == CONF_CONTINUE) {
2062                         continue;
2063                 }
2064
2065 #ifdef X11
2066                 CONF2("out_to_x") {
2067                         /* don't listen if X is already initialised or
2068                          * if we already know we don't want it */
2069                         if(x_initialised != YES) {
2070                                 if (string_to_bool(value)) {
2071                                         ctx->output_methods &= TO_X;
2072                                 } else {
2073                                         ctx->output_methods &= ~TO_X;
2074                                         x_initialised = NEVER;
2075                                 }
2076                         }
2077                 }
2078                 CONF("display") {
2079                         if (!value || x_initialised == YES) {
2080                                 CONF_ERR;
2081                         } else {
2082                                 if (disp)
2083                                         free(disp);
2084                                 disp = strdup(value);
2085                         }
2086                 }
2087                 CONF("alignment") {
2088 #ifdef OWN_WINDOW
2089                         if (window.type == TYPE_DOCK)
2090                                 ;
2091                         else
2092 #endif /*OWN_WINDOW */
2093                         if (value) {
2094                                 int a = string_to_alignment(value);
2095
2096                                 if (a <= 0) {
2097                                         CONF_ERR;
2098                                 } else {
2099                                         text_alignment = a;
2100                                 }
2101                         } else {
2102                                 CONF_ERR;
2103                         }
2104                 }
2105                 CONF("background") {
2106                         fork_to_background = string_to_bool(value);
2107                 }
2108 #else
2109                 CONF2("background") {
2110                         fork_to_background = string_to_bool(value);
2111                 }
2112 #endif /* X11 */
2113 #ifdef X11
2114                 CONF("show_graph_scale") {
2115                         show_graph_scale = string_to_bool(value);
2116                 }
2117                 CONF("show_graph_range") {
2118                         show_graph_range = string_to_bool(value);
2119                 }
2120                 CONF("border_inner_margin") {
2121                         if (value) {
2122                                 window.border_inner_margin = strtol(value, 0, 0);
2123                                 if (window.border_inner_margin < 0) window.border_inner_margin = 0;
2124                         } else {
2125                                 CONF_ERR;
2126                         }
2127                 }
2128                 CONF("border_outer_margin") {
2129                         if (value) {
2130                                 window.border_outer_margin = strtol(value, 0, 0);
2131                                 if (window.border_outer_margin < 0) window.border_outer_margin = 0;
2132                         } else {
2133                                 CONF_ERR;
2134                         }
2135                 }
2136                 CONF("border_width") {
2137                         if (value) {
2138                                 window.border_width = strtol(value, 0, 0);
2139                                 if (window.border_width < 0) window.border_width = 0;
2140                         } else {
2141                                 CONF_ERR;
2142                         }
2143                 }
2144 #endif /* X11 */
2145 #define TEMPLATE_CONF(n) \
2146                 CONF("template"#n) { \
2147                         if (value) { \
2148                                 free(template[n]); \
2149                                 template[n] = strdup(value); \
2150                         } else { \
2151                                 CONF_ERR; \
2152                         } \
2153                 }
2154                 TEMPLATE_CONF(0)
2155                 TEMPLATE_CONF(1)
2156                 TEMPLATE_CONF(2)
2157                 TEMPLATE_CONF(3)
2158                 TEMPLATE_CONF(4)
2159                 TEMPLATE_CONF(5)
2160                 TEMPLATE_CONF(6)
2161                 TEMPLATE_CONF(7)
2162                 TEMPLATE_CONF(8)
2163                 TEMPLATE_CONF(9)
2164                 CONF("imap") {
2165                         if (value) {
2166                                 ctx->info.mail = parse_mail_args(IMAP_TYPE, value);
2167                         } else {
2168                                 CONF_ERR;
2169                         }
2170                 }
2171                 CONF("pop3") {
2172                         if (value) {
2173                                 ctx->info.mail = parse_mail_args(POP3_TYPE, value);
2174                         } else {
2175                                 CONF_ERR;
2176                         }
2177                 }
2178                 CONF("default_bar_size") {
2179                         char err = 0;
2180                         if (value) {
2181                                 if (sscanf(value, "%d %d", &default_bar_width, &default_bar_height) != 2) {
2182                                         err = 1;
2183                                 }
2184                         } else {
2185                                 err = 1;
2186                         }
2187                         if (err) {
2188                                 CONF_ERR2("default_bar_size takes 2 integer arguments (ie. 'default_bar_size 0 6')")
2189                         }
2190                 }
2191 #ifdef X11
2192                 CONF("default_graph_size") {
2193                         char err = 0;
2194                         if (value) {
2195                                 if (sscanf(value, "%d %d", &default_graph_width, &default_graph_height) != 2) {
2196                                         err = 1;
2197                                 }
2198                         } else {
2199                                 err = 1;
2200                         }
2201                         if (err) {
2202                                 CONF_ERR2("default_graph_size takes 2 integer arguments (ie. 'default_graph_size 0 6')")
2203                         }
2204                 }
2205                 CONF("default_gauge_size") {
2206                         char err = 0;
2207                         if (value) {
2208                                 if (sscanf(value, "%d %d", &default_gauge_width, &default_gauge_height) != 2) {
2209                                         err = 1;
2210                                 }
2211                         } else {
2212                                 err = 1;
2213                         }
2214                         if (err) {
2215                                 CONF_ERR2("default_gauge_size takes 2 integer arguments (ie. 'default_gauge_size 0 6')")
2216                         }
2217                 }
2218 #endif
2219 #ifdef MPD
2220                 CONF("mpd_host") {
2221                         if (value) {
2222                                 mpd_set_host(value);
2223                         } else {
2224                                 CONF_ERR;
2225                         }
2226                 }
2227                 CONF("mpd_port") {
2228                         if (value && mpd_set_port(value)) {
2229                                 CONF_ERR;
2230                         }
2231                 }
2232                 CONF("mpd_password") {
2233                         if (value) {
2234                                 mpd_set_password(value, 0);
2235                         } else {
2236                                 CONF_ERR;
2237                         }
2238                 }
2239 #endif
2240                 CONF("music_player_interval") {
2241                         if (value) {
2242                                 ctx->info.music_player_interval = strtod(value, 0);
2243                         } else {
2244                                 CONF_ERR;
2245                         }
2246                 }
2247 #ifdef __OpenBSD__
2248                 CONF("sensor_device") {
2249                         if (value) {
2250                                 sensor_device = strtol(value, 0, 0);
2251                         } else {
2252                                 CONF_ERR;
2253                         }
2254                 }
2255 #endif
2256                 CONF("cpu_avg_samples") {
2257                         if (value) {
2258                                 cpu_avg_samples = strtol(value, 0, 0);
2259                                 if (cpu_avg_samples < 1 || cpu_avg_samples > 14) {
2260                                         CONF_ERR;
2261                                 } else {
2262                                         ctx->info.cpu_avg_samples = cpu_avg_samples;
2263                                 }
2264                         } else {
2265                                 CONF_ERR;
2266                         }
2267                 }
2268                 CONF("net_avg_samples") {
2269                         if (value) {
2270                                 net_avg_samples = strtol(value, 0, 0);
2271                                 if (net_avg_samples < 1 || net_avg_samples > 14) {
2272                                         CONF_ERR;
2273                                 } else {
2274                                         ctx->info.net_avg_samples = net_avg_samples;
2275                                 }
2276                         } else {
2277                                 CONF_ERR;
2278                         }
2279                 }
2280                 CONF("diskio_avg_samples") {
2281                         if (value) {
2282                                 diskio_avg_samples = strtol(value, 0, 0);
2283                                 if (diskio_avg_samples < 1 || diskio_avg_samples > 14) {
2284                                         CONF_ERR;
2285                                 } else {
2286                                         ctx->info.diskio_avg_samples = diskio_avg_samples;
2287                                 }
2288                         } else {
2289                                 CONF_ERR;
2290                         }
2291                 }
2292
2293 #ifdef HAVE_XDBE
2294                 CONF("double_buffer") {
2295                         use_xdbe = string_to_bool(value);
2296                 }
2297 #endif
2298 #ifdef X11
2299                 CONF("override_utf8_locale") {
2300                         utf8_mode = string_to_bool(value);
2301                 }
2302                 CONF("draw_borders") {
2303                         draw_borders = string_to_bool(value);
2304                 }
2305                 CONF("draw_graph_borders") {
2306                         draw_graph_borders = string_to_bool(value);
2307                 }
2308                 CONF("draw_shades") {
2309                         draw_shades = string_to_bool(value);
2310                 }
2311                 CONF("draw_outline") {
2312                         draw_outline = string_to_bool(value);
2313                 }
2314 #endif /* X11 */
2315                 CONF("out_to_console") {
2316                         if(string_to_bool(value)) {
2317                                 ctx->output_methods |= TO_STDOUT;
2318                         } else {
2319                                 ctx->output_methods &= ~TO_STDOUT;
2320                         }
2321                 }
2322                 CONF("extra_newline") {
2323                         extra_newline = string_to_bool(value);
2324                 }
2325                 CONF("out_to_stderr") {
2326                         if(string_to_bool(value))
2327                                 ctx->output_methods |= TO_STDERR;
2328                 }
2329 #ifdef NCURSES
2330                 CONF("out_to_ncurses") {
2331                         if(string_to_bool(value)) {
2332                                 initscr();
2333                                 start_color();
2334                                 ctx->output_methods |= TO_NCURSES;
2335                         }
2336                 }
2337 #endif
2338                 CONF("overwrite_file") {
2339                         if(overwrite_file) {
2340                                 free(overwrite_file);
2341                                 overwrite_file = 0;
2342                         }
2343                         if(overwrite_works(value)) {
2344                                 overwrite_file = strdup(value);
2345                                 ctx->output_methods |= OVERWRITE_FILE;
2346                         } else
2347                                 NORM_ERR("overwrite_file won't be able to create/overwrite '%s'", value);
2348                 }
2349                 CONF("append_file") {
2350                         if(append_file) {
2351                                 free(append_file);
2352                                 append_file = 0;
2353                         }
2354                         if(append_works(value)) {
2355                                 append_file = strdup(value);
2356                                 ctx->output_methods |= APPEND_FILE;
2357                         } else
2358                                 NORM_ERR("append_file won't be able to create/append '%s'", value);
2359                 }
2360                 CONF("use_spacer") {
2361                         if (value) {
2362                                 if (strcasecmp(value, "left") == EQUAL) {
2363                                         use_spacer = LEFT_SPACER;
2364                                 } else if (strcasecmp(value, "right") == EQUAL) {
2365                                         use_spacer = RIGHT_SPACER;
2366                                 } else if (strcasecmp(value, "none") == EQUAL) {
2367                                         use_spacer = NO_SPACER;
2368                                 } else {
2369                                         use_spacer = string_to_bool(value);
2370                                         NORM_ERR("use_spacer should have an argument of left, right, or"
2371                                                 " none.  '%s' seems to be some form of '%s', so"
2372                                                 " defaulting to %s.", value,
2373                                                 use_spacer ? "true" : "false",
2374                                                 use_spacer ? "right" : "none");
2375                                         if (use_spacer) {
2376                                                 use_spacer = RIGHT_SPACER;
2377                                         } else {
2378                                                 use_spacer = NO_SPACER;
2379                                         }
2380                                 }
2381                         } else {
2382                                 NORM_ERR("use_spacer should have an argument. Defaulting to right.");
2383                                 use_spacer = RIGHT_SPACER;
2384                         }
2385                 }
2386 #ifdef X11
2387 #ifdef XFT
2388                 CONF("use_xft") {
2389                         use_xft = string_to_bool(value);
2390                 }
2391                 CONF("font") {
2392                         if (value) {
2393                                 set_first_font(value);
2394                         }
2395                 }
2396                 CONF("xftalpha") {
2397                         if (value && font_count >= 0) {
2398                                 ctx->fonts[0].font_alpha = atof(value) * 65535.0;
2399                         }
2400                 }
2401                 CONF("xftfont") {
2402                         if (use_xft) {
2403 #else
2404                 CONF("use_xft") {
2405                         if (string_to_bool(value)) {
2406                                 NORM_ERR("Xft not enabled at compile time");
2407                         }
2408                 }
2409                 CONF("xftfont") {
2410                         /* xftfont silently ignored when no Xft */
2411                 }
2412                 CONF("xftalpha") {
2413                         /* xftalpha is silently ignored when no Xft */
2414                 }
2415                 CONF("font") {
2416 #endif
2417                         if (value) {
2418                                 set_first_font(value);
2419                         }
2420 #ifdef XFT
2421                         }
2422 #endif
2423                 }
2424                 CONF("gap_x") {
2425                         if (value) {
2426                                 gap_x = atoi(value);
2427                         } else {
2428                                 CONF_ERR;
2429                         }
2430                 }
2431                 CONF("gap_y") {
2432                         if (value) {
2433                                 gap_y = atoi(value);
2434                         } else {
2435                                 CONF_ERR;
2436                         }
2437                 }
2438 #endif /* X11 */
2439                 CONF("mail_spool") {
2440                         if (value) {
2441                                 char buffer[256];
2442
2443                                 variable_substitute(value, buffer, 256);
2444
2445                                 if (buffer[0] != '\0') {
2446                                         if (current_mail_spool) {
2447                                                 free(current_mail_spool);
2448                                         }
2449                                         current_mail_spool = strndup(buffer, text_buffer_size);
2450                                 }
2451                         } else {
2452                                 CONF_ERR;
2453                         }
2454                 }
2455 #ifdef X11
2456                 CONF("minimum_size") {
2457                         if (value) {
2458                                 if (sscanf(value, "%d %d", &minimum_width, &minimum_height)
2459                                                 != 2) {
2460                                         if (sscanf(value, "%d", &minimum_width) != 1) {
2461                                                 CONF_ERR;
2462                                         }
2463                                 }
2464                         } else {
2465                                 CONF_ERR;
2466                         }
2467                 }
2468                 CONF("maximum_width") {
2469                         if (value) {
2470                                 if (sscanf(value, "%d", &maximum_width) != 1) {
2471                                         CONF_ERR;
2472                                 }
2473                         } else {
2474                                 CONF_ERR;
2475                         }
2476                 }
2477 #endif /* X11 */
2478                 CONF("no_buffers") {
2479                         no_buffers = string_to_bool(value);
2480                 }
2481                 CONF("top_name_width") {
2482                         if (value) {
2483                                 if (sscanf(value, "%u", &top_name_width) != 1) {
2484                                         CONF_ERR;
2485                                 }
2486                         } else {
2487                                 CONF_ERR;
2488                         }
2489                         if (top_name_width >= max_user_text) {
2490                                 top_name_width = max_user_text - 1;
2491                         }
2492                 }
2493                 CONF("top_cpu_separate") {
2494                         cpu_separate = string_to_bool(value);
2495                 }
2496                 CONF("short_units") {
2497                         short_units = string_to_bool(value);
2498                 }
2499                 CONF("format_human_readable") {
2500                         format_human_readable = string_to_bool(value);
2501                 }
2502                 CONF("pad_percents") {
2503                         pad_percents = atoi(value);
2504                 }
2505 #ifdef X11
2506 #ifdef OWN_WINDOW
2507                 CONF("own_window") {
2508                         if (value) {
2509                                 own_window = string_to_bool(value);
2510                         }
2511                 }
2512                 CONF("own_window_class") {
2513                         if (value) {
2514                                 memset(window.class_name, 0, sizeof(window.class_name));
2515                                 strncpy(window.class_name, value,
2516                                                 sizeof(window.class_name) - 1);
2517                         }
2518                 }
2519                 CONF("own_window_title") {
2520                         if (value) {
2521                                 memset(window.title, 0, sizeof(window.title));
2522                                 strncpy(window.title, value, sizeof(window.title) - 1);
2523                         }
2524                 }
2525                 CONF("own_window_transparent") {
2526                         if (value) {
2527                                 set_transparent = string_to_bool(value);
2528                         }
2529                 }
2530                 CONF("own_window_hints") {
2531                         if (value) {
2532                                 char *p_hint, *p_save;
2533                                 char delim[] = ", ";
2534
2535                                 /* tokenize the value into individual hints */
2536                                 if ((p_hint = strtok_r(value, delim, &p_save)) != NULL) {
2537                                         do {
2538                                                 /* fprintf(stderr, "hint [%s] parsed\n", p_hint); */
2539                                                 if (strncmp(p_hint, "undecorate", 10) == EQUAL) {
2540                                                         SET_HINT(window.hints, HINT_UNDECORATED);
2541                                                 } else if (strncmp(p_hint, "below", 5) == EQUAL) {
2542                                                         SET_HINT(window.hints, HINT_BELOW);
2543                                                 } else if (strncmp(p_hint, "above", 5) == EQUAL) {
2544                                                         SET_HINT(window.hints, HINT_ABOVE);
2545                                                 } else if (strncmp(p_hint, "sticky", 6) == EQUAL) {
2546                                                         SET_HINT(window.hints, HINT_STICKY);
2547                                                 } else if (strncmp(p_hint, "skip_taskbar", 12) == EQUAL) {
2548                                                         SET_HINT(window.hints, HINT_SKIP_TASKBAR);
2549                                                 } else if (strncmp(p_hint, "skip_pager", 10) == EQUAL) {
2550                                                         SET_HINT(window.hints, HINT_SKIP_PAGER);
2551                                                 } else {
2552                                                         CONF_ERR;
2553                                                 }
2554
2555                                                 p_hint = strtok_r(NULL, delim, &p_save);
2556                                         } while (p_hint != NULL);
2557                                 }
2558                         } else {
2559                                 CONF_ERR;
2560                         }
2561                 }
2562                 CONF("own_window_type") {
2563                         if (value) {
2564                                 if (strncmp(value, "normal", 6) == EQUAL) {
2565                                         window.type = TYPE_NORMAL;
2566                                 } else if (strncmp(value, "desktop", 7) == EQUAL) {
2567                                         window.type = TYPE_DESKTOP;
2568                                 } else if (strncmp(value, "dock", 4) == EQUAL) {
2569                                         window.type = TYPE_DOCK;
2570                                         text_alignment = TOP_LEFT;
2571                                 } else if (strncmp(value, "panel", 5) == EQUAL) {
2572                                         window.type = TYPE_PANEL;
2573                                 } else if (strncmp(value, "override", 8) == EQUAL) {
2574                                         window.type = TYPE_OVERRIDE;
2575                                 } else {
2576                                         CONF_ERR;
2577                                 }
2578                         } else {
2579                                 CONF_ERR;
2580                         }
2581                 }
2582 #endif
2583                 CONF("stippled_borders") {
2584                         if (value) {
2585                                 stippled_borders = strtol(value, 0, 0);
2586                         } else {
2587                                 stippled_borders = 4;
2588                         }
2589                 }
2590 #ifdef IMLIB2
2591                 CONF("imlib_cache_size") {
2592                         if (value) {
2593                                 cimlib_set_cache_size(atoi(value));
2594                         }
2595                 }
2596                 CONF("imlib_cache_flush_interval") {
2597                         if (value) {
2598                                 cimlib_set_cache_flush_interval(atoi(value));
2599                         }
2600                 }
2601 #endif /* IMLIB2 */
2602 #endif /* X11 */
2603                 CONF("update_interval_on_battery") {
2604                         if (value) {
2605                                 update_interval_bat = strtod(value, 0);
2606                         } else {
2607                                 CONF_ERR;
2608                         }
2609                 }
2610                 CONF("update_interval") {
2611                         if (value) {
2612                                 set_update_interval(strtod(value, 0));
2613                         } else {
2614                                 CONF_ERR;
2615                         }
2616                         if (ctx->info.music_player_interval == 0) {
2617                                 // default to update_interval
2618                                 ctx->info.music_player_interval = ctx->update_interval;
2619                         }
2620                 }
2621                 CONF("total_run_times") {
2622                         if (value) {
2623                                 ctx->total_run_times = strtod(value, 0);
2624                         } else {
2625                                 CONF_ERR;
2626                         }
2627                 }
2628                 CONF("uppercase") {
2629                         stuff_in_uppercase = string_to_bool(value);
2630                 }
2631                 CONF("max_specials") {
2632                         if (value) {
2633                                 max_specials = atoi(value);
2634                         } else {
2635                                 CONF_ERR;
2636                         }
2637                 }
2638                 CONF("max_user_text") {
2639                         if (value) {
2640                                 max_user_text = atoi(value);
2641                         } else {
2642                                 CONF_ERR;
2643                         }
2644                 }
2645                 CONF("text_buffer_size") {
2646                         if (value) {
2647                                 text_buffer_size = atoi(value);
2648                                 if (text_buffer_size < DEFAULT_TEXT_BUFFER_SIZE) {
2649                                         NORM_ERR("text_buffer_size must be >=%i bytes", DEFAULT_TEXT_BUFFER_SIZE);
2650                                         text_buffer_size = DEFAULT_TEXT_BUFFER_SIZE;
2651                                 }
2652                         } else {
2653                                 CONF_ERR;
2654                         }
2655                 }
2656                 CONF("text") {
2657 #ifdef X11
2658                         if (ctx->output_methods & TO_X) {
2659                                 X11_initialisation();
2660                         }
2661 #endif
2662
2663                         if (global_text) {
2664                                 free(global_text);
2665                                 global_text = 0;
2666                         }
2667
2668                         global_text = (char *) malloc(1);
2669                         global_text[0] = '\0';
2670
2671                         while (!feof(fp)) {
2672                                 unsigned int l = strlen(global_text);
2673                                 unsigned int bl;
2674                                 char buf[CONF_BUFF_SIZE];
2675
2676                                 if (fgets(buf, CONF_BUFF_SIZE, fp) == NULL) {
2677                                         break;
2678                                 }
2679
2680                                 /* Remove \\-\n. */
2681                                 bl = strlen(buf);
2682                                 if (bl >= 2 && buf[bl-2] == '\\' && buf[bl-1] == '\n') {
2683                                         buf[bl-2] = '\0';
2684                                         bl -= 2;
2685                                         if (bl == 0) {
2686                                                 continue;
2687                                         }
2688                                 }
2689
2690                                 /* Check for continuation of \\-\n. */
2691                                 if (l > 0 && buf[0] == '\n' && global_text[l-1] == '\\') {
2692                                         global_text[l-1] = '\0';
2693                                         continue;
2694                                 }
2695
2696                                 global_text = (char *) realloc(global_text, l + bl + 1);
2697                                 strcat(global_text, buf);
2698
2699                                 if (strlen(global_text) > max_user_text) {
2700                                         break;
2701                                 }
2702                         }
2703                         fclose(fp);
2704                         if (strlen(global_text) < 1) {
2705                                 CRIT_ERR(NULL, NULL, "no text supplied in configuration; exiting");
2706                         }
2707                         global_text_lines = line + 1;
2708                         return TRUE;
2709                 }
2710 #ifdef TCP_PORT_MONITOR
2711                 CONF("max_port_monitor_connections") {
2712                         int max;
2713                         if (!value || (sscanf(value, "%d", &max) != 1)) {
2714                                 /* an error. use default, warn and continue. */
2715                                 tcp_portmon_set_max_connections(0);
2716                                 CONF_ERR;
2717                         } else if (tcp_portmon_set_max_connections(max)) {
2718                                 /* max is < 0, default has been set*/
2719                                 CONF_ERR;
2720                         }
2721                 }
2722 #endif
2723                 CONF("if_up_strictness") {
2724                         if (!value) {
2725                                 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
2726                                 ifup_strictness = IFUP_UP;
2727                         } else if (strcasecmp(value, "up") == EQUAL) {
2728                                 ifup_strictness = IFUP_UP;
2729                         } else if (strcasecmp(value, "link") == EQUAL) {
2730                                 ifup_strictness = IFUP_LINK;
2731                         } else if (strcasecmp(value, "address") == EQUAL) {
2732                                 ifup_strictness = IFUP_ADDR;
2733                         } else {
2734                                 NORM_ERR("incorrect if_up_strictness value, defaulting to 'up'");
2735                                 ifup_strictness = IFUP_UP;
2736                         }
2737                 }
2738
2739                 CONF("temperature_unit") {
2740                         if (!value) {
2741                                 NORM_ERR("config option 'temperature_unit' needs an argument, either 'celsius' or 'fahrenheit'");
2742                         } else if (set_temp_output_unit(value)) {
2743                                 NORM_ERR("temperature_unit: incorrect argument");
2744                         }
2745                 }
2746
2747 #ifdef HAVE_LUA
2748                 CONF("lua_load") {
2749                         if (value) {
2750                                 char *ptr = strtok(value, " ");
2751                                 while (ptr) {
2752                                         llua_load(ptr);
2753                                         ptr = strtok(NULL, " ");
2754                                 }
2755                         } else {
2756                                 CONF_ERR;
2757                         }
2758                 }
2759 #ifdef X11
2760                 CONF("lua_draw_hook_pre") {
2761                         if (value) {
2762                                 llua_set_draw_pre_hook(value);
2763                         } else {
2764                                 CONF_ERR;
2765                         }
2766                 }
2767                 CONF("lua_draw_hook_post") {
2768                         if (value) {
2769                                 llua_set_draw_post_hook(value);
2770                         } else {
2771                                 CONF_ERR;
2772                         }
2773                 }
2774                 CONF("lua_startup_hook") {
2775                         if (value) {
2776                                 llua_set_startup_hook(value);
2777                         } else {
2778                                 CONF_ERR;
2779                         }
2780                 }
2781                 CONF("lua_shutdown_hook") {
2782                         if (value) {
2783                                 llua_set_shutdown_hook(value);
2784                         } else {
2785                                 CONF_ERR;
2786                         }
2787                 }
2788 #endif /* X11 */
2789 #endif /* HAVE_LUA */
2790
2791                 CONF("color0"){}
2792                 CONF("color1"){}
2793                 CONF("color2"){}
2794                 CONF("color3"){}
2795                 CONF("color4"){}
2796                 CONF("color5"){}
2797                 CONF("color6"){}
2798                 CONF("color7"){}
2799                 CONF("color8"){}
2800                 CONF("color9"){}
2801                 CONF("default_color"){}
2802                 CONF3("default_shade_color", "default_shadecolor"){}
2803                 CONF3("default_outline_color", "default_outlinecolor") {}
2804                 CONF("own_window_colour") {}
2805
2806                 else {
2807                         NORM_ERR("%s: %d: no such configuration: '%s'", f, line, name);
2808                 }
2809         }
2810
2811         fclose(fp);
2812
2813         if (ctx->info.music_player_interval == 0) {
2814                 // default to update_interval
2815                 ctx->info.music_player_interval = ctx->update_interval;
2816         }
2817         if (!global_text) { // didn't supply any text
2818                 CRIT_ERR(NULL, NULL, "missing text block in configuration; exiting");
2819         }
2820         return TRUE;
2821 }
2822
2823 #ifdef X11
2824 void load_config_file_x11(conky_context *ctx, const char *f)
2825 {
2826         int line = 0;
2827         FILE *fp;
2828
2829         fp = open_config_file(f);
2830         if (!fp) {
2831                 return;
2832         }
2833         DBGP("reading contents from config file '%s'", f);
2834
2835         while (!feof(fp)) {
2836                 char buff[CONF_BUFF_SIZE], *name, *value;
2837                 int ret = do_config_step(&line, fp, buff, &name, &value);
2838                 if (ret == CONF_BREAK) {
2839                         break;
2840                 } else if (ret == CONF_CONTINUE) {
2841                         continue;
2842                 }
2843
2844                 CONF2("color0") {
2845                         X11_initialisation();
2846                         if (x_initialised == YES) {
2847                                 if (value) {
2848                                         color0 = get_x11_color(value);
2849                                 } else {
2850                                         CONF_ERR;
2851                                 }
2852                         }
2853                 }
2854                 CONF("color1") {
2855                         X11_initialisation();
2856                         if (x_initialised == YES) {
2857                                 if (value) {
2858                                         color1 = get_x11_color(value);
2859                                 } else {
2860                                         CONF_ERR;
2861                                 }
2862                         }
2863                 }
2864                 CONF("color2") {
2865                         X11_initialisation();
2866                         if (x_initialised == YES) {
2867                                 if (value) {
2868                                         color2 = get_x11_color(value);
2869                                 } else {
2870                                         CONF_ERR;
2871                                 }
2872                         }
2873                 }
2874                 CONF("color3") {
2875                         X11_initialisation();
2876                         if (x_initialised == YES) {
2877                                 if (value) {
2878                                         color3 = get_x11_color(value);
2879                                 } else {
2880                                         CONF_ERR;
2881                                 }
2882                         }
2883                 }
2884                 CONF("color4") {
2885                         X11_initialisation();
2886                         if (x_initialised == YES) {
2887                                 if (value) {
2888                                         color4 = get_x11_color(value);
2889                                 } else {
2890                                         CONF_ERR;
2891                                 }
2892                         }
2893                 }
2894                 CONF("color5") {
2895                         X11_initialisation();
2896                         if (x_initialised == YES) {
2897                                 if (value) {
2898                                         color5 = get_x11_color(value);
2899                                 } else {
2900                                         CONF_ERR;
2901                                 }
2902                         }
2903                 }
2904                 CONF("color6") {
2905                         X11_initialisation();
2906                         if (x_initialised == YES) {
2907                                 if (value) {
2908                                         color6 = get_x11_color(value);
2909                                 } else {
2910                                         CONF_ERR;
2911                                 }
2912                         }
2913                 }
2914                 CONF("color7") {
2915                         X11_initialisation();
2916                         if (x_initialised == YES) {
2917                                 if (value) {
2918                                         color7 = get_x11_color(value);
2919                                 } else {
2920                                         CONF_ERR;
2921                                 }
2922                         }
2923                 }
2924                 CONF("color8") {
2925                         X11_initialisation();
2926                         if (x_initialised == YES) {
2927                                 if (value) {
2928                                         color8 = get_x11_color(value);
2929                                 } else {
2930                                         CONF_ERR;
2931                                 }
2932                         }
2933                 }
2934                 CONF("color9") {
2935                         X11_initialisation();
2936                         if (x_initialised == YES) {
2937                                 if (value) {
2938                                         color9 = get_x11_color(value);
2939                                 } else {
2940                                         CONF_ERR;
2941                                 }
2942                         }
2943                 }
2944                 CONF("default_color") {
2945                         X11_initialisation();
2946                         if (x_initialised == YES) {
2947                                 if (value) {
2948                                         default_fg_color = get_x11_color(value);
2949                                 } else {
2950                                         CONF_ERR;
2951                                 }
2952                         }
2953                 }
2954                 CONF3("default_shade_color", "default_shadecolor") {
2955                         X11_initialisation();
2956                         if (x_initialised == YES) {
2957                                 if (value) {
2958                                         default_bg_color = get_x11_color(value);
2959                                 } else {
2960                                         CONF_ERR;
2961                                 }
2962                         }
2963                 }
2964                 CONF3("default_outline_color", "default_outlinecolor") {
2965                         X11_initialisation();
2966                         if (x_initialised == YES) {
2967                                 if (value) {
2968                                         default_out_color = get_x11_color(value);
2969                                 } else {
2970                                         CONF_ERR;
2971                                 }
2972                         }
2973                 }
2974 #ifdef OWN_WINDOW
2975                 CONF("own_window_colour") {
2976                         X11_initialisation();
2977                         if (x_initialised == YES) {
2978                                 if (value) {
2979                                         background_colour = get_x11_color(value);
2980                                 } else {
2981                                         NORM_ERR("Invalid colour for own_window_colour (try omitting the "
2982                                                 "'#' for hex colours");
2983                                 }
2984                         }
2985                 }
2986 #endif
2987                 CONF("text") {
2988                         /* initialize X11 if nothing X11-related is mentioned before TEXT (and if X11 is the default outputmethod) */
2989                         if (ctx->output_methods & TO_X) {
2990                                 X11_initialisation();
2991                         }
2992                 }
2993 #undef CONF
2994 #undef CONF2
2995 #undef CONF3
2996 #undef CONF_ERR
2997 #undef CONF_ERR2
2998 #undef CONF_BREAK
2999 #undef CONF_CONTINUE
3000 #undef CONF_BUFF_SIZE
3001         }
3002
3003         fclose(fp);
3004
3005 }
3006 #endif /* X11 */
3007