diff options
-rw-r--r-- | include/sway/criteria.h | 27 | ||||
-rw-r--r-- | sway/criteria.c | 349 |
2 files changed, 205 insertions, 171 deletions
diff --git a/include/sway/criteria.h b/include/sway/criteria.h index dc8dcb98..1ee69a38 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h | |||
@@ -14,29 +14,38 @@ enum criteria_type { | |||
14 | CT_NO_FOCUS = 1 << 4, | 14 | CT_NO_FOCUS = 1 << 4, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | enum pattern_type { | ||
18 | PATTERN_PCRE, | ||
19 | PATTERN_FOCUSED, | ||
20 | }; | ||
21 | |||
22 | struct pattern { | ||
23 | enum pattern_type match_type; | ||
24 | pcre *regex; | ||
25 | }; | ||
26 | |||
17 | struct criteria { | 27 | struct criteria { |
18 | enum criteria_type type; | 28 | enum criteria_type type; |
19 | char *raw; // entire criteria string (for logging) | 29 | char *raw; // entire criteria string (for logging) |
20 | char *cmdlist; | 30 | char *cmdlist; |
21 | char *target; // workspace or output name for `assign` criteria | 31 | char *target; // workspace or output name for `assign` criteria |
22 | 32 | ||
23 | bool autofail; // __focused__ while no focus or n/a for focused view | 33 | struct pattern *title; |
24 | pcre *title; | 34 | struct pattern *shell; |
25 | pcre *shell; | 35 | struct pattern *app_id; |
26 | pcre *app_id; | 36 | struct pattern *con_mark; |
27 | pcre *con_mark; | ||
28 | uint32_t con_id; // internal ID | 37 | uint32_t con_id; // internal ID |
29 | #if HAVE_XWAYLAND | 38 | #if HAVE_XWAYLAND |
30 | pcre *class; | 39 | struct pattern *class; |
31 | uint32_t id; // X11 window ID | 40 | uint32_t id; // X11 window ID |
32 | pcre *instance; | 41 | struct pattern *instance; |
33 | pcre *window_role; | 42 | struct pattern *window_role; |
34 | enum atom_name window_type; | 43 | enum atom_name window_type; |
35 | #endif | 44 | #endif |
36 | bool floating; | 45 | bool floating; |
37 | bool tiling; | 46 | bool tiling; |
38 | char urgent; // 'l' for latest or 'o' for oldest | 47 | char urgent; // 'l' for latest or 'o' for oldest |
39 | pcre *workspace; | 48 | struct pattern *workspace; |
40 | }; | 49 | }; |
41 | 50 | ||
42 | bool criteria_is_empty(struct criteria *criteria); | 51 | bool criteria_is_empty(struct criteria *criteria); |
diff --git a/sway/criteria.c b/sway/criteria.c index b2582851..eec625af 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -16,8 +16,7 @@ | |||
16 | #include "config.h" | 16 | #include "config.h" |
17 | 17 | ||
18 | bool criteria_is_empty(struct criteria *criteria) { | 18 | bool criteria_is_empty(struct criteria *criteria) { |
19 | return !criteria->autofail | 19 | return !criteria->title |
20 | && !criteria->title | ||
21 | && !criteria->shell | 20 | && !criteria->shell |
22 | && !criteria->app_id | 21 | && !criteria->app_id |
23 | && !criteria->con_mark | 22 | && !criteria->con_mark |
@@ -35,16 +34,64 @@ bool criteria_is_empty(struct criteria *criteria) { | |||
35 | && !criteria->workspace; | 34 | && !criteria->workspace; |
36 | } | 35 | } |
37 | 36 | ||
37 | // The error pointer is used for parsing functions, and saves having to pass it | ||
38 | // as an argument in several places. | ||
39 | char *error = NULL; | ||
40 | |||
41 | // Returns error string on failure or NULL otherwise. | ||
42 | static bool generate_regex(pcre **regex, char *value) { | ||
43 | const char *reg_err; | ||
44 | int offset; | ||
45 | |||
46 | *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); | ||
47 | |||
48 | if (!*regex) { | ||
49 | const char *fmt = "Regex compilation for '%s' failed: %s"; | ||
50 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; | ||
51 | error = malloc(len); | ||
52 | snprintf(error, len, fmt, value, reg_err); | ||
53 | return false; | ||
54 | } | ||
55 | |||
56 | return true; | ||
57 | } | ||
58 | |||
59 | static bool pattern_create(struct pattern **pattern, char *value) { | ||
60 | *pattern = calloc(1, sizeof(struct pattern)); | ||
61 | if (!*pattern) { | ||
62 | sway_log(SWAY_ERROR, "Failed to allocate pattern"); | ||
63 | } | ||
64 | |||
65 | if (strcmp(value, "__focused__") == 0) { | ||
66 | (*pattern)->match_type = PATTERN_FOCUSED; | ||
67 | } else { | ||
68 | (*pattern)->match_type = PATTERN_PCRE; | ||
69 | if (!generate_regex(&(*pattern)->regex, value)) { | ||
70 | return false; | ||
71 | }; | ||
72 | } | ||
73 | return true; | ||
74 | } | ||
75 | |||
76 | static void pattern_destroy(struct pattern *pattern) { | ||
77 | if (pattern) { | ||
78 | if (pattern->regex) { | ||
79 | pcre_free(pattern->regex); | ||
80 | } | ||
81 | free(pattern); | ||
82 | } | ||
83 | } | ||
84 | |||
38 | void criteria_destroy(struct criteria *criteria) { | 85 | void criteria_destroy(struct criteria *criteria) { |
39 | pcre_free(criteria->title); | 86 | pattern_destroy(criteria->title); |
40 | pcre_free(criteria->shell); | 87 | pattern_destroy(criteria->shell); |
41 | pcre_free(criteria->app_id); | 88 | pattern_destroy(criteria->app_id); |
42 | #if HAVE_XWAYLAND | 89 | #if HAVE_XWAYLAND |
43 | pcre_free(criteria->class); | 90 | pattern_destroy(criteria->class); |
44 | pcre_free(criteria->instance); | 91 | pattern_destroy(criteria->instance); |
45 | pcre_free(criteria->window_role); | 92 | pattern_destroy(criteria->window_role); |
46 | #endif | 93 | #endif |
47 | pcre_free(criteria->con_mark); | 94 | pattern_destroy(criteria->con_mark); |
48 | free(criteria->workspace); | 95 | free(criteria->workspace); |
49 | free(criteria->cmdlist); | 96 | free(criteria->cmdlist); |
50 | free(criteria->raw); | 97 | free(criteria->raw); |
@@ -99,36 +146,75 @@ static void find_urgent_iterator(struct sway_container *con, void *data) { | |||
99 | 146 | ||
100 | static bool criteria_matches_view(struct criteria *criteria, | 147 | static bool criteria_matches_view(struct criteria *criteria, |
101 | struct sway_view *view) { | 148 | struct sway_view *view) { |
102 | if (criteria->autofail) { | 149 | struct sway_seat *seat = input_manager_current_seat(); |
103 | return false; | 150 | struct sway_container *focus = seat_get_focused_container(seat); |
104 | } | 151 | struct sway_view *focused = focus ? focus->view : NULL; |
105 | 152 | ||
106 | if (criteria->title) { | 153 | if (criteria->title) { |
107 | const char *title = view_get_title(view); | 154 | const char *title = view_get_title(view); |
108 | if (!title || regex_cmp(title, criteria->title) != 0) { | 155 | if (!title) { |
109 | return false; | 156 | return false; |
110 | } | 157 | } |
158 | |||
159 | switch (criteria->title->match_type) { | ||
160 | case PATTERN_FOCUSED: | ||
161 | if (focused && strcmp(title, view_get_title(focused))) { | ||
162 | return false; | ||
163 | } | ||
164 | break; | ||
165 | case PATTERN_PCRE: | ||
166 | if (regex_cmp(title, criteria->title->regex) != 0) { | ||
167 | return false; | ||
168 | } | ||
169 | break; | ||
170 | } | ||
111 | } | 171 | } |
112 | 172 | ||
113 | if (criteria->shell) { | 173 | if (criteria->shell) { |
114 | const char *shell = view_get_shell(view); | 174 | const char *shell = view_get_shell(view); |
115 | if (!shell || regex_cmp(shell, criteria->shell) != 0) { | 175 | if (!shell) { |
116 | return false; | 176 | return false; |
117 | } | 177 | } |
178 | |||
179 | switch (criteria->shell->match_type) { | ||
180 | case PATTERN_FOCUSED: | ||
181 | if (focused && strcmp(shell, view_get_shell(focused))) { | ||
182 | return false; | ||
183 | } | ||
184 | break; | ||
185 | case PATTERN_PCRE: | ||
186 | if (regex_cmp(shell, criteria->shell->regex) != 0) { | ||
187 | return false; | ||
188 | } | ||
189 | break; | ||
190 | } | ||
118 | } | 191 | } |
119 | 192 | ||
120 | if (criteria->app_id) { | 193 | if (criteria->app_id) { |
121 | const char *app_id = view_get_app_id(view); | 194 | const char *app_id = view_get_app_id(view); |
122 | if (!app_id || regex_cmp(app_id, criteria->app_id) != 0) { | 195 | if (!app_id) { |
123 | return false; | 196 | return false; |
124 | } | 197 | } |
198 | |||
199 | switch (criteria->app_id->match_type) { | ||
200 | case PATTERN_FOCUSED: | ||
201 | if (focused && strcmp(app_id, view_get_app_id(focused))) { | ||
202 | return false; | ||
203 | } | ||
204 | break; | ||
205 | case PATTERN_PCRE: | ||
206 | if (regex_cmp(app_id, criteria->app_id->regex) != 0) { | ||
207 | return false; | ||
208 | } | ||
209 | break; | ||
210 | } | ||
125 | } | 211 | } |
126 | 212 | ||
127 | if (criteria->con_mark) { | 213 | if (criteria->con_mark) { |
128 | bool exists = false; | 214 | bool exists = false; |
129 | struct sway_container *con = view->container; | 215 | struct sway_container *con = view->container; |
130 | for (int i = 0; i < con->marks->length; ++i) { | 216 | for (int i = 0; i < con->marks->length; ++i) { |
131 | if (regex_cmp(con->marks->items[i], criteria->con_mark) == 0) { | 217 | if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) == 0) { |
132 | exists = true; | 218 | exists = true; |
133 | break; | 219 | break; |
134 | } | 220 | } |
@@ -154,23 +240,62 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
154 | 240 | ||
155 | if (criteria->class) { | 241 | if (criteria->class) { |
156 | const char *class = view_get_class(view); | 242 | const char *class = view_get_class(view); |
157 | if (!class || regex_cmp(class, criteria->class) != 0) { | 243 | if (!class) { |
158 | return false; | 244 | return false; |
159 | } | 245 | } |
246 | |||
247 | switch (criteria->class->match_type) { | ||
248 | case PATTERN_FOCUSED: | ||
249 | if (focused && strcmp(class, view_get_class(focused))) { | ||
250 | return false; | ||
251 | } | ||
252 | break; | ||
253 | case PATTERN_PCRE: | ||
254 | if (regex_cmp(class, criteria->class->regex) != 0) { | ||
255 | return false; | ||
256 | } | ||
257 | break; | ||
258 | } | ||
160 | } | 259 | } |
161 | 260 | ||
162 | if (criteria->instance) { | 261 | if (criteria->instance) { |
163 | const char *instance = view_get_instance(view); | 262 | const char *instance = view_get_instance(view); |
164 | if (!instance || regex_cmp(instance, criteria->instance) != 0) { | 263 | if (!instance) { |
165 | return false; | 264 | return false; |
166 | } | 265 | } |
266 | |||
267 | switch (criteria->instance->match_type) { | ||
268 | case PATTERN_FOCUSED: | ||
269 | if (focused && strcmp(instance, view_get_instance(focused))) { | ||
270 | return false; | ||
271 | } | ||
272 | break; | ||
273 | case PATTERN_PCRE: | ||
274 | if (regex_cmp(instance, criteria->instance->regex) != 0) { | ||
275 | return false; | ||
276 | } | ||
277 | break; | ||
278 | } | ||
167 | } | 279 | } |
168 | 280 | ||
169 | if (criteria->window_role) { | 281 | if (criteria->window_role) { |
170 | const char *role = view_get_window_role(view); | 282 | const char *window_role = view_get_window_role(view); |
171 | if (!role || regex_cmp(role, criteria->window_role) != 0) { | 283 | if (!window_role) { |
172 | return false; | 284 | return false; |
173 | } | 285 | } |
286 | |||
287 | switch (criteria->window_role->match_type) { | ||
288 | case PATTERN_FOCUSED: | ||
289 | if (focused && strcmp(window_role, view_get_window_role(focused))) { | ||
290 | return false; | ||
291 | } | ||
292 | break; | ||
293 | case PATTERN_PCRE: | ||
294 | if (regex_cmp(window_role, criteria->window_role->regex) != 0) { | ||
295 | return false; | ||
296 | } | ||
297 | break; | ||
298 | } | ||
174 | } | 299 | } |
175 | 300 | ||
176 | if (criteria->window_type != ATOM_LAST) { | 301 | if (criteria->window_type != ATOM_LAST) { |
@@ -213,9 +338,23 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
213 | 338 | ||
214 | if (criteria->workspace) { | 339 | if (criteria->workspace) { |
215 | struct sway_workspace *ws = view->container->workspace; | 340 | struct sway_workspace *ws = view->container->workspace; |
216 | if (!ws || regex_cmp(ws->name, criteria->workspace) != 0) { | 341 | if (!ws) { |
217 | return false; | 342 | return false; |
218 | } | 343 | } |
344 | |||
345 | switch (criteria->workspace->match_type) { | ||
346 | case PATTERN_FOCUSED: | ||
347 | if (focused && | ||
348 | strcmp(ws->name, focused->container->workspace->name)) { | ||
349 | return false; | ||
350 | } | ||
351 | break; | ||
352 | case PATTERN_PCRE: | ||
353 | if (regex_cmp(ws->name, criteria->workspace->regex) != 0) { | ||
354 | return false; | ||
355 | } | ||
356 | break; | ||
357 | } | ||
219 | } | 358 | } |
220 | 359 | ||
221 | return true; | 360 | return true; |
@@ -258,28 +397,6 @@ list_t *criteria_get_views(struct criteria *criteria) { | |||
258 | return matches; | 397 | return matches; |
259 | } | 398 | } |
260 | 399 | ||
261 | // The error pointer is used for parsing functions, and saves having to pass it | ||
262 | // as an argument in several places. | ||
263 | char *error = NULL; | ||
264 | |||
265 | // Returns error string on failure or NULL otherwise. | ||
266 | static bool generate_regex(pcre **regex, char *value) { | ||
267 | const char *reg_err; | ||
268 | int offset; | ||
269 | |||
270 | *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, ®_err, &offset, NULL); | ||
271 | |||
272 | if (!*regex) { | ||
273 | const char *fmt = "Regex compilation for '%s' failed: %s"; | ||
274 | int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3; | ||
275 | error = malloc(len); | ||
276 | snprintf(error, len, fmt, value, reg_err); | ||
277 | return false; | ||
278 | } | ||
279 | |||
280 | return true; | ||
281 | } | ||
282 | |||
283 | #if HAVE_XWAYLAND | 400 | #if HAVE_XWAYLAND |
284 | static enum atom_name parse_window_type(const char *type) { | 401 | static enum atom_name parse_window_type(const char *type) { |
285 | if (strcasecmp(type, "normal") == 0) { | 402 | if (strcasecmp(type, "normal") == 0) { |
@@ -363,92 +480,6 @@ static enum criteria_token token_from_name(char *name) { | |||
363 | return T_INVALID; | 480 | return T_INVALID; |
364 | } | 481 | } |
365 | 482 | ||
366 | /** | ||
367 | * Get a property of the focused view. | ||
368 | * | ||
369 | * Note that we are taking the focused view at the time of criteria parsing, not | ||
370 | * at the time of execution. This is because __focused__ only makes sense when | ||
371 | * using criteria via IPC. Using __focused__ in config is not useful because | ||
372 | * criteria is only executed once per view. | ||
373 | */ | ||
374 | static char *get_focused_prop(enum criteria_token token, bool *autofail) { | ||
375 | struct sway_seat *seat = input_manager_current_seat(); | ||
376 | struct sway_container *focus = seat_get_focused_container(seat); | ||
377 | |||
378 | struct sway_view *view = focus ? focus->view : NULL; | ||
379 | const char *value = NULL; | ||
380 | |||
381 | switch (token) { | ||
382 | case T_APP_ID: | ||
383 | *autofail = true; | ||
384 | if (view) { | ||
385 | value = view_get_app_id(view); | ||
386 | } | ||
387 | break; | ||
388 | case T_SHELL: | ||
389 | *autofail = true; | ||
390 | if (view) { | ||
391 | value = view_get_shell(view); | ||
392 | } | ||
393 | break; | ||
394 | case T_TITLE: | ||
395 | *autofail = true; | ||
396 | if (view) { | ||
397 | value = view_get_title(view); | ||
398 | } | ||
399 | break; | ||
400 | case T_WORKSPACE: | ||
401 | *autofail = true; | ||
402 | if (focus && focus->workspace) { | ||
403 | value = focus->workspace->name; | ||
404 | } | ||
405 | break; | ||
406 | case T_CON_ID: | ||
407 | *autofail = true; | ||
408 | if (view && view->container) { | ||
409 | size_t id = view->container->node.id; | ||
410 | size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; | ||
411 | char *id_str = malloc(id_size); | ||
412 | snprintf(id_str, id_size, "%zu", id); | ||
413 | value = id_str; | ||
414 | } | ||
415 | break; | ||
416 | #if HAVE_XWAYLAND | ||
417 | case T_CLASS: | ||
418 | *autofail = true; | ||
419 | if (view) { | ||
420 | value = view_get_class(view); | ||
421 | } | ||
422 | break; | ||
423 | case T_INSTANCE: | ||
424 | *autofail = true; | ||
425 | if (view) { | ||
426 | value = view_get_instance(view); | ||
427 | } | ||
428 | break; | ||
429 | case T_WINDOW_ROLE: | ||
430 | *autofail = true; | ||
431 | if (view) { | ||
432 | value = view_get_window_role(view); | ||
433 | } | ||
434 | break; | ||
435 | case T_WINDOW_TYPE: // These do not support __focused__ | ||
436 | case T_ID: | ||
437 | #endif | ||
438 | case T_CON_MARK: | ||
439 | case T_FLOATING: | ||
440 | case T_TILING: | ||
441 | case T_URGENT: | ||
442 | case T_INVALID: | ||
443 | *autofail = false; | ||
444 | break; | ||
445 | } | ||
446 | if (value) { | ||
447 | return strdup(value); | ||
448 | } | ||
449 | return NULL; | ||
450 | } | ||
451 | |||
452 | static bool parse_token(struct criteria *criteria, char *name, char *value) { | 483 | static bool parse_token(struct criteria *criteria, char *name, char *value) { |
453 | enum criteria_token token = token_from_name(name); | 484 | enum criteria_token token = token_from_name(name); |
454 | if (token == T_INVALID) { | 485 | if (token == T_INVALID) { |
@@ -459,20 +490,8 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
459 | return false; | 490 | return false; |
460 | } | 491 | } |
461 | 492 | ||
462 | char *effective_value = NULL; | ||
463 | if (value && strcmp(value, "__focused__") == 0) { | ||
464 | bool autofail = false; | ||
465 | effective_value = get_focused_prop(token, &autofail); | ||
466 | if (!effective_value && autofail) { | ||
467 | criteria->autofail = true; | ||
468 | return true; | ||
469 | } | ||
470 | } else if (value) { | ||
471 | effective_value = strdup(value); | ||
472 | } | ||
473 | |||
474 | // Require value, unless token is floating or tiled | 493 | // Require value, unless token is floating or tiled |
475 | if (!effective_value && token != T_FLOATING && token != T_TILING) { | 494 | if (!value && token != T_FLOATING && token != T_TILING) { |
476 | const char *fmt = "Token '%s' requires a value"; | 495 | const char *fmt = "Token '%s' requires a value"; |
477 | int len = strlen(fmt) + strlen(name) - 1; | 496 | int len = strlen(fmt) + strlen(name) - 1; |
478 | error = malloc(len); | 497 | error = malloc(len); |
@@ -483,41 +502,48 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
483 | char *endptr = NULL; | 502 | char *endptr = NULL; |
484 | switch (token) { | 503 | switch (token) { |
485 | case T_TITLE: | 504 | case T_TITLE: |
486 | generate_regex(&criteria->title, effective_value); | 505 | pattern_create(&criteria->title, value); |
487 | break; | 506 | break; |
488 | case T_SHELL: | 507 | case T_SHELL: |
489 | generate_regex(&criteria->shell, effective_value); | 508 | pattern_create(&criteria->shell, value); |
490 | break; | 509 | break; |
491 | case T_APP_ID: | 510 | case T_APP_ID: |
492 | generate_regex(&criteria->app_id, effective_value); | 511 | pattern_create(&criteria->app_id, value); |
493 | break; | 512 | break; |
494 | case T_CON_ID: | 513 | case T_CON_ID: |
495 | criteria->con_id = strtoul(effective_value, &endptr, 10); | 514 | if (strcmp(value, "__focused__") == 0) { |
496 | if (*endptr != 0) { | 515 | struct sway_seat *seat = input_manager_current_seat(); |
497 | error = strdup("The value for 'con_id' should be '__focused__' or numeric"); | 516 | struct sway_container *focus = seat_get_focused_container(seat); |
517 | struct sway_view *view = focus ? focus->view : NULL; | ||
518 | criteria->con_id = view ? view->container->node.id : 0; | ||
519 | } else { | ||
520 | criteria->con_id = strtoul(value, &endptr, 10); | ||
521 | if (*endptr != 0) { | ||
522 | error = strdup("The value for 'con_id' should be '__focused__' or numeric"); | ||
523 | } | ||
498 | } | 524 | } |
499 | break; | 525 | break; |
500 | case T_CON_MARK: | 526 | case T_CON_MARK: |
501 | generate_regex(&criteria->con_mark, effective_value); | 527 | pattern_create(&criteria->con_mark, value); |
502 | break; | 528 | break; |
503 | #if HAVE_XWAYLAND | 529 | #if HAVE_XWAYLAND |
504 | case T_CLASS: | 530 | case T_CLASS: |
505 | generate_regex(&criteria->class, effective_value); | 531 | pattern_create(&criteria->class, value); |
506 | break; | 532 | break; |
507 | case T_ID: | 533 | case T_ID: |
508 | criteria->id = strtoul(effective_value, &endptr, 10); | 534 | criteria->id = strtoul(value, &endptr, 10); |
509 | if (*endptr != 0) { | 535 | if (*endptr != 0) { |
510 | error = strdup("The value for 'id' should be numeric"); | 536 | error = strdup("The value for 'id' should be numeric"); |
511 | } | 537 | } |
512 | break; | 538 | break; |
513 | case T_INSTANCE: | 539 | case T_INSTANCE: |
514 | generate_regex(&criteria->instance, effective_value); | 540 | pattern_create(&criteria->instance, value); |
515 | break; | 541 | break; |
516 | case T_WINDOW_ROLE: | 542 | case T_WINDOW_ROLE: |
517 | generate_regex(&criteria->window_role, effective_value); | 543 | pattern_create(&criteria->window_role, value); |
518 | break; | 544 | break; |
519 | case T_WINDOW_TYPE: | 545 | case T_WINDOW_TYPE: |
520 | criteria->window_type = parse_window_type(effective_value); | 546 | criteria->window_type = parse_window_type(value); |
521 | break; | 547 | break; |
522 | #endif | 548 | #endif |
523 | case T_FLOATING: | 549 | case T_FLOATING: |
@@ -527,13 +553,13 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
527 | criteria->tiling = true; | 553 | criteria->tiling = true; |
528 | break; | 554 | break; |
529 | case T_URGENT: | 555 | case T_URGENT: |
530 | if (strcmp(effective_value, "latest") == 0 || | 556 | if (strcmp(value, "latest") == 0 || |
531 | strcmp(effective_value, "newest") == 0 || | 557 | strcmp(value, "newest") == 0 || |
532 | strcmp(effective_value, "last") == 0 || | 558 | strcmp(value, "last") == 0 || |
533 | strcmp(effective_value, "recent") == 0) { | 559 | strcmp(value, "recent") == 0) { |
534 | criteria->urgent = 'l'; | 560 | criteria->urgent = 'l'; |
535 | } else if (strcmp(effective_value, "oldest") == 0 || | 561 | } else if (strcmp(value, "oldest") == 0 || |
536 | strcmp(effective_value, "first") == 0) { | 562 | strcmp(value, "first") == 0) { |
537 | criteria->urgent = 'o'; | 563 | criteria->urgent = 'o'; |
538 | } else { | 564 | } else { |
539 | error = | 565 | error = |
@@ -542,12 +568,11 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { | |||
542 | } | 568 | } |
543 | break; | 569 | break; |
544 | case T_WORKSPACE: | 570 | case T_WORKSPACE: |
545 | generate_regex(&criteria->workspace, effective_value); | 571 | pattern_create(&criteria->workspace, value); |
546 | break; | 572 | break; |
547 | case T_INVALID: | 573 | case T_INVALID: |
548 | break; | 574 | break; |
549 | } | 575 | } |
550 | free(effective_value); | ||
551 | 576 | ||
552 | if (error) { | 577 | if (error) { |
553 | return false; | 578 | return false; |