1 // vim:ts=4:sw=4:expandtab
2 #include <config.h>
3 #include <stdbool.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <fcntl.h>
10 #include <dirent.h>
11 #include <ctype.h>
12 
13 #include "i3status.h"
14 
15 /*
16  * Returns the correct color format for dzen (^fg(color)), xmobar (<fc=color>)
17  * or lemonbar (%{Fcolor})
18  *
19  */
color(const char * colorstr)20 char *color(const char *colorstr) {
21     static char colorbuf[32];
22     if (!cfg_getbool(cfg_general, "colors")) {
23         colorbuf[0] = '\0';
24         return colorbuf;
25     }
26     if (output_format == O_DZEN2)
27         (void)snprintf(colorbuf, sizeof(colorbuf), "^fg(%s)", cfg_getstr(cfg_general, colorstr));
28     else if (output_format == O_XMOBAR)
29         (void)snprintf(colorbuf, sizeof(colorbuf), "<fc=%s>", cfg_getstr(cfg_general, colorstr));
30     else if (output_format == O_LEMONBAR)
31         (void)snprintf(colorbuf, sizeof(colorbuf), "%%{F%s}", cfg_getstr(cfg_general, colorstr));
32     else if (output_format == O_TERM) {
33         /* The escape-sequence for color is <CSI><col>;1m (bright/bold
34          * output), where col is a 3-bit rgb-value with b in the
35          * least-significant bit. We round the given color to the
36          * nearist 3-bit-depth color and output the escape-sequence */
37         char *str = cfg_getstr(cfg_general, colorstr);
38         int col = strtol(str + 1, NULL, 16);
39         int r = (col & (0xFF << 0)) / 0x80;
40         int g = (col & (0xFF << 8)) / 0x8000;
41         int b = (col & (0xFF << 16)) / 0x800000;
42         col = (r << 2) | (g << 1) | b;
43         (void)snprintf(colorbuf, sizeof(colorbuf), "\033[3%d;1m", col);
44     }
45     return colorbuf;
46 }
47 
48 /*
49  * Some color formats (xmobar) require to terminate colors again
50  *
51  */
endcolor(void)52 char *endcolor(void) {
53     if (output_format == O_XMOBAR)
54         return "</fc>";
55     else if (output_format == O_TERM)
56         return "\033[0m";
57     else
58         return "";
59 }
60 
print_separator(const char * separator)61 void print_separator(const char *separator) {
62     if (output_format == O_I3BAR || strlen(separator) == 0)
63         return;
64 
65     if (output_format == O_DZEN2)
66         printf("^fg(%s)%s^fg()", cfg_getstr(cfg_general, "color_separator"), separator);
67     else if (output_format == O_XMOBAR)
68         printf("<fc=%s>%s</fc>", cfg_getstr(cfg_general, "color_separator"), separator);
69     else if (output_format == O_LEMONBAR)
70         printf("%%{F%s}%s%%{F-}", cfg_getstr(cfg_general, "color_separator"), separator);
71     else if (output_format == O_TERM)
72         printf("%s%s%s", color("color_separator"), separator, endcolor());
73     else if (output_format == O_NONE)
74         printf("%s", separator);
75 }
76 
77 /*
78  * The term-output hides the cursor. We call this on exit to reset that.
79  */
reset_cursor(void)80 void reset_cursor(void) {
81     printf("\033[?25h");
82 }
83 
84 /*
85  * Escapes ampersand, less-than, greater-than, single-quote, and double-quote
86  * characters with the corresponding Pango markup strings if markup is enabled.
87  * See the glib implementation:
88  * https://git.gnome.org/browse/glib/tree/glib/gmarkup.c?id=03db1f455b4265654e237d2ad55464b4113cba8a#n2142
89  *
90  */
maybe_escape_markup(char * text,char ** buffer)91 void maybe_escape_markup(char *text, char **buffer) {
92     if (markup_format == M_NONE) {
93         *buffer += sprintf(*buffer, "%s", text);
94         return;
95     }
96     for (; *text != '\0'; text++) {
97         switch (*text) {
98             case '&':
99                 *buffer += sprintf(*buffer, "%s", "&amp;");
100                 break;
101             case '<':
102                 *buffer += sprintf(*buffer, "%s", "&lt;");
103                 break;
104             case '>':
105                 *buffer += sprintf(*buffer, "%s", "&gt;");
106                 break;
107             case '\'':
108                 *buffer += sprintf(*buffer, "%s", "&apos;");
109                 break;
110             case '"':
111                 *buffer += sprintf(*buffer, "%s", "&quot;");
112                 break;
113             default:
114                 if ((0x1 <= *text && *text <= 0x8) ||
115                     (0xb <= *text && *text <= 0xc) ||
116                     (0xe <= *text && *text <= 0x1f)) {
117                     *buffer += sprintf(*buffer, "&#x%x;", *text);
118                 } else {
119                     *(*buffer)++ = *text;
120                 }
121                 break;
122         }
123     }
124 }
125 
126 /*
127  * remove leading spaces
128  */
ltrim(const char * s)129 char *ltrim(const char *s) {
130     while (isspace(*s))
131         ++s;
132     return sstrdup(s);
133 }
134 
135 /*
136  * remove trailing spaces
137  */
rtrim(const char * s)138 char *rtrim(const char *s) {
139     char *r = sstrdup(s);
140     if (r != NULL) {
141         char *fr = r + strlen(s) - 1;
142         while ((isspace(*fr) || *fr == 0) && fr >= r)
143             --fr;
144         *++fr = 0;
145     }
146     return r;
147 }
148 
149 /*
150  * remove leading & trailing spaces
151  */
trim(const char * s)152 char *trim(const char *s) {
153     char *r = rtrim(s);
154     char *f = ltrim(r);
155     free(r);
156     return f;
157 }