@@ -27,18 +27,34 @@ struct mako_criteria *create_criteria(struct mako_config *config) {
27
27
return criteria ;
28
28
}
29
29
30
+ void free_cond (struct mako_condition * cond ) {
31
+ switch (cond -> operator ) {
32
+ case OP_EQUALS :
33
+ case OP_NOT_EQUALS :
34
+ free (cond -> value );
35
+ return ;
36
+ case OP_REGEX_MATCHES :
37
+ regfree (& cond -> pattern );
38
+ return ;
39
+ case OP_NONE :
40
+ case OP_TRUTHY :
41
+ case OP_FALSEY :
42
+ default :
43
+ // Nothing to free.
44
+ return ;
45
+ }
46
+ }
47
+
30
48
void destroy_criteria (struct mako_criteria * criteria ) {
31
49
wl_list_remove (& criteria -> link );
32
50
33
51
finish_style (& criteria -> style );
34
- free (criteria -> app_name );
35
- free (criteria -> app_icon );
36
- free (criteria -> category );
37
- free (criteria -> desktop_entry );
38
- free (criteria -> summary );
39
- regfree (& criteria -> summary_pattern );
40
- free (criteria -> body );
41
- regfree (& criteria -> body_pattern );
52
+ free_cond (& criteria -> app_name );
53
+ free_cond (& criteria -> app_icon );
54
+ free_cond (& criteria -> category );
55
+ free_cond (& criteria -> desktop_entry );
56
+ free_cond (& criteria -> summary );
57
+ free_cond (& criteria -> body );
42
58
free (criteria -> raw_string );
43
59
free (criteria -> output );
44
60
free (criteria -> mode );
@@ -59,6 +75,24 @@ static bool match_regex_criteria(regex_t *pattern, char *value) {
59
75
return true;
60
76
}
61
77
78
+ bool match_condition (struct mako_condition * cond , char * value ) {
79
+ switch (cond -> operator ) {
80
+ case OP_EQUALS :
81
+ return strcmp (cond -> value , value ) == 0 ;
82
+ case OP_NOT_EQUALS :
83
+ return strcmp (cond -> value , value ) != 0 ;
84
+ case OP_REGEX_MATCHES :
85
+ return match_regex_criteria (& cond -> pattern , value );
86
+ case OP_TRUTHY :
87
+ return strcmp ("" , value ) != 0 ;
88
+ case OP_FALSEY :
89
+ return strcmp ("" , value ) == 0 ;
90
+ case OP_NONE :
91
+ return true;
92
+ }
93
+ return true;
94
+ }
95
+
62
96
bool match_criteria (struct mako_criteria * criteria ,
63
97
struct mako_notification * notif ) {
64
98
struct mako_criteria_spec spec = criteria -> spec ;
@@ -74,12 +108,12 @@ bool match_criteria(struct mako_criteria *criteria,
74
108
}
75
109
76
110
if (spec .app_name &&
77
- strcmp ( criteria -> app_name , notif -> app_name ) != 0 ) {
111
+ ! match_condition ( & criteria -> app_name , notif -> app_name )) {
78
112
return false;
79
113
}
80
114
81
115
if (spec .app_icon &&
82
- strcmp ( criteria -> app_icon , notif -> app_icon ) != 0 ) {
116
+ ! match_condition ( & criteria -> app_icon , notif -> app_icon )) {
83
117
return false;
84
118
}
85
119
@@ -99,39 +133,25 @@ bool match_criteria(struct mako_criteria *criteria,
99
133
}
100
134
101
135
if (spec .category &&
102
- strcmp ( criteria -> category , notif -> category ) != 0 ) {
136
+ ! match_condition ( & criteria -> category , notif -> category )) {
103
137
return false;
104
138
}
105
139
106
140
if (spec .desktop_entry &&
107
- strcmp ( criteria -> desktop_entry , notif -> desktop_entry ) != 0 ) {
141
+ ! match_condition ( & criteria -> desktop_entry , notif -> desktop_entry )) {
108
142
return false;
109
143
}
110
144
111
145
if (spec .summary &&
112
- strcmp ( criteria -> summary , notif -> summary ) != 0 ) {
146
+ ! match_condition ( & criteria -> summary , notif -> summary )) {
113
147
return false;
114
148
}
115
149
116
- if (spec .summary_pattern ) {
117
- bool ret = match_regex_criteria (& criteria -> summary_pattern , notif -> summary );
118
- if (!ret ) {
119
- return false;
120
- }
121
- }
122
-
123
150
if (spec .body &&
124
- strcmp ( criteria -> body , notif -> body ) != 0 ) {
151
+ ! match_condition ( & criteria -> body , notif -> body )) {
125
152
return false;
126
153
}
127
154
128
- if (spec .body_pattern ) {
129
- bool ret = match_regex_criteria (& criteria -> body_pattern , notif -> body );
130
- if (!ret ) {
131
- return false;
132
- }
133
- }
134
-
135
155
if (spec .group_index &&
136
156
criteria -> group_index != notif -> group_index ) {
137
157
return false;
@@ -258,14 +278,38 @@ bool parse_criteria(const char *string, struct mako_criteria *criteria) {
258
278
return true;
259
279
}
260
280
261
- // Takes a token from the criteria string that looks like "key=value", figures
262
- // out which field of the criteria "key" refers to, and sets it to "value".
281
+ bool assign_condition (struct mako_condition * cond , enum operator op , char * value ) {
282
+ cond -> operator = op ;
283
+ switch (op ) {
284
+ case OP_REGEX_MATCHES :
285
+ if (regcomp (& cond -> pattern , value , REG_EXTENDED | REG_NOSUB )) {
286
+ fprintf (stderr , "Invalid regex '%s'\n" , value );
287
+ return false;
288
+ }
289
+ return true;
290
+ case OP_EQUALS :
291
+ case OP_NOT_EQUALS :
292
+ cond -> value = strdup (value );
293
+ // fall-thru
294
+ case OP_FALSEY :
295
+ case OP_TRUTHY :
296
+ case OP_NONE :
297
+ default :
298
+ return true;
299
+ }
300
+ return true;
301
+ }
302
+
303
+ // Takes a token from the criteria string that looks like
304
+ // "key=value", "key!=value", or "key~=value"; and figures
305
+ // out which field of the criteria "key" refers to, and sets it to the condition.
263
306
// Any further equal signs are assumed to be part of the value. If there is no .
264
307
// equal sign present, the field is treated as a boolean, with a leading
265
308
// exclamation point signifying negation.
266
309
//
267
310
// Note that the token will be consumed.
268
311
bool apply_criteria_field (struct mako_criteria * criteria , char * token ) {
312
+ enum operator op = OP_EQUALS ;
269
313
char * key = token ;
270
314
char * value = strstr (key , "=" );
271
315
bool bare_key = !value ;
@@ -275,6 +319,15 @@ bool apply_criteria_field(struct mako_criteria *criteria, char *token) {
275
319
}
276
320
277
321
if (value ) {
322
+ if (value [-1 ] == '~' ) {
323
+ op = OP_REGEX_MATCHES ;
324
+ // shorten the key.
325
+ value [-1 ] = '\0' ;
326
+ } else if (value [-1 ] == '!' ) {
327
+ op = OP_NOT_EQUALS ;
328
+ // shorten the key.
329
+ value [-1 ] = '\0' ;
330
+ }
278
331
// Skip past the equal sign to the value itself.
279
332
* value = '\0' ;
280
333
++ value ;
@@ -284,8 +337,10 @@ bool apply_criteria_field(struct mako_criteria *criteria, char *token) {
284
337
if (* key == '!' ) {
285
338
// Negated boolean, skip past the exclamation point.
286
339
++ key ;
340
+ op = OP_FALSEY ;
287
341
value = "false" ;
288
342
} else {
343
+ op = OP_TRUTHY ;
289
344
value = "true" ;
290
345
}
291
346
}
@@ -297,13 +352,11 @@ bool apply_criteria_field(struct mako_criteria *criteria, char *token) {
297
352
298
353
if (!bare_key ) {
299
354
if (strcmp (key , "app-name" ) == 0 ) {
300
- criteria -> app_name = strdup (value );
301
355
criteria -> spec .app_name = true;
302
- return true ;
356
+ return assign_condition ( & criteria -> app_name , op , value ) ;
303
357
} else if (strcmp (key , "app-icon" ) == 0 ) {
304
- criteria -> app_icon = strdup (value );
305
358
criteria -> spec .app_icon = true;
306
- return true ;
359
+ return assign_condition ( & criteria -> app_icon , op , value ) ;
307
360
} else if (strcmp (key , "urgency" ) == 0 ) {
308
361
if (!parse_urgency (value , & criteria -> urgency )) {
309
362
fprintf (stderr , "Invalid urgency value '%s'" , value );
@@ -312,13 +365,11 @@ bool apply_criteria_field(struct mako_criteria *criteria, char *token) {
312
365
criteria -> spec .urgency = true;
313
366
return true;
314
367
} else if (strcmp (key , "category" ) == 0 ) {
315
- criteria -> category = strdup (value );
316
368
criteria -> spec .category = true;
317
- return true ;
369
+ return assign_condition ( & criteria -> category , op , value ) ;
318
370
} else if (strcmp (key , "desktop-entry" ) == 0 ) {
319
- criteria -> desktop_entry = strdup (value );
320
371
criteria -> spec .desktop_entry = true;
321
- return true ;
372
+ return assign_condition ( & criteria -> desktop_entry , op , value ) ;
322
373
} else if (strcmp (key , "group-index" ) == 0 ) {
323
374
if (!parse_int (value , & criteria -> group_index )) {
324
375
fprintf (stderr , "Invalid group-index value '%s'" , value );
@@ -327,29 +378,11 @@ bool apply_criteria_field(struct mako_criteria *criteria, char *token) {
327
378
criteria -> spec .group_index = true;
328
379
return true;
329
380
} else if (strcmp (key , "summary" ) == 0 ) {
330
- criteria -> summary = strdup (value );
331
381
criteria -> spec .summary = true;
332
- return true;
333
- } else if (strcmp (key , "summary~" ) == 0 ) {
334
- if (regcomp (& criteria -> summary_pattern , value ,
335
- REG_EXTENDED | REG_NOSUB )) {
336
- fprintf (stderr , "Invalid summary~ regex '%s'\n" , value );
337
- return false;
338
- }
339
- criteria -> spec .summary_pattern = true;
340
- return true;
382
+ return assign_condition (& criteria -> summary , op , value );
341
383
} else if (strcmp (key , "body" ) == 0 ) {
342
- criteria -> body = strdup (value );
343
384
criteria -> spec .body = true;
344
- return true;
345
- } else if (strcmp (key , "body~" ) == 0 ) {
346
- if (regcomp (& criteria -> body_pattern , value ,
347
- REG_EXTENDED | REG_NOSUB )) {
348
- fprintf (stderr , "Invalid body~ regex '%s'\n" , value );
349
- return false;
350
- }
351
- criteria -> spec .body_pattern = true;
352
- return true;
385
+ return assign_condition (& criteria -> body , op , value );
353
386
} else if (strcmp (key , "anchor" ) == 0 ) {
354
387
return criteria -> spec .anchor =
355
388
parse_anchor (value , & criteria -> anchor );
@@ -477,15 +510,21 @@ struct mako_criteria *create_criteria_from_notification(
477
510
// We only really need to copy the ones that are in the spec, but it
478
511
// doesn't hurt anything to do the rest and it makes this code much nicer
479
512
// to look at.
480
- criteria -> app_name = strdup (notif -> app_name );
481
- criteria -> app_icon = strdup (notif -> app_icon );
513
+ criteria -> app_name .operator = OP_EQUALS ;
514
+ criteria -> app_name .value = strdup (notif -> app_name );
515
+ criteria -> app_icon .operator = OP_EQUALS ;
516
+ criteria -> app_icon .value = strdup (notif -> app_icon );
482
517
criteria -> actionable = !wl_list_empty (& notif -> actions );
483
518
criteria -> expiring = (notif -> requested_timeout != 0 );
484
519
criteria -> urgency = notif -> urgency ;
485
- criteria -> category = strdup (notif -> category );
486
- criteria -> desktop_entry = strdup (notif -> desktop_entry );
487
- criteria -> summary = strdup (notif -> summary );
488
- criteria -> body = strdup (notif -> body );
520
+ criteria -> category .operator = OP_EQUALS ;
521
+ criteria -> category .value = strdup (notif -> category );
522
+ criteria -> desktop_entry .operator = OP_EQUALS ;
523
+ criteria -> desktop_entry .value = strdup (notif -> desktop_entry );
524
+ criteria -> summary .operator = OP_EQUALS ;
525
+ criteria -> summary .value = strdup (notif -> summary );
526
+ criteria -> body .operator = OP_EQUALS ;
527
+ criteria -> body .value = strdup (notif -> body );
489
528
criteria -> group_index = notif -> group_index ;
490
529
criteria -> grouped = (notif -> group_index >= 0 );
491
530
criteria -> hidden = notif -> hidden ;
@@ -540,16 +579,6 @@ bool validate_criteria(struct mako_criteria *criteria) {
540
579
return false;
541
580
}
542
581
543
- if (criteria -> spec .summary && criteria -> spec .summary_pattern ) {
544
- fprintf (stderr , "Cannot set both `summary` and `summary~`\n" );
545
- return false;
546
- }
547
-
548
- if (criteria -> spec .body && criteria -> spec .body_pattern ) {
549
- fprintf (stderr , "Cannot set both `body` and `body~`\n" );
550
- return false;
551
- }
552
-
553
582
if (criteria -> style .spec .group_criteria_spec ) {
554
583
struct mako_criteria_spec * spec = & criteria -> style .group_criteria_spec ;
555
584
0 commit comments