aboutsummaryrefslogtreecommitdiffstats
path: root/sway/criteria.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/criteria.c')
-rw-r--r--sway/criteria.c99
1 files changed, 56 insertions, 43 deletions
diff --git a/sway/criteria.c b/sway/criteria.c
index d2a5566f..e16b4fa8 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -1,9 +1,9 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdlib.h> 1#include <stdlib.h>
3#include <stdio.h> 2#include <stdio.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <strings.h> 4#include <strings.h>
6#include <pcre.h> 5#define PCRE2_CODE_UNIT_WIDTH 8
6#include <pcre2.h>
7#include "sway/criteria.h" 7#include "sway/criteria.h"
8#include "sway/tree/container.h" 8#include "sway/tree/container.h"
9#include "sway/config.h" 9#include "sway/config.h"
@@ -18,6 +18,7 @@
18bool criteria_is_empty(struct criteria *criteria) { 18bool criteria_is_empty(struct criteria *criteria) {
19 return !criteria->title 19 return !criteria->title
20 && !criteria->shell 20 && !criteria->shell
21 && !criteria->all
21 && !criteria->app_id 22 && !criteria->app_id
22 && !criteria->con_mark 23 && !criteria->con_mark
23 && !criteria->con_id 24 && !criteria->con_id
@@ -40,17 +41,19 @@ bool criteria_is_empty(struct criteria *criteria) {
40char *error = NULL; 41char *error = NULL;
41 42
42// Returns error string on failure or NULL otherwise. 43// Returns error string on failure or NULL otherwise.
43static bool generate_regex(pcre **regex, char *value) { 44static bool generate_regex(pcre2_code **regex, char *value) {
44 const char *reg_err; 45 int errorcode;
45 int offset; 46 PCRE2_SIZE offset;
46
47 *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, &reg_err, &offset, NULL);
48 47
48 *regex = pcre2_compile((PCRE2_SPTR)value, PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &offset, NULL);
49 if (!*regex) { 49 if (!*regex) {
50 PCRE2_UCHAR buffer[256];
51 pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
52
50 const char *fmt = "Regex compilation for '%s' failed: %s"; 53 const char *fmt = "Regex compilation for '%s' failed: %s";
51 int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; 54 int len = strlen(fmt) + strlen(value) + strlen((char*) buffer) - 3;
52 error = malloc(len); 55 error = malloc(len);
53 snprintf(error, len, fmt, value, reg_err); 56 snprintf(error, len, fmt, value, buffer);
54 return false; 57 return false;
55 } 58 }
56 59
@@ -66,7 +69,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
66 if (strcmp(value, "__focused__") == 0) { 69 if (strcmp(value, "__focused__") == 0) {
67 (*pattern)->match_type = PATTERN_FOCUSED; 70 (*pattern)->match_type = PATTERN_FOCUSED;
68 } else { 71 } else {
69 (*pattern)->match_type = PATTERN_PCRE; 72 (*pattern)->match_type = PATTERN_PCRE2;
70 if (!generate_regex(&(*pattern)->regex, value)) { 73 if (!generate_regex(&(*pattern)->regex, value)) {
71 return false; 74 return false;
72 }; 75 };
@@ -77,7 +80,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
77static void pattern_destroy(struct pattern *pattern) { 80static void pattern_destroy(struct pattern *pattern) {
78 if (pattern) { 81 if (pattern) {
79 if (pattern->regex) { 82 if (pattern->regex) {
80 pcre_free(pattern->regex); 83 pcre2_code_free(pattern->regex);
81 } 84 }
82 free(pattern); 85 free(pattern);
83 } 86 }
@@ -93,14 +96,18 @@ void criteria_destroy(struct criteria *criteria) {
93 pattern_destroy(criteria->window_role); 96 pattern_destroy(criteria->window_role);
94#endif 97#endif
95 pattern_destroy(criteria->con_mark); 98 pattern_destroy(criteria->con_mark);
96 free(criteria->workspace); 99 pattern_destroy(criteria->workspace);
100 free(criteria->target);
97 free(criteria->cmdlist); 101 free(criteria->cmdlist);
98 free(criteria->raw); 102 free(criteria->raw);
99 free(criteria); 103 free(criteria);
100} 104}
101 105
102static int regex_cmp(const char *item, const pcre *regex) { 106static int regex_cmp(const char *item, const pcre2_code *regex) {
103 return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); 107 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
108 int result = pcre2_match(regex, (PCRE2_SPTR)item, strlen(item), 0, 0, match_data, NULL);
109 pcre2_match_data_free(match_data);
110 return result;
104} 111}
105 112
106#if HAVE_XWAYLAND 113#if HAVE_XWAYLAND
@@ -155,7 +162,7 @@ static bool criteria_matches_container(struct criteria *criteria,
155 bool exists = false; 162 bool exists = false;
156 struct sway_container *con = container; 163 struct sway_container *con = container;
157 for (int i = 0; i < con->marks->length; ++i) { 164 for (int i = 0; i < con->marks->length; ++i) {
158 if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) == 0) { 165 if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) >= 0) {
159 exists = true; 166 exists = true;
160 break; 167 break;
161 } 168 }
@@ -183,7 +190,7 @@ static bool criteria_matches_view(struct criteria *criteria,
183 if (criteria->title) { 190 if (criteria->title) {
184 const char *title = view_get_title(view); 191 const char *title = view_get_title(view);
185 if (!title) { 192 if (!title) {
186 return false; 193 title = "";
187 } 194 }
188 195
189 switch (criteria->title->match_type) { 196 switch (criteria->title->match_type) {
@@ -192,8 +199,8 @@ static bool criteria_matches_view(struct criteria *criteria,
192 return false; 199 return false;
193 } 200 }
194 break; 201 break;
195 case PATTERN_PCRE: 202 case PATTERN_PCRE2:
196 if (regex_cmp(title, criteria->title->regex) != 0) { 203 if (regex_cmp(title, criteria->title->regex) < 0) {
197 return false; 204 return false;
198 } 205 }
199 break; 206 break;
@@ -203,7 +210,7 @@ static bool criteria_matches_view(struct criteria *criteria,
203 if (criteria->shell) { 210 if (criteria->shell) {
204 const char *shell = view_get_shell(view); 211 const char *shell = view_get_shell(view);
205 if (!shell) { 212 if (!shell) {
206 return false; 213 shell = "";
207 } 214 }
208 215
209 switch (criteria->shell->match_type) { 216 switch (criteria->shell->match_type) {
@@ -212,8 +219,8 @@ static bool criteria_matches_view(struct criteria *criteria,
212 return false; 219 return false;
213 } 220 }
214 break; 221 break;
215 case PATTERN_PCRE: 222 case PATTERN_PCRE2:
216 if (regex_cmp(shell, criteria->shell->regex) != 0) { 223 if (regex_cmp(shell, criteria->shell->regex) < 0) {
217 return false; 224 return false;
218 } 225 }
219 break; 226 break;
@@ -223,7 +230,7 @@ static bool criteria_matches_view(struct criteria *criteria,
223 if (criteria->app_id) { 230 if (criteria->app_id) {
224 const char *app_id = view_get_app_id(view); 231 const char *app_id = view_get_app_id(view);
225 if (!app_id) { 232 if (!app_id) {
226 return false; 233 app_id = "";
227 } 234 }
228 235
229 switch (criteria->app_id->match_type) { 236 switch (criteria->app_id->match_type) {
@@ -232,8 +239,8 @@ static bool criteria_matches_view(struct criteria *criteria,
232 return false; 239 return false;
233 } 240 }
234 break; 241 break;
235 case PATTERN_PCRE: 242 case PATTERN_PCRE2:
236 if (regex_cmp(app_id, criteria->app_id->regex) != 0) { 243 if (regex_cmp(app_id, criteria->app_id->regex) < 0) {
237 return false; 244 return false;
238 } 245 }
239 break; 246 break;
@@ -255,7 +262,7 @@ static bool criteria_matches_view(struct criteria *criteria,
255 if (criteria->class) { 262 if (criteria->class) {
256 const char *class = view_get_class(view); 263 const char *class = view_get_class(view);
257 if (!class) { 264 if (!class) {
258 return false; 265 class = "";
259 } 266 }
260 267
261 switch (criteria->class->match_type) { 268 switch (criteria->class->match_type) {
@@ -264,8 +271,8 @@ static bool criteria_matches_view(struct criteria *criteria,
264 return false; 271 return false;
265 } 272 }
266 break; 273 break;
267 case PATTERN_PCRE: 274 case PATTERN_PCRE2:
268 if (regex_cmp(class, criteria->class->regex) != 0) { 275 if (regex_cmp(class, criteria->class->regex) < 0) {
269 return false; 276 return false;
270 } 277 }
271 break; 278 break;
@@ -275,17 +282,17 @@ static bool criteria_matches_view(struct criteria *criteria,
275 if (criteria->instance) { 282 if (criteria->instance) {
276 const char *instance = view_get_instance(view); 283 const char *instance = view_get_instance(view);
277 if (!instance) { 284 if (!instance) {
278 return false; 285 instance = "";
279 } 286 }
280 287
281 switch (criteria->instance->match_type) { 288 switch (criteria->instance->match_type) {
282 case PATTERN_FOCUSED: 289 case PATTERN_FOCUSED:
283 if (focused && strcmp(instance, view_get_instance(focused))) { 290 if (focused && lenient_strcmp(instance, view_get_instance(focused))) {
284 return false; 291 return false;
285 } 292 }
286 break; 293 break;
287 case PATTERN_PCRE: 294 case PATTERN_PCRE2:
288 if (regex_cmp(instance, criteria->instance->regex) != 0) { 295 if (regex_cmp(instance, criteria->instance->regex) < 0) {
289 return false; 296 return false;
290 } 297 }
291 break; 298 break;
@@ -295,17 +302,17 @@ static bool criteria_matches_view(struct criteria *criteria,
295 if (criteria->window_role) { 302 if (criteria->window_role) {
296 const char *window_role = view_get_window_role(view); 303 const char *window_role = view_get_window_role(view);
297 if (!window_role) { 304 if (!window_role) {
298 return false; 305 window_role = "";
299 } 306 }
300 307
301 switch (criteria->window_role->match_type) { 308 switch (criteria->window_role->match_type) {
302 case PATTERN_FOCUSED: 309 case PATTERN_FOCUSED:
303 if (focused && strcmp(window_role, view_get_window_role(focused))) { 310 if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) {
304 return false; 311 return false;
305 } 312 }
306 break; 313 break;
307 case PATTERN_PCRE: 314 case PATTERN_PCRE2:
308 if (regex_cmp(window_role, criteria->window_role->regex) != 0) { 315 if (regex_cmp(window_role, criteria->window_role->regex) < 0) {
309 return false; 316 return false;
310 } 317 }
311 break; 318 break;
@@ -363,8 +370,8 @@ static bool criteria_matches_view(struct criteria *criteria,
363 return false; 370 return false;
364 } 371 }
365 break; 372 break;
366 case PATTERN_PCRE: 373 case PATTERN_PCRE2:
367 if (regex_cmp(ws->name, criteria->workspace->regex) != 0) { 374 if (regex_cmp(ws->name, criteria->workspace->regex) < 0) {
368 return false; 375 return false;
369 } 376 }
370 break; 377 break;
@@ -449,6 +456,7 @@ static enum atom_name parse_window_type(const char *type) {
449#endif 456#endif
450 457
451enum criteria_token { 458enum criteria_token {
459 T_ALL,
452 T_APP_ID, 460 T_APP_ID,
453 T_CON_ID, 461 T_CON_ID,
454 T_CON_MARK, 462 T_CON_MARK,
@@ -471,7 +479,9 @@ enum criteria_token {
471}; 479};
472 480
473static enum criteria_token token_from_name(char *name) { 481static enum criteria_token token_from_name(char *name) {
474 if (strcmp(name, "app_id") == 0) { 482 if (strcmp(name, "all") == 0) {
483 return T_ALL;
484 } else if (strcmp(name, "app_id") == 0) {
475 return T_APP_ID; 485 return T_APP_ID;
476 } else if (strcmp(name, "con_id") == 0) { 486 } else if (strcmp(name, "con_id") == 0) {
477 return T_CON_ID; 487 return T_CON_ID;
@@ -517,8 +527,8 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
517 return false; 527 return false;
518 } 528 }
519 529
520 // Require value, unless token is floating or tiled 530 // Require value, unless token is all, floating or tiled
521 if (!value && token != T_FLOATING && token != T_TILING) { 531 if (!value && token != T_ALL && token != T_FLOATING && token != T_TILING) {
522 const char *fmt = "Token '%s' requires a value"; 532 const char *fmt = "Token '%s' requires a value";
523 int len = strlen(fmt) + strlen(name) - 1; 533 int len = strlen(fmt) + strlen(name) - 1;
524 error = malloc(len); 534 error = malloc(len);
@@ -528,6 +538,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
528 538
529 char *endptr = NULL; 539 char *endptr = NULL;
530 switch (token) { 540 switch (token) {
541 case T_ALL:
542 criteria->all = true;
543 break;
531 case T_TITLE: 544 case T_TITLE:
532 pattern_create(&criteria->title, value); 545 pattern_create(&criteria->title, value);
533 break; 546 break;
@@ -676,7 +689,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
676 } 689 }
677 name = calloc(head - namestart + 1, 1); 690 name = calloc(head - namestart + 1, 1);
678 if (head != namestart) { 691 if (head != namestart) {
679 strncpy(name, namestart, head - namestart); 692 memcpy(name, namestart, head - namestart);
680 } 693 }
681 // Parse token value 694 // Parse token value
682 skip_spaces(&head); 695 skip_spaces(&head);
@@ -703,7 +716,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
703 } 716 }
704 } 717 }
705 value = calloc(head - valuestart + 1, 1); 718 value = calloc(head - valuestart + 1, 1);
706 strncpy(value, valuestart, head - valuestart); 719 memcpy(value, valuestart, head - valuestart);
707 if (in_quotes) { 720 if (in_quotes) {
708 ++head; 721 ++head;
709 in_quotes = false; 722 in_quotes = false;
@@ -734,7 +747,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
734 ++head; 747 ++head;
735 int len = head - raw; 748 int len = head - raw;
736 criteria->raw = calloc(len + 1, 1); 749 criteria->raw = calloc(len + 1, 1);
737 strncpy(criteria->raw, raw, len); 750 memcpy(criteria->raw, raw, len);
738 return criteria; 751 return criteria;
739 752
740cleanup: 753cleanup: