bool nft_ipv46_rule_find(struct nft_family_ops *ops, struct nftnl_rule *r, struct iptables_command_state *cs) { struct iptables_command_state this = {}; nft_rule_to_iptables_command_state(r, &this); DEBUGP("comparing with... "); #ifdef DEBUG_DEL nft_rule_print_save(&this, r, NFT_RULE_APPEND, 0); #endif if (!ops->is_same(cs, &this)) return false; if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); return false; } if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); return false; } if (strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); return false; } return true; }
/** * Looks in the given list for a match identical to m. In case * of success, it returns 1 and the list is modified so that * its first element is the identical one. Returns 0 otherwise. * * NOTE: the return value is different from look_for_same_outputs! */ static int look_for_same_outputs_(struct match_list* m, struct match_list* list) { struct match_list* head=list; while (list!=NULL && compare_matches(&(m->m),&(list->m))==A_EQUALS_B) { if (!u_strcmp(m->output,list->output)) { /* We have an identical match */ unichar* tmp=head->output; head->output=list->output; list->output=tmp; return 1; } list=list->next; } return 0; }
/** * Caches the given token sequence in the given cache. Note that * match is supposed to contain a single match, not a match list. */ static void cache_match_internal(struct match_list* match,const int* tab,int start,int end,LocateCache *c,Abstract_allocator prv_alloc) { int token=-1; struct match_list* m=match; if (start<=end) { token=tab[start]; m=NULL; } /* No node */ if (*c==NULL) { *c=new_LocateCache(token,m,prv_alloc); if (token!=-1) { cache_match_internal(match,tab,start+1,end,&((*c)->middle),prv_alloc); } return; } /* There is a node */ if (token<(*c)->token) { /* If we have to move on the left */ return cache_match_internal(match,tab,start,end,&((*c)->left),prv_alloc); } if (token>(*c)->token) { /* If we have to move on the right */ return cache_match_internal(match,tab,start,end,&((*c)->right),prv_alloc); } /* We have the correct token */ if (token==-1) { /* If we are in a final node that already existed, we just add * the new match at the end of the match list to get the same match order as * if the cache system had not been used, but only if the match is not already present */ struct match_list* *ptr=&((*c)->matches); struct match_list* z; match->next=NULL; while ((*ptr)!=NULL) { z=*ptr; if (compare_matches(&(z->m),&(match->m))==A_EQUALS_B && !u_strcmp(z->output,match->output)) { /* We discard a match that was already in cache */ free_match_list_element(match,prv_alloc); return; } ptr=&((*ptr)->next); } (*ptr)=match; return; } cache_match_internal(match,tab,start+1,end,&((*c)->middle),prv_alloc); }
/** * Returns 1 if the given matches correspond to ambiguous outputs * for the same sequence; 0 otherwise. */ int are_ambiguous(struct match_list* a,struct match_list* b) { if (compare_matches(&(a->m),&(b->m))!=A_EQUALS_B) return 0; return 1; }
/** * Adds a match to the global list of matches. The function takes into * account the match policy. For instance, we don't take [2;3] into account * if we are in longest match mode and if we already have [2;5]. * * This function is derived from the 'add_match' one in 'Matches.cpp', but it differs because * in Locate, we know exactly where we are in the text, so that we can filter matches easily. When * exploring a text automaton, it's not so easy to sort matches, because the state from where we * started the match may correspond to a position in text lower than the one of a previous match. * * IMPORTANT: 'e' is to be copied if the corresponding match must be added to the list */ struct tfst_simple_match_list* add_element_to_list(struct locate_tfst_infos* p,struct tfst_simple_match_list* list,struct tfst_simple_match_list* e) { if (list==NULL) { /* We can always add a match to the empty list */ return new_tfst_simple_match_list(e,NULL); } switch (compare_matches(&(list->m),&(e->m))) { case A_BEFORE_B: case A_BEFORE_B_OVERLAP: { /* If the candidate starts after the end of the current match, then we have to go on, * no matter the mode (shortest, longest or all matches) */ list->next=add_element_to_list(p,list->next,e); return list; } case A_INCLUDES_B: { if (p->match_policy==SHORTEST_MATCHES) { /* e must replace the current match in the list */ replace_match(list,e); return list; } else if (p->match_policy==LONGEST_MATCHES) { /* Our match is shorter than a match in the list, we discard it */ return list; } else { list->next=add_element_to_list(p,list->next,e); return list; } } case A_EQUALS_B: { /* In any mode we replace the existing match by the new one, except if we allow * ambiguous outputs */ if (u_strcmp(list->output,e->output)) { if (p->ambiguous_output_policy==ALLOW_AMBIGUOUS_OUTPUTS) { list=new_tfst_simple_match_list(e,list); return list; } else { /* If we don't allow ambiguous outputs, we have to print an error message */ error("Unexpected ambiguous outputs:\n<%S>\n<%S>\n",list->output,e->output); } } replace_match(list,e); return list; } case B_INCLUDES_A: { if (p->match_policy==SHORTEST_MATCHES) { /* Our match is longer than a match in the list, we discard it */ return list; } else if (p->match_policy==LONGEST_MATCHES) { /* e must replace the current match in the list */ replace_match(list,e); return list; } else { list->next=add_element_to_list(p,list->next,e); return list; } } case A_AFTER_B: case A_AFTER_B_OVERLAP: { /* If the candidate ends before the start of the current match, then we have to insert it * no matter the mode (shortest, longest or all matches) */ list=new_tfst_simple_match_list(e,list); return list; } } /* Should not arrive here */ return NULL; }
/** * This function explores the two given match index and prints * the differences into 'output'. 'f1' and 'f2' are the concordance * files that are used to get the text sequences to put in 'output'. * Matches that appear in only one file are printed in green. * Matches that are identical in both files are printed in blue. * Matches that are different but with a non empty intersection like * "the blue car" and "blue car" are printed in red. */ void compute_concordance_differences(struct match_list* list1, struct match_list* list2, U_FILE* f1, U_FILE* f2, U_FILE* output, int diff_only) { /* We look both match index entirely */ while (!(list1==NULL && list2==NULL)) { if (list1==NULL) { /* If the first list is empty, then the current match in the second list * must be green */ print_diff_matches(output,NULL,f2,GREEN,NULL,list2->output); list2=list2->next; continue; } if (list2==NULL) { /* If the second list is empty, then the current match in the first list * must be green */ print_diff_matches(output,f1,NULL,GREEN,list1->output,NULL); list1=list1->next; continue; } switch (compare_matches(&(list1->m),&(list2->m))) { case A_BEFORE_B: { /* list1 has no common part with list2: * abcd,efgh */ print_diff_matches(output,f1,NULL,GREEN,list1->output,list2->output); list1=list1->next; break; } case A_INCLUDES_B: { /* list2 is included in list1: * abcdef,cdef */ print_diff_matches(output,f1,f2,RED,list1->output,list2->output); list1=list1->next; list2=list2->next; break; } case A_BEFORE_B_OVERLAP: { /* list2 overlaps list1: * abcdef,cdefgh * * We consider that they are two distinct lines, and we * print the first */ print_diff_matches(output,f1,NULL,GREEN,list1->output,list2->output); list1=list1->next; break; } case A_AFTER_B: { /* list2 has no common part with list1: * abcd,efgh */ print_diff_matches(output,NULL,f2,GREEN,list1->output,list2->output); list2=list2->next; break; } case B_INCLUDES_A: { /* list1 is included in list2: * abcd,abcdef */ print_diff_matches(output,f1,f2,RED,list1->output,list2->output); list1=list1->next; list2=list2->next; break; } case A_AFTER_B_OVERLAP: { /* list1 overlaps list2 * abcdef,cdefgh * We consider that they are two distinct lines, and we * print the first */ print_diff_matches(output,NULL,f2,GREEN,list1->output,list2->output); list2=list2->next; break; } case A_EQUALS_B: { /* list1 == list2: * abcd,abcd */ int different_outputs=u_strcmp(list1->output,list2->output); if (different_outputs) { /* If there are matches with ambiguous outputs, we may find * an exact match pair forward in the lists */ different_outputs=look_for_same_outputs(list1,list2); } if (!diff_only || different_outputs) { print_diff_matches(output,f1,f2,different_outputs?VIOLET:BLUE,list1->output,list2->output); } else { /* We have to skip the unused lines */ u_fskip_line(f1); u_fskip_line(f2); } list1=list1->next; list2=list2->next; break; } } } }
int libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags flags) { g_return_val_if_fail(a || b, 0); if (!a || !b) return 1; if (strcmp(a->name, b->name) != 0) return 1; if (a->width != b->width || a->height != b->height) return 1; if (!libwacom_same_layouts (a, b)) return 1; if (a->integration_flags != b->integration_flags) return 1; if (a->cls != b->cls) return 1; if (a->num_strips != b->num_strips) return 1; if (a->features != b->features) return 1; if (a->strips_num_modes != b->strips_num_modes) return 1; if (a->ring_num_modes != b->ring_num_modes) return 1; if (a->ring2_num_modes != b->ring2_num_modes) return 1; if (a->num_buttons != b->num_buttons) return 1; if (a->num_styli != b->num_styli) return 1; if (memcmp(a->supported_styli, b->supported_styli, sizeof(int) * a->num_styli) != 0) return 1; if (a->num_leds != b->num_leds) return 1; if (memcmp(a->status_leds, b->status_leds, sizeof(WacomStatusLEDs) * a->num_leds) != 0) return 1; if (memcmp(a->buttons, b->buttons, sizeof(WacomButtonFlags) * a->num_buttons) != 0) return 1; if ((flags & WCOMPARE_MATCHES) && compare_matches(a, b) != 0) return 1; else if (strcmp(a->matches[a->match]->match, b->matches[b->match]->match) != 0) return 1; return 0; }