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