xref: /netbsd-src/external/bsd/tmux/dist/style.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5  * Copyright (c) 2014 Tiago Cunha <tcunha@users.sourceforge.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */
27 int
28 style_parse(const struct grid_cell *defgc, struct grid_cell *gc,
29     const char *in)
30 {
31 	struct grid_cell	savedgc;
32 	const char		delimiters[] = " ,";
33 	char			tmp[32];
34 	int			val;
35 	size_t			end;
36 	u_char			fg, bg, attr, flags;
37 
38 	if (*in == '\0')
39 		return (0);
40 	if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
41 		return (-1);
42 	memcpy(&savedgc, gc, sizeof savedgc);
43 
44 	fg = gc->fg;
45 	bg = gc->bg;
46 	attr = gc->attr;
47 	flags = gc->flags;
48 	do {
49 		end = strcspn(in, delimiters);
50 		if (end > (sizeof tmp) - 1)
51 			goto error;
52 		memcpy(tmp, in, end);
53 		tmp[end] = '\0';
54 
55 		if (strcasecmp(tmp, "default") == 0) {
56 			fg = defgc->fg;
57 			bg = defgc->bg;
58 			attr = defgc->attr;
59 			flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
60 			flags |=
61 			    defgc->flags & (GRID_FLAG_FG256|GRID_FLAG_BG256);
62 		} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
63 			if ((val = colour_fromstring(tmp + 3)) == -1)
64 				goto error;
65 			if (*in == 'f' || *in == 'F') {
66 				if (val != 8) {
67 					if (val & 0x100) {
68 						flags |= GRID_FLAG_FG256;
69 						val &= ~0x100;
70 					} else
71 						flags &= ~GRID_FLAG_FG256;
72 					fg = val;
73 				} else {
74 					fg = defgc->fg;
75 					flags &= ~GRID_FLAG_FG256;
76 					flags |= defgc->flags & GRID_FLAG_FG256;
77 				}
78 			} else if (*in == 'b' || *in == 'B') {
79 				if (val != 8) {
80 					if (val & 0x100) {
81 						flags |= GRID_FLAG_BG256;
82 						val &= ~0x100;
83 					} else
84 						flags &= ~GRID_FLAG_BG256;
85 					bg = val;
86 				} else {
87 					bg = defgc->bg;
88 					flags &= ~GRID_FLAG_BG256;
89 					flags |= defgc->flags & GRID_FLAG_BG256;
90 				}
91 			} else
92 				goto error;
93 		} else if (strcasecmp(tmp, "none") == 0)
94 			attr = 0;
95 		else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
96 			if ((val = attributes_fromstring(tmp + 2)) == -1)
97 				goto error;
98 			attr &= ~val;
99 		} else {
100 			if ((val = attributes_fromstring(tmp)) == -1)
101 				goto error;
102 			attr |= val;
103 		}
104 
105 		in += end + strspn(in + end, delimiters);
106 	} while (*in != '\0');
107 	gc->fg = fg;
108 	gc->bg = bg;
109 	gc->attr = attr;
110 	gc->flags = flags;
111 
112 	return (0);
113 
114 error:
115 	memcpy(gc, &savedgc, sizeof *gc);
116 	return (-1);
117 }
118 
119 /* Convert style to a string. */
120 const char *
121 style_tostring(struct grid_cell *gc)
122 {
123 	int		 c, off = 0, comma = 0;
124 	static char	 s[256];
125 
126 	*s = '\0';
127 
128 	if (gc->fg != 8 || gc->flags & GRID_FLAG_FG256) {
129 		if (gc->flags & GRID_FLAG_FG256)
130 			c = gc->fg | 0x100;
131 		else
132 			c = gc->fg;
133 		off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(c));
134 		comma = 1;
135 	}
136 
137 	if (gc->bg != 8 || gc->flags & GRID_FLAG_BG256) {
138 		if (gc->flags & GRID_FLAG_BG256)
139 			c = gc->bg | 0x100;
140 		else
141 			c = gc->bg;
142 		off += xsnprintf(s + off, sizeof s - off, "%sbg=%s",
143 		    comma ? "," : "", colour_tostring(c));
144 		comma = 1;
145 	}
146 
147 	if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
148 		xsnprintf(s + off, sizeof s - off, "%s%s",
149 		    comma ? "," : "", attributes_tostring(gc->attr));
150 	}
151 
152 	if (*s == '\0')
153 		return ("default");
154 	return (s);
155 }
156 
157 /* Synchronize new -style option with the old one. */
158 void
159 style_update_new(struct options *oo, const char *name, const char *newname)
160 {
161 	int			 value;
162 	struct grid_cell	*gc;
163 	struct options_entry	*o;
164 
165 	/* It's a colour or attribute, but with no -style equivalent. */
166 	if (newname == NULL)
167 		return;
168 
169 	o = options_find1(oo, newname);
170 	if (o == NULL)
171 		o = options_set_style(oo, newname, "default", 0);
172 	gc = &o->style;
173 
174 	o = options_find1(oo, name);
175 	if (o == NULL)
176 		o = options_set_number(oo, name, 8);
177 	value = o->num;
178 
179 	if (strstr(name, "-bg") != NULL)
180 		colour_set_bg(gc, value);
181 	else if (strstr(name, "-fg") != NULL)
182 		colour_set_fg(gc, value);
183 	else if (strstr(name, "-attr") != NULL)
184 		gc->attr = value;
185 }
186 
187 /* Synchronize all the old options with the new -style one. */
188 void
189 style_update_old(struct options *oo, const char *name, struct grid_cell *gc)
190 {
191 	char	newname[128];
192 	int	c, size;
193 
194 	size = strrchr(name, '-') - name;
195 
196 	if (gc->flags & GRID_FLAG_BG256)
197 		c = gc->bg | 0x100;
198 	else
199 		c = gc->bg;
200 	xsnprintf(newname, sizeof newname, "%.*s-bg", size, name);
201 	options_set_number(oo, newname, c);
202 
203 	if (gc->flags & GRID_FLAG_FG256)
204 		c = gc->fg | 0x100;
205 	else
206 		c = gc->fg;
207 	xsnprintf(newname, sizeof newname, "%.*s-fg", size, name);
208 	options_set_number(oo, newname, c);
209 
210 	xsnprintf(newname, sizeof newname, "%.*s-attr", size, name);
211 	options_set_number(oo, newname, gc->attr);
212 }
213 
214 /* Apply a style. */
215 void
216 style_apply(struct grid_cell *gc, struct options *oo, const char *name)
217 {
218 	struct grid_cell	*gcp;
219 
220 	memcpy(gc, &grid_default_cell, sizeof *gc);
221 	gcp = options_get_style(oo, name);
222 	if (gcp->flags & GRID_FLAG_FG256)
223 		colour_set_fg(gc, gcp->fg | 0x100);
224 	else
225 		colour_set_fg(gc, gcp->fg);
226 	if (gcp->flags & GRID_FLAG_BG256)
227 		colour_set_bg(gc, gcp->bg | 0x100);
228 	else
229 		colour_set_bg(gc, gcp->bg);
230 	gc->attr |= gcp->attr;
231 }
232 
233 /* Apply a style, updating if default. */
234 void
235 style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
236 {
237 	struct grid_cell	*gcp;
238 
239 	gcp = options_get_style(oo, name);
240 	if (gcp->fg != 8 || gcp->flags & GRID_FLAG_FG256) {
241 		if (gcp->flags & GRID_FLAG_FG256)
242 			colour_set_fg(gc, gcp->fg | 0x100);
243 		else
244 			colour_set_fg(gc, gcp->fg);
245 	}
246 	if (gcp->bg != 8 || gcp->flags & GRID_FLAG_BG256) {
247 		if (gcp->flags & GRID_FLAG_BG256)
248 			colour_set_bg(gc, gcp->bg | 0x100);
249 		else
250 			colour_set_bg(gc, gcp->bg);
251 	}
252 	if (gcp->attr != 0)
253 		gc->attr |= gcp->attr;
254 }
255 
256 /* Check if two styles are the same. */
257 int
258 style_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
259 {
260 	return gc1->fg == gc2->fg &&
261 		gc1->bg == gc2->bg &&
262 		(gc1->flags & ~GRID_FLAG_PADDING) ==
263 		(gc2->flags & ~GRID_FLAG_PADDING) &&
264 		(gc1->attr & ~GRID_ATTR_CHARSET) ==
265 		(gc2->attr & ~GRID_ATTR_CHARSET);
266 }
267