diff options
Diffstat (limited to 'sway/criteria.c')
-rw-r--r-- | sway/criteria.c | 102 |
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 @@ | |||
18 | bool criteria_is_empty(struct criteria *criteria) { | 19 | bool 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) { | |||
40 | char *error = NULL; | 42 | char *error = NULL; |
41 | 43 | ||
42 | // Returns error string on failure or NULL otherwise. | 44 | // Returns error string on failure or NULL otherwise. |
43 | static bool generate_regex(pcre **regex, char *value) { | 45 | static 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, ®_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) { | |||
77 | static void pattern_destroy(struct pattern *pattern) { | 81 | static 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 | ||
102 | static int regex_cmp(const char *item, const pcre *regex) { | 107 | static 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 | ||
451 | enum criteria_token { | 459 | enum 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 | ||
473 | static enum criteria_token token_from_name(char *name) { | 482 | static 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 | ||
740 | cleanup: | 754 | cleanup: |