xref: /openbsd-src/usr.bin/tmux/style.c (revision 9f11ffb7133c203312a01e4b986886bc88c7d74b)
1 /* $OpenBSD: style.c,v 1.14 2017/03/22 07:16:54 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
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, fg, bg, attr, flags;
35 	size_t			end;
36 
37 	if (*in == '\0')
38 		return (0);
39 	if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
40 		return (-1);
41 	memcpy(&savedgc, gc, sizeof savedgc);
42 
43 	fg = gc->fg;
44 	bg = gc->bg;
45 	attr = gc->attr;
46 	flags = gc->flags;
47 	do {
48 		end = strcspn(in, delimiters);
49 		if (end > (sizeof tmp) - 1)
50 			goto error;
51 		memcpy(tmp, in, end);
52 		tmp[end] = '\0';
53 
54 		if (strcasecmp(tmp, "default") == 0) {
55 			fg = defgc->fg;
56 			bg = defgc->bg;
57 			attr = defgc->attr;
58 			flags = defgc->flags;
59 		} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
60 			if ((val = colour_fromstring(tmp + 3)) == -1)
61 				goto error;
62 			if (*in == 'f' || *in == 'F') {
63 				if (val != 8)
64 					fg = val;
65 				else
66 					fg = defgc->fg;
67 			} else if (*in == 'b' || *in == 'B') {
68 				if (val != 8)
69 					bg = val;
70 				else
71 					bg = defgc->bg;
72 			} else
73 				goto error;
74 		} else if (strcasecmp(tmp, "none") == 0)
75 			attr = 0;
76 		else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
77 			if ((val = attributes_fromstring(tmp + 2)) == -1)
78 				goto error;
79 			attr &= ~val;
80 		} else {
81 			if ((val = attributes_fromstring(tmp)) == -1)
82 				goto error;
83 			attr |= val;
84 		}
85 
86 		in += end + strspn(in + end, delimiters);
87 	} while (*in != '\0');
88 	gc->fg = fg;
89 	gc->bg = bg;
90 	gc->attr = attr;
91 	gc->flags = flags;
92 
93 	return (0);
94 
95 error:
96 	memcpy(gc, &savedgc, sizeof *gc);
97 	return (-1);
98 }
99 
100 /* Convert style to a string. */
101 const char *
102 style_tostring(struct grid_cell *gc)
103 {
104 	int		 off = 0, comma = 0;
105 	static char	 s[256];
106 
107 	*s = '\0';
108 
109 	if (gc->fg != 8) {
110 		off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(gc->fg));
111 		comma = 1;
112 	}
113 
114 	if (gc->bg != 8) {
115 		off += xsnprintf(s + off, sizeof s - off, "%sbg=%s",
116 		    comma ? "," : "", colour_tostring(gc->bg));
117 		comma = 1;
118 	}
119 
120 	if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
121 		xsnprintf(s + off, sizeof s - off, "%s%s",
122 		    comma ? "," : "", attributes_tostring(gc->attr));
123 	}
124 
125 	if (*s == '\0')
126 		return ("default");
127 	return (s);
128 }
129 
130 /* Apply a style. */
131 void
132 style_apply(struct grid_cell *gc, struct options *oo, const char *name)
133 {
134 	const struct grid_cell	*gcp;
135 
136 	memcpy(gc, &grid_default_cell, sizeof *gc);
137 	gcp = options_get_style(oo, name);
138 	gc->fg = gcp->fg;
139 	gc->bg = gcp->bg;
140 	gc->attr |= gcp->attr;
141 }
142 
143 /* Apply a style, updating if default. */
144 void
145 style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
146 {
147 	const struct grid_cell	*gcp;
148 
149 	gcp = options_get_style(oo, name);
150 	if (gcp->fg != 8)
151 		gc->fg = gcp->fg;
152 	if (gcp->bg != 8)
153 		gc->bg = gcp->bg;
154 	if (gcp->attr != 0)
155 		gc->attr |= gcp->attr;
156 }
157 
158 /* Check if two styles are the same. */
159 int
160 style_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
161 {
162 	return (gc1->fg == gc2->fg &&
163 	    gc1->bg == gc2->bg &&
164 	    (gc1->flags & ~GRID_FLAG_PADDING) ==
165 	    (gc2->flags & ~GRID_FLAG_PADDING) &&
166 	    (gc1->attr & ~GRID_ATTR_CHARSET) ==
167 	    (gc2->attr & ~GRID_ATTR_CHARSET));
168 }
169