Browse code

Support negated alternates for prefiltering (bb #2004).

Török Edvin authored on 2010/05/11 23:05:06
Showing 1 changed files
... ...
@@ -266,6 +266,7 @@ struct char_spec {
266 266
 	uint8_t start;
267 267
 	uint8_t end;
268 268
 	uint8_t step;
269
+	uint8_t negative;
269 270
 };
270 271
 
271 272
 static inline unsigned char spec_ith_char(const struct char_spec *spec, unsigned i)
... ...
@@ -279,7 +280,7 @@ static inline unsigned char spec_ith_char(const struct char_spec *spec, unsigned
279 279
 	return i;
280 280
 }
281 281
 
282
-static const struct char_spec full_range = {NULL, 0,0xff,1};
282
+static const struct char_spec full_range = {NULL, 0,0xff,1,0};
283 283
 
284 284
 static inline int spec_is_fullrange(const struct char_spec *spec0, const struct char_spec *spec1)
285 285
 {
... ...
@@ -292,6 +293,24 @@ static inline int spec_is_fullrange(const struct char_spec *spec0, const struct
292 292
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
293 293
 #endif
294 294
 
295
+#define SPEC_FOREACH(spec0, k0, spec1, k1) do {\
296
+    unsigned char c0 = spec_ith_char(spec0, k0);\
297
+    unsigned char c1 = spec_ith_char(spec1, k1);\
298
+    unsigned c0end, c1end, cc0,cc1;\
299
+    c0end = spec0->negative ? 255 : c0;\
300
+    c1end = spec1->negative ? 255 : c1;\
301
+    cc0 = spec0->negative ? 0 : c0;\
302
+    cc1 = spec1->negative ? 0 : c1;\
303
+    for (;cc0 <= c0end;cc0++) {\
304
+	for (;cc1 <= c1end; cc1++) {\
305
+	    uint16_t a = cc0 | (cc1<<8);\
306
+	    if (spec0->negative && cc0 == c0)\
307
+	    continue;\
308
+	    if (spec1->negative && cc1 == c1)\
309
+	    continue;
310
+
311
+#define SPEC_END_FOR }}} while(0)
312
+
295 313
 enum badness {
296 314
 	reject,
297 315
 	/* try to avoid if possible */
... ...
@@ -343,11 +362,10 @@ static inline void get_score(enum badness badness, unsigned i, const struct filt
343 343
 	/* at most 256 iterations here, otherwise base would be negative */
344 344
 	for(k0=spec0->start;k0 <= spec0->end;k0 += spec0->step) {
345 345
 		for(k1=spec1->start;k1 <= spec1->end;k1 += spec1->step) {
346
-			unsigned char c0 = spec_ith_char(spec0, k0);
347
-			unsigned char c1 = spec_ith_char(spec1, k1);
348
-			uint16_t a = c0 | (c1<<8);
346
+		    SPEC_FOREACH(spec0, k0, spec1, k1) {
349 347
 			num_introduced += filter_isset(m, i, a);
350 348
 			num_end_introduced += filter_end_isset(m, i, a);
349
+		    } SPEC_END_FOR;
351 350
 		}
352 351
 	}
353 352
 	*score = base - num_introduced;
... ...
@@ -396,8 +414,12 @@ static inline void add_choice(struct choice *choices, unsigned *cnt, unsigned i,
396 396
 
397 397
 static inline int32_t spec_iter(const struct char_spec *spec)
398 398
 {
399
-	assert(spec->step);
400
-	return (1 + spec->end - spec->start)/spec->step;
399
+    unsigned count;
400
+    assert(spec->step);
401
+    count = (1 + spec->end - spec->start)/spec->step;
402
+    if (spec->negative) /* all chars except itself are added */
403
+	count *= 254;
404
+    return count;
401 405
 }
402 406
 
403 407
 int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
... ...
@@ -436,6 +458,7 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
436 436
 		struct char_spec *spec = &chars[i];
437 437
 		const uint16_t p = i < prefix_len ? pat->prefix[i] : pat->pattern[i - prefix_len];
438 438
 		spec->alt = NULL;
439
+		spec->negative = 0;
439 440
 		switch (p & CLI_MATCH_WILDCARD) {
440 441
 			case CLI_MATCH_CHAR:
441 442
 				spec->start = spec->end = (uint8_t)p;
... ...
@@ -450,6 +473,7 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
450 450
 				assert(pat->special_table);
451 451
 				/* assert(altcnt < pat->alt); */
452 452
 				assert(pat->special_table[altcnt]);
453
+				spec->negative = pat->special_table[altcnt]->negative;
453 454
 				switch (pat->special_table[altcnt++]->type) {
454 455
 				    case 1: /* ALT_CHAR */
455 456
 					spec->start = 0;
... ...
@@ -459,8 +483,7 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
459 459
 					break;
460 460
 				    default:
461 461
 					stop = 1;
462
-					break;
463
-					/* TODO: should something be done here?
462
+					break;	/* TODO: should something be done here?
464 463
 					 * */
465 464
 				}
466 465
 				break;
... ...
@@ -508,6 +531,10 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
508 508
 				for(k1=spec1->start;k1 <= spec1->end;k1 += spec1->step) {
509 509
 					unsigned char c0 = spec_ith_char(spec0, k0);
510 510
 					unsigned char c1 = spec_ith_char(spec1, k1);
511
+					if (spec0->negative || spec1->negative) {
512
+					    scor = avoid_anywhere;
513
+					    break;
514
+					}
511 515
 					if ((!c0 && !c1) || (c0 == 0xff && c1 == 0xff)) {
512 516
 						scor = avoid_first;
513 517
 						break;
... ...
@@ -630,12 +657,12 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
630 630
 
631 631
 		for(k0=spec0->start;k0 <= spec0->end;k0 += spec0->step) {
632 632
 			for(k1=spec1->start;k1 <= spec1->end;k1 += spec1->step) {
633
-				unsigned char c0 = spec_ith_char(spec0, k0);
634
-				unsigned char c1 = spec_ith_char(spec1, k1);
635
-				if (!c0 && !c1 && !i) {
633
+			    SPEC_FOREACH(spec0, k0, spec1, k1) {
634
+				if (!cc0 && !cc1 && !i) {
636 635
 					detailed_dbg("filter (warning): subsignature begins with zero: %s\n",pat->virname);
637 636
 				}
638
-				filter_set_atpos(m, i, c0 | (c1<<8));
637
+				filter_set_atpos(m, i, a);
638
+			    } SPEC_END_FOR;
639 639
 			}
640 640
 		}
641 641
 	}
... ...
@@ -644,12 +671,12 @@ int  filter_add_acpatt(struct filter *m, const struct cli_ac_patt *pat)
644 644
 	if (spec0 && spec1) {
645 645
 	    for (k0=spec0->start;k0 <= spec0->end;k0 += spec0->step) {
646 646
 		for (k1=spec1->start;k1 <= spec1->end;k1 += spec1->step) {
647
-			unsigned char c0 = spec_ith_char(spec0, k0);
648
-			unsigned char c1 = spec_ith_char(spec1, k1);
649
-			if (!c0 && !c1) {
650
-				detailed_dbg("filter (warning): subsignature ends with zero: %s\n",pat->virname);
647
+		    SPEC_FOREACH(spec0, k0, spec1, k1) {
648
+			if (!cc0 && !cc1) {
649
+			    detailed_dbg("filter (warning): subsignature ends with zero: %s\n",pat->virname);
651 650
 			}
652
-			filter_set_end(m, j, c0 | (c1<<8));
651
+			filter_set_end(m, j, a);
652
+		    } SPEC_END_FOR;
653 653
 		}
654 654
 	    }
655 655
 	}