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